Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

remote-svn: add incremental import

Search for a note attached to the ref to update and read it's
'Revision-number:'-line. Start import from the next svn revision.

If there is no next revision in the svn repo, svnrdump terminates with
a message on stderr an non-zero return value. This looks a little
weird, but there is no other way to know whether there is a new
revision in the svn repo.

On the start of an incremental import, the parent of the first commit
in the fast-import stream is set to the branch name to update. All
following commits specify their parent by a mark number. Previous mark
files are currently not reused.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
Acked-by: David Michael Barr <b@rr-dav.id.au>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information...
commit 8e43a1d010e22a0e432de440b08cc4389d8370f9 1 parent 8d7cd8e
flyingflo authored September 19, 2012 gitster committed October 07, 2012
3  contrib/svn-fe/svn-fe.c
@@ -10,7 +10,8 @@ int main(int argc, char **argv)
10 10
 {
11 11
 	if (svndump_init(NULL))
12 12
 		return 1;
13  
-	svndump_read((argc > 1) ? argv[1] : NULL, "refs/heads/master");
  13
+	svndump_read((argc > 1) ? argv[1] : NULL, "refs/heads/master",
  14
+			"refs/notes/svn/revs");
14 15
 	svndump_deinit();
15 16
 	svndump_reset();
16 17
 	return 0;
79  remote-testsvn.c
@@ -12,7 +12,8 @@ static const char *url;
12 12
 static int dump_from_file;
13 13
 static const char *private_ref;
14 14
 static const char *remote_ref = "refs/heads/master";
15  
-static const char *marksfilename;
  15
+static const char *marksfilename, *notes_ref;
  16
+struct rev_note { unsigned int rev_nr; };
16 17
 
17 18
 static int cmd_capabilities(const char *line);
18 19
 static int cmd_import(const char *line);
@@ -48,14 +49,79 @@ static void terminate_batch(void)
48 49
 	fflush(stdout);
49 50
 }
50 51
 
  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])
  54
+{
  55
+	const unsigned char *note_sha1;
  56
+	char *msg = NULL;
  57
+	unsigned long msglen;
  58
+	enum object_type type;
  59
+
  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);
  68
+		free(msg);
  69
+		msg = NULL;
  70
+	}
  71
+	free_notes(NULL);
  72
+	return msg;
  73
+}
  74
+
  75
+static int parse_rev_note(const char *msg, struct rev_note *res)
  76
+{
  77
+	const char *key, *value, *end;
  78
+	size_t len;
  79
+
  80
+	while (*msg) {
  81
+		end = strchr(msg, '\n');
  82
+		len = end ? end - msg : strlen(msg);
  83
+
  84
+		key = "Revision-number: ";
  85
+		if (!prefixcmp(msg, key)) {
  86
+			long i;
  87
+			char *end;
  88
+			value = msg + strlen(key);
  89
+			i = strtol(value, &end, 0);
  90
+			if (end == value || i < 0 || i > UINT32_MAX)
  91
+				return -1;
  92
+			res->rev_nr = i;
  93
+		}
  94
+		msg += len + 1;
  95
+	}
  96
+	return 0;
  97
+}
  98
+
51 99
 static int cmd_import(const char *line)
