git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [RFC 00/16] GSOC remote-svn, rewritten patch series
@ 2012-07-26  7:32 Florian Achleitner
  2012-07-26  7:32 ` [RFC 01/16] Implement a remote helper for svn in C Florian Achleitner
  2012-07-30 14:31 ` [RFC v2 00/16] GSOC remote-svn, rewritten patch series Florian Achleitner
  0 siblings, 2 replies; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  7:32 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

Hi!

I decided to completely rewrite my commit history, I split, dropped, squashed, and reordered.
And finally rebased it all onto the current master.
Hope this removed a lot of my personal confusion and makes the patches 
more useful and understandable.
I think the remote helper does what it should now, except creating branches.
Several patches depend on each other, but some are purely optional and there are
working intermediate states.
I'll add some comments in the table of contents below.


[RFC 01/16] Implement a remote helper for svn in C.
[RFC 02/16] Integrate remote-svn into svn-fe/Makefile.
[RFC 03/16] Add svndump_init_fd to allow reading dumps from
[RFC 04/16] Add cat-blob report fifo from fast-import to #this one is still in discussion
[RFC 05/16] remote-svn, vcs-svn: Enable fetching to private refs.
[RFC 06/16] Add a symlink 'git-remote-svn' in base dir.
# basic functionality is available from here.
# additional features follow
[RFC 07/16] Allow reading svn dumps from files via file:// urls.
[RFC 08/16] vcs-svn: add fast_export_note to create notes
[RFC 09/16] Create a note for every imported commit containing svn
[RFC 10/16] When debug==1, start fast-import with "--stats" instead #optional
[RFC 11/16] Add explanatory comment for transport-helpers refs #optional
[RFC 12/16] remote-svn: add incremental import.
[RFC 13/16] Add a svnrdump-simulator replaying a dump file for
[RFC 14/16] transport-helper: add import|export-marks to fast-import
[RFC 15/16] remote-svn: add marks-file regeneration.
[RFC 16/16] Add a test script for remote-svn.


--
Florian

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [RFC 01/16] Implement a remote helper for svn in C.
  2012-07-26  7:32 [RFC 00/16] GSOC remote-svn, rewritten patch series Florian Achleitner
@ 2012-07-26  7:32 ` Florian Achleitner
  2012-07-26  7:32   ` [RFC 02/16] Integrate remote-svn into svn-fe/Makefile Florian Achleitner
  2012-07-26  7:46   ` [RFC 01/16] Implement a remote helper for svn in C Jonathan Nieder
  2012-07-30 14:31 ` [RFC v2 00/16] GSOC remote-svn, rewritten patch series Florian Achleitner
  1 sibling, 2 replies; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  7:32 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

Enables basic fetching from subversion repositories. When processing Remote URLs
starting with svn::, git invokes this remote-helper.
It starts svnrdump to extract revisions from the subversion repository in the
'dump file format', and converts them to a git-fast-import stream using
the functions of vcs-svn/.

Imported refs are created in a private namespace at refs/svn/<remote-name/master.
The revision history is imported linearly (no branch detection) and completely,
i.e. from revision 0 to HEAD.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 contrib/svn-fe/remote-svn.c |  219 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 219 insertions(+)
 create mode 100644 contrib/svn-fe/remote-svn.c

diff --git a/contrib/svn-fe/remote-svn.c b/contrib/svn-fe/remote-svn.c
new file mode 100644
index 0000000..29fc371
--- /dev/null
+++ b/contrib/svn-fe/remote-svn.c
@@ -0,0 +1,219 @@
+
+#include "cache.h"
+#include "remote.h"
+#include "strbuf.h"
+#include "url.h"
+#include "exec_cmd.h"
+#include "run-command.h"
+#include "svndump.h"
+#include "argv-array.h"
+
+static int debug;
+
+static inline void printd(const char *fmt, ...)
+{
+	if (debug) {
+		va_list vargs;
+		va_start(vargs, fmt);
+		fprintf(stderr, "rhsvn debug: ");
+		vfprintf(stderr, fmt, vargs);
+		fprintf(stderr, "\n");
+		va_end(vargs);
+	}
+}
+
+static const char *url;
+static const char *private_ref;
+static const char *remote_ref = "refs/heads/master";
+
+/*
+ * remote-helpers receive commands on their stdin. Command handler functions
+ * can return cmd_result, on fatal errors they die().
+ * NOT_HANDLED: the command was not handled by this function, name doesn't match.
+ * TERMINATE: Requests normal termination of the remote-helper.
+ */
+enum cmd_result { SUCCESS, NOT_HANDLED, TERMINATE };
+enum cmd_result cmd_capabilities(struct strbuf *line);
+enum cmd_result cmd_import(struct strbuf *line);
+enum cmd_result cmd_list(struct strbuf *line);
+enum cmd_result cmd_terminate(struct strbuf *line);
+
+typedef enum cmd_result (*input_command_handler)(struct strbuf *);
+
+const input_command_handler input_command_list[] = {
+		cmd_capabilities, cmd_import, cmd_list, cmd_terminate, NULL
+};
+
+enum cmd_result cmd_capabilities(struct strbuf *line)
+{
+	if (strcmp(line->buf, "capabilities"))
+		return NOT_HANDLED;
+
+	printf("import\n");
+	printf("refspec %s:%s\n\n", remote_ref, private_ref);
+	fflush(stdout);
+	return SUCCESS;
+}
+
+enum cmd_result cmd_import(struct strbuf *line)
+{
+	static int batch_active;
+	int code, report_fd;
+	char *back_pipe_env;
+	int dumpin_fd;
+	unsigned int startrev = 0;
+	struct argv_array svndump_argv = ARGV_ARRAY_INIT;
+	struct child_process svndump_proc;
+
+	/* terminate a current batch's fast-import stream */
+	if (line->len == 0 && batch_active) {
+		printf("done\n");
+		fflush(stdout);
+		batch_active = 0;
+		printd("import-batch finished.");
+		/*
+		 * should the remote helper terminate after a batch?
+		 * It seems that it should.
+		 */
+		return TERMINATE;
+	}
+	if (prefixcmp(line->buf, "import"))
+		return NOT_HANDLED;
+
+	/* import commands can be grouped together in a batch. Batches are ended by \n */
+	batch_active = 1;
+
+	/*
+	 * When the remote-helper is invoked by transport-helper.c it passes the
+	 * filename of this pipe in the env-var.
+	 */
+	back_pipe_env = getenv("GIT_REPORT_FIFO");
+	if (!back_pipe_env) {
+		die("Cannot get cat-blob-pipe from environment! GIT_REPORT_FIFO has to"
+				"be set by the caller.");
+	}
+
+	/*
+	 * Opening a fifo for reading usually blocks until a writer has opened it too.
+	 * Opening a fifo for writing usually blocks until a reader has opened it too.
+	 * Therefore, we open with RDWR on both sides to avoid deadlocks.
+	 * Especially if there's nothing to do and one pipe end is closed immediately.
+	 */
+	report_fd = open(back_pipe_env, O_RDWR);
+	if (report_fd < 0) {
+		die("Unable to open fast-import back-pipe! %s", strerror(errno));
+	}
+	printd("Opened fast-import back-pipe %s for reading.", back_pipe_env);
+
+	memset(&svndump_proc, 0, sizeof (struct child_process));
+	svndump_proc.out = -1;
+	argv_array_push(&svndump_argv, "svnrdump");
+	argv_array_push(&svndump_argv, "dump");
+	argv_array_push(&svndump_argv, url);
+	argv_array_pushf(&svndump_argv, "-r%u:HEAD", startrev);
+	svndump_proc.argv = svndump_argv.argv;
+
+	code = start_command(&svndump_proc);
+	if (code)
+		die("Unable to start %s, code %d", svndump_proc.argv[0], code);
+	dumpin_fd = svndump_proc.out;
+
+	svndump_init_fd(dumpin_fd, report_fd);
+	svndump_read(url, private_ref);
+	svndump_deinit();
+	svndump_reset();
+
+	close(dumpin_fd);
+	close(report_fd);
+	code = finish_command(&svndump_proc);
+	if (code)
+		warning("%s, returned %d", svndump_proc.argv[0], code);
+	argv_array_clear(&svndump_argv);
+
+	return SUCCESS;
+}
+
+enum cmd_result cmd_list(struct strbuf *line)
+{
+	if (strcmp(line->buf, "list"))
+		return NOT_HANDLED;
+
+	printf("? HEAD\n");
+	printf("? %s\n\n", remote_ref);
+	fflush(stdout);
+	return SUCCESS;
+}
+
+enum cmd_result cmd_terminate(struct strbuf *line)
+{
+	/* an empty line terminates the program, if not in a batch sequence */
+	if (line->len == 0)
+		return TERMINATE;
+	else
+		return NOT_HANDLED;
+}
+enum cmd_result do_command(struct strbuf *line)
+{
+	const input_command_handler *p = input_command_list;
+	enum cmd_result ret;
+	printd("command line '%s'", line->buf);
+	while(*p) {
+		ret = (*p)(line);
+		if (ret != NOT_HANDLED)
+			return ret;
+		p++;
+	}
+	warning("Unknown command '%s'\n", line->buf);
+	return ret;
+}
+
+int main(int argc, const char **argv)
+{
+	struct strbuf buf = STRBUF_INIT;
+	int nongit;
+	static struct remote *remote;
+
+	if (getenv("GIT_TRANSPORT_HELPER_DEBUG"))
+		debug = 1;
+
+	git_extract_argv0_path(argv[0]);
+	setup_git_directory_gently(&nongit);
+	if (argc < 2) {
+		usage("git-remote-svn <remote-name> [<url>]");
+		return 1;
+	}
+
+	remote = remote_get(argv[1]);
+	if (argc == 3)
+		url = argv[2];
+	else if (argc == 2)
+		url = remote->url[0];
+	else
+		warning("Excess arguments!");
+
+	end_url_with_slash(&buf, url);
+	url = strbuf_detach(&buf, NULL);
+
+	printd("remote-svn starting with url %s", url);
+
+	strbuf_init(&buf, 0);
+	strbuf_addf(&buf, "refs/svn/%s/master", remote->name);
+	private_ref = strbuf_detach(&buf, NULL);
+
+	while(1) {
+		if (strbuf_getline(&buf, stdin, '\n') == EOF) {
+			if (ferror(stdin))
+				die_errno("Error reading command stream");
+			else
+				die_errno("Unexpected end of command stream");
+		}
+		if (do_command(&buf) == TERMINATE)
+			break;
+		strbuf_reset(&buf);
+	}
+
+	strbuf_release(&buf);
+	free((void*)url);
+	free((void*)private_ref);
+	return 0;
+}
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 02/16] Integrate remote-svn into svn-fe/Makefile.
  2012-07-26  7:32 ` [RFC 01/16] Implement a remote helper for svn in C Florian Achleitner
@ 2012-07-26  7:32   ` Florian Achleitner
  2012-07-26  7:32     ` [RFC 03/16] Add svndump_init_fd to allow reading dumps from arbitrary FDs Florian Achleitner
  2012-07-26  7:46   ` [RFC 01/16] Implement a remote helper for svn in C Jonathan Nieder
  1 sibling, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  7:32 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

Requires some sha.h to be used and the libraries
to be linked, this is currently hardcoded.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 contrib/svn-fe/Makefile |   16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/contrib/svn-fe/Makefile b/contrib/svn-fe/Makefile
index 360d8da..8f0eec2 100644
--- a/contrib/svn-fe/Makefile
+++ b/contrib/svn-fe/Makefile
@@ -1,14 +1,14 @@
-all:: svn-fe$X
+all:: svn-fe$X remote-svn$X
 
 CC = gcc
 RM = rm -f
 MV = mv
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -DSHA1_HEADER='<openssl/sha.h>' -Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)
-EXTLIBS =
+EXTLIBS = -lssl -lcrypto -lpthread ../../xdiff/lib.a
 
 GIT_LIB = ../../libgit.a
 VCSSVN_LIB = ../../vcs-svn/lib.a
@@ -37,8 +37,12 @@ svn-fe$X: svn-fe.o $(VCSSVN_LIB) $(GIT_LIB)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ svn-fe.o \
 		$(ALL_LDFLAGS) $(LIBS)
 
-svn-fe.o: svn-fe.c ../../vcs-svn/svndump.h
-	$(QUIET_CC)$(CC) -I../../vcs-svn -o $*.o -c $(ALL_CFLAGS) $<
+remote-svn$X: remote-svn.o $(VCSSVN_LIB) $(GIT_LIB)
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ remote-svn.o \
+		$(ALL_LDFLAGS) $(LIBS)
+		
+%.o: %.c ../../vcs-svn/svndump.h
+	$(QUIET_CC)$(CC) -I../../vcs-svn -I../../ -o $*.o -c $(ALL_CFLAGS) $<
 
 svn-fe.html: svn-fe.txt
 	$(QUIET_SUBDIR0)../../Documentation $(QUIET_SUBDIR1) \
@@ -58,6 +62,6 @@ svn-fe.1: svn-fe.txt
 	$(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) libgit.a
 
 clean:
-	$(RM) svn-fe$X svn-fe.o svn-fe.html svn-fe.xml svn-fe.1
+	$(RM) svn-fe$X svn-fe.o svn-fe.html svn-fe.xml svn-fe.1 remote-svn.o
 
 .PHONY: all clean FORCE
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 03/16] Add svndump_init_fd to allow reading dumps from arbitrary FDs.
  2012-07-26  7:32   ` [RFC 02/16] Integrate remote-svn into svn-fe/Makefile Florian Achleitner
@ 2012-07-26  7:32     ` Florian Achleitner
  2012-07-26  7:32       ` [RFC 04/16] Add cat-blob report fifo from fast-import to remote-helper Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  7:32 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

The existing function only allows reading from a filename or
from stdin. Allow passing of a FD and an additional FD for
the back report pipe. This allows us to retrieve the name of
the pipe in the caller.

Fixes the filename could be NULL bug.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 vcs-svn/svndump.c |   22 ++++++++++++++++++----
 vcs-svn/svndump.h |    1 +
 2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c
index 2b168ae..76b42b2 100644
--- a/vcs-svn/svndump.c
+++ b/vcs-svn/svndump.c
@@ -468,11 +468,9 @@ void svndump_read(const char *url)
 		end_revision();
 }
 
-int svndump_init(const char *filename)
+static void init(int report_fd)
 {
-	if (buffer_init(&input, filename))
-		return error("cannot open %s: %s", filename, strerror(errno));
-	fast_export_init(REPORT_FILENO);
+	fast_export_init(report_fd);
 	strbuf_init(&dump_ctx.uuid, 4096);
 	strbuf_init(&dump_ctx.url, 4096);
 	strbuf_init(&rev_ctx.log, 4096);
@@ -482,6 +480,22 @@ int svndump_init(const char *filename)
 	reset_dump_ctx(NULL);
 	reset_rev_ctx(0);
 	reset_node_ctx(NULL);
+	return;
+}
+
+int svndump_init(const char *filename)
+{
+	if (buffer_init(&input, filename))
+		return error("cannot open %s: %s", filename ? filename : "NULL", strerror(errno));
+	init(REPORT_FILENO);
+	return 0;
+}
+
+int svndump_init_fd(int in_fd, int back_fd)
+{
+	if(buffer_fdinit(&input, in_fd))
+		return error("cannot open fd %d: %s", in_fd, strerror(errno));
+	init(back_fd);
 	return 0;
 }
 
diff --git a/vcs-svn/svndump.h b/vcs-svn/svndump.h
index df9ceb0..acb5b47 100644
--- a/vcs-svn/svndump.h
+++ b/vcs-svn/svndump.h
@@ -2,6 +2,7 @@
 #define SVNDUMP_H_
 
 int svndump_init(const char *filename);
+int svndump_init_fd(int in_fd, int back_fd);
 void svndump_read(const char *url);
 void svndump_deinit(void);
 void svndump_reset(void);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 04/16] Add cat-blob report fifo from fast-import to remote-helper.
  2012-07-26  7:32     ` [RFC 03/16] Add svndump_init_fd to allow reading dumps from arbitrary FDs Florian Achleitner
@ 2012-07-26  7:32       ` Florian Achleitner
  2012-07-26  7:32         ` [RFC 05/16] remote-svn, vcs-svn: Enable fetching to private refs Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  7:32 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

For some fast-import commands (e.g. cat-blob) an answer-channel
is required. For this purpose a fifo (aka named pipe) (mkfifo)
is created (.git/fast-import-report-fifo) by the transport-helper
when fetch via import is requested. The remote-helper and
fast-import open the ends of the pipe.

The filename of the fifo is passed to the remote-helper via
it's environment, helpers that don't use fast-import can
simply ignore it.
Add a new command line option --cat-blob-pipe to fast-import,
for this purpose.

Use argv_arrays in get_helper and get_importer.

Opening the pipe with O_RDWR prevents blocking open calls on both ends.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 fast-import.c      |   14 ++++++++++++
 transport-helper.c |   64 ++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 63 insertions(+), 15 deletions(-)

diff --git a/fast-import.c b/fast-import.c
index eed97c8..7619449 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -3180,6 +3180,15 @@ static void option_cat_blob_fd(const char *fd)
 	cat_blob_fd = (int) n;
 }
 
+static void option_cat_blob_pipe(const char *name)
+{
+	int report_fd = open(name, O_RDWR);
+	if(report_fd < 0) {
+		die("Unable to open fast-import back-pipe! %s", strerror(errno));
+	}
+	cat_blob_fd = report_fd;
+}
+
 static void option_export_pack_edges(const char *edges)
 {
 	if (pack_edges)
@@ -3337,6 +3346,11 @@ static void parse_argv(void)
 			continue;
 		}
 
+		if(!prefixcmp(a + 2, "cat-blob-pipe=")) {
+			option_cat_blob_pipe(a + 2 + strlen("cat-blob-pipe="));
+			continue;
+		}
+
 		die("unknown option %s", a);
 	}
 	if (i != global_argc)
diff --git a/transport-helper.c b/transport-helper.c
index 61c928f..616db91 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -10,6 +10,7 @@
 #include "string-list.h"
 #include "thread-utils.h"
 #include "sigchain.h"
+#include "argv-array.h"
 
 static int debug;
 
