Skip to content

Commit

Permalink
remote-svn: add incremental import
Browse files Browse the repository at this point in the history
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
flyingflo authored and gitster committed Oct 7, 2012
1 parent 8d7cd8e commit 8e43a1d
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 17 deletions.
3 changes: 2 additions & 1 deletion contrib/svn-fe/svn-fe.c
Expand Up @@ -10,7 +10,8 @@ int main(int argc, char **argv)
{ {
if (svndump_init(NULL)) if (svndump_init(NULL))
return 1; return 1;
svndump_read((argc > 1) ? argv[1] : NULL, "refs/heads/master"); svndump_read((argc > 1) ? argv[1] : NULL, "refs/heads/master",
"refs/notes/svn/revs");
svndump_deinit(); svndump_deinit();
svndump_reset(); svndump_reset();
return 0; return 0;
Expand Down
79 changes: 75 additions & 4 deletions remote-testsvn.c
Expand Up @@ -12,7 +12,8 @@ static const char *url;
static int dump_from_file; static int dump_from_file;
static const char *private_ref; static const char *private_ref;
static const char *remote_ref = "refs/heads/master"; static const char *remote_ref = "refs/heads/master";
static const char *marksfilename; static const char *marksfilename, *notes_ref;
struct rev_note { unsigned int rev_nr; };


static int cmd_capabilities(const char *line); static int cmd_capabilities(const char *line);
static int cmd_import(const char *line); static int cmd_import(const char *line);
Expand Down Expand Up @@ -48,14 +49,79 @@ static void terminate_batch(void)
fflush(stdout); fflush(stdout);
} }


/* NOTE: 'ref' refers to a git reference, while 'rev' refers to a svn revision. */
static char *read_ref_note(const unsigned char sha1[20])
{
const unsigned char *note_sha1;
char *msg = NULL;
unsigned long msglen;
enum object_type type;

init_notes(NULL, notes_ref, NULL, 0);
if (!(note_sha1 = get_note(NULL, sha1)))
return NULL; /* note tree not found */
if (!(msg = read_sha1_file(note_sha1, &type, &msglen)))
error("Empty notes tree. %s", notes_ref);
else if (!msglen || type != OBJ_BLOB) {
error("Note contains unusable content. "
"Is something else using this notes tree? %s", notes_ref);
free(msg);
msg = NULL;
}
free_notes(NULL);
return msg;
}

static int parse_rev_note(const char *msg, struct rev_note *res)
{
const char *key, *value, *end;
size_t len;

while (*msg) {
end = strchr(msg, '\n');
len = end ? end - msg : strlen(msg);

key = "Revision-number: ";
if (!prefixcmp(msg, key)) {
long i;
char *end;
value = msg + strlen(key);
i = strtol(value, &end, 0);
if (end == value || i < 0 || i > UINT32_MAX)
return -1;
res->rev_nr = i;
}
msg += len + 1;
}
return 0;
}

