You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2012/04/30 23:04:38 UTC

svn commit: r1332392 [1/4] - in /subversion/branches/ev2-export: ./ notes/api-errata/1.8/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_delta/ subversion/libsvn_diff/ subversion/libsvn_fs/ subversion/libsvn...

Author: hwright
Date: Mon Apr 30 21:04:36 2012
New Revision: 1332392

URL: http://svn.apache.org/viewvc?rev=1332392&view=rev
Log:
On the ev2-export branch:
Bring up-to-date with trunk.

Added:
    subversion/branches/ev2-export/notes/api-errata/1.8/
      - copied from r1332387, subversion/trunk/notes/api-errata/1.8/
Modified:
    subversion/branches/ev2-export/   (props changed)
    subversion/branches/ev2-export/CHANGES
    subversion/branches/ev2-export/subversion/include/private/svn_fs_util.h
    subversion/branches/ev2-export/subversion/include/private/svn_named_atomic.h
    subversion/branches/ev2-export/subversion/include/private/svn_ra_private.h
    subversion/branches/ev2-export/subversion/include/private/svn_sqlite.h
    subversion/branches/ev2-export/subversion/include/private/svn_wc_private.h
    subversion/branches/ev2-export/subversion/include/svn_error.h
    subversion/branches/ev2-export/subversion/include/svn_fs.h
    subversion/branches/ev2-export/subversion/include/svn_io.h
    subversion/branches/ev2-export/subversion/libsvn_client/diff.c
    subversion/branches/ev2-export/subversion/libsvn_client/merge.c
    subversion/branches/ev2-export/subversion/libsvn_client/ra.c
    subversion/branches/ev2-export/subversion/libsvn_client/revisions.c
    subversion/branches/ev2-export/subversion/libsvn_delta/compat.c
    subversion/branches/ev2-export/subversion/libsvn_delta/debug_editor.c
    subversion/branches/ev2-export/subversion/libsvn_delta/editor.c
    subversion/branches/ev2-export/subversion/libsvn_diff/diff_file.c
    subversion/branches/ev2-export/subversion/libsvn_diff/diff_memory.c
    subversion/branches/ev2-export/subversion/libsvn_fs/editor.c
    subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.c
    subversion/branches/ev2-export/subversion/libsvn_fs_base/bdb/lock-tokens-table.c
    subversion/branches/ev2-export/subversion/libsvn_fs_base/bdb/locks-table.c
    subversion/branches/ev2-export/subversion/libsvn_fs_base/err.c
    subversion/branches/ev2-export/subversion/libsvn_fs_base/lock.c
    subversion/branches/ev2-export/subversion/libsvn_fs_base/tree.c
    subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.c
    subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.h
    subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.c
    subversion/branches/ev2-export/subversion/libsvn_fs_fs/lock.c
    subversion/branches/ev2-export/subversion/libsvn_fs_fs/tree.c
    subversion/branches/ev2-export/subversion/libsvn_ra/debug_reporter.c
    subversion/branches/ev2-export/subversion/libsvn_ra_svn/marshal.c
    subversion/branches/ev2-export/subversion/libsvn_ra_svn/ra_svn.h
    subversion/branches/ev2-export/subversion/libsvn_repos/deprecated.c
    subversion/branches/ev2-export/subversion/libsvn_repos/dump.c
    subversion/branches/ev2-export/subversion/libsvn_repos/repos.c
    subversion/branches/ev2-export/subversion/libsvn_subr/error.c
    subversion/branches/ev2-export/subversion/libsvn_subr/hash.c
    subversion/branches/ev2-export/subversion/libsvn_subr/io.c
    subversion/branches/ev2-export/subversion/libsvn_subr/named_atomic.c
    subversion/branches/ev2-export/subversion/libsvn_subr/sqlite.c
    subversion/branches/ev2-export/subversion/libsvn_subr/stream.c
    subversion/branches/ev2-export/subversion/libsvn_subr/win32_crashrpt.c
    subversion/branches/ev2-export/subversion/libsvn_wc/entries.c
    subversion/branches/ev2-export/subversion/libsvn_wc/node.c
    subversion/branches/ev2-export/subversion/libsvn_wc/props.c
    subversion/branches/ev2-export/subversion/libsvn_wc/wc.h
    subversion/branches/ev2-export/subversion/libsvn_wc/wc_db.c
    subversion/branches/ev2-export/subversion/libsvn_wc/wc_db.h
    subversion/branches/ev2-export/subversion/po/de.po
    subversion/branches/ev2-export/subversion/svn/blame-cmd.c
    subversion/branches/ev2-export/subversion/svn/log-cmd.c
    subversion/branches/ev2-export/subversion/svn/props.c
    subversion/branches/ev2-export/subversion/svnadmin/main.c
    subversion/branches/ev2-export/subversion/svnlook/main.c
    subversion/branches/ev2-export/subversion/svnrdump/dump_editor.c
    subversion/branches/ev2-export/subversion/svnrdump/svnrdump.c
    subversion/branches/ev2-export/subversion/tests/cmdline/davautocheck.sh
    subversion/branches/ev2-export/subversion/tests/cmdline/merge_symmetric_tests.py
    subversion/branches/ev2-export/subversion/tests/cmdline/stat_tests.py
    subversion/branches/ev2-export/subversion/tests/cmdline/svnadmin_tests.py
    subversion/branches/ev2-export/subversion/tests/libsvn_subr/named_atomic-test.c
    subversion/branches/ev2-export/subversion/tests/libsvn_wc/op-depth-test.c
    subversion/branches/ev2-export/tools/buildbot/slaves/bb-openbsd/svnbuild.sh
    subversion/branches/ev2-export/tools/dev/unix-build/Makefile.svn

Propchange: subversion/branches/ev2-export/
------------------------------------------------------------------------------
  Merged /subversion/trunk:r1331061-1332387

Modified: subversion/branches/ev2-export/CHANGES
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/CHANGES?rev=1332392&r1=1332391&r2=1332392&view=diff
==============================================================================
--- subversion/branches/ev2-export/CHANGES (original)
+++ subversion/branches/ev2-export/CHANGES Mon Apr 30 21:04:36 2012
@@ -62,7 +62,7 @@ http://svn.apache.org/repos/asf/subversi
     * fix regression from 1.6 in update with --depth option (issue #4136)
     * propset: avoid undefined behaviour in error path (r1325361)
     * reset sqlite statements, partly for sqlite-3.7.11 compat (r1328846, et al)
-    * [reverted/renominated] fix assertion during 'svn diff -r BASE:HEAD ^/trunk' (issue #4161)
+    * fix assertion during 'svn diff -r BASE:HEAD ^/trunk' (issue #4161)
     * notify upon 'update' just removing locks on files (r1329876)
     * neon: fix potential use of freed memory during commits (r1329388)
     * 'status --xml' doesn't show repository deletes correctly (issue #4167)

Modified: subversion/branches/ev2-export/subversion/include/private/svn_fs_util.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/include/private/svn_fs_util.h?rev=1332392&r1=1332391&r2=1332392&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/include/private/svn_fs_util.h (original)
+++ subversion/branches/ev2-export/subversion/include/private/svn_fs_util.h Mon Apr 30 21:04:36 2012
@@ -59,8 +59,12 @@ svn_fs__canonicalize_abspath(const char 
 svn_error_t *
 svn_fs__check_fs(svn_fs_t *fs, svn_boolean_t expect_open);
 
-/** Temporary, to be removed in the next revision. */
-#define svn_fs__identifier(fs, unused) ((fs)->uuid)
+/* An identifier for FS to be used in the text of error messages.
+   (Not used anywhere but in this header.)
+
+   Note: we log the UUID, rather than (fs)->path, since some of these
+   errors are marshalled to the client. */
+#define svn_fs__identifier(fs) ((fs)->uuid)
 
 /* Constructing nice error messages for roots.  */
 
@@ -82,17 +86,17 @@ svn_fs__check_fs(svn_fs_t *fs, svn_boole
 
 /* Build a detailed `file already exists' message for PATH in ROOT.
    ROOT is of type svn_fs_root_t *. */
-#define SVN_FS__ALREADY_EXISTS(root, path_str, pool) (                         \
+#define SVN_FS__ALREADY_EXISTS(root, path_str) (                               \
   root->is_txn_root ?                                                          \
     svn_error_createf                                                          \
       (SVN_ERR_FS_ALREADY_EXISTS, 0,                                           \
        _("File already exists: filesystem '%s', transaction '%s', path '%s'"), \
-       svn_fs__identifier(root->fs, pool), root->txn, path_str)      \
+       svn_fs__identifier(root->fs), root->txn, path_str)      \
   :                                                                            \
     svn_error_createf                                                          \
       (SVN_ERR_FS_ALREADY_EXISTS, 0,                                           \
        _("File already exists: filesystem '%s', revision %ld, path '%s'"),     \
-       svn_fs__identifier(root->fs, pool), root->rev, path_str)      \
+       svn_fs__identifier(root->fs), root->rev, path_str)      \
   )
 
 /* ROOT is of type svn_fs_root_t *. */
@@ -103,64 +107,64 @@ svn_fs__check_fs(svn_fs_t *fs, svn_boole
 
 /* SVN_FS__ERR_NOT_MUTABLE: the caller attempted to change a node
    outside of a transaction. FS is of type "svn_fs_t *". */
-#define SVN_FS__ERR_NOT_MUTABLE(fs, rev, path_in_repo, scratch_pool)     \
+#define SVN_FS__ERR_NOT_MUTABLE(fs, rev, path_in_repo)                   \
   svn_error_createf(                                                     \
      SVN_ERR_FS_NOT_MUTABLE, 0,                                          \
      _("File is not mutable: filesystem '%s', revision %ld, path '%s'"), \
-     svn_fs__identifier(fs, scratch_pool), rev, path_in_repo)
+     svn_fs__identifier(fs), rev, path_in_repo)
 
 /* FS is of type "svn_fs_t *".*/
-#define SVN_FS__ERR_NOT_DIRECTORY(fs, path_in_repo, scratch_pool) \
+#define SVN_FS__ERR_NOT_DIRECTORY(fs, path_in_repo)               \
   svn_error_createf(                                              \
      SVN_ERR_FS_NOT_DIRECTORY, 0,                                 \
      _("'%s' is not a directory in filesystem '%s'"),             \
-     path_in_repo, svn_fs__identifier(fs, scratch_pool))
+     path_in_repo, svn_fs__identifier(fs))
 
 /* FS is of type "svn_fs_t *".   */
-#define SVN_FS__ERR_NOT_FILE(fs, path_in_repo, scratch_pool)      \
+#define SVN_FS__ERR_NOT_FILE(fs, path_in_repo)                    \
   svn_error_createf(                                              \
      SVN_ERR_FS_NOT_FILE, 0,                                      \
      _("'%s' is not a file in filesystem '%s'"),                  \
-     path_in_repo, svn_fs__identifier(fs, scratch_pool))
+     path_in_repo, svn_fs__identifier(fs))
 
 
 /* FS is of type "svn_fs_t *", LOCK is of type "svn_lock_t *".   */