@@ -17,6 +18,7 @@ struct helper_data {
 	const char *name;
 	struct child_process *helper;
 	FILE *out;
+	char *report_fifo;
 	unsigned fetch : 1,
 		import : 1,
 		export : 1,
@@ -101,6 +103,7 @@ static void do_take_over(struct transport *transport)
 static struct child_process *get_helper(struct transport *transport)
 {
 	struct helper_data *data = transport->data;
+	struct argv_array argv = ARGV_ARRAY_INIT;
 	struct strbuf buf = STRBUF_INIT;
 	struct child_process *helper;
 	const char **refspecs = NULL;
@@ -111,6 +114,7 @@ static struct child_process *get_helper(struct transport *transport)
 	char git_dir_buf[sizeof(GIT_DIR_ENVIRONMENT) + PATH_MAX + 1];
 	const char *helper_env[] = {
 		git_dir_buf,
+		NULL,	/* placeholder */
 		NULL
 	};
 
@@ -122,17 +126,23 @@ static struct child_process *get_helper(struct transport *transport)
 	helper->in = -1;
 	helper->out = -1;
 	helper->err = 0;
-	helper->argv = xcalloc(4, sizeof(*helper->argv));
-	strbuf_addf(&buf, "git-remote-%s", data->name);
-	helper->argv[0] = strbuf_detach(&buf, NULL);
-	helper->argv[1] = transport->remote->name;
-	helper->argv[2] = remove_ext_force(transport->url);
+	argv_array_pushf(&argv, "git-remote-%s", data->name);
+	argv_array_push(&argv, transport->remote->name);
+	argv_array_push(&argv, remove_ext_force(transport->url));
+	helper->argv = argv.argv;
 	helper->git_cmd = 0;
 	helper->silent_exec_failure = 1;
 
 	snprintf(git_dir_buf, sizeof(git_dir_buf), "%s=%s", GIT_DIR_ENVIRONMENT, get_git_dir());
 	helper->env = helper_env;
 
+	strbuf_init(&buf, 0);
+	strbuf_addf(&buf, "%s/fast-import-report-fifo", get_git_dir());
+	data->report_fifo = strbuf_detach(&buf, NULL);
+	strbuf_init(&buf, 0);
+	strbuf_addf(&buf, "GIT_REPORT_FIFO=%s", data->report_fifo);
+	helper_env[1] = strbuf_detach(&buf, NULL);
+
 	code = start_command(helper);
 	if (code < 0 && errno == ENOENT)
 		die("Unable to find remote helper for '%s'", data->name);
@@ -141,6 +151,8 @@ static struct child_process *get_helper(struct transport *transport)
 
 	data->helper = helper;
 	data->no_disconnect_req = 0;
+	free((void*) helper_env[1]);
+	argv_array_clear(&argv);
 
 	/*
 	 * Open the output as FILE* so strbuf_getline() can be used.
@@ -237,13 +249,13 @@ static int disconnect_helper(struct transport *transport)
 			xwrite(data->helper->in, "\n", 1);
 			sigchain_pop(SIGPIPE);
 		}
+
 		close(data->helper->in);
 		close(data->helper->out);
 		fclose(data->out);
 		res = finish_command(data->helper);
-		free((char *)data->helper->argv[0]);
-		free(data->helper->argv);
 		free(data->helper);
+		free(data->report_fifo);
 		data->helper = NULL;
 	}
 	return res;
@@ -373,16 +385,18 @@ static int fetch_with_fetch(struct transport *transport,
 	return 0;
 }
 
-static int get_importer(struct transport *transport, struct child_process *fastimport)
+static int get_importer(struct transport *transport, struct child_process *fastimport, struct argv_array *argv)
 {
 	struct child_process *helper = get_helper(transport);
+	struct helper_data *data = transport->data;
 	memset(fastimport, 0, sizeof(*fastimport));
 	fastimport->in = helper->out;
-	fastimport->argv = xcalloc(5, sizeof(*fastimport->argv));
-	fastimport->argv[0] = "fast-import";
-	fastimport->argv[1] = "--quiet";
-
+	argv_array_push(argv, "fast-import");
+	argv_array_push(argv, "--quiet");
+	argv_array_pushf(argv, "--cat-blob-pipe=%s", data->report_fifo);
+	fastimport->argv = argv->argv;
 	fastimport->git_cmd = 1;
+
 	return start_command(fastimport);
 }
 
@@ -421,10 +435,30 @@ static int fetch_with_import(struct transport *transport,
 	int i;
 	struct ref *posn;
 	struct strbuf buf = STRBUF_INIT;
+	struct argv_array importer_argv = ARGV_ARRAY_INIT;
+	struct stat fifostat;
+
+	/* create a fifo for back-reporting of fast-import to the remote helper,
+	 * if it doesn't exist. */
+	if(!stat(data->report_fifo, &fifostat)) {
+		if(S_ISFIFO(fifostat.st_mode)) {		/* exists and is fifo, unlink and recreate, to be sure that permissions are ok.. */
+			if (debug)
+				fprintf(stderr, "Debug: Remote helper: Unlinked existing fifo.\n");
+			if(unlink(data->report_fifo))
+				die_errno("Couldn't unlink fifo %s", data->report_fifo);
+		}
+		else
+			die("Fifo %s used by some other file.", data->report_fifo);
+	}
+	if(mkfifo(data->report_fifo, 0660))
+		die_errno("Couldn't create fifo %s", data->report_fifo);
+	if (debug)
+		fprintf(stderr, "Debug: Remote helper: Mkfifo %s\n", data->report_fifo);
+
 
 	get_helper(transport);
 
-	if (get_importer(transport, &fastimport))
+	if (get_importer(transport, &fastimport, &importer_argv))
 		die("Couldn't run fast-import");
 
 	for (i = 0; i < nr_heads; i++) {
@@ -441,8 +475,8 @@ static int fetch_with_import(struct transport *transport,
 
 	if (finish_command(&fastimport))
 		die("Error while running fast-import");
-	free(fastimport.argv);
-	fastimport.argv = NULL;
+
+	argv_array_clear(&importer_argv);
 
 	for (i = 0; i < nr_heads; i++) {
 		char *private;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 05/16] remote-svn, vcs-svn: Enable fetching to private refs.
  2012-07-26  7:32       ` [RFC 04/16] Add cat-blob report fifo from fast-import to remote-helper Florian Achleitner
@ 2012-07-26  7:32         ` Florian Achleitner
  2012-07-26  7:32           ` [RFC 06/16] Add a symlink 'git-remote-svn' in base dir Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  7:32 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

The reference to update by the fast-import stream is hard-coded.
When fetching from a remote the remote-helper shall update refs
in a private namespace, i.e. a private subdir of refs/.
This namespace is defined by the 'refspec' capability, that the
remote-helper advertises as a reply to the 'capablilities' command.

Extend svndump and fast-export to allow passing the target ref.
Update svn-fe to be compatible.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 contrib/svn-fe/svn-fe.c |    2 +-
 test-svn-fe.c           |    2 +-
 vcs-svn/fast_export.c   |    4 ++--
 vcs-svn/fast_export.h   |    2 +-
 vcs-svn/svndump.c       |   14 +++++++-------
 vcs-svn/svndump.h       |    2 +-
 6 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/contrib/svn-fe/svn-fe.c b/contrib/svn-fe/svn-fe.c
index 35db24f..c796cc0 100644
--- a/contrib/svn-fe/svn-fe.c
+++ b/contrib/svn-fe/svn-fe.c
@@ -10,7 +10,7 @@ int main(int argc, char **argv)
 {
 	if (svndump_init(NULL))
 		return 1;
-	svndump_read((argc > 1) ? argv[1] : NULL);
+	svndump_read((argc > 1) ? argv[1] : NULL, "refs/heads/master");
 	svndump_deinit();
 	svndump_reset();
 	return 0;
diff --git a/test-svn-fe.c b/test-svn-fe.c
index 83633a2..bb0e980 100644
--- a/test-svn-fe.c
+++ b/test-svn-fe.c
@@ -40,7 +40,7 @@ int main(int argc, char *argv[])
 	if (argc == 2) {
 		if (svndump_init(argv[1]))
 			return 1;
-		svndump_read(NULL);
+		svndump_read(NULL, "refs/remotes/svn/master");
 		svndump_deinit();
 		svndump_reset();
 		return 0;
diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c
index 1f04697..11f8f94 100644
--- a/vcs-svn/fast_export.c
+++ b/vcs-svn/fast_export.c
@@ -72,7 +72,7 @@ static char gitsvnline[MAX_GITSVN_LINE_LEN];
 void fast_export_begin_commit(uint32_t revision, const char *author,
 			const struct strbuf *log,
 			const char *uuid, const char *url,
-			unsigned long timestamp)
+			unsigned long timestamp, const char *local_ref)
 {
 	static const struct strbuf empty = STRBUF_INIT;
 	if (!log)
@@ -84,7 +84,7 @@ void fast_export_begin_commit(uint32_t revision, const char *author,
 	} else {
 		*gitsvnline = '\0';
 	}
-	printf("commit refs/heads/master\n");
+	printf("commit %s\n", local_ref);
 	printf("mark :%"PRIu32"\n", revision);
 	printf("committer %s <%s@%s> %ld +0000\n",
 		   *author ? author : "nobody",
diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h
index 8823aca..17eb13b 100644
--- a/vcs-svn/fast_export.h
+++ b/vcs-svn/fast_export.h
@@ -11,7 +11,7 @@ void fast_export_delete(const char *path);
 void fast_export_modify(const char *path, uint32_t mode, const char *dataref);
 void fast_export_begin_commit(uint32_t revision, const char *author,
 			const struct strbuf *log, const char *uuid,
-			const char *url, unsigned long timestamp);
+			const char *url, unsigned long timestamp, const char *local_ref);
 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_blob_delta(uint32_t mode,
diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c
index 76b42b2..c0d5931 100644
--- a/vcs-svn/svndump.c
+++ b/vcs-svn/svndump.c
@@ -299,22 +299,22 @@ static void handle_node(void)
 				node_ctx.text_length, &input);
 }
 
-static void begin_revision(void)
+static void begin_revision(const char *remote_ref)
 {
 	if (!rev_ctx.revision)	/* revision 0 gets no git commit. */
 		return;
 	fast_export_begin_commit(rev_ctx.revision, rev_ctx.author.buf,
 		&rev_ctx.log, dump_ctx.uuid.buf, dump_ctx.url.buf,
-		rev_ctx.timestamp);
+		rev_ctx.timestamp, remote_ref);
 }
 
-static void end_revision(void)
+static void end_revision()
 {
 	if (rev_ctx.revision)
 		fast_export_end_commit(rev_ctx.revision);
 }
 
-void svndump_read(const char *url)
+void svndump_read(const char *url, const char *local_ref)
 {
 	char *val;
 	char *t;
@@ -353,7 +353,7 @@ void svndump_read(const char *url)
 			if (active_ctx == NODE_CTX)
 				handle_node();
 			if (active_ctx == REV_CTX)
-				begin_revision();
+				begin_revision(local_ref);
 			if (active_ctx != DUMP_CTX)
 				end_revision();
 			active_ctx = REV_CTX;
@@ -366,7 +366,7 @@ void svndump_read(const char *url)
 				if (active_ctx == NODE_CTX)
 					handle_node();
 				if (active_ctx == REV_CTX)
-					begin_revision();
+					begin_revision(local_ref);
 				active_ctx = NODE_CTX;
 				reset_node_ctx(val);
 				break;
@@ -463,7 +463,7 @@ void svndump_read(const char *url)
 	if (active_ctx == NODE_CTX)
 		handle_node();
 	if (active_ctx == REV_CTX)
-		begin_revision();
+		begin_revision(local_ref);
 	if (active_ctx != DUMP_CTX)
 		end_revision();
 }
diff --git a/vcs-svn/svndump.h b/vcs-svn/svndump.h
index acb5b47..febeecb 100644
--- a/vcs-svn/svndump.h
+++ b/vcs-svn/svndump.h
@@ -3,7 +3,7 @@
 
 int svndump_init(const char *filename);
 int svndump_init_fd(int in_fd, int back_fd);
-void svndump_read(const char *url);
+void svndump_read(const char *url, const char *local_ref);
 void svndump_deinit(void);
 void svndump_reset(void);
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 06/16] Add a symlink 'git-remote-svn' in base dir.
  2012-07-26  7:32         ` [RFC 05/16] remote-svn, vcs-svn: Enable fetching to private refs Florian Achleitner
@ 2012-07-26  7:32           ` Florian Achleitner
  2012-07-26  7:32             ` [RFC 07/16] Allow reading svn dumps from files via file:// urls Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  7:32 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

Allow execution of git-remote-svn even if the binary
currently is located in contrib/svn-fe/.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 git-remote-svn |    1 +
 1 file changed, 1 insertion(+)
 create mode 120000 git-remote-svn

diff --git a/git-remote-svn b/git-remote-svn
new file mode 120000
index 0000000..d3b1c07
--- /dev/null
+++ b/git-remote-svn
@@ -0,0 +1 @@
+contrib/svn-fe/remote-svn
\ No newline at end of file
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 07/16] Allow reading svn dumps from files via file:// urls.
  2012-07-26  7:32           ` [RFC 06/16] Add a symlink 'git-remote-svn' in base dir Florian Achleitner
@ 2012-07-26  7:32             ` Florian Achleitner
  2012-07-26  7:32               ` [RFC 08/16] vcs-svn: add fast_export_note to create notes Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  7:32 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

For testing as well as for importing large, already
available dumps, it's useful to bypass svnrdump and
replay the svndump from a file directly.

Add support for file:// urls in the remote url.
e.g. svn::file:///path/to/dump
When the remote helper finds an url starting with
file:// it tries to open that file instead of invoking svnrdump.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 contrib/svn-fe/remote-svn.c |   56 +++++++++++++++++++++++++++++--------------
 1 file changed, 38 insertions(+), 18 deletions(-)

diff --git a/contrib/svn-fe/remote-svn.c b/contrib/svn-fe/remote-svn.c
index 29fc371..862b739 100644
--- a/contrib/svn-fe/remote-svn.c
+++ b/contrib/svn-fe/remote-svn.c
@@ -23,6 +23,7 @@ static inline void printd(const char *fmt, ...)
 }
 
 static const char *url;
+static int dump_from_file;
 static const char *private_ref;
 static const char *remote_ref = "refs/heads/master";
 
@@ -105,18 +106,28 @@ enum cmd_result cmd_import(struct strbuf *line)
 	}
 	printd("Opened fast-import back-pipe %s for reading.", back_pipe_env);
 
-	memset(&svndump_proc, 0, sizeof (struct child_process));
-	svndump_proc.out = -1;
-	argv_array_push(&svndump_argv, "svnrdump");
-	argv_array_push(&svndump_argv, "dump");
-	argv_array_push(&svndump_argv, url);
-	argv_array_pushf(&svndump_argv, "-r%u:HEAD", startrev);
-	svndump_proc.argv = svndump_argv.argv;
+	if(dump_from_file) {
+		dumpin_fd = open(url, O_RDONLY);
+		if(dumpin_fd < 0) {
+			die_errno("Couldn't open svn dump file %s.", url);
+		}
+	}
+	else {
+		memset(&svndump_proc, 0, sizeof (struct child_process));
+		svndump_proc.out = -1;
+		argv_array_push(&svndump_argv, "svnrdump");
+		argv_array_push(&svndump_argv, "dump");
+		argv_array_push(&svndump_argv, url);
+		argv_array_pushf(&svndump_argv, "-r%u:HEAD", startrev);
+		svndump_proc.argv = svndump_argv.argv;
+
+		code = start_command(&svndump_proc);
+		if (code)
+			die("Unable to start %s, code %d", svndump_proc.argv[0], code);
+		dumpin_fd = svndump_proc.out;
+
+	}
 
-	code = start_command(&svndump_proc);
-	if (code)
-		die("Unable to start %s, code %d", svndump_proc.argv[0], code);
-	dumpin_fd = svndump_proc.out;
 
 	svndump_init_fd(dumpin_fd, report_fd);
 	svndump_read(url, private_ref);
@@ -125,10 +136,12 @@ enum cmd_result cmd_import(struct strbuf *line)
 
 	close(dumpin_fd);
 	close(report_fd);
-	code = finish_command(&svndump_proc);
-	if (code)
-		warning("%s, returned %d", svndump_proc.argv[0], code);
-	argv_array_clear(&svndump_argv);
+	if(!dump_from_file) {
+		code = finish_command(&svndump_proc);
+		if (code)
+			warning("%s, returned %d", svndump_proc.argv[0], code);
+		argv_array_clear(&svndump_argv);
+	}
 
 	return SUCCESS;
 }
@@ -191,9 +204,16 @@ int main(int argc, const char **argv)
 	else
 		warning("Excess arguments!");
 
-	end_url_with_slash(&buf, url);
-	url = strbuf_detach(&buf, NULL);
-
+	if (!prefixcmp(url, "file://")) {
+		dump_from_file = 1;
+		url = url_decode(url + sizeof("file://")-1);
+		printd("remote-svn uses a file as dump input.");
+	}
+	else {
+		dump_from_file = 0;
+		end_url_with_slash(&buf, url);
+		url = strbuf_detach(&buf, NULL);
+	}
 	printd("remote-svn starting with url %s", url);
 
 	strbuf_init(&buf, 0);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 08/16] vcs-svn: add fast_export_note to create notes
  2012-07-26  7:32             ` [RFC 07/16] Allow reading svn dumps from files via file:// urls Florian Achleitner
@ 2012-07-26  7:32               ` Florian Achleitner
  2012-07-26  7:32                 ` [RFC 09/16] Create a note for every imported commit containing svn metadata Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  7:32 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git
  Cc: florian.achleitner.2.6.31, Dmitry Ivankov

From: Dmitry Ivankov <divanorama@gmail.com>

fast_export lacked a method to writes notes to fast-import stream.
Add two new functions fast_export_note which is similar to
fast_export_modify. And also add fast_export_buf_to_data to be able
to write inline blobs that don't come from a line_buffer or from delta
application.

To be used like this:
fast_export_begin_commit("refs/notes/somenotes", ...)

fast_export_note("refs/heads/master", "inline")
fast_export_buf_to_data(&data)
or maybe
fast_export_note("refs/heads/master", sha1)

Signed-off-by: Dmitry Ivankov <divanorama@gmail.com>
Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 vcs-svn/fast_export.c |   12 ++++++++++++
 vcs-svn/fast_export.h |    2 ++
 2 files changed, 14 insertions(+)

diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c
index 11f8f94..1ecae4b 100644
--- a/vcs-svn/fast_export.c
+++ b/vcs-svn/fast_export.c
@@ -68,6 +68,11 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)
 	putchar('\n');
 }
 
+void fast_export_note(const char *committish, const char *dataref)
+{
+	printf("N %s %s\n", dataref, committish);
+}
+
 static char gitsvnline[MAX_GITSVN_LINE_LEN];
 void fast_export_begin_commit(uint32_t revision, const char *author,
 			const struct strbuf *log,
@@ -222,6 +227,13 @@ static long apply_delta(off_t len, struct line_buffer *input,
 	return ret;
 }
 
+void fast_export_buf_to_data(const struct strbuf *data)
+{
+	printf("data %"PRIuMAX"\n", (uintmax_t)data->len);
+	fwrite(data->buf, data->len, 1, stdout);
+	fputc('\n', stdout);
+}
+
 void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input)
 {
 	assert(len >= 0);
diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h
index 17eb13b..9b32f1e 100644
--- a/vcs-svn/fast_export.h
+++ b/vcs-svn/fast_export.h
@@ -9,11 +9,13 @@ void fast_export_deinit(void);
 
 void fast_export_delete(const char *path);
 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_begin_commit(uint32_t revision, const char *author,
 			const struct strbuf *log, const char *uuid,
 			const char *url, unsigned long timestamp, const char *local_ref);
 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_buf_to_data(const struct strbuf *data);
 void fast_export_blob_delta(uint32_t mode,
 			uint32_t old_mode, const char *old_data,
 			off_t len, struct line_buffer *input);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 09/16] Create a note for every imported commit containing svn metadata.
  2012-07-26  7:32               ` [RFC 08/16] vcs-svn: add fast_export_note to create notes Florian Achleitner
@ 2012-07-26  7:32                 ` Florian Achleitner
  2012-07-26  7:32                   ` [RFC 10/16] When debug==1, start fast-import with "--stats" instead of "--quiet" Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  7:32 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

To provide metadata from svn dumps for further processing, e.g.
branch detection, attach a note to each imported commit that
stores additional information.
The notes are currently hard-coded in refs/notes/svn/revs.
Currently the following lines from the svn dump are directly
accumulated in the note. This can be refined on purpose, of course.
- "Revision-number"
- "Node-path"
- "Node-kind"
- "Node-action"
- "Node-copyfrom-path"
- "Node-copyfrom-rev"

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 vcs-svn/fast_export.c |   13 +++++++++++++
 vcs-svn/fast_export.h |    2 ++
 vcs-svn/svndump.c     |   21 +++++++++++++++++++--
 3 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c
index 1ecae4b..796dd1a 100644
--- a/vcs-svn/fast_export.c
+++ b/vcs-svn/fast_export.c
@@ -12,6 +12,7 @@
 #include "svndiff.h"
 #include "sliding_window.h"
 #include "line_buffer.h"
+#include "cache.h"
 
 #define MAX_GITSVN_LINE_LEN 4096
 
@@ -68,6 +69,18 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)
 	putchar('\n');
 }
 
+void fast_export_begin_note(uint32_t revision, const char *author,
+		const char *log, unsigned long timestamp)
+{
+	timestamp = 1341914616;
+	size_t loglen = strlen(log);
+	printf("commit refs/notes/svn/revs\n");
+	printf("committer %s <%s@%s> %ld +0000\n", author, author, "local", timestamp);
+	printf("data %"PRIuMAX"\n", loglen);
+	fwrite(log, loglen, 1, stdout);
+	fputc('\n', stdout);
+}
+
 void fast_export_note(const char *committish, const char *dataref)
 {
 	printf("N %s %s\n", dataref, committish);
diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h
index 9b32f1e..c2f6f11 100644
--- a/vcs-svn/fast_export.h
+++ b/vcs-svn/fast_export.h
@@ -10,6 +10,8 @@ void fast_export_deinit(void);
 void fast_export_delete(const char *path);
 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_begin_note(uint32_t revision, const char *author,
+		const char *log, unsigned long timestamp);
 void fast_export_begin_commit(uint32_t revision, const char *author,
 			const struct strbuf *log, const char *uuid,
 			const char *url, unsigned long timestamp, const char *local_ref);
diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c
index c0d5931..f0633c6 100644
--- a/vcs-svn/svndump.c
+++ b/vcs-svn/svndump.c
@@ -48,7 +48,7 @@ static struct {
 static struct {
 	uint32_t revision;
 	unsigned long timestamp;
-	struct strbuf log, author;
+	struct strbuf log, author, note;
 } rev_ctx;
 
 static struct {
@@ -77,6 +77,7 @@ static void reset_rev_ctx(uint32_t revision)
 	rev_ctx.timestamp = 0;
 	strbuf_reset(&rev_ctx.log);
 	strbuf_reset(&rev_ctx.author);
+	strbuf_reset(&rev_ctx.note);
 }
 
 static void reset_dump_ctx(const char *url)
@@ -310,8 +311,15 @@ static void begin_revision(const char *remote_ref)
 
 static void end_revision()
 {
-	if (rev_ctx.revision)
+	struct strbuf mark = STRBUF_INIT;
+	if (rev_ctx.revision) {
 		fast_export_end_commit(rev_ctx.revision);
+		fast_export_begin_note(rev_ctx.revision, "remote-svn",
+				"Note created by remote-svn.", rev_ctx.timestamp);
+		strbuf_addf(&mark, ":%"PRIu32, rev_ctx.revision);
+		fast_export_note(mark.buf, "inline");
+		fast_export_buf_to_data(&rev_ctx.note);
+	}
 }
 
 void svndump_read(const char *url, const char *local_ref)
@@ -358,6 +366,7 @@ void svndump_read(const char *url, const char *local_ref)
 				end_revision();
 			active_ctx = REV_CTX;
 			reset_rev_ctx(atoi(val));
+			strbuf_addf(&rev_ctx.note, "%s\n", t);
 			break;
 		case sizeof("Node-path"):
 			if (constcmp(t, "Node-"))
@@ -369,10 +378,12 @@ void svndump_read(const char *url, const char *local_ref)
 					begin_revision(local_ref);
 				active_ctx = NODE_CTX;
 				reset_node_ctx(val);
+				strbuf_addf(&rev_ctx.note, "%s\n", t);
 				break;
 			}
 			if (constcmp(t + strlen("Node-"), "kind"))
 				continue;
+			strbuf_addf(&rev_ctx.note, "%s\n", t);
 			if (!strcmp(val, "dir"))
 				node_ctx.type = REPO_MODE_DIR;
 			else if (!strcmp(val, "file"))
@@ -383,6 +394,7 @@ void svndump_read(const char *url, const char *local_ref)
 		case sizeof("Node-action"):
 			if (constcmp(t, "Node-action"))
 				continue;
+			strbuf_addf(&rev_ctx.note, "%s\n", t);
 			if (!strcmp(val, "delete")) {
 				node_ctx.action = NODEACT_DELETE;
 			} else if (!strcmp(val, "add")) {
@@ -401,11 +413,13 @@ void svndump_read(const char *url, const char *local_ref)
 				continue;
 			strbuf_reset(&node_ctx.src);
 			strbuf_addstr(&node_ctx.src, val);
+			strbuf_addf(&rev_ctx.note, "%s\n", t);
 			break;
 		case sizeof("Node-copyfrom-rev"):
 			if (constcmp(t, "Node-copyfrom-rev"))
 				continue;
 			node_ctx.srcRev = atoi(val);
+			strbuf_addf(&rev_ctx.note, "%s\n", t);
 			break;
 		case sizeof("Text-content-length"):
 			if (constcmp(t, "Text") && constcmp(t, "Prop"))
@@ -475,6 +489,7 @@ static void init(int report_fd)
 	strbuf_init(&dump_ctx.url, 4096);
 	strbuf_init(&rev_ctx.log, 4096);
 	strbuf_init(&rev_ctx.author, 4096);
+	strbuf_init(&rev_ctx.note, 4096);
 	strbuf_init(&node_ctx.src, 4096);
 	strbuf_init(&node_ctx.dst, 4096);
 	reset_dump_ctx(NULL);
@@ -506,6 +521,8 @@ void svndump_deinit(void)
 	reset_rev_ctx(0);
 	reset_node_ctx(NULL);
 	strbuf_release(&rev_ctx.log);
+	strbuf_release(&rev_ctx.author);
+	strbuf_release(&rev_ctx.note);
 	strbuf_release(&node_ctx.src);
 	strbuf_release(&node_ctx.dst);
 	if (buffer_deinit(&input))
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 10/16] When debug==1, start fast-import with "--stats" instead of "--quiet".
  2012-07-26  7:32                 ` [RFC 09/16] Create a note for every imported commit containing svn metadata Florian Achleitner
@ 2012-07-26  7:32                   ` Florian Achleitner
  2012-07-26  7:32                     ` [RFC 11/16] Add explanatory comment for transport-helpers refs mapping Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  7:32 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

fast-import prints statistics that could be interesting to the
developer of remote helpers.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 transport-helper.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/transport-helper.c b/transport-helper.c
index 616db91..d6daad5 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -392,7 +392,7 @@ static int get_importer(struct transport *transport, struct child_process *fasti
 	memset(fastimport, 0, sizeof(*fastimport));
 	fastimport->in = helper->out;
 	argv_array_push(argv, "fast-import");
-	argv_array_push(argv, "--quiet");
+	argv_array_push(argv, debug ? "--stats" : "--quiet");
 	argv_array_pushf(argv, "--cat-blob-pipe=%s", data->report_fifo);
 	fastimport->argv = argv->argv;
 	fastimport->git_cmd = 1;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 11/16] Add explanatory comment for transport-helpers refs mapping.
  2012-07-26  7:32                   ` [RFC 10/16] When debug==1, start fast-import with "--stats" instead of "--quiet" Florian Achleitner
@ 2012-07-26  7:32                     ` Florian Achleitner
  2012-07-26  7:32                       ` [RFC 12/16] remote-svn: add incremental import Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  7:32 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

transport-helpers can advertise the 'refspec' capability,
if not a default refspec *:* is assumed. This explains
the post-processing of refs after fetching with fast-import.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 transport-helper.c |   15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/transport-helper.c b/transport-helper.c
index d6daad5..e10fd6b 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -478,6 +478,21 @@ static int fetch_with_import(struct transport *transport,
 
 	argv_array_clear(&importer_argv);
 
+	/*
+	 * If the remote helper advertised the "refspec" capability,
+	 * it will have the written result of the import to the refs
+	 * named on the right hand side of the first refspec matching
+	 * each ref we were fetching.
+	 *
+	 * (If no "refspec" capability was specified, for historical
+	 * reasons we default to *:*.)
+	 *
+	 * Store the result in to_fetch[i].old_sha1.  Callers such
+	 * as "git fetch" can use the value to write feedback to the
+	 * terminal, populate FETCH_HEAD, and determine what new value
+	 * should be written to peer_ref if the update is a
+	 * fast-forward or this is a forced update.
+	 */
 	for (i = 0; i < nr_heads; i++) {
 		char *private;
 		posn = to_fetch[i];
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 12/16] remote-svn: add incremental import.
  2012-07-26  7:32                     ` [RFC 11/16] Add explanatory comment for transport-helpers refs mapping Florian Achleitner
@ 2012-07-26  7:32                       ` Florian Achleitner
  2012-07-26  7:32                         ` [RFC 13/16] Add a svnrdump-simulator replaying a dump file for testing Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  7:32 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

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>
---
 contrib/svn-fe/remote-svn.c |   73 +++++++++++++++++++++++++++++++++++++++++--
 contrib/svn-fe/svn-fe.c     |    3 +-
 test-svn-fe.c               |    2 +-
 vcs-svn/fast_export.c       |   16 +++++++---
 vcs-svn/fast_export.h       |    6 ++--
 vcs-svn/svndump.c           |   12 +++----
 vcs-svn/svndump.h           |    2 +-
 7 files changed, 96 insertions(+), 18 deletions(-)

diff --git a/contrib/svn-fe/remote-svn.c b/contrib/svn-fe/remote-svn.c
index 862b739..f23b82f 100644
--- a/contrib/svn-fe/remote-svn.c
+++ b/contrib/svn-fe/remote-svn.c
@@ -6,6 +6,7 @@
 #include "exec_cmd.h"
 #include "run-command.h"
 #include "svndump.h"
+#include "notes.h"
 #include "argv-array.h"
 
 static int debug;
@@ -26,6 +27,8 @@ static const char *url;
 static int dump_from_file;
 static const char *private_ref;
 static const char *remote_ref = "refs/heads/master";
+static const char *notes_ref;
+struct rev_note { unsigned int rev_nr; };
 
 /*
  * remote-helpers receive commands on their stdin. Command handler functions
@@ -56,13 +59,53 @@ enum cmd_result cmd_capabilities(struct strbuf *line)
 	return SUCCESS;
 }
 
+/* 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)) == NULL ||
+			!(msg = read_sha1_file(note_sha1, &type, &msglen)) ||
+			!msglen || type != OBJ_BLOB) {
+		free(msg);
+		return 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;
+			value = msg + strlen(key);
+			i = atol(value);
+			if(i < 0 || i > UINT32_MAX)
+				return 1;
+			res->rev_nr = i;
+		}
+		msg += len + 1;
+	}
+	return 0;
+}
+
 enum cmd_result cmd_import(struct strbuf *line)
 {
 	static int batch_active;
 	int code, report_fd;
 	char *back_pipe_env;
 	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 child_process svndump_proc;
 
@@ -106,6 +149,27 @@ enum cmd_result cmd_import(struct strbuf *line)
 	}
 	printd("Opened fast-import back-pipe %s for reading.", back_pipe_env);
 
+	if(read_ref(private_ref, head_sha1)) {
+		printd("New branch");
+		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 };
+			printd("Note found for %s", private_ref);
+			printd("Note:\n%s", note_msg);
+			parse_rev_note(note_msg, &note);
+			startrev = note.rev_nr + 1;
+			free(note_msg);
+		}
+	}
+
+	printd("starting import from revision %u", startrev);
+
 	if(dump_from_file) {
 		dumpin_fd = open(url, O_RDONLY);
 		if(dumpin_fd < 0) {
@@ -130,7 +194,7 @@ enum cmd_result cmd_import(struct strbuf *line)
 
 
 	svndump_init_fd(dumpin_fd, report_fd);
-	svndump_read(url, private_ref);
+	svndump_read(url, private_ref, notes_ref);
 	svndump_deinit();
 	svndump_reset();
 
@@ -220,6 +284,10 @@ int main(int argc, const char **argv)
 	strbuf_addf(&buf, "refs/svn/%s/master", remote->name);
 	private_ref = strbuf_detach(&buf, NULL);
 
+	strbuf_init(&buf, 0);
+	strbuf_addf(&buf, "refs/notes/%s/revs", remote->name);
+	notes_ref = strbuf_detach(&buf, NULL);
+
 	while(1) {
 		if (strbuf_getline(&buf, stdin, '\n') == EOF) {
 			if (ferror(stdin))
@@ -235,5 +303,6 @@ int main(int argc, const char **argv)
 	strbuf_release(&buf);
 	free((void*)url);
 	free((void*)private_ref);
+	free((void*)notes_ref);
 	return 0;
 }
diff --git a/contrib/svn-fe/svn-fe.c b/contrib/svn-fe/svn-fe.c
index c796cc0..f363505 100644
--- a/contrib/svn-fe/svn-fe.c
+++ b/contrib/svn-fe/svn-fe.c
@@ -10,7 +10,8 @@ int main(int argc, char **argv)
 {
 	if (svndump_init(NULL))
 		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_reset();
 	return 0;
diff --git a/test-svn-fe.c b/test-svn-fe.c
index bb0e980..2740570 100644
--- a/test-svn-fe.c
+++ b/test-svn-fe.c
@@ -40,7 +40,7 @@ int main(int argc, char *argv[])
 	if (argc == 2) {
 		if (svndump_init(argv[1]))
 			return 1;
-		svndump_read(NULL, "refs/remotes/svn/master");
+		svndump_read(NULL, "refs/remotes/svn/master", "refs/notes/svn/revs");
 		svndump_deinit();
 		svndump_reset();
 		return 0;
diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c
index 796dd1a..32f71a1 100644
--- a/vcs-svn/fast_export.c
+++ b/vcs-svn/fast_export.c
@@ -70,14 +70,20 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)
 }
 
 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;
 	timestamp = 1341914616;
 	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("data %"PRIuMAX"\n", loglen);
 	fwrite(log, loglen, 1, stdout);
+	if (firstnote) {
+		if (revision > 1)
+			printf("from %s^0", note_ref);
+		firstnote = 0;
+	}
 	fputc('\n', stdout);
 }
 
@@ -90,7 +96,7 @@ static char gitsvnline[MAX_GITSVN_LINE_LEN];
 void fast_export_begin_commit(uint32_t revision, const char *author,
 			const struct strbuf *log,
 			const char *uuid, const char *url,
-			unsigned long timestamp, const char *local_ref)
+			unsigned long timestamp, const char *local_ref, const char *parent)
 {
 	static const struct strbuf empty = STRBUF_INIT;
 	if (!log)
@@ -113,7 +119,9 @@ void fast_export_begin_commit(uint32_t revision, const char *author,
 	fwrite(log->buf, log->len, 1, stdout);
 	printf("%s\n", gitsvnline);
 	if (!first_commit_done) {
-		if (revision > 1)
+		if(parent)
+			printf("from %s^0\n", parent);
+		else if (revision > 1)
 			printf("from :%"PRIu32"\n", revision - 1);
 		first_commit_done = 1;
 	}
diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h
index c2f6f11..5174aae 100644
--- a/vcs-svn/fast_export.h
+++ b/vcs-svn/fast_export.h
@@ -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_note(const char *committish, const char *dataref);
 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,
-			const struct strbuf *log, const char *uuid,
-			const char *url, unsigned long timestamp, const char *local_ref);
+			const struct strbuf *log, const char *uuid,const char *url,
+			unsigned long timestamp, const char *local_ref, const char *parent);
 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_buf_to_data(const struct strbuf *data);
diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c
index f0633c6..b64802c 100644
--- a/vcs-svn/svndump.c
+++ b/vcs-svn/svndump.c
@@ -306,23 +306,23 @@ static void begin_revision(const char *remote_ref)
 		return;
 	fast_export_begin_commit(rev_ctx.revision, rev_ctx.author.buf,
 		&rev_ctx.log, dump_ctx.uuid.buf, dump_ctx.url.buf,
-		rev_ctx.timestamp, remote_ref);
+		rev_ctx.timestamp, remote_ref, rev_ctx.revision == 1 ? NULL : remote_ref);
 }
 
-static void end_revision()
+static void end_revision(const char *note_ref)
 {
 	struct strbuf mark = STRBUF_INIT;
 	if (rev_ctx.revision) {
 		fast_export_end_commit(rev_ctx.revision);
 		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);
 		fast_export_note(mark.buf, "inline");
 		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 *t;
@@ -363,7 +363,7 @@ void svndump_read(const char *url, const char *local_ref)
 			if (active_ctx == REV_CTX)
 				begin_revision(local_ref);
 			if (active_ctx != DUMP_CTX)
-				end_revision();
+				end_revision(notes_ref);
 			active_ctx = REV_CTX;
 			reset_rev_ctx(atoi(val));
 			strbuf_addf(&rev_ctx.note, "%s\n", t);
@@ -479,7 +479,7 @@ void svndump_read(const char *url, const char *local_ref)
 	if (active_ctx == REV_CTX)
 		begin_revision(local_ref);
 	if (active_ctx != DUMP_CTX)
-		end_revision();
+		end_revision(notes_ref);
 }
 
 static void init(int report_fd)
diff --git a/vcs-svn/svndump.h b/vcs-svn/svndump.h
index febeecb..b8eb129 100644
--- a/vcs-svn/svndump.h
+++ b/vcs-svn/svndump.h
@@ -3,7 +3,7 @@
 
 int svndump_init(const char *filename);
 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_reset(void);
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 13/16] Add a svnrdump-simulator replaying a dump file for testing.
  2012-07-26  7:32                       ` [RFC 12/16] remote-svn: add incremental import Florian Achleitner
@ 2012-07-26  7:32                         ` Florian Achleitner
  2012-07-26  7:32                           ` [RFC 14/16] transport-helper: add import|export-marks to fast-import command line Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  7:32 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

To ease testing without depending on a reachable svn server, this
compact python script mimics parts of svnrdumps behaviour.
It requires the remote url to start with sim://.
Start and end revisions are evaluated.
If the requested revision doesn't exist, as it is the case with
incremental imports, if no new commit was added, it returns 1
(like svnrdump).
To allow using the same dump file for simulating multiple
incremental imports the highest revision can be limited by setting
the environment variable SVNRMAX to that value. This simulates the
situation where higher revs don't exist yet.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 contrib/svn-fe/svnrdump_sim.py |   53 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100755 contrib/svn-fe/svnrdump_sim.py

diff --git a/contrib/svn-fe/svnrdump_sim.py b/contrib/svn-fe/svnrdump_sim.py
new file mode 100755
index 0000000..ab4ccf1
--- /dev/null
+++ b/contrib/svn-fe/svnrdump_sim.py
@@ -0,0 +1,53 @@
+#!/usr/bin/python
+"""
+Simulates svnrdump by replaying an existing dump from a file, taking care
+of the specified revision range.
+To simulate incremental imports the environment variable SVNRMAX can be set
+to the highest revision that should be available.
+"""
+import sys, os
+
+
+def getrevlimit():
+	var = 'SVNRMAX'
+	if os.environ.has_key(var):
+		return os.environ[var]
+	return None
+	
+def writedump(url, lower, upper):
+	if url.startswith('sim://'):
+		filename = url[6:]
+		if filename[-1] == '/': filename = filename[:-1] #remove terminating slash
+	else:
+		raise ValueError('sim:// url required')
+	f = open(filename, 'r');
+	state = 'header'
+	wroterev = False
+	while(True):
+		l = f.readline()
+		if l == '': break
+		if state == 'header' and l.startswith('Revision-number: '):
+			state = 'prefix'
+		if state == 'prefix' and l == 'Revision-number: %s\n' % lower:
+			state = 'selection'
+		if not upper == 'HEAD' and state == 'selection' and l == 'Revision-number: %s\n' % upper:
+			break;
+
+		if state == 'header' or state == 'selection':
+			if state == 'selection': wroterev = True
+			sys.stdout.write(l)
+	return wroterev
+
+if __name__ == "__main__":
+	if not (len(sys.argv) in (3, 4, 5)):
+		print "usage: %s dump URL -rLOWER:UPPER"
+		sys.exit(1)
+	if not sys.argv[1] == 'dump': raise NotImplementedError('only "dump" is suppported.')
+	url = sys.argv[2]
+	r = ('0', 'HEAD')
+	if len(sys.argv) == 4 and sys.argv[3][0:2] == '-r':
+		r = sys.argv[3][2:].lstrip().split(':')
+	if not getrevlimit() is None: r[1] = getrevlimit()
+	if writedump(url, r[0], r[1]): ret = 0
+	else: ret = 1
+	sys.exit(ret)
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 14/16] transport-helper: add import|export-marks to fast-import command line.
  2012-07-26  7:32                         ` [RFC 13/16] Add a svnrdump-simulator replaying a dump file for testing Florian Achleitner
@ 2012-07-26  7:32                           ` Florian Achleitner
  2012-07-26  7:32                             ` [RFC 15/16] remote-svn: add marks-file regeneration Florian Achleitner
  2012-07-26 16:15                             ` [RFC 14/16] transport-helper: add import|export-marks to fast-import command line Florian Achleitner
  0 siblings, 2 replies; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  7:32 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

fast-import internally uses marks that refer to an object via its sha1.
Those marks are created during import to find previously created objects.
At exit the accumulated marks can be exported to a file and reloaded at
startup, so that the previous marks are available.
Add command line options to the fast-import command line to enable this.
The mark files are stored in info/fast-import/marks/<remote-name>.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 transport-helper.c |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/transport-helper.c b/transport-helper.c
index e10fd6b..74f9608 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -394,6 +394,9 @@ static int get_importer(struct transport *transport, struct child_process *fasti
 	argv_array_push(argv, "fast-import");
 	argv_array_push(argv, debug ? "--stats" : "--quiet");
 	argv_array_pushf(argv, "--cat-blob-pipe=%s", data->report_fifo);
+	argv_array_push(argv, "--relative-marks");
+	argv_array_pushf(argv, "--import-marks-if-exists=marks/%s", transport->remote->name);
+	argv_array_pushf(argv, "--export-marks=marks/%s", transport->remote->name);
 	fastimport->argv = argv->argv;
 	fastimport->git_cmd = 1;
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 15/16] remote-svn: add marks-file regeneration.
  2012-07-26  7:32                           ` [RFC 14/16] transport-helper: add import|export-marks to fast-import command line Florian Achleitner
@ 2012-07-26  7:32                             ` Florian Achleitner
  2012-07-26  7:32                               ` [RFC 16/16] Add a test script for remote-svn Florian Achleitner
  2012-07-26 16:15                             ` [RFC 14/16] transport-helper: add import|export-marks to fast-import command line Florian Achleitner
  1 sibling, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  7:32 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

fast-import mark files are stored outside the object database and are therefore
not fetched and can be lost somehow else.
marks provide a svn revision --> git sha1 mapping, while the notes that are attached
to each commit when it is imported provide a git sha1 --> svn revision.

If the marks file is not available or not plausible, regenerate it by walking through
the notes tree.
, i.e.
The plausibility check tests if the highest revision in the marks file matches the
revision of the top ref. It doesn't ensure that the mark file is completely correct.
This could only be done with an effort equal to unconditional regeneration.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 contrib/svn-fe/remote-svn.c |   78 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 77 insertions(+), 1 deletion(-)

diff --git a/contrib/svn-fe/remote-svn.c b/contrib/svn-fe/remote-svn.c
index f23b82f..054433b 100644
--- a/contrib/svn-fe/remote-svn.c
+++ b/contrib/svn-fe/remote-svn.c
@@ -27,7 +27,7 @@ static const char *url;
 static int dump_from_file;
 static const char *private_ref;
 static const char *remote_ref = "refs/heads/master";
-static const char *notes_ref;
+static const char *notes_ref, *marksfilename;
 struct rev_note { unsigned int rev_nr; };
 
 /*
@@ -97,6 +97,75 @@ static int parse_rev_note(const char *msg, struct rev_note *res) {
 	return 0;
 }
 
+static int note2mark_cb(const unsigned char *object_sha1,
+		const unsigned char *note_sha1, char *note_path,
+		void *cb_data) {
+	FILE *file = (FILE *)cb_data;
+	char *msg;
+	unsigned long msglen;
+	enum object_type type;
+	struct rev_note note;
+	if (!(msg = read_sha1_file(note_sha1, &type, &msglen)) ||
+			!msglen || type != OBJ_BLOB) {
+		free(msg);
+		return 1;
+	}
+	if (parse_rev_note(msg, &note))
+		return 2;
+	if (fprintf(file, ":%d %s\n", note.rev_nr, sha1_to_hex(object_sha1)) < 1)
+		return 3;
+	return 0;
+}
+
+static void regenerate_marks() {
+	int ret;
+	FILE *marksfile;
+	marksfile = fopen(marksfilename, "w+");
+	if (!marksfile)
+		die_errno("Couldn't create mark file %s.", marksfilename);
+	ret = for_each_note(NULL, 0, note2mark_cb, marksfile);
+	if (ret)
+		die("Regeneration of marks failed, returned %d.", ret);
+	fclose(marksfile);
+}
+
+static void check_or_regenerate_marks(int latestrev) {
+	FILE *marksfile;
+	char *line = NULL;
+	size_t linelen = 0;
+	struct strbuf sb = STRBUF_INIT;
+	int found = 0;
+
+	if (latestrev < 1)
+		return;
+
+	printd("checking marks file %s.", marksfilename);
+	init_notes(NULL, notes_ref, NULL, 0);
+	marksfile = fopen(marksfilename, "r");
+	if (!marksfile) {
+		printd("no marks found, regenerate.");
+		regenerate_marks(marksfile);
+	}
+	else {
+		strbuf_addf(&sb, ":%d ", latestrev);
+		while (getline(&line, &linelen, marksfile) != -1) {
+			if (!prefixcmp(line, sb.buf)) {
+				found++;
+				break;
+			}
+		}
+		fclose(marksfile);
+		if (!found) {
+			printd("marks found but doesn't contain highest rev, regenerate.");
+			regenerate_marks();
+		}
+		else
+			printd("marks found and ok.");
+	}
+	free_notes(NULL);
+	strbuf_release(&sb);
+}
+
 enum cmd_result cmd_import(struct strbuf *line)
 {
 	static int batch_active;
@@ -168,6 +237,8 @@ enum cmd_result cmd_import(struct strbuf *line)
 		}
 	}
 
+	check_or_regenerate_marks(startrev - 1);
+
 	printd("starting import from revision %u", startrev);
 
 	if(dump_from_file) {
@@ -288,6 +359,10 @@ int main(int argc, const char **argv)
 	strbuf_addf(&buf, "refs/notes/%s/revs", remote->name);
 	notes_ref = strbuf_detach(&buf, NULL);
 
+	strbuf_init(&buf, 0);
+	strbuf_addf(&buf, "%s/info/fast-import/marks/%s", get_git_dir(), remote->name);
+	marksfilename = strbuf_detach(&buf, NULL);
+
 	while(1) {
 		if (strbuf_getline(&buf, stdin, '\n') == EOF) {
 			if (ferror(stdin))
@@ -304,5 +379,6 @@ int main(int argc, const char **argv)
 	free((void*)url);
 	free((void*)private_ref);
 	free((void*)notes_ref);
+	free((void*)marksfilename);
 	return 0;
 }
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 16/16] Add a test script for remote-svn.
  2012-07-26  7:32                             ` [RFC 15/16] remote-svn: add marks-file regeneration Florian Achleitner
@ 2012-07-26  7:32                               ` Florian Achleitner
  0 siblings, 0 replies; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  7:32 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

Use svnrdump_sim.py to emulate svnrdump without an svn server.
Tests fetching, incremental fetching, fetching from file://,
and the regeneration of fast-import's marks file.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 t/t9020-remote-svn.sh |   69 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)
 create mode 100755 t/t9020-remote-svn.sh

diff --git a/t/t9020-remote-svn.sh b/t/t9020-remote-svn.sh
new file mode 100755
index 0000000..a0c6a21
--- /dev/null
+++ b/t/t9020-remote-svn.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+test_description='tests remote-svn'
+
+. ./test-lib.sh
+
+# We override svnrdump by placing a symlink to the svnrdump-emulator in .
+export PATH="$HOME:$PATH"
+ln -sf $GIT_BUILD_DIR/contrib/svn-fe/svnrdump_sim.py "$HOME/svnrdump"
+
+init_git () {
+	rm -fr .git &&
+	git init &&
+	#git remote add svnsim svn::sim:///$TEST_DIRECTORY/t9020/example.svnrdump
+	# let's reuse an exisiting dump file!?
+	git remote add svnsim svn::sim:///$TEST_DIRECTORY/t9154/svn.dump
+	git remote add svnfile svn::file:///$TEST_DIRECTORY/t9154/svn.dump
+}
+
+test_debug '
+	git --version
+	which git
+	which svnrdump
+'
+
+test_expect_success 'simple fetch' '
+	init_git &&
+	git fetch svnsim &&
+	test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master  &&
+	cp .git/refs/remotes/svnsim/master master.good
+'
+
+test_debug '
+	cat .git/refs/svn/svnsim/master
+	cat .git/refs/remotes/svnsim/master
+'
+
+test_expect_success 'repeated fetch, nothing shall change' '
+	git fetch svnsim &&
+	test_cmp master.good .git/refs/remotes/svnsim/master
+'
+
+test_expect_success 'fetch from a file:// url gives the same result' '
+	git fetch svnfile 
+'
+
+test_expect_failure 'the sha1 differ because the git-svn-id line in the commit msg contains the url' '
+	test_cmp .git/refs/remotes/svnfile/master .git/refs/remotes/svnsim/master
+'
+
+test_expect_success 'mark-file regeneration' '
+	mv .git/info/fast-import/marks/svnsim .git/info/fast-import/marks/svnsim.old &&
+	git fetch svnsim &&
+	test_cmp .git/info/fast-import/marks/svnsim.old .git/info/fast-import/marks/svnsim
+'
+
+test_expect_success 'incremental imports must lead to the same head' '
+	export SVNRMAX=3 &&
+	init_git &&
+	git fetch svnsim &&
+	test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master  &&
+	unset SVNRMAX &&
+	git fetch svnsim &&
+	test_cmp master.good .git/refs/remotes/svnsim/master
+'
+
+test_debug 'git branch -a'	
+
+test_done
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: [RFC 01/16] Implement a remote helper for svn in C.
  2012-07-26  7:32 ` [RFC 01/16] Implement a remote helper for svn in C Florian Achleitner
  2012-07-26  7:32   ` [RFC 02/16] Integrate remote-svn into svn-fe/Makefile Florian Achleitner
@ 2012-07-26  7:46   ` Jonathan Nieder
  2012-07-26  8:02     ` Florian Achleitner
  1 sibling, 1 reply; 47+ messages in thread
From: Jonathan Nieder @ 2012-07-26  7:46 UTC (permalink / raw)
  To: Florian Achleitner; +Cc: David Michael Barr, git

Hi,

Florian Achleitner wrote:

> --- /dev/null
> +++ b/contrib/svn-fe/remote-svn.c
> @@ -0,0 +1,219 @@
> +
> +#include "cache.h"
> +#include "remote.h"
> +#include "strbuf.h"
> +#include "url.h"
> +#include "exec_cmd.h"
> +#include "run-command.h"
> +#include "svndump.h"
> +#include "argv-array.h"
> +
> +static int debug;
> +
> +static inline void printd(const char *fmt, ...)

I remember reviewing this before, and mentioning that this could be
replaced with trace_printf() and that would simplify some code and
improve the functionality.  I think I also remember giving some other
suggestions, but I don't have it in front of me so I can't be sure
(should have more time this weekend).

Did you look over that review?  Did you have any questions about it,
or was it just full of bad ideas, or something else?

It's silly and vain of me, but I'm not motivated by the idea of
spending more time looking over this without anything coming of it.
(Rejecting suggestions is fine, but sending feedback when doing so is
important because otherwise reviewers get demotivated.)

Hope that helps,
Jonathan

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 01/16] Implement a remote helper for svn in C.
  2012-07-26  7:46   ` [RFC 01/16] Implement a remote helper for svn in C Jonathan Nieder
@ 2012-07-26  8:02     ` Florian Achleitner
  2012-07-26  8:14       ` Jonathan Nieder
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  8:02 UTC (permalink / raw)
  To: Jonathan Nieder; +Cc: Florian Achleitner, David Michael Barr, git

On Thursday 26 July 2012 02:46:07 Jonathan Nieder wrote:
> Hi,
> 
> Florian Achleitner wrote:
> > --- /dev/null
> > +++ b/contrib/svn-fe/remote-svn.c
> > @@ -0,0 +1,219 @@
> > +
> > +#include "cache.h"
> > +#include "remote.h"
> > +#include "strbuf.h"
> > +#include "url.h"
> > +#include "exec_cmd.h"
> > +#include "run-command.h"
> > +#include "svndump.h"
> > +#include "argv-array.h"
> > +
> > +static int debug;
> > +
> > +static inline void printd(const char *fmt, ...)
> 
> I remember reviewing this before, and mentioning that this could be
> replaced with trace_printf() and that would simplify some code and
> improve the functionality.  I think I also remember giving some other
> suggestions, but I don't have it in front of me so I can't be sure
> (should have more time this weekend).
> 
> Did you look over that review?  Did you have any questions about it,
> or was it just full of bad ideas, or something else?
> 
> It's silly and vain of me, but I'm not motivated by the idea of
> spending more time looking over this without anything coming of it.
> (Rejecting suggestions is fine, but sending feedback when doing so is
> important because otherwise reviewers get demotivated.)

Yes, I incorporated your review in the new version, as far as applicable. But 
I didn't send you an answer on the detailed points. 
I will send an answer to the previous review ..

> 
> Hope that helps,
> Jonathan

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 01/16] Implement a remote helper for svn in C.
  2012-07-26  8:02     ` Florian Achleitner
@ 2012-07-26  8:14       ` Jonathan Nieder
  2012-07-26  8:37         ` Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Jonathan Nieder @ 2012-07-26  8:14 UTC (permalink / raw)
  To: Florian Achleitner; +Cc: David Michael Barr, git

Florian Achleitner wrote:

> Yes, I incorporated your review in the new version, as far as applicable. But 
> I didn't send you an answer on the detailed points. 
> I will send an answer to the previous review ..

Thanks.  Now that I check, I see that you did make lots of important
changes and probably lost the one I noticed just now in the noise.

Another way to keep reviewers happy is to describe what changed since
the last revision under the triple-dash for each patch when sending
out a new set of patches.  That way, they can see that there was
progress and there is less frustration when one specific change didn't
make it.

See http://thread.gmane.org/gmane.comp.version-control.git/176203
for example.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 01/16] Implement a remote helper for svn in C.
  2012-07-26  8:14       ` Jonathan Nieder
@ 2012-07-26  8:37         ` Florian Achleitner
  0 siblings, 0 replies; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26  8:37 UTC (permalink / raw)
  To: Jonathan Nieder; +Cc: Florian Achleitner, David Michael Barr, git

On Thursday 26 July 2012 03:14:43 Jonathan Nieder wrote:
> Florian Achleitner wrote:
> > Yes, I incorporated your review in the new version, as far as applicable.
> > But I didn't send you an answer on the detailed points.
> > I will send an answer to the previous review ..
> 
> Thanks.  Now that I check, I see that you did make lots of important
> changes and probably lost the one I noticed just now in the noise.
> 
> Another way to keep reviewers happy is to describe what changed since
> the last revision under the triple-dash for each patch when sending
> out a new set of patches.  That way, they can see that there was
> progress and there is less frustration when one specific change didn't
> make it.
> 
> See http://thread.gmane.org/gmane.comp.version-control.git/176203
> for example.

Yeah, that makes sense.
In this reroll, I really changed a lot, order and scope of patches is very 
different. Many haven't hit the list yet. I wanted to write a new more useful 
history.
The first patch, this one, consists of many enhancement commits I made after 
each other, finally integrated into one.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 14/16] transport-helper: add import|export-marks to fast-import command line.
  2012-07-26  7:32                           ` [RFC 14/16] transport-helper: add import|export-marks to fast-import command line Florian Achleitner
  2012-07-26  7:32                             ` [RFC 15/16] remote-svn: add marks-file regeneration Florian Achleitner
@ 2012-07-26 16:15                             ` Florian Achleitner
  2012-07-28  7:06                               ` Jonathan Nieder
  1 sibling, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-26 16:15 UTC (permalink / raw)
  To: git
  Cc: Florian Achleitner, Jonathan Nieder, David Michael Barr,
	Sverre Rabbelier


I just found that for fast-export something similar was added to transport-
helper in a515ebe9.
By adding a capabilities advertised by the remote helper. Probably that would 
be a nicer way to do that.
Btw, these added capabilities are not mentioned in Docs.

On Thursday 26 July 2012 09:32:35 Florian Achleitner wrote:
> fast-import internally uses marks that refer to an object via its sha1.
> Those marks are created during import to find previously created objects.
> At exit the accumulated marks can be exported to a file and reloaded at
> startup, so that the previous marks are available.
> Add command line options to the fast-import command line to enable this.
> The mark files are stored in info/fast-import/marks/<remote-name>.
> 
> Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
> ---
>  transport-helper.c |    3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/transport-helper.c b/transport-helper.c
> index e10fd6b..74f9608 100644
> --- a/transport-helper.c
> +++ b/transport-helper.c
> @@ -394,6 +394,9 @@ static int get_importer(struct transport *transport,
> struct child_process *fasti argv_array_push(argv, "fast-import");
>  	argv_array_push(argv, debug ? "--stats" : "--quiet");
>  	argv_array_pushf(argv, "--cat-blob-pipe=%s", data->report_fifo);
> +	argv_array_push(argv, "--relative-marks");
> +	argv_array_pushf(argv, "--import-marks-if-exists=marks/%s",
> transport->remote->name); +	argv_array_pushf(argv,
> "--export-marks=marks/%s", transport->remote->name); fastimport->argv =
> argv->argv;
>  	fastimport->git_cmd = 1;

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 14/16] transport-helper: add import|export-marks to fast-import command line.
  2012-07-26 16:15                             ` [RFC 14/16] transport-helper: add import|export-marks to fast-import command line Florian Achleitner
@ 2012-07-28  7:06                               ` Jonathan Nieder
  0 siblings, 0 replies; 47+ messages in thread
From: Jonathan Nieder @ 2012-07-28  7:06 UTC (permalink / raw)
  To: Florian Achleitner; +Cc: git, David Michael Barr, Sverre Rabbelier

Hi,

Florian Achleitner wrote:

>           a515ebe9.
[...]
> Btw, these added capabilities are not mentioned in Docs.

Sverre, any hints about how these (capabilities "import-marks <file>"
and "export-marks <file>") are meant to be used?  Why would one use
these instead of "feature import-marks" / "feature export-marks"?
Should there be a corresponding capability for relative-marks, too?

Curious,
Jonathan

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [RFC v2 00/16] GSOC remote-svn, rewritten patch series
  2012-07-26  7:32 [RFC 00/16] GSOC remote-svn, rewritten patch series Florian Achleitner
  2012-07-26  7:32 ` [RFC 01/16] Implement a remote helper for svn in C Florian Achleitner
@ 2012-07-30 14:31 ` Florian Achleitner
  2012-07-30 14:31   ` [RFC v2 01/16] Implement a remote helper for svn in C Florian Achleitner
  1 sibling, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-30 14:31 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

Updated after reviews.
Diff:
- remove all debug messages (printd).
- clarify url processing by splitting it into two variables url_in and url.
- Redesign to a central command dipatcher keeping a state (batch_active, batch_command).
	- remove tristate return value and the enum.
	- checks whether the batch is consistent and dies otherwise.

Changes concenctrate on patch 01, but have some tiny influence on the rest of 
the series (no more printd). 

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [RFC v2 01/16] Implement a remote helper for svn in C.
  2012-07-30 14:31 ` [RFC v2 00/16] GSOC remote-svn, rewritten patch series Florian Achleitner
@ 2012-07-30 14:31   ` Florian Achleitner
  2012-07-30 14:31     ` [RFC v2 02/16] Integrate remote-svn into svn-fe/Makefile Florian Achleitner
  2012-07-30 16:28     ` [RFC v2 01/16] Implement a remote helper for svn in C Junio C Hamano
  0 siblings, 2 replies; 47+ messages in thread
From: Florian Achleitner @ 2012-07-30 14:31 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

Enables basic fetching from subversion repositories. When processing Remote URLs
starting with svn::, git invokes this remote-helper.
It starts svnrdump to extract revisions from the subversion repository in the
'dump file format', and converts them to a git-fast-import stream using
the functions of vcs-svn/.

Imported refs are created in a private namespace at refs/svn/<remote-name/master.
The revision history is imported linearly (no branch detection) and completely,
i.e. from revision 0 to HEAD.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 contrib/svn-fe/remote-svn.c |  190 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 190 insertions(+)
 create mode 100644 contrib/svn-fe/remote-svn.c

diff --git a/contrib/svn-fe/remote-svn.c b/contrib/svn-fe/remote-svn.c
new file mode 100644
index 0000000..d5c2df8
--- /dev/null
+++ b/contrib/svn-fe/remote-svn.c
@@ -0,0 +1,190 @@
+
+#include "cache.h"
+#include "remote.h"
+#include "strbuf.h"
+#include "url.h"
+#include "exec_cmd.h"
+#include "run-command.h"
+#include "svndump.h"
+#include "argv-array.h"
+
+static const char *url;
+static const char *private_ref;
+static const char *remote_ref = "refs/heads/master";
+
+int cmd_capabilities(struct strbuf *line);
+int cmd_import(struct strbuf *line);
+int cmd_list(struct strbuf *line);
+
+typedef int (*input_command_handler)(struct strbuf *);
+struct input_command_entry {
+	const char *name;
+	input_command_handler fct;
+	unsigned char batchable;	/* whether the command starts or is part of a batch */
+};
+
+static const struct input_command_entry input_command_list[] = {
+		{ "capabilities", cmd_capabilities, 0 },
+		{ "import", cmd_import, 1 },
+		{ "list", cmd_list, 0 },
+		{ NULL, NULL }
+};
+
+int cmd_capabilities(struct strbuf *line)
+{
+	printf("import\n");
+	printf("refspec %s:%s\n\n", remote_ref, private_ref);
+	fflush(stdout);
+	return 0;
+}
+
+static void terminate_batch() {
+	/* terminate a current batch's fast-import stream */
+		printf("done\n");
+		fflush(stdout);
+}
+
+int cmd_import(struct strbuf *line)
+{
+	int code, report_fd;
+	char *back_pipe_env;
+	int dumpin_fd;
+	unsigned int startrev = 0;
+	struct argv_array svndump_argv = ARGV_ARRAY_INIT;
+	struct child_process svndump_proc;
+
+	/*
+	 * When the remote-helper is invoked by transport-helper.c it passes the
+	 * filename of this pipe in the env-var.
+	 */
+	back_pipe_env = getenv("GIT_REPORT_FIFO");
+	if (!back_pipe_env) {
+		die("Cannot get cat-blob-pipe from environment! GIT_REPORT_FIFO has to"
+				"be set by the caller.");
+	}
+
+	/*
+	 * Opening a fifo for reading usually blocks until a writer has opened it too.
+	 * Opening a fifo for writing usually blocks until a reader has opened it too.
+	 * Therefore, we open with RDWR on both sides to avoid deadlocks.
+	 * Especially if there's nothing to do and one pipe end is closed immediately.
+	 */
+	report_fd = open(back_pipe_env, O_RDWR);
+	if (report_fd < 0) {
+		die("Unable to open fast-import back-pipe! %s", strerror(errno));
+	}
+
+	memset(&svndump_proc, 0, sizeof (struct child_process));
+	svndump_proc.out = -1;
+	argv_array_push(&svndump_argv, "svnrdump");
+	argv_array_push(&svndump_argv, "dump");
+	argv_array_push(&svndump_argv, url);
+	argv_array_pushf(&svndump_argv, "-r%u:HEAD", startrev);
+	svndump_proc.argv = svndump_argv.argv;
+
+	code = start_command(&svndump_proc);
+	if (code)
+		die("Unable to start %s, code %d", svndump_proc.argv[0], code);
+	dumpin_fd = svndump_proc.out;
+
+	svndump_init_fd(dumpin_fd, report_fd);
+	svndump_read(url, private_ref);
+	svndump_deinit();
+	svndump_reset();
+
+	close(dumpin_fd);
+	close(report_fd);
+	code = finish_command(&svndump_proc);
+	if (code)
+		warning("%s, returned %d", svndump_proc.argv[0], code);
+	argv_array_clear(&svndump_argv);
+
+	return 0;
+}
+
+int cmd_list(struct strbuf *line)
+{
+	printf("? HEAD\n");
+	printf("? %s\n\n", remote_ref);
+	fflush(stdout);
+	return 0;
+}
+
+int do_command(struct strbuf *line)
+{
+	const struct input_command_entry *p = input_command_list;
+	static int batch_active;
+	static struct strbuf batch_command = STRBUF_INIT;
+	/*
+	 * import commands can be grouped together in a batch.
+	 * Batches are ended by \n. If no batch is active the program ends.
+	 */
+	if (line->len == 0 ) {
+		if (batch_active) {
+			terminate_batch();
+			batch_active = 0;
+			return 0;
+		}
+		return 1;
+	}
+	if (batch_active && strcmp(batch_command.buf, line->buf))
+		die("Active %s batch interrupted by %s", batch_command.buf, line->buf);
+
+	for(p = input_command_list; p->name; p++) {
+		if (!prefixcmp(line->buf, p->name) &&
+				(strlen(p->name) == line->len || line->buf[strlen(p->name)] == ' ')) {
+			if (p->batchable) {
+				batch_active = 1;
+				strbuf_release(&batch_command);
+				strbuf_addbuf(&batch_command, line);
+			}
+			return p->fct(line);
+		}
+	}
+	warning("Unknown command '%s'\n", line->buf);
+	return 0;
+}
+
+int main(int argc, const char **argv)
+{
+	struct strbuf buf = STRBUF_INIT;
+	int nongit;
+	static struct remote *remote;
+	const char *url_in;
+
+	git_extract_argv0_path(argv[0]);
+	setup_git_directory_gently(&nongit);
+	if (argc < 2 || argc > 3) {
+		usage("git-remote-svn <remote-name> [<url>]");
+		return 1;
+	}
+
+	remote = remote_get(argv[1]);
+	url_in = remote->url[0];
+	if (argc == 3)
+		url_in = argv[2];
+
+	end_url_with_slash(&buf, url_in);
+	url = strbuf_detach(&buf, NULL);
+
+	strbuf_init(&buf, 0);
+	strbuf_addf(&buf, "refs/svn/%s/master", remote->name);
+	private_ref = strbuf_detach(&buf, NULL);
+
+	while(1) {
+		if (strbuf_getline(&buf, stdin, '\n') == EOF) {
+			if (ferror(stdin))
+				die_errno("Error reading command stream");
+			else
+				die_errno("Unexpected end of command stream");
+		}
+		if (do_command(&buf))
+			break;
+		strbuf_reset(&buf);
+	}
+
+	strbuf_release(&buf);
+	free((void*)url);
+	free((void*)private_ref);
+	return 0;
+}
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC v2 02/16] Integrate remote-svn into svn-fe/Makefile.
  2012-07-30 14:31   ` [RFC v2 01/16] Implement a remote helper for svn in C Florian Achleitner
@ 2012-07-30 14:31     ` Florian Achleitner
  2012-07-30 14:31       ` [RFC v2 03/16] Add svndump_init_fd to allow reading dumps from arbitrary FDs Florian Achleitner
  2012-07-30 16:28     ` [RFC v2 01/16] Implement a remote helper for svn in C Junio C Hamano
  1 sibling, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-30 14:31 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