static int cmd_import(const char *line) static int cmd_import(const char *line)
{ {
int code; int code;
int dumpin_fd; int dumpin_fd;
unsigned int startrev = 0; char *note_msg;
unsigned char head_sha1[20];
unsigned int startrev;
struct argv_array svndump_argv = ARGV_ARRAY_INIT; struct argv_array svndump_argv = ARGV_ARRAY_INIT;
struct child_process svndump_proc; struct child_process svndump_proc;


if (read_ref(private_ref, head_sha1))
startrev = 0;
else {
note_msg = read_ref_note(head_sha1);
if(note_msg == NULL) {
warning("No note found for %s.", private_ref);
startrev = 0;
} else {
struct rev_note note = { 0 };
if (parse_rev_note(note_msg, &note))
die("Revision number couldn't be parsed from note.");
startrev = note.rev_nr + 1;
free(note_msg);
}
}

if (dump_from_file) { if (dump_from_file) {
dumpin_fd = open(url, O_RDONLY); dumpin_fd = open(url, O_RDONLY);
if(dumpin_fd < 0) if(dumpin_fd < 0)
Expand All @@ -79,7 +145,7 @@ static int cmd_import(const char *line)
"feature export-marks=%s\n", marksfilename, marksfilename); "feature export-marks=%s\n", marksfilename, marksfilename);


svndump_init_fd(dumpin_fd, STDIN_FILENO); svndump_init_fd(dumpin_fd, STDIN_FILENO);
svndump_read(url, private_ref); svndump_read(url, private_ref, notes_ref);
svndump_deinit(); svndump_deinit();
svndump_reset(); svndump_reset();


Expand Down Expand Up @@ -150,7 +216,8 @@ static int do_command(struct strbuf *line)
int main(int argc, const char **argv) int main(int argc, const char **argv)
{ {
struct strbuf buf = STRBUF_INIT, url_sb = STRBUF_INIT, struct strbuf buf = STRBUF_INIT, url_sb = STRBUF_INIT,
private_ref_sb = STRBUF_INIT, marksfilename_sb = STRBUF_INIT; private_ref_sb = STRBUF_INIT, marksfilename_sb = STRBUF_INIT,
notes_ref_sb = STRBUF_INIT;
static struct remote *remote; static struct remote *remote;
const char *url_in; const char *url_in;


Expand All @@ -176,6 +243,9 @@ int main(int argc, const char **argv)
strbuf_addf(&private_ref_sb, "refs/svn/%s/master", remote->name); strbuf_addf(&private_ref_sb, "refs/svn/%s/master", remote->name);
private_ref = private_ref_sb.buf; private_ref = private_ref_sb.buf;


strbuf_addf(&notes_ref_sb, "refs/notes/%s/revs", remote->name);
notes_ref = notes_ref_sb.buf;

strbuf_addf(&marksfilename_sb, "%s/info/fast-import/remote-svn/%s.marks", strbuf_addf(&marksfilename_sb, "%s/info/fast-import/remote-svn/%s.marks",
get_git_dir(), remote->name); get_git_dir(), remote->name);
marksfilename = marksfilename_sb.buf; marksfilename = marksfilename_sb.buf;
Expand All @@ -195,6 +265,7 @@ int main(int argc, const char **argv)
strbuf_release(&buf); strbuf_release(&buf);
strbuf_release(&url_sb); strbuf_release(&url_sb);
strbuf_release(&private_ref_sb); strbuf_release(&private_ref_sb);
strbuf_release(&notes_ref_sb);
strbuf_release(&marksfilename_sb); strbuf_release(&marksfilename_sb);
return 0; return 0;
} }
2 changes: 1 addition & 1 deletion test-svn-fe.c
Expand Up @@ -40,7 +40,7 @@ int main(int argc, char *argv[])
if (argc == 2) { if (argc == 2) {
if (svndump_init(argv[1])) if (svndump_init(argv[1]))
return 1; return 1;
svndump_read(NULL, "refs/heads/master"); svndump_read(NULL, "refs/heads/master", "refs/notes/svn/revs");
svndump_deinit(); svndump_deinit();
svndump_reset(); svndump_reset();
return 0; return 0;
Expand Down
10 changes: 8 additions & 2 deletions vcs-svn/fast_export.c
Expand Up @@ -68,13 +68,19 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)
} }


void fast_export_begin_note(uint32_t revision, const char *author, void fast_export_begin_note(uint32_t revision, const char *author,
const char *log, unsigned long timestamp) const char *log, unsigned long timestamp, const char *note_ref)
{ {
static int firstnote = 1;
size_t loglen = strlen(log); size_t loglen = strlen(log);
printf("commit refs/notes/svn/revs\n"); printf("commit %s\n", note_ref);
printf("committer %s <%s@%s> %ld +0000\n", author, author, "local", timestamp); printf("committer %s <%s@%s> %ld +0000\n", author, author, "local", timestamp);
printf("data %"PRIuMAX"\n", (uintmax_t)loglen); printf("data %"PRIuMAX"\n", (uintmax_t)loglen);
fwrite(log, loglen, 1, stdout); fwrite(log, loglen, 1, stdout);
if (firstnote) {
if (revision > 1)
printf("from %s^0", note_ref);
firstnote = 0;
}
fputc('\n', stdout); fputc('\n', stdout);
} }


Expand Down
6 changes: 3 additions & 3 deletions vcs-svn/fast_export.h
Expand Up @@ -11,10 +11,10 @@ void fast_export_delete(const char *path);
void fast_export_modify(const char *path, uint32_t mode, const char *dataref); void fast_export_modify(const char *path, uint32_t mode, const char *dataref);
void fast_export_note(const char *committish, const char *dataref); void fast_export_note(const char *committish, const char *dataref);
void fast_export_begin_note(uint32_t revision, const char *author, void fast_export_begin_note(uint32_t revision, const char *author,
const char *log, unsigned long timestamp); const char *log, unsigned long timestamp, const char *note_ref);
void fast_export_begin_commit(uint32_t revision, const char *author, void fast_export_begin_commit(uint32_t revision, const char *author,
const struct strbuf *log, const char *uuid, const struct strbuf *log, const char *uuid,const char *url,
const char *url, unsigned long timestamp, const char *local_ref); unsigned long timestamp, const char *local_ref);
void fast_export_end_commit(uint32_t revision); void fast_export_end_commit(uint32_t revision);
void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input); void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input);
void fast_export_buf_to_data(const struct strbuf *data); void fast_export_buf_to_data(const struct strbuf *data);
Expand Down
10 changes: 5 additions & 5 deletions vcs-svn/svndump.c
Expand Up @@ -309,20 +309,20 @@ static void begin_revision(const char *remote_ref)
rev_ctx.timestamp, remote_ref); rev_ctx.timestamp, remote_ref);
} }