-#define SVN_FS__ERR_PATH_ALREADY_LOCKED(fs, lock, scratch_pool)             \
+#define SVN_FS__ERR_PATH_ALREADY_LOCKED(fs, lock)                           \
   svn_error_createf(                                                        \
      SVN_ERR_FS_PATH_ALREADY_LOCKED, 0,                                     \
      _("Path '%s' is already locked by user '%s' in filesystem '%s'"),      \
-     lock->path, lock->owner, svn_fs__identifier(fs, scratch_pool))
+     (lock)->path, (lock)->owner, svn_fs__identifier(fs))
 
 /* FS is of type "svn_fs_t *". */
-#define SVN_FS__ERR_NO_SUCH_LOCK(fs, path_in_repo, scratch_pool)  \
+#define SVN_FS__ERR_NO_SUCH_LOCK(fs, path_in_repo)                \
   svn_error_createf(                                              \
      SVN_ERR_FS_NO_SUCH_LOCK, 0,                                  \
      _("No lock on path '%s' in filesystem '%s'"),                \
-     path_in_repo, svn_fs__identifier(fs, scratch_pool))
+     path_in_repo, svn_fs__identifier(fs))
 
 /* FS is of type "svn_fs_t *". */
-#define SVN_FS__ERR_LOCK_EXPIRED(fs, token, scratch_pool)        \
+#define SVN_FS__ERR_LOCK_EXPIRED(fs, token)                      \
   svn_error_createf(                                             \
      SVN_ERR_FS_LOCK_EXPIRED, 0,                                 \
      _("Lock has expired: lock-token '%s' in filesystem '%s'"),  \
-     token, svn_fs__identifier(fs, scratch_pool))
+     token, svn_fs__identifier(fs))
 
 /* FS is of type "svn_fs_t *". */
-#define SVN_FS__ERR_NO_USER(fs, scratch_pool)                       \
+#define SVN_FS__ERR_NO_USER(fs)                                     \
   svn_error_createf(                                                \
      SVN_ERR_FS_NO_USER, 0,                                         \
      _("No username is currently associated with filesystem '%s'"), \
-     svn_fs__identifier(fs, scratch_pool))
+     svn_fs__identifier(fs))
 
 /* SVN_FS__ERR_LOCK_OWNER_MISMATCH: trying to use a lock whose
    LOCK_OWNER doesn't match the USERNAME associated with FS.
    FS is of type "svn_fs_t *". */
-#define SVN_FS__ERR_LOCK_OWNER_MISMATCH(fs, username, lock_owner, pool) \
+#define SVN_FS__ERR_LOCK_OWNER_MISMATCH(fs, username, lock_owner)       \
   svn_error_createf(                                                    \
      SVN_ERR_FS_LOCK_OWNER_MISMATCH, 0,                                 \
      _("User '%s' is trying to use a lock owned by '%s' in "            \
        "filesystem '%s'"),                                              \
-     username, lock_owner, svn_fs__identifier(fs, pool))
+     username, lock_owner, svn_fs__identifier(fs))
 
 /* Return a NULL-terminated copy of the first component of PATH,
    allocated in POOL.  If path is empty, or consists entirely of

Modified: subversion/branches/ev2-export/subversion/include/private/svn_named_atomic.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/include/private/svn_named_atomic.h?rev=1332392&r1=1332391&r2=1332392&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/include/private/svn_named_atomic.h (original)
+++ subversion/branches/ev2-export/subversion/include/private/svn_named_atomic.h Mon Apr 30 21:04:36 2012
@@ -51,6 +51,16 @@ typedef struct svn_named_atomic__t svn_n
  */
 #define SVN_NAMED_ATOMIC__MAX_NAME_LENGTH 30
 
+/** Returns #FALSE when named atomics are not available to our process
+ * and svn_atomic_namespace__create is likely to fail.
+ *
+ * Please note that the actual check will be performed only once and later
+ * changes in process privileges will not reflect in the outcome of future
+ * calls to this function.
+ */
+svn_boolean_t
+svn_named_atomic__is_supported(void);
+
 /** Returns #TRUE on platforms that don't need expensive synchronization
  * objects to serialize access to named atomics. If this returns #FALSE,
  * reading from or modifying a #svn_named_atomic__t may be as expensive

Modified: subversion/branches/ev2-export/subversion/include/private/svn_ra_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/include/private/svn_ra_private.h?rev=1332392&r1=1332391&r2=1332392&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/include/private/svn_ra_private.h (original)
+++ subversion/branches/ev2-export/subversion/include/private/svn_ra_private.h Mon Apr 30 21:04:36 2012
@@ -214,6 +214,7 @@ typedef svn_error_t *(*svn_ra__get_copys
    in order to determine whether to use delta->add_directory() or the
    delta->add_file() vtable entry to perform the copy.
    ### unclear on impact if this is NULL.
+   ### this callback will disappear when "everything" is running Ev2
 
    CB_BATON is the baton used/shared by the above three callbacks.
 

Modified: subversion/branches/ev2-export/subversion/include/private/svn_sqlite.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/include/private/svn_sqlite.h?rev=1332392&r1=1332391&r2=1332392&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/include/private/svn_sqlite.h (original)
+++ subversion/branches/ev2-export/subversion/include/private/svn_sqlite.h Mon Apr 30 21:04:36 2012
@@ -151,7 +151,9 @@ svn_sqlite__get_statement(svn_sqlite__st
    Spec  Argument type             Item type
    ----  -----------------         ---------
    n     <none, absent>            Column assignment skip
-   i     apr_int64_t               Number
+   d     int                       Number
+   L     apr_int64_t               Number
+   i     apr_int64_t               Number (deprecated format spec)
    s     const char *              String
    b     const void *              Blob data
          apr_size_t                Blob length

Modified: subversion/branches/ev2-export/subversion/include/private/svn_wc_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/include/private/svn_wc_private.h?rev=1332392&r1=1332391&r2=1332392&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/include/private/svn_wc_private.h (original)
+++ subversion/branches/ev2-export/subversion/include/private/svn_wc_private.h Mon Apr 30 21:04:36 2012
@@ -689,34 +689,33 @@ svn_wc__node_get_pre_ng_status_data(svn_
                                     apr_pool_t *scratch_pool);
 
 
-/** This whole function is for legacy, and it sucks. It does not really
- * make sense to get the copy-from revision number without the copy-from
- * URL, but higher level code currently wants that. This should go away.
- * (This function serves to get away from entry_t->revision without having to
- * change the public API.)
+/**
+ * Return the location of the base for this node's next commit,
+ * reflecting any local tree modifications affecting this node.
  *
- * Get the base revision of @a local_abspath using @a wc_ctx.  If @a
+ * Get the base location of @a local_abspath using @a wc_ctx.  If @a
  * local_abspath is not in the working copy, return @c
  * SVN_ERR_WC_PATH_NOT_FOUND.
  *
- * Return the revision number of the base for this node's next commit,
- * reflecting any local tree modifications affecting this node.
- *
- * If this node has no uncommitted changes, return the same revision as
+ * If this node has no uncommitted changes, return the same location as
  * svn_wc__node_get_base().
  *
  * If this node is moved-here or copied-here (possibly as part of a replace),
- * return the revision of the copy/move source. Do the same even when the node
+ * return the location of the copy/move source. Do the same even when the node
  * has been removed from a recursive copy (subpath excluded from the copy).
  *
- * Else, if this node is locally added, return SVN_INVALID_REVNUM, or if this
- * node is locally deleted or replaced, return the revert-base revision.
+ * Else, if this node is locally added, return SVN_INVALID_REVNUM/NULL, or
+ * if locally deleted or replaced, return the revert-base location.
  */
 svn_error_t *
-svn_wc__node_get_commit_base_rev(svn_revnum_t *base_revision,
-                                 svn_wc_context_t *wc_ctx,
-                                 const char *local_abspath,
-                                 apr_pool_t *scratch_pool);
+svn_wc__node_get_commit_base(svn_revnum_t *revision,
+                             const char **repos_relpath,
+                             const char **repos_root_url,
+                             const char **repos_uuid,
+                             svn_wc_context_t *wc_ctx,
+                             const char *local_abspath,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool);
 
 /**
  * Fetch lock information (if any) for @a local_abspath using @a wc_ctx:

Modified: subversion/branches/ev2-export/subversion/include/svn_error.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/include/svn_error.h?rev=1332392&r1=1332391&r2=1332392&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/include/svn_error.h (original)
+++ subversion/branches/ev2-export/subversion/include/svn_error.h Mon Apr 30 21:04:36 2012
@@ -317,7 +317,10 @@ svn_handle_warning(FILE *stream,
 #ifdef SVN_ERR__TRACING
 #define SVN_ERR__TRACED "traced call"
 
-#define svn_error_trace(expr)  svn_error_quick_wrap((expr), SVN_ERR__TRACED)
+svn_error_t *
+svn_error__trace(const char *file, long line, svn_error_t *err);
+
+#define svn_error_trace(expr)  svn_error__trace(__FILE__, __LINE__, (expr))
 #else
 #define svn_error_trace(expr)  (expr)
 #endif

Modified: subversion/branches/ev2-export/subversion/include/svn_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/include/svn_fs.h?rev=1332392&r1=1332391&r2=1332392&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/include/svn_fs.h (original)
+++ subversion/branches/ev2-export/subversion/include/svn_fs.h Mon Apr 30 21:04:36 2012
@@ -865,7 +865,7 @@ svn_fs_begin_txn(svn_fs_txn_t **txn_p,
  * If @a conflict_p is non-zero, use it to provide details on any
  * conflicts encountered merging @a txn with the most recent committed
  * revisions.  If a conflict occurs, set @a *conflict_p to the path of
- * the conflict in @a txn, with the same lifetime as @a txn;
+ * the conflict in @a txn, allocated within @a pool;
  * otherwise, set @a *conflict_p to NULL.
  *
  * If the commit succeeds, @a txn is invalid.
@@ -881,6 +881,9 @@ svn_fs_begin_txn(svn_fs_txn_t **txn_p,
  * even though a non-@c NULL function return value may indicate that
  * something else went wrong in post commit FS processing.
  *
+ * @note See api-errata/1.8/fs001.txt for information on how this
+ * function was documented in versions prior to 1.8.
+ *
  * ### need to document this better. there are four combinations of
  * ### return values:
  * ### 1) err=NULL. conflict=NULL. new_rev is valid

Modified: subversion/branches/ev2-export/subversion/include/svn_io.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/include/svn_io.h?rev=1332392&r1=1332391&r2=1332392&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/include/svn_io.h (original)
+++ subversion/branches/ev2-export/subversion/include/svn_io.h Mon Apr 30 21:04:36 2012
@@ -1179,6 +1179,14 @@ svn_stream_tee(svn_stream_t *out1,
                svn_stream_t *out2,
                apr_pool_t *pool);
 
+/** Write NULL-terminated string @a str to @a stream.
+ *
+ * @since New in 1.8.
+ *
+ */
+svn_error_t *
+svn_stream_puts(svn_stream_t *stream,
+                const char *str);
 
 /** Write to @a stream using a printf-style @a fmt specifier, passed through
  * apr_psprintf() using memory from @a pool.

Modified: subversion/branches/ev2-export/subversion/libsvn_client/diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/diff.c?rev=1332392&r1=1332391&r2=1332392&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/diff.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/diff.c Mon Apr 30 21:04:36 2012
@@ -708,8 +708,7 @@ display_prop_diffs(const apr_array_heade
         if (!val_has_eol)
           {
             const char *s = "\\ No newline at end of property" APR_EOL_STR;
-            apr_size_t len = strlen(s);
-            SVN_ERR(svn_stream_write(outstream, s, &len));
+            SVN_ERR(svn_stream_puts(outstream, s));
           }
       }
     }

Modified: subversion/branches/ev2-export/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/merge.c?rev=1332392&r1=1332391&r2=1332392&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/merge.c Mon Apr 30 21:04:36 2012
@@ -2841,9 +2841,9 @@ update_the_list_of_added_subtrees(const 
     }
   else
     {
-      const char *added_path_parent =
-        svn_dirent_dirname(added_abspath, scratch_pool);
       apr_pool_t *subpool = svn_pool_create(scratch_pool);
+      const char *added_path_parent =
+        svn_dirent_dirname(added_abspath, subpool);
 
       /* Is NOTIFY->PATH the root of an added subtree? */
       while (strcmp(target_abspath, added_path_parent))