Requires some sha.h to be used and the libraries
to be linked, this is currently hardcoded.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 contrib/svn-fe/Makefile |   16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/contrib/svn-fe/Makefile b/contrib/svn-fe/Makefile
index 360d8da..8f0eec2 100644
--- a/contrib/svn-fe/Makefile
+++ b/contrib/svn-fe/Makefile
@@ -1,14 +1,14 @@
-all:: svn-fe$X
+all:: svn-fe$X remote-svn$X
 
 CC = gcc
 RM = rm -f
 MV = mv
 
-CFLAGS = -g -O2 -Wall
+CFLAGS = -g -O2 -Wall -DSHA1_HEADER='<openssl/sha.h>' -Wdeclaration-after-statement
 LDFLAGS =
 ALL_CFLAGS = $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)
-EXTLIBS =
+EXTLIBS = -lssl -lcrypto -lpthread ../../xdiff/lib.a
 
 GIT_LIB = ../../libgit.a
 VCSSVN_LIB = ../../vcs-svn/lib.a
@@ -37,8 +37,12 @@ svn-fe$X: svn-fe.o $(VCSSVN_LIB) $(GIT_LIB)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ svn-fe.o \
 		$(ALL_LDFLAGS) $(LIBS)
 
-svn-fe.o: svn-fe.c ../../vcs-svn/svndump.h
-	$(QUIET_CC)$(CC) -I../../vcs-svn -o $*.o -c $(ALL_CFLAGS) $<
+remote-svn$X: remote-svn.o $(VCSSVN_LIB) $(GIT_LIB)
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ remote-svn.o \
+		$(ALL_LDFLAGS) $(LIBS)
+		
+%.o: %.c ../../vcs-svn/svndump.h
+	$(QUIET_CC)$(CC) -I../../vcs-svn -I../../ -o $*.o -c $(ALL_CFLAGS) $<
 
 svn-fe.html: svn-fe.txt
 	$(QUIET_SUBDIR0)../../Documentation $(QUIET_SUBDIR1) \
