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 * cvs2git --cvsroot=[root] --module=[module] > script
33 * Creates a shell script that will generate the .git archive of
34 * the names CVS repository.
36 * IMPORTANT NOTE ABOUT "cvsps"! This requires version 2.1 or better,
37 * and the "TZ=UTC" and the "-A" flag is required for sane results!
45 static const char *cvsroot
;
46 static const char *cvsmodule
;
48 static char date
[100];
49 static char author
[100];
50 static char branch
[100];
51 static char ancestor
[100];
53 static char log
[32768];
54 static int loglen
= 0;
55 static int initial_commit
= 1;
57 static void lookup_author(char *n
, char **name
, char **email
)
60 * FIXME!!! I'm lazy and stupid.
62 * This could be something like
64 * printf("lookup_author '%s'\n", n);
65 * *name = "$author_name";
66 * *email = "$author_email";
68 * and that would allow the script to do its own
69 * lookups at run-time.
75 static void prepare_commit(void)
77 char *author_name
, *author_email
;
80 lookup_author(author
, &author_name
, &author_email
);
82 printf("export GIT_COMMITTER_NAME=%s\n", author_name
);
83 printf("export GIT_COMMITTER_EMAIL=%s\n", author_email
);
84 printf("export GIT_COMMITTER_DATE='+0000 %s'\n", date
);
86 printf("export GIT_AUTHOR_NAME=%s\n", author_name
);
87 printf("export GIT_AUTHOR_EMAIL=%s\n", author_email
);
88 printf("export GIT_AUTHOR_DATE='+0000 %s'\n", date
);
93 src_branch
= *ancestor
? ancestor
: branch
;
94 if (!strcmp(src_branch
, "HEAD"))
95 src_branch
= "master";
96 printf("ln -sf refs/heads/'%s' .git/HEAD\n", src_branch
);
99 * Even if cvsps claims an ancestor, we'll let the new
100 * branch name take precedence if it already exists
104 if (!strcmp(src_branch
, "HEAD"))
105 src_branch
= "master";
106 printf("[ -e .git/refs/heads/'%s' ] && ln -sf refs/heads/'%s' .git/HEAD\n",
107 src_branch
, src_branch
);
110 printf("git-read-tree -m HEAD || exit 1\n");
111 printf("git-checkout-cache -f -u -a\n");
114 static void commit(void)
116 const char *cmit_parent
= initial_commit
? "" : "-p HEAD";
117 const char *dst_branch
;
121 printf("tree=$(git-write-tree)\n");
122 printf("cat > .cmitmsg <<EOFMSG\n");
124 /* Escape $ characters, and remove control characters */
125 for (i
= 0; i
< loglen
; i
++) {
126 unsigned char c
= log
[i
];
135 if (c
== '\n' || c
== '\t')
142 printf("\nEOFMSG\n");
143 printf("commit=$(cat .cmitmsg | git-commit-tree $tree %s)\n", cmit_parent
);
146 if (!strcmp(dst_branch
, "HEAD"))
147 dst_branch
= "master";
149 printf("echo $commit > .git/refs/heads/'%s'\n", dst_branch
);
151 space
= strchr(tag
, ' ');
154 if (strcmp(tag
, "(none)"))
155 printf("echo $commit > .git/refs/tags/'%s'\n", tag
);
157 printf("echo 'Committed (to %s):' ; cat .cmitmsg; echo\n", dst_branch
);
169 static void update_file(char *line
)
171 char *name
, *version
;
174 while (isspace(*line
))
177 line
= strchr(line
, ':');
181 line
= strchr(line
, '>');
186 line
= strchr(line
, '(');
187 if (line
) { /* "(DEAD)" */
188 printf("git-update-cache --force-remove '%s'\n", name
);
192 dir
= strrchr(name
, '/');
194 printf("mkdir -p %.*s\n", (int)(dir
- name
), name
);
196 printf("cvs -q -d %s checkout -d .git-tmp -r%s '%s/%s'\n",
197 cvsroot
, version
, cvsmodule
, name
);
198 printf("mv -f .git-tmp/%s %s\n", dir
? dir
+1 : name
, name
);
199 printf("rm -rf .git-tmp\n");
200 printf("git-update-cache --add -- '%s'\n", name
);
208 { "Author:", author
},
209 { "Branch:", branch
},
210 { "Ancestor branch:", ancestor
},
216 int main(int argc
, char **argv
)
218 static char line
[1000];
219 enum state state
= Header
;
222 for (i
= 1; i
< argc
; i
++) {
223 const char *arg
= argv
[i
];
224 if (!memcmp(arg
, "--cvsroot=", 10)) {
228 if (!memcmp(arg
, "--module=", 9)) {
232 if (!strcmp(arg
, "-v")) {
240 cvsroot
= getenv("CVSROOT");
242 if (!cvsmodule
|| !cvsroot
) {
243 fprintf(stderr
, "I need a CVSROOT and module name\n");
247 printf("[ -d .git ] && exit 1\n");
248 printf("git-init-db\n");
249 printf("mkdir -p .git/refs/heads\n");
250 printf("mkdir -p .git/refs/tags\n");
251 printf("ln -sf refs/heads/master .git/HEAD\n");
253 while (fgets(line
, sizeof(line
), stdin
) != NULL
) {
254 int linelen
= strlen(line
);
256 while (linelen
&& isspace(line
[linelen
-1]))
260 struct hdrentry
*entry
;
264 printf("# H: %s\n", line
);
265 for (entry
= hdrs
; entry
->name
; entry
++) {
266 int len
= strlen(entry
->name
);
269 if (memcmp(entry
->name
, line
, len
))
277 while (isspace(*val
)) {
281 memcpy(entry
->dest
, val
, linelen
+1);
288 printf("# L: %s\n", line
);
289 if (!strcmp(line
, "Members:")) {
290 while (loglen
&& isspace(log
[loglen
-1]))
297 if (loglen
+ linelen
+ 5 > sizeof(log
))
299 memcpy(log
+ loglen
, line
, linelen
);
301 log
[loglen
++] = '\n';
306 printf("# M: %s\n", line
);