static void end_revision(void) static void end_revision(const char *note_ref)
{ {
struct strbuf mark = STRBUF_INIT; struct strbuf mark = STRBUF_INIT;
if (rev_ctx.revision) { if (rev_ctx.revision) {
fast_export_end_commit(rev_ctx.revision); fast_export_end_commit(rev_ctx.revision);
fast_export_begin_note(rev_ctx.revision, "remote-svn", fast_export_begin_note(rev_ctx.revision, "remote-svn",
"Note created by remote-svn.", rev_ctx.timestamp); "Note created by remote-svn.", rev_ctx.timestamp, note_ref);
strbuf_addf(&mark, ":%"PRIu32, rev_ctx.revision); strbuf_addf(&mark, ":%"PRIu32, rev_ctx.revision);
fast_export_note(mark.buf, "inline"); fast_export_note(mark.buf, "inline");
fast_export_buf_to_data(&rev_ctx.note); fast_export_buf_to_data(&rev_ctx.note);
} }
} }


void svndump_read(const char *url, const char *local_ref) void svndump_read(const char *url, const char *local_ref, const char *notes_ref)
{ {
char *val; char *val;
char *t; char *t;
Expand Down Expand Up @@ -363,7 +363,7 @@ void svndump_read(const char *url, const char *local_ref)
if (active_ctx == REV_CTX) if (active_ctx == REV_CTX)
begin_revision(local_ref); begin_revision(local_ref);
if (active_ctx != DUMP_CTX) if (active_ctx != DUMP_CTX)
end_revision(); end_revision(notes_ref);
active_ctx = REV_CTX; active_ctx = REV_CTX;
reset_rev_ctx(atoi(val)); reset_rev_ctx(atoi(val));
strbuf_addf(&rev_ctx.note, "%s\n", t); strbuf_addf(&rev_ctx.note, "%s\n", t);
Expand Down Expand Up @@ -479,7 +479,7 @@ void svndump_read(const char *url, const char *local_ref)
if (active_ctx == REV_CTX) if (active_ctx == REV_CTX)
begin_revision(local_ref); begin_revision(local_ref);
if (active_ctx != DUMP_CTX) if (active_ctx != DUMP_CTX)
end_revision(); end_revision(notes_ref);
} }


static void init(int report_fd) static void init(int report_fd)
Expand Down
2 changes: 1 addition & 1 deletion vcs-svn/svndump.h
Expand Up @@ -3,7 +3,7 @@


int svndump_init(const char *filename); int svndump_init(const char *filename);
int svndump_init_fd(int in_fd, int back_fd); int svndump_init_fd(int in_fd, int back_fd);
void svndump_read(const char *url, const char *local_ref); void svndump_read(const char *url, const char *local_ref, const char *notes_ref);
void svndump_deinit(void); void svndump_deinit(void);
void svndump_reset(void); void svndump_reset(void);


Expand Down

0 comments on commit 8e43a1d

Please sign in to comment.