4 * Copyright (C) Linus Torvalds 2005
13 static int verbose
= 0;
16 * This is a really stupid program that takes cvsps output, and
17 * generates a a long _shell_script_ that will create the GIT archive
20 * You've been warned. I told you it was stupid.
22 * NOTE NOTE NOTE! In order to do branches correctly, this needs
23 * the fixed cvsps that has the "Ancestor branch" tag output.
24 * Hopefully David Mansfield will update his distribution soon
25 * enough (he's the one who wrote the patch, so at least we don't
26 * have to figt maintainer issues ;)
31 * git-cvs2git --cvsroot=[root] --module=[module] > script
33 * Creates a shell script that will generate the .git archive of
34 * the names CVS repository.
36 * TZ=UTC cvsps -s 1234- -A |
37 * git-cvs2git -u --cvsroot=[root] --module=[module] > script
39 * Creates a shell script that will update the .git archive with
40 * CVS changes from patchset 1234 until the last one.
42 * IMPORTANT NOTE ABOUT "cvsps"! This requires version 2.1 or better,
43 * and the "TZ=UTC" and the "-A" flag is required for sane results!
51 static const char *cvsroot
;
52 static const char *cvsmodule
;
54 static char date
[100];
55 static char author
[100];
56 static char branch
[100];
57 static char ancestor
[100];
59 static char log
[32768];
60 static int loglen
= 0;
61 static int initial_commit
= 1;
63 static void lookup_author(char *n
, char **name
, char **email
)
66 * FIXME!!! I'm lazy and stupid.
68 * This could be something like
70 * printf("lookup_author '%s'\n", n);
71 * *name = "$author_name";
72 * *email = "$author_email";
74 * and that would allow the script to do its own
75 * lookups at run-time.
81 static void prepare_commit(void)
83 char *author_name
, *author_email
;
86 lookup_author(author
, &author_name
, &author_email
);
88 printf("export GIT_COMMITTER_NAME=%s\n", author_name
);
89 printf("export GIT_COMMITTER_EMAIL=%s\n", author_email
);
90 printf("export GIT_COMMITTER_DATE='+0000 %s'\n", date
);
92 printf("export GIT_AUTHOR_NAME=%s\n", author_name
);
93 printf("export GIT_AUTHOR_EMAIL=%s\n", author_email
);
94 printf("export GIT_AUTHOR_DATE='+0000 %s'\n", date
);
99 src_branch
= *ancestor
? ancestor
: branch
;
100 if (!strcmp(src_branch
, "HEAD"))
101 src_branch
= "master";
102 printf("ln -sf refs/heads/'%s' .git/HEAD\n", src_branch
);
105 * Even if cvsps claims an ancestor, we'll let the new
106 * branch name take precedence if it already exists
110 if (!strcmp(src_branch
, "HEAD"))
111 src_branch
= "master";
112 printf("[ -e .git/refs/heads/'%s' ] && ln -sf refs/heads/'%s' .git/HEAD\n",
113 src_branch
, src_branch
);
116 printf("git-read-tree -m HEAD || exit 1\n");
117 printf("git-checkout-cache -f -u -a\n");
120 static void commit(void)
122 const char *cmit_parent
= initial_commit
? "" : "-p HEAD";
123 const char *dst_branch
;
127 printf("tree=$(git-write-tree)\n");
128 printf("cat > .cmitmsg <<EOFMSG\n");
130 /* Escape $ characters, and remove control characters */
131 for (i
= 0; i
< loglen
; i
++) {
132 unsigned char c
= log
[i
];
141 if (c
== '\n' || c
== '\t')
148 printf("\nEOFMSG\n");
149 printf("commit=$(cat .cmitmsg | git-commit-tree $tree %s)\n", cmit_parent
);
152 if (!strcmp(dst_branch
, "HEAD"))
153 dst_branch
= "master";
155 printf("echo $commit > .git/refs/heads/'%s'\n", dst_branch
);
157 space
= strchr(tag
, ' ');
160 if (strcmp(tag
, "(none)"))
161 printf("echo $commit > .git/refs/tags/'%s'\n", tag
);
163 printf("echo 'Committed (to %s):' ; cat .cmitmsg; echo\n", dst_branch
);
175 static void update_file(char *line
)
177 char *name
, *version
;
180 while (isspace(*line
))
183 line
= strchr(line
, ':');
187 line
= strchr(line
, '>');
192 line
= strchr(line
, '(');
193 if (line
) { /* "(DEAD)" */
194 printf("git-update-cache --force-remove '%s'\n", name
);
198 dir
= strrchr(name
, '/');
200 printf("mkdir -p %.*s\n", (int)(dir
- name
), name
);
202 printf("cvs -q -d %s checkout -d .git-tmp -r%s '%s/%s'\n",
203 cvsroot
, version
, cvsmodule
, name
);
204 printf("mv -f .git-tmp/%s %s\n", dir
? dir
+1 : name
, name
);
205 printf("rm -rf .git-tmp\n");
206 printf("git-update-cache --add -- '%s'\n", name
);
209 static struct hdrentry
{
214 { "Author:", author
},
215 { "Branch:", branch
},
216 { "Ancestor branch:", ancestor
},
222 int main(int argc
, char **argv
)
224 static char line
[1000];
225 enum state state
= Header
;
228 for (i
= 1; i
< argc
; i
++) {
229 const char *arg
= argv
[i
];
230 if (!memcmp(arg
, "--cvsroot=", 10)) {
234 if (!memcmp(arg
, "--module=", 9)) {
238 if (!strcmp(arg
, "-v")) {
242 if (!strcmp(arg
, "-u")) {
250 cvsroot
= getenv("CVSROOT");
252 if (!cvsmodule
|| !cvsroot
) {
253 fprintf(stderr
, "I need a CVSROOT and module name\n");
257 if (initial_commit
) {
258 printf("[ -d .git ] && exit 1\n");
259 printf("git-init-db\n");
260 printf("mkdir -p .git/refs/heads\n");
261 printf("mkdir -p .git/refs/tags\n");
262 printf("ln -sf refs/heads/master .git/HEAD\n");
265 while (fgets(line
, sizeof(line
), stdin
) != NULL
) {
266 int linelen
= strlen(line
);
268 while (linelen
&& isspace(line
[linelen
-1]))
272 struct hdrentry
*entry
;
276 printf("# H: %s\n", line
);
277 for (entry
= hdrs
; entry
->name
; entry
++) {
278 int len
= strlen(entry
->name
);
281 if (memcmp(entry
->name
, line
, len
))
289 while (isspace(*val
)) {
293 memcpy(entry
->dest
, val
, linelen
+1);
300 printf("# L: %s\n", line
);
301 if (!strcmp(line
, "Members:")) {
302 while (loglen
&& isspace(log
[loglen
-1]))
309 if (loglen
+ linelen
+ 5 > sizeof(log
))
311 memcpy(log
+ loglen
, line
, linelen
);
313 log
[loglen
++] = '\n';
318 printf("# M: %s\n", line
);