2 * Copyright © 2006 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or (at
7 * your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 git_filename (rev_file
*file
, char *name
, int strip
)
31 if (strlen (file
->name
) - strip
>= MAXPATHLEN
)
33 strcpy (name
, file
->name
+ strip
);
34 while ((attic
= strstr (name
, "Attic/")) &&
35 (attic
== name
|| attic
[-1] == '/'))
38 memmove (attic
, attic
+ 6, l
- 5);
41 if (len
> 2 && !strcmp (name
+ len
- 2, ",v"))
46 #define GIT_CVS_DIR ".git-cvs"
49 git_cvs_file (char *base
)
57 if (mkdir (GIT_CVS_DIR
, 0777) < 0 && errno
!= EEXIST
) {
58 fprintf (stderr
, "%s: %s\n", GIT_CVS_DIR
, strerror (errno
));
62 filename_buf
= git_format_command ("%s/%s-%d",
63 GIT_CVS_DIR
, base
, id
++);
66 filename
= atom (filename_buf
);
71 extern const char *log_command
;
73 static size_t log_size
;
76 git_log(rev_commit
*commit
)
87 filename
= git_cvs_file ("log");
90 f
= fopen (filename
, "w+");
92 fprintf (stderr
, "%s: %s\n", filename
, strerror (errno
));
95 if (fputs (commit
->log
, f
) == EOF
) {
96 fprintf (stderr
, "%s: %s\n", filename
, strerror (errno
));
102 command
= git_format_command ("%s '%s'", log_command
, filename
);
105 n
= git_system (command
);
113 if (size
+ 1 >= log_size
) {
118 log_buf
= xrealloc(log_buf
, log_size
);
120 n
= fread(log_buf
+ size
, 1, log_size
- size
- 1, f
);
126 log_buf
[size
] = '\0';
130 typedef struct _cvs_author
{
131 struct _cvs_author
*next
;
137 #define AUTHOR_HASH 1021
139 static cvs_author
*author_buckets
[AUTHOR_HASH
];
142 git_fullname (char *name
)
144 cvs_author
**bucket
= &author_buckets
[((unsigned long) name
) % AUTHOR_HASH
];
147 for (a
= *bucket
; a
; a
= a
->next
)
154 git_free_author_map (void)
158 for (h
= 0; h
< AUTHOR_HASH
; h
++) {
159 cvs_author
**bucket
= &author_buckets
[h
];
162 while ((a
= *bucket
)) {
170 git_load_author_map (char *filename
)
180 cvs_author
*a
, **bucket
;
182 f
= fopen (filename
, "r");
184 fprintf (stderr
, "%s: %s\n", filename
, strerror (errno
));
187 while (fgets (line
, sizeof (line
) - 1, f
)) {
191 equal
= strchr (line
, '=');
193 fprintf (stderr
, "%s: (%d) missing '='\n", filename
, lineno
);
198 while (equal
> line
&& equal
[-1] == ' ')
202 if (git_fullname (name
)) {
203 fprintf (stderr
, "%s: (%d) duplicate name '%s' ignored\n",
204 filename
, lineno
, name
);
208 a
= calloc (1, sizeof (cvs_author
));
210 angle
= strchr (full
, '<');
212 fprintf (stderr
, "%s: (%d) missing email address '%s'\n",
213 filename
, lineno
, name
);
218 while (full
< angle
&& full
[0] == ' ')
220 while (angle
> full
&& angle
[-1] == ' ')
223 a
->full
= atom(full
);
224 angle
= strchr (email
, '>');
226 fprintf (stderr
, "%s: (%d) malformed email address '%s\n",
227 filename
, lineno
, name
);
232 a
->email
= atom (email
);
233 bucket
= &author_buckets
[((unsigned long) name
) % AUTHOR_HASH
];
241 static int git_total_commits
;
242 static int git_current_commit
;
243 static char *git_current_head
;
245 #define STATUS stdout
246 #define PROGRESS_LEN 20
251 int spot
= git_current_commit
* PROGRESS_LEN
/ git_total_commits
;
254 fprintf (STATUS
, "Save: %35.35s ", git_current_head
);
255 for (s
= 0; s
< PROGRESS_LEN
+ 1; s
++)
256 putc (s
== spot
? '*' : '.', STATUS
);
257 fprintf (STATUS
, " %5d of %5d\n", git_current_commit
, git_total_commits
);
261 static char *commit_text
;
262 static size_t commit_size
;
263 static void add_buffer(size_t *offset
, const char *fmt
, ...)
269 n
= vsnprintf(commit_text
+ *offset
, commit_size
- *offset
,
272 if (n
< commit_size
- *offset
)
278 commit_text
= xrealloc(commit_text
, commit_size
);
283 * Create a commit object in the repository using the current
284 * index and the information from the provided rev_commit
287 git_commit(rev_commit
*commit
)
293 unsigned char commit_sha1
[20];
295 int encoding_is_utf8
;
300 log
= git_log(commit
);
304 author
= git_fullname(commit
->author
);
306 // fprintf (stderr, "%s: not in author map\n", commit->author);
307 full
= commit
->author
;
308 email
= commit
->author
;
311 email
= author
->email
;
314 /* Not having i18n.commitencoding is the same as having utf-8 */
315 encoding_is_utf8
= is_encoding_utf8(git_commit_encoding
);
317 add_buffer(&size
, "tree %s\n", commit
->sha1
);
319 add_buffer(&size
, "parent %s\n", commit
->parent
->sha1
);
320 add_buffer(&size
, "author %s <%s> %lu +0000\n",
321 full
, email
, commit
->date
);
322 add_buffer(&size
, "committer %s <%s> %lu +0000\n",
323 full
, email
, commit
->date
);
324 if (!encoding_is_utf8
)
325 add_buffer(&size
, "encoding %s\n", git_commit_encoding
);
326 add_buffer(&size
, "\n%s", log
);
328 if (write_sha1_file(commit_text
, size
, commit_type
, commit_sha1
))
331 commit
->sha1
= atom(sha1_to_hex(commit_sha1
));
338 git_update_ref (char *sha1
, char *type
, char *name
)
343 command
= git_format_command ("git update-ref 'refs/%s/%s' '%s'",
347 n
= git_system (command
);
355 git_mktag (rev_commit
*commit
, char *name
)
364 filename
= git_cvs_file ("tag");
367 f
= fopen (filename
, "w");
369 fprintf (stderr
, "%s: %s\n", filename
, strerror (errno
));
373 author
= git_fullname (commit
->author
);
378 "tagger %s <%s> %ld +0000\n"
382 author
? author
->full
: commit
->author
,
383 author
? author
->email
: "",
386 fprintf (stderr
, "%s: %s\n", filename
, strerror (errno
));
393 fprintf (stderr
, "%s: %s\n", filename
, strerror (errno
));
398 command
= git_format_command ("git mktag < '%s'", filename
);
403 tag_sha1
= git_system_to_string (command
);
410 git_tag (rev_commit
*commit
, char *name
)
414 tag_sha1
= git_mktag (commit
, name
);
417 return git_update_ref (tag_sha1
, "tags", name
);
421 git_head (rev_commit
*commit
, char *name
)
423 return git_update_ref (commit
->sha1
, "heads", name
);
427 git_commit_recurse (rev_ref
*head
, rev_commit
*commit
, int strip
)
431 if (commit
->parent
&& !commit
->tail
)
432 if (!git_commit_recurse (head
, commit
->parent
, strip
))
434 ++git_current_commit
;
436 if (!git_commit (commit
))
438 for (t
= all_tags
; t
; t
= t
->next
)
439 if (t
->commit
== commit
)
440 if (!git_tag (commit
, t
->name
))
446 git_head_commit (rev_ref
*head
, int strip
)
448 git_current_head
= head
->name
;
450 if (!git_commit_recurse (head
, head
->commit
, strip
))
452 if (!git_head (head
->commit
, head
->name
))
458 git_ncommit (rev_list
*rl
)
464 for (h
= rl
->heads
; h
; h
= h
->next
) {
467 for (c
= h
->commit
; c
; c
= c
->parent
) {
477 git_rev_list_commit (rev_list
*rl
, int strip
)
481 git_load_author_map ("Authors");
482 git_total_commits
= git_ncommit (rl
);
483 git_current_commit
= 0;
484 for (h
= rl
->heads
; h
; h
= h
->next
)
485 if (!git_head_commit (h
, strip
))
487 fprintf (STATUS
, "\n");
488 // if (!git_checkout ("master"))
496 git_start_pack (void)
498 char *pack_file
= git_cvs_file ("pack");
500 packf
= fopen (pack_file
, "w");
507 git_file_pack (rev_file
*file
, int strip
)
509 char filename
[MAXPATHLEN
+ 1];
511 if (!git_filename (file
, filename
, strip
))
513 fprintf (packf
, "%s %s\n", file
->sha1
, filename
);
516 extern void reprepare_packed_git (void);
519 git_end_pack (char *pack_file
, char *pack_dir
)
523 char *src_pack_pack
, *src_pack_idx
;
524 char *dst_pack_pack
, *dst_pack_idx
;
526 if (fclose (packf
) == EOF
)
528 command
= git_format_command ("git pack-objects -q --non-empty .tmp-pack < '%s'",
534 pack_name
= git_system_to_string (command
);
539 fprintf (STATUS
, "Pack pack-%s created\n", pack_name
);
541 src_pack_pack
= git_format_command (".tmp-pack-%s.pack", pack_name
);
542 src_pack_idx
= git_format_command (".tmp-pack-%s.idx", pack_name
);
543 dst_pack_pack
= git_format_command ("%s/pack-%s.pack", pack_dir
, pack_name
);
544 dst_pack_idx
= git_format_command ("%s/pack-%s.idx", pack_dir
, pack_name
);
545 if (!src_pack_pack
|| !src_pack_idx
||
546 !dst_pack_pack
|| !dst_pack_idx
)
548 if (src_pack_pack
) free (src_pack_pack
);
549 if (src_pack_idx
) free (src_pack_idx
);
550 if (dst_pack_pack
) free (dst_pack_pack
);
551 if (dst_pack_idx
) free (dst_pack_idx
);
554 if (rename (src_pack_pack
, dst_pack_pack
) == -1 ||
555 rename (src_pack_idx
, dst_pack_idx
) == -1)
557 free (src_pack_pack
);
559 free (dst_pack_pack
);
562 (void) git_system ("git prune-packed");
563 reprepare_packed_git ();
567 git_pack_directory (void)
569 static char *pack_dir
;
576 git_dir
= git_system_to_string ("git rev-parse --git-dir");
579 objects_dir
= git_format_command ("%s/objects", git_dir
);
582 if (access (objects_dir
, F_OK
) == -1 &&
583 mkdir (objects_dir
, 0777) == -1)
589 pack_dir
= git_format_command ("%s/objects/pack", git_dir
);
592 if (access (pack_dir
, F_OK
) == -1 &&
593 mkdir (pack_dir
, 0777) == -1)
603 git_rev_list_pack (rev_list
*rl
, int strip
)
608 pack_dir
= git_pack_directory ();
611 pack_file
= git_start_pack ();
619 for (h
= rl
->heads
; h
; h
= h
->next
) {
622 for (c
= h
->commit
; c
; c
= c
->parent
) {
624 git_file_pack (c
->file
, strip
);
631 git_end_pack (pack_file
, pack_dir
);