@@ -58,6 +62,6 @@ svn-fe.1: svn-fe.txt
 	$(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) libgit.a
 
 clean:
-	$(RM) svn-fe$X svn-fe.o svn-fe.html svn-fe.xml svn-fe.1
+	$(RM) svn-fe$X svn-fe.o svn-fe.html svn-fe.xml svn-fe.1 remote-svn.o
 
 .PHONY: all clean FORCE
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC v2 03/16] Add svndump_init_fd to allow reading dumps from arbitrary FDs.
  2012-07-30 14:31     ` [RFC v2 02/16] Integrate remote-svn into svn-fe/Makefile Florian Achleitner
@ 2012-07-30 14:31       ` Florian Achleitner
  2012-07-30 14:31         ` [RFC v2 04/16] Add cat-blob report fifo from fast-import to remote-helper Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-30 14:31 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

The existing function only allows reading from a filename or
from stdin. Allow passing of a FD and an additional FD for
the back report pipe. This allows us to retrieve the name of
the pipe in the caller.

Fixes the filename could be NULL bug.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 vcs-svn/svndump.c |   22 ++++++++++++++++++----
 vcs-svn/svndump.h |    1 +
 2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c
index 2b168ae..76b42b2 100644
--- a/vcs-svn/svndump.c
+++ b/vcs-svn/svndump.c
@@ -468,11 +468,9 @@ void svndump_read(const char *url)
 		end_revision();
 }
 
-int svndump_init(const char *filename)
+static void init(int report_fd)
 {
-	if (buffer_init(&input, filename))
-		return error("cannot open %s: %s", filename, strerror(errno));
-	fast_export_init(REPORT_FILENO);
+	fast_export_init(report_fd);
 	strbuf_init(&dump_ctx.uuid, 4096);
 	strbuf_init(&dump_ctx.url, 4096);
 	strbuf_init(&rev_ctx.log, 4096);
@@ -482,6 +480,22 @@ int svndump_init(const char *filename)
 	reset_dump_ctx(NULL);
 	reset_rev_ctx(0);
 	reset_node_ctx(NULL);
+	return;
+}
+
+int svndump_init(const char *filename)
+{
+	if (buffer_init(&input, filename))
+		return error("cannot open %s: %s", filename ? filename : "NULL", strerror(errno));
+	init(REPORT_FILENO);
+	return 0;
+}
+
+int svndump_init_fd(int in_fd, int back_fd)
+{
+	if(buffer_fdinit(&input, in_fd))
+		return error("cannot open fd %d: %s", in_fd, strerror(errno));
+	init(back_fd);
 	return 0;
 }
 
diff --git a/vcs-svn/svndump.h b/vcs-svn/svndump.h
index df9ceb0..acb5b47 100644
--- a/vcs-svn/svndump.h
+++ b/vcs-svn/svndump.h
@@ -2,6 +2,7 @@
 #define SVNDUMP_H_
 
 int svndump_init(const char *filename);
+int svndump_init_fd(int in_fd, int back_fd);
 void svndump_read(const char *url);
 void svndump_deinit(void);
 void svndump_reset(void);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC v2 04/16] Add cat-blob report fifo from fast-import to remote-helper.
  2012-07-30 14:31       ` [RFC v2 03/16] Add svndump_init_fd to allow reading dumps from arbitrary FDs Florian Achleitner
