git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/9] Get svnrdump merged into git.git
@ 2010-07-13 23:36 Ramkumar Ramachandra
  2010-07-13 23:36 ` [PATCH 1/9] Add LICENSE Ramkumar Ramachandra
                   ` (10 more replies)
  0 siblings, 11 replies; 26+ messages in thread
From: Ramkumar Ramachandra @ 2010-07-13 23:36 UTC (permalink / raw)
  To: Git Mailing List
  Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier, avarab,
	Daniel Shahaf, Bert Huijben, Junio C Hamano, Eric Wong,
	Will Palmer, Greg Stein

Hi,

For the convinience of fellow Git developers, here's a series to get
svnrdump merged into git.git. Although the series is in excellent
shape (thanks to reviewers), I'd like to make a special request to
relax conformance guidelines a little bit for this series. I'll be
getting commit access to the ASF repository soon; I will commit it
there and make subsequent improvements in Subversion-land. As you can
imagine, due to whitespace and style differences, it's too painful to
backport the changes here. Once there's a release of Subversion with
svnrdump merged in, I will remove it from git.git.

The series incorporates suggestions by Jonathan, Bert, and
Daniel. However, it does not address the recent review by Stefan, and
does not attempt to; Stefan's review will be addressed in future
commits I make to svnrdump in the ASF repository.

Again, I'd request reviewers not to hold up this series for git.git:
suggestions will be incorporated as commits to the ASF. If something
does not work, I'll quickly post fixup patches while the series is
still in `pu`.

Thanks for reading.

-- Ram

Ramkumar Ramachandra (8):
  Add LICENSE
  Add skeleton SVN client and Makefile
  Add debug editor from Subversion trunk
  Drive the debug editor
  Dump the revprops at the start of every revision
  Implement directory-related functions
  Implement file-related functions
  Implement close_file

Will Palmer (1):
  Add a validation script

 vcs-svn/LICENSE        |   26 ++
 vcs-svn/Makefile       |    8 +
 vcs-svn/debug_editor.c |  421 +++++++++++++++++++++++++++++++
 vcs-svn/debug_editor.h |   10 +
 vcs-svn/dump_editor.c  |  652 ++++++++++++++++++++++++++++++++++++++++++++++++
 vcs-svn/dump_editor.h  |    8 +
 vcs-svn/dumpr_util.c   |  112 +++++++++
 vcs-svn/dumpr_util.h   |   92 +++++++
 vcs-svn/svnrdump.c     |  185 ++++++++++++++
 vcs-svn/validate.sh    |  226 +++++++++++++++++
 10 files changed, 1740 insertions(+), 0 deletions(-)
 create mode 100644 vcs-svn/LICENSE
 create mode 100644 vcs-svn/Makefile
 create mode 100644 vcs-svn/debug_editor.c
 create mode 100644 vcs-svn/debug_editor.h
 create mode 100644 vcs-svn/dump_editor.c
 create mode 100644 vcs-svn/dump_editor.h
 create mode 100644 vcs-svn/dumpr_util.c
 create mode 100644 vcs-svn/dumpr_util.h
 create mode 100644 vcs-svn/svnrdump.c
 create mode 100755 vcs-svn/validate.sh

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

* [PATCH 1/9] Add LICENSE
  2010-07-13 23:36 [PATCH 0/9] Get svnrdump merged into git.git Ramkumar Ramachandra
@ 2010-07-13 23:36 ` Ramkumar Ramachandra
  2010-07-14  4:47   ` Daniel Shahaf
  2010-07-13 23:36 ` [PATCH 2/9] Add skeleton SVN client and Makefile Ramkumar Ramachandra
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 26+ messages in thread
From: Ramkumar Ramachandra @ 2010-07-13 23:36 UTC (permalink / raw)
  To: Git Mailing List
  Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier, avarab,
	Daniel Shahaf, Bert Huijben, Junio C Hamano, Eric Wong,
	Will Palmer, Greg Stein

License the project under a two-clause BSD-style license. A dual
license will be required later when attempting to merge into
Subversion.

Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
 LICENSE |   26 ++++++++++++++++++++++++++
 1 files changed, 26 insertions(+), 0 deletions(-)
 create mode 100644 LICENSE

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..4367b7c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,26 @@
+Copyright (C) 2010 Ramkumar Ramachandra
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice(s), this list of conditions and the following disclaimer
+   unmodified other than the allowable addition of one or more
+   copyright notices.
+2. Redistributions in binary form must reproduce the above copyright
+   notice(s), this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-- 
1.7.1

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

* [PATCH 2/9] Add skeleton SVN client and Makefile
  2010-07-13 23:36 [PATCH 0/9] Get svnrdump merged into git.git Ramkumar Ramachandra
  2010-07-13 23:36 ` [PATCH 1/9] Add LICENSE Ramkumar Ramachandra
@ 2010-07-13 23:36 ` Ramkumar Ramachandra
  2010-07-13 23:36 ` [PATCH 3/9] Add debug editor from Subversion trunk Ramkumar Ramachandra
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 26+ messages in thread
From: Ramkumar Ramachandra @ 2010-07-13 23:36 UTC (permalink / raw)
  To: Git Mailing List
  Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier, avarab,
	Daniel Shahaf, Bert Huijben, Junio C Hamano, Eric Wong,
	Will Palmer, Greg Stein

Add a basic SVN command-line client along with a Makefile that does
just enough to establish a connection with the ASF subversion server;
it initializes a memory pool, sees that configuration files are in
order, builds up a context object, sets up an authentication baton,
and finally opens a session to the subversion server.

Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
 Makefile   |    8 +++++
 svnrdump.c |  102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 110 insertions(+), 0 deletions(-)
 create mode 100644 Makefile
 create mode 100644 svnrdump.c

diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..55f28e5
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,8 @@
+svnrdump: *.c
+	$(CC) -Wall -Werror -DAPR_POOL_DEBUG -ggdb3 -O0 -o $@ svnrdump.c -lsvn_client-1 -I. -I/usr/include/subversion-1 -I/usr/include/apr-1.0
+
+svnrdump_bench: *.c
+	$(CC) -O2 -o $@ svnrdump.c -lsvn_client-1 -I. -I/usr/include/subversion-1 -I/usr/include/apr-1.0
+
+clean:
+	$(RM) svnrdump svnrdump_bench
diff --git a/svnrdump.c b/svnrdump.c
new file mode 100644
index 0000000..35c1a73
--- /dev/null
+++ b/svnrdump.c
@@ -0,0 +1,102 @@
+/* Licensed under a two-clause BSD-style license.
+ * See LICENSE for details.
+ */
+
+#include "svn_pools.h"
+#include "svn_cmdline.h"
+#include "svn_client.h"
+#include "svn_ra.h"
+#include "svn_repos.h"
+#include "svn_path.h"
+
+static int verbose = 0;
+static apr_pool_t *pool = NULL;
+static svn_client_ctx_t *ctx = NULL;
+static svn_ra_session_t *session = NULL;
+
+static svn_error_t *open_connection(const char *url)
+{
+	SVN_ERR(svn_config_ensure (NULL, pool));
+	SVN_ERR(svn_client_create_context (&ctx, pool));
+	SVN_ERR(svn_ra_initialize(pool));
+
+	SVN_ERR(svn_config_get_config(&(ctx->config), NULL, pool));
+
+	/* Default authentication providers for non-interactive use */
+	SVN_ERR(svn_cmdline_create_auth_baton(&(ctx->auth_baton), TRUE,
+					      NULL, NULL, NULL, FALSE,
+					      FALSE, NULL, NULL, NULL,
+					      pool));
+	SVN_ERR(svn_client_open_ra_session(&session, url, ctx, pool));
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *replay_range(svn_revnum_t start_revision, svn_revnum_t end_revision)
+{
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *usage(FILE *out_stream)
+{
+	fprintf(out_stream,
+		"usage: svnrdump URL [-r LOWER[:UPPER]]\n\n"
+		"Dump the contents of repository at remote URL to stdout in a 'dumpfile'\n"
+		"v3 portable format.  Dump revisions LOWER rev through UPPER rev.\n"
+		"LOWER defaults to 1 and UPPER defaults to the highest possible revision\n"
+		"if omitted.\n");
+	return SVN_NO_ERROR;
+}
+
+
+int main(int argc, const char **argv)
+{
+	int i;
+	const char *url = NULL;
+	char *revision_cut = NULL;
+	svn_revnum_t start_revision = svn_opt_revision_unspecified;
+	svn_revnum_t end_revision = svn_opt_revision_unspecified;
+
+	if (svn_cmdline_init ("svnrdump", stderr) != EXIT_SUCCESS)
+		return EXIT_FAILURE;
+
+	pool = svn_pool_create(NULL);
+
+	for (i = 1; i < argc; i++) {
+		if (!strncmp("-r", argv[i], 2)) {
+			revision_cut = strchr(argv[i] + 2, ':');
+			if (revision_cut) {
+				start_revision = (svn_revnum_t) strtoul(argv[i] + 2, &revision_cut, 10);
+				end_revision = (svn_revnum_t) strtoul(revision_cut + 1, NULL, 10);
+			}
+			else
+				start_revision = (svn_revnum_t) strtoul(argv[i] + 2, NULL, 10);
+		} else if (!strcmp("-v", argv[i]) || !strcmp("--verbose", argv[i])) {
+			verbose = 1;
+		} else if (!strcmp("help", argv[i]) || !strcmp("--help", argv[i])) {
+			SVN_INT_ERR(usage(stdout));
+			return EXIT_SUCCESS;
+		} else if (*argv[i] == '-' || url) {
+			SVN_INT_ERR(usage(stderr));
+			return EXIT_FAILURE;
+		} else
+			url = argv[i];
+	}
+
+	if (!url || !svn_path_is_url(url)) {
+		usage(stderr);
+		return EXIT_FAILURE;
+	}
+	SVN_INT_ERR(open_connection(url));
+
+	/* Have sane start_revision and end_revision defaults if unspecified */
+	if (start_revision == svn_opt_revision_unspecified)
+		start_revision = 1;
+	if (end_revision == svn_opt_revision_unspecified)
+		SVN_INT_ERR(svn_ra_get_latest_revnum(session, &end_revision, pool));
+
+	SVN_INT_ERR(replay_range(start_revision, end_revision));
+
+	svn_pool_destroy(pool);
+	
+	return 0;
+}
-- 
1.7.1

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

* [PATCH 3/9] Add debug editor from Subversion trunk
  2010-07-13 23:36 [PATCH 0/9] Get svnrdump merged into git.git Ramkumar Ramachandra
  2010-07-13 23:36 ` [PATCH 1/9] Add LICENSE Ramkumar Ramachandra
  2010-07-13 23:36 ` [PATCH 2/9] Add skeleton SVN client and Makefile Ramkumar Ramachandra
@ 2010-07-13 23:36 ` Ramkumar Ramachandra
  2010-07-13 23:36 ` [PATCH 4/9] Drive the debug editor Ramkumar Ramachandra
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 26+ messages in thread
From: Ramkumar Ramachandra @ 2010-07-13 23:36 UTC (permalink / raw)
  To: Git Mailing List
  Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier, avarab,
	Daniel Shahaf, Bert Huijben, Junio C Hamano, Eric Wong,
	Will Palmer, Greg Stein

Add the debug editor from subversion/libsvn_delta/debug_editor.c along
with a header to expose the svn_delta__get_debug_editor function. It
is used for wrapping other editors, and prints the operations it does
to stderr making debugging easier.

Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
 Makefile       |    8 +-
 debug_editor.c |  421 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 debug_editor.h |   10 ++
 dump_editor.c  |  144 +++++++++++++++++++
 dump_editor.h  |    8 +
 dumpr_util.h   |    9 ++
 6 files changed, 596 insertions(+), 4 deletions(-)
 create mode 100644 debug_editor.c
 create mode 100644 debug_editor.h
 create mode 100644 dump_editor.c
 create mode 100644 dump_editor.h
 create mode 100644 dumpr_util.h

diff --git a/Makefile b/Makefile
index 55f28e5..3561909 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
-svnrdump: *.c
-	$(CC) -Wall -Werror -DAPR_POOL_DEBUG -ggdb3 -O0 -o $@ svnrdump.c -lsvn_client-1 -I. -I/usr/include/subversion-1 -I/usr/include/apr-1.0
+svnrdump: *.c *.h
+	$(CC) -Wall -Werror -DAPR_POOL_DEBUG -ggdb3 -O0 -o $@ svnrdump.c debug_editor.c dump_editor.c -lsvn_client-1 -I. -I/usr/include/subversion-1 -I/usr/include/apr-1.0
 
-svnrdump_bench: *.c
-	$(CC) -O2 -o $@ svnrdump.c -lsvn_client-1 -I. -I/usr/include/subversion-1 -I/usr/include/apr-1.0
+svnrdump_bench: *.c *.h
+	$(CC) -O2 -o $@ svnrdump.c debug_editor.c dump_editor.c -lsvn_client-1 -I. -I/usr/include/subversion-1 -I/usr/include/apr-1.0
 
 clean:
 	$(RM) svnrdump svnrdump_bench
diff --git a/debug_editor.c b/debug_editor.c
new file mode 100644
index 0000000..9271c7a
--- /dev/null
+++ b/debug_editor.c
@@ -0,0 +1,421 @@
+/*
+ * debug_editor.c :  An editor that writes the operations it does to stderr.
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+#include "svn_pools.h"
+#include "svn_cmdline.h"
+#include "svn_client.h"
+#include "svn_ra.h"
+
+#include "debug_editor.h"
+
+struct edit_baton
+{
+	const svn_delta_editor_t *wrapped_editor;
+	void *wrapped_edit_baton;
+
+	int indent_level;
+
+	svn_stream_t *out;
+};
+
+struct dir_baton
+{
+	void *edit_baton;
+	void *wrapped_dir_baton;
+};
+
+struct file_baton
+{
+	void *edit_baton;
+	void *wrapped_file_baton;
+};
+
+static svn_error_t *write_indent(struct edit_baton *eb, apr_pool_t *pool)
+{
+	int i;
+
+	for (i = 0; i < eb->indent_level; ++i)
+		SVN_ERR(svn_stream_printf(eb->out, pool, " "));
+
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *set_target_revision(void *edit_baton,
+					svn_revnum_t target_revision,
+					apr_pool_t *pool)
+{
+	struct edit_baton *eb = edit_baton;
+
+	SVN_ERR(write_indent(eb, pool));
+	SVN_ERR(svn_stream_printf(eb->out, pool, "set_target_revision : %ld\n",
+				  target_revision));
+
+	return eb->wrapped_editor->set_target_revision(eb->wrapped_edit_baton,
+						       target_revision,
+						       pool);
+}
+
+static svn_error_t *open_root(void *edit_baton,
+			      svn_revnum_t base_revision,
+			      apr_pool_t *pool,
+			      void **root_baton)
+{
+	struct edit_baton *eb = edit_baton;
+	struct dir_baton *dir_baton = apr_palloc(pool, sizeof(*dir_baton));
+
+	SVN_ERR(write_indent(eb, pool));
+	SVN_ERR(svn_stream_printf(eb->out, pool, "open_root : %ld\n",
+				  base_revision));
+	eb->indent_level++;
+
+	SVN_ERR(eb->wrapped_editor->open_root(eb->wrapped_edit_baton,
+					      base_revision,
+					      pool,
+					      &dir_baton->wrapped_dir_baton));
+
+	dir_baton->edit_baton = edit_baton;
+
+	*root_baton = dir_baton;
+
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *delete_entry(const char *path,
+				 svn_revnum_t base_revision,
+				 void *parent_baton,
+				 apr_pool_t *pool)
+{
+	struct dir_baton *pb = parent_baton;
+	struct edit_baton *eb = pb->edit_baton;
+
+	SVN_ERR(write_indent(eb, pool));
+	SVN_ERR(svn_stream_printf(eb->out, pool, "delete_entry : %s:%ld\n",
+				  path, base_revision));
+
+	return eb->wrapped_editor->delete_entry(path,
+						base_revision,
+						pb->wrapped_dir_baton,
+						pool);
+}
+
+static svn_error_t *add_directory(const char *path,
+				  void *parent_baton,
+				  const char *copyfrom_path,
+				  svn_revnum_t copyfrom_revision,
+				  apr_pool_t *pool,
+				  void **child_baton)
+{
+	struct dir_baton *pb = parent_baton;
+	struct edit_baton *eb = pb->edit_baton;
+	struct dir_baton *b = apr_palloc(pool, sizeof(*b));
+
+	SVN_ERR(write_indent(eb, pool));
+	SVN_ERR(svn_stream_printf(eb->out, pool,
+				  "add_directory : '%s' [from '%s':%ld]\n",
+				  path, copyfrom_path, copyfrom_revision));
+	eb->indent_level++;
+
+	SVN_ERR(eb->wrapped_editor->add_directory(path,
+						  pb->wrapped_dir_baton,
+						  copyfrom_path,
+						  copyfrom_revision,
+						  pool,
+						  &b->wrapped_dir_baton));
+
+	b->edit_baton = eb;
+	*child_baton = b;
+
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *open_directory(const char *path,
+				   void *parent_baton,
+				   svn_revnum_t base_revision,
+				   apr_pool_t *pool,
+				   void **child_baton)
+{
+	struct dir_baton *pb = parent_baton;
+	struct edit_baton *eb = pb->edit_baton;
+	struct dir_baton *db = apr_palloc(pool, sizeof(*db));
+
+	SVN_ERR(write_indent(eb, pool));
+	SVN_ERR(svn_stream_printf(eb->out, pool, "open_directory : '%s':%ld\n",
+				  path, base_revision));
+	eb->indent_level++;
+
+	SVN_ERR(eb->wrapped_editor->open_directory(path,
+						   pb->wrapped_dir_baton,
+						   base_revision,
+						   pool,
+						   &db->wrapped_dir_baton));
+
+	db->edit_baton = eb;
+	*child_baton = db;
+
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *add_file(const char *path,
+			     void *parent_baton,
+			     const char *copyfrom_path,
+			     svn_revnum_t copyfrom_revision,
+			     apr_pool_t *pool,
+			     void **file_baton)
+{
+	struct dir_baton *pb = parent_baton;
+	struct edit_baton *eb = pb->edit_baton;
+	struct file_baton *fb = apr_palloc(pool, sizeof(*fb));
+
+	SVN_ERR(write_indent(eb, pool));
+	SVN_ERR(svn_stream_printf(eb->out, pool,
+				  "add_file : '%s' [from '%s':%ld]\n",
+				  path, copyfrom_path, copyfrom_revision));
+
+	eb->indent_level++;
+
+	SVN_ERR(eb->wrapped_editor->add_file(path,
+					     pb->wrapped_dir_baton,
+					     copyfrom_path,
+					     copyfrom_revision,
+					     pool,
+					     &fb->wrapped_file_baton));
+
+	fb->edit_baton = eb;
+	*file_baton = fb;
+
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *open_file(const char *path,
+			      void *parent_baton,
+			      svn_revnum_t base_revision,
+			      apr_pool_t *pool,
+			      void **file_baton)
+{
+	struct dir_baton *pb = parent_baton;
+	struct edit_baton *eb = pb->edit_baton;
+	struct file_baton *fb = apr_palloc(pool, sizeof(*fb));
+
+	SVN_ERR(write_indent(eb, pool));
+	SVN_ERR(svn_stream_printf(eb->out, pool, "open_file : '%s':%ld\n",
+				  path, base_revision));
+
+	eb->indent_level++;
+
+	SVN_ERR(eb->wrapped_editor->open_file(path,
+					      pb->wrapped_dir_baton,
+					      base_revision,
+					      pool,
+					      &fb->wrapped_file_baton));
+
+	fb->edit_baton = eb;
+	*file_baton = fb;
+
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *apply_textdelta(void *file_baton,
+				    const char *base_checksum,
+				    apr_pool_t *pool,
+				    svn_txdelta_window_handler_t *handler,
+				    void **handler_baton)
+{
+	struct file_baton *fb = file_baton;
+	struct edit_baton *eb = fb->edit_baton;
+
+	SVN_ERR(write_indent(eb, pool));
+	SVN_ERR(svn_stream_printf(eb->out, pool, "apply_textdelta : %s\n",
+				  base_checksum));
+
+	SVN_ERR(eb->wrapped_editor->apply_textdelta(fb->wrapped_file_baton,
+						    base_checksum,
+						    pool,
+						    handler,
+						    handler_baton));
+
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *close_file(void *file_baton,
+			       const char *text_checksum,
+			       apr_pool_t *pool)
+{
+	struct file_baton *fb = file_baton;
+	struct edit_baton *eb = fb->edit_baton;
+
+	eb->indent_level--;
+
+	SVN_ERR(write_indent(eb, pool));
+	SVN_ERR(svn_stream_printf(eb->out, pool, "close_file : %s\n",
+				  text_checksum));
+
+	SVN_ERR(eb->wrapped_editor->close_file(fb->wrapped_file_baton,
+					       text_checksum, pool));
+
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *absent_file(const char *path,
+				void *file_baton,
+				apr_pool_t *pool)
+{
+	struct file_baton *fb = file_baton;
+	struct edit_baton *eb = fb->edit_baton;
+
+	SVN_ERR(write_indent(eb, pool));
+	SVN_ERR(svn_stream_printf(eb->out, pool, "absent_file : %s\n", path));
+
+	SVN_ERR(eb->wrapped_editor->absent_file(path, fb->wrapped_file_baton,
+						pool));
+
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *close_directory(void *dir_baton,
+				    apr_pool_t *pool)
+{
+	struct dir_baton *db = dir_baton;
+	struct edit_baton *eb = db->edit_baton;
+
+	eb->indent_level--;
+	SVN_ERR(write_indent(eb, pool));
+	SVN_ERR(svn_stream_printf(eb->out, pool, "close_directory\n"));
+
+	SVN_ERR(eb->wrapped_editor->close_directory(db->wrapped_dir_baton,
+						    pool));
+
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *absent_directory(const char *path,
+				     void *dir_baton,
+				     apr_pool_t *pool)
+{
+	struct dir_baton *db = dir_baton;
+	struct edit_baton *eb = db->edit_baton;
+
+	SVN_ERR(write_indent(eb, pool));
+	SVN_ERR(svn_stream_printf(eb->out, pool, "absent_directory : %s\n",
+				  path));
+
+	SVN_ERR(eb->wrapped_editor->absent_directory(path, db->wrapped_dir_baton,
+						     pool));
+
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *change_file_prop(void *file_baton,
+				     const char *name,
+				     const svn_string_t *value,
+				     apr_pool_t *pool)
+{
+	struct file_baton *fb = file_baton;
+	struct edit_baton *eb = fb->edit_baton;
+
+	SVN_ERR(write_indent(eb, pool));
+	SVN_ERR(svn_stream_printf(eb->out, pool, "change_file_prop : %s\n",
+				  name));
+
+	SVN_ERR(eb->wrapped_editor->change_file_prop(fb->wrapped_file_baton,
+						     name,
+						     value,
+						     pool));
+
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *change_dir_prop(void *dir_baton,
+				    const char *name,
+				    const svn_string_t *value,
+				    apr_pool_t *pool)
+{
+	struct dir_baton *db = dir_baton;
+	struct edit_baton *eb = db->edit_baton;
+
+	SVN_ERR(write_indent(eb, pool));
+	SVN_ERR(svn_stream_printf(eb->out, pool, "change_dir_prop : %s\n", name));
+
+	SVN_ERR(eb->wrapped_editor->change_dir_prop(db->wrapped_dir_baton,
+						    name,
+						    value,
+						    pool));
+
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *close_edit(void *edit_baton,
+			       apr_pool_t *pool)
+{
+	struct edit_baton *eb = edit_baton;
+
+	SVN_ERR(write_indent(eb, pool));
+	SVN_ERR(svn_stream_printf(eb->out, pool, "close_edit\n"));
+
+	SVN_ERR(eb->wrapped_editor->close_edit(eb->wrapped_edit_baton, pool));
+
+	return SVN_NO_ERROR;
+}
+
+svn_error_t *svn_delta__get_debug_editor(const svn_delta_editor_t **editor,
+					 void **edit_baton,
+					 const svn_delta_editor_t *wrapped_editor,
+					 void *wrapped_edit_baton,
+					 apr_pool_t *pool)
+{
+	svn_delta_editor_t *tree_editor = svn_delta_default_editor(pool);
+	struct edit_baton *eb = apr_palloc(pool, sizeof(*eb));
+	apr_file_t *errfp;
+	svn_stream_t *out;
+
+	apr_status_t apr_err = apr_file_open_stderr(&errfp, pool);
+	if (apr_err)
+		return svn_error_wrap_apr(apr_err, "Problem opening stderr");
+
+	out = svn_stream_from_aprfile2(errfp, TRUE, pool);
+
+	tree_editor->set_target_revision = set_target_revision;
+	tree_editor->open_root = open_root;
+	tree_editor->delete_entry = delete_entry;
+	tree_editor->add_directory = add_directory;
+	tree_editor->open_directory = open_directory;
+	tree_editor->change_dir_prop = change_dir_prop;
+	tree_editor->close_directory = close_directory;
+	tree_editor->absent_directory = absent_directory;
+	tree_editor->add_file = add_file;
+	tree_editor->open_file = open_file;
+	tree_editor->apply_textdelta = apply_textdelta;
+	tree_editor->change_file_prop = change_file_prop;
+	tree_editor->close_file = close_file;
+	tree_editor->absent_file = absent_file;
+	tree_editor->close_edit = close_edit;
+
+	eb->wrapped_editor = wrapped_editor;
+	eb->wrapped_edit_baton = wrapped_edit_baton;
+	eb->out = out;
+	eb->indent_level = 0;
+
+	*editor = tree_editor;
+	*edit_baton = eb;
+
+	return SVN_NO_ERROR;
+}
diff --git a/debug_editor.h b/debug_editor.h
new file mode 100644
index 0000000..a0d412a
--- /dev/null
+++ b/debug_editor.h
@@ -0,0 +1,10 @@
+#ifndef DEBUG_EDITOR_H_
+#define DEBUG_EDITOR_H_
+
+svn_error_t *svn_delta__get_debug_editor(const svn_delta_editor_t **editor,
+					 void **edit_baton,
+					 const svn_delta_editor_t *wrapped_editor,
+					 void *wrapped_edit_baton,
+					 apr_pool_t *pool);
+
+#endif
diff --git a/dump_editor.c b/dump_editor.c
new file mode 100644
index 0000000..2db3f7e
--- /dev/null
+++ b/dump_editor.c
@@ -0,0 +1,144 @@
+/* Licensed under a two-clause BSD-style license.
+ * See LICENSE for details.
+ */
+
+#include "svn_pools.h"
+#include "svn_repos.h"
+#include "svn_path.h"
+#include "svn_props.h"
+#include "svn_dirent_uri.h"
+
+#include "dumpr_util.h"
+
+static svn_error_t *open_root(void *edit_baton,
+			      svn_revnum_t base_revision,
+			      apr_pool_t *pool,
+			      void **root_baton)
+{
+	*root_baton = NULL;
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *delete_entry(const char *path,
+				 svn_revnum_t revision,
+				 void *parent_baton,
+				 apr_pool_t *pool)
+{
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *add_directory(const char *path,
+				  void *parent_baton,
+				  const char *copyfrom_path,
+				  svn_revnum_t copyfrom_rev,
+				  apr_pool_t *pool,
+				  void **child_baton)
+{
+	*child_baton = NULL;
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *open_directory(const char *path,
+				   void *parent_baton,
+				   svn_revnum_t base_revision,
+				   apr_pool_t *pool,
+				   void **child_baton)
+{
+	*child_baton = NULL;
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *close_directory(void *dir_baton,
+				    apr_pool_t *pool)
+{
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *add_file(const char *path,
+			     void *parent_baton,
+			     const char *copyfrom_path,
+			     svn_revnum_t copyfrom_rev,
+			     apr_pool_t *pool,
+			     void **file_baton)
+{
+	*file_baton = NULL;
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *open_file(const char *path,
+			      void *parent_baton,
+			      svn_revnum_t ancestor_revision,
+			      apr_pool_t *pool,
+			      void **file_baton)
+{
+	*file_baton = NULL;
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *change_dir_prop(void *parent_baton,
+				    const char *name,
+				    const svn_string_t *value,
+				    apr_pool_t *pool)
+{
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *change_file_prop(void *file_baton,
+				     const char *name,
+				     const svn_string_t *value,
+				     apr_pool_t *pool)
+{
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *apply_textdelta(void *file_baton, const char *base_checksum,
+				    apr_pool_t *pool,
+				    svn_txdelta_window_handler_t *handler,
+				    void **handler_baton)
+{
+	*handler = svn_delta_noop_window_handler;
+	*handler_baton = NULL;
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *close_file(void *file_baton,
+			       const char *text_checksum,
+			       apr_pool_t *pool)
+{
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *close_edit(void *edit_baton, apr_pool_t *pool)
+{
+	return SVN_NO_ERROR;
+}
+
+svn_error_t *get_dump_editor(const svn_delta_editor_t **editor,
+                             void **edit_baton,
+                             svn_revnum_t from_rev,
+                             apr_pool_t *pool)
+{
+	struct dump_edit_baton *eb = apr_pcalloc(pool, sizeof(struct dump_edit_baton));
+	eb->current_rev = from_rev;
+	SVN_ERR(svn_stream_for_stdout(&(eb->stream), pool));
+	svn_delta_editor_t *de = svn_delta_default_editor(pool);
+	
+	de->open_root = open_root;
+	de->delete_entry = delete_entry;
+	de->add_directory = add_directory;
+	de->open_directory = open_directory;
+	de->close_directory = close_directory;
+	de->change_dir_prop = change_dir_prop;
+	de->change_file_prop = change_file_prop;
+	de->apply_textdelta = apply_textdelta;
+	de->add_file = add_file;
+	de->open_file = open_file;
+	de->close_file = close_file;
+	de->close_edit = close_edit;
+
+	/* Set the edit_baton and editor */
+	*edit_baton = eb;
+	*editor = de;
+
+	return SVN_NO_ERROR;
+}
diff --git a/dump_editor.h b/dump_editor.h
new file mode 100644
index 0000000..9c70b74
--- /dev/null
+++ b/dump_editor.h
@@ -0,0 +1,8 @@
+#ifndef DUMP_EDITOR_H_
+#define DUMP_EDITOR_H_
+
+svn_error_t *get_dump_editor(const svn_delta_editor_t **editor,
+			     void **edit_baton,
+			     svn_revnum_t to_rev,
+			     apr_pool_t *pool);
+#endif
diff --git a/dumpr_util.h b/dumpr_util.h
new file mode 100644
index 0000000..199c9c4
--- /dev/null
+++ b/dumpr_util.h
@@ -0,0 +1,9 @@
+#ifndef DUMPR_UTIL_H_
+#define DUMPR_UTIL_H_
+
+struct dump_edit_baton {
+	svn_stream_t *stream;
+	svn_revnum_t current_rev;
+};
+
+#endif
-- 
1.7.1

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

* [PATCH 4/9] Drive the debug editor
  2010-07-13 23:36 [PATCH 0/9] Get svnrdump merged into git.git Ramkumar Ramachandra
                   ` (2 preceding siblings ...)
  2010-07-13 23:36 ` [PATCH 3/9] Add debug editor from Subversion trunk Ramkumar Ramachandra
@ 2010-07-13 23:36 ` Ramkumar Ramachandra
  2010-07-13 23:36 ` [PATCH 5/9] Dump the revprops at the start of every revision Ramkumar Ramachandra
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 26+ messages in thread
From: Ramkumar Ramachandra @ 2010-07-13 23:36 UTC (permalink / raw)
  To: Git Mailing List
  Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier, avarab,
	Daniel Shahaf, Bert Huijben, Junio C Hamano, Eric Wong,
	Will Palmer, Greg Stein

Wrap the dummy dump editor in the debug editor and drive the debug
editor to print out all the actions that occur during the replay to
stderr. In replay_revstart, extract and set editor/ edit_baton from
the replay_baton; they must persist across all the callback functions
while replaying a revision.

Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
 dumpr_util.h |    5 +++++
 svnrdump.c   |   47 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 52 insertions(+), 0 deletions(-)

diff --git a/dumpr_util.h b/dumpr_util.h
index 199c9c4..8f494c1 100644
--- a/dumpr_util.h
+++ b/dumpr_util.h
@@ -1,6 +1,11 @@
 #ifndef DUMPR_UTIL_H_
 #define DUMPR_UTIL_H_
 
+struct replay_baton {
+	const svn_delta_editor_t *editor;
+	void *edit_baton;
+};
+
 struct dump_edit_baton {
 	svn_stream_t *stream;
 	svn_revnum_t current_rev;
diff --git a/svnrdump.c b/svnrdump.c
index 35c1a73..e184fee 100644
--- a/svnrdump.c
+++ b/svnrdump.c
@@ -9,11 +9,39 @@
 #include "svn_repos.h"
 #include "svn_path.h"
 
+#include "debug_editor.h"
+#include "dump_editor.h"
+#include "dumpr_util.h"
+
 static int verbose = 0;
 static apr_pool_t *pool = NULL;
 static svn_client_ctx_t *ctx = NULL;
 static svn_ra_session_t *session = NULL;
 
+static svn_error_t *replay_revstart(svn_revnum_t revision,
+                                    void *replay_baton,
+                                    const svn_delta_editor_t **editor,
+                                    void **edit_baton,
+                                    apr_hash_t *rev_props,
+                                    apr_pool_t *pool)
+{
+	struct replay_baton *rb = replay_baton;
+	*editor = rb->editor;
+	*edit_baton = rb->edit_baton;
+
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *replay_revend(svn_revnum_t revision,
+                                  void *replay_baton,
+                                  const svn_delta_editor_t *editor,
+                                  void *edit_baton,
+                                  apr_hash_t *rev_props,
+                                  apr_pool_t *pool)
+{
+	return SVN_NO_ERROR;
+}
+
 static svn_error_t *open_connection(const char *url)
 {
 	SVN_ERR(svn_config_ensure (NULL, pool));
@@ -33,6 +61,25 @@ static svn_error_t *open_connection(const char *url)
 
 static svn_error_t *replay_range(svn_revnum_t start_revision, svn_revnum_t end_revision)
 {
+	const svn_delta_editor_t *dump_editor, *debug_editor;
+	void *debug_baton, *dump_baton;
+
+	SVN_ERR(get_dump_editor(&dump_editor,
+	                        &dump_baton, start_revision, pool));
+
+	SVN_ERR(svn_delta__get_debug_editor(&debug_editor,
+	                                    &debug_baton,
+	                                    dump_editor,
+	                                    dump_baton, pool));
+
+	struct replay_baton *replay_baton = apr_palloc(pool, sizeof(struct replay_baton));
+	replay_baton->editor = debug_editor;
+	replay_baton->edit_baton = debug_baton;
+	SVN_ERR(svn_cmdline_printf(pool, SVN_REPOS_DUMPFILE_MAGIC_HEADER ": %d\n",
+				   SVN_REPOS_DUMPFILE_FORMAT_VERSION));
+	SVN_ERR(svn_ra_replay_range(session, start_revision, end_revision,
+	                            0, TRUE, replay_revstart, replay_revend,
+	                            replay_baton, pool));
 	return SVN_NO_ERROR;
 }
 
-- 
1.7.1

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

* [PATCH 5/9] Dump the revprops at the start of every revision
  2010-07-13 23:36 [PATCH 0/9] Get svnrdump merged into git.git Ramkumar Ramachandra
                   ` (3 preceding siblings ...)
  2010-07-13 23:36 ` [PATCH 4/9] Drive the debug editor Ramkumar Ramachandra
@ 2010-07-13 23:36 ` Ramkumar Ramachandra
  2010-07-13 23:36 ` [PATCH 6/9] Implement directory-related functions Ramkumar Ramachandra
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 26+ messages in thread
From: Ramkumar Ramachandra @ 2010-07-13 23:36 UTC (permalink / raw)
  To: Git Mailing List
  Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier, avarab,
	Daniel Shahaf, Bert Huijben, Junio C Hamano, Eric Wong,
	Will Palmer, Greg Stein

Fill in replay_revstart to dump the revprops at the start of every
revision. Add an additional write_hash_to_stringbuf helper function.

Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
 Makefile      |    4 +-
 dump_editor.c |  207 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 dumpr_util.c  |  112 +++++++++++++++++++++++++++++++
 dumpr_util.h  |   63 +++++++++++++++++
 svnrdump.c    |   40 +++++++++++-
 5 files changed, 421 insertions(+), 5 deletions(-)
 create mode 100644 dumpr_util.c

diff --git a/Makefile b/Makefile
index 3561909..6a5a101 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 svnrdump: *.c *.h
-	$(CC) -Wall -Werror -DAPR_POOL_DEBUG -ggdb3 -O0 -o $@ svnrdump.c debug_editor.c dump_editor.c -lsvn_client-1 -I. -I/usr/include/subversion-1 -I/usr/include/apr-1.0
+	$(CC) -Wall -Werror -DAPR_POOL_DEBUG -ggdb3 -O0 -o $@ svnrdump.c debug_editor.c dump_editor.c dumpr_util.c -lsvn_client-1 -I. -I/usr/include/subversion-1 -I/usr/include/apr-1.0
 
 svnrdump_bench: *.c *.h
-	$(CC) -O2 -o $@ svnrdump.c debug_editor.c dump_editor.c -lsvn_client-1 -I. -I/usr/include/subversion-1 -I/usr/include/apr-1.0
+	$(CC) -O2 -o $@ svnrdump.c debug_editor.c dump_editor.c dumpr_util.c -lsvn_client-1 -I. -I/usr/include/subversion-1 -I/usr/include/apr-1.0
 
 clean:
 	$(RM) svnrdump svnrdump_bench
diff --git a/dump_editor.c b/dump_editor.c
index 2db3f7e..0506966 100644
--- a/dump_editor.c
+++ b/dump_editor.c
@@ -10,12 +10,213 @@
 
 #include "dumpr_util.h"
 
+#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
+
+/* Make a directory baton to represent the directory was path
+   (relative to EDIT_BATON's path) is PATH.
+
+   CMP_PATH/CMP_REV are the path/revision against which this directory
+   should be compared for changes.  If either is omitted (NULL for the
+   path, SVN_INVALID_REVNUM for the rev), just compare this directory
+   PATH against itself in the previous revision.
+
+   PARENT_DIR_BATON is the directory baton of this directory's parent,
+   or NULL if this is the top-level directory of the edit.  ADDED
+   indicated if this directory is newly added in this revision.
+   Perform all allocations in POOL.  */
+static struct dir_baton *make_dir_baton(const char *path,
+					const char *cmp_path,
+					svn_revnum_t cmp_rev,
+					void *edit_baton,
+					void *parent_dir_baton,
+					svn_boolean_t added,
+					apr_pool_t *pool)
+{
+	struct dump_edit_baton *eb = edit_baton;
+	struct dir_baton *pb = parent_dir_baton;
+	struct dir_baton *new_db = apr_pcalloc(pool, sizeof(*new_db));
+	const char *full_path;
+	apr_array_header_t *compose_path = apr_array_make(pool, 2, sizeof(const char *));
+
+	/* A path relative to nothing?  I don't think so. */
+	SVN_ERR_ASSERT_NO_RETURN(!path || pb);
+
+	/* Construct the full path of this node. */
+	if (pb) {
+		APR_ARRAY_PUSH(compose_path, const char *) = "/";
+		APR_ARRAY_PUSH(compose_path, const char *) = path;
+		full_path = svn_path_compose(compose_path, pool);
+	}
+	else
+		full_path = apr_pstrdup(pool, "/");
+
+	/* Remove leading slashes from copyfrom paths. */
+	if (cmp_path)
+		cmp_path = ((*cmp_path == '/') ? cmp_path + 1 : cmp_path);
+
+	new_db->eb = eb;
+	new_db->parent_dir_baton = pb;
+	new_db->path = full_path;
+	new_db->cmp_path = cmp_path ? apr_pstrdup(pool, cmp_path) : NULL;
+	new_db->cmp_rev = cmp_rev;
+	new_db->added = added;
+	new_db->written_out = FALSE;
+	new_db->deleted_entries = apr_hash_make(pool);
+	new_db->pool = pool;
+
+	return new_db;
+}
+
+/*
+ * Write out a node record for PATH of type KIND under EB->FS_ROOT.
+ * ACTION describes what is happening to the node (see enum svn_node_action).
+ * Write record to writable EB->STREAM, using EB->BUFFER to write in chunks.
+ *
+ * If the node was itself copied, IS_COPY is TRUE and the
+ * path/revision of the copy source are in CMP_PATH/CMP_REV.  If
+ * IS_COPY is FALSE, yet CMP_PATH/CMP_REV are valid, this node is part
+ * of a copied subtree.
+ */
+static svn_error_t *dump_node(struct dump_edit_baton *eb,
+			      const char *path,    /* an absolute path. */
+			      svn_node_kind_t kind,
+			      enum svn_node_action action,
+			      const char *cmp_path,
+			      svn_revnum_t cmp_rev,
+			      apr_pool_t *pool)
+{
+	/* Write out metadata headers for this file node. */
+	SVN_ERR(svn_stream_printf(eb->stream, pool,
+				  SVN_REPOS_DUMPFILE_NODE_PATH ": %s\n",
+				  (*path == '/') ? path + 1 : path));
+
+	if (kind == svn_node_file)
+		SVN_ERR(svn_stream_printf(eb->stream, pool,
+		                          SVN_REPOS_DUMPFILE_NODE_KIND ": file\n"));
+	else if (kind == svn_node_dir)
+		SVN_ERR(svn_stream_printf(eb->stream, pool,
+		                          SVN_REPOS_DUMPFILE_NODE_KIND ": dir\n"));
+
+	/* Remove leading slashes from copyfrom paths. */
+	if (cmp_path)
+		cmp_path = ((*cmp_path == '/') ? cmp_path + 1 : cmp_path);
+
+	switch (action) {
+		/* Appropriately handle the four svn_node_action actions */
+
+	case svn_node_action_change:
+		SVN_ERR(svn_stream_printf(eb->stream, pool,
+		                          SVN_REPOS_DUMPFILE_NODE_ACTION
+		                          ": change\n"));
+		break;
+
+	case svn_node_action_replace:
+		if (!eb->is_copy) {
+			/* a simple delete+add, implied by a single 'replace' action. */
+			SVN_ERR(svn_stream_printf(eb->stream, pool,
+			                          SVN_REPOS_DUMPFILE_NODE_ACTION
+			                          ": replace\n"));
+
+			eb->dump_props_pending = TRUE;
+			break;
+		}
+		/* More complex case: eb->is_copy is true, and
+		   cmp_path/ cmp_rev are present: delete the original,
+		   and then re-add it */
+
+		/* the path & kind headers have already been printed;  just
+		   add a delete action, and end the current record.*/
+		SVN_ERR(svn_stream_printf(eb->stream, pool,
+		                          SVN_REPOS_DUMPFILE_NODE_ACTION
+		                          ": delete\n\n"));
+
+		/* recurse:  print an additional add-with-history record. */
+		SVN_ERR(dump_node(eb, path, kind, svn_node_action_add,
+		                  cmp_path, cmp_rev, pool));
+
+		/* we can leave this routine quietly now, don't need to dump
+		   any content;  that was already done in the second record. */
+		eb->must_dump_props = FALSE;
+		eb->is_copy = FALSE;
+		break;
+
+	case svn_node_action_delete:
+		SVN_ERR(svn_stream_printf(eb->stream, pool,
+		                          SVN_REPOS_DUMPFILE_NODE_ACTION
+		                          ": delete\n"));
+
+		/* we can leave this routine quietly now, don't need to dump
+		   any content. */
+		SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n"));
+		eb->must_dump_props = FALSE;
+		break;
+
+	case svn_node_action_add:
+		SVN_ERR(svn_stream_printf(eb->stream, pool,
+		                          SVN_REPOS_DUMPFILE_NODE_ACTION ": add\n"));
+
+		if (!eb->is_copy) {
+			/* eb->dump_props_pending for files is handled in
+			   close_file which is called immediately.
+			   However, directories are not closed until
+			   all the work inside them have been done;
+			   eb->dump_props_pending for directories is
+			   handled in all the functions that can
+			   possibly be called after add_directory:
+			   add_directory, open_directory,
+			   delete_entry, close_directory, add_file,
+			   open_file and change_dir_prop;
+			   change_dir_prop is a special case
+			   ofcourse */
+
+			eb->dump_props_pending = TRUE;
+			break;
+		}
+
+		SVN_ERR(svn_stream_printf(eb->stream, pool,
+		                          SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV
+		                          ": %ld\n"
+		                          SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH
+		                          ": %s\n",
+		                          cmp_rev, cmp_path));
+
+		/* Dump the text only if apply_textdelta sets
+		   eb->must_dump_text */
+
+		/* UGLY hack: If a directory was copied from a
+		   previous revision, nothing else can be done, and
+		   close_file won't be called to write two blank
+		   lines; write them here */
+		if (kind == svn_node_dir)
+			SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n"));
+
+		eb->is_copy = FALSE;
+
+		break;
+	}
+
+	/* Dump property headers */
+	SVN_ERR(dump_props(eb, &(eb->must_dump_props), FALSE, pool));
+
+	return SVN_NO_ERROR;
+}
+
 static svn_error_t *open_root(void *edit_baton,
 			      svn_revnum_t base_revision,
 			      apr_pool_t *pool,
 			      void **root_baton)
 {
-	*root_baton = NULL;
+	/* Allocate a special pool for the edit_baton to avoid pool
+	   lifetime issues */
+	struct dump_edit_baton *eb = edit_baton;
+	eb->pool = svn_pool_create(pool);
+	eb->properties = apr_hash_make(eb->pool);
+	eb->del_properties = apr_hash_make(eb->pool);
+	eb->propstring = svn_stringbuf_create("", eb->pool);
+	eb->is_copy = FALSE;
+
+	*root_baton = make_dir_baton(NULL, NULL, SVN_INVALID_REVNUM,
+	                             edit_baton, NULL, FALSE, pool);
 	return SVN_NO_ERROR;
 }
 
@@ -110,6 +311,10 @@ static svn_error_t *close_file(void *file_baton,
 
 static svn_error_t *close_edit(void *edit_baton, apr_pool_t *pool)
 {
+	struct dump_edit_baton *eb = edit_baton;
+	svn_pool_destroy(eb->pool);
+	(eb->current_rev) ++;
+
 	return SVN_NO_ERROR;
 }
 
diff --git a/dumpr_util.c b/dumpr_util.c
new file mode 100644
index 0000000..33dc74a
--- /dev/null
+++ b/dumpr_util.c
@@ -0,0 +1,112 @@
+/* Licensed under a two-clause BSD-style license.
+ * See LICENSE for details.
+ */
+
+#include "svn_pools.h"
+#include "svn_cmdline.h"
+#include "svn_client.h"
+#include "svn_ra.h"
+#include "svn_repos.h"
+
+#include "dumpr_util.h"
+
+void write_hash_to_stringbuf(apr_hash_t *properties,
+			     svn_boolean_t deleted,
+			     svn_stringbuf_t **strbuf,
+			     apr_pool_t *pool)
+{
+	apr_hash_index_t *this;
+	const void *key;
+	void *val;
+	apr_ssize_t keylen;
+	svn_string_t *value;
+
+	if (!deleted) {
+		for (this = apr_hash_first(pool, properties); this;
+		     this = apr_hash_next(this)) {
+			/* Get this key and val. */
+			apr_hash_this(this, &key, &keylen, &val);
+			value = val;
+
+			/* Output name length, then name. */
+			svn_stringbuf_appendcstr(*strbuf,
+						 apr_psprintf(pool, "K %" APR_SSIZE_T_FMT "\n",
+							      keylen));
+
+			svn_stringbuf_appendbytes(*strbuf, (const char *) key, keylen);
+			svn_stringbuf_appendbytes(*strbuf, "\n", 1);
+
+			/* Output value length, then value. */
+			svn_stringbuf_appendcstr(*strbuf,
+						 apr_psprintf(pool, "V %" APR_SIZE_T_FMT "\n",
+							      value->len));
+
+			svn_stringbuf_appendbytes(*strbuf, value->data, value->len);
+			svn_stringbuf_appendbytes(*strbuf, "\n", 1);
+		}
+	}
+	else {
+		/* Output a "D " entry for each deleted property */
+		for (this = apr_hash_first(pool, properties); this;
+		     this = apr_hash_next(this)) {
+			/* Get this key */
+			apr_hash_this(this, &key, &keylen, NULL);
+
+			/* Output name length, then name */
+			svn_stringbuf_appendcstr(*strbuf,
+						 apr_psprintf(pool, "D %" APR_SSIZE_T_FMT "\n",
+							      keylen));
+
+			svn_stringbuf_appendbytes(*strbuf, (const char *) key, keylen);
+			svn_stringbuf_appendbytes(*strbuf, "\n", 1);
+		}
+	}
+}
+
+svn_error_t *dump_props(struct dump_edit_baton *eb,
+			svn_boolean_t *trigger_var,
+			svn_boolean_t dump_data_too,
+			apr_pool_t *pool)
+{
+	if (trigger_var && !*trigger_var)
+		return SVN_NO_ERROR;
+
+	/* Build a propstring to print */
+	svn_stringbuf_setempty(eb->propstring);
+	write_hash_to_stringbuf(eb->properties,
+				FALSE,
+				&(eb->propstring), eb->pool);
+	write_hash_to_stringbuf(eb->del_properties,
+				TRUE,
+				&(eb->propstring), eb->pool);
+	svn_stringbuf_appendbytes(eb->propstring, "PROPS-END\n", 10);
+
+	/* prop-delta header */
+	SVN_ERR(svn_stream_printf(eb->stream, pool,
+				  SVN_REPOS_DUMPFILE_PROP_DELTA
+				  ": true\n"));
+
+	/* prop-content-length header */
+	SVN_ERR(svn_stream_printf(eb->stream, pool,
+				  SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
+				  ": %" APR_SIZE_T_FMT "\n", eb->propstring->len));
+
+	if (dump_data_too) {
+		/* content-length header */
+		SVN_ERR(svn_stream_printf(eb->stream, pool,
+					  SVN_REPOS_DUMPFILE_CONTENT_LENGTH
+					  ": %" APR_SIZE_T_FMT "\n\n",
+					  eb->propstring->len));
+
+		/* the properties themselves */
+		SVN_ERR(svn_stream_write(eb->stream, eb->propstring->data,
+					 &(eb->propstring->len)));
+
+		/* Cleanup so that data is never dumped twice */
+		apr_hash_clear(eb->properties);
+		apr_hash_clear(eb->del_properties);
+		if (trigger_var)
+			*trigger_var = FALSE;
+	}
+	return SVN_NO_ERROR;
+}
diff --git a/dumpr_util.h b/dumpr_util.h
index 8f494c1..4b0d5b0 100644
--- a/dumpr_util.h
+++ b/dumpr_util.h
@@ -9,6 +9,69 @@ struct replay_baton {
 struct dump_edit_baton {
 	svn_stream_t *stream;
 	svn_revnum_t current_rev;
+
+	/* pool is for per-edit-session allocations */
+	apr_pool_t *pool;
+
+	/* Store the properties that changed */
+	apr_hash_t *properties;
+	apr_hash_t *del_properties; /* Value is always 0x1 */
+	svn_stringbuf_t *propstring;
+
+	/* Was a copy command issued? */
+	svn_boolean_t is_copy;
+
+	/* Path of changed file */
+	const char *changed_path;
+
+	/* Temporary file to write delta to along with its checksum */
+	char *temp_filepath;
+	svn_checksum_t *checksum;
+
+	/* Flags to trigger dumping props and text */
+	svn_boolean_t must_dump_props;
+	svn_boolean_t must_dump_text;
+	svn_boolean_t dump_props_pending;
+};
+
+struct dir_baton {
+	struct dump_edit_baton *eb;
+	struct dir_baton *parent_dir_baton;
+
+	/* is this directory a new addition to this revision? */
+	svn_boolean_t added;
+
+	/* has this directory been written to the output stream? */
+	svn_boolean_t written_out;
+
+	/* the absolute path to this directory */
+	const char *path;
+
+	/* the comparison path and revision of this directory.  if both of
+	   these are valid, use them as a source against which to compare
+	   the directory instead of the default comparison source of PATH in
+	   the previous revision. */
+	const char *cmp_path;
+	svn_revnum_t cmp_rev;
+
+	/* hash of paths that need to be deleted, though some -might- be
+	   replaced.  maps const char * paths to this dir_baton.  (they're
+	   full paths, because that's what the editor driver gives us.  but
+	   really, they're all within this directory.) */
+	apr_hash_t *deleted_entries;
+
+	/* pool to be used for deleting the hash items */
+	apr_pool_t *pool;
 };
 
+void write_hash_to_stringbuf(apr_hash_t *properties,
+			     svn_boolean_t deleted,
+			     svn_stringbuf_t **strbuf,
+			     apr_pool_t *pool);
+
+svn_error_t *dump_props(struct dump_edit_baton *eb,
+			svn_boolean_t *trigger_var,
+			svn_boolean_t dump_data_too,
+			apr_pool_t *pool);
+
 #endif
diff --git a/svnrdump.c b/svnrdump.c
index e184fee..d7c1eea 100644
--- a/svnrdump.c
+++ b/svnrdump.c
@@ -25,6 +25,39 @@ static svn_error_t *replay_revstart(svn_revnum_t revision,
                                     apr_hash_t *rev_props,
                                     apr_pool_t *pool)
 {
+	/* Editing this revision has just started; dump the revprops
+	   before invoking the editor callbacks */
+	svn_stringbuf_t *propstring = svn_stringbuf_create("", pool);
+	svn_stream_t *stdout_stream;
+
+	/* Create an stdout stream */
+	svn_stream_for_stdout(&stdout_stream, pool);
+
+        /* Print revision number and prepare the propstring */
+	SVN_ERR(svn_stream_printf(stdout_stream, pool,
+				  SVN_REPOS_DUMPFILE_REVISION_NUMBER
+				  ": %ld\n", revision));
+	write_hash_to_stringbuf(rev_props, FALSE, &propstring, pool);
+	svn_stringbuf_appendbytes(propstring, "PROPS-END\n", 10);
+
+	/* prop-content-length header */
+	SVN_ERR(svn_stream_printf(stdout_stream, pool,
+				  SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
+				  ": %" APR_SIZE_T_FMT "\n", propstring->len));
+
+	/* content-length header */
+	SVN_ERR(svn_stream_printf(stdout_stream, pool,
+				  SVN_REPOS_DUMPFILE_CONTENT_LENGTH
+				  ": %" APR_SIZE_T_FMT "\n\n", propstring->len));
+
+	/* Print the revprops now */
+	SVN_ERR(svn_stream_write(stdout_stream, propstring->data,
+				 &(propstring->len)));
+
+	svn_stream_close(stdout_stream);
+
+	/* Extract editor and editor_baton from the replay_baton and
+	   set them so that the editor callbacks can use them */
 	struct replay_baton *rb = replay_baton;
 	*editor = rb->editor;
 	*edit_baton = rb->edit_baton;
@@ -39,6 +72,9 @@ static svn_error_t *replay_revend(svn_revnum_t revision,
                                   apr_hash_t *rev_props,
                                   apr_pool_t *pool)
 {
+	/* Editor has finished for this revision and close_edit has
+	   been called; do nothing: just continue to the next
+	   revision */
 	return SVN_NO_ERROR;
 }
 
@@ -73,8 +109,8 @@ static svn_error_t *replay_range(svn_revnum_t start_revision, svn_revnum_t end_r
 	                                    dump_baton, pool));
 
 	struct replay_baton *replay_baton = apr_palloc(pool, sizeof(struct replay_baton));
-	replay_baton->editor = debug_editor;
-	replay_baton->edit_baton = debug_baton;
+	replay_baton->editor = dump_editor;
+	replay_baton->edit_baton = dump_baton;
 	SVN_ERR(svn_cmdline_printf(pool, SVN_REPOS_DUMPFILE_MAGIC_HEADER ": %d\n",
 				   SVN_REPOS_DUMPFILE_FORMAT_VERSION));
 	SVN_ERR(svn_ra_replay_range(session, start_revision, end_revision,
-- 
1.7.1

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

* [PATCH 6/9] Implement directory-related functions
  2010-07-13 23:36 [PATCH 0/9] Get svnrdump merged into git.git Ramkumar Ramachandra
                   ` (4 preceding siblings ...)
  2010-07-13 23:36 ` [PATCH 5/9] Dump the revprops at the start of every revision Ramkumar Ramachandra
@ 2010-07-13 23:36 ` Ramkumar Ramachandra
  2010-07-13 23:36 ` [PATCH 7/9] Implement file-related functions Ramkumar Ramachandra
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 26+ messages in thread
From: Ramkumar Ramachandra @ 2010-07-13 23:36 UTC (permalink / raw)
  To: Git Mailing List
  Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier, avarab,
	Daniel Shahaf, Bert Huijben, Junio C Hamano, Eric Wong,
	Will Palmer, Greg Stein

Implement open_directory, add_directory, change_dir_prop and
close_directory. All of them involve adding and removing entries from
the directory_baton and dumping the related node information. Note
that open_directory doesn't need any corresponding node information to
be printed.

Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
 dump_editor.c |  112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 110 insertions(+), 2 deletions(-)

diff --git a/dump_editor.c b/dump_editor.c
index 0506966..7fafa8b 100644
--- a/dump_editor.c
+++ b/dump_editor.c
@@ -225,6 +225,15 @@ static svn_error_t *delete_entry(const char *path,
 				 void *parent_baton,
 				 apr_pool_t *pool)
 {
+	struct dir_baton *pb = parent_baton;
+	const char *mypath = apr_pstrdup(pb->pool, path);
+
+	/* Some pending properties to dump? */
+	SVN_ERR(dump_props(pb->eb, &(pb->eb->dump_props_pending), TRUE, pool));
+
+	/* remember this path needs to be deleted */
+	apr_hash_set(pb->deleted_entries, mypath, APR_HASH_KEY_STRING, pb);
+
 	return SVN_NO_ERROR;
 }
 
@@ -235,7 +244,35 @@ static svn_error_t *add_directory(const char *path,
 				  apr_pool_t *pool,
 				  void **child_baton)
 {
-	*child_baton = NULL;
+	struct dir_baton *pb = parent_baton;
+	void *val;
+	struct dir_baton *new_db
+		= make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb, pb, TRUE, pool);
+
+	/* Some pending properties to dump? */
+	SVN_ERR(dump_props(pb->eb, &(pb->eb->dump_props_pending), TRUE, pool));
+
+	/* This might be a replacement -- is the path already deleted? */
+	val = apr_hash_get(pb->deleted_entries, path, APR_HASH_KEY_STRING);
+
+	/* Detect an add-with-history */
+	pb->eb->is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
+
+	/* Dump the node */
+	SVN_ERR(dump_node(pb->eb, path,
+	                  svn_node_dir,
+	                  val ? svn_node_action_replace : svn_node_action_add,
+	                  pb->eb->is_copy ? copyfrom_path : NULL,
+	                  pb->eb->is_copy ? copyfrom_rev : SVN_INVALID_REVNUM,
+	                  pool));
+
+	if (val)
+		/* Delete the path, it's now been dumped */
+		apr_hash_set(pb->deleted_entries, path, APR_HASH_KEY_STRING, NULL);
+
+	new_db->written_out = TRUE;
+
+	*child_baton = new_db;
 	return SVN_NO_ERROR;
 }
 
@@ -245,13 +282,56 @@ static svn_error_t *open_directory(const char *path,
 				   apr_pool_t *pool,
 				   void **child_baton)
 {
-	*child_baton = NULL;
+	struct dir_baton *pb = parent_baton;
+	struct dir_baton *new_db;
+	const char *cmp_path = NULL;
+	svn_revnum_t cmp_rev = SVN_INVALID_REVNUM;
+	apr_array_header_t *compose_path = apr_array_make(pool, 2, sizeof(const char *));
+
+	/* Some pending properties to dump? */
+	SVN_ERR(dump_props(pb->eb, &(pb->eb->dump_props_pending), TRUE, pool));
+
+	/* If the parent directory has explicit comparison path and rev,
+	   record the same for this one. */
+	if (pb && ARE_VALID_COPY_ARGS(pb->cmp_path, pb->cmp_rev)) {
+		APR_ARRAY_PUSH(compose_path, const char *) = pb->cmp_path;
+		APR_ARRAY_PUSH(compose_path, const char *) = svn_relpath_basename(path, pool);
+		cmp_path = svn_path_compose(compose_path, pool);
+		cmp_rev = pb->cmp_rev;
+	}
+
+	new_db = make_dir_baton(path, cmp_path, cmp_rev, pb->eb, pb, FALSE, pool);
+	*child_baton = new_db;
 	return SVN_NO_ERROR;
 }
 
 static svn_error_t *close_directory(void *dir_baton,
 				    apr_pool_t *pool)
 {
+	struct dir_baton *db = dir_baton;
+	struct dump_edit_baton *eb = db->eb;
+	apr_hash_index_t *hi;
+	apr_pool_t *subpool = svn_pool_create(pool);
+
+	/* Some pending properties to dump? */
+	SVN_ERR(dump_props(eb, &(eb->dump_props_pending), TRUE, pool));
+
+	/* Dump the directory entries */
+	for (hi = apr_hash_first(pool, db->deleted_entries); hi;
+	     hi = apr_hash_next(hi)) {
+		const void *key;
+		const char *path;
+		apr_hash_this(hi, &key, NULL, NULL);
+		path = key;
+
+		svn_pool_clear(subpool);
+
+		SVN_ERR(dump_node(db->eb, path,
+		                  svn_node_unknown, svn_node_action_delete,
+		                  NULL, SVN_INVALID_REVNUM, subpool));
+	}
+
+	svn_pool_destroy(subpool);
 	return SVN_NO_ERROR;
 }
 
@@ -281,6 +361,34 @@ static svn_error_t *change_dir_prop(void *parent_baton,
 				    const svn_string_t *value,
 				    apr_pool_t *pool)
 {
+	struct dir_baton *db = parent_baton;
+
+	if (svn_property_kind(NULL, name) != svn_prop_regular_kind)
+		return SVN_NO_ERROR;
+
+	value ? apr_hash_set(db->eb->properties, apr_pstrdup(pool, name),
+	                     APR_HASH_KEY_STRING, svn_string_dup(value, pool)) :
+		apr_hash_set(db->eb->del_properties, apr_pstrdup(pool, name),
+		             APR_HASH_KEY_STRING, (void *)0x1);
+
+	/* This function is what distinguishes between a directory that is
+	   opened to merely get somewhere, vs. one that is opened because it
+	   actually changed by itself  */
+	if (! db->written_out) {
+		/* If eb->dump_props_pending was set, it means that the
+		   node information corresponding to add_directory has already
+		   been written; just don't unset it and dump_node will dump
+		   the properties before doing anything else. If it wasn't
+		   set, node information hasn't been written yet: so dump the
+		   node itself before dumping the props */
+
+		SVN_ERR(dump_node(db->eb, db->path,
+		                  svn_node_dir, svn_node_action_change,
+		                  db->cmp_path, db->cmp_rev, pool));
+
+		SVN_ERR(dump_props(db->eb, NULL, TRUE, pool));
+		db->written_out = TRUE;
+	}
 	return SVN_NO_ERROR;
 }
 
-- 
1.7.1

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

* [PATCH 7/9] Implement file-related functions
  2010-07-13 23:36 [PATCH 0/9] Get svnrdump merged into git.git Ramkumar Ramachandra
                   ` (5 preceding siblings ...)
  2010-07-13 23:36 ` [PATCH 6/9] Implement directory-related functions Ramkumar Ramachandra
@ 2010-07-13 23:36 ` Ramkumar Ramachandra
  2010-07-13 23:36 ` [PATCH 8/9] Implement close_file Ramkumar Ramachandra
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 26+ messages in thread
From: Ramkumar Ramachandra @ 2010-07-13 23:36 UTC (permalink / raw)
  To: Git Mailing List
  Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier, avarab,
	Daniel Shahaf, Bert Huijben, Junio C Hamano, Eric Wong,
	Will Palmer, Greg Stein

Implement add_file, open_file and change_file_prop. All of them
involve dumping the corresponding node information and setting up the
file_baton for apply_textdelta and close_file to use.

Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
 dump_editor.c |  127 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 dumpr_util.h  |   15 +++++++
 2 files changed, 138 insertions(+), 4 deletions(-)

diff --git a/dump_editor.c b/dump_editor.c
index 7fafa8b..8b0a830 100644
--- a/dump_editor.c
+++ b/dump_editor.c
@@ -342,7 +342,34 @@ static svn_error_t *add_file(const char *path,
 			     apr_pool_t *pool,
 			     void **file_baton)
 {
-	*file_baton = NULL;
+	struct dir_baton *pb = parent_baton;
+	void *val;
+
+	/* Some pending properties to dump? */
+	SVN_ERR(dump_props(pb->eb, &(pb->eb->dump_props_pending), TRUE, pool));
+
+	/* This might be a replacement -- is the path already deleted? */
+	val = apr_hash_get(pb->deleted_entries, path, APR_HASH_KEY_STRING);
+
+	/* Detect add-with-history. */
+	pb->eb->is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
+
+	/* Dump the node. */
+	SVN_ERR(dump_node(pb->eb, path,
+	                  svn_node_file,
+	                  val ? svn_node_action_replace : svn_node_action_add,
+	                  pb->eb->is_copy ? copyfrom_path : NULL,
+	                  pb->eb->is_copy ? copyfrom_rev : SVN_INVALID_REVNUM,
+	                  pool));
+
+	if (val)
+		/* delete the path, it's now been dumped. */
+		apr_hash_set(pb->deleted_entries, path, APR_HASH_KEY_STRING, NULL);
+
+	/* Build a nice file baton to pass to change_file_prop and apply_textdelta */
+	pb->eb->changed_path = path;
+	*file_baton = pb->eb;
+
 	return SVN_NO_ERROR;
 }
 
@@ -352,7 +379,31 @@ static svn_error_t *open_file(const char *path,
 			      apr_pool_t *pool,
 			      void **file_baton)
 {
-	*file_baton = NULL;
+	struct dir_baton *pb = parent_baton;
+	const char *cmp_path = NULL;
+	svn_revnum_t cmp_rev = SVN_INVALID_REVNUM;
+
+	/* Some pending properties to dump? */
+	SVN_ERR(dump_props(pb->eb, &(pb->eb->dump_props_pending), TRUE, pool));
+
+	apr_array_header_t *compose_path = apr_array_make(pool, 2, sizeof(const char *));
+	/* If the parent directory has explicit comparison path and rev,
+	   record the same for this one. */
+	if (pb && ARE_VALID_COPY_ARGS(pb->cmp_path, pb->cmp_rev)) {
+		APR_ARRAY_PUSH(compose_path, const char *) = pb->cmp_path;
+		APR_ARRAY_PUSH(compose_path, const char *) = svn_relpath_basename(path, pool);
+		cmp_path = svn_path_compose(compose_path, pool);
+		cmp_rev = pb->cmp_rev;
+	}
+
+	SVN_ERR(dump_node(pb->eb, path,
+	                  svn_node_file, svn_node_action_change,
+	                  cmp_path, cmp_rev, pool));
+
+	/* Build a nice file baton to pass to change_file_prop and apply_textdelta */
+	pb->eb->changed_path = path;
+	*file_baton = pb->eb;
+
 	return SVN_NO_ERROR;
 }
 
@@ -397,6 +448,44 @@ static svn_error_t *change_file_prop(void *file_baton,
 				     const svn_string_t *value,
 				     apr_pool_t *pool)
 {
+	struct dump_edit_baton *eb = file_baton;
+
+	if (svn_property_kind(NULL, name) != svn_prop_regular_kind)
+		return SVN_NO_ERROR;
+
+	apr_hash_set(eb->properties, apr_pstrdup(pool, name),
+		     APR_HASH_KEY_STRING, value ?
+		     svn_string_dup(value, pool): (void *)0x1);
+
+	/* Dump the property headers and wait; close_file might need
+	   to write text headers too depending on whether
+	   apply_textdelta is called */
+	eb->dump_props_pending = TRUE;
+
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t *window_handler(svn_txdelta_window_t *window, void *baton)
+{
+	struct handler_baton *hb = baton;
+	struct dump_edit_baton *eb = hb->eb;
+	static svn_error_t *err;
+
+	err = hb->apply_handler(window, hb->apply_baton);
+	if (window != NULL && !err)
+		return SVN_NO_ERROR;
+
+	if (err)
+		SVN_ERR(err);
+
+	/* Write information about the filepath to hb->eb */
+	eb->temp_filepath = apr_pstrdup(eb->pool,
+					hb->temp_filepath);
+
+	/* Cleanup */
+	SVN_ERR(svn_io_file_close(hb->temp_file, hb->pool));
+	SVN_ERR(svn_stream_close(hb->temp_filestream));
+	svn_pool_destroy(hb->pool);
 	return SVN_NO_ERROR;
 }
 
@@ -405,8 +494,38 @@ static svn_error_t *apply_textdelta(void *file_baton, const char *base_checksum,
 				    svn_txdelta_window_handler_t *handler,
 				    void **handler_baton)
 {
-	*handler = svn_delta_noop_window_handler;
-	*handler_baton = NULL;
+	struct dump_edit_baton *eb = file_baton;
+	apr_status_t apr_err;
+	const char *tempdir;
+
+	/* Custom handler_baton allocated in a separate pool */
+	apr_pool_t *handler_pool = svn_pool_create(pool);
+	struct handler_baton *hb = apr_pcalloc(handler_pool, sizeof(*hb));
+	hb->pool = handler_pool;
+	hb->eb = eb;
+
+	/* Use a temporary file to measure the text-content-length */
+	SVN_ERR(svn_io_temp_dir(&tempdir, hb->pool));
+
+	hb->temp_filepath = svn_dirent_join(tempdir, "XXXXXX", hb->pool);
+	apr_err = apr_file_mktemp(&(hb->temp_file), hb->temp_filepath,
+				  APR_CREATE | APR_READ | APR_WRITE | APR_EXCL,
+				  hb->pool);
+	if (apr_err != APR_SUCCESS)
+		SVN_ERR(svn_error_wrap_apr(apr_err, NULL));
+
+	hb->temp_filestream = svn_stream_from_aprfile2(hb->temp_file, TRUE, hb->pool);
+
+	/* Prepare to write the delta to the temporary file */
+	svn_txdelta_to_svndiff2(&(hb->apply_handler), &(hb->apply_baton),
+	                        hb->temp_filestream, 0, hb->pool);
+	eb->must_dump_text = TRUE;
+
+	/* The actual writing takes place when this function has finished */
+	/* Set the handler and handler_baton */
+	*handler = window_handler;
+	*handler_baton = hb;
+
 	return SVN_NO_ERROR;
 }
 
diff --git a/dumpr_util.h b/dumpr_util.h
index 4b0d5b0..9870b0d 100644
--- a/dumpr_util.h
+++ b/dumpr_util.h
@@ -64,6 +64,21 @@ struct dir_baton {
 	apr_pool_t *pool;
 };
 
+struct handler_baton
+{
+	svn_txdelta_window_handler_t apply_handler;
+	void *apply_baton;
+	apr_pool_t *pool;
+
+	/* Information about the path of the tempoarary file used */
+	char *temp_filepath;
+	apr_file_t *temp_file;
+	svn_stream_t *temp_filestream;
+
+	/* To fill in the edit baton fields */
+	struct dump_edit_baton *eb;
+};
+
 void write_hash_to_stringbuf(apr_hash_t *properties,
 			     svn_boolean_t deleted,
 			     svn_stringbuf_t **strbuf,
-- 
1.7.1

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

* [PATCH 8/9] Implement close_file
  2010-07-13 23:36 [PATCH 0/9] Get svnrdump merged into git.git Ramkumar Ramachandra
                   ` (6 preceding siblings ...)
  2010-07-13 23:36 ` [PATCH 7/9] Implement file-related functions Ramkumar Ramachandra
@ 2010-07-13 23:36 ` Ramkumar Ramachandra
  2010-07-13 23:36 ` [PATCH 9/9] Add a validation script Ramkumar Ramachandra
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 26+ messages in thread
From: Ramkumar Ramachandra @ 2010-07-13 23:36 UTC (permalink / raw)
  To: Git Mailing List
  Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier, avarab,
	Daniel Shahaf, Bert Huijben, Junio C Hamano, Eric Wong,
	Will Palmer, Greg Stein

close_file measures the length of the temporary file to write text
headers and full text before cleaning up the temporary file. It also
writes props and prop deltas if necessary.

Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
 dump_editor.c |   76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 76 insertions(+), 0 deletions(-)

diff --git a/dump_editor.c b/dump_editor.c
index 8b0a830..b2fd3d6 100644
--- a/dump_editor.c
+++ b/dump_editor.c
@@ -533,7 +533,82 @@ static svn_error_t *close_file(void *file_baton,
 			       const char *text_checksum,
 			       apr_pool_t *pool)
 {
+	struct dump_edit_baton *eb = file_baton;
+	apr_file_t *temp_file;
+	svn_stream_t *temp_filestream;
+	apr_finfo_t *info = apr_pcalloc(pool, sizeof(apr_finfo_t));
+
+	/* We didn't write the property headers because we were
+	   waiting for file_prop_change; write them now */
+	SVN_ERR(dump_props(eb, &(eb->dump_props_pending), FALSE, pool));
+
+	/* The prop headers have already been dumped in dump_node */
+	/* Dump the text headers */
+	if (eb->must_dump_text) {
+		/* text-delta header */
+		SVN_ERR(svn_stream_printf(eb->stream, pool,
+					  SVN_REPOS_DUMPFILE_TEXT_DELTA
+					  ": true\n"));
+
+		/* Measure the length */
+		SVN_ERR(svn_io_stat(info, eb->temp_filepath, APR_FINFO_SIZE, pool));
+
+		/* text-content-length header */
+		SVN_ERR(svn_stream_printf(eb->stream, pool,
+					  SVN_REPOS_DUMPFILE_TEXT_CONTENT_LENGTH
+					  ": %lu\n",
+					  (unsigned long)info->size));
+		/* text-content-md5 header */
+		SVN_ERR(svn_stream_printf(eb->stream, pool,
+					  SVN_REPOS_DUMPFILE_TEXT_CONTENT_MD5
+					  ": %s\n",
+					  text_checksum));
+	}
+
+	/* content-length header: if both text and props are absent,
+	   skip this block */
+	if (eb->must_dump_props || eb->dump_props_pending)
+		SVN_ERR(svn_stream_printf(eb->stream, pool,
+					  SVN_REPOS_DUMPFILE_CONTENT_LENGTH
+					  ": %ld\n\n",
+					  (unsigned long)info->size + eb->propstring->len));
+	else if (eb->must_dump_text)
+		SVN_ERR(svn_stream_printf(eb->stream, pool,
+					  SVN_REPOS_DUMPFILE_CONTENT_LENGTH
+					  ": %ld\n\n",
+					  (unsigned long)info->size));
+
+	/* Dump the props; the propstring should have already been
+	   written in dump_node or above */
+	if (eb->must_dump_props || eb->dump_props_pending) {
+		SVN_ERR(svn_stream_write(eb->stream, eb->propstring->data,
+					 &(eb->propstring->len)));
+
+		/* Cleanup */
+		eb->must_dump_props = eb->dump_props_pending = FALSE;
+		apr_hash_clear(eb->properties);
+		apr_hash_clear(eb->del_properties);
+	}
+
+	/* Dump the text */
+	if (eb->must_dump_text) {
+
+		/* Open the temporary file, map it to a stream, copy
+		   the stream to eb->stream, close and delete the
+		   file */
+		SVN_ERR(svn_io_file_open(&temp_file, eb->temp_filepath, APR_READ, 0600, pool));
+		temp_filestream = svn_stream_from_aprfile2(temp_file, TRUE, pool);
+		SVN_ERR(svn_stream_copy3(temp_filestream, eb->stream, NULL, NULL, pool));
+
+		/* Cleanup */
+		SVN_ERR(svn_io_file_close(temp_file, pool));
+		SVN_ERR(svn_stream_close(temp_filestream));
+		SVN_ERR(svn_io_remove_file2(eb->temp_filepath, TRUE, pool));
+		eb->must_dump_text = FALSE;
+	}
+
+	SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n"));
+
 	return SVN_NO_ERROR;
 }
 
-- 
1.7.1

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

* [PATCH 9/9] Add a validation script
  2010-07-13 23:36 [PATCH 0/9] Get svnrdump merged into git.git Ramkumar Ramachandra
                   ` (7 preceding siblings ...)
  2010-07-13 23:36 ` [PATCH 8/9] Implement close_file Ramkumar Ramachandra
@ 2010-07-13 23:36 ` Ramkumar Ramachandra
  2010-07-13 23:58 ` [PATCH 0/9] Get svnrdump merged into git.git Ramkumar Ramachandra
  2010-07-14 14:54 ` Junio C Hamano
  10 siblings, 0 replies; 26+ messages in thread
From: Ramkumar Ramachandra @ 2010-07-13 23:36 UTC (permalink / raw)
  To: Git Mailing List
  Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier, avarab,
	Daniel Shahaf, Bert Huijben, Junio C Hamano, Eric Wong,
	Will Palmer, Greg Stein

From: Will Palmer <wpalmer@gmail.com>

Add a validation script. Using an existing dump known to be correct
(possibly generated using `svnsync` and `svnadmin dump --deltas`), it
compares the outputs produced by `svnadmin load` when fed with this
dump and the dump from the program.

The arguments added are:
    --svnadmin-dump=<file>      existing "svnadmin dump"
    --svndumpr-dump=<file>      existing "svndumpr" dump
    --repos=<url-or-path>       SVN repos URL, or local repos
    -r<revision>                end revision to dump/cut
    --ignore-existing           regenerate svnadmin-dump even if
                                it already exists
    --make                      run "make svndumpr" prior to svnrdump
    generate                    as with the old parameter, but now
                                implied by default
    validate                    as with the old parameter, but now
                                implied by default

The end result is that the only step technically needed to test
validation is:

./validate.sh --make --repos=/path/to/local/repos

Signed-off-by: Will Palmer <wpalmer@gmail.com>
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
 validate.sh |  226 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 226 insertions(+), 0 deletions(-)
 create mode 100755 validate.sh

diff --git a/validate.sh b/validate.sh
new file mode 100755
index 0000000..6bdb427
--- /dev/null
+++ b/validate.sh
@@ -0,0 +1,226 @@
+#!/bin/sh
+usage(){
+	sed 's/..//' <<USAGE
+		Usage: validate.sh [--svnadmin-dump=<file>] [--svnrdump-dump=<file>]
+		                   [--repos=<url-or-path>] [-r<revision>]
+		                   [--ignore-existing-dump] [--make]
+		                   [generate] [validate]
+USAGE
+}
+
+svnadmin_dump=
+svnrdump_dump=
+repos_url=
+repos_path=
+end_rev=
+do_make=
+do_both=1
+do_generate=1
+do_validate=1
+do_ignore_existing_svnadmin_dump=
+while test "$#" -gt 0; do
+	case "$1" in
+	--svnadmin-dump=*)
+		svnadmin_dump="${1#*=}"
+		;;
+	--svnrdump-dump=*)
+		svnrdump_dump="${1#*=}"
+		;;
+	--ignore-existing|--ignore-existing-dump)
+		do_ignore_existing_svnadmin_dump=1
+		;;
+	--repos=*)
+		repos_url="${1#*=}"
+		repos_protocol="${repos_url%://*}"
+		repos_path="${repos_url#file://}"
+		if test "$repos_protocol" = "$repos_path"; then
+			repos_protocol=
+			repos_url=
+		elif test ! "$repos_protocol" = 'file'; then
+			repos_path=
+		fi
+		;;
+	-r*)
+		end_rev="${1#-r}"
+		;;
+	--make)
+		do_make=1
+		;;
+	generate)
+		do_generate=1
+		test -n "$do_both" && do_validate=
+		do_both=
+		;;
+	validate)
+		do_validate=1
+		test -n "$do_both" && do_generate=
+		do_both=
+		;;
+	-h|--help)
+		usage
+		exit
+		;;
+	*)
+		echo "unknown option $1" >&2
+		usage >&2
+		exit 1
+	esac
+	shift
+done
+
+if test -z "$svnrdump_dump"; then
+	if test -z "$repos_url"; then
+		if test -n "$repos_path"; then
+			repos_url="file://$(readlink -f "$repos_path")"
+			if test $? -ne 0; then
+				echo "error: unable to derive repos url from path" >&2
+				echo "--svnrdump_dump=<file> or a local (file://) --repos=<url> is required" >&2
+				exit 1
+			fi
+		else
+				echo "--svnrdump_dump=<file> or a local (file://) --repos=<url> is required" >&2
+				exit 1
+		fi
+	fi
+fi
+
+svnadmin_dump_cut="t/svnadmin-$end_rev.dump"
+svnrdump_dump_cut="t/svnrdump-$end_rev.dump"
+mkdir t 2>/dev/null
+
+if test -z "$svnadmin_dump"; then
+	if test -z "$repos_path"; then
+		echo "--svnadmin_dump=<file> or a local (file://) --repos=<url> is required" >&2
+		usage >&2
+		exit 1
+	fi
+
+	svnadmin_dump="$svnadmin_dump_cut"
+	if test -z "$do_ignore_existing_svnadmin_dump" && test -r "$svnadmin_dump"; then
+		echo "Using existing $svnadmin_dump"
+	else
+		echo "Generating $svnadmin_dump ..."
+
+		r=
+		if test -n "$end_rev"; then
+			r="-r0:$end_rev"
+		else
+			r="-r0:HEAD"
+		fi
+
+		svnadmin dump --deltas $r "$repos_path" > "$svnadmin_dump"
+		if test $? -ne 0; then
+			echo "error: failed to create canonical dump for comparison" >&2
+			exit 1
+		fi
+	fi
+else
+	echo "Using specified $svnadmin_dump"
+fi
+
+if test -z "$svnrdump_dump"; then
+	svnrdump_dump="$svnrdump_dump_cut"
+
+	if test -n "$do_make"; then
+		make svnrdump > /dev/null;
+		if test $? -ne 0; then
+			echo "error: Make failed. Check the program." >&2
+			exit 1;
+		fi
+	fi
+
+	echo "Generating $svnrdump_dump ..."
+
+	r=
+	test -n "$end_rev" && r="-r0:$end_rev"
+
+	./svnrdump -v $r "$repos_url" > "$svnrdump_dump"
+	if test $? -ne 0; then
+		echo "error: failed to create dump for validation" >&2
+		exit 1
+	fi
+else
+	echo "Using specified $svnrdump_dump"
+fi
+
+cut_dump(){
+	r="$1"
+	test -z "$r" && r=-1
+
+	gawk '
+		BEGIN {
+			max='"$r"'
+			hit_max=0
+		}
+		/^Revision-number: [0-9][0-9]*$/ {
+		rev=$2
+			if (rev == max) {
+				hit_max=1
+			} else if ( hit_max ) {
+				exit
+			}
+		}
+		{ print $0 }
+		END {
+			if (max == -1 || hit_max) {
+				exit 0
+			}
+			exit 1
+		}'
+}
+
+if test ! "$svnadmin_dump" = "$svnadmin_dump_cut"; then
+	cut_dump "$end_rev" <"$svnadmin_dump" >"$svnadmin_dump_cut"
+	if test $? -ne 0; then
+		echo "error: failed to cut canonical dump $svnadmin_dump for comparison" >&2
+		exit 1
+	fi
+	echo "Successfully generated cut canonical dump $svnadmin_dump_cut for comparison" >&2
+fi
+
+echo "Comparing canonical and svnrdump-based dumps..."
+diff -au "$svnadmin_dump_cut" "$svnrdump_dump" > t/dump-diff.error
+gawk \
+	'$0 !~ "Prop-delta: true|Text-delta-base-|sha1|Text-copy-source-|^-$" && $0 ~ "^+|^-" { print; }' \
+	t/dump-diff.error >t/dump-diff-filtered.error;
+
+if test -n "$do_generate"; then
+	echo "Generating canonical import logs..."
+
+	rm -rf t/repo;
+	mkdir t/repo;
+	svnadmin create t/repo;
+
+	svnadmin load t/repo < "$svnadmin_dump_cut" \
+	    1>"$svnadmin_dump_cut.import.log" 2>"$svnadmin_dump_cut.import.error";
+	if test $? -ne 0; then
+		echo "error: Load $end_rev failed. See $svnadmin_dump_cut.import.* for details" >&2
+		exit 1
+	fi
+	echo "Successfully generated canonical repository for comparison."
+fi
+
+if test -n "$do_validate"; then
+	echo "Generating svnrdump-based import logs..."
+
+	log_prefix=t/svnrdump-$end_rev
+
+	rm -rf t/repo;
+	mkdir t/repo;
+	svnadmin create t/repo;
+
+	svnadmin load t/repo < "$svnrdump_dump" 1>"$log_prefix.import.log" 2>"$log_prefix.import.error";
+	if test $? -ne 0; then
+		echo "error: Load $end_rev failed. See $log_prefix.import.* for details" >&2
+		exit 1
+	fi
+	echo "Successfully loaded svnrdump-based repository for validation"
+
+	echo "Comparing canonical and svnrdump-based import logs..."
+	diff -au "$svnadmin_dump_cut.import.log" "$log_prefix.import.log" > t/import-diff.error;
+	if test $? -ne 0; then
+		echo "Validation failed. See t/import-diff.error for details." >&2
+		exit 1
+	fi
+	echo "Validation successful"
+fi
-- 
1.7.1

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

* Re: [PATCH 0/9] Get svnrdump merged into git.git
  2010-07-13 23:36 [PATCH 0/9] Get svnrdump merged into git.git Ramkumar Ramachandra
                   ` (8 preceding siblings ...)
  2010-07-13 23:36 ` [PATCH 9/9] Add a validation script Ramkumar Ramachandra
@ 2010-07-13 23:58 ` Ramkumar Ramachandra
  2010-07-14  0:15   ` Jonathan Nieder
  2010-07-14 14:54 ` Junio C Hamano
  10 siblings, 1 reply; 26+ messages in thread
From: Ramkumar Ramachandra @ 2010-07-13 23:58 UTC (permalink / raw)
  To: Git Mailing List
  Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier, avarab,
	Daniel Shahaf, Bert Huijben, Junio C Hamano, Eric Wong,
	Will Palmer, Greg Stein

Hi,

Just to clarify again, I'm doing this roundabout dance because a lot
of other work in the git-remote-svn toolchain (svn-fe, a new dumpfile
parser I'm writing, and a future branch/ tag mapper that some people
are working on) is dependent on svnrdump; compiling the Subversion
trunk just for svnrdump is both inconvinient and non-trivial. It's
alright if the git.git version of svnrdump rots for a few months
(before a Subversion release includes it), as long as it works and
doesn't halt future work.

Thanks.

-- Ram

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

* Re: [PATCH 0/9] Get svnrdump merged into git.git
  2010-07-13 23:58 ` [PATCH 0/9] Get svnrdump merged into git.git Ramkumar Ramachandra
@ 2010-07-14  0:15   ` Jonathan Nieder
  2010-07-14  0:22     ` Ramkumar Ramachandra
  0 siblings, 1 reply; 26+ messages in thread
From: Jonathan Nieder @ 2010-07-14  0:15 UTC (permalink / raw)
  To: Ramkumar Ramachandra
  Cc: Git Mailing List, David Michael Barr, Sverre Rabbelier, avarab,
	Daniel Shahaf, Bert Huijben, Junio C Hamano, Eric Wong,
	Will Palmer, Greg Stein

Hi Ram,

Sorry I missed this message before.

Ramkumar Ramachandra wrote:

> It's
> alright if the git.git version of svnrdump rots for a few months
> (before a Subversion release includes it), as long as it works and
> doesn't halt future work.

To clarify: is that because of API differences between svn 1.6 and
trunk?

If we are including a convenience copy of files that are (soon to be)
in svn trunk, I don’t see much reason to diverge from the svn
version except for API differences and the overhead of updating too
frequently.

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

* Re: [PATCH 0/9] Get svnrdump merged into git.git
  2010-07-14  0:15   ` Jonathan Nieder
@ 2010-07-14  0:22     ` Ramkumar Ramachandra
  2010-07-14  0:28       ` Jonathan Nieder
  0 siblings, 1 reply; 26+ messages in thread
From: Ramkumar Ramachandra @ 2010-07-14  0:22 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Git Mailing List, David Michael Barr, Sverre Rabbelier, avarab,
	Daniel Shahaf, Bert Huijben, Junio C Hamano, Eric Wong,
	Will Palmer, Greg Stein

Hi Jonathan,

Jonathan Nieder writes:
> If we are including a convenience copy of files that are (soon to be)
> in svn trunk, I don’t see much reason to diverge from the svn
> version except for API differences and the overhead of updating too
> frequently.

Is licensing an issue? I won't be the copyright holder or the sole
contributor to svnrdump when it's in ASF. Can I just copy-paste from
there into the git.git tree?

-- Ram

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

* Re: [PATCH 0/9] Get svnrdump merged into git.git
  2010-07-14  0:22     ` Ramkumar Ramachandra
@ 2010-07-14  0:28       ` Jonathan Nieder
  2010-07-14  0:49         ` Ramkumar Ramachandra
  0 siblings, 1 reply; 26+ messages in thread
From: Jonathan Nieder @ 2010-07-14  0:28 UTC (permalink / raw)
  To: Ramkumar Ramachandra
  Cc: Git Mailing List, David Michael Barr, Sverre Rabbelier, avarab,
	Daniel Shahaf, Bert Huijben, Junio C Hamano, Eric Wong,
	Will Palmer, Greg Stein

Ramkumar Ramachandra wrote:

> Is licensing an issue? I won't be the copyright holder or the sole
> contributor to svnrdump when it's in ASF. Can I just copy-paste from
> there into the git.git tree?

As long as the relevant licenses permit that.  svnrdump only links to
libsvnclient, right?  So copy-pasting the code along with

 - a copy of the Apache license
 - prominent notices in any files that differ from the svn version
 - the notices from the Subversion NOTICE file

should be okay.

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

* Re: [PATCH 0/9] Get svnrdump merged into git.git
  2010-07-14  0:28       ` Jonathan Nieder
@ 2010-07-14  0:49         ` Ramkumar Ramachandra
  2010-07-14  7:03           ` Stefan Sperling
  0 siblings, 1 reply; 26+ messages in thread
From: Ramkumar Ramachandra @ 2010-07-14  0:49 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Git Mailing List, David Michael Barr, Sverre Rabbelier, avarab,
	Daniel Shahaf, Bert Huijben, Junio C Hamano, Eric Wong,
	Will Palmer, Greg Stein, Stefan Sperling

Hi,

Jonathan Nieder writes:
> As long as the relevant licenses permit that.  svnrdump only links to
> libsvnclient, right?

I can see another problem coming: things are likely to move around
quite a bit after the code gets into the ASF. For instance, Stefan's
recent review points out that write_hash_to_stringbuf should probably
be in a reusable library. If these changes happen soon, svnrdump will
be tightly integrated into Subversion, and it'll be hard to separate
out an independent program. Then again, we don't know how soon this
will happen.

If you get this series merged into git.git, Git people will be able to
read and review it easily and it'll be guaranteed to compile against
SVN 1.6. In other words, it won't be a moving part. The downside being
that it's too painful to backport changes from the ASF version, so
it'll remain outdated atleast until the next Subversion release, and
we don't know how soon that'll happen and be widely available.

If the former option is preferred, I'll send one large patch to the
list for mirroring the version in ASF. Also, could the Subversion
people confirm that licensing isn't an issue?

-- Ram

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

* Re: [PATCH 1/9] Add LICENSE
  2010-07-13 23:36 ` [PATCH 1/9] Add LICENSE Ramkumar Ramachandra
@ 2010-07-14  4:47   ` Daniel Shahaf
  2010-07-14 11:23     ` Ramkumar Ramachandra
  0 siblings, 1 reply; 26+ messages in thread
From: Daniel Shahaf @ 2010-07-14  4:47 UTC (permalink / raw)
  To: Ramkumar Ramachandra
  Cc: Git Mailing List, David Michael Barr, Jonathan Nieder,
	Sverre Rabbelier, avarab, Bert Huijben, Junio C Hamano, Eric Wong,
	Will Palmer, Greg Stein

[ are all of these CCs really necessary?  that's another thing I almost never
see over at dev@svn ]

Ramkumar Ramachandra wrote on Wed, Jul 14, 2010 at 01:36:08 +0200:
> License the project under a two-clause BSD-style license. A dual
> license will be required later when attempting to merge into
> Subversion.
> 

If it ends in svn trunk as subversion/svnrdump/ (and not as a tools/ utility),
it's going to have to be licensed under the Apache License v2.

Daniel
(AFAIK)

> Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
> ---
>  LICENSE |   26 ++++++++++++++++++++++++++
>  1 files changed, 26 insertions(+), 0 deletions(-)
>  create mode 100644 LICENSE
> 
> diff --git a/LICENSE b/LICENSE
> new file mode 100644
> index 0000000..4367b7c
> --- /dev/null
> +++ b/LICENSE
> @@ -0,0 +1,26 @@
> +Copyright (C) 2010 Ramkumar Ramachandra
> +All rights reserved.
> +
> +Redistribution and use in source and binary forms, with or without
> +modification, are permitted provided that the following conditions
> +are met:
> +1. Redistributions of source code must retain the above copyright
> +   notice(s), this list of conditions and the following disclaimer
> +   unmodified other than the allowable addition of one or more
> +   copyright notices.
> +2. Redistributions in binary form must reproduce the above copyright
> +   notice(s), this list of conditions and the following disclaimer in
> +   the documentation and/or other materials provided with the
> +   distribution.
> +
> +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
> +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> +PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
> +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
> +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
> +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
> +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
> +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> -- 
> 1.7.1
> 

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

* Re: [PATCH 0/9] Get svnrdump merged into git.git
  2010-07-14  0:49         ` Ramkumar Ramachandra
@ 2010-07-14  7:03           ` Stefan Sperling
  2010-07-14 11:26             ` Ramkumar Ramachandra
  0 siblings, 1 reply; 26+ messages in thread
From: Stefan Sperling @ 2010-07-14  7:03 UTC (permalink / raw)
  To: Ramkumar Ramachandra
  Cc: Jonathan Nieder, Git Mailing List, David Michael Barr,
	Sverre Rabbelier, avarab, Daniel Shahaf, Bert Huijben,
	Junio C Hamano, Eric Wong, Will Palmer, Greg Stein

On Wed, Jul 14, 2010 at 02:49:59AM +0200, Ramkumar Ramachandra wrote:
> Hi,
> 
> Jonathan Nieder writes:
> > As long as the relevant licenses permit that.  svnrdump only links to
> > libsvnclient, right?

It links against a couple of Subversion libraries and against APR.

> I can see another problem coming: things are likely to move around
> quite a bit after the code gets into the ASF. For instance, Stefan's
> recent review points out that write_hash_to_stringbuf should probably
> be in a reusable library. If these changes happen soon, svnrdump will
> be tightly integrated into Subversion, and it'll be hard to separate
> out an independent program. Then again, we don't know how soon this
> will happen.
> 
> If you get this series merged into git.git, Git people will be able to
> read and review it easily and it'll be guaranteed to compile against
> SVN 1.6. In other words, it won't be a moving part. The downside being
> that it's too painful to backport changes from the ASF version, so
> it'll remain outdated atleast until the next Subversion release, and
> we don't know how soon that'll happen and be widely available.
> 
> If the former option is preferred, I'll send one large patch to the
> list for mirroring the version in ASF.

Git devs will want a version of svnrdump that compiles against
the 1.6.x libraries. We'll want a version that compiles against
the trunk (so we can release it with 1.7).

So depending on which APIs svnrdump is using, it's likely that
you'll have to maintain 2 slightly differing versions anyway,
until 1.7 is released. (The current ETA for 1.7 is autumn, BTW).

> Also, could the Subversion
> people confirm that licensing isn't an issue?

I didn't catch any licensing discussion. What's the issue?

Stefan

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

* Re: [PATCH 1/9] Add LICENSE
  2010-07-14  4:47   ` Daniel Shahaf
@ 2010-07-14 11:23     ` Ramkumar Ramachandra
  0 siblings, 0 replies; 26+ messages in thread
From: Ramkumar Ramachandra @ 2010-07-14 11:23 UTC (permalink / raw)
  To: Daniel Shahaf, Git Mailing List, David Michael Barr,
	Jonathan Nieder, Sverre Rabbelier <

Hi Daniel,

Daniel Shahaf writes:
> [ are all of these CCs really necessary?  that's another thing I almost never
> see over at dev@svn ]

It's Git culture. Since our list is so high volume, many people aren't
subscribed to the list. Even those who are subscribed often cannot
read all the emails. When I CC someone on a list email, I'm implicitly
telling them "Please review this patch" or "Please comment on this" or
simply "You were involved with this work; just FYI, this is where it's
going". Most email clients have convinient markers to tell people if
they're marked on the To or Cc fields, or are simply receiving it
because they're subscribed to a list.

> If it ends in svn trunk as subversion/svnrdump/ (and not as a tools/ utility),
> it's going to have to be licensed under the Apache License v2.

Yes, I know. PATCH v2 is licensed appropriately. My intial idea was to
dual-license it: two-clause BSD for the git.git version and Apache for
the ASF version, but it seems like too much work now.

-- Ram

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

* Re: [PATCH 0/9] Get svnrdump merged into git.git
  2010-07-14  7:03           ` Stefan Sperling
@ 2010-07-14 11:26             ` Ramkumar Ramachandra
  2010-07-14 12:55               ` Stefan Sperling
  0 siblings, 1 reply; 26+ messages in thread
From: Ramkumar Ramachandra @ 2010-07-14 11:26 UTC (permalink / raw)
  To: Stefan Sperling
  Cc: Jonathan Nieder, Git Mailing List, David Michael Barr,
	Sverre Rabbelier, avarab, Daniel Shahaf, Bert Huijben,
	Junio C Hamano, Eric Wong, Will Palmer, Greg Stein

Hi Stefan,

Stefan Sperling writes:
> Git devs will want a version of svnrdump that compiles against
> the 1.6.x libraries. We'll want a version that compiles against
> the trunk (so we can release it with 1.7).
> 
> So depending on which APIs svnrdump is using, it's likely that
> you'll have to maintain 2 slightly differing versions anyway,
> until 1.7 is released. (The current ETA for 1.7 is autumn, BTW).

Right, that's alright. I'll just have a commit that I'll keep `rebase
--onto`ing to have the 1.6-specific changes.

> > Also, could the Subversion
> > people confirm that licensing isn't an issue?
> 
> I didn't catch any licensing discussion. What's the issue?

I guess there's no issue then- sorry, I know close to nothing about
licensing.

-- Ram

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

* Re: [PATCH 0/9] Get svnrdump merged into git.git
  2010-07-14 11:26             ` Ramkumar Ramachandra
@ 2010-07-14 12:55               ` Stefan Sperling
  0 siblings, 0 replies; 26+ messages in thread
From: Stefan Sperling @ 2010-07-14 12:55 UTC (permalink / raw)
  To: Ramkumar Ramachandra
  Cc: Jonathan Nieder, Git Mailing List, David Michael Barr,
	Sverre Rabbelier, avarab, Daniel Shahaf, Bert Huijben,
	Junio C Hamano, Eric Wong, Will Palmer, Greg Stein

On Wed, Jul 14, 2010 at 01:26:20PM +0200, Ramkumar Ramachandra wrote:
> Stefan Sperling writes:
> > I didn't catch any licensing discussion. What's the issue?
> 
> I guess there's no issue then- sorry, I know close to nothing about
> licensing.

Well, the only theoretical issue I can see is that the FSF says that
the GPLv2 was incompatible with the Apache 2.0 licence.
See http://www.apache.org/licenses/GPL-compatibility.html

So if git distributed their own version of svnrdump licensed under GPLv2,
depending on who you believe, distributors of Git binaries would violate
the GPLv2 by linking svnrdump to the Subversion libraries.

Mercurial recently switched to GPLv3 for this reason. They have code
that uses Subversion's Python bindings. They made this switch on their
own accord, however, after consulting the Software Freedom Law Center.
The Subversion project itself was not involved in that decision.

Possible workarounds are simply ignoring the FSF, or distributing all
copies of svnrdump under Apache 2.0 or GPLv3 (but the svnrdump included
in Subversion itself must be licensed under Apache 2.0).

Stefan

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

* Re: [PATCH 0/9] Get svnrdump merged into git.git
  2010-07-13 23:36 [PATCH 0/9] Get svnrdump merged into git.git Ramkumar Ramachandra
                   ` (9 preceding siblings ...)
  2010-07-13 23:58 ` [PATCH 0/9] Get svnrdump merged into git.git Ramkumar Ramachandra
@ 2010-07-14 14:54 ` Junio C Hamano
  2010-07-15 10:55   ` Ramkumar Ramachandra
  10 siblings, 1 reply; 26+ messages in thread
From: Junio C Hamano @ 2010-07-14 14:54 UTC (permalink / raw)
  To: Ramkumar Ramachandra
  Cc: Git Mailing List, David Michael Barr, Jonathan Nieder,
	Sverre Rabbelier, avarab, Daniel Shahaf, Bert Huijben, Eric Wong,
	Will Palmer, Greg Stein

Ramkumar Ramachandra <artagnon@gmail.com> writes:

> For the convinience of fellow Git developers, here's a series to get
> svnrdump merged into git.git.

Given you'll be maintaining a variant that can link with 1.6 subversion
libraries anyway, I'd rather see you host this as an independent, related
project, perhaps at repo.or.cz and/or github.com, and add a link to point
at it at https://git.wiki.kernel.org/index.php/InterfacesFrontendsAndTools

Thanks.

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

* Re: [PATCH 0/9] Get svnrdump merged into git.git
  2010-07-14 14:54 ` Junio C Hamano
@ 2010-07-15 10:55   ` Ramkumar Ramachandra
       [not found]     ` <20100806175709.GA2683@burratino>
  0 siblings, 1 reply; 26+ messages in thread
From: Ramkumar Ramachandra @ 2010-07-15 10:55 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Git Mailing List, David Michael Barr, Jonathan Nieder,
	Sverre Rabbelier, avarab, Daniel Shahaf, Bert Huijben, Eric Wong,
	Will Palmer, Greg Stein

Hi Junio,

Junio C Hamano writes:
> Given you'll be maintaining a variant that can link with 1.6 subversion
> libraries anyway, I'd rather see you host this as an independent, related
> project, perhaps at repo.or.cz and/or github.com, and add a link to point
> at it at https://git.wiki.kernel.org/index.php/InterfacesFrontendsAndTools

I think that sorts it out then. Thanks. I've merged this series into a
new project on my GitHub [1]. I'll soon convert whitespace/ style and
add some instructions, and maintain a branch that compiles against
libsvn 1.6. Until svnrdump is in a re-usable library in the ASF, I'm
afraid the git-remote-svn toolchain will simply have to spawn the
executable and read the output from a pipe. Instructions can then be
simplified to: compile `svnrdump` and place the executable anywhere in
your $PATH.

[1]: http://github.com/artagnon/svnrdump

-- Ram

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

* Re: [PATCH svnrdump-standalone] Sync with upstream
       [not found]     ` <20100806175709.GA2683@burratino>
@ 2010-08-06 18:37       ` Jonathan Nieder
  2010-08-07  2:30       ` Jonathan Nieder
  1 sibling, 0 replies; 26+ messages in thread
From: Jonathan Nieder @ 2010-08-06 18:37 UTC (permalink / raw)
  To: Ramkumar Ramachandra; +Cc: Git Mailing List

Jonathan Nieder wrote:

> Delete all files and copy in newer versions from Subversion
> upstream (http://svn.apache.org/repos/asf/subversion/trunk@982862).

Here’s the “while at it” part:

> While at it, port for an out-of-tree build against svn 1.6:
> 
>  - include a stripped-down version of the autoconf-generated
>    Makefile for Linux and a .gitignore file listing build
>    products;
> 
>  - use apr_hash_clear directly instead of svn_hash__clear
>    (since the latter’s signature has changed);
> 
>  - build and use an svn17_compat module for functions used
>    that were added in Subversion 1.7.
> 
> In theory, the svn17_compat module could shrink over time
> as simpler compatibility shims are devised.
>
> The result builds and all dump tests pass.
>
> Caveats: Most load tests do not pass.  Chances are this will only
> build against libsvn 1.6, not 1.7, since I did not do the appropriate
> identifier-renaming dance.

Most of this patch is Subversion code.

The rest, which is my own doing, I place in the public domain.
You may freely use, modify, distribute, and relicense it.

 .gitignore      |    5 +
 Makefile        |   35 +++
 dump_editor.c   |    9 +-
 svn17_compat.c  |  842 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 svn17_compat.h  |  179 ++++++++++++
 svnrdump.c      |    5 +-
 svntest/main.py |   17 +-
 7 files changed, 1076 insertions(+), 16 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 Makefile
 create mode 100644 svn17_compat.c
 create mode 100644 svn17_compat.h

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..af251b1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+*.lo
+*.o
+*.pyc
+/svn-test-work/
+/svnrdump
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..b022411
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,35 @@
+CC=gcc
+PYTHON=python
+LIBTOOL=libtool
+LTFLAGS=--tag=CC --silent
+CFLAGS=-g -O2 -pthread -Wall -Werror=implicit-function-declaration
+EXEEXT=
+CPPFLAGS=-DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE
+LDFLAGS=
+COMPILE=$(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES)
+LINK=$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) $(CFLAGS)
+LT_COMPILE=$(LIBTOOL) $(LTFLAGS) --mode=compile $(COMPILE) $(CFLAGS)
+
+INCLUDES=-I/usr/include/subversion-1 -I/usr/include/apr-1.0
+LIBS=-lsvn_client-1 -lsvn_ra-1 -lsvn_repos-1 -lsvn_delta-1 -lsvn_subr-1 -lapr-1
+OBJECTS=dump_editor.lo load_editor.lo svnrdump.lo svn17_compat.lo
+
+.SUFFIXES: .c .lo
+
+svnrdump$(EXEEXT): $(OBJECTS)
+	$(LINK) $(LDFLAGS) -o svnrdump$(EXEEXT) $(OBJECTS) $(LIBS)
+
+.c.lo:
+	$(LT_COMPILE) -o $@ -c $<
+
+dump_editor.lo: dump_editor.c dump_editor.h svn17_compat.h
+load_editor.lo: load_editor.c load_editor.h
+svnrdump.lo: svnrdump.c dump_editor.h load_editor.h svn17_compat.h
+svn17_compat.lo: svn17_compat.c svn17_compat.h
+
+check: svnrdump$(EXEEXT) svnrdump_tests.py
+	$(PYTHON) svnrdump_tests.py
+
+clean:
+	$(RM) svnrdump$(EXEEXT)
+	$(RM) *.lo *.o
diff --git a/dump_editor.c b/dump_editor.c
index dac9d15..72ad04f 100644
--- a/dump_editor.c
+++ b/dump_editor.c
@@ -29,6 +29,7 @@
 #include "svn_props.h"
 #include "svn_dirent_uri.h"
 
+#include "svn17_compat.h"
 #include "dump_editor.h"
 
 #define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
@@ -166,8 +167,8 @@ dump_props(struct dump_edit_baton *eb,
       SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n"));
 
       /* Cleanup so that data is never dumped twice. */
-      svn_hash__clear(eb->props, pool);
-      svn_hash__clear(eb->deleted_props, pool);
+      apr_hash_clear(eb->props);
+      apr_hash_clear(eb->deleted_props);
       if (trigger_var)
         *trigger_var = FALSE;
     }
@@ -711,8 +712,8 @@ close_file(void *file_baton,
 
       /* Cleanup */
       eb->dump_props = eb->dump_props_pending = FALSE;
-      svn_hash__clear(eb->props, pool);
-      svn_hash__clear(eb->deleted_props, pool);
+      apr_hash_clear(eb->props);
+      apr_hash_clear(eb->deleted_props);
     }
 
   /* Dump the text */
diff --git a/svn17_compat.c b/svn17_compat.c
new file mode 100644
index 0000000..e6d8774
--- /dev/null
+++ b/svn17_compat.c
@@ -0,0 +1,842 @@
+/*
+ * svn17_compat.c :   a library to make Subversion 1.6 look like 1.7.
+ *
+ * ====================================================================
+ *    This file is derived from code licensed to the Apache
+ *    Software Foundation (ASF) under one or more contributor
+ *    license agreements.  See the NOTICE file distributed with
+ *    this file for additional information regarding copyright
+ *    ownership.  The ASF licenses those portions to you under
+ *    the Apache License, Version 2.0 (the "License"); you may
+ *    not use those portions except in compliance with the
+ *    License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ *
+ *    Any code in this file not licensed from the ASF is
+ *    original code in the public domain.  You may freely use,
+ *    modify, distribute, and relicense such code.
+ * ====================================================================
+ */
+\f
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <apr.h>
+#include <apr_strings.h>
+#include <apr_hash.h>
+#include <apr_lib.h>
+#include <apr_errno.h>
+#include <apr_pools.h>
+
+#include <svn_error.h>
+#include <svn_config.h>
+#include <svn_io.h>
+#include <svn_dirent_uri.h>
+#include <svn_path.h>
+#include "svn17_compat.h"
+
+/* TRUE if s is the canonical empty path, FALSE otherwise
+   From libsvn_subr/dirent_uri.c. */
+#define SVN_PATH_IS_EMPTY(s) ((s)[0] == '\0')
+
+/* Path type definition. Used only by internal functions.
+   From libsvn_subr/dirent_uri.c. */
+typedef enum {
+  type_uri,
+  type_dirent,
+  type_relpath
+} path_type_t;
+
+/* Here is the BNF for path components in a URI. "pchar" is a
+   character in a path component.
+
+      pchar       = unreserved | escaped |
+                    ":" | "@" | "&" | "=" | "+" | "$" | ","
+      unreserved  = alphanum | mark
+      mark        = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
+
+   Note that "escaped" doesn't really apply to what users can put in
+   their paths, so that really means the set of characters is:
+
+      alphanum | mark | ":" | "@" | "&" | "=" | "+" | "$" | ","
+
+   From libsvn_subr/path.c. */
+static const char svn_uri__char_validity[256] = {
+  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+  0, 1, 0, 0, 1, 0, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 1, 0, 0,
+
+  /* 64 */
+  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 0, 0, 1,
+  0, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 0, 1, 0,
+
+  /* 128 */
+  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+
+  /* 192 */
+  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+/* From libsvn_subr/dirent_uri.c. */
+static svn_boolean_t
+svn_uri_is_canonical(const char *uri, apr_pool_t *pool)
+{
+  const char *ptr = uri, *seg = uri;
+  const char *schema_data = NULL;
+
+  /* URI is canonical if it has:
+   *  - no '.' segments
+   *  - no closing '/', unless for the root path '/' itself
+   *  - no '//'
+   *  - lowercase URL scheme
+   *  - lowercase URL hostname
+   */
+
+  if (*uri == '\0')
+    return TRUE;
+
+  /* Maybe parse hostname and scheme. */
+  if (*ptr != '/')
+    {
+      while (*ptr && (*ptr != '/') && (*ptr != ':'))
+        ptr++;
+
+      if (*ptr == ':' && *(ptr+1) == '/' && *(ptr+2) == '/')
+        {
+          /* Found a scheme, check that it's all lowercase. */
+          ptr = uri;
+          while (*ptr != ':')
+            {
+              if (*ptr >= 'A' && *ptr <= 'Z')
+                return FALSE;
+              ptr++;
+            }
+          /* Skip :// */
+          ptr += 3;
+
+          /* This might be the hostname */
+          seg = ptr;
+          while (*ptr && (*ptr != '/') && (*ptr != '@'))
+            ptr++;
+
+          if (! *ptr)
+            return TRUE;
+
+          if (*ptr == '@')
+            seg = ptr + 1;
+
+          /* Found a hostname, check that it's all lowercase. */
+          ptr = seg;
+          while (*ptr && *ptr != '/')
+            {
+              if (*ptr >= 'A' && *ptr <= 'Z')
+                return FALSE;
+              ptr++;
+            }
+
+          schema_data = ptr;
+        }
+      else
+        {
+          /* Didn't find a scheme; finish the segment. */
+          while (*ptr && *ptr != '/')
+            ptr++;
+        }
+    }
+
+#ifdef SVN_USE_DOS_PATHS
+  if (schema_data && *ptr == '/')
+    {
+      /* If this is a file url, ptr now points to the third '/' in
+         file:///C:/path. Check that if we have such a URL the drive
+         letter is in uppercase. */
+      if (strncmp(uri, "file:", 5) == 0 &&
+          ! (*(ptr+1) >= 'A' && *(ptr+1) <= 'Z') &&
+          *(ptr+2) == ':')
+        return FALSE;
+    }
+#endif /* SVN_USE_DOS_PATHS */
+
+  /* Now validate the rest of the URI. */
+  while(1)
+    {
+      apr_size_t seglen = ptr - seg;
+
+      if (seglen == 1 && *seg == '.')
+        return FALSE;  /*  /./   */
+
+      if (*ptr == '/' && *(ptr+1) == '/')
+        return FALSE;  /*  //    */
+
+      if (! *ptr && *(ptr - 1) == '/' && ptr - 1 != uri)
+        return FALSE;  /* foo/  */
+
+      if (! *ptr)
+        break;
+
+      if (*ptr == '/')
+        ptr++;
+      seg = ptr;
+
+
+      while (*ptr && (*ptr != '/'))
+        ptr++;
+    }
+
+  if (schema_data)
+    {
+      ptr = schema_data;
+
+      while (*ptr)
+        {
+          if (*ptr == '%')
+            {
+              char digitz[3];
+              int val;
+
+              /* Can't use apr_isxdigit() because lower case letters are
+                 not in our canonical format */
+              if (((*(ptr+1) < '0' || (*ptr+1) > '9'))
+                  && (*(ptr+1) < 'A' || (*ptr+1) > 'F'))
+                return FALSE;
+              else if (((*(ptr+2) < '0' || (*ptr+2) > '9'))
+                  && (*(ptr+2) < 'A' || (*ptr+2) > 'F'))
+                return FALSE;
+
+              digitz[0] = *(++ptr);
+              digitz[1] = *(++ptr);
+              digitz[2] = '\0';
+              val = (int)strtol(digitz, NULL, 16);
+
+              if (svn_uri__char_validity[val])
+                return FALSE; /* Should not have been escaped */
+            }
+          else if (*ptr != '/' && !svn_uri__char_validity[(unsigned char)*ptr])
+            return FALSE; /* Character should have been escaped */
+          ptr++;
+        }
+    }
+
+  return TRUE;
+}
+
+/* From libsvn_subr/dirent_uri.c. */
+static svn_boolean_t
+svn_uri_is_absolute(const char *uri)
+{
+  /* uri is absolute if it starts with '/' */
+  if (uri && uri[0] == '/')
+    return TRUE;
+
+  /* URLs are absolute. */
+  return svn_path_is_url(uri);
+}
+
+/* Calculates the length occupied by the schema defined root of URI
+   From libsvn_subr/dirent_uri.c. */
+static apr_size_t
+uri_schema_root_length(const char *uri, apr_size_t len)
+{
+  apr_size_t i;
+
+  for (i = 0; i < len; i++)
+    {
+      if (uri[i] == '/')
+        {
+          if (i > 0 && uri[i-1] == ':' && i < len-1 && uri[i+1] == '/')
+            {
+              /* We have an absolute uri */
+              if (i == 5 && strncmp("file", uri, 4) == 0)
+                return 7; /* file:// */
+              else
+                {
+                  for (i += 2; i < len; i++)
+                    if (uri[i] == '/')
+                      return i;
+
+                  return len; /* Only a hostname is found */
+                }
+            }
+          else
+            return 0;
+        }
+    }
+
+  return 0;
+}
+
+/* From libsvn_subr/dirent_uri.c. */
+char *
+svn_uri_join(const char *base, const char *component, apr_pool_t *pool)
+{
+  apr_size_t blen = strlen(base);
+  apr_size_t clen = strlen(component);
+  char *path;
+
+  assert(svn_uri_is_canonical(base, pool));
+  assert(svn_uri_is_canonical(component, pool));
+
+  /* If either is empty return the other */
+  if (SVN_PATH_IS_EMPTY(base))
+    return apr_pmemdup(pool, component, clen + 1);
+  if (SVN_PATH_IS_EMPTY(component))
+    return apr_pmemdup(pool, base, blen + 1);
+
+  /* If the component is absolute, then return it.  */
+  if (svn_uri_is_absolute(component))
+    {
+      if (*component != '/')
+        return apr_pmemdup(pool, component, clen + 1);
+      else
+        {
+          /* The uri is not absolute enough; use only the root from base */
+          apr_size_t n = uri_schema_root_length(base, blen);
+
+          path = apr_palloc(pool, n + clen + 1);
+
+          if (n > 0)
+            memcpy(path, base, n);
+
+          memcpy(path + n, component, clen + 1); /* Include '\0' */
+
+          return path;
+        }
+    }
+
+  if (blen == 1 && base[0] == '/')
+    blen = 0; /* Ignore base, just return separator + component */
+
+  /* Construct the new, combined path. */
+  path = apr_palloc(pool, blen + 1 + clen + 1);
+  memcpy(path, base, blen);
+  path[blen] = '/';
+  memcpy(path + blen + 1, component, clen + 1);
+
+  return path;
+}
+
+/* From libsvn_subr/dirent_uri.c. */
+static svn_boolean_t
+svn_relpath_is_canonical(const char *relpath,
+                         apr_pool_t *pool)
+{
+  const char *ptr = relpath, *seg = relpath;
+
+  /* RELPATH is canonical if it has:
+   *  - no '.' segments
+   *  - no start and closing '/'
+   *  - no '//'
+   */
+
+  if (*relpath == '\0')
+    return TRUE;
+
+  if (*ptr == '/')
+    return FALSE;
+
+  /* Now validate the rest of the path. */
+  while(1)
+    {
+      apr_size_t seglen = ptr - seg;
+
+      if (seglen == 1 && *seg == '.')
+        return FALSE;  /*  /./   */
+
+      if (*ptr == '/' && *(ptr+1) == '/')
+        return FALSE;  /*  //    */
+
+      if (! *ptr && *(ptr - 1) == '/')
+        return FALSE;  /* foo/  */
+
+      if (! *ptr)
+        break;
+
+      if (*ptr == '/')
+        ptr++;
+      seg = ptr;
+
+      while (*ptr && (*ptr != '/'))
+        ptr++;
+    }
+
+  return TRUE;
+}
+
+/* From libsvn_subr/dirent_uri.c. */
+const char *
+svn_relpath_basename(const char *relpath,
+                     apr_pool_t *pool)
+{
+  apr_size_t len = strlen(relpath);
+  apr_size_t start;
+
+  assert(!pool || svn_relpath_is_canonical(relpath, pool));
+
+  start = len;
+  while (start > 0 && relpath[start - 1] != '/')
+    --start;
+
+  if (pool)
+    return apr_pstrmemdup(pool, relpath + start, len - start);
+  else
+    return relpath + start;
+}
+
+/* From libsvn_subr/dirent_uri.c. */
+const char *
+svn_dirent_basename(const char *dirent, apr_pool_t *pool)
+{
+  apr_size_t len = strlen(dirent);
+  apr_size_t start;
+
+  assert(!pool || svn_dirent_is_canonical(dirent, pool));
+
+  if (svn_dirent_is_root(dirent, len))
+    return "";
+  else
+    {
+      start = len;
+      while (start > 0 && dirent[start - 1] != '/'
+#ifdef SVN_USE_DOS_PATHS
+             && dirent[start - 1] != ':'
+#endif
+            )
+        --start;
+    }
+
+  if (pool)
+    return apr_pstrmemdup(pool, dirent + start, len - start);
+  else
+    return dirent + start;
+}
+
+/* Locale insensitive tolower() for converting parts of dirents and urls
+   while canonicalizing.  From libsvn_subr/dirent_uri.c. */
+static char
+canonicalize_to_lower(char c)
+{
+  if (c < 'A' || c > 'Z')
+    return c;
+  else
+    return c - 'A' + 'a';
+}
+
+/* Locale insensitive toupper() for converting parts of dirents and urls
+   while canonicalizing.  From libsvn_subr/dirent_uri.c. */
+static char
+canonicalize_to_upper(char c)
+{
+  if (c < 'a' || c > 'z')
+    return c;
+  else
+    return c - 'a' + 'A';
+}
+
+
+/* Return the canonicalized version of PATH, of type TYPE, allocated in
+ * POOL.  From libsvn_subr/dirent_uri.c.
+ */
+static const char *
+canonicalize(path_type_t type, const char *path, apr_pool_t *pool)
+{
+  char *canon, *dst;
+  const char *src;
+  apr_size_t seglen;
+  apr_size_t schemelen = 0;
+  apr_size_t canon_segments = 0;
+  svn_boolean_t url = FALSE;
+  char *schema_data = NULL;
+
+  /* "" is already canonical, so just return it; note that later code
+     depends on path not being zero-length.  */
+  if (SVN_PATH_IS_EMPTY(path))
+    return "";
+
+  dst = canon = apr_pcalloc(pool, strlen(path) + 1);
+
+  /* If this is supposed to be an URI and it starts with "scheme://", then
+     copy the scheme, host name, etc. to DST and set URL = TRUE. */
+  src = path;
+  if (type == type_uri && *src != '/')
+    {
+      while (*src && (*src != '/') && (*src != ':'))
+        src++;
+
+      if (*src == ':' && *(src+1) == '/' && *(src+2) == '/')
+        {
+          const char *seg;
+
+          url = TRUE;
+
+          /* Found a scheme, convert to lowercase and copy to dst. */
+          src = path;
+          while (*src != ':')
+            {
+              *(dst++) = canonicalize_to_lower((*src++));
+              schemelen++;
+            }
+          *(dst++) = ':';
+          *(dst++) = '/';
+          *(dst++) = '/';
+          src += 3;
+          schemelen += 3;
+
+          /* This might be the hostname */
+          seg = src;
+          while (*src && (*src != '/') && (*src != '@'))
+            src++;
+
+          if (*src == '@')
+            {
+              /* Copy the username & password. */
+              seglen = src - seg + 1;
+              memcpy(dst, seg, seglen);
+              dst += seglen;
+              src++;
+            }
+          else
+            src = seg;
+
+          /* Found a hostname, convert to lowercase and copy to dst. */
+          while (*src && (*src != '/'))
+            *(dst++) = canonicalize_to_lower((*src++));
+
+          /* Copy trailing slash, or null-terminator. */
+          *(dst) = *(src);
+
+          /* Move src and dst forward only if we are not
+           * at null-terminator yet. */
+          if (*src)
+            {
+              src++;
+              dst++;
+              schema_data = dst;
+            }
+
+          canon_segments = 1;
+        }
+    }
+
+  /* Copy to DST any separator or drive letter that must come before the
+     first regular path segment. */
+  if (! url && type != type_relpath)
+    {
+      src = path;
+      /* If this is an absolute path, then just copy over the initial
+         separator character. */
+      if (*src == '/')
+        {
+          *(dst++) = *(src++);
+
+#ifdef SVN_USE_DOS_PATHS
+          /* On Windows permit two leading separator characters which means an
+           * UNC path. */
+          if ((type == type_dirent) && *src == '/')
+            *(dst++) = *(src++);
+#endif /* SVN_USE_DOS_PATHS */
+        }
+#ifdef SVN_USE_DOS_PATHS
+      /* On Windows the first segment can be a drive letter, which we normalize
+         to upper case. */
+      else if (type == type_dirent &&
+               ((*src >= 'a' && *src <= 'z') ||
+                (*src >= 'A' && *src <= 'Z')) &&
+               (src[1] == ':'))
+        {
+          *(dst++) = canonicalize_to_upper(*(src++));
+          /* Leave the ':' to be processed as (or as part of) a path segment
+             by the following code block, so we need not care whether it has
+             a slash after it. */
+        }
+#endif /* SVN_USE_DOS_PATHS */
+    }
+
+  while (*src)
+    {
+      /* Parse each segment, find the closing '/' */
+      const char *next = src;
+      while (*next && (*next != '/'))
+        ++next;
+
+      seglen = next - src;
+
+      if (seglen == 0 || (seglen == 1 && src[0] == '.'))
+        {
+          /* Noop segment, so do nothing. */
+        }
+#ifdef SVN_USE_DOS_PATHS
+      /* If this is the first path segment of a file:// URI and it contains a
+         windows drive letter, convert the drive letter to upper case. */
+      else if (url && canon_segments == 1 && seglen == 2 &&
+               (strncmp(canon, "file:", 5) == 0) &&
+               src[0] >= 'a' && src[0] <= 'z' && src[1] == ':')
+        {
+          *(dst++) = canonicalize_to_upper(src[0]);
+          *(dst++) = ':';
+          if (*next)
+            *(dst++) = *next;
+          canon_segments++;
+        }
+#endif /* SVN_USE_DOS_PATHS */
+      else
+        {
+          /* An actual segment, append it to the destination path */
+          if (*next)
+            seglen++;
+          memcpy(dst, src, seglen);
+          dst += seglen;
+          canon_segments++;
+        }
+
+      /* Skip over trailing slash to the next segment. */
+      src = next;
+      if (*src)
+        src++;
+    }
+
+  /* Remove the trailing slash if there was at least one
+   * canonical segment and the last segment ends with a slash.
+   *
+   * But keep in mind that, for URLs, the scheme counts as a
+   * canonical segment -- so if path is ONLY a scheme (such
+   * as "https://") we should NOT remove the trailing slash. */
+  if ((canon_segments > 0 && *(dst - 1) == '/')
+      && ! (url && path[schemelen] == '\0'))
+    {
+      dst --;
+    }
+
+  *dst = '\0';
+
+#ifdef SVN_USE_DOS_PATHS
+  /* Skip leading double slashes when there are less than 2
+   * canon segments. UNC paths *MUST* have two segments. */
+  if ((type == type_dirent) && canon[0] == '/' && canon[1] == '/')
+    {
+      if (canon_segments < 2)
+        return canon + 1;
+      else
+        {
+          /* Now we're sure this is a valid UNC path, convert the server name
+             (the first path segment) to lowercase as Windows treats it as case
+             insensitive.
+             Note: normally the share name is treated as case insensitive too,
+             but it seems to be possible to configure Samba to treat those as
+             case sensitive, so better leave that alone. */
+          dst = canon + 2;
+          while (*dst && *dst != '/')
+            *(dst++) = canonicalize_to_lower(*dst);
+        }
+    }
+#endif /* SVN_USE_DOS_PATHS */
+
+  /* Check the normalization of characters in a uri */
+  if (schema_data)
+    {
+      int need_extra = 0;
+      src = schema_data;
+
+      while (*src)
+        {
+          switch (*src)
+            {
+              case '/':
+                break;
+              case '%':
+                if (!apr_isxdigit(*(src+1)) || !apr_isxdigit(*(src+2)))
+                  need_extra += 2;
+                else
+                  src += 2;
+                break;
+              default:
+                if (!svn_uri__char_validity[(unsigned char)*src])
+                  need_extra += 2;
+                break;
+            }
+          src++;
+        }
+
+      if (need_extra > 0)
+        {
+          apr_size_t pre_schema_size = (apr_size_t)(schema_data - canon);
+
+          dst = apr_palloc(pool, (apr_size_t)(src - canon) + need_extra + 1);
+          memcpy(dst, canon, pre_schema_size);
+          canon = dst;
+
+          dst += pre_schema_size;
+        }
+      else
+        dst = schema_data;
+
+      src = schema_data;
+
+      while (*src)
+        {
+          switch (*src)
+            {
+              case '/':
+                *(dst++) = '/';
+                break;
+              case '%':
+                if (!apr_isxdigit(*(src+1)) || !apr_isxdigit(*(src+2)))
+                  {
+                    *(dst++) = '%';
+                    *(dst++) = '2';
+                    *(dst++) = '5';
+                  }
+                else
+                  {
+                    char digitz[3];
+                    int val;
+
+                    digitz[0] = *(++src);
+                    digitz[1] = *(++src);
+                    digitz[2] = 0;
+
+                    val = (int)strtol(digitz, NULL, 16);
+
+                    if (svn_uri__char_validity[(unsigned char)val])
+                      *(dst++) = (char)val;
+                    else
+                      {
+                        *(dst++) = '%';
+                        *(dst++) = canonicalize_to_upper(digitz[0]);
+                        *(dst++) = canonicalize_to_upper(digitz[1]);
+                      }
+                  }
+                break;
+              default:
+                if (!svn_uri__char_validity[(unsigned char)*src])
+                  {
+                    apr_snprintf(dst, 4, "%%%02X", (unsigned char)*src);
+                    dst += 3;
+                  }
+                else
+                  *(dst++) = *src;
+                break;
+            }
+          src++;
+        }
+      *dst = '\0';
+    }
+
+  return canon;
+}
+
+/* From libsvn_subr/dirent_uri.c. */
+const char *
+svn_uri_canonicalize(const char *uri, apr_pool_t *pool)
+{
+  return canonicalize(type_uri, uri, pool);
+}
+
+/* New code (public domain). */
+svn_error_t *
+svn_io_remove_file2(const char *path,
+                   svn_boolean_t ignore_enoent,
+                   apr_pool_t *scratch_pool)
+{
+  svn_error_t *err = svn_io_remove_file(path, scratch_pool);
+  if (ignore_enoent && err && APR_STATUS_IS_ENOENT(err->apr_err))
+    {
+      svn_error_clear(err);
+      return SVN_NO_ERROR;
+    }
+  return err;
+}
+
+/* From libsvn_subr/cmdline.c. */
+svn_error_t *
+svn_cmdline__apply_config_options(apr_hash_t *config,
+                                  const apr_array_header_t *config_options,
+                                  const char *prefix,
+                                  const char *argument_name)
+{
+  int i;
+
+  for (i = 0; i < config_options->nelts; i++)
+   {
+     svn_config_t *cfg;
+     svn_cmdline__config_argument_t *arg =
+                          APR_ARRAY_IDX(config_options, i,
+                                        svn_cmdline__config_argument_t *);
+
+     cfg = apr_hash_get(config, arg->file, APR_HASH_KEY_STRING);
+
+     if (cfg)
+       {
+         svn_config_set(cfg, arg->section, arg->option, arg->value);
+       }
+     else
+       {
+         svn_error_t *err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+             _("Unrecognized file in argument of %s"), argument_name);
+
+         svn_handle_warning2(stderr, err, prefix);
+         svn_error_clear(err);
+       }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* From libsvn_subr/cmdline.c. */
+svn_error_t *
+svn_cmdline__parse_config_option(apr_array_header_t *config_options,
+                                 const char *opt_arg,
+                                 apr_pool_t *pool)
+{
+  svn_cmdline__config_argument_t *config_option;
+  const char *first_colon, *second_colon, *equals_sign;
+  apr_size_t len = strlen(opt_arg);
+  if ((first_colon = strchr(opt_arg, ':')) && (first_colon != opt_arg))
+    {
+      if ((second_colon = strchr(first_colon + 1, ':')) &&
+          (second_colon != first_colon + 1))
+        {
+          if ((equals_sign = strchr(second_colon + 1, '=')) &&
+              (equals_sign != second_colon + 1))
+            {
+              config_option = apr_pcalloc(pool, sizeof(*config_option));
+              config_option->file = apr_pstrndup(pool, opt_arg,
+                                                 first_colon - opt_arg);
+              config_option->section = apr_pstrndup(pool, first_colon + 1,
+                                                    second_colon - first_colon - 1);
+              config_option->option = apr_pstrndup(pool, second_colon + 1,
+                                                   equals_sign - second_colon -
+1);
+
+              if (! (strchr(config_option->option, ':')))
+                {
+                  config_option->value = apr_pstrndup(pool, equals_sign + 1,
+                                                      opt_arg + len - equals_sign - 1);
+                  APR_ARRAY_PUSH(config_options, svn_cmdline__config_argument_t
+*)
+                                       = config_option;
+                  return SVN_NO_ERROR;
+                }
+            }
+        }
+    }
+  return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                          _("Invalid syntax of argument of --config-option"));
+}
diff --git a/svn17_compat.h b/svn17_compat.h
new file mode 100644
index 0000000..2c48cd6
--- /dev/null
+++ b/svn17_compat.h
@@ -0,0 +1,179 @@
+/**
+ * @copyright
+ * ====================================================================
+ *    This file is derived from code licensed to the Apache
+ *    Software Foundation (ASF) under one or more contributor
+ *    license agreements.  See the NOTICE file distributed with
+ *    this file for additional information regarding copyright
+ *    ownership.  The ASF licenses those portions to you under
+ *    the Apache License, Version 2.0 (the "License"); you may
+ *    not use those portions except in compliance with the
+ *    License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ *
+ *    Any code in this file not licensed from the ASF is
+ *    original code in the public domain.  You may freely use,
+ *    modify, distribute, and relicense such code.
+ * ====================================================================
+ * @endcopyright
+ *
+ * @file compat.h
+ * @brief SVN 1.7 compatibility routines.
+ */
+
+#ifndef SVN17_COMPAT_H
+#define SVN17_COMPAT_H
+
+#include <apr.h>
+#include <apr_pools.h>
+
+#include <svn_types.h>
+
+/** Join a valid base uri (@a base) with a relative path or uri
+ * (@a component), allocating the result in @a pool. @a component need
+ * not be a single component: it can be a relative path or a '/'
+ * prefixed relative path to join component to the root path of @a base.
+ *
+ * If @a component is the empty path, then @a base will be copied and
+ * returned.
+ *
+ * If the @a component is an absolute uri, then it is copied and returned.
+ *
+ * If @a component starts with a '/' and @a base contains a scheme, the
+ * scheme defined joining rules are applied.
+ *
+ * From svn_dirent_uri.h.
+ */
+char *
+svn_uri_join(const char *base,
+             const char *component,
+             apr_pool_t *pool);
+
+/** Get the basename of the specified canonicalized @a relpath.  The
+ * basename is defined as the last component of the relpath.  If the @a
+ * relpath has only one component then that is returned. The returned
+ * value will have no slashes in it.
+ *
+ * Example: svn_relpath_basename("/trunk/foo/bar") -> "bar"
+ *
+ * The returned basename will be allocated in @a pool. If @a
+ * pool is NULL a pointer to the basename in @a relpath is returned.
+ *
+ * @note If an empty string is passed, then an empty string will be returned.
+ *
+ * From svn_dirent_uri.h.
+ */
+const char *
+svn_relpath_basename(const char *uri,
+                     apr_pool_t *pool);
+
+/** Gets the name of the specified canonicalized @a dirent as it is known
+ * within its parent directory. If the @a dirent is root, return "". The
+ * returned value will not have slashes in it.
+ *
+ * Example: svn_dirent_basename("/foo/bar") -> "bar"
+ *
+ * The returned basename will be allocated in @a pool. If @a pool is NULL
+ * a pointer to the basename in @a dirent is returned.
+ *
+ * @note If an empty string is passed, then an empty string will be returned.
+ *
+ * From svn_dirent_uri.h.
+ */
+const char *
+svn_dirent_basename(const char *dirent,
+                    apr_pool_t *pool);
+
+/** Return a new uri like @a uri, but transformed such that some types
+ * of uri specification redundancies are removed.
+ *
+ * This involves collapsing redundant "/./" elements, removing
+ * multiple adjacent separator characters, removing trailing
+ * separator characters, and possibly other semantically inoperative
+ * transformations.
+ *
+ * If @a uri starts with a schema, this function also normalizes the
+ * escaping of the path component by unescaping characters that don't
+ * need escaping and escaping characters that do need escaping but
+ * weren't.
+ *
+ * This functions supports URLs.
+ *
+ * The returned uri may be statically allocated or allocated from @a pool.
+ *
+ * From svn_dirent_uri.h.
+ */
+const char *
+svn_uri_canonicalize(const char *uri,
+                     apr_pool_t *pool);
+
+/** Remove file @a path, a utf8-encoded path.  This wraps apr_file_remove(),
+ * converting any error to a Subversion error. If @a ignore_enoent is TRUE, and
+ * the file is not present (APR_STATUS_IS_ENOENT returns TRUE), then no
+ * error will be returned.
+ *
+ * From svn_io.h.
+ */
+svn_error_t *
+svn_io_remove_file2(const char *path,
+                   svn_boolean_t ignore_enoent,
+                   apr_pool_t *scratch_pool);
+
+/* From svn_private_config.h.
+ */
+#define PACKAGE_NAME "subversion"
+#define N_(x) x
+#include <locale.h>
+#include <libintl.h>
+#define _(x) dgettext(PACKAGE_NAME, x)
+
+/** Sets the config options in @a config_options, an apr array containing
+ * svn_cmdline__config_argument_t* elements to the configuration in @a cfg,
+ * a hash mapping of <tt>const char *</tt> configuration file names to
+ * @c svn_config_t *'s. Write warnings to stderr.
+ *
+ * Use @a prefix as prefix and @a argument_name in warning messages.
+ *
+ * From private/svn_cmdline_private.h.
+ */
+svn_error_t *
+svn_cmdline__apply_config_options(apr_hash_t *config,
+                                  const apr_array_header_t *config_options,
+                                  const char *prefix,
+                                  const char *argument_name);
+
+/** Container for config options parsed with svn_cmdline__parse_config_option
+ *
+ * From private/svn_cmdline_private.h.
+ */
+typedef struct svn_cmdline__config_argument_t
+{
+  const char *file;
+  const char *section;
+  const char *option;
+  const char *value;
+} svn_cmdline__config_argument_t;
+
+/** Parser for 'FILE:SECTION:OPTION=[VALUE]'-style option arguments.
+ *
+ * Parses @a opt_arg and places its value in @a config_options, an apr array
+ * containing svn_cmdline__config_argument_t* elements, allocating the option
+ * data in @a pool
+ *
+ * From private/svn_cmdline_private.h.
+ */
+svn_error_t *
+svn_cmdline__parse_config_option(apr_array_header_t *config_options,
+                                 const char *opt_arg,
+                                 apr_pool_t *pool);
+
+
+#endif /* SVN17_COMPAT_H */
diff --git a/svnrdump.c b/svnrdump.c
index daf826e..a320b24 100644
--- a/svnrdump.c
+++ b/svnrdump.c
@@ -30,15 +30,14 @@
 #include "svn_repos.h"
 #include "svn_path.h"
 #include "svn_utf.h"
-#include "svn_private_config.h"
 #include "svn_string.h"
 #include "svn_props.h"
+#include "svn_dirent_uri.h"
 
+#include "svn17_compat.h"
 #include "dump_editor.h"
 #include "load_editor.h"
 
-#include "private/svn_cmdline_private.h"
-
 static svn_opt_subcommand_t dump_cmd, load_cmd;
 
 enum svn_svnrdump__longopt_t
diff --git a/svntest/main.py b/svntest/main.py
index 2c59101..3e938d6 100644
--- a/svntest/main.py
+++ b/svntest/main.py
@@ -149,15 +149,14 @@ def url2pathname(path):
 # The locations of the svn, svnadmin and svnlook binaries, relative to
 # the only scripts that import this file right now (they live in ../).
 # Use --bin to override these defaults.
-svn_binary = os.path.abspath('../../svn/svn' + _exe)
-svnadmin_binary = os.path.abspath('../../svnadmin/svnadmin' + _exe)
-svnlook_binary = os.path.abspath('../../svnlook/svnlook' + _exe)
-svnrdump_binary = os.path.abspath('../../svnrdump/svnrdump' + _exe)
-svnsync_binary = os.path.abspath('../../svnsync/svnsync' + _exe)
-svnversion_binary = os.path.abspath('../../svnversion/svnversion' + _exe)
-svndumpfilter_binary = os.path.abspath('../../svndumpfilter/svndumpfilter' + \
-                                       _exe)
-entriesdump_binary = os.path.abspath('entries-dump' + _exe)
+svn_binary = 'svn'
+svnadmin_binary = 'svnadmin'
+svnlook_binary = 'svnlook'
+svnrdump_binary = os.path.abspath('./svnrdump' + _exe)
+svnsync_binary = 'svnsync'
+svnversion_binary = 'svnversion'
+svndumpfilter_binary = 'svndumpfilter'
+entriesdump_binary = 'entries-dump'
 
 # Location to the pristine repository, will be calculated from test_area_url
 # when we know what the user specified for --url.
-- 
1.7.2.1.544.ga752d.dirty

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

* Re: [PATCH svnrdump-standalone] Sync with upstream
       [not found]     ` <20100806175709.GA2683@burratino>
  2010-08-06 18:37       ` [PATCH svnrdump-standalone] Sync with upstream Jonathan Nieder
@ 2010-08-07  2:30       ` Jonathan Nieder
  2010-08-07  2:47         ` Ramkumar Ramachandra
  2010-08-07  2:51         ` Ramkumar Ramachandra
  1 sibling, 2 replies; 26+ messages in thread
From: Jonathan Nieder @ 2010-08-07  2:30 UTC (permalink / raw)
  To: Ramkumar Ramachandra; +Cc: Git Mailing List

Jonathan Nieder wrote:

> Caveats: Most load tests do not pass.

They pass now.  Thanks for the help!

You can

  git clone git://repo.or.cz/svnrdump/jrn.git

for the tree.  The todo branch documents how to revive the
git-svn branches.

Have fun,
Jonathan

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

* Re: [PATCH svnrdump-standalone] Sync with upstream
  2010-08-07  2:30       ` Jonathan Nieder
@ 2010-08-07  2:47         ` Ramkumar Ramachandra
  2010-08-07  2:51         ` Ramkumar Ramachandra
  1 sibling, 0 replies; 26+ messages in thread
From: Ramkumar Ramachandra @ 2010-08-07  2:47 UTC (permalink / raw)
  To: Jonathan Nieder; +Cc: Git Mailing List

Hi Jonathan,

Jonathan Nieder writes:
> Jonathan Nieder wrote:
> 
> > Caveats: Most load tests do not pass.
> 
> They pass now.  Thanks for the help!

:)

> You can
> 
>   git clone git://repo.or.cz/svnrdump/jrn.git
> 
> for the tree.  The todo branch documents how to revive the
> git-svn branches.

Thanks for this- I can easily maintain an out-of-trunk version that
compiles against 1.6 now. Much nicer than your massive patches :)

-- Ram

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

* Re: [PATCH svnrdump-standalone] Sync with upstream
  2010-08-07  2:30       ` Jonathan Nieder
  2010-08-07  2:47         ` Ramkumar Ramachandra
@ 2010-08-07  2:51         ` Ramkumar Ramachandra
  1 sibling, 0 replies; 26+ messages in thread
From: Ramkumar Ramachandra @ 2010-08-07  2:51 UTC (permalink / raw)
  To: Jonathan Nieder; +Cc: Git Mailing List

Hi Jonathan,

Jonathan Nieder writes:
> for the tree.  The todo branch documents how to revive the
> git-svn branches.

Thanks especially for taking the effort to import the history from SVN
and write a nice NOTES file :)

-- Ram

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

end of thread, other threads:[~2010-08-07  2:52 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-07-13 23:36 [PATCH 0/9] Get svnrdump merged into git.git Ramkumar Ramachandra
2010-07-13 23:36 ` [PATCH 1/9] Add LICENSE Ramkumar Ramachandra
2010-07-14  4:47   ` Daniel Shahaf
2010-07-14 11:23     ` Ramkumar Ramachandra
2010-07-13 23:36 ` [PATCH 2/9] Add skeleton SVN client and Makefile Ramkumar Ramachandra
2010-07-13 23:36 ` [PATCH 3/9] Add debug editor from Subversion trunk Ramkumar Ramachandra
2010-07-13 23:36 ` [PATCH 4/9] Drive the debug editor Ramkumar Ramachandra
2010-07-13 23:36 ` [PATCH 5/9] Dump the revprops at the start of every revision Ramkumar Ramachandra
2010-07-13 23:36 ` [PATCH 6/9] Implement directory-related functions Ramkumar Ramachandra
2010-07-13 23:36 ` [PATCH 7/9] Implement file-related functions Ramkumar Ramachandra
2010-07-13 23:36 ` [PATCH 8/9] Implement close_file Ramkumar Ramachandra
2010-07-13 23:36 ` [PATCH 9/9] Add a validation script Ramkumar Ramachandra
2010-07-13 23:58 ` [PATCH 0/9] Get svnrdump merged into git.git Ramkumar Ramachandra
2010-07-14  0:15   ` Jonathan Nieder
2010-07-14  0:22     ` Ramkumar Ramachandra
2010-07-14  0:28       ` Jonathan Nieder
2010-07-14  0:49         ` Ramkumar Ramachandra
2010-07-14  7:03           ` Stefan Sperling
2010-07-14 11:26             ` Ramkumar Ramachandra
2010-07-14 12:55               ` Stefan Sperling
2010-07-14 14:54 ` Junio C Hamano
2010-07-15 10:55   ` Ramkumar Ramachandra
     [not found]     ` <20100806175709.GA2683@burratino>
2010-08-06 18:37       ` [PATCH svnrdump-standalone] Sync with upstream Jonathan Nieder
2010-08-07  2:30       ` Jonathan Nieder
2010-08-07  2:47         ` Ramkumar Ramachandra
2010-08-07  2:51         ` Ramkumar Ramachandra

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 NNTP newsgroup(s).