diff options
Diffstat (limited to 'subversion/include/private/svn_editor.h')
-rw-r--r-- | subversion/include/private/svn_editor.h | 641 |
1 files changed, 458 insertions, 183 deletions
diff --git a/subversion/include/private/svn_editor.h b/subversion/include/private/svn_editor.h index 38c3e2b..d714bb1 100644 --- a/subversion/include/private/svn_editor.h +++ b/subversion/include/private/svn_editor.h @@ -32,11 +32,90 @@ #include "svn_types.h" #include "svn_error.h" #include "svn_io.h" /* for svn_stream_t */ +#include "svn_delta.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ + +/*** Temporarily private stuff (should move to svn_delta.h when Editor + V2 is made public) ***/ + +/** 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 baton is an implementation-specific closure. + */ +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. + * + * Implementations should set @a *kind to the node kind of @a path in + * @a base_revision, using @a scratch_pool for temporary allocations. + * + * @a baton is an implementation-specific closure. + */ +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. + * + * @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. + */ +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; + +/** Return a collection of default shim functions in @a result_pool. + */ +svn_delta_shim_callbacks_t * +svn_delta_shim_callbacks_default(apr_pool_t *result_pool); + + + /** Transforming trees ("editing"). * * In Subversion, we have a number of occasions where we transform a tree @@ -79,15 +158,15 @@ extern "C" { * coupling between those subsystems. * * The set of changes, and the data necessary to describe it entirely, is - * completely unbounded. An addition of one simple 20Gb file would be well - * past the available memory of any machine processing these operations. + * 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. * * - * HISTORY + * <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 @@ -96,7 +175,7 @@ extern "C" { * 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 "@c svn_delta_editor_t" interface focused + * 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 @@ -105,7 +184,7 @@ extern "C" { * a set of operations describing the change, and a "receiver" accepts and * applies them to its tree. * - * The classic interface was named "@c svn_delta_editor_t" and was described + * 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. @@ -117,12 +196,51 @@ extern "C" { * 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. + * + * * @defgroup svn_editor The editor interface * @{ */ /** An abstract object that edits a target tree. * + * @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> * @@ -146,12 +264,13 @@ extern "C" { * svn_editor_setcb_add_file() \n * svn_editor_setcb_add_symlink() \n * svn_editor_setcb_add_absent() \n - * svn_editor_setcb_set_props() \n - * svn_editor_setcb_set_text() \n - * svn_editor_setcb_set_target() \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_rotate() \n * svn_editor_setcb_complete() \n * svn_editor_setcb_abort() * @@ -168,17 +287,18 @@ extern "C" { * svn_editor_add_file() \n * svn_editor_add_symlink() \n * svn_editor_add_absent() \n - * svn_editor_set_props() \n - * svn_editor_set_text() \n - * svn_editor_set_target() \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() + * svn_editor_move() \n + * svn_editor_rotate() * \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 + * 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. @@ -205,33 +325,42 @@ extern "C" { * 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/rotated, 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. * - * - svn_editor_add_file() -- An svn_editor_set_text() call must follow - * for the same path (at some point). - * - * - svn_editor_set_props() - * - The @a complete argument must be TRUE if no more calls will follow on - * the same path. @a complete must always be TRUE for directories. - * - If @a complete is FALSE, and: - * - if @a relpath is a file, this must (at some point) be followed by - * an svn_editor_set_text() call on the same path. - * - if @a relpath is a symlink, this must (at some point) be followed by - * an svn_editor_set_target() call on the same path. - * - * - svn_editor_set_text() and svn_editor_set_target() must always occur - * @b after an svn_editor_set_props() or svn_editor_add_file() call on - * the same path, if any.\n - * In other words, if there are two calls coming in on the same path, the - * first of them has to be either svn_editor_set_props() or - * svn_editor_add_file(). + * - 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, move, or rotate 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). Paths listed in a rotation are both sources and + * destinations, so they may not be referenced again in an add_* or a + * deletion; these paths may have alter_* operations applied. + * + * - The ancestor of an added, copied-here, moved-here, rotated, 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 @@ -242,6 +371,13 @@ extern "C" { * - 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. + * + * - Paths mentioned in svn_editor_rotate() may have their properties + * and contents edited (via alter_* calls) by a previous or later call, + * but they may not be subject to a later move, rotate, or deletion. * * - One of svn_editor_complete() or svn_editor_abort() must be called * exactly once, which must be the final call the driver invokes. @@ -250,19 +386,16 @@ extern "C" { * svn_editor_abort() must imply that the transformation was not completed * successfully. * - * - If any callback invocation returns with an error, the driver must - * invoke svn_editor_abort() and stop transmitting operations. + * - 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, except for the following pairs, where a change must be completed - * when receiving the second callback in each pair: - * - svn_editor_add_file() and svn_editor_set_text() - * - svn_editor_set_props() (if @a complete is FALSE) and - * svn_editor_set_text() (if the node is a file) - * - svn_editor_set_props() (if @a complete is FALSE) and - * svn_editor_set_target() (if the node is a symbolic link) + * + * 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. @@ -276,16 +409,34 @@ extern "C" { * 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 path for the paths sent and received via the - * callbacks' @a relpath arguments. - * - * For example, during an "update", the driver has a working copy checked - * out at a specific repository URL. The receiver sees the repository as a - * whole. 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. + * 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> @@ -322,16 +473,19 @@ extern "C" { * context. * * - * ### TODO @todo anything missing? -- allow text and prop change to follow - * a move or copy. -- set_text() vs. apply_text_delta()? -- If a - * set_props/set_text/set_target/copy/move/delete in a merge source is - * applied to a different branch, which side will REVISION arguments reflect - * and is there still a problem? + * @todo ### TODO anything missing? * - * @since New in 1.7. + * @since New in 1.8. */ typedef struct svn_editor_t svn_editor_t; +/** The kind of the checksum to be used throughout the #svn_editor_t APIs. + * + * @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. + */ +#define SVN_EDITOR_CHECKSUM_KIND svn_checksum_sha1 + /** These function types define the callback functions a tree delta consumer * implements. @@ -358,7 +512,7 @@ typedef struct svn_editor_t svn_editor_t; */ /** @see svn_editor_add_directory(), svn_editor_t. - * @since New in 1.7. + * @since New in 1.8. */ typedef svn_error_t *(*svn_editor_cb_add_directory_t)( void *baton, @@ -369,17 +523,19 @@ typedef svn_error_t *(*svn_editor_cb_add_directory_t)( apr_pool_t *scratch_pool); /** @see svn_editor_add_file(), svn_editor_t. - * @since New in 1.7. + * @since New in 1.8. */ typedef svn_error_t *(*svn_editor_cb_add_file_t)( void *baton, const char *relpath, + const svn_checksum_t *checksum, + svn_stream_t *contents, apr_hash_t *props, svn_revnum_t replaces_rev, apr_pool_t *scratch_pool); /** @see svn_editor_add_symlink(), svn_editor_t. - * @since New in 1.7. + * @since New in 1.8. */ typedef svn_error_t *(*svn_editor_cb_add_symlink_t)( void *baton, @@ -390,7 +546,7 @@ typedef svn_error_t *(*svn_editor_cb_add_symlink_t)( apr_pool_t *scratch_pool); /** @see svn_editor_add_absent(), svn_editor_t. - * @since New in 1.7. + * @since New in 1.8. */ typedef svn_error_t *(*svn_editor_cb_add_absent_t)( void *baton, @@ -399,40 +555,42 @@ typedef svn_error_t *(*svn_editor_cb_add_absent_t)( svn_revnum_t replaces_rev, apr_pool_t *scratch_pool); -/** @see svn_editor_set_props(), svn_editor_t. - * @since New in 1.7. +/** @see svn_editor_alter_directory(), svn_editor_t. + * @since New in 1.8. */ -typedef svn_error_t *(*svn_editor_cb_set_props_t)( +typedef svn_error_t *(*svn_editor_cb_alter_directory_t)( void *baton, const char *relpath, svn_revnum_t revision, + const apr_array_header_t *children, apr_hash_t *props, - svn_boolean_t complete, apr_pool_t *scratch_pool); -/** @see svn_editor_set_text(), svn_editor_t. - * @since New in 1.7. +/** @see svn_editor_alter_file(), svn_editor_t. + * @since New in 1.8. */ -typedef svn_error_t *(*svn_editor_cb_set_text_t)( +typedef svn_error_t *(*svn_editor_cb_alter_file_t)( void *baton, const char *relpath, svn_revnum_t revision, + apr_hash_t *props, const svn_checksum_t *checksum, svn_stream_t *contents, apr_pool_t *scratch_pool); -/** @see svn_editor_set_target(), svn_editor_t. - * @since New in 1.7. +/** @see svn_editor_alter_symlink(), svn_editor_t. + * @since New in 1.8. */ -typedef svn_error_t *(*svn_editor_cb_set_target_t)( +typedef svn_error_t *(*svn_editor_cb_alter_symlink_t)( void *baton, const char *relpath, svn_revnum_t revision, + apr_hash_t *props, const char *target, apr_pool_t *scratch_pool); /** @see svn_editor_delete(), svn_editor_t. - * @since New in 1.7. + * @since New in 1.8. */ typedef svn_error_t *(*svn_editor_cb_delete_t)( void *baton, @@ -441,7 +599,7 @@ typedef svn_error_t *(*svn_editor_cb_delete_t)( apr_pool_t *scratch_pool); /** @see svn_editor_copy(), svn_editor_t. - * @since New in 1.7. + * @since New in 1.8. */ typedef svn_error_t *(*svn_editor_cb_copy_t)( void *baton, @@ -452,7 +610,7 @@ typedef svn_error_t *(*svn_editor_cb_copy_t)( apr_pool_t *scratch_pool); /** @see svn_editor_move(), svn_editor_t. - * @since New in 1.7. + * @since New in 1.8. */ typedef svn_error_t *(*svn_editor_cb_move_t)( void *baton, @@ -462,15 +620,24 @@ typedef svn_error_t *(*svn_editor_cb_move_t)( svn_revnum_t replaces_rev, apr_pool_t *scratch_pool); +/** @see svn_editor_rotate(), svn_editor_t. + * @since New in 1.8. + */ +typedef svn_error_t *(*svn_editor_cb_rotate_t)( + void *baton, + const apr_array_header_t *relpaths, + const apr_array_header_t *revisions, + apr_pool_t *scratch_pool); + /** @see svn_editor_complete(), svn_editor_t. - * @since New in 1.7. + * @since New in 1.8. */ typedef svn_error_t *(*svn_editor_cb_complete_t)( void *baton, apr_pool_t *scratch_pool); /** @see svn_editor_abort(), svn_editor_t. - * @since New in 1.7. + * @since New in 1.8. */ typedef svn_error_t *(*svn_editor_cb_abort_t)( void *baton, @@ -491,7 +658,7 @@ typedef svn_error_t *(*svn_editor_cb_abort_t)( * @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.7. + * @since New in 1.8. */ svn_error_t * svn_editor_create(svn_editor_t **editor, @@ -502,11 +669,22 @@ svn_editor_create(svn_editor_t **editor, 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.7. + * @since New in 1.8. */ svn_error_t * svn_editor_setcb_add_directory(svn_editor_t *editor, @@ -517,7 +695,7 @@ svn_editor_setcb_add_directory(svn_editor_t *editor, * to @a callback. * @a scratch_pool is used for temporary allocations (if any). * @see also svn_editor_setcb_many(). - * @since New in 1.7. + * @since New in 1.8. */ svn_error_t * svn_editor_setcb_add_file(svn_editor_t *editor, @@ -528,7 +706,7 @@ svn_editor_setcb_add_file(svn_editor_t *editor, * to @a callback. * @a scratch_pool is used for temporary allocations (if any). * @see also svn_editor_setcb_many(). - * @since New in 1.7. + * @since New in 1.8. */ svn_error_t * svn_editor_setcb_add_symlink(svn_editor_t *editor, @@ -539,51 +717,51 @@ svn_editor_setcb_add_symlink(svn_editor_t *editor, * to @a callback. * @a scratch_pool is used for temporary allocations (if any). * @see also svn_editor_setcb_many(). - * @since New in 1.7. + * @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_set_props_t callback in @a editor +/** 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.7. + * @since New in 1.8. */ svn_error_t * -svn_editor_setcb_set_props(svn_editor_t *editor, - svn_editor_cb_set_props_t callback, - apr_pool_t *scratch_pool); +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_set_text_t callback in @a editor +/** 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.7. + * @since New in 1.8. */ svn_error_t * -svn_editor_setcb_set_text(svn_editor_t *editor, - svn_editor_cb_set_text_t callback, - apr_pool_t *scratch_pool); +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_set_target_t callback in @a editor +/** 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.7. + * @since New in 1.8. */ svn_error_t * -svn_editor_setcb_set_target(svn_editor_t *editor, - svn_editor_cb_set_target_t callback, - apr_pool_t *scratch_pool); +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.7. + * @since New in 1.8. */ svn_error_t * svn_editor_setcb_delete(svn_editor_t *editor, @@ -594,7 +772,7 @@ svn_editor_setcb_delete(svn_editor_t *editor, * to @a callback. * @a scratch_pool is used for temporary allocations (if any). * @see also svn_editor_setcb_many(). - * @since New in 1.7. + * @since New in 1.8. */ svn_error_t * svn_editor_setcb_copy(svn_editor_t *editor, @@ -605,18 +783,29 @@ svn_editor_setcb_copy(svn_editor_t *editor, * to @a callback. * @a scratch_pool is used for temporary allocations (if any). * @see also svn_editor_setcb_many(). - * @since New in 1.7. + * @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_rotate_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_rotate(svn_editor_t *editor, + svn_editor_cb_rotate_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.7. + * @since New in 1.8. */ svn_error_t * svn_editor_setcb_complete(svn_editor_t *editor, @@ -627,7 +816,7 @@ svn_editor_setcb_complete(svn_editor_t *editor, * to @a callback. * @a scratch_pool is used for temporary allocations (if any). * @see also svn_editor_setcb_many(). - * @since New in 1.7. + * @since New in 1.8. */ svn_error_t * svn_editor_setcb_abort(svn_editor_t *editor, @@ -638,7 +827,7 @@ svn_editor_setcb_abort(svn_editor_t *editor, /** 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.7. + * @since New in 1.8. */ typedef struct svn_editor_cb_many_t { @@ -646,12 +835,13 @@ typedef struct svn_editor_cb_many_t 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_set_props_t cb_set_props; - svn_editor_cb_set_text_t cb_set_text; - svn_editor_cb_set_target_t cb_set_target; + 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_rotate_t cb_rotate; svn_editor_cb_complete_t cb_complete; svn_editor_cb_abort_t cb_abort; @@ -660,7 +850,7 @@ typedef struct 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.7. + * @since New in 1.8. */ svn_error_t * svn_editor_setcb_many(svn_editor_t *editor, @@ -683,21 +873,14 @@ svn_editor_setcb_many(svn_editor_t *editor, * Create a new directory at @a relpath. The immediate parent of @a relpath * is expected to exist. * - * Set the properties of the new directory 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 directory, @a props must be NULL. - * - * If this add is expected to replace a previously existing file 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 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. + * 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. */ @@ -713,24 +896,30 @@ svn_editor_add_directory(svn_editor_t *editor, * 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 NULL. + * 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 or + * 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 + * #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.7. + * @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); @@ -743,7 +932,7 @@ svn_editor_add_file(svn_editor_t *editor, * svn_editor_add_file(). * * For all restrictions on driving the editor, see #svn_editor_t. - * @since New in 1.7. + * @since New in 1.8. */ svn_error_t * svn_editor_add_symlink(svn_editor_t *editor, @@ -757,11 +946,12 @@ svn_editor_add_symlink(svn_editor_t *editor, * 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.7. + * @since New in 1.8. */ svn_error_t * svn_editor_add_absent(svn_editor_t *editor, @@ -769,61 +959,96 @@ svn_editor_add_absent(svn_editor_t *editor, svn_node_kind_t kind, svn_revnum_t replaces_rev); -/** Drive @a editor's #svn_editor_cb_set_props_t callback. +/** 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. * - * Set or change properties on the existing node at @a relpath. - * ### TODO @todo Does this send *all* properties, always? - * ### TODO @todo What is REVISION for? - * ### what about "entry props"? will these still be handled via - * ### the general prop function? + * 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. * - * @a complete must be FALSE if and only if - * - @a relpath is a file and an svn_editor_set_text() call will follow on - * the same path, or - * - @a relpath is a symbolic link and an svn_editor_set_target() call will - * follow on the same path. + * 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.7. + * @since New in 1.8. */ svn_error_t * -svn_editor_set_props(svn_editor_t *editor, - const char *relpath, - svn_revnum_t revision, - apr_hash_t *props, - svn_boolean_t complete); +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_set_text_t callback. +/** Drive @a editor's #svn_editor_cb_alter_file_t callback. * - * Set/change the text content of a file at @a relpath to @a contents - * with checksum @a checksum. - * ### TODO @todo Does this send the *complete* content, always? - * ### TODO @todo What is REVISION for? + * 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.7. + * @since New in 1.8. */ svn_error_t * -svn_editor_set_text(svn_editor_t *editor, - const char *relpath, - svn_revnum_t revision, - const svn_checksum_t *checksum, - svn_stream_t *contents); +svn_editor_alter_file(svn_editor_t *editor, + const char *relpath, + svn_revnum_t revision, + apr_hash_t *props, + const svn_checksum_t *checksum, + svn_stream_t *contents); -/** Drive @a editor's #svn_editor_cb_set_target_t callback. +/** 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. * - * Set/change the link target that a symbolic link at @a relpath points at - * to @a target. - * ### TODO @todo What is REVISION for? + * 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.7. + * @since New in 1.8. */ svn_error_t * -svn_editor_set_target(svn_editor_t *editor, - const char *relpath, - svn_revnum_t revision, - const char *target); +svn_editor_alter_symlink(svn_editor_t *editor, + const char *relpath, + svn_revnum_t revision, + apr_hash_t *props, + const char *target); /** Drive @a editor's #svn_editor_cb_delete_t callback. * @@ -831,7 +1056,7 @@ svn_editor_set_target(svn_editor_t *editor, * revision @a revision of that path. * * For all restrictions on driving the editor, see #svn_editor_t. - * @since New in 1.7. + * @since New in 1.8. */ svn_error_t * svn_editor_delete(svn_editor_t *editor, @@ -845,8 +1070,13 @@ svn_editor_delete(svn_editor_t *editor, * * 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.7. + * @since New in 1.8. */ svn_error_t * svn_editor_copy(svn_editor_t *editor, @@ -856,29 +1086,22 @@ svn_editor_copy(svn_editor_t *editor, svn_revnum_t replaces_rev); /** Drive @a editor's #svn_editor_cb_move_t callback. - * Move the node at @a src_relpath, expected to be identical to revision @a - * src_revision of that path, to @a dst_relpath. + * + * 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() and svn_editor_rotate(). * * For a description of @a replaces_rev, see svn_editor_add_file(). * - * ### stsp: How would I describe a merge of revision range rA-rB, - * ### within which a file foo.c was delete in rN, re-created in rM, - * ### and then renamed to bar.c in rX? - * ### Would the following be valid? - * ### svn_editor_add_file(ed, "foo.c", props, rN); - * ### svn_editor_move(ed, "foo.c", rM, "bar.c", rN); - * ### - * ### gstein: no, it would be: - * ### svn_editor_delete(e, "foo.c", rN); - * ### svn_editor_add_file(e, "foo.c", props, SVN_INVALID_REVNUM); - * ### svn_editor_move(e, "foo.c", rM, "bar.c", SVN_INVALID_REVNUM); - * ### - * ### replaces_rev is to indicate a deletion of the destination node - * ### that occurs as part of the move. there are no replacements in - * ### your example. + * ### 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.7. + * @since New in 1.8. */ svn_error_t * svn_editor_move(svn_editor_t *editor, @@ -887,23 +1110,53 @@ svn_editor_move(svn_editor_t *editor, const char *dst_relpath, svn_revnum_t replaces_rev); +/** Drive @a editor's #svn_editor_cb_rotate_t callback. + * + * Perform a rotation among multiple nodes in the target tree. + * + * The @a relpaths and @a revisions arrays (pair-wise) specify nodes in the + * tree which are located at a path and expected to be at a specific + * revision. These nodes are simultaneously moved in a rotation pattern. + * For example, the node at index 0 of @a relpaths and @a revisions will + * be moved to the relpath specified at index 1 of @a relpaths. The node + * at index 1 will be moved to the location at index 2. The node at index + * N-1 will be moved to the relpath specified at index 0. + * + * The simplest form of this operation is to swap nodes A and B. One may + * think to move A to a temporary location T, then move B to A, then move + * T to B. However, this last move violations the Once Rule by moving T + * (which had already by edited by the move from A). In order to keep the + * restrictions against multiple moves of a single node, the rotation + * operation is needed for certain types of tree edits. + * + * ### what happens if one of the paths of the rotation 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. + */ +svn_error_t * +svn_editor_rotate(svn_editor_t *editor, + const apr_array_header_t *relpaths, + const apr_array_header_t *revisions); + /** Drive @a editor's #svn_editor_cb_complete_t callback. * - * Send word that the tree delta has been completed successfully. + * Send word that the edit has been completed successfully. * * For all restrictions on driving the editor, see #svn_editor_t. - * @since New in 1.7. + * @since New in 1.8. */ svn_error_t * svn_editor_complete(svn_editor_t *editor); /** Drive @a editor's #svn_editor_cb_abort_t callback. * - * Notify that the tree delta transmission was not successful. + * 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_editor_t. - * @since New in 1.7. + * @since New in 1.8. */ svn_error_t * svn_editor_abort(svn_editor_t *editor); @@ -912,6 +1165,28 @@ svn_editor_abort(svn_editor_t *editor); /** @} */ +/** 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 */ |