@ 2012-07-30 14:31         ` Florian Achleitner
  2012-07-30 14:31           ` [RFC v2 05/16] remote-svn, vcs-svn: Enable fetching to private refs Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-30 14:31 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

For some fast-import commands (e.g. cat-blob) an answer-channel
is required. For this purpose a fifo (aka named pipe) (mkfifo)
is created (.git/fast-import-report-fifo) by the transport-helper
when fetch via import is requested. The remote-helper and
fast-import open the ends of the pipe.

The filename of the fifo is passed to the remote-helper via
it's environment, helpers that don't use fast-import can
simply ignore it.
Add a new command line option --cat-blob-pipe to fast-import,
for this purpose.

Use argv_arrays in get_helper and get_importer.

Opening the pipe with O_RDWR prevents blocking open calls on both ends.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 fast-import.c      |   14 ++++++++++++
 transport-helper.c |   64 ++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 63 insertions(+), 15 deletions(-)

diff --git a/fast-import.c b/fast-import.c
index eed97c8..7619449 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -3180,6 +3180,15 @@ static void option_cat_blob_fd(const char *fd)
 	cat_blob_fd = (int) n;
 }
 
+static void option_cat_blob_pipe(const char *name)
+{
+	int report_fd = open(name, O_RDWR);
+	if(report_fd < 0) {
+		die("Unable to open fast-import back-pipe! %s", strerror(errno));
+	}
+	cat_blob_fd = report_fd;
+}
+
 static void option_export_pack_edges(const char *edges)
 {
 	if (pack_edges)
@@ -3337,6 +3346,11 @@ static void parse_argv(void)
 			continue;
 		}
 
+		if(!prefixcmp(a + 2, "cat-blob-pipe=")) {
+			option_cat_blob_pipe(a + 2 + strlen("cat-blob-pipe="));
+			continue;
+		}
+
 		die("unknown option %s", a);
 	}
 	if (i != global_argc)
diff --git a/transport-helper.c b/transport-helper.c
index 61c928f..616db91 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -10,6 +10,7 @@
 #include "string-list.h"
 #include "thread-utils.h"
 #include "sigchain.h"
+#include "argv-array.h"
 
 static int debug;
 
@@ -17,6 +18,7 @@ struct helper_data {
 	const char *name;
 	struct child_process *helper;
 	FILE *out;
+	char *report_fifo;
 	unsigned fetch : 1,
 		import : 1,
 		export : 1,
@@ -101,6 +103,7 @@ static void do_take_over(struct transport *transport)
 static struct child_process *get_helper(struct transport *transport)
 {
 	struct helper_data *data = transport->data;
+	struct argv_array argv = ARGV_ARRAY_INIT;
 	struct strbuf buf = STRBUF_INIT;
 	struct child_process *helper;
 	const char **refspecs = NULL;
@@ -111,6 +114,7 @@ static struct child_process *get_helper(struct transport *transport)
 	char git_dir_buf[sizeof(GIT_DIR_ENVIRONMENT) + PATH_MAX + 1];
 	const char *helper_env[] = {
 		git_dir_buf,
+		NULL,	/* placeholder */
 		NULL
 	};
 
@@ -122,17 +126,23 @@ static struct child_process *get_helper(struct transport *transport)
 	helper->in = -1;
 	helper->out = -1;
 	helper->err = 0;
-	helper->argv = xcalloc(4, sizeof(*helper->argv));
-	strbuf_addf(&buf, "git-remote-%s", data->name);
-	helper->argv[0] = strbuf_detach(&buf, NULL);
-	helper->argv[1] = transport->remote->name;
-	helper->argv[2] = remove_ext_force(transport->url);
+	argv_array_pushf(&argv, "git-remote-%s", data->name);
+	argv_array_push(&argv, transport->remote->name);
+	argv_array_push(&argv, remove_ext_force(transport->url));
+	helper->argv = argv.argv;
 	helper->git_cmd = 0;
 	helper->silent_exec_failure = 1;
 
 	snprintf(git_dir_buf, sizeof(git_dir_buf), "%s=%s", GIT_DIR_ENVIRONMENT, get_git_dir());
 	helper->env = helper_env;
 
+	strbuf_init(&buf, 0);
+	strbuf_addf(&buf, "%s/fast-import-report-fifo", get_git_dir());
+	data->report_fifo = strbuf_detach(&buf, NULL);
+	strbuf_init(&buf, 0);
+	strbuf_addf(&buf, "GIT_REPORT_FIFO=%s", data->report_fifo);
+	helper_env[1] = strbuf_detach(&buf, NULL);
+
 	code = start_command(helper);
 	if (code < 0 && errno == ENOENT)
 		die("Unable to find remote helper for '%s'", data->name);
@@ -141,6 +151,8 @@ static struct child_process *get_helper(struct transport *transport)
 
 	data->helper = helper;
 	data->no_disconnect_req = 0;
+	free((void*) helper_env[1]);
+	argv_array_clear(&argv);
 
 	/*
 	 * Open the output as FILE* so strbuf_getline() can be used.
@@ -237,13 +249,13 @@ static int disconnect_helper(struct transport *transport)
 			xwrite(data->helper->in, "\n", 1);
 			sigchain_pop(SIGPIPE);
 		}
+
 		close(data->helper->in);
 		close(data->helper->out);
 		fclose(data->out);
 		res = finish_command(data->helper);
-		free((char *)data->helper->argv[0]);
-		free(data->helper->argv);
 		free(data->helper);
+		free(data->report_fifo);
 		data->helper = NULL;
 	}
 	return res;
@@ -373,16 +385,18 @@ static int fetch_with_fetch(struct transport *transport,
 	return 0;
 }
 
-static int get_importer(struct transport *transport, struct child_process *fastimport)
+static int get_importer(struct transport *transport, struct child_process *fastimport, struct argv_array *argv)
 {
 	struct child_process *helper = get_helper(transport);
+	struct helper_data *data = transport->data;
 	memset(fastimport, 0, sizeof(*fastimport));
 	fastimport->in = helper->out;
-	fastimport->argv = xcalloc(5, sizeof(*fastimport->argv));
-	fastimport->argv[0] = "fast-import";
-	fastimport->argv[1] = "--quiet";
-
+	argv_array_push(argv, "fast-import");
+	argv_array_push(argv, "--quiet");
+	argv_array_pushf(argv, "--cat-blob-pipe=%s", data->report_fifo);
+	fastimport->argv = argv->argv;
 	fastimport->git_cmd = 1;
+
 	return start_command(fastimport);
 }
 
@@ -421,10 +435,30 @@ static int fetch_with_import(struct transport *transport,
 	int i;
 	struct ref *posn;
 	struct strbuf buf = STRBUF_INIT;
+	struct argv_array importer_argv = ARGV_ARRAY_INIT;
+	struct stat fifostat;
+
+	/* create a fifo for back-reporting of fast-import to the remote helper,
+	 * if it doesn't exist. */
+	if(!stat(data->report_fifo, &fifostat)) {
+		if(S_ISFIFO(fifostat.st_mode)) {		/* exists and is fifo, unlink and recreate, to be sure that permissions are ok.. */
+			if (debug)
+				fprintf(stderr, "Debug: Remote helper: Unlinked existing fifo.\n");
+			if(unlink(data->report_fifo))
+				die_errno("Couldn't unlink fifo %s", data->report_fifo);
+		}
+		else
+			die("Fifo %s used by some other file.", data->report_fifo);
+	}
+	if(mkfifo(data->report_fifo, 0660))
+		die_errno("Couldn't create fifo %s", data->report_fifo);
+	if (debug)
+		fprintf(stderr, "Debug: Remote helper: Mkfifo %s\n", data->report_fifo);
+
 
 	get_helper(transport);
 
-	if (get_importer(transport, &fastimport))
+	if (get_importer(transport, &fastimport, &importer_argv))
 		die("Couldn't run fast-import");
 
 	for (i = 0; i < nr_heads; i++) {
@@ -441,8 +475,8 @@ static int fetch_with_import(struct transport *transport,
 
 	if (finish_command(&fastimport))
 		die("Error while running fast-import");
-	free(fastimport.argv);
-	fastimport.argv = NULL;
+
+	argv_array_clear(&importer_argv);
 
 	for (i = 0; i < nr_heads; i++) {
 		char *private;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC v2 05/16] remote-svn, vcs-svn: Enable fetching to private refs.
  2012-07-30 14:31         ` [RFC v2 04/16] Add cat-blob report fifo from fast-import to remote-helper Florian Achleitner
@ 2012-07-30 14:31           ` Florian Achleitner
  2012-07-30 14:31             ` [RFC v2 06/16] Add a symlink 'git-remote-svn' in base dir Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-30 14:31 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

The reference to update by the fast-import stream is hard-coded.
When fetching from a remote the remote-helper shall update refs
in a private namespace, i.e. a private subdir of refs/.
This namespace is defined by the 'refspec' capability, that the
remote-helper advertises as a reply to the 'capablilities' command.

Extend svndump and fast-export to allow passing the target ref.
Update svn-fe to be compatible.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 contrib/svn-fe/svn-fe.c |    2 +-
 test-svn-fe.c           |    2 +-
 vcs-svn/fast_export.c   |    4 ++--
 vcs-svn/fast_export.h   |    2 +-
 vcs-svn/svndump.c       |   14 +++++++-------
 vcs-svn/svndump.h       |    2 +-
 6 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/contrib/svn-fe/svn-fe.c b/contrib/svn-fe/svn-fe.c
index 35db24f..c796cc0 100644
--- a/contrib/svn-fe/svn-fe.c
+++ b/contrib/svn-fe/svn-fe.c
@@ -10,7 +10,7 @@ int main(int argc, char **argv)
 {
 	if (svndump_init(NULL))
 		return 1;
-	svndump_read((argc > 1) ? argv[1] : NULL);
+	svndump_read((argc > 1) ? argv[1] : NULL, "refs/heads/master");
 	svndump_deinit();
 	svndump_reset();
 	return 0;
diff --git a/test-svn-fe.c b/test-svn-fe.c
index 83633a2..bb0e980 100644
--- a/test-svn-fe.c
+++ b/test-svn-fe.c
@@ -40,7 +40,7 @@ int main(int argc, char *argv[])
 	if (argc == 2) {
 		if (svndump_init(argv[1]))
 			return 1;
-		svndump_read(NULL);
+		svndump_read(NULL, "refs/remotes/svn/master");
 		svndump_deinit();
 		svndump_reset();
 		return 0;
diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c
index 1f04697..11f8f94 100644
--- a/vcs-svn/fast_export.c
+++ b/vcs-svn/fast_export.c
@@ -72,7 +72,7 @@ static char gitsvnline[MAX_GITSVN_LINE_LEN];
 void fast_export_begin_commit(uint32_t revision, const char *author,
 			const struct strbuf *log,
 			const char *uuid, const char *url,
-			unsigned long timestamp)
+			unsigned long timestamp, const char *local_ref)
 {
 	static const struct strbuf empty = STRBUF_INIT;
 	if (!log)
@@ -84,7 +84,7 @@ void fast_export_begin_commit(uint32_t revision, const char *author,
 	} else {
 		*gitsvnline = '\0';
 	}
-	printf("commit refs/heads/master\n");
+	printf("commit %s\n", local_ref);
 	printf("mark :%"PRIu32"\n", revision);
 	printf("committer %s <%s@%s> %ld +0000\n",
 		   *author ? author : "nobody",
diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h
index 8823aca..17eb13b 100644
--- a/vcs-svn/fast_export.h
+++ b/vcs-svn/fast_export.h
@@ -11,7 +11,7 @@ void fast_export_delete(const char *path);
 void fast_export_modify(const char *path, uint32_t mode, const char *dataref);
 void fast_export_begin_commit(uint32_t revision, const char *author,
 			const struct strbuf *log, const char *uuid,
-			const char *url, unsigned long timestamp);
+			const char *url, unsigned long timestamp, const char *local_ref);
 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_blob_delta(uint32_t mode,
diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c
index 76b42b2..c0d5931 100644
--- a/vcs-svn/svndump.c
+++ b/vcs-svn/svndump.c
@@ -299,22 +299,22 @@ static void handle_node(void)
 				node_ctx.text_length, &input);
 }
 
-static void begin_revision(void)
+static void begin_revision(const char *remote_ref)
 {
 	if (!rev_ctx.revision)	/* revision 0 gets no git commit. */
 		return;
 	fast_export_begin_commit(rev_ctx.revision, rev_ctx.author.buf,
 		&rev_ctx.log, dump_ctx.uuid.buf, dump_ctx.url.buf,
-		rev_ctx.timestamp);
+		rev_ctx.timestamp, remote_ref);
 }
 
-static void end_revision(void)
+static void end_revision()
 {
 	if (rev_ctx.revision)
 		fast_export_end_commit(rev_ctx.revision);
 }
 
-void svndump_read(const char *url)
+void svndump_read(const char *url, const char *local_ref)
 {
 	char *val;
 	char *t;
@@ -353,7 +353,7 @@ void svndump_read(const char *url)
 			if (active_ctx == NODE_CTX)
 				handle_node();
 			if (active_ctx == REV_CTX)
-				begin_revision();
+				begin_revision(local_ref);
 			if (active_ctx != DUMP_CTX)
 				end_revision();
 			active_ctx = REV_CTX;
@@ -366,7 +366,7 @@ void svndump_read(const char *url)
 				if (active_ctx == NODE_CTX)
 					handle_node();
 				if (active_ctx == REV_CTX)
-					begin_revision();
+					begin_revision(local_ref);
 				active_ctx = NODE_CTX;
 				reset_node_ctx(val);
 				break;
@@ -463,7 +463,7 @@ void svndump_read(const char *url)
 	if (active_ctx == NODE_CTX)
 		handle_node();
 	if (active_ctx == REV_CTX)
-		begin_revision();
+		begin_revision(local_ref);
 	if (active_ctx != DUMP_CTX)
 		end_revision();
 }
diff --git a/vcs-svn/svndump.h b/vcs-svn/svndump.h
index acb5b47..febeecb 100644
--- a/vcs-svn/svndump.h
+++ b/vcs-svn/svndump.h
@@ -3,7 +3,7 @@
 
 int svndump_init(const char *filename);
 int svndump_init_fd(int in_fd, int back_fd);
-void svndump_read(const char *url);
+void svndump_read(const char *url, const char *local_ref);
 void svndump_deinit(void);
 void svndump_reset(void);
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC v2 06/16] Add a symlink 'git-remote-svn' in base dir.
  2012-07-30 14:31           ` [RFC v2 05/16] remote-svn, vcs-svn: Enable fetching to private refs Florian Achleitner
@ 2012-07-30 14:31             ` Florian Achleitner
  2012-07-30 14:31               ` [RFC v2 07/16] Allow reading svn dumps from files via file:// urls Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-30 14:31 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

Allow execution of git-remote-svn even if the binary
currently is located in contrib/svn-fe/.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 git-remote-svn |    1 +
 1 file changed, 1 insertion(+)
 create mode 120000 git-remote-svn

diff --git a/git-remote-svn b/git-remote-svn
new file mode 120000
index 0000000..d3b1c07
--- /dev/null
+++ b/git-remote-svn
@@ -0,0 +1 @@
+contrib/svn-fe/remote-svn
\ No newline at end of file
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC v2 07/16] Allow reading svn dumps from files via file:// urls.
  2012-07-30 14:31             ` [RFC v2 06/16] Add a symlink 'git-remote-svn' in base dir Florian Achleitner
@ 2012-07-30 14:31               ` Florian Achleitner
  2012-07-30 14:31                 ` [RFC v2 08/16] vcs-svn: add fast_export_note to create notes Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-30 14:31 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

For testing as well as for importing large, already
available dumps, it's useful to bypass svnrdump and
replay the svndump from a file directly.

Add support for file:// urls in the remote url.
e.g. svn::file:///path/to/dump
When the remote helper finds an url starting with
file:// it tries to open that file instead of invoking svnrdump.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 contrib/svn-fe/remote-svn.c |   54 +++++++++++++++++++++++++++++--------------
 1 file changed, 37 insertions(+), 17 deletions(-)

diff --git a/contrib/svn-fe/remote-svn.c b/contrib/svn-fe/remote-svn.c
index d5c2df8..9dcf78b 100644
--- a/contrib/svn-fe/remote-svn.c
+++ b/contrib/svn-fe/remote-svn.c
@@ -9,6 +9,7 @@
 #include "argv-array.h"
 
 static const char *url;
+static int dump_from_file;
 static const char *private_ref;
 static const char *remote_ref = "refs/heads/master";
 
@@ -74,18 +75,28 @@ int cmd_import(struct strbuf *line)
 		die("Unable to open fast-import back-pipe! %s", strerror(errno));
 	}
 
-	memset(&svndump_proc, 0, sizeof (struct child_process));
-	svndump_proc.out = -1;
-	argv_array_push(&svndump_argv, "svnrdump");
-	argv_array_push(&svndump_argv, "dump");
-	argv_array_push(&svndump_argv, url);
-	argv_array_pushf(&svndump_argv, "-r%u:HEAD", startrev);
-	svndump_proc.argv = svndump_argv.argv;
+	if(dump_from_file) {
+		dumpin_fd = open(url, O_RDONLY);
+		if(dumpin_fd < 0) {
+			die_errno("Couldn't open svn dump file %s.", url);
+		}
+	}
+	else {
+		memset(&svndump_proc, 0, sizeof (struct child_process));
+		svndump_proc.out = -1;
+		argv_array_push(&svndump_argv, "svnrdump");
+		argv_array_push(&svndump_argv, "dump");
+		argv_array_push(&svndump_argv, url);
+		argv_array_pushf(&svndump_argv, "-r%u:HEAD", startrev);
+		svndump_proc.argv = svndump_argv.argv;
+
+		code = start_command(&svndump_proc);
+		if (code)
+			die("Unable to start %s, code %d", svndump_proc.argv[0], code);
+		dumpin_fd = svndump_proc.out;
+
+	}
 
-	code = start_command(&svndump_proc);
-	if (code)
-		die("Unable to start %s, code %d", svndump_proc.argv[0], code);
-	dumpin_fd = svndump_proc.out;
 
 	svndump_init_fd(dumpin_fd, report_fd);
 	svndump_read(url, private_ref);
@@ -94,10 +105,12 @@ int cmd_import(struct strbuf *line)
 
 	close(dumpin_fd);
 	close(report_fd);
-	code = finish_command(&svndump_proc);
-	if (code)
-		warning("%s, returned %d", svndump_proc.argv[0], code);
-	argv_array_clear(&svndump_argv);
+	if(!dump_from_file) {
+		code = finish_command(&svndump_proc);
+		if (code)
+			warning("%s, returned %d", svndump_proc.argv[0], code);
+		argv_array_clear(&svndump_argv);
+	}
 
 	return 0;
 }
@@ -164,8 +177,15 @@ int main(int argc, const char **argv)
 	if (argc == 3)
 		url_in = argv[2];
 
-	end_url_with_slash(&buf, url_in);
-	url = strbuf_detach(&buf, NULL);
+	if (!prefixcmp(url_in, "file://")) {
+		dump_from_file = 1;
+		url = url_decode(url_in + sizeof("file://")-1);
+	}
+	else {
+		dump_from_file = 0;
+		end_url_with_slash(&buf, url_in);
+		url = strbuf_detach(&buf, NULL);
+	}
 
 	strbuf_init(&buf, 0);
 	strbuf_addf(&buf, "refs/svn/%s/master", remote->name);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC v2 08/16] vcs-svn: add fast_export_note to create notes
  2012-07-30 14:31               ` [RFC v2 07/16] Allow reading svn dumps from files via file:// urls Florian Achleitner
@ 2012-07-30 14:31                 ` Florian Achleitner
  2012-07-30 14:31                   ` [RFC v2 09/16] Create a note for every imported commit containing svn metadata Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-30 14:31 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git
  Cc: florian.achleitner.2.6.31, Dmitry Ivankov

From: Dmitry Ivankov <divanorama@gmail.com>

fast_export lacked a method to writes notes to fast-import stream.
Add two new functions fast_export_note which is similar to
fast_export_modify. And also add fast_export_buf_to_data to be able
to write inline blobs that don't come from a line_buffer or from delta
application.

To be used like this:
fast_export_begin_commit("refs/notes/somenotes", ...)

fast_export_note("refs/heads/master", "inline")
fast_export_buf_to_data(&data)
or maybe
fast_export_note("refs/heads/master", sha1)

Signed-off-by: Dmitry Ivankov <divanorama@gmail.com>
Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 vcs-svn/fast_export.c |   12 ++++++++++++
 vcs-svn/fast_export.h |    2 ++
 2 files changed, 14 insertions(+)

diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c
index 11f8f94..1ecae4b 100644
--- a/vcs-svn/fast_export.c
+++ b/vcs-svn/fast_export.c
@@ -68,6 +68,11 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)
 	putchar('\n');
 }
 
+void fast_export_note(const char *committish, const char *dataref)
+{
+	printf("N %s %s\n", dataref, committish);
+}
+
 static char gitsvnline[MAX_GITSVN_LINE_LEN];
 void fast_export_begin_commit(uint32_t revision, const char *author,
 			const struct strbuf *log,
@@ -222,6 +227,13 @@ static long apply_delta(off_t len, struct line_buffer *input,
 	return ret;
 }
 
+void fast_export_buf_to_data(const struct strbuf *data)
+{
+	printf("data %"PRIuMAX"\n", (uintmax_t)data->len);
+	fwrite(data->buf, data->len, 1, stdout);
+	fputc('\n', stdout);
+}
+
 void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input)
 {
 	assert(len >= 0);
diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h
index 17eb13b..9b32f1e 100644
--- a/vcs-svn/fast_export.h
+++ b/vcs-svn/fast_export.h
@@ -9,11 +9,13 @@ void fast_export_deinit(void);
 
 void fast_export_delete(const char *path);
 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_begin_commit(uint32_t revision, const char *author,
 			const struct strbuf *log, const char *uuid,
 			const char *url, unsigned long timestamp, const char *local_ref);
 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_buf_to_data(const struct strbuf *data);
 void fast_export_blob_delta(uint32_t mode,
 			uint32_t old_mode, const char *old_data,
 			off_t len, struct line_buffer *input);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC v2 09/16] Create a note for every imported commit containing svn metadata.
  2012-07-30 14:31                 ` [RFC v2 08/16] vcs-svn: add fast_export_note to create notes Florian Achleitner
@ 2012-07-30 14:31                   ` Florian Achleitner
  2012-07-30 14:31                     ` [RFC v2 10/16] When debug==1, start fast-import with "--stats" instead of "--quiet" Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-30 14:31 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

To provide metadata from svn dumps for further processing, e.g.
branch detection, attach a note to each imported commit that
stores additional information.
The notes are currently hard-coded in refs/notes/svn/revs.
Currently the following lines from the svn dump are directly
accumulated in the note. This can be refined on purpose, of course.
- "Revision-number"
- "Node-path"
- "Node-kind"
- "Node-action"
- "Node-copyfrom-path"
- "Node-copyfrom-rev"

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 vcs-svn/fast_export.c |   13 +++++++++++++
 vcs-svn/fast_export.h |    2 ++
 vcs-svn/svndump.c     |   21 +++++++++++++++++++--
 3 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c
index 1ecae4b..796dd1a 100644
--- a/vcs-svn/fast_export.c
+++ b/vcs-svn/fast_export.c
@@ -12,6 +12,7 @@
 #include "svndiff.h"
 #include "sliding_window.h"
 #include "line_buffer.h"
+#include "cache.h"
 
 #define MAX_GITSVN_LINE_LEN 4096
 
@@ -68,6 +69,18 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)
 	putchar('\n');
 }
 
+void fast_export_begin_note(uint32_t revision, const char *author,
+		const char *log, unsigned long timestamp)
+{
+	timestamp = 1341914616;
+	size_t loglen = strlen(log);
+	printf("commit refs/notes/svn/revs\n");
+	printf("committer %s <%s@%s> %ld +0000\n", author, author, "local", timestamp);
+	printf("data %"PRIuMAX"\n", loglen);
+	fwrite(log, loglen, 1, stdout);
+	fputc('\n', stdout);
+}
+
 void fast_export_note(const char *committish, const char *dataref)
 {
 	printf("N %s %s\n", dataref, committish);
diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h
index 9b32f1e..c2f6f11 100644
--- a/vcs-svn/fast_export.h
+++ b/vcs-svn/fast_export.h
@@ -10,6 +10,8 @@ void fast_export_deinit(void);
 void fast_export_delete(const char *path);
 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_begin_note(uint32_t revision, const char *author,
+		const char *log, unsigned long timestamp);
 void fast_export_begin_commit(uint32_t revision, const char *author,
 			const struct strbuf *log, const char *uuid,
 			const char *url, unsigned long timestamp, const char *local_ref);
diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c
index c0d5931..f0633c6 100644
--- a/vcs-svn/svndump.c
+++ b/vcs-svn/svndump.c
@@ -48,7 +48,7 @@ static struct {
 static struct {
 	uint32_t revision;
 	unsigned long timestamp;
-	struct strbuf log, author;
+	struct strbuf log, author, note;
 } rev_ctx;
 
 static struct {
@@ -77,6 +77,7 @@ static void reset_rev_ctx(uint32_t revision)
 	rev_ctx.timestamp = 0;
 	strbuf_reset(&rev_ctx.log);
 	strbuf_reset(&rev_ctx.author);
+	strbuf_reset(&rev_ctx.note);
 }
 
 static void reset_dump_ctx(const char *url)
@@ -310,8 +311,15 @@ static void begin_revision(const char *remote_ref)
 
 static void end_revision()
 {
-	if (rev_ctx.revision)
+	struct strbuf mark = STRBUF_INIT;
+	if (rev_ctx.revision) {
 		fast_export_end_commit(rev_ctx.revision);
+		fast_export_begin_note(rev_ctx.revision, "remote-svn",
+				"Note created by remote-svn.", rev_ctx.timestamp);
+		strbuf_addf(&mark, ":%"PRIu32, rev_ctx.revision);
+		fast_export_note(mark.buf, "inline");
+		fast_export_buf_to_data(&rev_ctx.note);
+	}
 }
 
 void svndump_read(const char *url, const char *local_ref)
@@ -358,6 +366,7 @@ void svndump_read(const char *url, const char *local_ref)
 				end_revision();
 			active_ctx = REV_CTX;
 			reset_rev_ctx(atoi(val));
+			strbuf_addf(&rev_ctx.note, "%s\n", t);
 			break;
 		case sizeof("Node-path"):
 			if (constcmp(t, "Node-"))
@@ -369,10 +378,12 @@ void svndump_read(const char *url, const char *local_ref)
 					begin_revision(local_ref);
 				active_ctx = NODE_CTX;
 				reset_node_ctx(val);
+				strbuf_addf(&rev_ctx.note, "%s\n", t);
 				break;
 			}
 			if (constcmp(t + strlen("Node-"), "kind"))
 				continue;
+			strbuf_addf(&rev_ctx.note, "%s\n", t);
 			if (!strcmp(val, "dir"))
 				node_ctx.type = REPO_MODE_DIR;
 			else if (!strcmp(val, "file"))
@@ -383,6 +394,7 @@ void svndump_read(const char *url, const char *local_ref)
 		case sizeof("Node-action"):
 			if (constcmp(t, "Node-action"))
 				continue;
+			strbuf_addf(&rev_ctx.note, "%s\n", t);
 			if (!strcmp(val, "delete")) {
 				node_ctx.action = NODEACT_DELETE;
 			} else if (!strcmp(val, "add")) {
@@ -401,11 +413,13 @@ void svndump_read(const char *url, const char *local_ref)
 				continue;
 			strbuf_reset(&node_ctx.src);
 			strbuf_addstr(&node_ctx.src, val);
+			strbuf_addf(&rev_ctx.note, "%s\n", t);
 			break;
 		case sizeof("Node-copyfrom-rev"):
 			if (constcmp(t, "Node-copyfrom-rev"))
 				continue;
 			node_ctx.srcRev = atoi(val);
+			strbuf_addf(&rev_ctx.note, "%s\n", t);
 			break;
 		case sizeof("Text-content-length"):
 			if (constcmp(t, "Text") && constcmp(t, "Prop"))
@@ -475,6 +489,7 @@ static void init(int report_fd)
 	strbuf_init(&dump_ctx.url, 4096);
 	strbuf_init(&rev_ctx.log, 4096);
 	strbuf_init(&rev_ctx.author, 4096);
+	strbuf_init(&rev_ctx.note, 4096);
 	strbuf_init(&node_ctx.src, 4096);
 	strbuf_init(&node_ctx.dst, 4096);
 	reset_dump_ctx(NULL);
@@ -506,6 +521,8 @@ void svndump_deinit(void)
 	reset_rev_ctx(0);
 	reset_node_ctx(NULL);
 	strbuf_release(&rev_ctx.log);
+	strbuf_release(&rev_ctx.author);
+	strbuf_release(&rev_ctx.note);
 	strbuf_release(&node_ctx.src);
 	strbuf_release(&node_ctx.dst);
 	if (buffer_deinit(&input))
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC v2 10/16] When debug==1, start fast-import with "--stats" instead of "--quiet".
  2012-07-30 14:31                   ` [RFC v2 09/16] Create a note for every imported commit containing svn metadata Florian Achleitner
@ 2012-07-30 14:31                     ` Florian Achleitner
  2012-07-30 14:31                       ` [RFC v2 11/16] Add explanatory comment for transport-helpers refs mapping Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-30 14:31 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

fast-import prints statistics that could be interesting to the
developer of remote helpers.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 transport-helper.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/transport-helper.c b/transport-helper.c
index 616db91..d6daad5 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -392,7 +392,7 @@ static int get_importer(struct transport *transport, struct child_process *fasti
 	memset(fastimport, 0, sizeof(*fastimport));
 	fastimport->in = helper->out;
 	argv_array_push(argv, "fast-import");
-	argv_array_push(argv, "--quiet");
+	argv_array_push(argv, debug ? "--stats" : "--quiet");
 	argv_array_pushf(argv, "--cat-blob-pipe=%s", data->report_fifo);
 	fastimport->argv = argv->argv;
 	fastimport->git_cmd = 1;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC v2 11/16] Add explanatory comment for transport-helpers refs mapping.
  2012-07-30 14:31                     ` [RFC v2 10/16] When debug==1, start fast-import with "--stats" instead of "--quiet" Florian Achleitner
@ 2012-07-30 14:31                       ` Florian Achleitner
  2012-07-30 14:31                         ` [RFC v2 12/16] remote-svn: add incremental import Florian Achleitner
  2012-07-30 17:08                         ` [RFC v2 11/16] Add explanatory comment for transport-helpers refs mapping Jonathan Nieder
  0 siblings, 2 replies; 47+ messages in thread
From: Florian Achleitner @ 2012-07-30 14:31 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

transport-helpers can advertise the 'refspec' capability,
if not a default refspec *:* is assumed. This explains
the post-processing of refs after fetching with fast-import.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 transport-helper.c |   15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/transport-helper.c b/transport-helper.c
index d6daad5..e10fd6b 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -478,6 +478,21 @@ static int fetch_with_import(struct transport *transport,
 
 	argv_array_clear(&importer_argv);
 
+	/*
+	 * If the remote helper advertised the "refspec" capability,
+	 * it will have the written result of the import to the refs
+	 * named on the right hand side of the first refspec matching
+	 * each ref we were fetching.
+	 *
+	 * (If no "refspec" capability was specified, for historical
+	 * reasons we default to *:*.)
+	 *
+	 * Store the result in to_fetch[i].old_sha1.  Callers such
+	 * as "git fetch" can use the value to write feedback to the
+	 * terminal, populate FETCH_HEAD, and determine what new value
+	 * should be written to peer_ref if the update is a
+	 * fast-forward or this is a forced update.
+	 */
 	for (i = 0; i < nr_heads; i++) {
 		char *private;
 		posn = to_fetch[i];
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC v2 12/16] remote-svn: add incremental import.
  2012-07-30 14:31                       ` [RFC v2 11/16] Add explanatory comment for transport-helpers refs mapping Florian Achleitner
@ 2012-07-30 14:31                         ` Florian Achleitner
  2012-07-30 14:31                           ` [RFC v2 13/16] Add a svnrdump-simulator replaying a dump file for testing Florian Achleitner
  2012-07-30 17:08                         ` [RFC v2 11/16] Add explanatory comment for transport-helpers refs mapping Jonathan Nieder
  1 sibling, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-30 14:31 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

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>
---
 contrib/svn-fe/remote-svn.c |   70 +++++++++++++++++++++++++++++++++++++++++--
 contrib/svn-fe/svn-fe.c     |    3 +-
 test-svn-fe.c               |    2 +-
 vcs-svn/fast_export.c       |   16 +++++++---
 vcs-svn/fast_export.h       |    6 ++--
 vcs-svn/svndump.c           |   12 ++++----
 vcs-svn/svndump.h           |    2 +-
 7 files changed, 92 insertions(+), 19 deletions(-)

diff --git a/contrib/svn-fe/remote-svn.c b/contrib/svn-fe/remote-svn.c
index 9dcf78b..2b4c827 100644
--- a/contrib/svn-fe/remote-svn.c
+++ b/contrib/svn-fe/remote-svn.c
@@ -6,12 +6,15 @@
 #include "exec_cmd.h"
 #include "run-command.h"
 #include "svndump.h"
+#include "notes.h"
 #include "argv-array.h"
 
 static const char *url;
 static int dump_from_file;
 static const char *private_ref;
 static const char *remote_ref = "refs/heads/master";
+static const char *notes_ref;
+struct rev_note { unsigned int rev_nr; };
 
 int cmd_capabilities(struct strbuf *line);
 int cmd_import(struct strbuf *line);
@@ -45,12 +48,52 @@ static void terminate_batch() {
 		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)) == NULL ||
+			!(msg = read_sha1_file(note_sha1, &type, &msglen)) ||
+			!msglen || type != OBJ_BLOB) {
+		free(msg);
+		return 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;
+			value = msg + strlen(key);
+			i = atol(value);
+			if(i < 0 || i > UINT32_MAX)
+				return 1;
+			res->rev_nr = i;
+		}
+		msg += len + 1;
+	}
+	return 0;
+}
+
 int cmd_import(struct strbuf *line)
 {
 	int code, report_fd;
 	char *back_pipe_env;
 	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 child_process svndump_proc;
 
@@ -75,6 +118,23 @@ int cmd_import(struct strbuf *line)
 		die("Unable to open fast-import back-pipe! %s", strerror(errno));
 	}
 