Modified: subversion/branches/ev2-export/subversion/libsvn_client/ra.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/ra.c?rev=1332392&r1=1332391&r2=1332392&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/ra.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/ra.c Mon Apr 30 21:04:36 2012
@@ -1012,8 +1012,9 @@ svn_client__ra_provide_base(svn_stream_t
     {
       /* The pristine contents refer to the BASE, or to the pristine of
          a copy/move to this location. Fetch the correct revision.  */
-      SVN_ERR(svn_wc__node_get_commit_base_rev(revision, reb->wc_ctx,
-                                               local_abspath, scratch_pool));
+      SVN_ERR(svn_wc__node_get_commit_base(revision, NULL, NULL, NULL,
+                                           reb->wc_ctx, local_abspath,
+                                           scratch_pool, scratch_pool));
     }
 
   return SVN_NO_ERROR;
@@ -1056,8 +1057,9 @@ svn_client__ra_provide_props(apr_hash_t 
     {
       /* The pristine props refer to the BASE, or to the pristine props of
          a copy/move to this location. Fetch the correct revision.  */
-      SVN_ERR(svn_wc__node_get_commit_base_rev(revision, reb->wc_ctx,
-                                               local_abspath, scratch_pool));
+      SVN_ERR(svn_wc__node_get_commit_base(revision, NULL, NULL, NULL,
+                                           reb->wc_ctx, local_abspath,
+                                           scratch_pool, scratch_pool));
     }
 
   return SVN_NO_ERROR;
@@ -1100,6 +1102,9 @@ svn_client__ra_make_cb_baton(svn_wc_cont
 {
   struct ra_ev2_baton *reb = apr_palloc(result_pool, sizeof(*reb));
 
+  SVN_ERR_ASSERT_NO_RETURN(wc_ctx != NULL);
+  SVN_ERR_ASSERT_NO_RETURN(relpath_map != NULL);
+
   reb->wc_ctx = wc_ctx;
   reb->relpath_map = relpath_map;
 

Modified: subversion/branches/ev2-export/subversion/libsvn_client/revisions.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/revisions.c?rev=1332392&r1=1332391&r2=1332392&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/revisions.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/revisions.c Mon Apr 30 21:04:36 2012
@@ -91,9 +91,9 @@ svn_client__get_revision_number(svn_revn
         if (svn_path_is_url(local_abspath))
           goto invalid_rev_arg;
 
-        err = svn_wc__node_get_commit_base_rev(revnum, wc_ctx,
-                                               local_abspath,
-                                               scratch_pool);
+        err = svn_wc__node_get_commit_base(revnum, NULL, NULL, NULL,
+                                           wc_ctx, local_abspath,
+                                           scratch_pool, scratch_pool);
 
         /* Return the same error as older code did (before and at r935091).
            At least svn_client_proplist3 promises SVN_ERR_ENTRY_NOT_FOUND. */

Modified: subversion/branches/ev2-export/subversion/libsvn_delta/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_delta/compat.c?rev=1332392&r1=1332391&r2=1332392&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_delta/compat.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_delta/compat.c Mon Apr 30 21:04:36 2012
@@ -112,9 +112,8 @@ struct ev2_edit_baton
 {
   svn_editor_t *editor;
 
-  /* ### need to ensure we understand the proper root for these relpaths  */
-  apr_hash_t *changes;  /* RELPATH -> struct change_node  */
-  apr_hash_t *paths;
+  apr_hash_t *changes;  /* REPOS_RELPATH -> struct change_node  */
+
   apr_array_header_t *path_order;
   int paths_processed;
 
@@ -157,28 +156,6 @@ struct ev2_file_baton
   const char *delta_base;
 };
 
-enum action_code_t
-{
-  ACTION_MKDIR,
-  ACTION_COPY,
-  ACTION_PROPSET,
-  ACTION_PUT,
-  ACTION_DELETE,
-  ACTION_ADD_ABSENT
-};
-
-struct path_action
-{
-  enum action_code_t action;
-  void *args;
-};
-
-struct copy_args
-{
-  const char *copyfrom_path;
-  svn_revnum_t copyfrom_rev;
-};
-
 enum restructure_action_t
 {
   RESTRUCTURE_NONE = 0,
@@ -222,61 +199,19 @@ struct change_node
 };
 
 
-static svn_error_t *
-add_action(struct ev2_edit_baton *eb,
-           const char *path,
-           enum action_code_t action,
-           void *args)
-{
-  struct path_action *p_action;
-  apr_array_header_t *action_list = apr_hash_get(eb->paths, path,
-                                                 APR_HASH_KEY_STRING);
-
-  p_action = apr_palloc(eb->edit_pool, sizeof(*p_action));
-  p_action->action = action;
-  p_action->args = args;
-
-  if (action_list == NULL)
-    {
-      const char *path_dup = apr_pstrdup(eb->edit_pool, path);
-
-      action_list = apr_array_make(eb->edit_pool, 1,
-                                   sizeof(struct path_action *));
-      apr_hash_set(eb->paths, path_dup, APR_HASH_KEY_STRING, action_list);
-      APR_ARRAY_PUSH(eb->path_order, const char *) = path_dup;
-    }
-
-  APR_ARRAY_PUSH(action_list, struct path_action *) = p_action;
-
-  return SVN_NO_ERROR;
-}
-
-
 static struct change_node *
 locate_change(struct ev2_edit_baton *eb,
               const char *relpath)
 {
   struct change_node *change = apr_hash_get(eb->changes, relpath,
                                             APR_HASH_KEY_STRING);
-  apr_array_header_t *action_list;
 
   if (change != NULL)
     return change;
 
-  /* Shift RELPATH into the proper pool.  */
+  /* Shift RELPATH into the proper pool, and record the observed order.  */
   relpath = apr_pstrdup(eb->edit_pool, relpath);
-
-  /* Investigate whether there is an action in PATHS. Any presence there
-     will determine whether we need to update PATH_ORDER.  */
-  action_list = apr_hash_get(eb->paths, relpath, APR_HASH_KEY_STRING);
-  if (action_list == NULL)
-    {
-      /* Store an empty ACTION_LIST into PATHS.  */
-      action_list = apr_array_make(eb->edit_pool, 1,
-                                   sizeof(struct path_action *));
-      apr_hash_set(eb->paths, relpath, APR_HASH_KEY_STRING, action_list);
-      APR_ARRAY_PUSH(eb->path_order, const char *) = relpath;
-    }
+  APR_ARRAY_PUSH(eb->path_order, const char *) = relpath;
 
   /* Return an empty change. Callers will tweak as needed.  */
   change = apr_pcalloc(eb->edit_pool, sizeof(*change));
@@ -353,17 +288,13 @@ get_children(struct ev2_edit_baton *eb,
   apr_array_header_t *children = apr_array_make(pool, 1, sizeof(const char *));
   apr_hash_index_t *hi;
 
-  for (hi = apr_hash_first(pool, eb->paths); hi; hi = apr_hash_next(hi))
+  for (hi = apr_hash_first(pool, eb->changes); hi; hi = apr_hash_next(hi))
     {
-      const char *p = svn__apr_hash_index_key(hi);
+      const char *repos_relpath = svn__apr_hash_index_key(hi);
       const char *child;
 
-      /* Sanitize our paths. */
-      if (*p == '/')
-        p++;
-
       /* Find potential children. */
-      child = svn_relpath_skip_ancestor(path, p);
+      child = svn_relpath_skip_ancestor(path, repos_relpath);
       if (!child || !*child)
         continue;
 
@@ -381,173 +312,131 @@ get_children(struct ev2_edit_baton *eb,
 
 static svn_error_t *
 process_actions(struct ev2_edit_baton *eb,
-                const char *path,
-                apr_array_header_t *actions,
+                const char *repos_relpath,
                 const struct change_node *change,
                 apr_pool_t *scratch_pool)
 {
   apr_hash_t *props = NULL;
-  svn_boolean_t need_add = FALSE;
-  svn_boolean_t need_copy = FALSE;
-  const char *copyfrom_path;
-  svn_revnum_t copyfrom_rev;
-  apr_array_header_t *children = NULL;
   svn_stream_t *contents = NULL;
   svn_checksum_t *checksum = NULL;
-  svn_revnum_t delete_revnum = SVN_INVALID_REVNUM;
-  svn_revnum_t props_base_revision = SVN_INVALID_REVNUM;
-  svn_revnum_t text_base_revision = SVN_INVALID_REVNUM;
   svn_kind_t kind = svn_kind_unknown;
 
-  if (*path == '/')
+  SVN_ERR_ASSERT(change != NULL);
+
+  if (change->unlock)
+    SVN_ERR(eb->do_unlock(eb->unlock_baton, repos_relpath, scratch_pool));
+
+  if (change->action == RESTRUCTURE_DELETE)
     {
-      path++;
-      *eb->found_abs_paths = TRUE;
+      /* If the action was left as RESTRUCTURE_DELETE, then a
+         replacement is not occurring. Just do the delete and bail.  */
+      SVN_ERR(svn_editor_delete(eb->editor, repos_relpath,
+                                change->deleting));
+
+      /* No further work possible on this node.  */
+      return SVN_NO_ERROR;
     }
+  if (change->action == RESTRUCTURE_ADD_ABSENT)
+    {
+      SVN_ERR(svn_editor_add_absent(eb->editor, repos_relpath,
+                                    change->kind, change->deleting));
 
-  SVN_ERR_ASSERT(change != NULL);
-  if (change != NULL)
+      /* No further work possible on this node.  */
+      return SVN_NO_ERROR;
+    }
+
+  if (change->contents_abspath != NULL)
     {
-      if (change->unlock)
-        SVN_ERR(eb->do_unlock(eb->unlock_baton, path, scratch_pool));
+      /* We can only set text on files. */
+      /* ### validate we aren't overwriting KIND?  */
+      kind = svn_kind_file;
+
+      /* ### the checksum might be in CHANGE->CHECKSUM  */
+      SVN_ERR(svn_io_file_checksum2(&checksum, change->contents_abspath,
+                                    svn_checksum_sha1, scratch_pool));
+      SVN_ERR(svn_stream_open_readonly(&contents, change->contents_abspath,
+                                       scratch_pool, scratch_pool));
+    }
 
-      if (change->action == RESTRUCTURE_DELETE)
-        {
-          /* If the action was left as RESTRUCTURE_DELETE, then a
-             replacement is not occurring. Just do the delete and bail.  */
-          SVN_ERR(svn_editor_delete(eb->editor, path, change->deleting));
+  if (change->props != NULL)
+    {
+      /* ### validate we aren't overwriting KIND?  */
+      kind = change->kind;
+      props = change->props;
+    }
 
-          /* No further work possible on this node.  */
-          return SVN_NO_ERROR;
-        }
-      if (change->action == RESTRUCTURE_ADD_ABSENT)
-        {
-          SVN_ERR(svn_editor_add_absent(eb->editor, path, change->kind,
-                                        change->deleting));
+  if (change->action == RESTRUCTURE_ADD)
+    {
+      /* An add might be a replace. Grab the revnum we're replacing.  */
+      svn_revnum_t replaces_rev = change->deleting;
 
-          /* No further work possible on this node.  */
-          return SVN_NO_ERROR;
-        }
+      kind = change->kind;
 
-      if (change->action == RESTRUCTURE_ADD)
+      if (change->copyfrom_path != NULL)
         {
-          kind = change->kind;
-
-          /* An add might be a replace. Grab the revnum we're replacing.  */
-          delete_revnum = change->deleting;
+          SVN_ERR(svn_editor_copy(eb->editor, change->copyfrom_path,
+                                  change->copyfrom_rev,
+                                  repos_relpath, replaces_rev));
+          /* Fall through to possibly make changes post-copy.  */
+        }
+      else
+        {
+          /* If no properties were defined, then use an empty set.  */
+          if (props == NULL)
+            props = apr_hash_make(scratch_pool);
 
           if (kind == svn_kind_dir)
             {
-              children = get_children(eb, path, scratch_pool);
+              const apr_array_header_t *children;
+
+              children = get_children(eb, repos_relpath, scratch_pool);
+              SVN_ERR(svn_editor_add_directory(eb->editor, repos_relpath,
+                                               children, props,
+                                               replaces_rev));
             }
           else
             {
-              /* If this file is copied here, then we don't need CONTENTS.
-                 Otherwise, the contents comes from apply_txdelta() and has
-                 been saved at CONTENTS_ABSPATH. If apply_txdelta() was not
-                 called, then we're adding an empty file.  */
-              if (change->copyfrom_path == NULL
-                  && change->contents_abspath == NULL)
+              /* If this file was added, but apply_txdelta() was not
+                 called (ie. no CONTENTS_ABSPATH), then we're adding
+                 an empty file.  */
+              if (change->contents_abspath == NULL)
                 {
                   contents = svn_stream_empty(scratch_pool);
                   checksum = svn_checksum_empty_checksum(svn_checksum_sha1,
                                                          scratch_pool);
                 }
-            }
 
-          if (change->copyfrom_path != NULL)
-            {
-              need_copy = TRUE;
-              copyfrom_path = change->copyfrom_path;
-              copyfrom_rev = change->copyfrom_rev;
+              SVN_ERR(svn_editor_add_file(eb->editor, repos_relpath,
+                                          checksum, contents, props,
+                                          replaces_rev));
             }
-          else
-            {
-              need_add = TRUE;
-            }
-        }
-
-      if (change->contents_abspath != NULL)
-        {
-          /* We can only set text on files. */
-          /* ### validate we aren't overwriting KIND?  */
-          kind = svn_kind_file;
-
-          /* ### the checksum might be in CHANGE->CHECKSUM  */
-          SVN_ERR(svn_io_file_checksum2(&checksum, change->contents_abspath,
-                                        svn_checksum_sha1, scratch_pool));
-          SVN_ERR(svn_stream_open_readonly(&contents, change->contents_abspath,
-                                           scratch_pool, scratch_pool));
-
-          text_base_revision = change->changing;
-        }
 
-      if (change->props != NULL)
-        {
-          /* ### validate we aren't overwriting KIND?  */
-          kind = change->kind;
-          props = change->props;
-          props_base_revision = change->changing;
-        }
-    }
-
-  /* We've now got a wholistic view of what has happened to this node,
-   * so we can call our own editor APIs on it. */
-
-  if (need_add)
-    {
-      if (props == NULL)
-        props = apr_hash_make(scratch_pool);
-
-      if (kind == svn_kind_dir)
-        {
-          SVN_ERR(svn_editor_add_directory(eb->editor, path, children,
-                                           props, delete_revnum));
-        }
-      else
-        {
-          SVN_ERR(svn_editor_add_file(eb->editor, path, checksum, contents,
-                                      props, delete_revnum));
+          /* No further work possible on this node.  */
+          return SVN_NO_ERROR;
         }
-
-      /* No further work possible on this node.  */
-      return SVN_NO_ERROR;
-    }
-
-  if (need_copy)
-    {
-      SVN_ERR(svn_editor_copy(eb->editor, copyfrom_path, copyfrom_rev, path,
-                              delete_revnum));
-      /* Fall through to possibly make changes post-copy.  */
     }
 
 #if 0
   /* There *should* be work for this node. But it seems that isn't true
      in some cases. Future investigation...  */
-  SVN_ERR_ASSERT(need_copy || props || contents);
+  SVN_ERR_ASSERT(props || contents);
 #endif
   if (props || contents)
     {
-      /* We fetched and modified the props or content in some way. Apply 'em
-         now.  */
-      svn_revnum_t base_revision;
-
-      if (SVN_IS_VALID_REVNUM(props_base_revision)
-            && SVN_IS_VALID_REVNUM(text_base_revision))
-        SVN_ERR_ASSERT(props_base_revision == text_base_revision);
-
-      if (SVN_IS_VALID_REVNUM(props_base_revision))
-        base_revision = props_base_revision;
-      else if (SVN_IS_VALID_REVNUM(text_base_revision))
-        base_revision = text_base_revision;
-      else
-        base_revision = SVN_INVALID_REVNUM;
+      /* Changes to properties or content should have indicated the revision
+         it was intending to change.
+
+         Oop. Not true. The node may be locally-added.  */
+#if 0
+      SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(change->changing));
+#endif
 
       if (kind == svn_kind_dir)
-        SVN_ERR(svn_editor_alter_directory(eb->editor, path, base_revision,
-                                           props));
+        SVN_ERR(svn_editor_alter_directory(eb->editor, repos_relpath,
+                                           change->changing, props));
       else
-        SVN_ERR(svn_editor_alter_file(eb->editor, path, base_revision, props,
+        SVN_ERR(svn_editor_alter_file(eb->editor, repos_relpath,
+                                      change->changing, props,
                                       checksum, contents));
     }
 
@@ -566,16 +455,16 @@ run_ev2_actions(struct ev2_edit_baton *e
      as part of close_edit() and then some more as part of abort_edit()  */
   for (; eb->paths_processed < eb->path_order->nelts; ++eb->paths_processed)
     {
-      const char *path = APR_ARRAY_IDX(eb->path_order, eb->paths_processed,
-                                       const char *);
-      apr_array_header_t *actions = apr_hash_get(eb->paths, path,
-                                                 APR_HASH_KEY_STRING);
-      struct change_node *change = apr_hash_get(eb->changes, path,
-                                                APR_HASH_KEY_STRING);
+      const char *repos_relpath = APR_ARRAY_IDX(eb->path_order,
+                                                eb->paths_processed,
+                                                const char *);
+      const struct change_node *change = apr_hash_get(eb->changes,
+                                                      repos_relpath,
+                                                      APR_HASH_KEY_STRING);
 
       svn_pool_clear(iterpool);
 
-      SVN_ERR(process_actions(eb, path, actions, change, iterpool));
+      SVN_ERR(process_actions(eb, repos_relpath, change, iterpool));
     }
   svn_pool_destroy(iterpool);
 
@@ -700,7 +589,6 @@ ev2_add_directory(const char *path,
   else
     {
       /* A copy */
-      struct copy_args *args = apr_palloc(pb->eb->edit_pool, sizeof(*args));
 
       change->copyfrom_path = map_to_repos_relpath(pb->eb, copyfrom_path,
                                                    pb->eb->edit_pool);
@@ -813,7 +701,6 @@ ev2_add_file(const char *path,
   else
     {
       /* A copy */
-      struct copy_args *args = apr_palloc(pb->eb->edit_pool, sizeof(*args));
 
       change->copyfrom_path = map_to_repos_relpath(fb->eb, copyfrom_path,
                                                    fb->eb->edit_pool);
@@ -1081,7 +968,6 @@ svn_delta__delta_from_editor(const svn_d
 
   eb->editor = editor;
   eb->changes = apr_hash_make(pool);
-  eb->paths = apr_hash_make(pool);
   eb->path_order = apr_array_make(pool, 1, sizeof(const char *));
   eb->edit_pool = pool;
   eb->found_abs_paths = found_abs_paths;
@@ -1109,29 +995,9 @@ svn_delta__delta_from_editor(const svn_d
 /* ### note the similarity to struct change_node. these structures will
    ### be combined in the future.  */
 struct operation {
-  enum {
-    OP_OPEN,
-    OP_DELETE,
-    OP_ADD,
-    OP_REPLACE,
-    OP_ADD_ABSENT,
-    OP_PROPSET           /* only for files for which no other operation is
-                            occuring; directories are OP_OPEN with non-empty
-                            props */
-  } operation;
-
-  const char *path;
-  svn_kind_t kind;  /* to copy, mkdir, put or set revprops */
-  svn_revnum_t base_revision;       /* When committing, the base revision */
-  svn_revnum_t copyfrom_revision;      /* to copy, valid for add and replace */
-  svn_checksum_t *new_checksum;   /* An MD5 hash of the new contents, if any */
-  const char *copyfrom_url;       /* to copy, valid for add and replace */
-  const char *src_file;  /* for put, the source file for contents */
-  apr_hash_t *children;  /* const char *path -> struct operation * */
-  apr_hash_t *prop_mods; /* const char *prop_name ->
-                            const svn_string_t *prop_value */
-  apr_array_header_t *prop_dels; /* const char *prop_name deletions */
-  void *baton;           /* as returned by the commit editor */
+  /* ### leave these two here for now. still used.  */
+  svn_revnum_t base_revision;
+  void *baton;
 };
 
 struct editor_baton
@@ -1150,228 +1016,38 @@ struct editor_baton
   const char *repos_root;
   const char *base_relpath;
 
-  apr_hash_t *paths;
+  /* REPOS_RELPATH -> struct change_node *  */
+  apr_hash_t *changes;
+
   apr_pool_t *edit_pool;
 };
 
 
-/* Find the operation associated with PATH, which is a single-path
-   component representing a child of the path represented by
-   OPERATION.  If no such child operation exists, create a new one of
-   type OP_OPEN. */
-static struct operation *
-get_operation(const char *path,
-              struct operation *operation,
-              svn_revnum_t base_revision,
-              apr_pool_t *result_pool)
+/* Insert a new change for RELPATH, or return an existing one.  */
+static struct change_node *
+insert_change(const char *relpath,
+              apr_hash_t *changes)
 {
-  struct operation *child = apr_hash_get(operation->children, path,
-                                         APR_HASH_KEY_STRING);
-  if (! child)
-    {
-      child = apr_pcalloc(result_pool, sizeof(*child));
-      child->children = apr_hash_make(result_pool);
-      child->path = apr_pstrdup(result_pool, path);
-      child->operation = OP_OPEN;
-      child->copyfrom_revision = SVN_INVALID_REVNUM;
-      child->kind = svn_kind_dir;
-      child->base_revision = base_revision;
-      child->prop_mods = apr_hash_make(result_pool);
-      child->prop_dels = apr_array_make(result_pool, 1, sizeof(const char *));
-      apr_hash_set(operation->children, apr_pstrdup(result_pool, path),
-                   APR_HASH_KEY_STRING, child);
-    }
-
-  /* If an operation has a child, it must of necessity be a directory,
-     so ensure this fact. */
-  operation->kind = svn_kind_dir;
-
-  return child;
-}
-
-/* Add PATH to the operations tree rooted at OPERATION, creating any
-   intermediate nodes that are required.  Here's what's expected for
-   each action type:
-
-      ACTION          URL    REV      SRC-FILE  PROPNAME
-      ------------    -----  -------  --------  --------
-      ACTION_MKDIR    NULL   invalid  NULL      NULL
-      ACTION_COPY     valid  valid    NULL      NULL
-      ACTION_PUT      NULL   invalid  valid     NULL
-      ACTION_DELETE   NULL   invalid  NULL      NULL
-      ACTION_PROPSET  valid  invalid  NULL      valid
-
-   Node type information is obtained for any copy source (to determine
-   whether to create a file or directory) and for any deleted path (to
-   ensure it exists since svn_delta_editor_t->delete_entry doesn't
-   return an error on non-existent nodes). */
-static svn_error_t *
-build(struct editor_baton *eb,
-      enum action_code_t action,
-      const char *relpath,
-      svn_kind_t kind,
-      const char *url,
-      svn_revnum_t rev,
-      apr_hash_t *props,
-      const char *src_file,
-      svn_checksum_t *checksum,
-      svn_revnum_t head,
-      apr_pool_t *scratch_pool)
-{
-  apr_array_header_t *path_bits;
-  const char *path_so_far = "";
-  struct operation *operation = &eb->root;
-  int i;
-
-  /* We should only see PROPS when action is ACTION_PROPSET. */
-  SVN_ERR_ASSERT((props && action == ACTION_PROPSET)
-                || (!props && action != ACTION_PROPSET) );
-
-  relpath = svn_relpath_skip_ancestor(eb->base_relpath, relpath);
-
-  /* Look for any previous operations we've recognized for PATH.  If
-     any of PATH's ancestors have not yet been traversed, we'll be
-     creating OP_OPEN operations for them as we walk down PATH's path
-     components. */
-  path_bits = svn_path_decompose(relpath, scratch_pool);
-  for (i = 0; i < path_bits->nelts; ++i)
-    {
-      const char *path_bit = APR_ARRAY_IDX(path_bits, i, const char *);
-      path_so_far = svn_relpath_join(path_so_far, path_bit, scratch_pool);
-      operation = get_operation(path_so_far, operation, head, eb->edit_pool);
-    }
-
-  /* Handle property changes. */
-  if (props)
-    {
-      apr_hash_t *current_props;
-      apr_array_header_t *propdiffs;
-
-      operation->kind = kind;
-
-      if (operation->operation == OP_REPLACE)
-        current_props = apr_hash_make(scratch_pool);
-      else if (operation->copyfrom_url)
-        {
-          const char *copyfrom_relpath;
-
-          if (eb->repos_root)
-            copyfrom_relpath = svn_uri_skip_ancestor(eb->repos_root,
-                                                     operation->copyfrom_url,
-                                                     scratch_pool);
-          else
-            copyfrom_relpath = operation->copyfrom_url;
-
-          SVN_ERR(eb->fetch_props_func(&current_props, eb->fetch_props_baton,
-                                       copyfrom_relpath,
-                                       operation->copyfrom_revision,
-                                       scratch_pool, scratch_pool));
-        }
-      else
-        SVN_ERR(eb->fetch_props_func(&current_props, eb->fetch_props_baton,
-                                     svn_relpath_join(eb->base_relpath,
-                                                      relpath,
-                                                      scratch_pool),
-                                     rev, scratch_pool,
-                                     scratch_pool));
-
-      SVN_ERR(svn_prop_diffs(&propdiffs, props, current_props, scratch_pool));
-
-      for (i = 0; i < propdiffs->nelts; i++)
-        {
-          /* Note: the array returned by svn_prop_diffs() is an array of
-             actual structures, not pointers to them. */
-          svn_prop_t *prop = &APR_ARRAY_IDX(propdiffs, i, svn_prop_t);
-          if (!prop->value)
-            APR_ARRAY_PUSH(operation->prop_dels, const char *) =
-                                        apr_pstrdup(eb->edit_pool, prop->name);
-          else
-            apr_hash_set(operation->prop_mods,
-                         apr_pstrdup(eb->edit_pool, prop->name),
-                         APR_HASH_KEY_STRING,
-                         svn_string_dup(prop->value, eb->edit_pool));
-        }
-
-      /* If we're not adding this thing ourselves, check for existence.  */
-      if (! ((operation->operation == OP_ADD) ||
-             (operation->operation == OP_REPLACE)))
-        {
-          if ((operation->kind == svn_kind_file)
-                   && (operation->operation == OP_OPEN))
-            operation->operation = OP_PROPSET;
-        }
-      if (!SVN_IS_VALID_REVNUM(operation->copyfrom_revision))
-        operation->copyfrom_revision = rev;
-      return SVN_NO_ERROR;
-    }
-
-  if (action == ACTION_DELETE)
-    {
-      operation->operation = OP_DELETE;
-      operation->base_revision = rev;
-    }
-
-  else if (action == ACTION_ADD_ABSENT)
-    operation->operation = OP_ADD_ABSENT;
+  apr_pool_t *result_pool;
+  struct change_node *change;
 
-  /* Handle copy operations (which can be adds or replacements). */
-  else if (action == ACTION_COPY)
-    {
-      operation->operation =
-        operation->operation == OP_DELETE ? OP_REPLACE : OP_ADD;
+  change = apr_hash_get(changes, relpath, APR_HASH_KEY_STRING);
+  if (change != NULL)
+    return change;
 
-      if (kind == svn_kind_none || kind == svn_kind_unknown)
-        SVN_ERR(eb->fetch_kind_func(&operation->kind, eb->fetch_kind_baton,
-                                    url, rev, scratch_pool));
-      else
-        operation->kind = kind;
+  result_pool = apr_hash_pool_get(changes);
 
-      operation->copyfrom_revision = rev;
+  /* Return an empty change. Callers will tweak as needed.  */
+  change = apr_pcalloc(result_pool, sizeof(*change));
+  change->changing = SVN_INVALID_REVNUM;
+  change->deleting = SVN_INVALID_REVNUM;
 
-      if (eb->repos_root)
-        operation->copyfrom_url = svn_path_url_add_component2(eb->repos_root,
-                                                              url,
-                                                              eb->edit_pool);
-      else
-        operation->copyfrom_url = apr_pstrcat(eb->edit_pool, "/", url, NULL);
-    }
-  /* Handle mkdir operations (which can be adds or replacements). */
-  else if (action == ACTION_MKDIR)
-    {
-      operation->operation =
-        operation->operation == OP_DELETE ? OP_REPLACE : OP_ADD;
-      operation->kind = svn_kind_dir;
-    }
-  /* Handle put operations (which can be adds, replacements, or opens). */
-  else if (action == ACTION_PUT)
-    {
-      if (operation->operation == OP_DELETE)
-        {
-          operation->operation = OP_REPLACE;
-        }
-      else if (operation->operation == OP_OPEN)
-        {
-          if (kind == svn_kind_file)
-            operation->operation = OP_OPEN;
-          else if (kind == svn_kind_none)
-            operation->operation = OP_ADD;
-          else
-            return svn_error_createf(SVN_ERR_BAD_URL, NULL,
-                                     "'%s' is not a file", relpath);
-        }
-      operation->kind = svn_kind_file;
-      operation->src_file = apr_pstrdup(eb->edit_pool, src_file);
-      operation->new_checksum = svn_checksum_dup(checksum, eb->edit_pool);
-    }
-  else
-    {
-      /* We shouldn't get here. */
-      SVN_ERR_MALFUNCTION();
-    }
+  apr_hash_set(changes, relpath, APR_HASH_KEY_STRING, change);
 
-  return SVN_NO_ERROR;
+  return change;
 }
 
+
 /* This implements svn_editor_cb_add_directory_t */
 static svn_error_t *
 add_directory_cb(void *baton,
@@ -1382,24 +1058,12 @@ add_directory_cb(void *baton,
                  apr_pool_t *scratch_pool)
 {
   struct editor_baton *eb = baton;
+  struct change_node *change = insert_change(relpath, eb->changes);
 
-  if (SVN_IS_VALID_REVNUM(replaces_rev))
-    {
-      /* We need to add the delete action. */
-
-      SVN_ERR(build(eb, ACTION_DELETE, relpath, svn_kind_unknown,
-                    NULL, SVN_INVALID_REVNUM,
-                    NULL, NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
-    }
-
-  SVN_ERR(build(eb, ACTION_MKDIR, relpath, svn_kind_dir,
-                NULL, SVN_INVALID_REVNUM,
-                NULL, NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
-
-  if (props && apr_hash_count(props) > 0)
-    SVN_ERR(build(eb, ACTION_PROPSET, relpath, svn_kind_dir,
-                  NULL, SVN_INVALID_REVNUM, props,
-                  NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
+  change->action = RESTRUCTURE_ADD;
+  change->kind = svn_kind_dir;
+  change->deleting = replaces_rev;
+  change->props = apr_hash_copy(eb->edit_pool, props);
 
   return SVN_NO_ERROR;
 }
@@ -1418,6 +1082,7 @@ add_file_cb(void *baton,
   const char *tmp_filename;
   svn_stream_t *tmp_stream;
   svn_checksum_t *md5_checksum;
+  struct change_node *change = insert_change(relpath, eb->changes);
 
   /* We may need to re-checksum these contents */
   if (!(checksum && checksum->kind == svn_checksum_md5))
@@ -1426,30 +1091,18 @@ add_file_cb(void *baton,
   else
     md5_checksum = (svn_checksum_t *)checksum;
 
-  if (SVN_IS_VALID_REVNUM(replaces_rev))
-    {
-      /* We need to add the delete action. */
-
-      SVN_ERR(build(eb, ACTION_DELETE, relpath, svn_kind_unknown,
-                    NULL, SVN_INVALID_REVNUM,
-                    NULL, NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
-    }
-
   /* Spool the contents to a tempfile, and provide that to the driver. */
   SVN_ERR(svn_stream_open_unique(&tmp_stream, &tmp_filename, NULL,
                                  svn_io_file_del_on_pool_cleanup,
                                  eb->edit_pool, scratch_pool));
   SVN_ERR(svn_stream_copy3(contents, tmp_stream, NULL, NULL, scratch_pool));
 
-  SVN_ERR(build(eb, ACTION_PUT, relpath, svn_kind_none,
-                NULL, SVN_INVALID_REVNUM,
-                NULL, tmp_filename, md5_checksum, SVN_INVALID_REVNUM,
-                scratch_pool));
-
-  if (props && apr_hash_count(props) > 0)
-    SVN_ERR(build(eb, ACTION_PROPSET, relpath, svn_kind_file,
-                  NULL, SVN_INVALID_REVNUM, props,
-                  NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
+  change->action = RESTRUCTURE_ADD;
+  change->kind = svn_kind_file;
+  change->deleting = replaces_rev;
+  change->props = apr_hash_copy(eb->edit_pool, props);
+  change->contents_abspath = tmp_filename;
+  change->checksum = svn_checksum_dup(md5_checksum, eb->edit_pool);
 
   return SVN_NO_ERROR;
 }
@@ -1463,17 +1116,18 @@ add_symlink_cb(void *baton,
                svn_revnum_t replaces_rev,
                apr_pool_t *scratch_pool)
 {
+#if 0
   struct editor_baton *eb = baton;
+  struct change_node *change = insert_change(relpath, eb->changes);
 
-  if (SVN_IS_VALID_REVNUM(replaces_rev))
-    {
-      /* We need to add the delete action. */
-
-      SVN_ERR(build(eb, ACTION_DELETE, relpath, svn_kind_unknown,
-                    NULL, SVN_INVALID_REVNUM,
-                    NULL, NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
-    }
+  change->action = RESTRUCTURE_ADD;
+  change->kind = svn_kind_symlink;
+  change->deleting = replaces_rev;
+  change->props = apr_hash_copy(eb->edit_pool, props);
+  /* ### target  */
+#endif
 
+  SVN__NOT_IMPLEMENTED();
   return SVN_NO_ERROR;
 }
 
@@ -1486,10 +1140,11 @@ add_absent_cb(void *baton,
               apr_pool_t *scratch_pool)
 {
   struct editor_baton *eb = baton;
+  struct change_node *change = insert_change(relpath, eb->changes);
 
-  SVN_ERR(build(eb, ACTION_ADD_ABSENT, relpath, kind,
-                NULL, SVN_INVALID_REVNUM,
-                NULL, NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
+  change->action = RESTRUCTURE_ADD_ABSENT;
+  change->kind = kind;
+  change->deleting = replaces_rev;
 
   return SVN_NO_ERROR;
 }
@@ -1503,12 +1158,15 @@ alter_directory_cb(void *baton,
                    apr_pool_t *scratch_pool)
 {
   struct editor_baton *eb = baton;
+  struct change_node *change = insert_change(relpath, eb->changes);
 
   /* ### should we verify the kind is truly a directory?  */
 
-  SVN_ERR(build(eb, ACTION_PROPSET, relpath, svn_kind_dir,
-                NULL, SVN_INVALID_REVNUM,
-                props, NULL, NULL, revision, scratch_pool));
+  /* Note: this node may already have information in CHANGE as a result
+     of an earlier copy/move operation.  */
+  change->kind = svn_kind_dir;
+  change->changing = revision;
+  change->props = apr_hash_copy(eb->edit_pool, props);
 
   return SVN_NO_ERROR;
 }
@@ -1527,6 +1185,7 @@ alter_file_cb(void *baton,
   const char *tmp_filename;
   svn_stream_t *tmp_stream;
   svn_checksum_t *md5_checksum;
+  struct change_node *change = insert_change(relpath, eb->changes);
 
   /* ### should we verify the kind is truly a file?  */
 
@@ -1546,17 +1205,19 @@ alter_file_cb(void *baton,
                                      eb->edit_pool, scratch_pool));
       SVN_ERR(svn_stream_copy3(contents, tmp_stream, NULL, NULL,
                                scratch_pool));
-
-      SVN_ERR(build(eb, ACTION_PUT, relpath, svn_kind_file,
-                    NULL, SVN_INVALID_REVNUM,
-                    NULL, tmp_filename, md5_checksum, revision, scratch_pool));
     }
 
-  if (props)
+  /* Note: this node may already have information in CHANGE as a result
+     of an earlier copy/move operation.  */
+
+  change->kind = svn_kind_file;
+  change->changing = revision;
+  if (props != NULL)
+    change->props = apr_hash_copy(eb->edit_pool, props);
+  if (contents != NULL)
     {
-      SVN_ERR(build(eb, ACTION_PROPSET, relpath, svn_kind_file,
-                    NULL, SVN_INVALID_REVNUM,
-                    props, NULL, NULL, revision, scratch_pool));
+      change->contents_abspath = tmp_filename;
+      change->checksum = svn_checksum_dup(md5_checksum, eb->edit_pool);
     }
 
   return SVN_NO_ERROR;
@@ -1587,10 +1248,11 @@ delete_cb(void *baton,
           apr_pool_t *scratch_pool)
 {
   struct editor_baton *eb = baton;
+  struct change_node *change = insert_change(relpath, eb->changes);
 
-  SVN_ERR(build(eb, ACTION_DELETE, relpath, svn_kind_unknown,
-                NULL, revision, NULL, NULL, NULL, SVN_INVALID_REVNUM,
-                scratch_pool));
+  change->action = RESTRUCTURE_DELETE;
+  /* change->kind = svn_kind_unknown;  */
+  change->deleting = revision;
 
   return SVN_NO_ERROR;
 }
@@ -1605,19 +1267,22 @@ copy_cb(void *baton,
         apr_pool_t *scratch_pool)
 {
   struct editor_baton *eb = baton;
+  struct change_node *change = insert_change(dst_relpath, eb->changes);
 
-  if (SVN_IS_VALID_REVNUM(replaces_rev))
-    {
-      /* We need to add the delete action. */
-
-      SVN_ERR(build(eb, ACTION_DELETE, dst_relpath, svn_kind_unknown,
-                    NULL, SVN_INVALID_REVNUM,
-                    NULL, NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
-    }
+  change->action = RESTRUCTURE_ADD;
+  /* change->kind = svn_kind_unknown;  */
+  change->deleting = replaces_rev;
+  change->copyfrom_path = apr_pstrdup(eb->edit_pool, src_relpath);
+  change->copyfrom_rev = src_revision;
+
+  /* We need the source's kind to know whether to call add_directory()
+     or add_file() later on.  */
+  SVN_ERR(eb->fetch_kind_func(&change->kind, eb->fetch_kind_baton,
+                              change->copyfrom_path,
+                              change->copyfrom_rev,
+                              scratch_pool));
 
-  SVN_ERR(build(eb, ACTION_COPY, dst_relpath, svn_kind_unknown,
-                src_relpath, src_revision, NULL, NULL, NULL,
-                SVN_INVALID_REVNUM, scratch_pool));
+  /* Note: this node may later have alter_*() called on it.  */
 
   return SVN_NO_ERROR;
 }
@@ -1632,23 +1297,30 @@ move_cb(void *baton,
         apr_pool_t *scratch_pool)
 {
   struct editor_baton *eb = baton;
+  struct change_node *change;
 
-  /* Delete the move source. */
-  SVN_ERR(build(eb, ACTION_DELETE, src_relpath, svn_kind_unknown,
-                NULL, src_revision, NULL, NULL, NULL, SVN_INVALID_REVNUM,
-                scratch_pool));
-
-  if (SVN_IS_VALID_REVNUM(replaces_rev))
-    {
-      /* We need to add the delete action for the replaced target. */
-      SVN_ERR(build(eb, ACTION_DELETE, dst_relpath, svn_kind_unknown,
-                    NULL, SVN_INVALID_REVNUM,
-                    NULL, NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
-    }
-
-  SVN_ERR(build(eb, ACTION_COPY, dst_relpath, svn_kind_unknown,
-                src_relpath, src_revision, NULL, NULL, NULL,
-                SVN_INVALID_REVNUM, scratch_pool));
+  /* Remap a move into a DELETE + COPY.  */
+
+  change = insert_change(src_relpath, eb->changes);
+  change->action = RESTRUCTURE_DELETE;
+  /* change->kind = svn_kind_unknown;  */
+  change->deleting = src_revision;
+
+  change = insert_change(dst_relpath, eb->changes);
+  change->action = RESTRUCTURE_ADD;
+  /* change->kind = svn_kind_unknown;  */
+  change->deleting = replaces_rev;
+  change->copyfrom_path = apr_pstrdup(eb->edit_pool, src_relpath);
+  change->copyfrom_rev = src_revision;
+
+  /* We need the source's kind to know whether to call add_directory()
+     or add_file() later on.  */
+  SVN_ERR(eb->fetch_kind_func(&change->kind, eb->fetch_kind_baton,
+                              change->copyfrom_path,
+                              change->copyfrom_rev,
+                              scratch_pool));
+
+  /* Note: this node may later have alter_*() called on it.  */
 
   return SVN_NO_ERROR;
 }
@@ -1664,200 +1336,287 @@ rotate_cb(void *baton,
   return SVN_NO_ERROR;
 }
 
+
 static svn_error_t *
-change_props(const svn_delta_editor_t *editor,
-             void *baton,
-             const struct operation *child,
-             apr_pool_t *scratch_pool)
+drive_ev1_props(const struct editor_baton *eb,
+                const char *repos_relpath,
+                const struct change_node *change,
+                void *node_baton,
+                apr_pool_t *scratch_pool)
 {
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  apr_hash_t *old_props;
+  apr_array_header_t *propdiffs;
+  const char *ev1_relpath;
+  int i;
 
-  if (child->prop_dels)
+  /* If there are no properties to install, then just exit.  */
+  if (change->props == NULL)
+    return SVN_NO_ERROR;
+
+  if (change->copyfrom_path)
     {
-      int i;
-      for (i = 0; i < child->prop_dels->nelts; i++)
-        {
-          const char *prop_name;
+      /* The pristine properties are from the copy/move source.  */
+      SVN_ERR(eb->fetch_props_func(&old_props, eb->fetch_props_baton,
+                                   change->copyfrom_path,
+                                   change->copyfrom_rev,
+                                   scratch_pool, iterpool));
+    }
+  else if (change->action == RESTRUCTURE_ADD)
+    {
+      /* Locally-added nodes have no pristine properties.
 
-          svn_pool_clear(iterpool);
-          prop_name = APR_ARRAY_IDX(child->prop_dels, i, const char *);
-          if (child->kind == svn_kind_dir)
-            SVN_ERR(editor->change_dir_prop(baton, prop_name,
-                                            NULL, iterpool));
-          else
-            SVN_ERR(editor->change_file_prop(baton, prop_name,
-                                             NULL, iterpool));
-        }
+         Note: we can use iterpool; this hash only needs to survive to
+         the propdiffs call, and there are no contents to preserve.  */
+      old_props = apr_hash_make(iterpool);
     }
+  else
+    {
+      /* Fetch the pristine properties for whatever we're editing.  */
+      SVN_ERR(eb->fetch_props_func(&old_props, eb->fetch_props_baton,
+                                   repos_relpath, change->changing,
+                                   scratch_pool, iterpool));
+    }
+
+  SVN_ERR(svn_prop_diffs(&propdiffs, change->props, old_props, scratch_pool));
 
-  if (apr_hash_count(child->prop_mods))
+  ev1_relpath = svn_relpath_skip_ancestor(eb->base_relpath, repos_relpath);
+
+  for (i = 0; i < propdiffs->nelts; i++)
     {
-      apr_hash_index_t *hi;
-      for (hi = apr_hash_first(scratch_pool, child->prop_mods);
-           hi; hi = apr_hash_next(hi))
-        {
-          const char *name = svn__apr_hash_index_key(hi);
-          svn_string_t *val = svn__apr_hash_index_val(hi);
+      /* Note: the array returned by svn_prop_diffs() is an array of
+         actual structures, not pointers to them. */
+      const svn_prop_t *prop = &APR_ARRAY_IDX(propdiffs, i, svn_prop_t);
 
-          svn_pool_clear(iterpool);
-          if (child->kind == svn_kind_dir)
-            SVN_ERR(editor->change_dir_prop(baton, name, val, iterpool));
-          else
-            SVN_ERR(editor->change_file_prop(baton, name, val, iterpool));
-        }
+      svn_pool_clear(iterpool);
+
+      if (change->kind == svn_kind_dir)
+        SVN_ERR(eb->deditor->change_dir_prop(node_baton,
+                                             prop->name, prop->value,
+                                             iterpool));
+      else
+        SVN_ERR(eb->deditor->change_file_prop(node_baton,
+                                              prop->name, prop->value,
+                                              iterpool));
+    }
+
+  /* Handle the funky unlock protocol. Note: only possibly on files.  */
+  if (change->unlock)
+    {
+      SVN_ERR_ASSERT(change->kind == svn_kind_file);
+      SVN_ERR(eb->deditor->change_file_prop(node_baton,
+                                            SVN_PROP_ENTRY_LOCK_TOKEN, NULL,
+                                            iterpool));
     }
 
   svn_pool_destroy(iterpool);
   return SVN_NO_ERROR;
 }
 
+
+/* Conforms to svn_delta_path_driver_cb_func_t  */
 static svn_error_t *
-drive_tree(struct operation *op,
-           const struct operation *parent_op,
-           const svn_delta_editor_t *editor,
-           svn_boolean_t make_abs_paths,
-           apr_pool_t *scratch_pool)
+apply_change(void **dir_baton,
+             void *parent_baton,
+             void *callback_baton,
+             const char *ev1_relpath,
+             apr_pool_t *result_pool)
 {
-  const char *path = op->path;
+  /* ### fix this?  */
+  apr_pool_t *scratch_pool = result_pool;
+  const struct editor_baton *eb = callback_baton;
+  const struct change_node *change;
+  const char *relpath;
+  void *file_baton = NULL;
+
+  /* Typically, we are not creating new directory batons.  */
+  *dir_baton = NULL;
 
-  if (path[0] != '/' && make_abs_paths)
-    path = apr_pstrcat(scratch_pool, "/", path, NULL);
+  relpath = svn_relpath_join(eb->base_relpath, ev1_relpath, scratch_pool);
+  change = apr_hash_get(eb->changes, relpath, APR_HASH_KEY_STRING);
 
-  /* Deletes and replacements are simple -- just delete the thing. */
-  if (op->operation == OP_DELETE || op->operation == OP_REPLACE)
+  /* The callback should only be called for paths in CHANGES.  */
+  SVN_ERR_ASSERT(change != NULL);
+
+  /* Are we editing the root of the tree?  */
+  if (parent_baton == NULL)
     {
-      SVN_ERR(editor->delete_entry(path, op->base_revision,
-                                   parent_op->baton, scratch_pool));
+      /* The root was opened in start_edit_func()  */
+      *dir_baton = eb->root.baton;
+
+      /* Only property edits are allowed on the root.  */
+      SVN_ERR_ASSERT(change->action == RESTRUCTURE_NONE);
+      SVN_ERR(drive_ev1_props(eb, relpath, change, *dir_baton, scratch_pool));
+
+      /* No further action possible for the root.  */
+      return SVN_NO_ERROR;
     }
 
-  if (op->kind == svn_kind_dir)
+  if (change->action == RESTRUCTURE_DELETE)
     {
-      /* Open or create our baton. */
-      if (op->operation == OP_OPEN || op->operation == OP_PROPSET)
-        SVN_ERR(editor->open_directory(path, parent_op->baton,
-                                       op->base_revision,
-                                       scratch_pool, &op->baton));
+      SVN_ERR(eb->deditor->delete_entry(ev1_relpath, change->deleting,
+                                        parent_baton, scratch_pool));
 
-      else if (op->operation == OP_ADD || op->operation == OP_REPLACE)
-        SVN_ERR(editor->add_directory(path, parent_op->baton,
-                                      op->copyfrom_url, op->copyfrom_revision,
-                                      scratch_pool, &op->baton));
+      /* No futher action possible for this node.  */
+      return SVN_NO_ERROR;
+    }
 
-      else if (op->operation == OP_ADD_ABSENT)
-        SVN_ERR(editor->absent_directory(path, parent_op->baton,
+  /* If we're not deleting this node, then we should know its kind.  */
+  SVN_ERR_ASSERT(change->kind != svn_kind_unknown);
+
+  if (change->action == RESTRUCTURE_ADD_ABSENT)
+    {
+      if (change->kind == svn_kind_dir)
+        SVN_ERR(eb->deditor->absent_directory(ev1_relpath, parent_baton,
+                                              scratch_pool));
+      else
+        SVN_ERR(eb->deditor->absent_file(ev1_relpath, parent_baton,
                                          scratch_pool));
 
-      if (op->baton)
-        {
-          apr_pool_t *iterpool = svn_pool_create(scratch_pool);
-          apr_hash_index_t *hi;
+      /* No further action possible for this node.  */
+      return SVN_NO_ERROR;
+    }
+  /* RESTRUCTURE_NONE or RESTRUCTURE_ADD  */
 
-          /* Do any prop mods we may have. */
-          SVN_ERR(change_props(editor, op->baton, op, scratch_pool));
+  if (change->action == RESTRUCTURE_ADD)
+    {
+      const char *copyfrom_url = NULL;
+      svn_revnum_t copyfrom_rev = SVN_INVALID_REVNUM;
 
-          for (hi = apr_hash_first(scratch_pool, op->children);
-               hi; hi = apr_hash_next(hi))
-            {
-              struct operation *child = svn__apr_hash_index_val(hi);
+      /* Do we have an old node to delete first?  */
+      if (SVN_IS_VALID_REVNUM(change->deleting))
+        SVN_ERR(eb->deditor->delete_entry(ev1_relpath, change->deleting,
+                                          parent_baton, scratch_pool));
 
-              svn_pool_clear(iterpool);
-              SVN_ERR(drive_tree(child, op, editor, make_abs_paths, iterpool));
-            }
-          svn_pool_destroy(iterpool);
+      /* Are we copying the node from somewhere?  */
+      if (change->copyfrom_path)
+        {
+          if (eb->repos_root)
+            copyfrom_url = svn_path_url_add_component2(eb->repos_root,
+                                                       change->copyfrom_path,
+                                                       scratch_pool);
+          else
+            /* ### prefix with "/" ?  */
+            copyfrom_url = change->copyfrom_path;
 
-          /* We're done, close the directory. */
-          SVN_ERR(editor->close_directory(op->baton, scratch_pool));
+          copyfrom_rev = change->copyfrom_rev;
         }
+
+      if (change->kind == svn_kind_dir)
+        SVN_ERR(eb->deditor->add_directory(ev1_relpath, parent_baton,
+                                           copyfrom_url, copyfrom_rev,
+                                           result_pool, dir_baton));
+      else
+        SVN_ERR(eb->deditor->add_file(ev1_relpath, parent_baton,
+                                      copyfrom_url, copyfrom_rev,
+                                      result_pool, &file_baton));
     }
   else
     {
-      /* This currently treats anything that isn't a directory as a file.
-         I don't know that that's a valid assumption... */
-
-      void *file_baton = NULL;
-
-      /* Open or create our baton. */
-      if (op->operation == OP_OPEN || op->operation == OP_PROPSET)
-        SVN_ERR(editor->open_file(path, parent_op->baton, op->base_revision,
-                                  scratch_pool, &file_baton));
-
-      else if (op->operation == OP_ADD || op->operation == OP_REPLACE)
-        SVN_ERR(editor->add_file(path, parent_op->baton, op->copyfrom_url,
-                                 op->copyfrom_revision, scratch_pool,
-                                 &file_baton));
-
-      else if (op->operation == OP_ADD_ABSENT)
-        SVN_ERR(editor->absent_file(path, parent_op->baton, scratch_pool));
+      if (change->kind == svn_kind_dir)
+        SVN_ERR(eb->deditor->open_directory(ev1_relpath, parent_baton,
+                                            change->changing,
+                                            result_pool, dir_baton));
+      else
+        SVN_ERR(eb->deditor->open_file(ev1_relpath, parent_baton,
+                                       change->changing,
+                                       result_pool, &file_baton));
+    }
 
-      if (file_baton)
-        {
-          /* Do we need to change text contents? */
-          if (op->src_file)
-            {
-              svn_txdelta_window_handler_t handler;
-              void *handler_baton;
-              svn_stream_t *contents;
-
-              SVN_ERR(editor->apply_textdelta(file_baton, NULL, scratch_pool,
-                                              &handler, &handler_baton));
-              SVN_ERR(svn_stream_open_readonly(&contents, op->src_file,
-                                               scratch_pool, scratch_pool));
-              SVN_ERR(svn_txdelta_send_stream(contents, handler, handler_baton,
-                                              NULL, scratch_pool));
-              SVN_ERR(svn_stream_close(contents));
-            }
+  /* Apply any properties in CHANGE to the node.  */
+  if (change->kind == svn_kind_dir)
+    SVN_ERR(drive_ev1_props(eb, relpath, change, *dir_baton, scratch_pool));
+  else
+    SVN_ERR(drive_ev1_props(eb, relpath, change, file_baton, scratch_pool));
 
-          /* Do any prop mods we may have. */
-          SVN_ERR(change_props(editor, file_baton, op, scratch_pool));
+  if (change->contents_abspath)
+    {
+      svn_txdelta_window_handler_t handler;
+      void *handler_baton;
+      svn_stream_t *contents;
+
+      /* ### would be nice to have a BASE_CHECKSUM, but hey: this is the
+         ### shim code...  */
+      SVN_ERR(eb->deditor->apply_textdelta(file_baton, NULL, scratch_pool,
+                                           &handler, &handler_baton));
+      SVN_ERR(svn_stream_open_readonly(&contents, change->contents_abspath,
+                                       scratch_pool, scratch_pool));
+      /* ### it would be nice to send a true txdelta here, but whatever.  */
+      SVN_ERR(svn_txdelta_send_stream(contents, handler, handler_baton,
+                                      NULL, scratch_pool));
+      SVN_ERR(svn_stream_close(contents));
+    }
 
-          /* Close the file. */
-          SVN_ERR(editor->close_file(file_baton,
-                                     svn_checksum_to_cstring(op->new_checksum,
-                                                             scratch_pool),
-                                     scratch_pool));
-        }
+  if (file_baton)
+    {
+      const char *digest = svn_checksum_to_cstring(change->checksum,
+                                                   scratch_pool);
 
+      SVN_ERR(eb->deditor->close_file(file_baton, digest, scratch_pool));
     }
 
   return SVN_NO_ERROR;
 }
 
-/* This is a special case of drive_tree(), meant to handle the root, which
-   doesn't have a parent and should already be open. */
+
 static svn_error_t *
-drive_root(struct operation *root,
-           const svn_delta_editor_t *editor,
-           svn_boolean_t make_abs_paths,
-           apr_pool_t *scratch_pool)
+drive_changes(const struct editor_baton *eb,
+              apr_pool_t *scratch_pool)
 {
+  struct change_node *change;
+  apr_array_header_t *paths = apr_array_make(scratch_pool, 10,
+                                             sizeof(const char *));
   apr_hash_index_t *hi;
-  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
-  /* Early out: if we haven't opened the root yet (which would usually only
-     be the case in an abort), there isn't much we can do here. */
-  if (!root->baton)
+  /* If we never opened a root baton, then the caller aborted the editor
+     before it even began. There is nothing to do. Bail.  */
+  if (eb->root.baton == NULL)
     return SVN_NO_ERROR;
 
-  /* Do any prop mods we may have. */
-  SVN_ERR(change_props(editor, root->baton, root, scratch_pool));
+  /* We need to make the path driver believe we want to make changes to
+     the root. Otherwise, it will attempt an open_root(), which we already
+     did in start_edit_func(). We can forge up a change record, if one
+     does not already exist.  */
+  change = insert_change(eb->base_relpath, eb->changes);
+  change->kind = svn_kind_dir;
+  /* No property changes (tho they might exist from a real change).  */
 
-  /* Now iterate over our children. */
-  for (hi = apr_hash_first(scratch_pool, root->children);
-       hi; hi = apr_hash_next(hi))
+  for (hi = apr_hash_first(scratch_pool, eb->changes); hi;
+       hi = apr_hash_next(hi))
     {
-      struct operation *child = svn__apr_hash_index_val(hi);
-
-      svn_pool_clear(iterpool);
-      SVN_ERR(drive_tree(child, root, editor, make_abs_paths, iterpool));
+      const char *relpath = svn__apr_hash_index_key(hi);
+      const char *ev1_relpath = svn_relpath_skip_ancestor(eb->base_relpath,
+                                                          relpath);
+      APR_ARRAY_PUSH(paths, const char *) = ev1_relpath;
     }
 
-  /* We need to close the root directory, but leave it to our caller to call
-     close_ or abort_edit(). */
-  SVN_ERR(editor->close_directory(root->baton, scratch_pool));
+  /* We need to pass SVN_INVALID_REVNUM to the path_driver. It uses this
+     revision whenever it opens directory batons. If we specified a "real"
+     value, such as eb->root.base_revision, then it might use that for a
+     subdirectory *incorrectly*.
+
+     Specifically, log_tests 38 demonstrates that erroneous behavior when
+     it attempts to open "/A" at revision 0 (not there, of course).
+
+     All this said: passing SVN_INVALID_REVNUM to all of those
+     open_directory() calls is not the best behavior either, but it does
+     happen to magically work. (ugh)
+
+     Thankfully, we're moving away from this skitchy behavior to Ev2.
+
+     Final note: every other caller of svn_delta_path_driver() passes
+     SVN_INVALID_REVNUM, so we can't be the only goofball.
+
+     Note: dropping const on the callback_baton.  */
+  SVN_ERR(svn_delta_path_driver(eb->deditor, eb->dedit_baton,
+                                SVN_INVALID_REVNUM, paths,
+                                apply_change, (void *)eb,
+                                scratch_pool));
 
   return SVN_NO_ERROR;
 }
 
+
 /* This implements svn_editor_cb_complete_t */
 static svn_error_t *
 complete_cb(void *baton,
@@ -1867,7 +1626,7 @@ complete_cb(void *baton,
   svn_error_t *err;
 
   /* Drive the tree we've created. */
-  err = drive_root(&eb->root, eb->deditor, *eb->make_abs_paths, scratch_pool);
+  err = drive_changes(eb, scratch_pool);
   if (!err)
      {
        err = svn_error_compose_create(err, eb->deditor->close_edit(
@@ -1894,7 +1653,7 @@ abort_cb(void *baton,
      point. */
 
   /* Drive the tree we've created. */
-  err = drive_root(&eb->root, eb->deditor, *eb->make_abs_paths, scratch_pool);
+  err = drive_changes(eb, scratch_pool);
 
   err2 = eb->deditor->abort_edit(eb->dedit_baton, scratch_pool);
 
@@ -1916,6 +1675,10 @@ start_edit_func(void *baton,
   struct editor_baton *eb = baton;
 
   eb->root.base_revision = base_revision;
+
+  /* For some Ev1 editors (such as the repos commit editor), the root must
+     be open before can invoke any callbacks. The open_root() call sets up
+     stuff (eg. open an FS txn) which will be needed.  */
   SVN_ERR(eb->deditor->open_root(eb->dedit_baton, eb->root.base_revision,
                                  eb->edit_pool, &eb->root.baton));
 
@@ -1941,25 +1704,14 @@ do_unlock(void *baton,
           apr_pool_t *scratch_pool)
 {
   struct editor_baton *eb = baton;
-  apr_array_header_t *path_bits = svn_path_decompose(path, scratch_pool);
-  const char *path_so_far = "";
-  struct operation *operation = &eb->root;
-  int i;
-
-  /* Look for any previous operations we've recognized for PATH.  If
-     any of PATH's ancestors have not yet been traversed, we'll be
-     creating OP_OPEN operations for them as we walk down PATH's path
-     components. */
-  for (i = 0; i < path_bits->nelts; ++i)
-    {
-      const char *path_bit = APR_ARRAY_IDX(path_bits, i, const char *);
-      path_so_far = svn_relpath_join(path_so_far, path_bit, scratch_pool);
-      operation = get_operation(path_so_far, operation, SVN_INVALID_REVNUM,
-                                eb->edit_pool);
-    }
 
-  APR_ARRAY_PUSH(operation->prop_dels, const char *) =
-                                                SVN_PROP_ENTRY_LOCK_TOKEN;
+  {
+    /* PATH is REPOS_RELPATH  */
+    struct change_node *change = insert_change(path, eb->changes);
+
+    /* We will need to propagate a deletion of SVN_PROP_ENTRY_LOCK_TOKEN  */
+    change->unlock = TRUE;
+  }
 
   return SVN_NO_ERROR;
 }
@@ -2037,22 +1789,17 @@ svn_delta__editor_from_delta(svn_editor_
   eb->deditor = deditor;
   eb->dedit_baton = dedit_baton;
   eb->edit_pool = result_pool;
-  eb->paths = apr_hash_make(result_pool);
   eb->repos_root = apr_pstrdup(result_pool, repos_root);
   eb->base_relpath = apr_pstrdup(result_pool, base_relpath);
 
+  eb->changes = apr_hash_make(result_pool);
+
   eb->fetch_kind_func = fetch_kind_func;
   eb->fetch_kind_baton = fetch_kind_baton;
   eb->fetch_props_func = fetch_props_func;
   eb->fetch_props_baton = fetch_props_baton;
 
-  eb->root.path = NULL;
-  eb->root.children = apr_hash_make(result_pool);
-  eb->root.kind = svn_kind_dir;
-  eb->root.operation = OP_OPEN;
-  eb->root.prop_mods = apr_hash_make(result_pool);
-  eb->root.prop_dels = apr_array_make(result_pool, 1, sizeof(const char *));
-  eb->root.copyfrom_revision = SVN_INVALID_REVNUM;
+  eb->root.base_revision = SVN_INVALID_REVNUM;
 
   eb->make_abs_paths = send_abs_paths;
 

Modified: subversion/branches/ev2-export/subversion/libsvn_delta/debug_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_delta/debug_editor.c?rev=1332392&r1=1332391&r2=1332392&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_delta/debug_editor.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_delta/debug_editor.c Mon Apr 30 21:04:36 2012
@@ -51,7 +51,7 @@ write_indent(struct edit_baton *eb, apr_
   int i;
 
   for (i = 0; i < eb->indent_level; ++i)
-    SVN_ERR(svn_stream_printf(eb->out, pool, " "));
+    SVN_ERR(svn_stream_puts(eb->out, " "));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/ev2-export/subversion/libsvn_delta/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_delta/editor.c?rev=1332392&r1=1332391&r2=1332392&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_delta/editor.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_delta/editor.c Mon Apr 30 21:04:36 2012
@@ -397,7 +397,7 @@ check_cancel(svn_editor_t *editor)
       END_CALLBACK(editor);
     }
 
-  return err;
+  return svn_error_trace(err);
 }
 
 
@@ -448,7 +448,7 @@ svn_editor_add_directory(svn_editor_t *e
 #endif
 
   svn_pool_clear(editor->scratch_pool);
-  return err;
+  return svn_error_trace(err);
 }
 
 
@@ -486,7 +486,7 @@ svn_editor_add_file(svn_editor_t *editor
   CLEAR_INCOMPLETE(editor, relpath);
 
   svn_pool_clear(editor->scratch_pool);
-  return err;
+  return svn_error_trace(err);
 }
 
 
@@ -519,7 +519,7 @@ svn_editor_add_symlink(svn_editor_t *edi
   CLEAR_INCOMPLETE(editor, relpath);
 
   svn_pool_clear(editor->scratch_pool);
-  return err;
+  return svn_error_trace(err);
 }
 
 
@@ -550,7 +550,7 @@ svn_editor_add_absent(svn_editor_t *edit
   CLEAR_INCOMPLETE(editor, relpath);
 
   svn_pool_clear(editor->scratch_pool);
-  return err;
+  return svn_error_trace(err);
 }
 
 
@@ -581,7 +581,7 @@ svn_editor_alter_directory(svn_editor_t 
   MARK_COMPLETED(editor, relpath);
 
   svn_pool_clear(editor->scratch_pool);
-  return err;
+  return svn_error_trace(err);
 }
 
 
@@ -619,7 +619,7 @@ svn_editor_alter_file(svn_editor_t *edit
   MARK_COMPLETED(editor, relpath);
 
   svn_pool_clear(editor->scratch_pool);
-  return err;
+  return svn_error_trace(err);
 }
 
 
@@ -652,7 +652,7 @@ svn_editor_alter_symlink(svn_editor_t *e
   MARK_COMPLETED(editor, relpath);
 
   svn_pool_clear(editor->scratch_pool);
-  return err;
+  return svn_error_trace(err);
 }
 
 
@@ -680,7 +680,7 @@ svn_editor_delete(svn_editor_t *editor,
   MARK_COMPLETED(editor, relpath);
 
   svn_pool_clear(editor->scratch_pool);
-  return err;
+  return svn_error_trace(err);
 }
 
 
@@ -713,7 +713,7 @@ svn_editor_copy(svn_editor_t *editor,
   CLEAR_INCOMPLETE(editor, dst_relpath);
 
   svn_pool_clear(editor->scratch_pool);
-  return err;
+  return svn_error_trace(err);
 }
 
 
@@ -748,7 +748,7 @@ svn_editor_move(svn_editor_t *editor,
   CLEAR_INCOMPLETE(editor, dst_relpath);
 
   svn_pool_clear(editor->scratch_pool);
-  return err;
+  return svn_error_trace(err);
 }
 
 
@@ -795,7 +795,7 @@ svn_editor_rotate(svn_editor_t *editor,
 #endif
 
   svn_pool_clear(editor->scratch_pool);
-  return err;
+  return svn_error_trace(err);
 }
 
 
@@ -819,7 +819,7 @@ svn_editor_complete(svn_editor_t *editor
   MARK_FINISHED(editor);
 
   svn_pool_clear(editor->scratch_pool);
-  return err;
+  return svn_error_trace(err);
 }
 
 
@@ -840,5 +840,5 @@ svn_editor_abort(svn_editor_t *editor)
   MARK_FINISHED(editor);
 
   svn_pool_clear(editor->scratch_pool);
-  return err;
+  return svn_error_trace(err);
 }