6 #include "run-command.h"
7 #include "vcs-svn/svndump.h"
9 #include "argv-array.h"
11 static const char *url
;
12 static int dump_from_file
;
13 static const char *private_ref
;
14 static const char *remote_ref
= "refs/heads/master";
15 static const char *marksfilename
, *notes_ref
;
16 struct rev_note
{ unsigned int rev_nr
; };
18 static int cmd_capabilities(const char *line
);
19 static int cmd_import(const char *line
);
20 static int cmd_list(const char *line
);
22 typedef int (*input_command_handler
)(const char *);
23 struct input_command_entry
{
25 input_command_handler fn
;
26 unsigned char batchable
; /* whether the command starts or is part of a batch */
29 static const struct input_command_entry input_command_list
[] = {
30 { "capabilities", cmd_capabilities
, 0 },
31 { "import", cmd_import
, 1 },
32 { "list", cmd_list
, 0 },
36 static int cmd_capabilities(const char *line
)
39 printf("bidi-import\n");
40 printf("refspec %s:%s\n\n", remote_ref
, private_ref
);
45 static void terminate_batch(void)
47 /* terminate a current batch's fast-import stream */
52 /* NOTE: 'ref' refers to a git reference, while 'rev' refers to a svn revision. */
53 static char *read_ref_note(const unsigned char sha1
[20])
55 const unsigned char *note_sha1
;
58 enum object_type type
;
60 init_notes(NULL
, notes_ref
, NULL
, 0);
61 if (!(note_sha1
= get_note(NULL
, sha1
)))
62 return NULL
; /* note tree not found */
63 if (!(msg
= read_sha1_file(note_sha1
, &type
, &msglen
)))
64 error("Empty notes tree. %s", notes_ref
);
65 else if (!msglen
|| type
!= OBJ_BLOB
) {
66 error("Note contains unusable content. "
67 "Is something else using this notes tree? %s", notes_ref
);
75 static int parse_rev_note(const char *msg
, struct rev_note
*res
)
77 const char *key
, *value
, *end
;
81 end
= strchr(msg
, '\n');
82 len
= end
? end
- msg
: strlen(msg
);
84 key
= "Revision-number: ";
85 if (!prefixcmp(msg
, key
)) {
88 value
= msg
+ strlen(key
);
89 i
= strtol(value
, &end
, 0);
90 if (end
== value
|| i
< 0 || i
> UINT32_MAX
)
99 static int cmd_import(const char *line
)
104 unsigned char head_sha1
[20];
105 unsigned int startrev
;
106 struct argv_array svndump_argv
= ARGV_ARRAY_INIT
;
107 struct child_process svndump_proc
;
109 if (read_ref(private_ref
, head_sha1
))
112 note_msg
= read_ref_note(head_sha1
);
113 if(note_msg
== NULL
) {
114 warning("No note found for %s.", private_ref
);
117 struct rev_note note
= { 0 };
118 if (parse_rev_note(note_msg
, ¬e
))
119 die("Revision number couldn't be parsed from note.");
120 startrev
= note
.rev_nr
+ 1;
125 if (dump_from_file
) {
126 dumpin_fd
= open(url
, O_RDONLY
);
128 die_errno("Couldn't open svn dump file %s.", url
);
130 memset(&svndump_proc
, 0, sizeof(struct child_process
));
131 svndump_proc
.out
= -1;
132 argv_array_push(&svndump_argv
, "svnrdump");
133 argv_array_push(&svndump_argv
, "dump");
134 argv_array_push(&svndump_argv
, url
);
135 argv_array_pushf(&svndump_argv
, "-r%u:HEAD", startrev
);
136 svndump_proc
.argv
= svndump_argv
.argv
;
138 code
= start_command(&svndump_proc
);
140 die("Unable to start %s, code %d", svndump_proc
.argv
[0], code
);
141 dumpin_fd
= svndump_proc
.out
;
143 /* setup marks file import/export */
144 printf("feature import-marks-if-exists=%s\n"
145 "feature export-marks=%s\n", marksfilename
, marksfilename
);
147 svndump_init_fd(dumpin_fd
, STDIN_FILENO
);
148 svndump_read(url
, private_ref
, notes_ref
);
153 if (!dump_from_file
) {
154 code
= finish_command(&svndump_proc
);
156 warning("%s, returned %d", svndump_proc
.argv
[0], code
);
157 argv_array_clear(&svndump_argv
);
163 static int cmd_list(const char *line
)
165 printf("? %s\n\n", remote_ref
);
170 static int do_command(struct strbuf
*line
)
172 const struct input_command_entry
*p
= input_command_list
;
173 static struct string_list batchlines
= STRING_LIST_INIT_DUP
;
174 static const struct input_command_entry
*batch_cmd
;
176 * commands can be grouped together in a batch.
177 * Batches are ended by \n. If no batch is active the program ends.
178 * During a batch all lines are buffered and passed to the handler function
179 * when the batch is terminated.
181 if (line
->len
== 0) {
183 struct string_list_item
*item
;
184 for_each_string_list_item(item
, &batchlines
)
185 batch_cmd
->fn(item
->string
);
188 string_list_clear(&batchlines
, 0);
189 return 0; /* end of the batch, continue reading other commands. */
191 return 1; /* end of command stream, quit */
194 if (prefixcmp(batch_cmd
->name
, line
->buf
))
195 die("Active %s batch interrupted by %s", batch_cmd
->name
, line
->buf
);
196 /* buffer batch lines */
197 string_list_append(&batchlines
, line
->buf
);
201 for (p
= input_command_list
; p
->name
; p
++) {
202 if (!prefixcmp(line
->buf
, p
->name
) && (strlen(p
->name
) == line
->len
||
203 line
->buf
[strlen(p
->name
)] == ' ')) {
206 string_list_append(&batchlines
, line
->buf
);
209 return p
->fn(line
->buf
);
212 die("Unknown command '%s'\n", line
->buf
);
216 int main(int argc
, const char **argv
)
218 struct strbuf buf
= STRBUF_INIT
, url_sb
= STRBUF_INIT
,
219 private_ref_sb
= STRBUF_INIT
, marksfilename_sb
= STRBUF_INIT
,
220 notes_ref_sb
= STRBUF_INIT
;
221 static struct remote
*remote
;
224 git_extract_argv0_path(argv
[0]);
225 setup_git_directory();
226 if (argc
< 2 || argc
> 3) {
227 usage("git-remote-svn <remote-name> [<url>]");
231 remote
= remote_get(argv
[1]);
232 url_in
= (argc
== 3) ? argv
[2] : remote
->url
[0];
234 if (!prefixcmp(url_in
, "file://")) {
236 url
= url_decode(url_in
+ sizeof("file://")-1);
239 end_url_with_slash(&url_sb
, url_in
);
243 strbuf_addf(&private_ref_sb
, "refs/svn/%s/master", remote
->name
);
244 private_ref
= private_ref_sb
.buf
;
246 strbuf_addf(¬es_ref_sb
, "refs/notes/%s/revs", remote
->name
);
247 notes_ref
= notes_ref_sb
.buf
;
249 strbuf_addf(&marksfilename_sb
, "%s/info/fast-import/remote-svn/%s.marks",
250 get_git_dir(), remote
->name
);
251 marksfilename
= marksfilename_sb
.buf
;
254 if (strbuf_getline(&buf
, stdin
, '\n') == EOF
) {
256 die("Error reading command stream");
258 die("Unexpected end of command stream");
260 if (do_command(&buf
))
265 strbuf_release(&buf
);
266 strbuf_release(&url_sb
);
267 strbuf_release(&private_ref_sb
);
268 strbuf_release(¬es_ref_sb
);
269 strbuf_release(&marksfilename_sb
);