+	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 };
+			parse_rev_note(note_msg, &note);
+			startrev = note.rev_nr + 1;
+			free(note_msg);
+		}
+	}
+
+
 	if(dump_from_file) {
 		dumpin_fd = open(url, O_RDONLY);
 		if(dumpin_fd < 0) {
@@ -97,9 +157,8 @@ int cmd_import(struct strbuf *line)
 
 	}
 
-
 	svndump_init_fd(dumpin_fd, report_fd);
-	svndump_read(url, private_ref);
+	svndump_read(url, private_ref, notes_ref);
 	svndump_deinit();
 	svndump_reset();
 
@@ -191,6 +250,10 @@ int main(int argc, const char **argv)
 	strbuf_addf(&buf, "refs/svn/%s/master", remote->name);
 	private_ref = strbuf_detach(&buf, NULL);
 
+	strbuf_init(&buf, 0);
+	strbuf_addf(&buf, "refs/notes/%s/revs", remote->name);
+	notes_ref = strbuf_detach(&buf, NULL);
+
 	while(1) {
 		if (strbuf_getline(&buf, stdin, '\n') == EOF) {
 			if (ferror(stdin))
@@ -206,5 +269,6 @@ int main(int argc, const char **argv)
 	strbuf_release(&buf);
 	free((void*)url);
 	free((void*)private_ref);
+	free((void*)notes_ref);
 	return 0;
 }
diff --git a/contrib/svn-fe/svn-fe.c b/contrib/svn-fe/svn-fe.c
index c796cc0..f363505 100644
--- a/contrib/svn-fe/svn-fe.c
+++ b/contrib/svn-fe/svn-fe.c
@@ -10,7 +10,8 @@ int main(int argc, char **argv)
 {
 	if (svndump_init(NULL))
 		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_reset();
 	return 0;
diff --git a/test-svn-fe.c b/test-svn-fe.c
index bb0e980..2740570 100644
--- a/test-svn-fe.c
+++ b/test-svn-fe.c
@@ -40,7 +40,7 @@ int main(int argc, char *argv[])
 	if (argc == 2) {
 		if (svndump_init(argv[1]))
 			return 1;
-		svndump_read(NULL, "refs/remotes/svn/master");
+		svndump_read(NULL, "refs/remotes/svn/master", "refs/notes/svn/revs");
 		svndump_deinit();
 		svndump_reset();
 		return 0;
diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c
index 796dd1a..32f71a1 100644
--- a/vcs-svn/fast_export.c
+++ b/vcs-svn/fast_export.c
@@ -70,14 +70,20 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)
 }
 
 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;
 	timestamp = 1341914616;
 	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("data %"PRIuMAX"\n", loglen);
 	fwrite(log, loglen, 1, stdout);
+	if (firstnote) {
+		if (revision > 1)
+			printf("from %s^0", note_ref);
+		firstnote = 0;
+	}
 	fputc('\n', stdout);
 }
 
@@ -90,7 +96,7 @@ static char gitsvnline[MAX_GITSVN_LINE_LEN];
 void fast_export_begin_commit(uint32_t revision, const char *author,
 			const struct strbuf *log,
 			const char *uuid, const char *url,
-			unsigned long timestamp, const char *local_ref)
+			unsigned long timestamp, const char *local_ref, const char *parent)
 {
 	static const struct strbuf empty = STRBUF_INIT;
 	if (!log)
@@ -113,7 +119,9 @@ void fast_export_begin_commit(uint32_t revision, const char *author,
 	fwrite(log->buf, log->len, 1, stdout);
 	printf("%s\n", gitsvnline);
 	if (!first_commit_done) {
-		if (revision > 1)
+		if(parent)
+			printf("from %s^0\n", parent);
+		else if (revision > 1)
 			printf("from :%"PRIu32"\n", revision - 1);
 		first_commit_done = 1;
 	}
diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h
index c2f6f11..5174aae 100644
--- a/vcs-svn/fast_export.h
+++ b/vcs-svn/fast_export.h
@@ -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_note(const char *committish, const char *dataref);
 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,
-			const struct strbuf *log, const char *uuid,
-			const char *url, unsigned long timestamp, const char *local_ref);
+			const struct strbuf *log, const char *uuid,const char *url,
+			unsigned long timestamp, const char *local_ref, const char *parent);
 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_buf_to_data(const struct strbuf *data);
diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c
index f0633c6..b64802c 100644
--- a/vcs-svn/svndump.c
+++ b/vcs-svn/svndump.c
@@ -306,23 +306,23 @@ static void begin_revision(const char *remote_ref)
 		return;
 	fast_export_begin_commit(rev_ctx.revision, rev_ctx.author.buf,
 		&rev_ctx.log, dump_ctx.uuid.buf, dump_ctx.url.buf,
-		rev_ctx.timestamp, remote_ref);
+		rev_ctx.timestamp, remote_ref, rev_ctx.revision == 1 ? NULL : remote_ref);
 }
 
-static void end_revision()
+static void end_revision(const char *note_ref)
 {
 	struct strbuf mark = STRBUF_INIT;
 	if (rev_ctx.revision) {
 		fast_export_end_commit(rev_ctx.revision);
 		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);
 		fast_export_note(mark.buf, "inline");
 		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 *t;
@@ -363,7 +363,7 @@ void svndump_read(const char *url, const char *local_ref)
 			if (active_ctx == REV_CTX)
 				begin_revision(local_ref);
 			if (active_ctx != DUMP_CTX)
-				end_revision();
+				end_revision(notes_ref);
 			active_ctx = REV_CTX;
 			reset_rev_ctx(atoi(val));
 			strbuf_addf(&rev_ctx.note, "%s\n", t);
@@ -479,7 +479,7 @@ void svndump_read(const char *url, const char *local_ref)
 	if (active_ctx == REV_CTX)
 		begin_revision(local_ref);
 	if (active_ctx != DUMP_CTX)
-		end_revision();
+		end_revision(notes_ref);
 }
 
 static void init(int report_fd)
diff --git a/vcs-svn/svndump.h b/vcs-svn/svndump.h
index febeecb..b8eb129 100644
--- a/vcs-svn/svndump.h
+++ b/vcs-svn/svndump.h
@@ -3,7 +3,7 @@
 
 int svndump_init(const char *filename);
 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_reset(void);
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC v2 13/16] Add a svnrdump-simulator replaying a dump file for testing.
  2012-07-30 14:31                         ` [RFC v2 12/16] remote-svn: add incremental import Florian Achleitner
@ 2012-07-30 14:31                           ` Florian Achleitner
  2012-07-30 14:31                             ` [RFC v2 14/16] transport-helper: add import|export-marks to fast-import command line Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-30 14:31 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

To ease testing without depending on a reachable svn server, this
compact python script mimics parts of svnrdumps behaviour.
It requires the remote url to start with sim://.
Start and end revisions are evaluated.
If the requested revision doesn't exist, as it is the case with
incremental imports, if no new commit was added, it returns 1
(like svnrdump).
To allow using the same dump file for simulating multiple
incremental imports the highest revision can be limited by setting
the environment variable SVNRMAX to that value. This simulates the
situation where higher revs don't exist yet.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 contrib/svn-fe/svnrdump_sim.py |   53 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100755 contrib/svn-fe/svnrdump_sim.py

diff --git a/contrib/svn-fe/svnrdump_sim.py b/contrib/svn-fe/svnrdump_sim.py
new file mode 100755
index 0000000..ab4ccf1
--- /dev/null
+++ b/contrib/svn-fe/svnrdump_sim.py
@@ -0,0 +1,53 @@
+#!/usr/bin/python
+"""
+Simulates svnrdump by replaying an existing dump from a file, taking care
+of the specified revision range.
+To simulate incremental imports the environment variable SVNRMAX can be set
+to the highest revision that should be available.
+"""
+import sys, os
+
+
+def getrevlimit():
+	var = 'SVNRMAX'
+	if os.environ.has_key(var):
+		return os.environ[var]
+	return None
+	
+def writedump(url, lower, upper):
+	if url.startswith('sim://'):
+		filename = url[6:]
+		if filename[-1] == '/': filename = filename[:-1] #remove terminating slash
+	else:
+		raise ValueError('sim:// url required')
+	f = open(filename, 'r');
+	state = 'header'
+	wroterev = False
+	while(True):
+		l = f.readline()
+		if l == '': break
+		if state == 'header' and l.startswith('Revision-number: '):
+			state = 'prefix'
+		if state == 'prefix' and l == 'Revision-number: %s\n' % lower:
+			state = 'selection'
+		if not upper == 'HEAD' and state == 'selection' and l == 'Revision-number: %s\n' % upper:
+			break;
+
+		if state == 'header' or state == 'selection':
+			if state == 'selection': wroterev = True
+			sys.stdout.write(l)
+	return wroterev
+
+if __name__ == "__main__":
+	if not (len(sys.argv) in (3, 4, 5)):
+		print "usage: %s dump URL -rLOWER:UPPER"
+		sys.exit(1)
+	if not sys.argv[1] == 'dump': raise NotImplementedError('only "dump" is suppported.')
+	url = sys.argv[2]
+	r = ('0', 'HEAD')
+	if len(sys.argv) == 4 and sys.argv[3][0:2] == '-r':
+		r = sys.argv[3][2:].lstrip().split(':')
+	if not getrevlimit() is None: r[1] = getrevlimit()
+	if writedump(url, r[0], r[1]): ret = 0
+	else: ret = 1
+	sys.exit(ret)
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC v2 14/16] transport-helper: add import|export-marks to fast-import command line.
  2012-07-30 14:31                           ` [RFC v2 13/16] Add a svnrdump-simulator replaying a dump file for testing Florian Achleitner