52 100
 {
53 101
 	int code;
54 102
 	int dumpin_fd;
55  
-	unsigned int startrev = 0;
  103
+	char *note_msg;
  104
+	unsigned char head_sha1[20];
  105
+	unsigned int startrev;
56 106
 	struct argv_array svndump_argv = ARGV_ARRAY_INIT;
57 107
 	struct child_process svndump_proc;
58 108
 
  109
+	if (read_ref(private_ref, head_sha1))
  110
+		startrev = 0;
  111
+	else {
  112
+		note_msg = read_ref_note(head_sha1);
  113
+		if(note_msg == NULL) {
  114
+			warning("No note found for %s.", private_ref);
  115
+			startrev = 0;
  116
+		} else {
  117
+			struct rev_note note = { 0 };
  118
+			if (parse_rev_note(note_msg, &note))
  119
+				die("Revision number couldn't be parsed from note.");
  120
+			startrev = note.rev_nr + 1;
  121
+			free(note_msg);
  122
+		}
  123
+	}
  124
+
59 125
 	if (dump_from_file) {
60 126
 		dumpin_fd = open(url, O_RDONLY);
61 127
 		if(dumpin_fd < 0)
@@ -79,7 +145,7 @@ static int cmd_import(const char *line)
79 145
 			"feature export-marks=%s\n", marksfilename, marksfilename);
80 146
 
81 147
 	svndump_init_fd(dumpin_fd, STDIN_FILENO);
82  
-	svndump_read(url, private_ref);
  148
+	svndump_read(url, private_ref, notes_ref);
83 149
 	svndump_deinit();
84 150
 	svndump_reset();
85 151
 
@@ -150,7 +216,8 @@ static int do_command(struct strbuf *line)
150 216
 int main(int argc, const char **argv)
151 217
 {
152 218
 	struct strbuf buf = STRBUF_INIT, url_sb = STRBUF_INIT,
153  
-			private_ref_sb = STRBUF_INIT, marksfilename_sb = STRBUF_INIT;
  219
+			private_ref_sb = STRBUF_INIT, marksfilename_sb = STRBUF_INIT,
  220
+			notes_ref_sb = STRBUF_INIT;
154 221
 	static struct remote *remote;
155 222
 	const char *url_in;
156 223
 
@@ -176,6 +243,9 @@ int main(int argc, const char **argv)
176 243
 	strbuf_addf(&private_ref_sb, "refs/svn/%s/master", remote->name);
177 244
 	private_ref = private_ref_sb.buf;
178 245
 
  246
+	strbuf_addf(&notes_ref_sb, "refs/notes/%s/revs", remote->name);
  247
+	notes_ref = notes_ref_sb.buf;
  248
+
179 249
 	strbuf_addf(&marksfilename_sb, "%s/info/fast-import/remote-svn/%s.marks",
180 250
 		get_git_dir(), remote->name);
181 251
 	marksfilename = marksfilename_sb.buf;
@@ -195,6 +265,7 @@ int main(int argc, const char **argv)
195 265
 	strbuf_release(&buf);
196 266
 	strbuf_release(&url_sb);
197 267
 	strbuf_release(&private_ref_sb);
  268
+	strbuf_release(&notes_ref_sb);
198 269
 	strbuf_release(&marksfilename_sb);
199 270
 	return 0;
200 271
 }
2  test-svn-fe.c
@@ -40,7 +40,7 @@ int main(int argc, char *argv[])
40 40
 	if (argc == 2) {
41 41
 		if (svndump_init(argv[1]))
42 42
 			return 1;
43  
-		svndump_read(NULL, "refs/heads/master");
  43
+		svndump_read(NULL, "refs/heads/master", "refs/notes/svn/revs");
44 44
 		svndump_deinit();
45 45
 		svndump_reset();
46 46
 		return 0;
10  vcs-svn/fast_export.c
@@ -68,13 +68,19 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)
68 68
 }
69 69
 
70 70
 void fast_export_begin_note(uint32_t revision, const char *author,
71  
-		const char *log, unsigned long timestamp)
  71
+		const char *log, unsigned long timestamp, const char *note_ref)
72 72
 {
  73
+	static int firstnote = 1;
73 74
 	size_t loglen = strlen(log);
74  
-	printf("commit refs/notes/svn/revs\n");
  75
+	printf("commit %s\n", note_ref);
75 76
 	printf("committer %s <%s@%s> %ld +0000\n", author, author, "local", timestamp);
76 77
 	printf("data %"PRIuMAX"\n", (uintmax_t)loglen);
77 78
 	fwrite(log, loglen, 1, stdout);
  79
+	if (firstnote) {
  80
+		if (revision > 1)
  81
+			printf("from %s^0", note_ref);
  82
+		firstnote = 0;
  83
+	}
78 84
 	fputc('\n', stdout);
79 85
 }
