You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2014/06/30 16:09:16 UTC

svn commit: r1606748 [1/2] - in /subversion/branches/move-tracking-2/subversion: include/private/svn_editor3.h libsvn_delta/editor3.c

Author: julianfoad
Date: Mon Jun 30 14:09:16 2014
New Revision: 1606748

URL: http://svn.apache.org/r1606748
Log:
On the 'moves-tracking-2' branch: add an experimental new editor design.

* subversion/include/private/svn_editor3.h,
  subversion/libsvn_delta/editor3.c
  New files.

Added:
    subversion/branches/move-tracking-2/subversion/include/private/svn_editor3.h
      - copied, changed from r1606692, subversion/branches/move-tracking-2/subversion/include/private/svn_editor.h
    subversion/branches/move-tracking-2/subversion/libsvn_delta/editor3.c
      - copied, changed from r1606692, subversion/branches/move-tracking-2/subversion/libsvn_delta/editor.c

Copied: subversion/branches/move-tracking-2/subversion/include/private/svn_editor3.h (from r1606692, subversion/branches/move-tracking-2/subversion/include/private/svn_editor.h)
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/include/private/svn_editor3.h?p2=subversion/branches/move-tracking-2/subversion/include/private/svn_editor3.h&p1=subversion/branches/move-tracking-2/subversion/include/private/svn_editor.h&r1=1606692&r2=1606748&rev=1606748&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/include/private/svn_editor.h (original)
+++ subversion/branches/move-tracking-2/subversion/include/private/svn_editor3.h Mon Jun 30 14:09:16 2014
@@ -20,12 +20,16 @@
  * ====================================================================
  * @endcopyright
  *
- * @file svn_editor.h
- * @brief Tree editing functions and structures
+ * @file svn_editor3.h
+ * @brief Tree editing
+ *
+ * @since New in 1.10.
  */
 
-#ifndef SVN_EDITOR_H
-#define SVN_EDITOR_H
+#ifndef SVN_EDITOR3_H
+#define SVN_EDITOR3_H
+
+#include "svn_editor.h"
 
 #include <apr_pools.h>
 