@ 2012-07-30 14:31                             ` Florian Achleitner
  2012-07-30 14:31                               ` [RFC v2 15/16] remote-svn: add marks-file regeneration Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-30 14:31 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

fast-import internally uses marks that refer to an object via its sha1.
Those marks are created during import to find previously created objects.
At exit the accumulated marks can be exported to a file and reloaded at
startup, so that the previous marks are available.
Add command line options to the fast-import command line to enable this.
The mark files are stored in info/fast-import/marks/<remote-name>.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 transport-helper.c |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/transport-helper.c b/transport-helper.c
index e10fd6b..74f9608 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -394,6 +394,9 @@ static int get_importer(struct transport *transport, struct child_process *fasti
 	argv_array_push(argv, "fast-import");
 	argv_array_push(argv, debug ? "--stats" : "--quiet");
 	argv_array_pushf(argv, "--cat-blob-pipe=%s", data->report_fifo);
+	argv_array_push(argv, "--relative-marks");
+	argv_array_pushf(argv, "--import-marks-if-exists=marks/%s", transport->remote->name);
+	argv_array_pushf(argv, "--export-marks=marks/%s", transport->remote->name);
 	fastimport->argv = argv->argv;
 	fastimport->git_cmd = 1;
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC v2 15/16] remote-svn: add marks-file regeneration.
  2012-07-30 14:31                             ` [RFC v2 14/16] transport-helper: add import|export-marks to fast-import command line Florian Achleitner
@ 2012-07-30 14:31                               ` Florian Achleitner
  2012-07-30 14:31                                 ` [RFC v2 16/16] Add a test script for remote-svn Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Florian Achleitner @ 2012-07-30 14:31 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

fast-import mark files are stored outside the object database and are therefore
not fetched and can be lost somehow else.
marks provide a svn revision --> git sha1 mapping, while the notes that are attached
to each commit when it is imported provide a git sha1 --> svn revision.

If the marks file is not available or not plausible, regenerate it by walking through
the notes tree.
, i.e.
The plausibility check tests if the highest revision in the marks file matches the
revision of the top ref. It doesn't ensure that the mark file is completely correct.
This could only be done with an effort equal to unconditional regeneration.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 contrib/svn-fe/remote-svn.c |   74 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 70 insertions(+), 4 deletions(-)

diff --git a/contrib/svn-fe/remote-svn.c b/contrib/svn-fe/remote-svn.c
index 2b4c827..168c973 100644
--- a/contrib/svn-fe/remote-svn.c
+++ b/contrib/svn-fe/remote-svn.c
@@ -13,7 +13,7 @@ static const char *url;
 static int dump_from_file;
 static const char *private_ref;
 static const char *remote_ref = "refs/heads/master";
-static const char *notes_ref;
+static const char *notes_ref, *marksfilename;
 struct rev_note { unsigned int rev_nr; };
 
 int cmd_capabilities(struct strbuf *line);
@@ -86,8 +86,69 @@ static int parse_rev_note(const char *msg, struct rev_note *res) {
 	return 0;
 }
 
-int cmd_import(struct strbuf *line)
-{
+static int note2mark_cb(const unsigned char *object_sha1,
+		const unsigned char *note_sha1, char *note_path,
+		void *cb_data) {
+	FILE *file = (FILE *)cb_data;
+	char *msg;
+	unsigned long msglen;
+	enum object_type type;
+	struct rev_note note;
+	if (!(msg = read_sha1_file(note_sha1, &type, &msglen)) ||
+			!msglen || type != OBJ_BLOB) {
+		free(msg);
+		return 1;
+	}
+	if (parse_rev_note(msg, &note))
+		return 2;
+	if (fprintf(file, ":%d %s\n", note.rev_nr, sha1_to_hex(object_sha1)) < 1)
+		return 3;
+	return 0;
+}
+
+static void regenerate_marks() {
+	int ret;
+	FILE *marksfile;
+	marksfile = fopen(marksfilename, "w+");
+	if (!marksfile)
+		die_errno("Couldn't create mark file %s.", marksfilename);
+	ret = for_each_note(NULL, 0, note2mark_cb, marksfile);
+	if (ret)
+		die("Regeneration of marks failed, returned %d.", ret);
+	fclose(marksfile);
+}
+
+static void check_or_regenerate_marks(int latestrev) {
+	FILE *marksfile;
+	char *line = NULL;
+	size_t linelen = 0;
+	struct strbuf sb = STRBUF_INIT;
+	int found = 0;
+
+	if (latestrev < 1)
+		return;
+
+	init_notes(NULL, notes_ref, NULL, 0);
+	marksfile = fopen(marksfilename, "r");
+	if (!marksfile)
+		regenerate_marks(marksfile);
+	else {
+		strbuf_addf(&sb, ":%d ", latestrev);
+		while (getline(&line, &linelen, marksfile) != -1) {
+			if (!prefixcmp(line, sb.buf)) {
+				found++;
+				break;
+			}
+		}
+		fclose(marksfile);
+		if (!found)
+			regenerate_marks();
+	}
+	free_notes(NULL);
+	strbuf_release(&sb);
+}
+
+int cmd_import(struct strbuf *line) {
 	int code, report_fd;
 	char *back_pipe_env;
 	int dumpin_fd;
@@ -133,7 +194,7 @@ int cmd_import(struct strbuf *line)
 			free(note_msg);
 		}
 	}
-
+	check_or_regenerate_marks(startrev - 1);
 
 	if(dump_from_file) {
 		dumpin_fd = open(url, O_RDONLY);
@@ -254,6 +315,10 @@ int main(int argc, const char **argv)
 	strbuf_addf(&buf, "refs/notes/%s/revs", remote->name);
 	notes_ref = strbuf_detach(&buf, NULL);
 
+	strbuf_init(&buf, 0);
+	strbuf_addf(&buf, "%s/info/fast-import/marks/%s", get_git_dir(), remote->name);
+	marksfilename = strbuf_detach(&buf, NULL);
+
 	while(1) {
 		if (strbuf_getline(&buf, stdin, '\n') == EOF) {
 			if (ferror(stdin))
@@ -270,5 +335,6 @@ int main(int argc, const char **argv)
 	free((void*)url);
 	free((void*)private_ref);
 	free((void*)notes_ref);
+	free((void*)marksfilename);
 	return 0;
 }
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC v2 16/16] Add a test script for remote-svn.
  2012-07-30 14:31                               ` [RFC v2 15/16] remote-svn: add marks-file regeneration Florian Achleitner
@ 2012-07-30 14:31                                 ` Florian Achleitner
  0 siblings, 0 replies; 47+ messages in thread
From: Florian Achleitner @ 2012-07-30 14:31 UTC (permalink / raw)
  To: Jonathan Nieder, David Michael Barr, git; +Cc: florian.achleitner.2.6.31

Use svnrdump_sim.py to emulate svnrdump without an svn server.
Tests fetching, incremental fetching, fetching from file://,
and the regeneration of fast-import's marks file.

Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
---
 t/t9020-remote-svn.sh |   69 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)
 create mode 100755 t/t9020-remote-svn.sh

diff --git a/t/t9020-remote-svn.sh b/t/t9020-remote-svn.sh
new file mode 100755
index 0000000..a0c6a21
--- /dev/null
+++ b/t/t9020-remote-svn.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+test_description='tests remote-svn'
+
+. ./test-lib.sh
+
+# We override svnrdump by placing a symlink to the svnrdump-emulator in .
+export PATH="$HOME:$PATH"
+ln -sf $GIT_BUILD_DIR/contrib/svn-fe/svnrdump_sim.py "$HOME/svnrdump"
+
+init_git () {
+	rm -fr .git &&
+	git init &&
+	#git remote add svnsim svn::sim:///$TEST_DIRECTORY/t9020/example.svnrdump
+	# let's reuse an exisiting dump file!?
+	git remote add svnsim svn::sim:///$TEST_DIRECTORY/t9154/svn.dump
+	git remote add svnfile svn::file:///$TEST_DIRECTORY/t9154/svn.dump
+}
+
+test_debug '
+	git --version
+	which git
+	which svnrdump
+'
+
+test_expect_success 'simple fetch' '
+	init_git &&
+	git fetch svnsim &&
+	test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master  &&
+	cp .git/refs/remotes/svnsim/master master.good
+'
+
+test_debug '
+	cat .git/refs/svn/svnsim/master
+	cat .git/refs/remotes/svnsim/master
+'
+
+test_expect_success 'repeated fetch, nothing shall change' '
+	git fetch svnsim &&
+	test_cmp master.good .git/refs/remotes/svnsim/master
+'
+
+test_expect_success 'fetch from a file:// url gives the same result' '
+	git fetch svnfile 
+'
+
+test_expect_failure 'the sha1 differ because the git-svn-id line in the commit msg contains the url' '
+	test_cmp .git/refs/remotes/svnfile/master .git/refs/remotes/svnsim/master
+'
+
+test_expect_success 'mark-file regeneration' '
+	mv .git/info/fast-import/marks/svnsim .git/info/fast-import/marks/svnsim.old &&
+	git fetch svnsim &&
+	test_cmp .git/info/fast-import/marks/svnsim.old .git/info/fast-import/marks/svnsim
+'
+
+test_expect_success 'incremental imports must lead to the same head' '
+	export SVNRMAX=3 &&
+	init_git &&
+	git fetch svnsim &&
+	test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master  &&
+	unset SVNRMAX &&
+	git fetch svnsim &&
+	test_cmp master.good .git/refs/remotes/svnsim/master
+'
+
+test_debug 'git branch -a'	
+
+test_done
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: [RFC v2 01/16] Implement a remote helper for svn in C.
  2012-07-30 14:31   ` [RFC v2 01/16] Implement a remote helper for svn in C Florian Achleitner
  2012-07-30 14:31     ` [RFC v2 02/16] Integrate remote-svn into svn-fe/Makefile Florian Achleitner
@ 2012-07-30 16:28     ` Junio C Hamano
  2012-07-31 19:26       ` Florian Achleitner
  1 sibling, 1 reply; 47+ messages in thread
From: Junio C Hamano @ 2012-07-30 16:28 UTC (permalink / raw)
  To: Florian Achleitner; +Cc: Jonathan Nieder, David Michael Barr, git

Florian Achleitner <florian.achleitner.2.6.31@gmail.com> writes:

> Enables basic fetching from subversion repositories. When processing Remote URLs
> starting with svn::, git invokes this remote-helper.
> It starts svnrdump to extract revisions from the subversion repository in the
> 'dump file format', and converts them to a git-fast-import stream using
> the functions of vcs-svn/.
>
> Imported refs are created in a private namespace at refs/svn/<remote-name/master.
> The revision history is imported linearly (no branch detection) and completely,
> i.e. from revision 0 to HEAD.
>
> Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
> ---
>  contrib/svn-fe/remote-svn.c |  190 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 190 insertions(+)
>  create mode 100644 contrib/svn-fe/remote-svn.c
>
> diff --git a/contrib/svn-fe/remote-svn.c b/contrib/svn-fe/remote-svn.c
> new file mode 100644
> index 0000000..d5c2df8
> --- /dev/null
> +++ b/contrib/svn-fe/remote-svn.c
> @@ -0,0 +1,190 @@
> +
> +#include "cache.h"
> +#include "remote.h"
> +#include "strbuf.h"
> +#include "url.h"
> +#include "exec_cmd.h"
> +#include "run-command.h"
> +#include "svndump.h"
> +#include "argv-array.h"
> +
> +static const char *url;
> +static const char *private_ref;
> +static const char *remote_ref = "refs/heads/master";
> +
> +int cmd_capabilities(struct strbuf *line);
> +int cmd_import(struct strbuf *line);
> +int cmd_list(struct strbuf *line);

How many of these and other symbols are necessary to be visible
outside this file?

> +typedef int (*input_command_handler)(struct strbuf *);
> +struct input_command_entry {
> +	const char *name;
> +	input_command_handler fct;
> +	unsigned char batchable;	/* whether the command starts or is part of a batch */
> +};
> +
> +static const struct input_command_entry input_command_list[] = {
> +		{ "capabilities", cmd_capabilities, 0 },
> +		{ "import", cmd_import, 1 },
> +		{ "list", cmd_list, 0 },
> +		{ NULL, NULL }
> +};
> +
> +int cmd_capabilities(struct strbuf *line)
> +{
> +	printf("import\n");
> +	printf("refspec %s:%s\n\n", remote_ref, private_ref);
> +	fflush(stdout);
> +	return 0;
> +}
> +
> +static void terminate_batch() {
> +	/* terminate a current batch's fast-import stream */

Style:

	static void terminate_batch(void)
	{
		/* terminate ...

> +		printf("done\n");
> +		fflush(stdout);
> +}
> +
> +int cmd_import(struct strbuf *line)
> +{
> +	int code, report_fd;
> +	char *back_pipe_env;
> +	int dumpin_fd;
> +	unsigned int startrev = 0;
> +	struct argv_array svndump_argv = ARGV_ARRAY_INIT;
> +	struct child_process svndump_proc;
> +
> +	/*
> +	 * When the remote-helper is invoked by transport-helper.c it passes the
> +	 * filename of this pipe in the env-var.
> +	 */

s/ it passes/, &/;

> +	back_pipe_env = getenv("GIT_REPORT_FIFO");

Can we name "back pipe", "report fifo" and "report fd" more
consistently and descriptively?

What kind of "REPORT" are we talking about here?  Is it to carry the
contents of 

> +	if (!back_pipe_env) {
> +		die("Cannot get cat-blob-pipe from environment! GIT_REPORT_FIFO has to"
> +				"be set by the caller.");
> +	}

Style: unnecesary {} block around a simple statement.  It is OK to
have such a block early in a series if you add more statements to it
in later steps, but that does not seem to be the case for this patch
series.

> +	/*
> +	 * Opening a fifo for reading usually blocks until a writer has opened it too.
> +	 * Opening a fifo for writing usually blocks until a reader has opened it too.
> +	 * Therefore, we open with RDWR on both sides to avoid deadlocks.
> +	 * Especially if there's nothing to do and one pipe end is closed immediately.
> +	 */

This smells somewhat fishy "justification".  Are we reading what we
wrote to the fifo?  Who is expected to come at the other end of the
fifo?  Is it this process that creates that other process?  Perhaps
you should open it _after_ spawning the process, telling it to open
the same fifo for writing (if you are sitting on the reading end)?

> +	report_fd = open(back_pipe_env, O_RDWR);
> +	if (report_fd < 0) {
> +		die("Unable to open fast-import back-pipe! %s", strerror(errno));
> +	}

Style: (ditto).

> +int cmd_list(struct strbuf *line)
> +{
> +	printf("? HEAD\n");
> +	printf("? %s\n\n", remote_ref);
> +	fflush(stdout);
> +	return 0;
> +}

It somehow feels funny that remote_ref (which seems to be hardcoded
to "refs/heads/master") and HEAD are listed here, even though the
other side is not even in the Git land and the name "master" does
not have any significance.  The name "refs/heads/master" may be
necessary to form the LHS of the refspec in cmd_capabilities(), but
it somehow feels more natural to only advertise HEAD here and also
futz the refspec to printf("refspec HEAD:%s", private_ref) in
cmd_capabilities().  Perhaps you tried it already and it did not
work for some reason; I dunno.

> +int do_command(struct strbuf *line)
> +{
> +	const struct input_command_entry *p = input_command_list;
> +	static int batch_active;
> +	static struct strbuf batch_command = STRBUF_INIT;
> +	/*
> +	 * import commands can be grouped together in a batch.
> +	 * Batches are ended by \n. If no batch is active the program ends.
> +	 */
> +	if (line->len == 0 ) {

Style: lose the SP before closing parenthesis ")".

> +		if (batch_active) {
> +			terminate_batch();
> +			batch_active = 0;
> +			return 0;
> +		}

Is it an error to feed an empty line when batch is not active?
How is the error diagnosed?
Is the user told about the error, and if so how?

> +		return 1;
> +	}
> +	if (batch_active && strcmp(batch_command.buf, line->buf))
> +		die("Active %s batch interrupted by %s", batch_command.buf, line->buf);

So after issuing "import" that causes batch_active to become true,
another command e.g. "list" cannot be issued and will result in this
die() unless the batch is concluded by issuing an empty line.  Can
an "import" be issued while another "import" batch is in effect?

> +	for(p = input_command_list; p->name; p++) {
> +		if (!prefixcmp(line->buf, p->name) &&
> +				(strlen(p->name) == line->len || line->buf[strlen(p->name)] == ' ')) {
> +			if (p->batchable) {
> +				batch_active = 1;
> +				strbuf_release(&batch_command);
> +				strbuf_addbuf(&batch_command, line);

Wouldn't it make more sense to get rid of batch_active variable and
use the presense of batch_command as the signal for the batch in
effect?  Your "if (batch_active)" becomes "if (batch_command.len)",
and "batch_active = 0" becomes "strbuf_release(&batch_command)".

> +			}
> +			return p->fct(line);
> +		}
> +	}
> +	warning("Unknown command '%s'\n", line->buf);
> +	return 0;
> +}
> +
> +int main(int argc, const char **argv)
> +{
> +	struct strbuf buf = STRBUF_INIT;
> +	int nongit;
> +	static struct remote *remote;
> +	const char *url_in;
> +
> +	git_extract_argv0_path(argv[0]);
> +	setup_git_directory_gently(&nongit);
> +	if (argc < 2 || argc > 3) {
> +		usage("git-remote-svn <remote-name> [<url>]");
> +		return 1;
> +	}
> +
> +	remote = remote_get(argv[1]);
> +	url_in = remote->url[0];
> +	if (argc == 3)
> +		url_in = argv[2];
> +
> +	end_url_with_slash(&buf, url_in);
> +	url = strbuf_detach(&buf, NULL);
> +
> +	strbuf_init(&buf, 0);
> +	strbuf_addf(&buf, "refs/svn/%s/master", remote->name);
> +	private_ref = strbuf_detach(&buf, NULL);
> +
> +	while(1) {
> +		if (strbuf_getline(&buf, stdin, '\n') == EOF) {
> +			if (ferror(stdin))
> +				die_errno("Error reading command stream");
> +			else
> +				die_errno("Unexpected end of command stream");

On the else clause, ferror() did not say there was an error.  What
errno do we see from die_errno() in that case?

> +		}
> +		if (do_command(&buf))
> +			break;
> +		strbuf_reset(&buf);
> +	}
> +
> +	strbuf_release(&buf);
> +	free((void*)url);
> +	free((void*)private_ref);
> +	return 0;
> +}

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC v2 11/16] Add explanatory comment for transport-helpers refs mapping.
  2012-07-30 14:31                       ` [RFC v2 11/16] Add explanatory comment for transport-helpers refs mapping Florian Achleitner
  2012-07-30 14:31                         ` [RFC v2 12/16] remote-svn: add incremental import Florian Achleitner
@ 2012-07-30 17:08                         ` Jonathan Nieder
  2012-07-30 17:25                           ` Junio C Hamano
  2012-07-30 17:38                           ` Junio C Hamano
  1 sibling, 2 replies; 47+ messages in thread
From: Jonathan Nieder @ 2012-07-30 17:08 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Florian Achleitner, David Michael Barr, git, Jeff King,
	Sverre Rabbelier, Matthieu Moy

Hi Junio,

Florian Achleitner wrote:

> transport-helpers can advertise the 'refspec' capability,
> if not a default refspec *:* is assumed. This explains
> the post-processing of refs after fetching with fast-import.
>
> Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>

The patch below adds a comment to fetch_with_import() explaining the
loop that saves the fetched commit names after 'git fast-import' has
done its work.  It avoids some confusion that Florian encountered on
first reading about which refs the fast-import stream is supposed to
use to write its result.

(By the way, I guess I find the above paragraph clearer than Florian's
commit message.  But aside from that, the patch seems good to me.)

I would like to see the patch applied so the remote-svn series without
it gets shorter and easier to review. ;-)  Munging the two context
lines ending with argv_array_clear(&importer_argv); to

 	free(fastimport.argv);
 	fastimport.argv = NULL;

makes this patch apply against master.  Does it look ready for
application to you?  If you'd like, I can send a copy rebased against
'master'.

Patch left unsnipped for reference.

Thanks,
Jonathan

