You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by pb...@apache.org on 2012/03/21 03:39:00 UTC
svn commit: r1303257 [1/4] - in /subversion/branches/inheritable-props: ./
build/ac-macros/ notes/ notes/directory-index/ notes/wc-ng/
subversion/bindings/swig/ruby/test/ subversion/include/
subversion/include/private/ subversion/libsvn_client/ subvers...
Author: pburba
Date: Wed Mar 21 02:38:58 2012
New Revision: 1303257
URL: http://svn.apache.org/viewvc?rev=1303257&view=rev
Log:
On the inheritable-props branch: Sync with ^/subversion/trunk through
r1303255.
Added:
subversion/branches/inheritable-props/subversion/libsvn_ra_serf/sb_bucket.c
- copied unchanged from r1303255, subversion/trunk/subversion/libsvn_ra_serf/sb_bucket.c
Modified:
subversion/branches/inheritable-props/ (props changed)
subversion/branches/inheritable-props/CHANGES
subversion/branches/inheritable-props/Makefile.in
subversion/branches/inheritable-props/build/ac-macros/serf.m4
subversion/branches/inheritable-props/configure.ac
subversion/branches/inheritable-props/notes/directory-index/dirindex.py
subversion/branches/inheritable-props/notes/directory-index/logimport.py
subversion/branches/inheritable-props/notes/directory-index/schema.sql
subversion/branches/inheritable-props/notes/ra-serf-testing.txt
subversion/branches/inheritable-props/notes/wc-ng/conflict-storage
subversion/branches/inheritable-props/subversion/bindings/swig/ruby/test/test_info.rb
subversion/branches/inheritable-props/subversion/include/private/svn_client_private.h
subversion/branches/inheritable-props/subversion/include/svn_client.h
subversion/branches/inheritable-props/subversion/include/svn_editor.h
subversion/branches/inheritable-props/subversion/include/svn_props.h
subversion/branches/inheritable-props/subversion/libsvn_client/commit.c
subversion/branches/inheritable-props/subversion/libsvn_client/deprecated.c
subversion/branches/inheritable-props/subversion/libsvn_client/merge.c
subversion/branches/inheritable-props/subversion/libsvn_client/prop_commands.c
subversion/branches/inheritable-props/subversion/libsvn_client/util.c
subversion/branches/inheritable-props/subversion/libsvn_delta/compat.c
subversion/branches/inheritable-props/subversion/libsvn_delta/editor.c
subversion/branches/inheritable-props/subversion/libsvn_fs_fs/dag.c
subversion/branches/inheritable-props/subversion/libsvn_fs_fs/dag.h
subversion/branches/inheritable-props/subversion/libsvn_fs_fs/fs.h
subversion/branches/inheritable-props/subversion/libsvn_fs_fs/tree.c
subversion/branches/inheritable-props/subversion/libsvn_ra_serf/blame.c
subversion/branches/inheritable-props/subversion/libsvn_ra_serf/commit.c
subversion/branches/inheritable-props/subversion/libsvn_ra_serf/getdate.c
subversion/branches/inheritable-props/subversion/libsvn_ra_serf/getlocks.c
subversion/branches/inheritable-props/subversion/libsvn_ra_serf/locks.c
subversion/branches/inheritable-props/subversion/libsvn_ra_serf/log.c
subversion/branches/inheritable-props/subversion/libsvn_ra_serf/merge.c
subversion/branches/inheritable-props/subversion/libsvn_ra_serf/options.c
subversion/branches/inheritable-props/subversion/libsvn_ra_serf/property.c
subversion/branches/inheritable-props/subversion/libsvn_ra_serf/ra_serf.h
subversion/branches/inheritable-props/subversion/libsvn_ra_serf/replay.c
subversion/branches/inheritable-props/subversion/libsvn_ra_serf/serf.c
subversion/branches/inheritable-props/subversion/libsvn_ra_serf/update.c
subversion/branches/inheritable-props/subversion/libsvn_ra_serf/util.c
subversion/branches/inheritable-props/subversion/libsvn_repos/fs-wrap.c
subversion/branches/inheritable-props/subversion/libsvn_subr/properties.c
subversion/branches/inheritable-props/subversion/libsvn_subr/spillbuf.c
subversion/branches/inheritable-props/subversion/libsvn_subr/svn_string.c
subversion/branches/inheritable-props/subversion/libsvn_wc/props.c
subversion/branches/inheritable-props/subversion/libsvn_wc/update_editor.c
subversion/branches/inheritable-props/subversion/svn/cl.h
subversion/branches/inheritable-props/subversion/svn/main.c
subversion/branches/inheritable-props/subversion/svn/merge-cmd.c
subversion/branches/inheritable-props/subversion/svnrdump/dump_editor.c
subversion/branches/inheritable-props/subversion/svnrdump/load_editor.c
subversion/branches/inheritable-props/subversion/svnsync/sync.c
subversion/branches/inheritable-props/subversion/tests/cmdline/merge_reintegrate_tests.py
subversion/branches/inheritable-props/subversion/tests/cmdline/merge_tests.py
subversion/branches/inheritable-props/subversion/tests/cmdline/svnadmin_tests.py
subversion/branches/inheritable-props/subversion/tests/cmdline/svntest/main.py
subversion/branches/inheritable-props/subversion/tests/cmdline/svntest/sandbox.py
subversion/branches/inheritable-props/subversion/tests/cmdline/tree_conflict_tests.py
subversion/branches/inheritable-props/subversion/tests/cmdline/update_tests.py
subversion/branches/inheritable-props/subversion/tests/libsvn_client/ (props changed)
subversion/branches/inheritable-props/subversion/tests/libsvn_wc/op-depth-test.c
subversion/branches/inheritable-props/tools/client-side/mergeinfo-sanitizer.py (contents, props changed)
Propchange: subversion/branches/inheritable-props/
------------------------------------------------------------------------------
Merged /subversion/trunk:r1301214-1303255
Modified: subversion/branches/inheritable-props/CHANGES
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/CHANGES?rev=1303257&r1=1303256&r2=1303257&view=diff
==============================================================================
--- subversion/branches/inheritable-props/CHANGES (original)
+++ subversion/branches/inheritable-props/CHANGES Wed Mar 21 02:38:58 2012
@@ -396,6 +396,11 @@ http://svn.apache.org/repos/asf/subversi
* plug a memory leak in the bdb backend (r1205726)
* server-side performance fix for "log -g" (r1152282)
* fix description of svndumpfilter's --targets option (r1151911)
+ * fix datastream corruption during resumed transfer in ra_serf (r1154733)
+ * fix a crash in ra_svn SASL authentication (r1166555, -678)
+ * fix potential corruption on 32-bit FSFS with large files (r1230212)
+ * make website links point to subversion.apache.org (r896893, -901, r915036)
+ * fix non-fatal FSFS corruption bug with concurrent commits (issue #4129)
Developer-visible changes:
* fix sqlite distfile retrieval in get-deps.sh (r1134734)
Modified: subversion/branches/inheritable-props/Makefile.in
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/Makefile.in?rev=1303257&r1=1303256&r2=1303257&view=diff
==============================================================================
--- subversion/branches/inheritable-props/Makefile.in (original)
+++ subversion/branches/inheritable-props/Makefile.in Wed Mar 21 02:38:58 2012
@@ -381,16 +381,18 @@ fast-clean: doc-clean
$(abs_srcdir)/build $(top_srcdir)/subversion/tests/cmdline/svntest \
-name "*.pyc" -exec rm {} ';'
-# clean all but bulky test output, returning to before './configure' was run.
+# clean everything, returning to before './configure' was run.
SVN_CONFIG_SCRIPT_FILES = @SVN_CONFIG_SCRIPT_FILES@
-fast-distclean: fast-clean
- rm -fr Makefile config.cache config.log config.nice config.status \
- libtool mkmf.log subversion/svn_private_config.h \
- subversion/bindings/javahl/classes subversion/bindings/javahl/include \
+local-distclean: local-clean
+ rm -fr config.cache config.log config.nice config.status \
+ libtool mkmf.log subversion/svn_private_config.h \
+ subversion/bindings/javahl/classes \
+ subversion/bindings/javahl/include \
$(SVN_CONFIG_SCRIPT_FILES)
+ rm -f Makefile
# clean everything out, returning to before './autogen.sh' was run.
-local-extraclean: local-distclean extraclean-swig extraclean-ctypes-python extraclean-javahl
+local-extraclean: extraclean-bindings local-distclean
rm -f $(top_srcdir)/build-outputs.mk \
$(top_srcdir)/subversion/svn_private_config.h.in \
$(top_srcdir)/configure \
@@ -408,10 +410,7 @@ local-extraclean: local-distclean extrac
# clean everything, including test output.
-local-clean: fast-clean check-clean clean-swig clean-ctypes-python clean-javahl
-
-# clean everything, including test output.
-local-distclean: fast-distclean check-clean
+local-clean: check-clean clean-bindings fast-clean
local-install: @INSTALL_RULES@
@@ -437,8 +436,6 @@ clean-javahl:
rm -f $(libsvnjavahl_PATH)/*.lo
rm -f $(libsvnjavahl_PATH)/*.o
-extraclean-javahl: clean-javahl
-
check-tigris-javahl: javahl-compat
@FIX_JAVAHL_LIB@
$(JAVA) "-Dtest.rootdir=$(javahl_test_rootdir)" "-Dtest.srcdir=$(javahl_test_srcdir)" "-Dtest.rooturl=$(BASE_URL)" "-Dtest.fstype=$(FS_TYPE)" -Djava.library.path=@JAVAHL_OBJDIR@:$(libdir) -classpath $(javahl_compat_tests_PATH):$(javahl_tests_CLASSPATH) "-Dtest.tests=$(JAVAHL_TESTS)" org.tigris.subversion.javahl.RunTests
@@ -575,36 +572,24 @@ external-all external-install:
done;
### apr-util relies on generated files in apr, so reverse the
-### list so that it is cleaned before apr.
-external-clean external-distclean:
+### list so that it is cleaned before apr. also note that Neon does
+### not have an extraclean target, so get "close" with distclean
+external-clean external-distclean external-extraclean:
@target=`echo $@ | sed s/external-//`; \
list='$(SVN_EXTERNAL_PROJECT_SUBDIRS)'; \
for i in $$list; do \
revlist="$$i $$revlist"; \
done; \
for i in $$revlist; do \
- echo "------ making $$target in $$i"; \
- (cd $$i && $(MAKE) $$target) || exit 1; \
- echo "------ completed $$target in $$i"; \
- done;
-
-### temporary hack. Neon does not have an "extraclean" and neither does db
-### If we don't have extraclean -- do the next best thing.
-external-extraclean:
- @list='$(SVN_EXTERNAL_PROJECT_SUBDIRS)'; \
- for i in $$list; do \
- revlist="$$i $$revlist"; \
- done; \
- for i in $$revlist; do \
- if test "$$i" = "neon" || test "$$i" = "db/dist"; then \
- echo "------ making distclean(no extraclean) in $$i"; \
+ if test "$$i" = "neon" -a "$$target" = "extraclean"; then \
+ echo "------ making distclean (no extraclean) in $$i"; \
(cd $$i && $(MAKE) distclean) || exit 1; \
- echo "------ completed distclean(no extraclean) in $$i"; \
+ echo "------ completed distclean (no extraclean) in $$i"; \
else \
- echo "------ making extraclean in $$i"; \
- (cd $$i && $(MAKE) extraclean) || exit 1; \
- echo "------ completed extraclean in $$i"; \
- fi; \
+ echo "------ making $$target in $$i"; \
+ (cd $$i && $(MAKE) $$target) || exit 1; \
+ echo "------ completed $$target in $$i"; \
+ fi; \
done;
@@ -729,10 +714,15 @@ install-man:
install-swig-py: install-swig-py-lib
install-swig-rb: install-swig-rb-lib
+clean-bindings: clean-swig clean-ctypes-python clean-javahl
+
+extraclean-bindings: clean-swig extraclean-swig-headers \
+ extraclean-swig-py extraclean-swig-rb \
+ extraclean-swig-pl \
+ clean-ctypes-python clean-javahl \
+
clean-swig: clean-swig-headers clean-swig-py clean-swig-rb clean-swig-pl
@rm -f .swig_checked
-extraclean-swig: extraclean-swig-headers extraclean-swig-py \
- extraclean-swig-rb extraclean-swig-pl
EXTRACLEAN_SWIG_HEADERS=rm -f $(SWIG_SRC_DIR)/proxy/*.swg
@@ -866,8 +856,6 @@ clean-ctypes-python:
cd $(CTYPES_PYTHON_SRC_DIR); \
$(PYTHON) setup.py clean --all
-extraclean-ctypes-python: clean-ctypes-python
-
# manually describe a dependency, which we won't otherwise detect
subversion/libsvn_wc/wc-queries.h: $(abs_srcdir)/subversion/libsvn_wc/wc-metadata.sql
Modified: subversion/branches/inheritable-props/build/ac-macros/serf.m4
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/build/ac-macros/serf.m4?rev=1303257&r1=1303256&r2=1303257&view=diff
==============================================================================
--- subversion/branches/inheritable-props/build/ac-macros/serf.m4 (original)
+++ subversion/branches/inheritable-props/build/ac-macros/serf.m4 Wed Mar 21 02:38:58 2012
@@ -32,14 +32,14 @@ AC_DEFUN(SVN_LIB_SERF,
serf_check_patch="$3"
AC_ARG_WITH(serf,AS_HELP_STRING([--with-serf=PREFIX],
- [Serf WebDAV client library]),
+ [Serf HTTP client library]),
[
if test "$withval" = "yes" ; then
AC_MSG_ERROR([--with-serf requires an argument.])
elif test "$withval" != "no" ; then
AC_MSG_NOTICE([serf library configuration])
serf_prefix=$withval
- for serf_major in serf-2 serf-1 serf-0; do
+ for serf_major in serf-2 serf-1; do
if ! test -d $serf_prefix/include/$serf_major; then continue; fi
save_cppflags="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $SVN_APR_INCLUDES $SVN_APRUTIL_INCLUDES -I$serf_prefix/include/$serf_major"
@@ -62,20 +62,7 @@ AC_DEFUN(SVN_LIB_SERF,
test $serf_found = yes && break
done
fi
- ], [
- if test -d "$srcdir/serf"; then
- serf_found=reconfig
- fi
- ])
-
-
- if test $serf_found = "reconfig"; then
- SVN_EXTERNAL_PROJECT([serf], [--with-apr=$apr_config --with-apr-util=$apu_config])
- serf_major=serf-`$srcdir/serf/build/get-version.sh major $srcdir/serf/serf.h SERF`
- serf_prefix=$prefix
- SVN_SERF_INCLUDES="-I$srcdir/serf"
- SVN_SERF_LIBS="$abs_builddir/serf/lib$serf_major.la"
- fi
+ ])
if test $serf_found = "yes"; then
SVN_SERF_INCLUDES="-I$serf_prefix/include/$serf_major"
@@ -85,8 +72,6 @@ AC_DEFUN(SVN_LIB_SERF,
SVN_SERF_LIBS="-l$serf_major"
LDFLAGS="$LDFLAGS -L$serf_prefix/lib"
fi
- elif test $serf_found = "reconfig"; then
- serf_found=yes
fi
svn_lib_serf=$serf_found
Modified: subversion/branches/inheritable-props/configure.ac
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/configure.ac?rev=1303257&r1=1303256&r2=1303257&view=diff
==============================================================================
--- subversion/branches/inheritable-props/configure.ac (original)
+++ subversion/branches/inheritable-props/configure.ac Wed Mar 21 02:38:58 2012
@@ -138,7 +138,7 @@ if test "$svn_lib_neon" = "yes"; then
fi
dnl Search for serf as an alternative to neon
-SVN_LIB_SERF(0,7,1)
+SVN_LIB_SERF(1,0,0)
if test "$svn_lib_serf" = "yes"; then
AC_DEFINE([SVN_HAVE_SERF], 1,
Modified: subversion/branches/inheritable-props/notes/directory-index/dirindex.py
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/notes/directory-index/dirindex.py?rev=1303257&r1=1303256&r2=1303257&view=diff
==============================================================================
--- subversion/branches/inheritable-props/notes/directory-index/dirindex.py (original)
+++ subversion/branches/inheritable-props/notes/directory-index/dirindex.py Wed Mar 21 02:38:58 2012
@@ -23,10 +23,64 @@ import sqlite3
class Error(Exception):
- pass
+ def __init__(self, msg, *args, **kwargs):
+ opcode = kwargs.pop("action", None)
+ if opcode is not None:
+ msg = Dirent._opname(opcode) + msg
+ super(Error, self).__init__(msg, *args, **kwargs)
+
+
+class SQL(object):
+ """Named index of SQL schema definitions and statements.
+
+ Parses "schema.sql" and creates a class-level attribute for each
+ script and statement in that file.
+ """
+
+ @classmethod
+ def _load_statements(cls):
+ import cStringIO
+ import pkgutil
+ import re
+
+ comment_rx = re.compile(r"\s*--.*$")
+ header_rx = re.compile(r"^---(STATEMENT|SCRIPT)"
+ r"\s+(?P<name>[_A-Z]+)$")
+
+ name = None
+ content = None
+
+ def record_current_statement():
+ if name is not None:
+ setattr(cls, name, content.getvalue())
+
+ schema = cStringIO.StringIO(pkgutil.get_data(__name__, "schema.sql"))
+ for line in schema:
+ line = line.rstrip()
+ if not line:
+ continue
+
+ header = header_rx.match(line)
+ if header:
+ record_current_statement()
+ name = header.group("name")
+ content = cStringIO.StringIO()
+ continue
+
+ line = comment_rx.sub("", line)
+ if not line:
+ continue
+
+ if content is not None:
+ content.write(line)
+ content.write("\n")
+ record_current_statement()
+SQL._load_statements()
class SQLobject(object):
+ """Base for ORM abstractions."""
+
__slots__ = ()
def __init__(self, **kwargs):
for name, val in kwargs.items():
@@ -68,91 +122,105 @@ class SQLobject(object):
class Revent(SQLobject):
+ """O/R mapping for the "revision" table."""
+
__slots__ = ("version", "created", "author", "log")
def _put(self, cursor):
if self.created is None:
now = datetime.datetime.utcnow()
self.created = now.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
- self._execute(cursor,
- "INSERT INTO revision (version, created, author, log)"
- " VALUES (?, ?, ?, ?)",
+ self._execute(cursor, SQL.INSERT_REVISION_RECORD,
[self.version, self.created, self.author, self.log])
@classmethod
def _get(cls, cursor, pkey):
- cursor.execute("SELECT * FROM revision WHERE version = ?", [pkey])
+ cursor.execute(SQL.GET_REVENT_BY_VERSION, [pkey])
return cls._from_row(cursor.fetchone())
-class Pathent(SQLobject):
- __slots__ = ("pathid", "abspath")
+class Strent(SQLobject):
+ """O/R mapping for the "strindex" table."""
+
+ __slots__ = ("strid", "content")
def _put(self, cursor):
- self._execute(cursor,
- "INSERT INTO pathindex (abspath) VALUES (?)",
- [self.abspath])
- self.pathid = cursor.lastrowid
+ self._execute(cursor, SQL.INSERT_STRINDEX_RECORD, [self.content])
+ self.strid = cursor.lastrowid
@classmethod
def _get(cls, cursor, pkey):
- cls._execute(cursor,
- "SELECT * FROM pathindex WHERE pathid = ?",
- [pkey])
+ cls._execute(cursor, SQL.GET_STRENT_BY_STRID, [pkey])
return cls._from_row(cursor.fetchone())
@classmethod
- def _find(cls, cursor, abspath):
- cls._execute(cursor,
- "SELECT * FROM pathindex WHERE abspath = ?",
- [abspath])
+ def _find(cls, cursor, content):
+ cls._execute(cursor, SQL.GET_STRENT_BY_CONTENT, [content])
return cls._from_row(cursor.fetchone())
class Dirent(SQLobject):
- __slots__ = ("rowid", "pathid", "version", "deleted",
- "kind", "origin", "copied", "subtree",
+ """O/R mapping for a virtual non-materialized view representing
+ a join of the "dirindex" and "strindex" tables."""
+
+ __slots__ = ("rowid", "origin", "pathid", "version",
+ "kind", "opcode", "subtree",
"abspath")
+ # Kinds
+ DIR = "D"
+ FILE = "F"
+
+ # Opcodes
+ ADD = "A"
+ REPLACE = "R"
+ MODIFY = "M"
+ DELETE = "D"
+ RENAME = "N"
+
+ # Opcode names
+ __opnames = {ADD: "add",
+ REPLACE: "replace",
+ MODIFY: "modify",
+ DELETE: "delete",
+ RENAME: "rename"}
+
+ @classmethod
+ def _opname(cls, opcode):
+ return cls.__opnames.get(opcode)
+
+ @property
+ def _deleted(self):
+ return (self.opcode == self.DELETE)
+
def __str__(self):
- return "%3d %c%c %s" % (
+ return "%d %c%c%c %c %s" % (
self.version,
- self.deleted and "x" or " ",
- self.kind and "f" or "d",
- self.abspath)
+ self.subtree and "(" or " ",
+ self.opcode,
+ self.subtree and ")" or " ",
+ self.kind, self.abspath)
def _put(self, cursor):
- pathent = Pathent._find(cursor, self.abspath)
- if pathent is None:
- pathent = Pathent(abspath = self.abspath)
- pathent._put(cursor)
- self._execute(cursor,
- "INSERT INTO dirindex"
- " (pathid, version, deleted,"
- " kind, origin, copied, subtree)"
- " VALUES (?, ?, ?, ?, ?, ?, ?)",
- [pathent.pathid, self.version, self.deleted,
- self.kind, self.origin, self.copied, self.subtree])
+ strent = Strent._find(cursor, self.abspath)
+ if strent is None:
+ strent = Strent(content = self.abspath)
+ strent._put(cursor)
+ self._execute(cursor, SQL.INSERT_DIRINDEX_RECORD,
+ [self.origin, strent.strid, self.version,
+ self.kind, self.opcode,self.subtree])
self.rowid = cursor.lastrowid
- self.pathid = pathent.pathid
+ self.pathid = strent.strid
@classmethod
def _get(cls, cursor, pkey):
- cls._execute(cursor,
- "SELECT dirindex.*, pathindex.abspath"
- " FROM dirindex JOIN pathindex"
- " ON dirindex.pathid = pathindex.pathid"
- " WHERE dirindex.rowid = ?", [pkey])
+ cls._execute(cursor, SQL.GET_DIRENT_BY_ROWID, [pkey])
return cls._from_row(cursor.fetchone())
@classmethod
def _find(cls, cursor, abspath, version):
cls._execute(cursor,
- "SELECT dirindex.*, pathindex.abspath"
- " FROM dirindex JOIN pathindex"
- " ON dirindex.pathid = pathindex.pathid"
- " WHERE pathindex.abspath = ?"
- " AND dirindex.version = ?",
+ SQL.GET_DIRENT_BY_ABSPATH_AND_VERSION,
[abspath, version])
return cls._from_row(cursor.fetchone())
@@ -162,53 +230,27 @@ class Index(object):
self.conn = sqlite3.connect(database, isolation_level = "IMMEDIATE")
self.conn.row_factory = sqlite3.Row
self.cursor = self.conn.cursor()
+ self.cursor.execute("PRAGMA page_size = 4096")
+ self.cursor.execute("PRAGMA temp_store = MEMORY")
self.cursor.execute("PRAGMA foreign_keys = ON")
self.cursor.execute("PRAGMA case_sensitive_like = ON")
self.cursor.execute("PRAGMA encoding = 'UTF-8'")
- __schema = """
-DROP TABLE IF EXISTS dirindex;
-DROP TABLE IF EXISTS pathindex;
-DROP TABLE IF EXISTS revision;
-
-CREATE TABLE revision (
- version integer NOT NULL PRIMARY KEY,
- created timestamp NOT NULL,
- author varchar NULL,
- log varchar NULL
-);
-
-CREATE TABLE pathindex (
- pathid integer NOT NULL PRIMARY KEY,
- abspath varchar NOT NULL UNIQUE
-);
-
-CREATE TABLE dirindex (
- rowid integer NOT NULL PRIMARY KEY,
- pathid integer NOT NULL REFERENCES pathindex(pathid),
- version integer NOT NULL REFERENCES revision(version),
- deleted boolean NOT NULL,
- kind integer NOT NULL,
- origin integer NULL REFERENCES dirindex(rowid),
- copied boolean NOT NULL,
- subtree boolean NOT NULL
-);
-CREATE UNIQUE INDEX dirindex_versioned_tree ON dirindex(pathid, version DESC);
-CREATE INDEX dirindex_successor_list ON dirindex(origin);
-CREATE INDEX dirindex_deleted ON dirindex(deleted);
-
-INSERT INTO revision (version, created, author, log)
- VALUES (0, 'EPOCH', NULL, NULL);
-INSERT INTO pathindex (pathid, abspath) VALUES (0, '/');
-INSERT INTO dirindex (rowid, pathid, version, deleted,
- kind, origin, copied, subtree)
- VALUES (0, 0, 0, 0, 0, NULL, 0, 0);
-"""
+ @staticmethod
+ def normpath(abspath):
+ return abspath.rstrip("/")
+
+ @staticmethod
+ def subtree_pattern(abspath):
+ return (abspath.rstrip("/")
+ .replace("#", "##")
+ .replace("%", "#%")
+ .replace("_", "#_")) + "/%"
def initialize(self):
try:
- SQLobject._log("%s", self.__schema)
- self.cursor.executescript(self.__schema)
+ SQLobject._log("%s", SQL.CREATE_SCHEMA)
+ self.cursor.executescript(SQL.CREATE_SCHEMA)
self.commit()
finally:
self.rollback()
@@ -245,34 +287,20 @@ INSERT INTO dirindex (rowid, pathid, ver
def lookup(self, abspath, version):
SQLobject._execute(
self.cursor,
- "SELECT dirindex.*, pathindex.abspath FROM dirindex"
- " JOIN pathindex ON dirindex.pathid = pathindex.pathid"
- " WHERE pathindex.abspath = ? AND dirindex.version <= ?"
- " ORDER BY pathindex.abspath ASC, dirindex.version DESC"
- " LIMIT 1",
+ SQL.LOOKUP_ABSPATH_AT_REVISION,
[abspath, version])
row = self.cursor.fetchone()
- if row is not None and not row["deleted"]:
- return Dirent._from_row(row)
+ if row is not None:
+ dirent = Dirent._from_row(row)
+ if not dirent._deleted:
+ return dirent
return None
def subtree(self, abspath, version):
- pattern = (abspath.rstrip("/")
- .replace("#", "##")
- .replace("%", "#%")
- .replace("_", "#_")) + "/%"
SQLobject._execute(
self.cursor,
- "SELECT dirindex.*, pathindex.abspath FROM dirindex"
- " JOIN pathindex ON dirindex.pathid = pathindex.pathid"
- " JOIN (SELECT pathid, MAX(version) AS maxver FROM dirindex"
- " WHERE version <= ? GROUP BY pathid) AS filtered"
- " ON dirindex.pathid == filtered.pathid"
- " AND dirindex.version == filtered.maxver"
- " WHERE pathindex.abspath LIKE ? ESCAPE '#'"
- " AND NOT dirindex.deleted"
- " ORDER BY pathindex.abspath ASC",
- [version, pattern])
+ SQL.LIST_SUBTREE_AT_REVISION,
+ [version, self.subtree_pattern(abspath)])
for row in self.cursor:
yield Dirent._from_row(row)
@@ -286,10 +314,7 @@ INSERT INTO dirindex (rowid, pathid, ver
assert isinstance(dirent, Dirent)
SQLobject._execute(
self.cursor,
- "SELECT dirindex.*, pathindex.abspath FROM dirindex"
- " JOIN pathindex ON dirindex.pathid = pathindex.pathid"
- " WHERE dirindex.origin = ?"
- " ORDER BY pathindex.abspath ASC, dirindex.version ASC",
+ SQL.LIST_DIRENT_SUCCESSORS,
[dirent.rowid])
for row in self.cursor:
yield Dirent._from_row(row)
@@ -307,157 +332,218 @@ class Revision(object):
self.__context = None
index.rollback()
+ class __Context(object):
+ def __init__(self, version, connection):
+ self.version = version
+ self.conn = connection
+ self.cursor = connection.cursor()
+ SQLobject._execute(self.cursor, SQL.CREATE_TRANSACTION_CONTEXT)
+
+ def clear(self):
+ SQLobject._execute(self.cursor, SQL.REMOVE_TRANSACTION_CONTEXT)
+
+ def __iter__(self):
+ SQLobject._execute(self.cursor, SQL.LIST_TRANSACTION_RECORDS)
+ for row in self.cursor:
+ dirent = Dirent._from_row(row)
+ dirent.version = self.version
+ yield dirent
+
+ def lookup(self, abspath):
+ SQLobject._execute(self.cursor,
+ SQL.GET_TRANSACTION_RECORD,
+ [abspath])
+ row = self.cursor.fetchone()
+ if row is not None:
+ dirent = Dirent._from_row(row)
+ dirent.version = self.version
+ return dirent
+ return None
+
+ def remove(self, abspath, purge=False):
+ target = self.lookup(abspath)
+ if not target:
+ raise Error("txn context: remove nonexistent " + abspath)
+ logging.debug("txn context: remove %s", abspath)
+ SQLobject._execute(self.cursor,
+ SQL.REMOVE_TRANSACTION_RECORD,
+ [abspath])
+ if purge:
+ logging.debug("txn context: purge %s/*", abspath)
+ SQLobject._execute(self.cursor,
+ SQL.REMOVE_TRANSACTION_SUBTREE,
+ [Index.subtree_pattern(abspath)])
+
+ def record(self, dirent, replace=False, purge=False):
+ target = self.lookup(dirent.abspath)
+ if target is not None:
+ if not replace:
+ raise Error("txn context: record existing "
+ + dirent.abspath)
+ elif not target.subtree:
+ raise Error("txn context: replace conflict "
+ + dirent.abspath)
+ self.remove(target.abspath, purge and target.kind == Dirent.DIR)
+ SQLobject._execute(self.cursor,
+ SQL.INSERT_TRANSACTION_RECORD,
+ [dirent.origin, dirent.abspath,
+ dirent.kind, dirent.opcode, dirent.subtree])
+
def __enter__(self):
if self.revent is not None:
raise Error("revision is read-only")
- SQLobject._log("BEGIN")
+ self.__context = self.__Context(self.version, self.index.conn)
+ SQLobject._execute(self.index.cursor, "BEGIN")
self.revent = self.index.new_revision(
self.version, self.__created, self.__author, self.__log)
- self.__context = {}
return self
def __exit__(self, exc_type, exc_value, traceback):
try:
- if exc_type is None and len(self.__context):
- for dirent in sorted(self.__context.itervalues()):
+ if exc_type is None:
+ for dirent in self.__context:
self.index.insert(dirent)
+ logging.debug("insert: %s", dirent)
self.index.commit()
+ else:
+ self.index.rollback()
except:
self.index.rollback()
raise
finally:
+ self.__context.clear()
self.__context = None
- def __record(self, dirent, action):
- self.__context[dirent.abspath] = dirent
- if dirent.subtree:
- action = "(%s)" % action
- else:
- action = " %s " % action
- logging.debug(" %-9s %s", action, dirent)
+ def __record(self, dirent, replace=False, purge=False):
+ self.__context.record(dirent, replace, purge)
+ logging.debug("record: %s", dirent)
- def __check_writable(self, action):
+ def __check_writable(self, opcode):
if self.__context is None:
- raise Error(action + " requires a transaction")
+ raise Error(" requires a transaction", action=opcode)
- def __check_not_root(self, abspath, action):
+ def __check_not_root(self, abspath, opcode):
if abspath.rstrip("/") == "":
- raise Error(action + " not allowed on /")
+ raise Error(" not allowed on /", action=opcode)
- def __find_target(self, abspath, action):
- target = self.__context.get(abspath)
- if target is not None and not target.subtree:
- raise Error(action + " overrides explicit " + abspath)
- if target is None:
- target = self.index.lookup(abspath, self.version - 1)
+ def __find_target(self, abspath, opcode):
+ target = self.__context.lookup(abspath)
+ if target is not None:
+ if not target.subtree:
+ raise Error(" overrides explicit " + abspath, action=opcode)
+ return target, target.origin
+ target = self.index.lookup(abspath, self.version - 1)
if target is None:
- raise Error(action + " target does not exist: " + abspath)
- return target
+ raise Error(" target does not exist: " + abspath, action=opcode)
+ return target, target.rowid
def lookup(self, abspath):
try:
- return self.index.lookup(abspath, self.version)
+ return self.index.lookup(self.index.normpath(abspath),
+ self.version)
finally:
if self.__context is None:
self.index.rollback()
- def __add(self, action, abspath, kind, frompath, fromver):
+ def __add(self, opcode, abspath, kind, frompath, fromver):
origin = None
if frompath is not None:
+ frompath = self.index.normpath(frompath)
+ fromver = int(fromver)
origin = self.index.lookup(frompath, fromver)
if origin is None:
- raise Error(action + " source does not exist: " + frompath)
+ raise Error(" source does not exist: " + frompath, action=opcode)
if origin.kind != kind:
- raise Error(action + " changes the source object kind")
+ raise Error(" changes the source object kind", action=opcode)
origin = origin.rowid
- dirent = Dirent(abspath = abspath,
+ dirent = Dirent(origin = origin,
+ abspath = abspath,
version = self.version,
- deleted = 0,
kind = kind,
- origin = origin,
- copied = int(origin is not None),
+ opcode = opcode,
subtree = 0)
- self.__record(dirent, action)
- if frompath is not None:
- offset = len(frompath.rstrip("/"))
- prefix = abspath.rstrip("/")
- for source in self.index.subtree(frompath, fromver):
- dirent = Dirent(rowid = source.rowid,
- abspath = prefix + source.abspath[offset:],
- version = self.version,
- deleted = 0,
- kind = source.kind,
- origin = source.rowid,
- copied = 1,
- subtree = 1)
- self.__record(dirent, action)
+ self.__record(dirent,
+ replace=(opcode == Dirent.REPLACE),
+ purge=(opcode == Dirent.REPLACE))
+ if frompath is not None and dirent.kind == Dirent.DIR:
+ prefix = dirent.abspath
+ offset = len(frompath)
+ for source in list(self.index.subtree(frompath, fromver)):
+ abspath = prefix + source.abspath[offset:]
+ self.__record(Dirent(origin = source.rowid,
+ abspath = abspath,
+ version = self.version,
+ kind = source.kind,
+ opcode = opcode,
+ subtree = 1))
def add(self, abspath, kind, frompath=None, fromver=None):
- action = "add"
- self.__check_writable(action)
- self.__check_not_root(abspath, action)
- return self.__add(action, abspath, kind, frompath, fromver)
+ opcode = Dirent.ADD
+ abspath = self.index.normpath(abspath)
+ self.__check_writable(opcode)
+ self.__check_not_root(abspath, opcode)
+ return self.__add(opcode, abspath, kind, frompath, fromver)
def replace(self, abspath, kind, frompath=None, fromver=None):
- action = "replace"
- self.__check_writable(action)
- self.__check_not_root(abspath, action)
- self.__find_target(abspath, action)
- return self.__add(action, abspath, kind, frompath, fromver)
+ opcode = Dirent.REPLACE
+ abspath = self.index.normpath(abspath)
+ self.__check_writable(opcode)
+ self.__check_not_root(abspath, opcode)
+ self.__find_target(abspath, opcode)
+ return self.__add(opcode, abspath, kind, frompath, fromver)
def modify(self, abspath):
- action = "modify"
- self.__check_writable(action)
- target = self.__find_target(abspath, action)
- dirent = Dirent(abspath = abspath,
+ opcode = Dirent.MODIFY
+ abspath = self.index.normpath(abspath)
+ self.__check_writable(opcode)
+ target, origin = self.__find_target(abspath, opcode)
+ dirent = Dirent(origin = origin,
+ abspath = abspath,
version = self.version,
- deleted = 0,
kind = target.kind,
- origin = target.rowid,
- copied = 0,
+ opcode = opcode,
subtree = 0)
- self.__record(dirent, action)
+ self.__record(dirent, replace=True)
def delete(self, abspath):
- action = "replace"
- self.__check_writable(action)
- self.__check_not_root(abspath, action)
- target = self.__find_target(abspath, action)
- dirent = Dirent(abspath = abspath,
+ opcode = Dirent.DELETE
+ abspath = self.index.normpath(abspath)
+ self.__check_writable(opcode)
+ self.__check_not_root(abspath, opcode)
+ target, origin = self.__find_target(abspath, opcode)
+ dirent = Dirent(origin = origin,
+ abspath = abspath,
version = self.version,
- deleted = 1,
kind = target.kind,
- origin = target.rowid,
- copied = 0,
+ opcode = opcode,
subtree = 0)
- self.__record(dirent, action)
- for source in self.index.subtree(abspath, self.version - 1):
- dirent = Dirent(rowid = source.rowid,
- abspath = source.abspath,
- version = self.version,
- deleted = 1,
- kind = source.kind,
- origin = source.rowid,
- copied = 0,
- subtree = 1)
- self.__record(dirent, action)
+ self.__record(dirent, replace=True, purge=True)
+ if target.version < self.version and dirent.kind == Dirent.DIR:
+ for source in self.index.subtree(abspath, self.version - 1):
+ self.__record(Dirent(origin = source.rowid,
+ abspath = source.abspath,
+ version = self.version,
+ kind = source.kind,
+ opcode = opcode,
+ subtree = 1))
def simpletest(database):
ix = Index(database)
ix.initialize()
with Revision(ix, 1) as rev:
- rev.add(u'/A', 0)
- rev.add(u'/A/B', 0)
- rev.add(u'/A/B/c', 1)
+ rev.add(u'/A', Dirent.DIR)
+ rev.add(u'/A/B', Dirent.DIR)
+ rev.add(u'/A/B/c', Dirent.FILE)
with Revision(ix, 2) as rev:
- rev.add(u'/A/B/d', 1)
+ rev.add(u'/A/B/d', Dirent.FILE)
with Revision(ix, 3) as rev:
- rev.add(u'/X', 0, u'/A', 1)
- rev.add(u'/X/B/d', 1, u'/A/B/d', 2)
+ rev.add(u'/X', Dirent.DIR, u'/A', 1)
+ rev.add(u'/X/B/d', Dirent.FILE, u'/A/B/d', 2)
with Revision(ix, 4) as rev:
+ # rev.rename(u'/X/B/d', u'/X/B/x')
rev.delete(u'/X/B/d')
- rev.add(u'/X/B/x', 1, u'/X/B/d', 3)
+ rev.add(u'/X/B/x', Dirent.FILE, u'/X/B/d', 3)
with Revision(ix, 5) as rev:
rev.delete(u'/A')
@@ -474,12 +560,13 @@ def simpletest(database):
print "/A/B/c@4 -> %s@%d" % (dirent.abspath, dirent.version)
for succ in ix.successors(dirent):
print "%11s %s %s@%d" % (
- "", succ.deleted and "x_x" or "-->",
+ "", succ._deleted and "x_x" or "-->",
succ.abspath, succ.version)
ix.close()
def loggedsimpletest(database):
import sys
- logging.basicConfig(level=SQLobject.LOGLEVEL, stream=sys.stderr)
+ logging.basicConfig(level=logging.DEBUG, #SQLobject.LOGLEVEL,
+ stream=sys.stderr)
simpletest(database)
Modified: subversion/branches/inheritable-props/notes/directory-index/logimport.py
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/notes/directory-index/logimport.py?rev=1303257&r1=1303256&r2=1303257&view=diff
==============================================================================
--- subversion/branches/inheritable-props/notes/directory-index/logimport.py (original)
+++ subversion/branches/inheritable-props/notes/directory-index/logimport.py Wed Mar 21 02:38:58 2012
@@ -16,7 +16,11 @@
# specific language governing permissions and limitations
# under the License.
-# Usage: logimport <database-name> <repoa-url> [path-to-svn]
+# Usage: logimport [options] <database-name> <repoa-url>
+# Options:
+# --svn=PATH Use a non-default svn binary
+# --debug Enable debug-level logging to logimport.debug.log
+# --sqldebug Enable SQL-level logging to logimport.sql.log
#
# Converts the history of the repository at <repos-url> into a
# single-tree directory index.
@@ -31,11 +35,11 @@ try:
except ImportError:
from xml.etree.ElementTree import iterparse
-from dirindex import Index, Revision
+from dirindex import Dirent, Index, Revision
def parse(index, stream):
- kindmap = {"dir": 0, "file": 1}
+ kindmap = {"dir": Dirent.DIR, "file": Dirent.FILE}
version = None
revcount = 0
@@ -46,11 +50,11 @@ def parse(index, stream):
version = int(logentry.get("revision"))
revcount += 1
- if revcount == 1 or not revcount % 1000:
- revlogger = logging.info
+ if revcount == 1:
+ logging.info("initial: r%d", version)
else:
- revlogger = logging.debug
- revlogger("%d: r%d", revcount, version)
+ logger = not revcount % 1000 and logging.info or logging.debug
+ logger("%d: r%d", revcount, version)
created = logentry.find("date")
if created is not None:
@@ -77,7 +81,7 @@ def parse(index, stream):
action = path.get("action")
handler, newnode = actionmap[action]
if not newnode:
- logging.debug(" %-s %s", action, abspath)
+ logging.debug(" %s %s", action, abspath)
handler(abspath)
continue
@@ -98,24 +102,83 @@ def parse(index, stream):
def logimport(database, url, svn):
- index = Index(database)
- index.initialize()
- index.cursor.execute("PRAGMA journal_mode = MEMORY")
- index.cursor.execute("PRAGMA locking_mode = EXCLUSIVE")
- index.cursor.execute("PRAGMA synchronous = OFF")
- svnlog = subprocess.Popen(
- [svn, "log", "-v", "--xml", "-r1:HEAD", url],
- stdout = subprocess.PIPE)
- parse(index, svnlog.stdout)
- sys.exit(svnlog.wait())
+ try:
+ index = Index(database)
+ index.cursor.execute("PRAGMA journal_mode = MEMORY")
+ index.cursor.execute("PRAGMA locking_mode = EXCLUSIVE")
+ index.cursor.execute("PRAGMA synchronous = OFF")
+ index.cursor.execute("PRAGMA cache_size = -100000")
+ index.initialize()
+ svnlog = subprocess.Popen(
+ [svn, "log", "-v", "--xml", "-r1:HEAD", url],
+ stdout = subprocess.PIPE)
+ parse(index, svnlog.stdout)
+ return svnlog.wait()
+ except:
+ logging.exception("logimport failed")
+ try:
+ svnlog.wait()
+ except:
+ pass
+ return 2
+
+
+def main():
+ import logging.config
+ from optparse import OptionParser
+ from dirindex import SQLobject
+
+ parser = OptionParser("Usage: %prog [options] <database-name> <repoa-url>")
+ parser.add_option("--svn", action="store", default="svn",
+ help="Use a non-default svn binary", metavar="PATH")
+ parser.add_option("--debug", action="store_true", default=False,
+ help="Enable debug-level logging to logimport.debug.log")
+ parser.add_option("--sqldebug", action="store_true", default=False,
+ help="Enable SQL-level logging to logimport.debug.log")
+
+ opts, args = parser.parse_args()
+ if len(args) != 2:
+ parser.error("wrong number of arguments")
+ database, url = args
+
+ logconfig = {
+ "version": 1,
+ "formatters": {
+ "console": {"format": "%(levelname)-7s %(message)s"},
+ "logfile": {"format": "%(asctime)s %(levelname)-7s %(message)s"}},
+ "handlers": {
+ "console": {
+ "class": "logging.StreamHandler",
+ "level": logging.INFO,
+ "stream": sys.stderr,
+ "formatter": "console"}},
+ "root": {
+ "level": logging.INFO,
+ "handlers": ["console"]}}
+
+ handlers = logconfig["root"]["handlers"]
+ if opts.debug:
+ logconfig["root"]["level"] = logging.DEBUG
+ logconfig["handlers"]["debug"] = {
+ "class": "logging.FileHandler",
+ "level": logging.DEBUG,
+ "mode": "w",
+ "filename": "./logimport.debug.log",
+ "formatter": "logfile"}
+ handlers.append("debug")
+ if opts.sqldebug:
+ logconfig["root"]["level"] = SQLobject.LOGLEVEL
+ logconfig["handlers"]["sqldebug"] = {
+ "class": "logging.FileHandler",
+ "level": SQLobject.LOGLEVEL,
+ "mode": "w",
+ "filename": "./logimport.sql.log",
+ "formatter": "logfile"}
+ handlers.append("sqldebug")
+
+ logging.config.dictConfig(logconfig)
+ sys.exit(logimport(database, url, opts.svn))
if __name__ == "__main__":
- database = sys.argv[1]
- url = sys.argv[2]
- if len(sys.argv) > 3:
- svn = sys.argv[3]
- else:
- svn = "svn"
- logging.basicConfig(level=logging.INFO, stream=sys.stderr)
- logimport(database, url, svn)
+ main()
Modified: subversion/branches/inheritable-props/notes/directory-index/schema.sql
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/notes/directory-index/schema.sql?rev=1303257&r1=1303256&r2=1303257&view=diff
==============================================================================
--- subversion/branches/inheritable-props/notes/directory-index/schema.sql (original)
+++ subversion/branches/inheritable-props/notes/directory-index/schema.sql Wed Mar 21 02:38:58 2012
@@ -16,6 +16,15 @@
-- specific language governing permissions and limitations
-- under the License.
+
+---SCRIPT CREATE_SCHEMA
+
+DROP TABLE IF EXISTS dirindex;
+DROP TABLE IF EXISTS strindex;
+DROP TABLE IF EXISTS revision;
+
+-- Revision record
+
CREATE TABLE revision (
version integer NOT NULL PRIMARY KEY,
created timestamp NOT NULL,
@@ -23,73 +32,152 @@ CREATE TABLE revision (
log varchar NULL
);
-CREATE TABLE pathindex (
- pathid integer NOT NULL PRIMARY KEY,
- abspath varchar NOT NULL UNIQUE
+-- Path lookup table
+
+CREATE TABLE strindex (
+ strid integer NOT NULL PRIMARY KEY,
+ content varchar NOT NULL UNIQUE
);
+-- Versioned directory tree
+
CREATE TABLE dirindex (
-- unique id of this node revision, used for
-- predecessor/successor links
rowid integer NOT NULL PRIMARY KEY,
+ -- link to this node's immediate predecessor
+ origin integer NULL REFERENCES dirindex(rowid),
+
-- absolute (repository) path
- pathid integer NOT NULL REFERENCES pathindex(pathid),
+ pathid integer NOT NULL REFERENCES strindex(strid),
-- revision number
version integer NOT NULL REFERENCES revision(version),
- -- node deletion flag
- deleted boolean NOT NULL,
-
- -- node kind (0 = dir, 1 = file, etc.)
- kind integer NOT NULL,
-
- -- predecessor link
- origin integer NULL REFERENCES dirindex(rowid),
+ -- node kind (D = dir, F = file, etc.)
+ kind character(1) NOT NULL,
- -- the predecessor is a copy source
- copied boolean NOT NULL,
+ -- the operation that produced this entry:
+ -- A = add, R = replace, M = modify, D = delete, N = rename
+ opcode character(1) NOT NULL,
-- the index entry is the result of an implicit subtree operation
subtree boolean NOT NULL
);
CREATE UNIQUE INDEX dirindex_versioned_tree ON dirindex(pathid, version DESC);
CREATE INDEX dirindex_successor_list ON dirindex(origin);
-CREATE INDEX dirindex_deleted ON dirindex(deleted);
+CREATE INDEX dirindex_operation ON dirindex(opcode);
+
+-- Repository root
--- repository root
INSERT INTO revision (version, created, author, log)
VALUES (0, 'EPOCH', NULL, NULL);
-INSERT INTO pathindex (pathid, abspath) VALUES (0, '/');
-INSERT INTO dirindex (rowid, pathid, version, deleted,
- kind, origin, copied, subtree)
- VALUES (0, 0, 0, 0, 0, NULL, 0, 0);
-
-
--- lookup PATH@REVISION
-
-SELECT
- dirindex.*, pathindex.abspath
-FROM dirindex JOIN pathindex
- ON dirindex.pathid = pathindex.pathid
-WHERE
- pathindex.abspath = '' -- $PATH
- AND dirindex.version <= 0 -- $REVISION
-ORDER BY pathindex.abspath ASC, dirindex.version DESC
-LIMIT 1; -- then check dirindex.deleted
-
--- single-revision tree for REVISION
-
-SELECT
- dirindex.*, pathindex.abspath
-FROM dirindex JOIN pathindex
- ON dirindex.pathid = pathindex.pathid
+INSERT INTO strindex (strid, content) VALUES (0, '/');
+INSERT INTO dirindex (rowid, origin, pathid, version, kind, opcode, subtree)
+ VALUES (0, NULL, 0, 0, 'D', 'A', 0);
+
+
+---STATEMENT INSERT_REVISION_RECORD
+
+INSERT INTO revision (version, created, author, log)
+ VALUES (?, ?, ?, ?);
+
+---STATEMENT GET_REVENT_BY_VERSION
+
+SELECT * FROM revision WHERE version = ?;
+
+---STATEMENT INSERT_STRINDEX_RECORD
+
+INSERT INTO strindex (content) VALUES (?);
+
+---STATEMENT GET_STRENT_BY_STRID
+
+SELECT * FROM strindex WHERE strid = ?;
+
+---STATEMENT GET_STRENT_BY_CONTENT
+
+SELECT * FROM strindex WHERE content = ?;
+
+---STATEMENT INSERT_DIRINDEX_RECORD
+
+INSERT INTO dirindex (origin, pathid, version, kind, opcode, subtree)
+ VALUES (?, ?, ?, ?, ?, ?);
+
+---STATEMENT GET_DIRENT_BY_ROWID
+
+SELECT dirindex.*, strindex.content FROM dirindex
+ JOIN strindex ON dirindex.pathid = strindex.strid
+WHERE dirindex.rowid = ?;
+
+---STATEMENT GET_DIRENT_BY_ABSPATH_AND_VERSION
+
+SELECT dirindex.*, strindex.content AS abspath FROM dirindex
+ JOIN strindex ON dirindex.pathid = strindex.strid
+WHERE abspath = ? AND dirindex.version = ?;
+
+---STATEMENT LOOKUP_ABSPATH_AT_REVISION
+
+SELECT dirindex.*, strindex.content AS abspath FROM dirindex
+ JOIN strindex ON dirindex.pathid = strindex.strid
+WHERE abspath = ? AND dirindex.version <= ?
+ORDER BY abspath ASC, dirindex.version DESC
+LIMIT 1;
+
+---STATEMENT LIST_SUBTREE_AT_REVISION
+
+SELECT dirindex.*, strindex.content AS abspath FROM dirindex
+ JOIN strindex ON dirindex.pathid = strindex.strid
JOIN (SELECT pathid, MAX(version) AS maxver FROM dirindex
- WHERE version <= 0 -- $REVISION
- GROUP BY pathid)
- AS filtered
+ WHERE version <= ? GROUP BY pathid)
+ AS filtered
ON dirindex.pathid == filtered.pathid
- AND dirindex.version == filtered.maxver
-WHERE NOT dirindex.deleted
-ORDER BY pathindex.abspath ASC;
+ AND dirindex.version == filtered.maxver
+WHERE abspath LIKE ? ESCAPE '#'
+ AND dirindex.opcode <> 'D'
+ORDER BY abspath ASC;
+
+---STATEMENT LIST_DIRENT_SUCCESSORS
+
+SELECT dirindex.*, strindex.content AS abspath FROM dirindex
+ JOIN strindex ON dirindex.pathid = strindex.strid
+WHERE dirindex.origin = ?
+ORDER BY abspath ASC, dirindex.version ASC;
+
+
+-- Temporary transaction
+
+---SCRIPT CREATE_TRANSACTION_CONTEXT
+
+CREATE TEMPORARY TABLE txncontext (
+ origin integer NULL,
+ abspath varchar NOT NULL UNIQUE,
+ kind character(1) NOT NULL,
+ opcode character(1) NOT NULL,
+ subtree boolean NOT NULL
+);
+
+---SCRIPT REMOVE_TRANSACTION_CONTEXT
+
+DROP TABLE IF EXISTS temp.txncontext;
+
+---STATEMENT INSERT_TRANSACTION_RECORD
+
+INSERT INTO temp.txncontext (origin, abspath, kind, opcode, subtree)
+ VALUES (?, ?, ?, ?, ?);
+
+---STATEMENT GET_TRANSACTION_RECORD
+
+SELECT * FROM temp.txncontext WHERE abspath = ?;
+
+---STATEMENT REMOVE_TRANSACTION_RECORD
+
+DELETE FROM temp.txncontext WHERE abspath = ?;
+
+---STATEMENT REMOVE_TRANSACTION_SUBTREE
+
+DELETE FROM temp.txncontext WHERE abspath LIKE ? ESCAPE '#';
+
+---STATEMENT LIST_TRANSACTION_RECORDS
+
+SELECT * FROM temp.txncontext ORDER BY abspath ASC;
Modified: subversion/branches/inheritable-props/notes/ra-serf-testing.txt
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/notes/ra-serf-testing.txt?rev=1303257&r1=1303256&r2=1303257&view=diff
==============================================================================
--- subversion/branches/inheritable-props/notes/ra-serf-testing.txt (original)
+++ subversion/branches/inheritable-props/notes/ra-serf-testing.txt Wed Mar 21 02:38:58 2012
@@ -1,3 +1,5 @@
+[ THE CUSTOM TESTING CODE DESCRIBED BELOW WAS REMOVED in r1302567 ]
+
For the 1.7 release, ra_serf grew a new internal feature to "pause"
the parsing of (large) XML response bodies. This file intends to
document the strategy for testing this new feature.
Modified: subversion/branches/inheritable-props/notes/wc-ng/conflict-storage
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/notes/wc-ng/conflict-storage?rev=1303257&r1=1303256&r2=1303257&view=diff
==============================================================================
--- subversion/branches/inheritable-props/notes/wc-ng/conflict-storage (original)
+++ subversion/branches/inheritable-props/notes/wc-ng/conflict-storage Wed Mar 21 02:38:58 2012
@@ -200,7 +200,7 @@ Tree conflicts
Tree conflicts exist on files or directories.
### JAF: And symlinks, I presume - or, if not, why not?
-### stsp: Symlinks are resolved before retreiving conflict information.,
+### stsp: Symlinks are resolved before retreiving conflict information.
The following information is stored if there is a tree conflict on the node:
@@ -212,8 +212,18 @@ The following information is stored if t
LOCAL_CHANGE is the local change which conflicted with the
incoming change during the operation. Possible values are "edit", "add",
-"delete", "rename", "replace", "obstructed", "missing", and "unversioned"
-(### possibly collapse "unversioned" with "obstructed"?).
+"delete", "rename", "replace", "obstructed", "missing", "unversioned",
+"moved-away", "moved-here", and "copied-here".
+
+### possibly collapse "unversioned" with "obstructed"?
+
+### what is "replace"? we should probably have "replace-add",
+### "replace-moved-away", "replace-moved-here", and "replace-copied-here"
+### hrm. this probably isn't the right representation. "replace-add"
+### says how the new node arrived, but not how the original departed.
+### was it a deleted or moved-away? for example, a local-deleted
+### followed by an add, followed by an incoming-delete should probably
+### be deemed "no conflict".
ORIGINAL_NODE_KIND is the kind of the node in the BASE tree.
MINE_NODE_KIND is the kind of the node from the WORKING tree at the
@@ -221,7 +231,9 @@ time the conflict was flagged.
INCOMING_CHANGE is the incoming change which conflicted with the
local change during the operation. Possible values are "edit", "add",
-"delete", "rename", and "replace".
+"delete", "rename", "replace", "moved-away", "moved-here", and
+"copied-here".
+### see concerns above about LOCAL_CHANGE.
The *_SHA1 sum fields are only present if {ORIGINAL,MINE,INCOMING}_NODE_KIND
is "file".
Modified: subversion/branches/inheritable-props/subversion/bindings/swig/ruby/test/test_info.rb
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/bindings/swig/ruby/test/test_info.rb?rev=1303257&r1=1303256&r2=1303257&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/bindings/swig/ruby/test/test_info.rb (original)
+++ subversion/branches/inheritable-props/subversion/bindings/swig/ruby/test/test_info.rb Wed Mar 21 02:38:58 2012
@@ -217,7 +217,6 @@ class SvnInfoTest < Test::Unit::TestCase
assert_equal([file1, file2, file4].sort, keys[0..-2])
assert_match(/\A#{file5}/, file5_key)
assert(info.diffs[file1].has_key?(:modified))
- assert(info.diffs[file1].has_key?(:property_changed))
assert(info.diffs[file2].has_key?(:modified))
assert(info.diffs[file4].has_key?(:added))
assert(info.diffs[file4].has_key?(:property_changed))
@@ -230,8 +229,6 @@ class SvnInfoTest < Test::Unit::TestCase
assert_equal(0, info.diffs[file4][:added].deleted_line)
assert_equal(0, info.diffs[file5_key][:copied].added_line)
assert_equal(0, info.diffs[file5_key][:copied].deleted_line)
- assert_equal("Name: #{file1_prop_key}\n - #{file1_prop_value}\n",
- info.diffs[file1][:property_changed].body)
assert_equal("Name: #{file4_prop_key}\n + #{file4_prop_value}\n",
info.diffs[file4][:property_changed].body)
assert_equal(commit_info.revision, info.revision)
Modified: subversion/branches/inheritable-props/subversion/include/private/svn_client_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/include/private/svn_client_private.h?rev=1303257&r1=1303256&r2=1303257&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/include/private/svn_client_private.h (original)
+++ subversion/branches/inheritable-props/subversion/include/private/svn_client_private.h Wed Mar 21 02:38:58 2012
@@ -100,6 +100,53 @@ svn_client__wc_node_get_origin(const cha
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
+/* A macro to mark sections of code that belong to the 'symmetric merge'
+ * feature while it's still new. */
+#ifdef SVN_DEBUG
+#define SVN_WITH_SYMMETRIC_MERGE
+#endif
+
+#ifdef SVN_WITH_SYMMETRIC_MERGE
+
+/* Details of a symmetric merge. */
+typedef struct svn_client__symmetric_merge_t svn_client__symmetric_merge_t;
+
+/* Find the information needed to merge all unmerged changes from a source
+ * branch into a target branch. The information is the locations of the
+ * youngest common ancestor, merge base, and such like.
+ *
+ * Set *MERGE to the information needed to merge all unmerged changes
+ * (up to SOURCE_REVISION) from the source branch SOURCE_PATH_OR_URL @
+ * SOURCE_REVISION into the target WC at TARGET_WCPATH.
+ */
+svn_error_t *
+svn_client__find_symmetric_merge(svn_client__symmetric_merge_t **merge,
+ const char *source_path_or_url,
+ const svn_opt_revision_t *source_revision,
+ const char *target_wcpath,
+ svn_boolean_t allow_mixed_rev,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/* Perform a symmetric merge.
+ *
+ * Merge according to MERGE into the WC at TARGET_WCPATH.
+ */
+svn_error_t *
+svn_client__do_symmetric_merge(const svn_client__symmetric_merge_t *merge,
+ const char *target_wcpath,
+ svn_depth_t depth,
+ svn_boolean_t ignore_ancestry,
+ svn_boolean_t force,
+ svn_boolean_t record_only,
+ svn_boolean_t dry_run,
+ const apr_array_header_t *merge_options,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *scratch_pool);
+
+#endif /* SVN_WITH_SYMMETRIC_MERGE */
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
Modified: subversion/branches/inheritable-props/subversion/include/svn_client.h
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/include/svn_client.h?rev=1303257&r1=1303256&r2=1303257&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/include/svn_client.h (original)
+++ subversion/branches/inheritable-props/subversion/include/svn_client.h Wed Mar 21 02:38:58 2012
@@ -1788,6 +1788,30 @@ svn_client_delete(svn_client_commit_info
* @{
*/
+/**
+ * The callback invoked by svn_client_import5() before adding a node to the
+ * list of nodes to be imported.
+ *
+ * @a baton is the value passed to @a svn_client_import5 as filter_baton.
+ *
+ * The callback receives the @a local_abspath for each node and the @a dirent
+ * for it when walking the directory tree. Only the kind of node, including
+ * special status is available in @a dirent.
+ *
+ * Implementations can set @a *filtered to TRUE, to make the import filter the
+ * node and (if the node is a directory) all its descendants.
+ *
+ * @a scratch_pool can be used for temporary allocations.
+ *
+ * @since New in 1.8.
+ */
+typedef svn_error_t *(*svn_client_import_filter_func_t)(
+ void *baton,
+ svn_boolean_t *filtered,
+ const char *local_abspath,
+ const svn_io_dirent2_t *dirent,
+ apr_pool_t *scratch_pool);
+
/** Import file or directory @a path into repository directory @a url at
* head, authenticating with the authentication baton cached in @a ctx,
* and using @a ctx->log_msg_func3/@a ctx->log_msg_baton3 to get a log message
@@ -1843,12 +1867,38 @@ svn_client_delete(svn_client_commit_info
* If @a ignore_unknown_node_types is @c FALSE, ignore files of which the
* node type is unknown, such as device files and pipes.
*
+ * If @a filter_callback is non-NULL, call it for each node that isn't ignored
+ * for other reasons with @a filter_baton, to allow third party to ignore
+ * specific nodes during importing.
+ *
* If @a commit_callback is non-NULL, then for each successful commit, call
* @a commit_callback with @a commit_baton and a #svn_commit_info_t for
* the commit.
*
+ * @since New in 1.8.
+ */
+svn_error_t *
+svn_client_import5(const char *path,
+ const char *url,
+ svn_depth_t depth,
+ svn_boolean_t no_ignore,
+ svn_boolean_t ignore_unknown_node_types,
+ const apr_hash_t *revprop_table,
+ svn_client_import_filter_func_t filter_callback,
+ void *filter_baton,
+ svn_commit_callback2_t commit_callback,
+ void *commit_baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *scratch_pool);
+
+/**
+ * Similar to svn_client_import5(), but without support for an optional
+ * @a filter_callback.
+ *
* @since New in 1.7.
+ * @deprecated Provided for backward compatibility with the 1.7 API.
*/
+SVN_DEPRECATED
svn_error_t *
svn_client_import4(const char *path,
const char *url,
Modified: subversion/branches/inheritable-props/subversion/include/svn_editor.h
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/include/svn_editor.h?rev=1303257&r1=1303256&r2=1303257&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/include/svn_editor.h (original)
+++ subversion/branches/inheritable-props/subversion/include/svn_editor.h Wed Mar 21 02:38:58 2012
@@ -153,6 +153,13 @@ extern "C" {
* "should", "should not", "recommended", "may", and "optional" in this
* document are to be interpreted as described in RFC 2119.
*
+ * @note The editor is *not* reentrant. The receiver should not directly
+ * or indirectly invoke an editor API unless it has been marked as
+ * explicitly supporting reentrancy during a receiver's callback. This
+ * limitation extends to the cancellation callback, too. (This limitation
+ * is due to the scratch_pool shared by all callbacks, and cleared after
+ * each callback; a reentrant call could clear the outer call's pool)
+ *
* \n
* <h3>Life-Cycle</h3>
*
Modified: subversion/branches/inheritable-props/subversion/include/svn_props.h
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/include/svn_props.h?rev=1303257&r1=1303256&r2=1303257&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/include/svn_props.h (original)
+++ subversion/branches/inheritable-props/subversion/include/svn_props.h Wed Mar 21 02:38:58 2012
@@ -190,10 +190,20 @@ typedef enum svn_prop_kind
svn_prop_regular_kind
} svn_prop_kind_t;
+/** Return the property kind of a property named @a prop_name.
+ *
+ * @since New in 1.8
+ */
+svn_prop_kind_t
+svn_property_kind2(const char *prop_name);
+
/** Return the prop kind of a property named @a prop_name, and
* (if @a prefix_len is non-@c NULL) set @a *prefix_len to the length of
* the prefix of @a prop_name that was sufficient to distinguish its kind.
+ *
+ * @deprecated Provided for backward compatibility with the 1.7 API.
*/
+SVN_DEPRECATED
svn_prop_kind_t
svn_property_kind(int *prefix_len,
const char *prop_name);
Modified: subversion/branches/inheritable-props/subversion/libsvn_client/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_client/commit.c?rev=1303257&r1=1303256&r2=1303257&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/libsvn_client/commit.c (original)
+++ subversion/branches/inheritable-props/subversion/libsvn_client/commit.c Wed Mar 21 02:38:58 2012
@@ -77,7 +77,7 @@ typedef struct import_ctx_t
} import_ctx_t;
-/* Apply PATH's contents (as a delta against the empty string) to
+/* Apply LOCAL_ABSPATH's contents (as a delta against the empty string) to
FILE_BATON in EDITOR. Use POOL for any temporary allocation.
PROPERTIES is the set of node properties set on this file.
@@ -87,7 +87,7 @@ typedef struct import_ctx_t
/* ### how does this compare against svn_wc_transmit_text_deltas2() ??? */
static svn_error_t *
-send_file_contents(const char *path,
+send_file_contents(const char *local_abspath,
void *file_baton,
const svn_delta_editor_t *editor,
apr_hash_t *properties,
@@ -135,12 +135,13 @@ send_file_contents(const char *path,
if (special)
{
- SVN_ERR(svn_subst_read_specialfile(&contents, path, pool, pool));
+ SVN_ERR(svn_subst_read_specialfile(&contents, local_abspath,
+ pool, pool));
}
else
{
/* Open the working copy file. */
- SVN_ERR(svn_stream_open_readonly(&contents, path, pool, pool));
+ SVN_ERR(svn_stream_open_readonly(&contents, local_abspath, pool, pool));
/* If we have EOL styles or keywords, then detranslate the file. */
if (svn_subst_translation_required(eol_style, eol, keywords,
@@ -150,7 +151,9 @@ send_file_contents(const char *path,
return svn_error_createf(SVN_ERR_IO_UNKNOWN_EOL, NULL,
_("%s property on '%s' contains "
"unrecognized EOL-style '%s'"),
- SVN_PROP_EOL_STYLE, path,
+ SVN_PROP_EOL_STYLE,
+ svn_dirent_local_style(local_abspath,
+ pool),
eol_style_val->data);
/* We're importing, so translate files with 'native' eol-style to
@@ -189,8 +192,9 @@ send_file_contents(const char *path,
static svn_error_t *
import_file(const svn_delta_editor_t *editor,
void *dir_baton,
- const char *path,
+ const char *local_abspath,
const char *edit_path,
+ const svn_io_dirent2_t *dirent,
import_ctx_t *import_ctx,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
@@ -201,12 +205,8 @@ import_file(const svn_delta_editor_t *ed
const char *text_checksum;
apr_hash_t* properties;
apr_hash_index_t *hi;
- svn_node_kind_t kind;
- svn_boolean_t is_special;
-
- SVN_ERR(svn_path_check_valid(path, pool));
- SVN_ERR(svn_io_check_special_path(path, &kind, &is_special, pool));
+ SVN_ERR(svn_path_check_valid(local_abspath, pool));
/* Add the file, using the pool from the FILES hash. */
SVN_ERR(editor->add_file(edit_path, dir_baton, NULL, SVN_INVALID_REVNUM,
@@ -215,10 +215,10 @@ import_file(const svn_delta_editor_t *ed
/* Remember that the repository was modified */
import_ctx->repos_changed = TRUE;
- if (! is_special)
+ if (! dirent->special)
{
/* add automatic properties */
- SVN_ERR(svn_client__get_auto_props(&properties, &mimetype, path,
+ SVN_ERR(svn_client__get_auto_props(&properties, &mimetype, local_abspath,
import_ctx->magic_cookie,
ctx, pool));
}
@@ -239,7 +239,8 @@ import_file(const svn_delta_editor_t *ed
if (ctx->notify_func2)
{
svn_wc_notify_t *notify
- = svn_wc_create_notify(path, svn_wc_notify_commit_added, pool);
+ = svn_wc_create_notify(local_abspath, svn_wc_notify_commit_added,
+ pool);
notify->kind = svn_node_file;
notify->mime_type = mimetype;
notify->content_state = notify->prop_state
@@ -251,7 +252,7 @@ import_file(const svn_delta_editor_t *ed
/* If this is a special file, we need to set the svn:special
property and create a temporary detranslated version in order to
send to the server. */
- if (is_special)
+ if (dirent->special)
{
apr_hash_set(properties, SVN_PROP_SPECIAL, APR_HASH_KEY_STRING,
svn_string_create(SVN_PROP_BOOLEAN_TRUE, pool));
@@ -263,7 +264,7 @@ import_file(const svn_delta_editor_t *ed
}
/* Now, transmit the file contents. */
- SVN_ERR(send_file_contents(path, file_baton, editor,
+ SVN_ERR(send_file_contents(local_abspath, file_baton, editor,
properties, digest, pool));
/* Finally, close the file. */
@@ -275,7 +276,7 @@ import_file(const svn_delta_editor_t *ed
}
-/* Import directory PATH into the repository directory indicated by
+/* Import directory LOCAL_ABSPATH into the repository directory indicated by
* DIR_BATON in EDITOR. EDIT_PATH is the path imported as the root
* directory, so all edits are relative to that.
*
@@ -291,6 +292,9 @@ import_file(const svn_delta_editor_t *ed
* If NO_IGNORE is FALSE, don't import files or directories that match
* ignore patterns.
*
+ * If FILTER_CALLBACK is not NULL, call it with FILTER_BATON on each to be
+ * imported node below LOCAL_ABSPATH to allow filtering nodes.
+ *
* If CTX->NOTIFY_FUNC is non-null, invoke it with CTX->NOTIFY_BATON for each
* directory.
*
@@ -298,12 +302,14 @@ import_file(const svn_delta_editor_t *ed
static svn_error_t *
import_dir(const svn_delta_editor_t *editor,
void *dir_baton,
- const char *path,
+ const char *local_abspath,
const char *edit_path,
svn_depth_t depth,
apr_hash_t *excludes,
svn_boolean_t no_ignore,
svn_boolean_t ignore_unknown_node_types,
+ svn_client_import_filter_func_t filter_callback,
+ void *filter_baton,
import_ctx_t *import_ctx,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
@@ -313,18 +319,18 @@ import_dir(const svn_delta_editor_t *edi
apr_hash_index_t *hi;
apr_array_header_t *ignores;
- SVN_ERR(svn_path_check_valid(path, pool));
+ SVN_ERR(svn_path_check_valid(local_abspath, pool));
if (!no_ignore)
SVN_ERR(svn_wc_get_default_ignores(&ignores, ctx->config, pool));
- SVN_ERR(svn_io_get_dirents3(&dirents, path, TRUE, pool, pool));
+ SVN_ERR(svn_io_get_dirents3(&dirents, local_abspath, TRUE, pool, pool));
for (hi = apr_hash_first(pool, dirents); hi; hi = apr_hash_next(hi))
{
- const char *this_path, *this_edit_path, *abs_path;
+ const char *this_abspath, *this_edit_path;
const char *filename = svn__apr_hash_index_key(hi);
- const svn_io_dirent_t *dirent = svn__apr_hash_index_val(hi);
+ const svn_io_dirent2_t *dirent = svn__apr_hash_index_val(hi);
svn_pool_clear(subpool);
@@ -342,7 +348,7 @@ import_dir(const svn_delta_editor_t *edi
if (ctx->notify_func2)
{
svn_wc_notify_t *notify
- = svn_wc_create_notify(svn_dirent_join(path, filename,
+ = svn_wc_create_notify(svn_dirent_join(local_abspath, filename,
subpool),
svn_wc_notify_skip, subpool);
notify->kind = svn_node_dir;
@@ -357,18 +363,28 @@ import_dir(const svn_delta_editor_t *edi
/* Typically, we started importing from ".", in which case
edit_path is "". So below, this_path might become "./blah",
and this_edit_path might become "blah", for example. */
- this_path = svn_dirent_join(path, filename, subpool);
+ this_abspath = svn_dirent_join(local_abspath, filename, subpool);
this_edit_path = svn_relpath_join(edit_path, filename, subpool);
/* If this is an excluded path, exclude it. */
- SVN_ERR(svn_dirent_get_absolute(&abs_path, this_path, subpool));
- if (apr_hash_get(excludes, abs_path, APR_HASH_KEY_STRING))
+ if (apr_hash_get(excludes, this_abspath, APR_HASH_KEY_STRING))
continue;
if ((!no_ignore) && svn_wc_match_ignore_list(filename, ignores,
subpool))
continue;
+ if (filter_callback != NULL)
+ {
+ svn_boolean_t filter = FALSE;
+
+ SVN_ERR(filter_callback(filter_baton, &filter, this_abspath,
+ dirent, subpool));
+
+ if (filter)
+ continue;
+ }
+
if (dirent->kind == svn_node_dir && depth >= svn_depth_immediates)
{
void *this_dir_baton;
@@ -389,7 +405,8 @@ import_dir(const svn_delta_editor_t *edi
if (ctx->notify_func2)
{
svn_wc_notify_t *notify
- = svn_wc_create_notify(this_path, svn_wc_notify_commit_added,
+ = svn_wc_create_notify(this_abspath,
+ svn_wc_notify_commit_added,
subpool);
notify->kind = svn_node_dir;
notify->content_state = notify->prop_state
@@ -404,9 +421,10 @@ import_dir(const svn_delta_editor_t *edi
if (depth == svn_depth_immediates)
depth_below_here = svn_depth_empty;
- SVN_ERR(import_dir(editor, this_dir_baton, this_path,
+ SVN_ERR(import_dir(editor, this_dir_baton, this_abspath,
this_edit_path, depth_below_here, excludes,
no_ignore, ignore_unknown_node_types,
+ filter_callback, filter_baton,
import_ctx, ctx,
subpool));
}
@@ -416,8 +434,9 @@ import_dir(const svn_delta_editor_t *edi
}
else if (dirent->kind == svn_node_file && depth >= svn_depth_files)
{
- SVN_ERR(import_file(editor, dir_baton, this_path,
- this_edit_path, import_ctx, ctx, subpool));
+ SVN_ERR(import_file(editor, dir_baton, this_abspath,
+ this_edit_path, dirent,
+ import_ctx, ctx, subpool));
}
else if (dirent->kind != svn_node_dir && dirent->kind != svn_node_file)
{
@@ -427,7 +446,7 @@ import_dir(const svn_delta_editor_t *edi
if (ctx->notify_func2)
{
svn_wc_notify_t *notify
- = svn_wc_create_notify(this_path,
+ = svn_wc_create_notify(this_abspath,
svn_wc_notify_skip, subpool);
notify->kind = svn_node_dir;
notify->content_state = notify->prop_state
@@ -440,7 +459,7 @@ import_dir(const svn_delta_editor_t *edi
return svn_error_createf
(SVN_ERR_NODE_UNKNOWN_KIND, NULL,
_("Unknown or unversionable type for '%s'"),
- svn_dirent_local_style(this_path, subpool));
+ svn_dirent_local_style(this_abspath, subpool));
}
}
@@ -485,7 +504,7 @@ import_dir(const svn_delta_editor_t *edi
* not necessarily the root.)
*/
static svn_error_t *
-import(const char *path,
+import(const char *local_abspath,
const apr_array_header_t *new_entries,
const svn_delta_editor_t *editor,
void *edit_baton,
@@ -493,15 +512,17 @@ import(const char *path,
apr_hash_t *excludes,
svn_boolean_t no_ignore,
svn_boolean_t ignore_unknown_node_types,
+ svn_client_import_filter_func_t filter_callback,
+ void *filter_baton,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
void *root_baton;
- svn_node_kind_t kind;
apr_array_header_t *ignores;
apr_array_header_t *batons = NULL;
const char *edit_path = "";
import_ctx_t *import_ctx = apr_pcalloc(pool, sizeof(*import_ctx));
+ const svn_io_dirent2_t *dirent;
svn_magic__init(&import_ctx->magic_cookie, pool);
@@ -512,7 +533,7 @@ import(const char *path,
pool, &root_baton));
/* Import a file or a directory tree. */
- SVN_ERR(svn_io_check_path(path, &kind, pool));
+ SVN_ERR(svn_io_stat_dirent(&dirent, local_abspath, FALSE, pool, pool));
/* Make the intermediate directory components necessary for properly
rooting our import source tree. */
@@ -529,7 +550,7 @@ import(const char *path,
/* If this is the last path component, and we're importing a
file, then this component is the name of the file, not an
intermediate directory. */
- if ((i == new_entries->nelts - 1) && (kind == svn_node_file))
+ if ((i == new_entries->nelts - 1) && (dirent->kind == svn_node_file))
break;
APR_ARRAY_PUSH(batons, void *) = root_baton;
@@ -542,7 +563,7 @@ import(const char *path,
import_ctx->repos_changed = TRUE;
}
}
- else if (kind == svn_node_file)
+ else if (dirent->kind == svn_node_file)
{
return svn_error_create
(SVN_ERR_NODE_UNKNOWN_KIND, NULL,
@@ -557,32 +578,37 @@ import(const char *path,
if something underneath it also has our reserved name, then we'll
error. */
- if (kind == svn_node_file)
+ if (dirent->kind == svn_node_file)
{
+ /* This code path ignores EXCLUDES and FILTER, but they don't make
+ much sense for a single file import anyway. */
svn_boolean_t ignores_match = FALSE;
if (!no_ignore)
{
SVN_ERR(svn_wc_get_default_ignores(&ignores, ctx->config, pool));
- ignores_match = svn_wc_match_ignore_list(path, ignores, pool);
+ ignores_match = svn_wc_match_ignore_list(local_abspath,
+ ignores, pool);
}
if (!ignores_match)
- SVN_ERR(import_file(editor, root_baton, path, edit_path,
- import_ctx, ctx, pool));
+ SVN_ERR(import_file(editor, root_baton, local_abspath, edit_path,
+ dirent, import_ctx, ctx, pool));
}
- else if (kind == svn_node_dir)
+ else if (dirent->kind == svn_node_dir)
{
- SVN_ERR(import_dir(editor, root_baton, path, edit_path,
+ SVN_ERR(import_dir(editor, root_baton, local_abspath, edit_path,
depth, excludes, no_ignore,
- ignore_unknown_node_types, import_ctx, ctx, pool));
+ ignore_unknown_node_types,
+ filter_callback, filter_baton,
+ import_ctx, ctx, pool));
}
- else if (kind == svn_node_none
- || kind == svn_node_unknown)
+ else if (dirent->kind == svn_node_none
+ || dirent->kind == svn_node_unknown)
{
return svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL,
_("'%s' does not exist"),
- svn_dirent_local_style(path, pool));
+ svn_dirent_local_style(local_abspath, pool));
}
/* Close up shop; it's time to go home. */
@@ -705,26 +731,28 @@ get_ra_editor(svn_ra_session_t **ra_sess
/*** Public Interfaces. ***/
svn_error_t *
-svn_client_import4(const char *path,
+svn_client_import5(const char *path,
const char *url,
svn_depth_t depth,
svn_boolean_t no_ignore,
svn_boolean_t ignore_unknown_node_types,
const apr_hash_t *revprop_table,
+ svn_client_import_filter_func_t filter_callback,
+ void *filter_baton,
svn_commit_callback2_t commit_callback,
void *commit_baton,
svn_client_ctx_t *ctx,
- apr_pool_t *pool)
+ apr_pool_t *scratch_pool)
{
svn_error_t *err = SVN_NO_ERROR;
const char *log_msg = "";
const svn_delta_editor_t *editor;
void *edit_baton;
svn_ra_session_t *ra_session;
- apr_hash_t *excludes = apr_hash_make(pool);
+ apr_hash_t *excludes = apr_hash_make(scratch_pool);
svn_node_kind_t kind;
const char *local_abspath;
- apr_array_header_t *new_entries = apr_array_make(pool, 4,
+ apr_array_header_t *new_entries = apr_array_make(scratch_pool, 4,
sizeof(const char *));
const char *temp;
const char *dir;
@@ -734,7 +762,7 @@ svn_client_import4(const char *path,
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
_("'%s' is not a local path"), path);
- SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
+ SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
/* Create a new commit item and add it to the array. */
if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx))
@@ -745,30 +773,30 @@ svn_client_import4(const char *path,
svn_client_commit_item3_t *item;
const char *tmp_file;
apr_array_header_t *commit_items
- = apr_array_make(pool, 1, sizeof(item));
+ = apr_array_make(scratch_pool, 1, sizeof(item));
- item = svn_client_commit_item3_create(pool);
- item->path = apr_pstrdup(pool, path);
+ item = svn_client_commit_item3_create(scratch_pool);
+ item->path = apr_pstrdup(scratch_pool, path);
item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD;
APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item;
SVN_ERR(svn_client__get_log_msg(&log_msg, &tmp_file, commit_items,
- ctx, pool));
+ ctx, scratch_pool));
if (! log_msg)
return SVN_NO_ERROR;
if (tmp_file)
{
const char *abs_path;
- SVN_ERR(svn_dirent_get_absolute(&abs_path, tmp_file, pool));
+ SVN_ERR(svn_dirent_get_absolute(&abs_path, tmp_file, scratch_pool));
apr_hash_set(excludes, abs_path, APR_HASH_KEY_STRING, (void *)1);
}
}
- SVN_ERR(svn_io_check_path(local_abspath, &kind, pool));
+ SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool));
/* Figure out all the path components we need to create just to have
a place to stick our imported tree. */
- subpool = svn_pool_create(pool);
+ subpool = svn_pool_create(scratch_pool);
do
{
svn_pool_clear(subpool);
@@ -788,7 +816,7 @@ svn_client_import4(const char *path,
else
svn_error_clear(err);
- svn_uri_split(&temp, &dir, url, pool);
+ svn_uri_split(&temp, &dir, url, scratch_pool);
APR_ARRAY_PUSH(new_entries, const char *) = dir;
url = temp;
}
@@ -833,19 +861,20 @@ svn_client_import4(const char *path,
&& svn_wc_is_adm_dir(temp = APR_ARRAY_IDX(new_entries,
new_entries->nelts - 1,
const char *),
- pool))
+ scratch_pool))
return svn_error_createf
(SVN_ERR_CL_ADM_DIR_RESERVED, NULL,
_("'%s' is a reserved name and cannot be imported"),
- /* ### Is svn_path_local_style() really necessary for this? */
- svn_dirent_local_style(temp, pool));
+ svn_dirent_local_style(temp, scratch_pool));
/* If an error occurred during the commit, abort the edit and return
the error. We don't even care if the abort itself fails. */
- if ((err = import(path, new_entries, editor, edit_baton,
+ if ((err = import(local_abspath, new_entries, editor, edit_baton,
depth, excludes, no_ignore,
- ignore_unknown_node_types, ctx, subpool)))
+ ignore_unknown_node_types,
+ filter_callback, filter_baton,
+ ctx, subpool)))
{
svn_error_clear(editor->abort_edit(edit_baton, subpool));
return svn_error_trace(err);
Modified: subversion/branches/inheritable-props/subversion/libsvn_client/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_client/deprecated.c?rev=1303257&r1=1303256&r2=1303257&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/libsvn_client/deprecated.c (original)
+++ subversion/branches/inheritable-props/subversion/libsvn_client/deprecated.c Wed Mar 21 02:38:58 2012
@@ -386,6 +386,27 @@ svn_client_args_to_target_array(apr_arra
/*** From commit.c ***/
svn_error_t *
+svn_client_import4(const char *path,
+ const char *url,
+ svn_depth_t depth,
+ svn_boolean_t no_ignore,
+ svn_boolean_t ignore_unknown_node_types,
+ const apr_hash_t *revprop_table,
+ svn_commit_callback2_t commit_callback,
+ void *commit_baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ return svn_error_trace(svn_client_import5(path, url, depth, no_ignore,
+ ignore_unknown_node_types,
+ revprop_table,
+ NULL, NULL,
+ commit_callback, commit_baton,
+ ctx, pool));
+}
+
+
+svn_error_t *
svn_client_import3(svn_commit_info_t **commit_info_p,
const char *path,
const char *url,