80 86
 
6  vcs-svn/fast_export.h
@@ -11,10 +11,10 @@ void fast_export_delete(const char *path);
11 11
 void fast_export_modify(const char *path, uint32_t mode, const char *dataref);
12 12
 void fast_export_note(const char *committish, const char *dataref);
13 13
 void fast_export_begin_note(uint32_t revision, const char *author,
14  
-		const char *log, unsigned long timestamp);
  14
+		const char *log, unsigned long timestamp, const char *note_ref);
15 15
 void fast_export_begin_commit(uint32_t revision, const char *author,
16  
-			const struct strbuf *log, const char *uuid,
17  
-			const char *url, unsigned long timestamp, const char *local_ref);
  16
+			const struct strbuf *log, const char *uuid,const char *url,
  17
+			unsigned long timestamp, const char *local_ref);
18 18
 void fast_export_end_commit(uint32_t revision);
19 19
 void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input);
20 20
 void fast_export_buf_to_data(const struct strbuf *data);
10  vcs-svn/svndump.c
@@ -309,20 +309,20 @@ static void begin_revision(const char *remote_ref)
309 309
 		rev_ctx.timestamp, remote_ref);
310 310
 }
311 311
 
312  
-static void end_revision(void)
  312
+static void end_revision(const char *note_ref)
313 313
 {
314 314
 	struct strbuf mark = STRBUF_INIT;
315 315
 	if (rev_ctx.revision) {
316 316
 		fast_export_end_commit(rev_ctx.revision);
317 317
 		fast_export_begin_note(rev_ctx.revision, "remote-svn",
318  
-				"Note created by remote-svn.", rev_ctx.timestamp);
  318
+				"Note created by remote-svn.", rev_ctx.timestamp, note_ref);
319 319
 		strbuf_addf(&mark, ":%"PRIu32, rev_ctx.revision);
320 320
 		fast_export_note(mark.buf, "inline");
321 321
 		fast_export_buf_to_data(&rev_ctx.note);
322 322
 	}
323 323
 }
324 324
 
325  
-void svndump_read(const char *url, const char *local_ref)
  325
+void svndump_read(const char *url, const char *local_ref, const char *notes_ref)
326 326
 {
327 327
 	char *val;
328 328
 	char *t;
@@ -363,7 +363,7 @@ void svndump_read(const char *url, const char *local_ref)
363 363
 			if (active_ctx == REV_CTX)
364 364
 				begin_revision(local_ref);
365 365
 			if (active_ctx != DUMP_CTX)
366  
-				end_revision();
  366
+				end_revision(notes_ref);
367 367
 			active_ctx = REV_CTX;
368 368
 			reset_rev_ctx(atoi(val));
369 369
 			strbuf_addf(&rev_ctx.note, "%s\n", t);
@@ -479,7 +479,7 @@ void svndump_read(const char *url, const char *local_ref)
479 479
 	if (active_ctx == REV_CTX)
480 480
 		begin_revision(local_ref);
481 481
 	if (active_ctx != DUMP_CTX)
482  
-		end_revision();
  482
+		end_revision(notes_ref);
483 483
 }
484 484
 
485 485
 static void init(int report_fd)
2  vcs-svn/svndump.h
@@ -3,7 +3,7 @@
3 3
 
4 4
 int svndump_init(const char *filename);
5 5
 int svndump_init_fd(int in_fd, int back_fd);
6  
-void svndump_read(const char *url, const char *local_ref);
  6
+void svndump_read(const char *url, const char *local_ref, const char *notes_ref);
7 7
 void svndump_deinit(void);
8 8
 void svndump_reset(void);
9 9
 

0 notes on commit 8e43a1d

Please sign in to comment.
Something went wrong with that request. Please try again.