> ---
>  transport-helper.c |   15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/transport-helper.c b/transport-helper.c
> index d6daad5..e10fd6b 100644
> --- a/transport-helper.c
> +++ b/transport-helper.c
> @@ -478,6 +478,21 @@ static int fetch_with_import(struct transport *transport,
>  
>  	argv_array_clear(&importer_argv);
>  
> +	/*
> +	 * If the remote helper advertised the "refspec" capability,
> +	 * it will have the written result of the import to the refs
> +	 * named on the right hand side of the first refspec matching
> +	 * each ref we were fetching.
> +	 *
> +	 * (If no "refspec" capability was specified, for historical
> +	 * reasons we default to *:*.)
> +	 *
> +	 * Store the result in to_fetch[i].old_sha1.  Callers such
> +	 * as "git fetch" can use the value to write feedback to the
> +	 * terminal, populate FETCH_HEAD, and determine what new value
> +	 * should be written to peer_ref if the update is a
> +	 * fast-forward or this is a forced update.
> +	 */
>  	for (i = 0; i < nr_heads; i++) {
>  		char *private;
>  		posn = to_fetch[i];
> -- 
> 1.7.9.5
> 

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC v2 11/16] Add explanatory comment for transport-helpers refs mapping.
  2012-07-30 17:08                         ` [RFC v2 11/16] Add explanatory comment for transport-helpers refs mapping Jonathan Nieder
@ 2012-07-30 17:25                           ` Junio C Hamano
  2012-07-30 17:38                           ` Junio C Hamano
  1 sibling, 0 replies; 47+ messages in thread
From: Junio C Hamano @ 2012-07-30 17:25 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Florian Achleitner, David Michael Barr, git, Jeff King,
	Sverre Rabbelier, Matthieu Moy

Jonathan Nieder <jrnieder@gmail.com> writes:

> Hi Junio,
>
> Florian Achleitner wrote:
>
>> transport-helpers can advertise the 'refspec' capability,
>> if not a default refspec *:* is assumed. This explains
>> the post-processing of refs after fetching with fast-import.
>>
>> Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
>
> The patch below adds a comment to fetch_with_import() explaining the
> loop that saves the fetched commit names after 'git fast-import' has
> done its work.  It avoids some confusion that Florian encountered on
> first reading about which refs the fast-import stream is supposed to
> use to write its result.

>
> (By the way, I guess I find the above paragraph clearer than Florian's
> commit message.  But aside from that, the patch seems good to me.)
>
> I would like to see the patch applied so the remote-svn series without
> it gets shorter and easier to review.

Sounds pretty safe, and as long as mentors and stakeholders in the
area are happy with what the comment says, I see no issue applying
it now.  Is it understood by all parties that Florian may need to
rebase the series on top of it?

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC v2 11/16] Add explanatory comment for transport-helpers refs mapping.
  2012-07-30 17:08                         ` [RFC v2 11/16] Add explanatory comment for transport-helpers refs mapping Jonathan Nieder
  2012-07-30 17:25                           ` Junio C Hamano
@ 2012-07-30 17:38                           ` Junio C Hamano
  2012-07-30 19:15                             ` Jonathan Nieder
  1 sibling, 1 reply; 47+ messages in thread
From: Junio C Hamano @ 2012-07-30 17:38 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Florian Achleitner, David Michael Barr, git, Jeff King,
	Sverre Rabbelier, Matthieu Moy

Jonathan Nieder <jrnieder@gmail.com> writes:

> I would like to see the patch applied so the remote-svn series without
> it gets shorter and easier to review. ;-)  Munging the two context
> lines ending with argv_array_clear(&importer_argv); to
>
>  	free(fastimport.argv);
>  	fastimport.argv = NULL;
>
> makes this patch apply against master.  Does it look ready for
> application to you?  If you'd like, I can send a copy rebased against
> 'master'.

No need for that; "git apply -3" as well as "git am -3" can grok
this just fine ;-)

>> +	/*
>> +	 * If the remote helper advertised the "refspec" capability,
>> +	 * it will have the written result of the import to the refs

perhaps s/will have the written result of/would have written result of/?

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC v2 11/16] Add explanatory comment for transport-helpers refs mapping.
  2012-07-30 17:38                           ` Junio C Hamano
@ 2012-07-30 19:15                             ` Jonathan Nieder
  2012-07-30 20:15                               ` Florian Achleitner
  0 siblings, 1 reply; 47+ messages in thread
From: Jonathan Nieder @ 2012-07-30 19:15 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Florian Achleitner, David Michael Barr, git, Jeff King,
	Sverre Rabbelier, Matthieu Moy

Junio C Hamano wrote:
> Jonathan Nieder <jrnieder@gmail.com> writes:

>>> +	/*
>>> +	 * If the remote helper advertised the "refspec" capability,
>>> +	 * it will have the written result of the import to the refs
>
> perhaps s/will have the written result of/would have written result of/?

That would sound like 'If the remote helper advertised the "refspec"
capability, it would have written the result of the import to the
refs, but it didn't, so...', so I think "will" is the right tense.
But 'will have the written' is awkward.  How about:

	 * The fast-import stream of a remote helper advertising the
	 * "refspec" capability writes to the refs named after the right
	 * hand side of the first refspec matching each ref we were
	 * fetching.
	 *
	 * (If no "refspec" capability is specified, for historical
	 * reasons the default is *:*.)
	 *
	 * Store the result in to_fetch[i].old_sha1. [...]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC v2 11/16] Add explanatory comment for transport-helpers refs mapping.
  2012-07-30 19:15                             ` Jonathan Nieder
@ 2012-07-30 20:15                               ` Florian Achleitner
  0 siblings, 0 replies; 47+ messages in thread
From: Florian Achleitner @ 2012-07-30 20:15 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Junio C Hamano, Florian Achleitner, David Michael Barr, git,
	Jeff King, Sverre Rabbelier, Matthieu Moy

On Monday 30 July 2012 14:15:53 Jonathan Nieder wrote:
> Junio C Hamano wrote:
> > Jonathan Nieder <jrnieder@gmail.com> writes:
> >>> +	/*
> >>> +	 * If the remote helper advertised the "refspec" capability,
> >>> +	 * it will have the written result of the import to the refs
> > 
> > perhaps s/will have the written result of/would have written result of/?
> 
> That would sound like 'If the remote helper advertised the "refspec"
> capability, it would have written the result of the import to the
> refs, but it didn't, so...', so I think "will" is the right tense.
> But 'will have the written' is awkward.  How about:

Yes, thats clearly a typing error of mine, 'the' is to be deleted.

> 
> 	 * The fast-import stream of a remote helper advertising the
> 	 * "refspec" capability writes to the refs named after the right
> 	 * hand side of the first refspec matching each ref we were
> 	 * fetching.
> 	 *
> 	 * (If no "refspec" capability is specified, for historical
> 	 * reasons the default is *:*.)
> 	 *
> 	 * Store the result in to_fetch[i].old_sha1. [...]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC v2 01/16] Implement a remote helper for svn in C.
  2012-07-30 16:28     ` [RFC v2 01/16] Implement a remote helper for svn in C Junio C Hamano
@ 2012-07-31 19:26       ` Florian Achleitner
  0 siblings, 0 replies; 47+ messages in thread
From: Florian Achleitner @ 2012-07-31 19:26 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Florian Achleitner, Jonathan Nieder, David Michael Barr, git

On Monday 30 July 2012 09:28:27 Junio C Hamano wrote:
> Florian Achleitner <florian.achleitner.2.6.31@gmail.com> writes:
> > Enables basic fetching from subversion repositories. When processing
> > Remote URLs starting with svn::, git invokes this remote-helper.
> > It starts svnrdump to extract revisions from the subversion repository in
> > the 'dump file format', and converts them to a git-fast-import stream
> > using the functions of vcs-svn/.
> > 
> > Imported refs are created in a private namespace at
> > refs/svn/<remote-name/master. The revision history is imported linearly
> > (no branch detection) and completely, i.e. from revision 0 to HEAD.
> > 
> > Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com>
> > ---
> > 
> >  contrib/svn-fe/remote-svn.c |  190
> >  +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190
> >  insertions(+)
> >  create mode 100644 contrib/svn-fe/remote-svn.c
> > 
> > diff --git a/contrib/svn-fe/remote-svn.c b/contrib/svn-fe/remote-svn.c
> > new file mode 100644
> > index 0000000..d5c2df8
> > --- /dev/null
> > +++ b/contrib/svn-fe/remote-svn.c
> > @@ -0,0 +1,190 @@
> > +
> > +#include "cache.h"
> > +#include "remote.h"
> > +#include "strbuf.h"
> > +#include "url.h"
> > +#include "exec_cmd.h"
> > +#include "run-command.h"
> > +#include "svndump.h"
> > +#include "argv-array.h"
> > +
> > +static const char *url;
> > +static const char *private_ref;
> > +static const char *remote_ref = "refs/heads/master";
> > +
> > +int cmd_capabilities(struct strbuf *line);
> > +int cmd_import(struct strbuf *line);
> > +int cmd_list(struct strbuf *line);
> 
> How many of these and other symbols are necessary to be visible
> outside this file?

Will check and make them static.

> 
> > +typedef int (*input_command_handler)(struct strbuf *);
> > +struct input_command_entry {
> > +	const char *name;
> > +	input_command_handler fct;
> > +	unsigned char batchable;	/* whether the command starts or is part of a
> > batch */ +};
> > +
> > +static const struct input_command_entry input_command_list[] = {
> > +		{ "capabilities", cmd_capabilities, 0 },
> > +		{ "import", cmd_import, 1 },
> > +		{ "list", cmd_list, 0 },
> > +		{ NULL, NULL }
> > +};
> > +
> > +int cmd_capabilities(struct strbuf *line)
> > +{
> > +	printf("import\n");
> > +	printf("refspec %s:%s\n\n", remote_ref, private_ref);
> > +	fflush(stdout);
> > +	return 0;
> > +}
> > +
> > +static void terminate_batch() {
> > +	/* terminate a current batch's fast-import stream */
> 
> Style:
> 
> 	static void terminate_batch(void)
> 	{
> 		/* terminate ...
> 

Ok. Opening braces in new lines, right? But inside functions it's ok to have 
them on the same line?

> > +		printf("done\n");
> > +		fflush(stdout);
> > +}
> > +
> > +int cmd_import(struct strbuf *line)
> > +{
> > +	int code, report_fd;
> > +	char *back_pipe_env;
> > +	int dumpin_fd;
> > +	unsigned int startrev = 0;
> > +	struct argv_array svndump_argv = ARGV_ARRAY_INIT;
> > +	struct child_process svndump_proc;
> > +
> > +	/*
> > +	 * When the remote-helper is invoked by transport-helper.c it passes 
the
> > +	 * filename of this pipe in the env-var.
> > +	 */
> 
> s/ it passes/, &/;
> 
> > +	back_pipe_env = getenv("GIT_REPORT_FIFO");
> 
> Can we name "back pipe", "report fifo" and "report fd" more
> consistently and descriptively?
> 
> What kind of "REPORT" are we talking about here?  Is it to carry the
> contents of

This topic (pipe vs. fifo) is still under discussion with Jonathan. I called it 
REPORT, because that was the name of it in vcs-svn. That will change.

> 
> > +	if (!back_pipe_env) {
> > +		die("Cannot get cat-blob-pipe from environment! GIT_REPORT_FIFO has 
to"
> > +				"be set by the caller.");
> > +	}
> 
> Style: unnecesary {} block around a simple statement.  It is OK to
> have such a block early in a series if you add more statements to it
> in later steps, but that does not seem to be the case for this patch
> series.

ack.

> 
> > +	/*
> > +	 * Opening a fifo for reading usually blocks until a writer has opened
> > it too. +	 * Opening a fifo for writing usually blocks until a reader has
> > opened it too. +	 * Therefore, we open with RDWR on both sides to avoid
> > deadlocks. +	 * Especially if there's nothing to do and one pipe end is
> > closed immediately. +	 */
> 
> This smells somewhat fishy "justification".  Are we reading what we
> wrote to the fifo?  Who is expected to come at the other end of the
> fifo?  Is it this process that creates that other process?  Perhaps
> you should open it _after_ spawning the process, telling it to open
> the same fifo for writing (if you are sitting on the reading end)?

Of course, it's a workaround. The fifo is from fast-import to the remote-
helper. I explained the deadlocks that can occur in a mail some days ago. 
Pasted:

"
I believe it can be solved using RDONLY and WRONLY too. Probably we solve it 
by not using the fifo at all.
Currently the blocking comes from the fact, that fast-import doesn't parse 
it's command line at startup. It rather reads an input line first and decides 
whether to parse the argv after reading the first input line or at the end of 
the input. (don't know why)
remote-svn opens the pipe before sending the first command to fast-import and 
blocks on the open, while fast-import waits for input --> deadlock.
with remote-svn: RDWR, fast-import: WRONLY, this works.

Other scenario: Nothing to import, remote-svn only sends 'done' and closes the 
pipe again. After fast-import reads the first line it parses it's command line 
and tries to open the fifo which is already closed on the other side --> 
blocks.
This is solved by using RDWR on both sides.

If we change the points where the pipes are openend and closed, this could be 
circumvented.
"

see http://thread.gmane.org/gmane.comp.version-control.git/199159/focus=202272

> 
> > +	report_fd = open(back_pipe_env, O_RDWR);
> > +	if (report_fd < 0) {
> > +		die("Unable to open fast-import back-pipe! %s", strerror(errno));
> > +	}
> 
> Style: (ditto).
> 
> > +int cmd_list(struct strbuf *line)
> > +{
> > +	printf("? HEAD\n");
> > +	printf("? %s\n\n", remote_ref);
> > +	fflush(stdout);
> > +	return 0;
> > +}
> 
> It somehow feels funny that remote_ref (which seems to be hardcoded
> to "refs/heads/master") and HEAD are listed here, even though the
> other side is not even in the Git land and the name "master" does
> not have any significance.  The name "refs/heads/master" may be
> necessary to form the LHS of the refspec in cmd_capabilities(), but
> it somehow feels more natural to only advertise HEAD here and also
> futz the refspec to printf("refspec HEAD:%s", private_ref) in
> cmd_capabilities().  Perhaps you tried it already and it did not
> work for some reason; I dunno.

Using HEAD as remote_ref, i.e. here (only once) and in the refspec doesn't 
work. Git doesn't import anything then. Using only refs/heads/master works.
So I will drop that hardcoded 'HEAD' here.

> 
> > +int do_command(struct strbuf *line)
> > +{
> > +	const struct input_command_entry *p = input_command_list;
> > +	static int batch_active;
> > +	static struct strbuf batch_command = STRBUF_INIT;
> > +	/*
> > +	 * import commands can be grouped together in a batch.
> > +	 * Batches are ended by \n. If no batch is active the program ends.
> > +	 */
> > +	if (line->len == 0 ) {
> 
> Style: lose the SP before closing parenthesis ")".

ack.
> 
> > +		if (batch_active) {
> > +			terminate_batch();
> > +			batch_active = 0;
> > +			return 0;
> > +		}
> 
> Is it an error to feed an empty line when batch is not active?
> How is the error diagnosed?
> Is the user told about the error, and if so how?

An empty line outside a batch terminates the remote-helper, this signals the 
end of the command stream (according to  the specs).
Return 1 makes the main loop break.
Will add a commment.

> 
> > +		return 1;
> > +	}
> > +	if (batch_active && strcmp(batch_command.buf, line->buf))
> > +		die("Active %s batch interrupted by %s", batch_command.buf, line-
>buf);
> 
> So after issuing "import" that causes batch_active to become true,
> another command e.g. "list" cannot be issued and will result in this
> die() unless the batch is concluded by issuing an empty line.  Can
> an "import" be issued while another "import" batch is in effect?

Hm, as far as i understand it, there is no way how an import can be in a 
different import batch. Because the batch is just a continuous sequence of 
import commands.

> 
> > +	for(p = input_command_list; p->name; p++) {
> > +		if (!prefixcmp(line->buf, p->name) &&
> > +				(strlen(p->name) == line->len || line->buf[strlen(p->name)] 
== ' '))
> > {
> > +			if (p->batchable) {
> > +				batch_active = 1;
> > +				strbuf_release(&batch_command);
> > +				strbuf_addbuf(&batch_command, line);
> 
> Wouldn't it make more sense to get rid of batch_active variable and
> use the presense of batch_command as the signal for the batch in
> effect?  Your "if (batch_active)" becomes "if (batch_command.len)",
> and "batch_active = 0" becomes "strbuf_release(&batch_command)".
> 

Yes, makes more sense.

> > +			}
> > +			return p->fct(line);
> > +		}
> > +	}
> > +	warning("Unknown command '%s'\n", line->buf);
> > +	return 0;
> > +}
> > +
> > +int main(int argc, const char **argv)
> > +{
> > +	struct strbuf buf = STRBUF_INIT;
> > +	int nongit;
> > +	static struct remote *remote;
> > +	const char *url_in;
> > +
> > +	git_extract_argv0_path(argv[0]);
> > +	setup_git_directory_gently(&nongit);
> > +	if (argc < 2 || argc > 3) {
> > +		usage("git-remote-svn <remote-name> [<url>]");
> > +		return 1;
> > +	}
> > +
> > +	remote = remote_get(argv[1]);
> > +	url_in = remote->url[0];
> > +	if (argc == 3)
> > +		url_in = argv[2];
> > +
> > +	end_url_with_slash(&buf, url_in);
> > +	url = strbuf_detach(&buf, NULL);
> > +
> > +	strbuf_init(&buf, 0);
> > +	strbuf_addf(&buf, "refs/svn/%s/master", remote->name);
> > +	private_ref = strbuf_detach(&buf, NULL);
> > +
> > +	while(1) {
> > +		if (strbuf_getline(&buf, stdin, '\n') == EOF) {
> > +			if (ferror(stdin))
> > +				die_errno("Error reading command stream");
> > +			else
> > +				die_errno("Unexpected end of command stream");
> 
> On the else clause, ferror() did not say there was an error.  What
> errno do we see from die_errno() in that case?

Checked the manpage of ferror: 
"These  functions  should  not fail and do not set the external variable 
errno."
So it doesn't make sense for both, I think.

> 
> > +		}
> > +		if (do_command(&buf))
> > +			break;
> > +		strbuf_reset(&buf);
> > +	}
> > +
> > +	strbuf_release(&buf);
> > +	free((void*)url);
> > +	free((void*)private_ref);
> > +	return 0;
> > +}

^ permalink raw reply	[flat|nested] 47+ messages in thread

end of thread, other threads:[~2012-07-31 19:26 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-26  7:32 [RFC 00/16] GSOC remote-svn, rewritten patch series Florian Achleitner
2012-07-26  7:32 ` [RFC 01/16] Implement a remote helper for svn in C Florian Achleitner
2012-07-26  7:32   ` [RFC 02/16] Integrate remote-svn into svn-fe/Makefile Florian Achleitner
2012-07-26  7:32     ` [RFC 03/16] Add svndump_init_fd to allow reading dumps from arbitrary FDs Florian Achleitner
2012-07-26  7:32       ` [RFC 04/16] Add cat-blob report fifo from fast-import to remote-helper Florian Achleitner
2012-07-26  7:32         ` [RFC 05/16] remote-svn, vcs-svn: Enable fetching to private refs Florian Achleitner
2012-07-26  7:32           ` [RFC 06/16] Add a symlink 'git-remote-svn' in base dir Florian Achleitner
2012-07-26  7:32             ` [RFC 07/16] Allow reading svn dumps from files via file:// urls Florian Achleitner
2012-07-26  7:32               ` [RFC 08/16] vcs-svn: add fast_export_note to create notes Florian Achleitner
2012-07-26  7:32                 ` [RFC 09/16] Create a note for every imported commit containing svn metadata Florian Achleitner
2012-07-26  7:32                   ` [RFC 10/16] When debug==1, start fast-import with "--stats" instead of "--quiet" Florian Achleitner
2012-07-26  7:32                     ` [RFC 11/16] Add explanatory comment for transport-helpers refs mapping Florian Achleitner
2012-07-26  7:32                       ` [RFC 12/16] remote-svn: add incremental import Florian Achleitner
2012-07-26  7:32                         ` [RFC 13/16] Add a svnrdump-simulator replaying a dump file for testing Florian Achleitner
2012-07-26  7:32                           ` [RFC 14/16] transport-helper: add import|export-marks to fast-import command line Florian Achleitner
2012-07-26  7:32                             ` [RFC 15/16] remote-svn: add marks-file regeneration Florian Achleitner
2012-07-26  7:32                               ` [RFC 16/16] Add a test script for remote-svn Florian Achleitner
2012-07-26 16:15                             ` [RFC 14/16] transport-helper: add import|export-marks to fast-import command line Florian Achleitner
2012-07-28  7:06                               ` Jonathan Nieder
2012-07-26  7:46   ` [RFC 01/16] Implement a remote helper for svn in C Jonathan Nieder
2012-07-26  8:02     ` Florian Achleitner
2012-07-26  8:14       ` Jonathan Nieder
2012-07-26  8:37         ` Florian Achleitner
2012-07-30 14:31 ` [RFC v2 00/16] GSOC remote-svn, rewritten patch series Florian Achleitner
2012-07-30 14:31   ` [RFC v2 01/16] Implement a remote helper for svn in C Florian Achleitner
2012-07-30 14:31     ` [RFC v2 02/16] Integrate remote-svn into svn-fe/Makefile Florian Achleitner
2012-07-30 14:31       ` [RFC v2 03/16] Add svndump_init_fd to allow reading dumps from arbitrary FDs Florian Achleitner
2012-07-30 14:31         ` [RFC v2 04/16] Add cat-blob report fifo from fast-import to remote-helper Florian Achleitner
2012-07-30 14:31           ` [RFC v2 05/16] remote-svn, vcs-svn: Enable fetching to private refs Florian Achleitner
2012-07-30 14:31             ` [RFC v2 06/16] Add a symlink 'git-remote-svn' in base dir Florian Achleitner
2012-07-30 14:31               ` [RFC v2 07/16] Allow reading svn dumps from files via file:// urls Florian Achleitner
2012-07-30 14:31                 ` [RFC v2 08/16] vcs-svn: add fast_export_note to create notes Florian Achleitner
2012-07-30 14:31                   ` [RFC v2 09/16] Create a note for every imported commit containing svn metadata Florian Achleitner
2012-07-30 14:31                     ` [RFC v2 10/16] When debug==1, start fast-import with "--stats" instead of "--quiet" Florian Achleitner
2012-07-30 14:31                       ` [RFC v2 11/16] Add explanatory comment for transport-helpers refs mapping Florian Achleitner
2012-07-30 14:31                         ` [RFC v2 12/16] remote-svn: add incremental import Florian Achleitner
2012-07-30 14:31                           ` [RFC v2 13/16] Add a svnrdump-simulator replaying a dump file for testing Florian Achleitner
2012-07-30 14:31                             ` [RFC v2 14/16] transport-helper: add import|export-marks to fast-import command line Florian Achleitner
2012-07-30 14:31                               ` [RFC v2 15/16] remote-svn: add marks-file regeneration Florian Achleitner
2012-07-30 14:31                                 ` [RFC v2 16/16] Add a test script for remote-svn Florian Achleitner
2012-07-30 17:08                         ` [RFC v2 11/16] Add explanatory comment for transport-helpers refs mapping Jonathan Nieder
2012-07-30 17:25                           ` Junio C Hamano
2012-07-30 17:38                           ` Junio C Hamano
2012-07-30 19:15                             ` Jonathan Nieder
2012-07-30 20:15                               ` Florian Achleitner
2012-07-30 16:28     ` [RFC v2 01/16] Implement a remote helper for svn in C Junio C Hamano
2012-07-31 19:26       ` Florian Achleitner

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).