@@ -39,444 +43,697 @@ extern "C" {
 #endif /* __cplusplus */
 
 
-/*** Temporarily private stuff (should move to svn_delta.h when Editor
-     V2 is made public) ***/
+/*
+ * ### Under construction. Currently, two kinds of editor interface are
+ *     declared within the same "svn_editor3_t" framework. This is for
+ *     experimentation, and not intended to stay that way.
+ */
+
+/*
+ * ===================================================================
+ * Possible contexts (uses) for an editor
+ * ===================================================================
+ *
+ * (1) Commit directly to repo
+ *
+ *   - From single-rev to single-rev
+ *   - Diff: with simple context (for simple merge with recent commits)
+ *   - Copies: can send O(1) "copy" (recursive + edits)
+ *   - Copies: can copy from within the new rev (?)
+ *
+ * (2) Commit from WC
+ *
+ *   - From mixed-rev to single-rev
+ *   - Rx needs to be told the "from" revisions
+ *   - Diff: with simple context (for simple merge with recent commits)
+ *   - Copies: can copy from within the new rev (?)
+ *
+ * (3) Update/Switch
+ *
+ *   - One change per *WC* path rather than per *repo* path
+ *   - From mixed-rev to single-rev
+ *   - Rx initially has a complete copy of the "from" state
+ *   - Diff: with context (for merging)
+ *   - Copies: can expand "copy" (non-recursive)
+ *
+ * (4) Diff (wc-base/repo:repo) (for merging/patching/displaying)
+ *
+ *   - From mixed-rev (for wc-base) to single-rev
+ *       (enhancement: mixed-rev "to" state?)
+ *   - Rx needs to be told the "from" revisions
+ *   - Diff: with context (for merging)
+ *   - Diff: can be reversible
+ *   - Copies: can send O(1) "copy" (recursive + edits)
+ *   - Copies: can expand "copy" (non-recursive)
+ *
+ * ===================================================================
+ * Two different styles of "editing"
+ * ===================================================================
+ *
+ * (1) Ordered, cumulative changes to a txn
+ *
+ * (2) Transmission of a set of independent changes
+ *
+ * These can be mixed: e.g. one interface declared here uses style (1)
+ * for tree changes with style (2) for content changes.
+ *
+ * ===================================================================
+ * WC update/switch
+ * ===================================================================
+ *
+ * How Subversion does an update (or switch), roughly:
+ *
+ *   - Client sends a "report" of WC base node locations to server.
+ *   - Server calculates a diff from reported mixed-rev WC-base to
+ *     requested single-rev target.
+ *   - Server maps repo paths to WC paths (using the report) before
+ *     transmitting edits.
+ *
+ * ===================================================================
+ * Commit from WC
+ * ===================================================================
+ * 
+ * How Subversion does a commit, roughly:
+ *
+ *   - Server starts a txn based on current head rev
+ *
+ *                   r1 2 3 4 5 6 7 8 head  txn
+ *     WC-base  @4 -> A . . M . . . . .     |...
+ *      |_B     @3 -> A . M . . . . . .  == |...D
+ *      |_C     @3 -> A . M . . . . . .     |...
+ *        |_foo @6 -> . A . . . M . D .     |...
+ *       \_____________________________________/
+ *            del /B r3
+ *
+ *   - Client sends changes based on its WC-base rev for each node,
+ *     sending "this is the base rev I'm using" for each node.
+ *
+ *   - Server "merges" the client's changes into the txn on the fly,
+ *     rejecting as "out of date" any change that requires a non-trivial
+ *     merge.
+ *
+ *                   r1 2 3 4 5 6 7 8 head
+ *     WC-base  @4 -> A . . M . . . . .
+ *      |_B     @3 -> A . M . . . . . .    txn
+ *      |_C     @3 -> A . M . . . . . . \  |...
+ *        |_foo @6 -> . A . . . M . D .  \ |...x
+ *       \                                 |...
+ *        \                                |...OOD! (deleted since r6)
+ *         \___________________________________/
+ *            edit /C/foo r6
+ *
+ *   - Server "merges" the txn in the same way with any further commits,
+ *     until there are no further commits, and then commits the txn.
+ *
+ * The old design assumes that the client can refer to a node by its path.
+ * Either this path in the txn refers to the same node as in the WC base,
+ * or the WC base node has since been deleted and perhaps replaced. This is
+ * detected by the OOD check. The node's path-in-txn can never be different
+ * from its path-in-WC-base.
+ *
+ * When we introduce moves, it is possible that nodes referenced by the WC
+ * will have been moved in the repository after the WC-base and before the
+ * txn-base. Unless the client queries for such moves, it will not know
+ * what path-in-txn corresponds to each path-in-WC-base.
+ * 
+ * It seems wrong to design an editor interface that requires there have
+ * been no moves in the repository between the WC base and the txn-base
+ * affecting the paths being referenced in the commit. Not totally
+ * unreasonable for the typical work flows of today, but unreasonably
+ * restricting the work flows that should be possible in the future with
+ * move tracking in place.
+ */
+
+/**
+ * @defgroup svn_editor The editor interface
+ * @{
+ */
+
+/** Tree Editor
+ */
+typedef struct svn_editor3_t svn_editor3_t;
 
-/** Callback to retrieve a node's entire set of properties.  This is
- * needed by the various editor shims in order to effect backwards
- * compatibility.
- *
- * Implementations should set @a *props to the hash of properties
- * associated with @a path in @a base_revision, allocating that hash
- * and its contents in @a result_pool, and should use @a scratch_pool
- * for temporary allocations.
+/** A location in the current transaction (when @a rev == -1) or in
+ * a revision (when @a rev != -1). */
+typedef struct pathrev_t
+{
+  svn_revnum_t rev;
+  const char *relpath;
+} pathrev_t;
+
+/** Node-Branch Identifier -- like the FSFS <node-id>.<copy-id>.
+ * (Presently a null-terminated C string.) */
+typedef char *svn_editor3_nbid_t;
+
+/** Versioned content of a node, excluding tree structure information.
+ *
+ * This specifies the content (properties, text of a file, symbolic link
+ * target) directly, or by reference to an existing committed node, or
+ * by a delta against such a reference content.
  *
- * @a baton is an implementation-specific closure.
+ * ### An idea: If the sender and receiver agree, the content for a node
+ *     may be specified as "null" to designate that the content is not
+ *     available. For example, when a client performing a WC update has
+ *     no read authorization for a given path, the server may send null
+ *     content and the client may record an 'absent' WC node. (This
+ *     would not make sense in a commit.)
  */
-typedef svn_error_t *(*svn_delta_fetch_props_func_t)(
-  apr_hash_t **props,
-  void *baton,
-  const char *path,
-  svn_revnum_t base_revision,
-  apr_pool_t *result_pool,
-  apr_pool_t *scratch_pool
-  );
-
-/** Callback to retrieve a node's kind.  This is needed by the various
- * editor shims in order to effect backwards compatibility.
+typedef struct svn_editor3_node_content_t svn_editor3_node_content_t;
+
+/** The kind of the checksum to be used throughout the #svn_editor3_t APIs.
+ */
+#define SVN_EDITOR3_CHECKSUM_KIND svn_checksum_sha1
+
+
+/** These functions are called by the tree delta driver to edit the target.
  *
- * Implementations should set @a *kind to the node kind of @a path in
- * @a base_revision, using @a scratch_pool for temporary allocations.
+ * @see svn_editor3_t.
  *
- * @a baton is an implementation-specific closure.
+ * @defgroup svn_editor3_drive Driving the editor
+ * @{
  */
-typedef svn_error_t *(*svn_delta_fetch_kind_func_t)(
-  svn_node_kind_t *kind,
-  void *baton,
-  const char *path,
-  svn_revnum_t base_revision,
-  apr_pool_t *scratch_pool
-  );
-
-/** Callback to fetch the name of a file to use as a delta base.
- *
- * Implementations should set @a *filename to the name of a file
- * suitable for use as a delta base for @a path in @a base_revision
- * (allocating @a *filename from @a result_pool), or to @c NULL if the
- * base stream is empty.  @a scratch_pool is provided for temporary
- * allocations.
+
+/*
+ * ===================================================================
+ * Editor for Commit from WC, with Incremental Path-Based Tree Changes
+ * ===================================================================
+ *
+ * Versioning model assumed:
+ *
+ *   - per-node, copying-is-branching
+ *   - copying is independent per node: a copy-child is not detectably
+ *     "the same copy" as its parent, it's just copied at the same time
+ *       => (cp ^/a@5 b; del b/c; cp ^/a/c@5 b/c) == (cp ^/a@5 b)
+ *   - a node-rev's versioned state consists of:
+ *        its tree linkage (parent node-branch identity, name)
+ *        its content (props, text, link-target)
+ *   - resurrection is supported
+ *
+ * Edit Operations:
+ *
+ *   - mk  kind               {dir-path | ^/dir-path@rev}[1] new-name[2]
+ *   - cp  ^/from-path@rev[3] {dir-path | ^/dir-path@rev}[1] new-name[2]
+ *   - cp  from-path[4]       {dir-path | ^/dir-path@rev}[1] new-name[2]
+ *   - mv  ^/from-path@rev[4] {dir-path | ^/dir-path@rev}[1] new-name[2]
+ *   - res ^/from-path@rev[3] {dir-path | ^/dir-path@rev}[1] new-name[2]
+ *   - rm                     {path | ^/path@rev}[5]
+ *   - put new-content        {path | ^/path@rev}[5]
+ *
+ * Preconditions:
+ *
+ *   [1] target parent dir must exist in txn
+ *   [2] target name (in parent dir) must not exist in txn
+ *   [3] source must exist in committed revision
+ *   [4] source must exist in txn
+ *   [5] target must exist in txn
+ *
+ * Characteristics of this editor:
+ *
+ *   - tree changes form an ordered list
+ *   - content changes are unordered and independent
+ *   - all tree changes MAY be sent before all content changes
+ *
+ *   ### In order to expand the scope of this editor to situations like
+ *       update/switch, where the receiver doesn't have the repository
+ *       to refer to, Can we add a full-traversal kind of copy?
+ *       Is that merely a matter of driving the same API in a different
+ *       way ("let the copy operation mean non-recursive copy")? Or is
+ *       it totally out of scope? (To support WC update we need other
+ *       changes too, not just this.)
+ *
+ * Description of operations:
+ *
+ *   - "cp", "mv" and "rm" are recursive; "mk" and "put" are non-recursive.
+ *
+ *   - "mk": Create a single new node, not related to any other existing
+ *     node. The default content is empty, and MAY be altered by "put".
+ *
+ *   - "cp": Create a copy of the subtree found at the specified "from"
+ *     location in a committed revision or [if supported] in the current
+ *     txn. Each node in the target subtree is marked as "copied from" the
+ *     node with the corresponding path in the source subtree.
+ *
+ *   - "mv": Move a subtree to a new parent node-branch and/or a new name.
+ *     The source must be present in the txn but is specified by reference
+ *     to a location in a committed revision.
+ *
+ *   - "res": Resurrect a previously deleted node-branch. The specified
+ *     source is any location at which this node-branch existed, not
+ *     necessarily at its youngest revision nor even within its most
+ *     recent period of existence. The default content is that of the
+ *     source location, and MAY be altered by "put".
+ *
+ *     The source node-branch MUST NOT exist in the txn. If the source
+ *     node-branch exists in the txn-base, resurrection would be
+ *     equivalent to reverting a local delete in the txn; the sender
+ *     SHOULD NOT do this. [### Why not? Just because it seems like
+ *     unnecessary flexibility.]
+ *
+ *     ### Can we have a recursive resurrect operation? What should it do
+ *         if a child node is still alive (moved or already resurrected)?
+ *
+ *   - "rm": Remove the specified node and, recursively, all nodes that
+ *     are currently its children in the txn. It does not delete nodes
+ *     that used to be its children that have since been moved away.
+ *     "rm" SHOULD NOT be used on a node-branch created by "mk" nor on the
+ *     root node-branch created by "cp", but MAY be used on a child of a
+ *     copy.
+ *
+ *   - "put": Set the content of a node to the specified value. (The new
+ *     content may be described in terms of a delta against another node's
+ *     content.)
+ *
+ *     "put" MAY be sent for any node that exists in the final state, and
+ *     SHOULD NOT be sent for a node that will no longer exist in the final
+ *     state. "put" SHOULD NOT be sent more than once for any node-branch.
+ *     "put" MUST provide the right kind of content to match the node kind;
+ *     it cannot change the kind of a node nor convert the content to match
+ *     the node kind.
+ *
+ * Commit Rebase:
+ *
+ *   - We assume the rebase will require there be no moves in
+ *     intervening commits that overlap path-wise with the edits we are
+ *     making. (If it would follow such moves while merging "on the fly",
+ *     then it would be harder to design the editor such that the sender
+ *     would know what paths-in-txn to refer to.)
+ *
+ *     This is quite a stringent restriction. See "Paths" below.
+ *
+ * Notes on Paths:
+ *
+ *   - A bare "path" refers to a "path-in-txn", that is a path in the
+ *     current state of the transaction. ^/path@rev refers to a path in a
+ *     committed revision which is to be traced to the current transaction.
+ *     A path-in-txn can refer to a node that was created with "mk" or
+ *     "cp" (including children) and MAY [### or SHOULD NOT?] refer to a
+ *     node-branch that already existed before the edit began.
+ *
+ *   - Ev1 declares, by nesting, exactly what parent dir each operation
+ *     refers to: a pre-existing one (in which case it checks it's still
+ *     the same one) or one it has just created in the txn. We make this
+ *     distinction with {path-in-txn | ^/path-in-rev@rev} instead.
+ *
+ *   - When the target path to "mk" or "cp" or "mv" is specified as
+ *     ^/dir-path@rev, the new (root) path to be created in the txn is:
+ *
+ *         (^/dir-path@rev traced forward to the txn)/(new-name)
+ *
+ *     When the target path to "rm" or "put" is specified as ^/path@rev,
+ *     the path to be removed or changed in the txn is:
+ *
+ *         (^/path@rev traced forward to the txn)
+ *
+ *   - Why use the semantic form "^/path@rev" rather than
+ *     (path-in-txn, wc-base-rev)?
+ * 
+ *     Basically because, in general (if other commits on the server
+ *     are allowed to move the nodes that this commit is editing),
+ *     then (path-in-txn, wc-base-rev) does not unambiguously identify
+ *     a node-revision or a specific path in revision wc-base-rev. The
+ *     sender cannot know what path in the txn corresponds to a given path
+ *     in wc-base-rev.
+ *
+ *     The server needs to identify the specific node-revision on which
+ *     the client is basing a change, in order to check whether it is
+ *     out of date. If the base of the change is out of date, a merge of
+ *     this node would be required. The merge cannot be done on the server
+ *     as then the committed version may differ from the version sent by
+ *     the client, and there is no mechanism to inform the client of this.
+ *     Therefore the commit must be rejected and the merge done on the
+ *     client side via an "update".
+ *
+ *     (As a possible special case, if each side of the merge has identical
+ *     changes, this may be considered a null merge when a "permissive"
+ *     strictness policy is in effect.)
+ * 
+ *     Given "^/path@rev" the receiver can trace the node-branch forward
+ *     from ^/path@rev to the txn, and find the path at which it is
+ *     currently located in the txn (or find that it is not present), as
+ *     well as discovering whether there was any change to it (including
+ *     deletion) between ^/path@rev and the txn-base.
+ * 
+ *     When the node-branch is traced forward to the txn, due to moves in
+ *     the txn the path-in-txn may be different from the initial path.
+ *     The client needs to know the path-in-txn in order for future operations.
+ *     (This is the case even if the out-of-date check rejects any move
+ *     between WC-base and txn-base that affects the node-branch.)
+ *
+ *     Given (path-in-txn, wc-base-rev), if the OOD check *allows* merging
+ *     with repository-side moves, then the sender cannot know what the paths
+ *     in the txn-base are, and so cannot know what path-in-txn identifies
+ *     any node that existed in an earlier revision.
+ *
+ *     Given (path-in-txn, wc-base-rev), if the OOD check *forbids* merging
+ *     with repository-side moves then the receiver can trace backward
+ *     from path-in-txn to path-in-txn-base and then from path-in-txn-base
+ *     to path-in-rev, and find:
+ *
+ *       (a) this node-branch did not exist in "rev" => OOD
+ *       (b) path-in-rev != path-in-txn-base => OOD
+ *       (c) path-in-rev == path-in-txn-base => OOD iff changed
+ *
+ *     It would seem unnecessarily restrictive to expect that we would
+ *     never want the OOD check to allow merging with a repository-side
+ *     move of a parent of the node we are editing.
+ *
+ *   - When a target path is specified by ^/path@rev, note that the sender
+ *     and the receiver both have to map that path forward through moves
+ *     to calculate the corresponding path-in-txn.
+ *
+ *     ### If the server can merge the edits with repository-side moves
+ *     on the fly, then the sender will not know what in-txn paths to
+ *     refer to subsequently.
+ *
+ *     ### One way to support this: the sender could use "^/path@rev" to
+ *     refer to a pre-existing node, appended with any sub-path created in
+ *     the txn:
+ *
+ *         [^/path/in/rev] @rev [/path/components/created/within/txn]
+ *
+ *     The "^/path/in/rev@rev" part acts like an unambiguous node-id for
+ *     each pre-existing node. The remaining part acts like an identifier
+ *     for nodes created in the txn, but is unambiguous only if we take
+ *     care not to allow them to be moved around freely.
+ *
+ * Notes on Copying:
+ *
+ *   - Copy from path-in-txn is required iff we want to support copying
+ *     from "this revision". If we don't then the source is necessarily
+ *     a pre-existing node and so can be referenced by ^/path@rev.
+ *
+ *   - There is no provision for making a non-tracked copy of a subtree,
+ *     nor a copy in which some nodes are tracked and others untracked,
+ *     in a single operation.
+ *
+ * Notes on Moving:
+ *
+ *   - There is no operation to move a subtree whose root node was created
+ *     in this txn, merely because it is not necessary. (A node created by
+ *     "mk" can always be created in the required location. A subtree of a
+ *     copy can be moved by deleting it and making a new copy from the
+ *     corresponding subtree of the original copy root, as there is no
+ *     distinction between the first copy and the second copy.)
  *
- * @a baton is an implementation-specific closure.
  */
-typedef svn_error_t *(*svn_delta_fetch_base_func_t)(
-  const char **filename,
-  void *baton,
-  const char *path,
-  svn_revnum_t base_revision,
-  apr_pool_t *result_pool,
-  apr_pool_t *scratch_pool
-  );
-
-/** Collection of callbacks used for the shim code.  This structure
- * may grow additional fields in the future.  Therefore, always use
- * svn_delta_shim_callbacks_default() to allocate new instances of it.
+
+/** Make a single new node ("versioned object") with empty content.
+ * 
+ * Set the node kind to @a new_kind. Create the node in the parent
+ * directory node-branch specified by @a parent_loc which may be either in
+ * a committed revision or in the current txn. Set the new node's name to
+ * @a new_name.
+ *
+ * The new node is not related by node identity to any other existing node
+ * nor to any other node created by another "mk" operation.
+ *
+ * Preconditions: see above.
+ *
+ * @node "put" is optional for a node made by "mk".
  */
-typedef struct svn_delta_shim_callbacks_t
-{
-  svn_delta_fetch_props_func_t fetch_props_func;
-  svn_delta_fetch_kind_func_t fetch_kind_func;
-  svn_delta_fetch_base_func_t fetch_base_func;
-  void *fetch_baton;
-} svn_delta_shim_callbacks_t;
+svn_error_t *
+svn_editor3_mk(svn_editor3_t *editor,
+               svn_node_kind_t new_kind,
+               pathrev_t parent_loc,
+               const char *new_name);
 
-/** Return a collection of default shim functions in @a result_pool.
+/** Create a copy of a subtree.
+ *
+ * The source subtree is found at @a from_loc. If @a from_loc is a
+ * location in a committed revision, make a copy from (and referring to)
+ * that location. [If supported] If @a from_loc is a location in the
+ * current txn, make a copy from the current txn, which when committed
+ * will refer to the committed revision.
+ *
+ * Create the root node of the new subtree in the parent directory
+ * node-branch specified by @a parent_loc (which may be either in a
+ * committed revision or in the current txn) with the name @a new_name.
+ *
+ * Each node in the target subtree has a "copied from" relationship with
+ * the node with the corresponding path in the source subtree.
+ *
+ * The content of a node copied from an existing revision is, by default,
+ * the content of the source node. The content of a node copied from this
+ * revision is, by default, the FINAL content of the source node as
+ * committed, even if the source node is changed after the copy operation.
+ * In either case, the default content MAY be changed by a "put".
  */
-svn_delta_shim_callbacks_t *
-svn_delta_shim_callbacks_default(apr_pool_t *result_pool);
+svn_error_t *
+svn_editor3_cp(svn_editor3_t *editor,
+               pathrev_t from_loc,
+               pathrev_t parent_loc,
+               const char *new_name);
 
+/** Move a subtree to a new parent directory and/or a new name.
+ *
+ * The root node of the source subtree in the current txn is the node-branch
+ * specified by @a from_loc. @a from_loc must refer to a committed revision.
+ *
+ * Create the root node of the new subtree in the parent directory
+ * node-branch specified by @a parent_loc (which may be either in a
+ * committed revision or in the current txn) with the name @a new_name.
+ *
+ * Each node in the target subtree remains the same node-branch as
+ * the node with the corresponding path in the source subtree.
+ */
+svn_error_t *
+svn_editor3_mv(svn_editor3_t *editor,
+               pathrev_t from_loc,
+               pathrev_t new_parent_loc,
+               const char *new_name);
 
-
-/** Transforming trees ("editing").
+/** Resurrect a node.
+ *
+ * Resurrect the node-branch that previously existed at @a from_loc,
+ * a location in a committed revision. Put the resurrected node at
+ * @a parent_loc, @a new_name.
  *
- * In Subversion, we have a number of occasions where we transform a tree
- * from one state into another. This process is called "editing" a tree.
+ * Set the content to @a new_content.
+ */
+svn_error_t *
+svn_editor3_res(svn_editor3_t *editor,
+                pathrev_t from_loc,
+                pathrev_t parent_loc,
+                const char *new_name);
+
+/** Remove the existing node-branch identified by @a loc and, recursively,
+ * all nodes that are currently its children in the txn.
  *
- * In processing a `commit' command:
- * - The client examines its working copy data to determine the set of
- *   changes necessary to transform its base tree into the desired target.
- * - The client networking library delivers that set of changes/operations
- *   across the wire as an equivalent series of network requests (for
- *   example, to svnserve as an ra_svn protocol stream, or to an
- *   Apache httpd server as WebDAV commands)
- * - The server receives those requests and applies the sequence of
- *   operations on a revision, producing a transaction representing the
- *   desired target.
- * - The Subversion server then commits the transaction to the filesystem.
- *
- * In processing an `update' command, the process is reversed:
- * - The Subversion server module talks to the filesystem and computes a
- *   set of changes necessary to bring the client's working copy up to date.
- * - The server serializes this description of changes, and delivers it to
- *   the client.
- * - The client networking library receives that reply, producing a set
- *   of changes/operations to alter the working copy into the revision
- *   requested by the update command.
- * - The working copy library applies those operations to the working copy
- *   to align it with the requested update target.
- *
- * The series of changes (or operations) necessary to transform a tree from
- * one state into another is passed between subsystems using this "editor"
- * interface. The "receiver" edits its tree according to the operations
- * described by the "driver".
- *
- * Note that the driver must have a perfect understanding of the tree which
- * the receiver will be applying edits upon. There is no room for error here,
- * and the interface embodies assumptions/requirements that the driver has
- * about the targeted tree. As a result, this interface is a standardized
- * mechanism of *describing* those change operations, but the intimate
- * knowledge between the driver and the receiver implies some level of
- * coupling between those subsystems.
- *
- * The set of changes, and the data necessary to describe it entirely, is
- * completely unbounded. An addition of one simple 20 GB file might be well
- * past the available memory of a machine processing these operations.
- * As a result, the API to describe the changes is designed to be applied
- * in a sequential (and relatively random-access) model. The operations
- * can be streamed from the driver to the receiver, resulting in the
- * receiver editing its tree to the target state defined by the driver.
- *
- *
- * <h3>History</h3>
- *
- * Classically, Subversion had a notion of a "tree delta" which could be
- * passed around as an independent entity. Theory implied this delta was an
- * entity in its own right, to be used when and where necessary.
- * Unfortunately, this theory did not work well in practice. The producer
- * and consumer of these tree deltas were (and are) tightly coupled. As noted
- * above, the tree delta producer needed to be *totally* aware of the tree
- * that it needed to edit. So rather than telling the delta consumer how to
- * edit its tree, the classic #svn_delta_editor_t interface focused
- * entirely on the tree delta, an intermediate (logical) data structure
- * which was unusable outside of the particular, coupled pairing of producer
- * and consumer. This generation of the API forgoes the logical tree delta
- * entity and directly passes the necessary edits/changes/operations from
- * the producer to the consumer. In our new parlance, one subsystem "drives"
- * a set of operations describing the change, and a "receiver" accepts and
- * applies them to its tree.
- *
- * The classic interface was named #svn_delta_editor_t and was described
- * idiomatically as the "editor interface". This generation of the interface
- * retains the "editor" name for that reason. All notions of a "tree delta"
- * structure are no longer part of this interface.
- *
- * The old interface was purely vtable-based and used a number of special
- * editors which could be interposed between the driver and receiver. Those
- * editors provided cancellation, debugging, and other various operations.
- * While the "interposition" pattern is still possible with this interface,
- * the most common functionality (cancellation and debugging) have been
- * integrated directly into this new editor system.
- *
- *
- * <h3>Implementation Plan</h3>
- * @note This section can be removed after Ev2 is fully implemented.
- *
- * The delta editor is pretty engrained throughout Subversion, so attempting
- * to replace it in situ is somewhat akin to performing open heart surgery
- * while the patient is running a marathon.  However, a viable plan should
- * make things a bit easier, and help parallelize the work.
- *
- * In short, the following items need to be done:
- *  -# Implement backward compatibility wrappers ("shims")
- *  -# Use shims to update editor consumers to Ev2
- *  -# Update editor producers to drive Ev2
- *     - This will largely involve rewriting the RA layers to accept and
- *       send Ev2 commands
- *  -# Optimize consumers and producers to leverage the features of Ev2
- *
- * The shims are largely self-contained, and as of this writing, are almost
- * complete.  They can be released without much ado.  However, they do add
- * <em>significant</em> performance regressions, which make releasing code
- * which is half-delta-editor and half-Ev2 inadvisable.  As such, the updating
- * of producers and consumers to Ev2 will probably need to wait until 1.9,
- * though it could be largely parallelized.
+ * It does not delete nodes that used to be children of the specified
+ * node-branch that have since been moved away.
+ */
+svn_error_t *
+svn_editor3_rm(svn_editor3_t *editor,
+               pathrev_t loc);
+
+/** Set the content of the node-branch identified by @a loc.
  *
+ * Set the content to @a new_content.
+ */
+svn_error_t *
+svn_editor3_put(svn_editor3_t *editor,
+                pathrev_t loc,
+                const svn_editor3_node_content_t *new_content);
+
+
+/*
+ * ========================================================================
+ * Editor for Commit from WC, with Separate Unordered Per-Node Tree Changes
+ * ========================================================================
  *
- * @defgroup svn_editor The editor interface
- * @{
+ * Versioning model assumed:
+ *
+ *   - per-node, copying-is-branching
+ *   - copying is independent per node: a copy-child is not detectably
+ *     "the same copy" as its parent, it's just copied at the same time
+ *       => (cp ^/a@5 b; del b/c; cp ^/a/c@5 b/c) == (cp ^/a@5 b)
+ *   - a node-rev's versioned state consists of:
+ *        its tree linkage (parent node-branch identity, name)
+ *        its content (props, text, link-target)
+ *   - resurrection is supported
+ *
+ * Edit Operations:
+ *
+ *   - add     kind      new-parent-nb[2] new-name new-content  ->  new-nb
+ *   - copy    nb@rev[3] new-parent-nb[2] new-name new-content  ->  new-nb
+ *   - delete  nb[1]   since-rev
+ *   - alter   nb[1,2] since-rev new-parent-nb[2] new-name new-content
+ *
+ * Preconditions:
+ *
+ *   [1] node-branch must exist in initial state
+ *   [2] node-branch must exist in final state
+ *   [3] source must exist in committed revision or txn final state
+ *
+ * Characteristics of this editor:
+ *
+ *   - tree changes and content changes are specified per node
+ *   - the changes for each node are unordered and mostly independent;
+ *     the only dependencies are those needed to ensure the result is a
+ *     directory hierarchy
+ *   - copies are non-recursive
+ *     ### Can we design recursive (cheap) copy?
+ *
+ *
+ * Notes on Copying:
+ *
+ *   - copy_one and copy_tree are separate. In this model it doesn't
+ *     make sense to describe a copy-and-modify by means of generating
+ *     a full copy (with ids, at least implicitly, for each node) and
+ *     then potentially "deleting" some of the generated child nodes.
+ *     Instead, each node has to be specified in its final state or not
+ *     at all. Tree-copy therefore generates an immutable copy, while
+ *     single-node copy supports arbitrary copy-and-modify operations,
+ *     and tree-copy can be used for any unmodified subtrees therein.
+ *     There is no need to reference the root node of a tree-copy again
+ *     within the same edit, and so no id is provided.
  */
 
-/** An abstract object that edits a target tree.
+/** Create a new versioned object of kind @a new_kind.
+ * 
+ * Assign the new node a locally unique node-branch-id, @a local_nbid,
+ * with which it can be referenced within this edit.
+ *
+ * Set the node's parent and name to @a new_parent_nbid and @a new_name.
  *
- * @note The term "follow" means at any later time in the editor drive.
- * Terms such as "must", "must not", "required", "shall", "shall not",
- * "should", "should not", "recommended", "may", and "optional" in this
- * document are to be interpreted as described in RFC 2119.
- *
- * @note The editor objects are *not* reentrant. The receiver should not
- * directly or indirectly invoke an editor API with the same object 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). Note that the code itself is reentrant, so
- * there is no problem using the APIs on different editor objects.
- *
- * \n
- * <h3>Life-Cycle</h3>
- *
- * - @b Create: A receiver uses svn_editor_create() to create an
- *    "empty" svn_editor_t.  It cannot be used yet, since it still lacks
- *    actual callback functions.  svn_editor_create() sets the
- *    #svn_editor_t's callback baton and scratch pool that the callback
- *    functions receive, as well as a cancellation callback and baton
- *    (see "Cancellation" below).
- *
- * - @b Set callbacks: The receiver calls svn_editor_setcb_many() or a
- *    succession of the other svn_editor_setcb_*() functions to tell
- *    #svn_editor_t which functions to call when driven by the various
- *    operations.  Callback functions are implemented by the receiver and must
- *    adhere to the @c svn_editor_cb_*_t function types as expected by the
- *    svn_editor_setcb_*() functions. See: \n
- *      svn_editor_cb_many_t \n
- *      svn_editor_setcb_many() \n
- *      or \n
- *      svn_editor_setcb_add_directory() \n
- *      svn_editor_setcb_add_file() \n
- *      svn_editor_setcb_add_symlink() \n
- *      svn_editor_setcb_add_absent() \n
- *      svn_editor_setcb_alter_directory() \n
- *      svn_editor_setcb_alter_file() \n
- *      svn_editor_setcb_alter_symlink() \n
- *      svn_editor_setcb_delete() \n
- *      svn_editor_setcb_copy() \n
- *      svn_editor_setcb_move() \n
- *      svn_editor_setcb_complete() \n
- *      svn_editor_setcb_abort()
- *
- * - @b Drive: The driver is provided with the completed #svn_editor_t
- *    instance. (It is typically passed to a generic driving
- *    API, which could receive the driving editor calls over the network
- *    by providing a proxy #svn_editor_t on the remote side.)
- *    The driver invokes the #svn_editor_t instance's callback functions
- *    according to the restrictions defined below, in order to describe the
- *    entire set of operations necessary to transform the receiver's tree
- *    into the desired target. The callbacks can be invoked using the
- *    svn_editor_*() functions, i.e.: \n
- *      svn_editor_add_directory() \n
- *      svn_editor_add_file() \n
- *      svn_editor_add_symlink() \n
- *      svn_editor_add_absent() \n
- *      svn_editor_alter_directory() \n
- *      svn_editor_alter_file() \n
- *      svn_editor_alter_symlink() \n
- *      svn_editor_delete() \n
- *      svn_editor_copy() \n
- *      svn_editor_move() \n
- *    \n\n
- *    Just before each callback invocation is carried out, the @a cancel_func
- *    that was passed to svn_editor_create() is invoked to poll any
- *    external reasons to cancel the sequence of operations.  Unless it
- *    overrides the cancellation (denoted by #SVN_ERR_CANCELLED), the driver
- *    aborts the transmission by invoking the svn_editor_abort() callback.
- *    Exceptions to this are calls to svn_editor_complete() and
- *    svn_editor_abort(), which cannot be canceled externally.
- *
- * - @b Receive: While the driver invokes operations upon the editor, the
- *    receiver finds its callback functions called with the information
- *    to operate on its tree. Each actual callback function receives those
- *    arguments that the driver passed to the "driving" functions, plus these:
- *    -  @a baton: This is the @a editor_baton pointer originally passed to
- *       svn_editor_create().  It may be freely used by the callback
- *       implementation to store information across all callbacks.
- *    -  @a scratch_pool: This temporary pool is cleared directly after
- *       each callback returns.  See "Pool Usage".
- *    \n\n
- *    If the receiver encounters an error within a callback, it returns an
- *    #svn_error_t*. The driver receives this and aborts transmission.
- *
- * - @b Complete/Abort: The driver will end transmission by calling \n
- *    svn_editor_complete() if successful, or \n
- *    svn_editor_abort() if an error or cancellation occurred.
- * \n\n
- *
- * <h3>Driving Order Restrictions</h3>
- * In order to reduce complexity of callback receivers, the editor callbacks
- * must be driven in adherence to these rules:
- *
- * - If any path is added (with add_*) or deleted/moved, then
- *   an svn_editor_alter_directory() call must be made for its parent
- *   directory with the target/eventual set of children.
- *
- * - svn_editor_add_directory() -- Another svn_editor_add_*() call must
- *   follow for each child mentioned in the @a children argument of any
- *   svn_editor_add_directory() call.
- *
- * - For each node created with add_*, if its parent was created using
- *   svn_editor_add_directory(), then the new child node MUST have been
- *   mentioned in the @a children parameter of the parent's creation.
- *   This allows the parent directory to properly mark the child as
- *   "incomplete" until the child's add_* call arrives.
- *
- * - A path should never be referenced more than once by the add_*, alter_*,
- *   and delete operations (the "Once Rule"). The source path of a copy (and
- *   its children, if a directory) may be copied many times, and are
- *   otherwise subject to the Once Rule. The destination path of a copy
- *   or move may have alter_* operations applied, but not add_* or delete.
- *   If the destination path of a copy or move is a directory,
- *   then its children are subject to the Once Rule. The source path of
- *   a move (and its child paths) may be referenced in add_*, or as the
- *   destination of a copy (where these new or copied nodes are subject
- *   to the Once Rule).
- *
- * - The ancestor of an added, copied-here, moved-here, or
- *   modified node may not be deleted. The ancestor may not be moved
- *   (instead: perform the move, *then* the edits).
- *
- * - svn_editor_delete() must not be used to replace a path -- i.e.
- *   svn_editor_delete() must not be followed by an svn_editor_add_*() on
- *   the same path, nor by an svn_editor_copy() or svn_editor_move() with
- *   the same path as the copy/move target.
- *
- *   Instead of a prior delete call, the add/copy/move callbacks should be
- *   called with the @a replaces_rev argument set to the revision number of
- *   the node at this path that is being replaced.  Note that the path and
- *   revision number are the key to finding any other information about the
- *   replaced node, like node kind, etc.
- *   @todo say which function(s) to use.
- *
- * - svn_editor_delete() must not be used to move a path -- i.e.
- *   svn_editor_delete() must not delete the source path of a previous
- *   svn_editor_copy() call. Instead, svn_editor_move() must be used.
- *   Note: if the desired semantics is one (or more) copies, followed
- *   by a delete... that is fine. It is simply that svn_editor_move()
- *   should be used to describe a semantic move.
- *
- * - One of svn_editor_complete() or svn_editor_abort() must be called
- *   exactly once, which must be the final call the driver invokes.
- *   Invoking svn_editor_complete() must imply that the set of changes has
- *   been transmitted completely and without errors, and invoking
- *   svn_editor_abort() must imply that the transformation was not completed
- *   successfully.
- *
- * - If any callback invocation (besides svn_editor_complete()) returns
- *   with an error, the driver must invoke svn_editor_abort() and stop
- *   transmitting operations.
- * \n\n
- *
- * <h3>Receiving Restrictions</h3>
- *
- * All callbacks must complete their handling of a path before they return.
- * Since future callbacks will never reference this path again (due to the
- * Once Rule), the changes can and should be completed.
- *
- * This restriction is not recursive -- a directory's children may remain
- * incomplete until later callback calls are received.
- *
- * For example, an svn_editor_add_directory() call during an 'update'
- * operation will create the directory itself, including its properties,
- * and will complete any client notification for the directory itself.
- * The immediate children of the added directory, given in @a children,
- * will be recorded in the WC as 'incomplete' and will be completed in the
- * course of the same operation sequence, when the corresponding callbacks
- * for these items are invoked.
- * \n\n
- *
- * <h3>Timing and State</h3>
- * The calls made by the driver to alter the state in the receiver are
- * based on the receiver's *current* state, which includes all prior changes
- * made during the edit.
- *
- * Example: copy A to B; set-props on A; copy A to C. The props on C
- * should reflect the updated properties of A.
- *
- * Example: mv A@N to B; mv C@M to A. The second move cannot be marked as
- * a "replacing" move since it is not replacing A. The node at A was moved
- * away. The second operation is simply moving C to the now-empty path
- * known as A.
- *
- * <h3>Paths</h3>
- * Each driver/receiver implementation of this editor interface must
- * establish the expected root for all the paths sent and received via
- * the callbacks' @a relpath arguments.
- *
- * For example, during an "update", the driver is the repository, as a
- * whole. The receiver may have just a portion of that repository. Here,
- * the receiver could tell the driver which repository URL the working
- * copy refers to, and thus the driver could send @a relpath arguments
- * that are relative to the receiver's working copy.
- *
- * @note Because the source of a copy may be located *anywhere* in the
- * repository, editor drives should typically use the repository root
- * as the negotiated root. This allows the @a src_relpath argument in
- * svn_editor_copy() to specify any possible source.
- * \n\n
- *
- * <h3>Pool Usage</h3>
- * The @a result_pool passed to svn_editor_create() is used to allocate
- * the #svn_editor_t instance, and thus it must not be cleared before the
- * driver has finished driving the editor.
- *
- * The @a scratch_pool passed to each callback invocation is derived from
- * the @a result_pool that was passed to svn_editor_create(). It is
- * cleared directly after each single callback invocation.
- * To allocate memory with a longer lifetime from within a callback
- * function, you may use your own pool kept in the @a editor_baton.
- *
- * The @a scratch_pool passed to svn_editor_create() may be used to help
- * during construction of the #svn_editor_t instance, but it is assumed to
- * live only until svn_editor_create() returns.
- * \n\n
- *
- * <h3>Cancellation</h3>
- * To allow graceful interruption by external events (like a user abort),
- * svn_editor_create() can be passed an #svn_cancel_func_t that is
- * polled every time the driver invokes a callback, just before the
- * actual editor callback implementation is invoked.  If this function
- * decides to return with an error, the driver will receive this error
- * as if the callback function had returned it, i.e. as the result from
- * calling any of the driving functions (e.g. svn_editor_add_directory()).
- * As with any other error, the driver must then invoke svn_editor_abort()
- * and abort the transformation sequence. See #svn_cancel_func_t.
- *
- * The @a cancel_baton argument to svn_editor_create() is passed
- * unchanged to each poll of @a cancel_func.
- *
- * The cancellation function and baton are typically provided by the client
- * context.
- *
- *
- * @todo ### TODO anything missing?
- *
- * @since New in 1.8.
+ * Set the content to @a new_content.
+ *
+ * For all restrictions on driving the editor, see #svn_editor3_t.
  */
-typedef struct svn_editor_t svn_editor_t;
+svn_error_t *
+svn_editor3_add(svn_editor3_t *editor,
+                svn_editor3_nbid_t local_nbid,
+                svn_node_kind_t new_kind,
+                svn_editor3_nbid_t new_parent_nbid,
+                const char *new_name,
+                const svn_editor3_node_content_t *new_content);
 
-/** The kind of the checksum to be used throughout the #svn_editor_t APIs.
+/** Create a copy of an existing or new node, and optionally change its
+ * content.
+ *
+ * Assign the target node a locally unique node-branch-id, @a local_nbid,
+ * with which it can be referenced within this edit.
+ *
+ * Copy from the source node at @a src_revision, @a src_nbid. If
+ * @a src_revision is #SVN_INVALID_REVNUM, it means copy from within
+ * the new revision being described.
+ *   ### See note on copy_tree().
+ *
+ * Set the target node's parent and name to @a new_parent_nbid and
+ * @a new_name. Set the target node's content to @a new_content.
+ *
+ * @note This copy is not recursive. Children may be copied separately if
+ * required.
  *
- * @note ### This may change before Ev2 is official released, so just like
- * everything else in this file, please don't rely upon it until then.
+ * @see svn_editor3_copy_tree()
+ *
+ * For all restrictions on driving the editor, see #svn_editor3_t.
+ */
+svn_error_t *
+svn_editor3_copy_one(svn_editor3_t *editor,
+                     svn_editor3_nbid_t local_nbid,
+                     svn_revnum_t src_revision,
+                     svn_editor3_nbid_t src_nbid,
+                     svn_editor3_nbid_t new_parent_nbid,
+                     const char *new_name,
+                     const svn_editor3_node_content_t *new_content);
+
+/** Create a copy of an existing or new subtree. Each node in the source
+ * subtree will be copied (branched) to the same relative path within the
+ * target subtree. The nodes created by this copy cannot be modified or
+ * addressed within this edit.
+ *
+ * Set the target root node's parent and name to @a new_parent_nbid and
+ * @a new_name.
+ *
+ * Copy from the source node at @a src_revision, @a src_nbid. If
+ * @a src_revision is #SVN_INVALID_REVNUM, it means copy from within
+ * the new revision being described. In this case the subtree copied is
+ * the FINAL subtree as committed, regardless of the order in which the
+ * edit operations are described.
+ *   ### Is it necessarily the case that the state at the end of the edit
+ *       is the state to be committed (subject to rebasing), or is it
+ *       possible that a later edit might be performed on the txn?
+ *       And how might we apply this principle to a non-commit editor
+ *       such as a WC update?
+ *
+ * The content of each node copied from an existing revision is the content
+ * of the source node. The content of each node copied from this revision
+ * is the FINAL content of the source node as committed.
+ *
+ * @see svn_editor3_copy_one()
+ *
+ * For all restrictions on driving the editor, see #svn_editor3_t.
  */
-#define SVN_EDITOR_CHECKSUM_KIND svn_checksum_sha1
+svn_error_t *
+svn_editor3_copy_tree(svn_editor3_t *editor,
+                      svn_revnum_t src_revision,
+                      svn_editor3_nbid_t src_nbid,
+                      svn_editor3_nbid_t new_parent_nbid,
+                      const char *new_name);
+
+/** Delete the existing node-branch identified by @a nbid.
+ *
+ * @a since_rev specifies the base revision on which this deletion was
+ * performed: the server can consider the change "out of date" if a commit
+ * since then has changed or deleted this node-branch.
+ *
+ * ###  @note The delete is not recursive. Child nodes must be explicitly
+ *      deleted or moved away.
+ *   OR @note The delete is implicitly recursive: each child node that
+ *      is not otherwise moved to a new parent will be deleted as well.
+ *
+ * For all restrictions on driving the editor, see #svn_editor3_t.
+ */
+svn_error_t *
+svn_editor3_delete(svn_editor3_t *editor,
+                   svn_revnum_t since_rev,
+                   svn_editor3_nbid_t nbid);
+
+/** Alter the tree position and/or contents of the node-branch identified
+ * by @a nbid, or resurrect it if it previously existed.
+ *
+ * @a since_rev specifies the base revision on which this edit was
+ * performed: the server can consider the change "out of date" if a commit
+ * since then has changed or deleted this node-branch.
+ *
+ * Set the node's parent and name to @a new_parent_nbid and @a new_name.
+ *
+ * Set the content to @a new_content.
+ *
+ * A no-op change MUST be accepted but, in the interest of efficiency,
+ * SHOULD NOT be sent.
+ *
+ * For all restrictions on driving the editor, see #svn_editor3_t.
+ */
+svn_error_t *
+svn_editor3_alter(svn_editor3_t *editor,
+                  svn_revnum_t since_rev,
+                  svn_editor3_nbid_t nbid,
+                  svn_editor3_nbid_t new_parent_nbid,
+                  const char *new_name,
+                  const svn_editor3_node_content_t *new_content);
+
+/** Drive @a editor's #svn_editor3_cb_complete_t callback.
+ *
+ * Send word that the edit has been completed successfully.
+ *
+ * For all restrictions on driving the editor, see #svn_editor3_t.
+ */
+svn_error_t *
+svn_editor3_complete(svn_editor3_t *editor);
+
+/** Drive @a editor's #svn_editor3_cb_abort_t callback.
+ *
+ * Notify that the edit transmission was not successful.
+ * ### TODO @todo Shouldn't we add a reason-for-aborting argument?
+ *
+ * For all restrictions on driving the editor, see #svn_editor3_t.
+ */
+svn_error_t *
+svn_editor3_abort(svn_editor3_t *editor);
+
+/** @} */
 
 
 /** These function types define the callback functions a tree delta consumer
@@ -486,143 +743,135 @@ typedef struct svn_editor_t svn_editor_t
  * which has the same arguments with these differences:
  *
  * - These "receiving" functions have a @a baton argument, which is the
- *   @a editor_baton originally passed to svn_editor_create(), as well as
+ *   @a editor_baton originally passed to svn_editor3_create(), as well as
  *   a @a scratch_pool argument.
  *
- * - The "driving" functions have an #svn_editor_t* argument, in order to
+ * - The "driving" functions have an #svn_editor3_t* argument, in order to
  *   call the implementations of the function types defined here that are
- *   registered with the given #svn_editor_t instance.
+ *   registered with the given #svn_editor3_t instance.
  *
  * Note that any remaining arguments for these function types are explained
  * in the comment for the "driving" functions. Each function type links to
  * its corresponding "driver".
  *
- * @see svn_editor_t, svn_editor_cb_many_t.
+ * @see svn_editor3_t, svn_editor3_cb_funcs_t.
  *
  * @defgroup svn_editor_callbacks Editor callback definitions
  * @{
  */
 
-/** @see svn_editor_add_directory(), svn_editor_t.
- * @since New in 1.8.
+/** @see svn_editor3_mk(), svn_editor3_t.
  */
-typedef svn_error_t *(*svn_editor_cb_add_directory_t)(
+typedef svn_error_t *(*svn_editor3_cb_mk_t)(
   void *baton,
-  const char *relpath,
-  const apr_array_header_t *children,
-  apr_hash_t *props,
-  svn_revnum_t replaces_rev,
+  svn_node_kind_t new_kind,
+  pathrev_t parent_loc,
+  const char *new_name,
   apr_pool_t *scratch_pool);
 
-/** @see svn_editor_add_file(), svn_editor_t.
- * @since New in 1.8.
+/** @see svn_editor3_cp(), svn_editor3_t.
  */
-typedef svn_error_t *(*svn_editor_cb_add_file_t)(
+typedef svn_error_t *(*svn_editor3_cb_cp_t)(
   void *baton,
-  const char *relpath,
-  const svn_checksum_t *checksum,
-  svn_stream_t *contents,
-  apr_hash_t *props,
-  svn_revnum_t replaces_rev,
+  pathrev_t from_loc,
+  pathrev_t parent_loc,
+  const char *new_name,
   apr_pool_t *scratch_pool);
 
-/** @see svn_editor_add_symlink(), svn_editor_t.
- * @since New in 1.8.
+/** @see svn_editor3_mv(), svn_editor3_t.
  */
-typedef svn_error_t *(*svn_editor_cb_add_symlink_t)(
+typedef svn_error_t *(*svn_editor3_cb_mv_t)(
   void *baton,
-  const char *relpath,
-  const char *target,
-  apr_hash_t *props,
-  svn_revnum_t replaces_rev,
+  pathrev_t from_loc,
+  pathrev_t new_parent_loc,
+  const char *new_name,
   apr_pool_t *scratch_pool);
 
-/** @see svn_editor_add_absent(), svn_editor_t.
- * @since New in 1.8.
+/** @see svn_editor3_res(), svn_editor3_t.
  */
-typedef svn_error_t *(*svn_editor_cb_add_absent_t)(
+typedef svn_error_t *(*svn_editor3_cb_res_t)(
   void *baton,
-  const char *relpath,
-  svn_node_kind_t kind,
-  svn_revnum_t replaces_rev,
+  pathrev_t from_loc,
+  pathrev_t parent_loc,
+  const char *new_name,
   apr_pool_t *scratch_pool);
 
-/** @see svn_editor_alter_directory(), svn_editor_t.
- * @since New in 1.8.
+/** @see svn_editor3_rm(), svn_editor3_t.
  */
-typedef svn_error_t *(*svn_editor_cb_alter_directory_t)(
+typedef svn_error_t *(*svn_editor3_cb_rm_t)(
   void *baton,
-  const char *relpath,
-  svn_revnum_t revision,
-  const apr_array_header_t *children,
-  apr_hash_t *props,
+  pathrev_t loc,
   apr_pool_t *scratch_pool);
 
-/** @see svn_editor_alter_file(), svn_editor_t.
- * @since New in 1.8.
+/** @see svn_editor3_put(), svn_editor3_t.
  */
-typedef svn_error_t *(*svn_editor_cb_alter_file_t)(
+typedef svn_error_t *(*svn_editor3_cb_put_t)(
   void *baton,
-  const char *relpath,
-  svn_revnum_t revision,
-  const svn_checksum_t *checksum,
-  svn_stream_t *contents,
-  apr_hash_t *props,
+  pathrev_t loc,
+  const svn_editor3_node_content_t *new_content,
   apr_pool_t *scratch_pool);
 
-/** @see svn_editor_alter_symlink(), svn_editor_t.
- * @since New in 1.8.
+/** @see svn_editor3_add(), svn_editor3_t.
  */
-typedef svn_error_t *(*svn_editor_cb_alter_symlink_t)(
+typedef svn_error_t *(*svn_editor3_cb_add_t)(
   void *baton,
-  const char *relpath,
-  svn_revnum_t revision,
-  const char *target,
-  apr_hash_t *props,
+  svn_editor3_nbid_t local_nbid,
+  svn_node_kind_t new_kind,
+  svn_editor3_nbid_t new_parent_nbid,
+  const char *new_name,
+  const svn_editor3_node_content_t *new_content,
   apr_pool_t *scratch_pool);
 
-/** @see svn_editor_delete(), svn_editor_t.
- * @since New in 1.8.
+/** @see svn_editor3_copy(), svn_editor3_t.
  */
-typedef svn_error_t *(*svn_editor_cb_delete_t)(
+typedef svn_error_t *(*svn_editor3_cb_copy_one_t)(
   void *baton,
-  const char *relpath,
-  svn_revnum_t revision,
+  svn_editor3_nbid_t local_nbid,
+  svn_revnum_t src_revision,
+  svn_editor3_nbid_t src_nbid,
+  svn_editor3_nbid_t new_parent_nbid,
+  const char *new_name,
+  const svn_editor3_node_content_t *new_content,
   apr_pool_t *scratch_pool);
 
-/** @see svn_editor_copy(), svn_editor_t.
- * @since New in 1.8.
+/** @see svn_editor3_copy(), svn_editor3_t.
  */
-typedef svn_error_t *(*svn_editor_cb_copy_t)(
+typedef svn_error_t *(*svn_editor3_cb_copy_tree_t)(
   void *baton,
-  const char *src_relpath,
   svn_revnum_t src_revision,
-  const char *dst_relpath,
-  svn_revnum_t replaces_rev,
+  svn_editor3_nbid_t src_nbid,
+  svn_editor3_nbid_t new_parent_nbid,
+  const char *new_name,
   apr_pool_t *scratch_pool);
 
-/** @see svn_editor_move(), svn_editor_t.
- * @since New in 1.8.
+/** @see svn_editor3_delete(), svn_editor3_t.
  */
-typedef svn_error_t *(*svn_editor_cb_move_t)(
+typedef svn_error_t *(*svn_editor3_cb_delete_t)(
   void *baton,
-  const char *src_relpath,
-  svn_revnum_t src_revision,
-  const char *dst_relpath,
-  svn_revnum_t replaces_rev,
+  svn_revnum_t since_rev,
+  svn_editor3_nbid_t nbid,
   apr_pool_t *scratch_pool);
 
-/** @see svn_editor_complete(), svn_editor_t.
- * @since New in 1.8.
+/** @see svn_editor3_alter(), svn_editor3_t.
  */
-typedef svn_error_t *(*svn_editor_cb_complete_t)(
+typedef svn_error_t *(*svn_editor3_cb_alter_t)(
   void *baton,
+  svn_revnum_t since_rev,
+  svn_editor3_nbid_t nbid,
+  svn_editor3_nbid_t new_parent_nbid,
+  const char *new_name,
+  const svn_editor3_node_content_t *new_content,
   apr_pool_t *scratch_pool);
 
-/** @see svn_editor_abort(), svn_editor_t.
- * @since New in 1.8.
+/** @see svn_editor3_complete(), svn_editor3_t.
  */
-typedef svn_error_t *(*svn_editor_cb_abort_t)(
+typedef svn_error_t *(*svn_editor3_cb_complete_t)(
+  void *baton,
+  apr_pool_t *scratch_pool);
+
+/** @see svn_editor3_abort(), svn_editor3_t.
+ */
+typedef svn_error_t *(*svn_editor3_cb_abort_t)(
   void *baton,
   apr_pool_t *scratch_pool);
 
@@ -631,505 +880,155 @@ typedef svn_error_t *(*svn_editor_cb_abo
 
 /** These functions create an editor instance so that it can be driven.
  *
- * @defgroup svn_editor_create Editor creation
+ * @defgroup svn_editor3_create Editor creation
  * @{
  */
 
-/** Allocate an #svn_editor_t instance from @a result_pool, store
- * @a editor_baton, @a cancel_func and @a cancel_baton in the new instance
- * and return it in @a editor.
+/** A set of editor callback functions.
+ *
+ * If a function pointer is NULL, it will not be called.
+ *
+ * @see svn_editor3_create(), svn_editor3_t.
+ */
+typedef struct svn_editor3_cb_funcs_t
+{
+  svn_editor3_cb_mk_t cb_mk;
+  svn_editor3_cb_cp_t cb_cp;
+  svn_editor3_cb_mv_t cb_mv;
+  svn_editor3_cb_res_t cb_res;
+  svn_editor3_cb_rm_t cb_rm;
+  svn_editor3_cb_put_t cb_put;
+
+  svn_editor3_cb_add_t cb_add;
+  svn_editor3_cb_copy_one_t cb_copy_one;
+  svn_editor3_cb_copy_tree_t cb_copy_tree;
+  svn_editor3_cb_delete_t cb_delete;
+  svn_editor3_cb_alter_t cb_alter;
+
+  svn_editor3_cb_complete_t cb_complete;
+  svn_editor3_cb_abort_t cb_abort;
+
+} svn_editor3_cb_funcs_t;
+
+/** Allocate an #svn_editor3_t instance from @a result_pool, store
+ * @a *editor_funcs, @a editor_baton, @a cancel_func and @a cancel_baton
+ * in the new instance and return it in @a *editor.
+ *
  * @a scratch_pool is used for temporary allocations (if any). Note that
  * this is NOT the same @a scratch_pool that is passed to callback functions.
- * @see svn_editor_t
- * @since New in 1.8.
+ *
+ * @see svn_editor3_t
  */
 svn_error_t *
-svn_editor_create(svn_editor_t **editor,
-                  void *editor_baton,
-                  svn_cancel_func_t cancel_func,
-                  void *cancel_baton,
-                  apr_pool_t *result_pool,
-                  apr_pool_t *scratch_pool);
-
+svn_editor3_create(svn_editor3_t **editor,
+                   const svn_editor3_cb_funcs_t *editor_funcs,
+                   void *editor_baton,
+                   svn_cancel_func_t cancel_func,
+                   void *cancel_baton,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool);
 
 /** Return an editor's private baton.
  *
  * In some cases, the baton is required outside of the callbacks. This
  * function returns the private baton for use.
- *
- * @since New in 1.8.
  */
 void *
-svn_editor_get_baton(const svn_editor_t *editor);
-
-
-/** Sets the #svn_editor_cb_add_directory_t callback in @a editor
- * to @a callback.
- * @a scratch_pool is used for temporary allocations (if any).
- * @see also svn_editor_setcb_many().
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_setcb_add_directory(svn_editor_t *editor,
-                               svn_editor_cb_add_directory_t callback,
-                               apr_pool_t *scratch_pool);
-
-/** Sets the #svn_editor_cb_add_file_t callback in @a editor
- * to @a callback.
- * @a scratch_pool is used for temporary allocations (if any).
- * @see also svn_editor_setcb_many().
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_setcb_add_file(svn_editor_t *editor,
-                          svn_editor_cb_add_file_t callback,
-                          apr_pool_t *scratch_pool);
-
-/** Sets the #svn_editor_cb_add_symlink_t callback in @a editor
- * to @a callback.
- * @a scratch_pool is used for temporary allocations (if any).
- * @see also svn_editor_setcb_many().
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_setcb_add_symlink(svn_editor_t *editor,
-                             svn_editor_cb_add_symlink_t callback,
-                             apr_pool_t *scratch_pool);
-
-/** Sets the #svn_editor_cb_add_absent_t callback in @a editor
- * to @a callback.
- * @a scratch_pool is used for temporary allocations (if any).
- * @see also svn_editor_setcb_many().
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_setcb_add_absent(svn_editor_t *editor,
-                            svn_editor_cb_add_absent_t callback,
-                            apr_pool_t *scratch_pool);
-
-/** Sets the #svn_editor_cb_alter_directory_t callback in @a editor
- * to @a callback.
- * @a scratch_pool is used for temporary allocations (if any).
- * @see also svn_editor_setcb_many().
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_setcb_alter_directory(svn_editor_t *editor,
-                                 svn_editor_cb_alter_directory_t callback,
-                                 apr_pool_t *scratch_pool);
-
-/** Sets the #svn_editor_cb_alter_file_t callback in @a editor
- * to @a callback.
- * @a scratch_pool is used for temporary allocations (if any).
- * @see also svn_editor_setcb_many().
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_setcb_alter_file(svn_editor_t *editor,
-                            svn_editor_cb_alter_file_t callback,
-                            apr_pool_t *scratch_pool);
-
-/** Sets the #svn_editor_cb_alter_symlink_t callback in @a editor
- * to @a callback.
- * @a scratch_pool is used for temporary allocations (if any).
- * @see also svn_editor_setcb_many().
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_setcb_alter_symlink(svn_editor_t *editor,
-                               svn_editor_cb_alter_symlink_t callback,
-                               apr_pool_t *scratch_pool);
-
-/** Sets the #svn_editor_cb_delete_t callback in @a editor
- * to @a callback.
- * @a scratch_pool is used for temporary allocations (if any).
- * @see also svn_editor_setcb_many().
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_setcb_delete(svn_editor_t *editor,
-                        svn_editor_cb_delete_t callback,
-                        apr_pool_t *scratch_pool);
-
-/** Sets the #svn_editor_cb_copy_t callback in @a editor
- * to @a callback.
- * @a scratch_pool is used for temporary allocations (if any).
- * @see also svn_editor_setcb_many().
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_setcb_copy(svn_editor_t *editor,
-                      svn_editor_cb_copy_t callback,
-                      apr_pool_t *scratch_pool);
-
-/** Sets the #svn_editor_cb_move_t callback in @a editor
- * to @a callback.
- * @a scratch_pool is used for temporary allocations (if any).
- * @see also svn_editor_setcb_many().
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_setcb_move(svn_editor_t *editor,
-                      svn_editor_cb_move_t callback,
-                      apr_pool_t *scratch_pool);
-
-/** Sets the #svn_editor_cb_complete_t callback in @a editor
- * to @a callback.
- * @a scratch_pool is used for temporary allocations (if any).
- * @see also svn_editor_setcb_many().
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_setcb_complete(svn_editor_t *editor,
-                          svn_editor_cb_complete_t callback,
-                          apr_pool_t *scratch_pool);
-
-/** Sets the #svn_editor_cb_abort_t callback in @a editor
- * to @a callback.
- * @a scratch_pool is used for temporary allocations (if any).
- * @see also svn_editor_setcb_many().
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_setcb_abort(svn_editor_t *editor,
-                       svn_editor_cb_abort_t callback,
-                       apr_pool_t *scratch_pool);
-
-
-/** Lists a complete set of editor callbacks.
- * This is a convenience structure.
- * @see svn_editor_setcb_many(), svn_editor_create(), svn_editor_t.
- * @since New in 1.8.
- */
-typedef struct svn_editor_cb_many_t
-{
-  svn_editor_cb_add_directory_t cb_add_directory;
-  svn_editor_cb_add_file_t cb_add_file;
-  svn_editor_cb_add_symlink_t cb_add_symlink;
-  svn_editor_cb_add_absent_t cb_add_absent;
-  svn_editor_cb_alter_directory_t cb_alter_directory;
-  svn_editor_cb_alter_file_t cb_alter_file;
-  svn_editor_cb_alter_symlink_t cb_alter_symlink;
-  svn_editor_cb_delete_t cb_delete;
-  svn_editor_cb_copy_t cb_copy;
-  svn_editor_cb_move_t cb_move;
-  svn_editor_cb_complete_t cb_complete;
-  svn_editor_cb_abort_t cb_abort;
-
-} svn_editor_cb_many_t;
-
-/** Sets all the callback functions in @a editor at once, according to the
- * callback functions stored in @a many.
- * @a scratch_pool is used for temporary allocations (if any).
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_setcb_many(svn_editor_t *editor,
-                      const svn_editor_cb_many_t *many,
-                      apr_pool_t *scratch_pool);
+svn_editor3_get_baton(const svn_editor3_t *editor);
 
 /** @} */
 
 
-/** These functions are called by the tree delta driver to edit the target.
- *
- * @see svn_editor_t.
+/*
+ * ========================================================================
+ * Node Content Interface
+ * ========================================================================
  *
- * @defgroup svn_editor_drive Driving the editor
+ * @defgroup svn_editor3_node_content Node content interface
  * @{
  */
 
-/** Drive @a editor's #svn_editor_cb_add_directory_t callback.
+/** Versioned content of a node, excluding tree structure information.
  *
- * Create a new directory at @a relpath. The immediate parent of @a relpath
- * is expected to exist.
+ * The @a ref field specifies a reference content: the content of an
+ * existing committed node, or empty. The other fields are optional
+ * overrides for parts of the content.
  *
- * For descriptions of @a props and @a replaces_rev, see
- * svn_editor_add_file().
- *
- * A complete listing of the immediate children of @a relpath that will be
- * added subsequently is given in @a children. @a children is an array of
- * const char*s, each giving the basename of an immediate child. It is an
- * error to pass NULL for @a children; use an empty array to indicate
- * the new directory will have no children.
- *
- * For all restrictions on driving the editor, see #svn_editor_t.
+ * ### Specify content as deltas against the (optional) reference instead
+ *     of as overrides?
  */
-svn_error_t *
-svn_editor_add_directory(svn_editor_t *editor,
-                         const char *relpath,
-                         const apr_array_header_t *children,
-                         apr_hash_t *props,
-                         svn_revnum_t replaces_rev);
-
-/** Drive @a editor's #svn_editor_cb_add_file_t callback.
- *
- * Create a new file at @a relpath. The immediate parent of @a relpath
- * is expected to exist.
- *
- * The file's contents are specified in @a contents which has a checksum
- * matching @a checksum. Both values must be non-NULL.
- *
- * Set the properties of the new file to @a props, which is an
- * apr_hash_t holding key-value pairs. Each key is a const char* of a
- * property name, each value is a const svn_string_t*. If no properties are
- * being set on the new file, @a props must be the empty hash. It is an
- * error to pass NULL for @a props.
- *
- * If this add is expected to replace a previously existing file, symlink or
- * directory at @a relpath, the revision number of the node to be replaced
- * must be given in @a replaces_rev. Otherwise, @a replaces_rev must be
- * #SVN_INVALID_REVNUM.  Note: it is not allowed to call a "delete" followed
- * by an "add" on the same path. Instead, an "add" with @a replaces_rev set
- * accordingly MUST be used.
- *
- * For all restrictions on driving the editor, see #svn_editor_t.
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_add_file(svn_editor_t *editor,
-                    const char *relpath,
-                    const svn_checksum_t *checksum,
-                    svn_stream_t *contents,
-                    apr_hash_t *props,
-                    svn_revnum_t replaces_rev);
-
-/** Drive @a editor's #svn_editor_cb_add_symlink_t callback.
- *
- * Create a new symbolic link at @a relpath, with a link target of @a
- * target. The immediate parent of @a relpath is expected to exist.
- *
- * For descriptions of @a props and @a replaces_rev, see
- * svn_editor_add_file().
- *
- * For all restrictions on driving the editor, see #svn_editor_t.
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_add_symlink(svn_editor_t *editor,
-                       const char *relpath,
-                       const char *target,
-                       apr_hash_t *props,
-                       svn_revnum_t replaces_rev);
-
-/** Drive @a editor's #svn_editor_cb_add_absent_t callback.
- *
- * Create an "absent" node of kind @a kind at @a relpath. The immediate
- * parent of @a relpath is expected to exist.
- * ### TODO @todo explain "absent".
- * ### JAF: What are the allowed values of 'kind'?
- *
- * For a description of @a replaces_rev, see svn_editor_add_file().
- *
- * For all restrictions on driving the editor, see #svn_editor_t.
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_add_absent(svn_editor_t *editor,
-                      const char *relpath,
-                      svn_node_kind_t kind,
-                      svn_revnum_t replaces_rev);
-
-/** Drive @a editor's #svn_editor_cb_alter_directory_t callback.
- *
- * Alter the properties of the directory at @a relpath.
- *
- * @a revision specifies the revision at which the receiver should
- * expect to find this node. That is, @a relpath at the start of the
- * whole edit and @a relpath at @a revision must lie within the same
- * node-rev (aka location history segment). This information may be used
- * to catch an attempt to alter and out-of-date directory. If the
- * directory does not have a corresponding revision in the repository
- * (e.g. it has not yet been committed), then @a revision should be
- * #SVN_INVALID_REVNUM.
- *
- * If any changes to the set of children will be made in the future of
- * the edit drive, then @a children MUST specify the resulting set of
- * children. See svn_editor_add_directory() for the format of @a children.
- * If not changes will be made, then NULL may be specified.
- *
- * For a description of @a props, see svn_editor_add_file(). If no changes
- * to the properties will be made (ie. only future changes to the set of
- * children), then @a props may be NULL.
- *
- * It is an error to pass NULL for both @a children and @a props.
- *
- * For all restrictions on driving the editor, see #svn_editor_t.
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_alter_directory(svn_editor_t *editor,
-                           const char *relpath,
-                           svn_revnum_t revision,
-                           const apr_array_header_t *children,
-                           apr_hash_t *props);
-
-/** Drive @a editor's #svn_editor_cb_alter_file_t callback.
- *
- * Alter the properties and/or the contents of the file at @a relpath
- * with @a revision as its expected revision. See svn_editor_alter_directory()
- * for more information about @a revision.
- *
- * If @a props is non-NULL, then the properties will be applied.
- *
- * If @a contents is non-NULL, then the stream will be copied to
- * the file, and its checksum must match @a checksum (which must also
- * be non-NULL). If @a contents is NULL, then @a checksum must also
- * be NULL, and no change will be applied to the file's contents.
- *
- * The properties and/or the contents must be changed. It is an error to
- * pass NULL for @a props, @a checksum, and @a contents.
- *
- * For a description of @a checksum and @a contents see
- * svn_editor_add_file(). This function allows @a props to be NULL, but
- * the parameter is otherwise described by svn_editor_add_file().
- *
- * For all restrictions on driving the editor, see #svn_editor_t.
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_alter_file(svn_editor_t *editor,
-                      const char *relpath,
-                      svn_revnum_t revision,
-                      const svn_checksum_t *checksum,
-                      svn_stream_t *contents,
-                      apr_hash_t *props);
+struct svn_editor3_node_content_t
+{
+  /* Reference the content in an existing, committed node-rev.
+   *
+   * If this is (SVN_INVALID_REVNUM, NULL) then the reference content
+   * is empty.
+   *
+   * ### Reference a whole node-rev instead? (Don't need to reference a
+   *     specific rev.)
+   */
+  pathrev_t ref;
 
-/** Drive @a editor's #svn_editor_cb_alter_symlink_t callback.
- *
- * Alter the properties and/or the target of the symlink at @a relpath
- * with @a revision as its expected revision. See svn_editor_alter_directory()
- * for more information about @a revision.
- *
- * If @a props is non-NULL, then the properties will be applied.
- *
- * If @a target is non-NULL, then the symlink's target will be updated.
- *
- * The properties and/or the target must be changed. It is an error to
- * pass NULL for @a props and @a target.
- *
- * This function allows @a props to be NULL, but the parameter is
- * otherwise described by svn_editor_add_file().
- *
- * For all restrictions on driving the editor, see #svn_editor_t.
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_alter_symlink(svn_editor_t *editor,
-                         const char *relpath,
-                         svn_revnum_t revision,
-                         const char *target,
-                         apr_hash_t *props);
+  /* Properties (for all node kinds).
+   * Maps (const char *) name -> (svn_string_t) value. */
+  apr_hash_t *props;
 
-/** Drive @a editor's #svn_editor_cb_delete_t callback.
- *
- * Delete the existing node at @a relpath, expected to be identical to
- * revision @a revision of that path.
- *
- * For all restrictions on driving the editor, see #svn_editor_t.
- * @since New in 1.8.
- */
-svn_error_t *
-svn_editor_delete(svn_editor_t *editor,
-                  const char *relpath,
-                  svn_revnum_t revision);
+  /* Text checksum (only for a file; otherwise SHOULD be NULL). */
+  const svn_checksum_t *checksum;
 
-/** Drive @a editor's #svn_editor_cb_copy_t callback.
- *
- * Copy the node at @a src_relpath, expected to be identical to revision @a
- * src_revision of that path, to @a dst_relpath.
- *
- * For a description of @a replaces_rev, see svn_editor_add_file().
- *
- * @note See the general instructions on paths for this API. Since the
- * @a src_relpath argument must generally be able to reference any node
- * in the repository, the implication is that the editor's root must be
- * the repository root.
- *
- * For all restrictions on driving the editor, see #svn_editor_t.
- * @since New in 1.8.
+  /* Text stream, readable (only for a file; otherwise SHOULD be NULL).
+   * ### May be null if we expect the receiver to retrieve the text by its
+   *     checksum? */
+  svn_stream_t *stream;
+
+  /* Symlink target (only for a symlink; otherwise SHOULD be NULL). */
+  const char *target;
+
+};
+
+/* Duplicate a node-content into result_pool.
+ * ### What about the stream though? Maybe we shouldn't have a _dup.
  */
-svn_error_t *
-svn_editor_copy(svn_editor_t *editor,
-                const char *src_relpath,
-                svn_revnum_t src_revision,
-                const char *dst_relpath,
-                svn_revnum_t replaces_rev);
+/* svn_editor3_node_content_t *
+svn_editor3_node_content_dup(const svn_editor3_node_content_t *old,
+                             apr_pool_t *result_pool); */
 
-/** Drive @a editor's #svn_editor_cb_move_t callback.
- *
- * Move the node at @a src_relpath to @a dst_relpath.
- *
- * @a src_revision specifies the revision at which the receiver should
- * expect to find this node.  That is, @a src_relpath at the start of
- * the whole edit and @a src_relpath at @a src_revision must lie within
- * the same node-rev (aka history-segment).  This is just like the
- * revisions specified to svn_editor_delete().
+/* Create a new node-content object for a directory node.
  *
- * For a description of @a replaces_rev, see svn_editor_add_file().
- *
- * ### what happens if one side of this move is not "within" the receiver's
- * ### set of paths?
- *
- * For all restrictions on driving the editor, see #svn_editor_t.
- * @since New in 1.8.
- */
+ * Allocate it in @a result_pool. */
 svn_error_t *
-svn_editor_move(svn_editor_t *editor,
-                const char *src_relpath,
-                svn_revnum_t src_revision,
-                const char *dst_relpath,
-                svn_revnum_t replaces_rev);
+svn_editor3_node_content_create_dir(svn_editor3_node_content_t **content,
+                                    pathrev_t ref,
+                                    apr_hash_t *props,
+                                    apr_pool_t *result_pool);
 
-/** Drive @a editor's #svn_editor_cb_complete_t callback.
- *
- * Send word that the edit has been completed successfully.
+/* Create a new node-content object for a file node.
  *
- * For all restrictions on driving the editor, see #svn_editor_t.
- * @since New in 1.8.
- */
+ * Allocate it in @a result_pool. */
 svn_error_t *
-svn_editor_complete(svn_editor_t *editor);
+svn_editor3_node_content_create_file(svn_editor3_node_content_t **content,
+                                     pathrev_t ref,
+                                     apr_hash_t *props,
+                                     const svn_checksum_t *checksum,
+                                     svn_stream_t *stream,
+                                     apr_pool_t *result_pool);
 
-/** Drive @a editor's #svn_editor_cb_abort_t callback.
- *
- * Notify that the edit transmission was not successful.
- * ### TODO @todo Shouldn't we add a reason-for-aborting argument?
+/* Create a new node-content object for a symlink node.
  *
- * For all restrictions on driving the editor, see #svn_editor_t.
- * @since New in 1.8.
- */
+ * Allocate it in @a result_pool. */
 svn_error_t *
-svn_editor_abort(svn_editor_t *editor);
+svn_editor3_node_content_create_symlink(svn_editor3_node_content_t **content,
+                                        pathrev_t ref,
+                                        apr_hash_t *props,
+                                        const char *target,
+                                        apr_pool_t *result_pool);
 
 /** @} */
 
 /** @} */
 
-/** A temporary API which conditionally inserts a double editor shim
- * into the chain of delta editors.  Used for testing Editor v2.
- *
- * Whether or not the shims are inserted is controlled by a compile-time
- * option in libsvn_delta/compat.c.
- *
- * @note The use of these shims and this API will likely cause all kinds
- * of performance degredation.  (Which is actually a moot point since they
- * don't even work properly yet anyway.)
- */
-svn_error_t *
-svn_editor__insert_shims(const svn_delta_editor_t **deditor_out,
-                         void **dedit_baton_out,
-                         const svn_delta_editor_t *deditor_in,
-                         void *dedit_baton_in,
-                         const char *repos_root,
-                         const char *base_dir,
-                         svn_delta_shim_callbacks_t *shim_callbacks,
-                         apr_pool_t *result_pool,
-                         apr_pool_t *scratch_pool);
-
-
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
 
-#endif /* SVN_EDITOR_H */
+#endif /* SVN_EDITOR3_H */