From: Jonathan Nieder <jrnieder@gmail.com>
To: Ramkumar Ramachandra <artagnon@gmail.com>
Cc: Git Mailing List <git@vger.kernel.org>
Subject: Re: [PATCH svnrdump-standalone] Sync with upstream
Date: Fri, 6 Aug 2010 13:37:36 -0500 [thread overview]
Message-ID: <20100806183736.GA2985@burratino> (raw)
In-Reply-To: <20100806175709.GA2683@burratino>
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
next prev parent reply other threads:[~2010-08-06 18:39 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
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 ` Jonathan Nieder [this message]
2010-08-07 2:30 ` [PATCH svnrdump-standalone] Sync with upstream Jonathan Nieder
2010-08-07 2:47 ` Ramkumar Ramachandra
2010-08-07 2:51 ` Ramkumar Ramachandra
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20100806183736.GA2985@burratino \
--to=jrnieder@gmail.com \
--cc=artagnon@gmail.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).