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/10/27 17:52:23 UTC
svn commit: r1634591 [4/4] - in
/subversion/branches/move-tracking-2/subversion:
include/private/svn_editor3.h libsvn_delta/compat3.c libsvn_delta/editor3.c
libsvn_ra/ra_loader.c svnmover/svnmover.c
Modified: subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c?rev=1634591&r1=1634590&r2=1634591&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c (original)
+++ subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c Mon Oct 27 16:52:23 2014
@@ -80,97 +80,6 @@ check_lib_versions(void)
/* ====================================================================== */
-/* Construct a txn-path.
- */
-static svn_editor3_txn_path_t
-txn_path(const char *repos_relpath, svn_revnum_t revision,
- const char *created_relpath)
-{
- svn_editor3_txn_path_t p;
-
- p.peg.rev = revision;
- p.peg.relpath = repos_relpath;
- p.relpath = created_relpath;
- return p;
-}
-
-/* Return a txn-path constructed by extending TXN_PATH with RELPATH.
- */
-static svn_editor3_txn_path_t
-txn_path_join(svn_editor3_txn_path_t txn_path,
- const char *relpath,
- apr_pool_t *result_pool)
-{
- svn_editor3_txn_path_t p = txn_path;
-
- p.relpath = svn_relpath_join(p.relpath, relpath, result_pool);
- return p;
-}
-
-/* Return a human-readable string representation of LOC.
- */
-static const char *
-txn_path_str(svn_editor3_txn_path_t loc,
- apr_pool_t *result_pool)
-{
- return apr_psprintf(result_pool, "%s@%ld//%s",
- loc.peg.relpath, loc.peg.rev, loc.relpath);
-}
-
-/* Return the full relpath of LOC,
- * ### assuming the peg-path part doesn't need translation between its
- * peg-revision and the transaction in which we interpret it.
- */
-static const char *
-txn_path_to_relpath(svn_editor3_txn_path_t loc,
- apr_pool_t *result_pool)
-{
- return svn_relpath_join(loc.peg.relpath, loc.relpath, result_pool);
-}
-
-/* Return the txn-path of the parent directory of LOC.
- */
-static svn_editor3_txn_path_t
-txn_path_dirname(svn_editor3_txn_path_t loc,
- apr_pool_t *result_pool)
-{
- svn_editor3_txn_path_t parent_loc;
-
- parent_loc.peg.rev = loc.peg.rev;
- if (*loc.relpath)
- {
- parent_loc.peg.relpath = apr_pstrdup(result_pool, loc.peg.relpath);
- parent_loc.relpath = svn_relpath_dirname(loc.relpath, result_pool);
- }
- else
- {
- parent_loc.peg.relpath = svn_relpath_dirname(loc.peg.relpath,
- result_pool);
- parent_loc.relpath = apr_pstrdup(result_pool, loc.relpath);
- }
- return parent_loc;
-}
-
-/* Return the txn-path of the parent directory of LOC.
- */
-static const char *
-txn_path_basename(svn_editor3_txn_path_t loc)
-{
- const char *base;
-
- if (*loc.relpath)
- {
- base = svn_relpath_basename(loc.relpath, NULL);
- }
- else
- {
- base = svn_relpath_basename(loc.peg.relpath, NULL);
- }
- return base;
-}
-
-/* ====================================================================== */
-
typedef struct mtcc_t
{
apr_pool_t *pool;
@@ -207,2197 +116,217 @@ mtcc_create(mtcc_t **mtcc_p,
SVN_ERR(svn_ra_get_repos_root2(mtcc->ra_session, &mtcc->repos_root_url,
result_pool));
- SVN_ERR(svn_ra_get_latest_revnum(mtcc->ra_session, &mtcc->head_revision,
- scratch_pool));
-
- if (! SVN_IS_VALID_REVNUM(base_revision))
- mtcc->base_revision = mtcc->head_revision;
- else if (base_revision > mtcc->head_revision)
- return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
- _("No such revision %ld (HEAD is %ld)"),
- base_revision, mtcc->head_revision);
- else
- mtcc->base_revision = base_revision;
-
- SVN_ERR(svn_ra_get_commit_editor_ev3(mtcc->ra_session, &mtcc->editor,
- revprops,
- commit_callback, commit_baton,
- NULL /*lock_tokens*/, FALSE /*keep_locks*/,
- result_pool));
- *mtcc_p = mtcc;
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-mtcc_commit(mtcc_t *mtcc,
- apr_pool_t *scratch_pool)
-{
- svn_error_t *err;
-
-#if 0
- /* No changes -> no revision. Easy out */
- if (MTCC_UNMODIFIED(mtcc))
- {
- svn_editor3_abort(mtcc->editor);
- svn_pool_destroy(mtcc->pool);
- return SVN_NO_ERROR;
- }
-#endif
-
-#if 0
- const char *session_url;
-
- SVN_ERR(svn_ra_get_session_url(mtcc->ra_session, &session_url, scratch_pool));
-
- if (mtcc->root_op->kind != OP_OPEN_DIR)
- {
- const char *name;
-
- svn_uri_split(&session_url, &name, session_url, scratch_pool);
-
- if (*name)
- {
- SVN_ERR(mtcc_reparent(session_url, mtcc, scratch_pool));
-
- SVN_ERR(svn_ra_reparent(mtcc->ra_session, session_url, scratch_pool));
- }
- }
-#endif
-
- err = svn_editor3_complete(mtcc->editor);
-
- return svn_error_trace(err);
-}
-
-static svn_error_t *
-commit_callback(const svn_commit_info_t *commit_info,
- void *baton,
- apr_pool_t *pool)
-{
- SVN_ERR(svn_cmdline_printf(pool, "r%ld committed by %s at %s\n",
- commit_info->revision,
- (commit_info->author
- ? commit_info->author : "(no author)"),
- commit_info->date));
- return SVN_NO_ERROR;
-}
-
-typedef enum action_code_t {
- ACTION_LIST_BRANCHES,
- ACTION_LIST_BRANCHES_R,
- ACTION_BRANCH,
- ACTION_BRANCHIFY,
- ACTION_DISSOLVE,
- ACTION_MERGE,
- ACTION_MV,
- ACTION_MKDIR,
- ACTION_CP,
- ACTION_RM
-} action_code_t;
-
-struct action {
- action_code_t action;
-
- /* revision (copy-from-rev of path[0] for cp) */
- svn_revnum_t rev;
-
- /* action path[0] path[1] path[2]
- * ------ ------- ------- -------
- * list_br path
- * branch source target
- * branchify path
- * dissolve path
- * merge from to yca@rev
- * mv source target
- * mkdir target
- * cp source target
- * rm target
- */
- const char *path[3];
-};
-
-/* ====================================================================== */
-
-/* ### */
-#define SVN_ERR_BRANCHING 123456
-
-struct svn_branch_family_t;
-struct svn_branch_instance_t;
-
-/* Per-repository branching info.
- */
-typedef struct svn_branch_repos_t
-{
- svn_ra_session_t *ra_session;
- svn_editor3_t *editor;
-
- /* The range of family ids assigned within this repos (starts at 0). */
- int next_fid;
-
- /* Array of (svn_branch_revision_info_t *), indexed by revision number. */
- apr_array_header_t *rev_roots;
-
- /* The pool in which this object lives. */
- apr_pool_t *pool;
-} svn_branch_repos_t;
-
-/* Info about the branching in a specific revision (committed or uncommitted) */
-typedef struct svn_branch_revision_root_t
-{
- /* The repository in which this revision exists. */
- svn_branch_repos_t *repos;
-
- /* The root branch instance. */
- struct svn_branch_instance_t *root_branch;
-
-} svn_branch_revision_root_t;
-
-/* A branch family.
- * ### Most of this is not per-revision data. Move it out of revision-root?
- */
-typedef struct svn_branch_family_t
-{
- /* --- Identity of this object --- */
-
- /* The repository in which this family exists. */
- svn_branch_repos_t *repos;
-
- /* The outer family of which this is a sub-family. NULL if this is the
- root family. */
- /*struct svn_branch_family_t *outer_family;*/
-
- /* The FID of this family within its repository. */
- int fid;
-
- /* --- Contents of this object --- */
-
- /* The branch definitions in this family. */
- apr_array_header_t *branch_definitions;
-
- /* The branch instances in this family. */
- /* ### This is per-revision data. Move to svn_branch_revision_root_t? */
- apr_array_header_t *branch_instances;
-
- /* The range of branch ids assigned within this family. */
- int first_bid, next_bid;
-
- /* The range of element ids assigned within this family. */
- int first_eid, next_eid;
-
- /* The immediate sub-families of this family. */
- apr_array_header_t *sub_families;
-
- /* The pool in which this object lives. */
- apr_pool_t *pool;
-} svn_branch_family_t;
-
-/* A branch.
- *
- * A branch definition object describes the characteristics of a branch
- * in a given family with a given BID. This definition is common to each
- * branch that has this same family and BID: there can be one such instance
- * within each branch of its outer families.
- *
- * Often, all branches in a family have the same root element. For example,
- * branching /trunk to /branches/br1 results in:
- *
- * family 1, branch 1, root-EID 100
- * EID 100 => /trunk
- * ...
- * family 1, branch 2, root-EID 100
- * EID 100 => /branches/br1
- * ...
- *
- * However, the root element of one branch may correspond to a non-root
- * element of another branch; such a branch could be called a "subtree
- * branch". Using the same example, branching from the trunk subtree
- * /trunk/D (which is not itself a branch root) results in:
- *
- * family 1, branch 3: root-EID = 104
- * EID 100 => (nil)
- * ...
- * EID 104 => /branches/branch-of-trunk-subtree-D
- * ...
- *
- * If family 1 were nested inside an outer family, then there could be
- * multiple branch-instances for each branch-definition. In the above
- * example, all instances of (family 1, branch 1) will have root-EID 100,
- * and all instances of (family 1, branch 3) will have root-EID 104.
- */
-typedef struct svn_branch_definition_t
-{
- /* --- Identity of this object --- */
-
- /* The family of which this branch is a member. */
- svn_branch_family_t *family;
-
- /* The BID of this branch within its family. */
- int bid;
-
- /* The EID, within the outer family, of the branch root element. */
- /*int outer_family_eid_of_branch_root;*/
-
- /* --- Contents of this object --- */
-
- /* The EID within its family of its pathwise root element. */
- int root_eid;
-} svn_branch_definition_t;
-
-/* A branch instance.
- *
- * A branch instance object describes one branch in this family. (There is
- * one instance of this branch within each branch of its outer families.)
- */
-typedef struct svn_branch_instance_t
-{
- /* --- Identity of this object --- */
-
- svn_branch_definition_t *definition;
-
- /* The revision to which this branch-revision-instance belongs */
- svn_branch_revision_root_t *rev_root;
-
- /* The branch (instance?), within the outer family, that contains the
- root element of this branch. */
- /*svn_branch_instance_t *outer_family_branch_instance;*/
-
- /* --- Contents of this object --- */
-
- /* EID <-> path mapping in the current revision. Path is relative to
- repos root. There is always an entry for root_eid. */
- apr_hash_t *eid_to_path, *path_to_eid;
-} svn_branch_instance_t;
-
-/* element */
-/*
-typedef struct svn_branch_element_t
-{
- int eid;
- svn_branch_family_t *family;
-} svn_branch_element_t;
-*/
-
-/* Branch-Revision-Element */
-typedef struct svn_branch_el_rev_id_t
-{
- /* The branch-instance that applies to REV. */
- svn_branch_instance_t *branch;
- /* Element. */
- int eid;
- /* Revision. SVN_INVALID_REVNUM means 'in this transaction', not 'head'.
- ### Do we need this if BRANCH refers to a particular branch-revision? */
- svn_revnum_t rev;
-
-} svn_branch_el_rev_id_t;
-
-typedef struct svn_branch_el_rev_content_t
-{
- int parent_eid;
- const char *name;
- svn_editor3_node_content_t *content;
-
-} svn_branch_el_rev_content_t;
-
-/* Create a new branching metadata object */
-static svn_branch_repos_t *
-svn_branch_repos_create(svn_ra_session_t *ra_session,
- svn_editor3_t *editor,
- apr_pool_t *result_pool)
-{
- svn_branch_repos_t *repos = apr_pcalloc(result_pool, sizeof(*repos));
-
- repos->ra_session = ra_session;
- repos->editor = editor;
- repos->rev_roots = apr_array_make(result_pool, 1, sizeof(void *));
- repos->pool = result_pool;
- return repos;
-}
-
-/* Create a new branching revision-info object */
-static svn_branch_revision_root_t *
-svn_branch_revision_root_create(svn_branch_repos_t *repos,
- struct svn_branch_instance_t *root_branch,
- apr_pool_t *result_pool)
-{
- svn_branch_revision_root_t *rev_root
- = apr_pcalloc(result_pool, sizeof(*rev_root));
-
- rev_root->repos = repos;
- rev_root->root_branch = root_branch;
- return rev_root;
-}
-
-/* Create a new branch family object */
-static svn_branch_family_t *
-svn_branch_family_create(svn_branch_repos_t *repos,
- int fid,
- int first_bid,
- int next_bid,
- int first_eid,
- int next_eid,
- apr_pool_t *result_pool)
-{
- svn_branch_family_t *f = apr_pcalloc(result_pool, sizeof(*f));
-
- f->fid = fid;
- f->repos = repos;
- f->branch_definitions = apr_array_make(result_pool, 1, sizeof(void *));
- f->branch_instances = apr_array_make(result_pool, 1, sizeof(void *));
- f->sub_families = apr_array_make(result_pool, 1, sizeof(void *));
- f->first_bid = first_bid;
- f->next_bid = next_bid;
- f->first_eid = first_eid;
- f->next_eid = next_eid;
- f->pool = result_pool;
- return f;
-}
-
-/* Create a new branch definition object */
-static svn_branch_definition_t *
-svn_branch_definition_create(svn_branch_family_t *family,
- int bid,
- int root_eid,
- apr_pool_t *result_pool)
-{
- svn_branch_definition_t *b = apr_pcalloc(result_pool, sizeof(*b));
-
- SVN_ERR_ASSERT_NO_RETURN(bid >= family->first_bid
- && bid < family->next_bid);
- SVN_ERR_ASSERT_NO_RETURN(root_eid >= family->first_eid
- && root_eid < family->next_eid);
-
- b->family = family;
- b->bid = bid;
- b->root_eid = root_eid;
- return b;
-}
-
-/* Create a new branch instance object */
-static svn_branch_instance_t *
-svn_branch_instance_create(svn_branch_definition_t *branch_definition,
- svn_branch_revision_root_t *rev_root,
- apr_pool_t *result_pool)
-{
- svn_branch_instance_t *b = apr_pcalloc(result_pool, sizeof(*b));
-
- b->definition = branch_definition;
- b->rev_root = rev_root;
- b->eid_to_path = apr_hash_make(result_pool);
- b->path_to_eid = apr_hash_make(result_pool);
- return b;
-}
-
-static const char *
-branch_get_root_path(const svn_branch_instance_t *branch);
-
-/* In BRANCH, set or change the path mapping for EID to point to PATH.
- *
- * Do not check for or remove any previous mappings; just overwrite
- * the mapping for EID to this new PATH and for PATH to this new EID.
- * EID MUST be a valid EID belonging to BRANCH's family.
- *
- * Duplicate EID and PATH into the mapping's pool.
- */
-static void
-branch_mapping_set(svn_branch_instance_t *branch,
- int eid,
- const char *path)
-{
- apr_pool_t *pool = apr_hash_pool_get(branch->eid_to_path);
- int *eid_stored = apr_pmemdup(pool, &eid, sizeof(eid));
-
- SVN_ERR_ASSERT_NO_RETURN(eid >= branch->definition->family->first_eid
- && eid < branch->definition->family->next_eid);
-
- /* overwrite the EID-to-new-PATH and part of the mapping */
- path = apr_pstrdup(pool, path);
- apr_hash_set(branch->eid_to_path, eid_stored, sizeof(eid), path);
- svn_hash_sets(branch->path_to_eid, path, eid_stored);
-}
-
-/* In BRANCH, remove the path mapping for EID if there is one.
- *
- * Do not check for any previous mappings, or for validity of EID or any
- * mappings.
- */
-static void
-branch_mapping_unset_by_eid(svn_branch_instance_t *branch,
- int eid)
-{
- const char *path = apr_hash_get(branch->eid_to_path, &eid, sizeof(eid));
-
- if (path)
- {
- apr_hash_set(branch->eid_to_path, &eid, sizeof(eid), NULL);
- svn_hash_sets(branch->path_to_eid, path, NULL);
- }
-}
-
-/* In BRANCH, set or change the path mapping for EID to point to PATH.
- *
- * If a mapping from EID to a different path already exists, update it
- * to map to PATH. PATH MUST NOT already be mapped to a different EID.
- * PATH MUST be pathwise within the root path of BRANCH.
- */
-static void
-branch_mapping_update(svn_branch_instance_t *branch,
- int eid,
- const char *path)
-{
- int *old_eid_p = svn_hash_gets(branch->path_to_eid, path);
-
- SVN_ERR_ASSERT_NO_RETURN(eid == branch->definition->root_eid
- || svn_relpath_skip_ancestor(
- branch_get_root_path(branch), path));
- /* we don't allow mapping a new EID to an existing path */
- SVN_ERR_ASSERT_NO_RETURN(! old_eid_p || *old_eid_p == eid);
-
- /* Remove any mapping to an old path, as the path-to-EID part of such a
- mapping would not be overwritten simply by setting the new mapping. */
- branch_mapping_unset_by_eid(branch, eid);
-
- branch_mapping_set(branch, eid, path);
-}
-
-/* In BRANCH, remove the path mapping for EID, so that the element EID
- * is considered as no longer existing in BRANCH.
- *
- * A mapping for EID MUST already exist in BRANCH.
- */
-static void
-branch_mapping_remove_by_eid(svn_branch_instance_t *branch,
- int eid)
-{
- const char *path = apr_hash_get(branch->eid_to_path, &eid, sizeof(eid));
-
- SVN_ERR_ASSERT_NO_RETURN(eid >= branch->definition->family->first_eid
- && eid < branch->definition->family->next_eid);
- SVN_ERR_ASSERT_NO_RETURN(path);
-
- apr_hash_set(branch->eid_to_path, &eid, sizeof(eid), NULL);
- svn_hash_sets(branch->path_to_eid, path, NULL);
-}
-
-/* In BRANCH, remove the path mapping for PATH, so that the element
- * at PATH is considered as no longer existing in BRANCH.
- *
- * A mapping for PATH MUST already exist in BRANCH.
- */
-static void
-branch_mapping_remove_by_path(svn_branch_instance_t *branch,
- const char *path)
-{
- int *eid_p = svn_hash_gets(branch->path_to_eid, path);
-
- SVN_ERR_ASSERT_NO_RETURN(svn_relpath_skip_ancestor(
- branch_get_root_path(branch), path));
- SVN_ERR_ASSERT_NO_RETURN(eid_p);
-
- apr_hash_set(branch->eid_to_path, eid_p, sizeof(*eid_p), NULL);
- svn_hash_sets(branch->path_to_eid, path, NULL);
-}
-
-/* Return the EID in BRANCH of the element at repos-relpath PATH,
- * or -1 if PATH is not currently present in BRANCH.
- *
- * PATH MUST be pathwise within BRANCH.
- */
-static int
-branch_get_eid_by_path(const svn_branch_instance_t *branch,
- const char *path)
-{
- int *eid_p = svn_hash_gets(branch->path_to_eid, path);
-
- /* If the branch knows its root path, PATH must be within that. */
- SVN_ERR_ASSERT_NO_RETURN(! branch_get_root_path(branch)
- || svn_relpath_skip_ancestor(
- branch_get_root_path(branch), path));
-
- if (! eid_p)
- return -1;
- return *eid_p;
-}
-
-/* Return the repos-relpath for element EID of BRANCH, or NULL if EID
- * is not currently present in BRANCH.
- *
- * EID MUST be a valid EID belonging to BRANCH's family, but the element
- * need not be present in any branch.
- */
-static const char *
-branch_get_path_by_eid(const svn_branch_instance_t *branch,
- int eid)
-{
- const char *path = apr_hash_get(branch->eid_to_path, &eid, sizeof(eid));
-
- SVN_ERR_ASSERT_NO_RETURN(eid >= branch->definition->family->first_eid
- && eid < branch->definition->family->next_eid);
-
- return path;
-}
-
-/* Return the root repos-relpath of BRANCH. This is always available. */
-static const char *
-branch_get_root_path(const svn_branch_instance_t *branch)
-{
- return branch_get_path_by_eid(branch, branch->definition->root_eid);
-}
-
-/* */
-static svn_boolean_t
-branch_is_root_path(const svn_branch_instance_t *branch,
- const char *rrpath)
-{
- return branch_get_eid_by_path(branch, rrpath) == branch->definition->root_eid;
-}
-
-/* In BRANCH, update the path mappings to reflect a delete of a subtree
- * at FROM_PATH.
- *
- * FROM_PATH MUST be an existing path in BRANCH, and may be the root path
- * of BRANCH.
- *
- * If INCLUDE_SELF is true, include the element at FROM_PATH, otherwise
- * only act on children (recursively) of FROM_PATH.
- */
-static svn_error_t *
-branch_mappings_delete(svn_branch_instance_t *branch,
- const char *from_path,
- svn_boolean_t include_self,
- apr_pool_t *scratch_pool)
-{
- apr_hash_index_t *hi;
-
- for (hi = apr_hash_first(scratch_pool, branch->eid_to_path);
- hi; hi = apr_hash_next(hi))
- {
- const int *eid_p = apr_hash_this_key(hi);
- const char *this_path = apr_hash_this_val(hi);
- const char *remainder = svn_relpath_skip_ancestor(from_path, this_path);
-
- if (remainder && (include_self || remainder[0]))
- {
- branch_mapping_unset_by_eid(branch, *eid_p);
- }
- }
-
- return SVN_NO_ERROR;
-}
-
-/* In BRANCH, update the path mappings to reflect a move of a subtree
- * from FROM_PATH to TO_PATH.
- *
- * FROM_PATH MUST be an existing path in BRANCH, and may be the root path
- * of BRANCH.
- *
- * TO_PATH MUST be a path in TO_BRANCH at which nothing currently exists.
- */
-static svn_error_t *
-branch_mappings_move(svn_branch_instance_t *branch,
- const char *from_path,
- const char *to_path,
- apr_pool_t *scratch_pool)
-{
- apr_hash_index_t *hi;
-
- SVN_ERR_ASSERT(branch_get_eid_by_path(branch, from_path) >= 0);
- SVN_ERR_ASSERT(branch_get_eid_by_path(branch, to_path) == -1);
-
- for (hi = apr_hash_first(scratch_pool, branch->eid_to_path);
- hi; hi = apr_hash_next(hi))
- {
- const int *eid_p = apr_hash_this_key(hi);
- const char *this_from_path = apr_hash_this_val(hi);
- const char *remainder = svn_relpath_skip_ancestor(from_path, this_from_path);
-
- if (remainder)
- {
- const char *this_to_path = svn_relpath_join(to_path, remainder,
- scratch_pool);
-
- branch_mapping_unset_by_eid(branch, *eid_p);
- branch_mapping_set(branch, *eid_p, this_to_path);
- }
- }
-
- return SVN_NO_ERROR;
-}
-
-static int
-family_add_new_element(svn_branch_family_t *family);
-
-/* In TO_BRANCH, assign new EIDs and path mappings to reflect the copying
- * of a subtree from FROM_BRANCH:FROM_PATH to TO_BRANCH:TO_PATH. Assign
- * a new EID in TO_BRANCH's family for each copied element.
- *
- * FROM_BRANCH and TO_BRANCH may be the same or different branch instances
- * in the same or different branch families.
- *
- * FROM_PATH MUST be an existing path in FROM_BRANCH, and may be the
- * root path of FROM_BRANCH.
- *
- * TO_PATH MUST be a path in TO_BRANCH at which nothing currently exists
- * if INCLUDE_SELF, or an existing path if not INCLUDE_SELF.
- *
- * If INCLUDE_SELF is true, include the element at FROM_PATH, otherwise
- * only act on children (recursively) of FROM_PATH.
- */
-static svn_error_t *
-branch_mappings_copy(svn_branch_instance_t *from_branch,
- const char *from_path,
- svn_branch_instance_t *to_branch,
- const char *to_path,
- svn_boolean_t include_self,
- apr_pool_t *scratch_pool)
-{
- apr_hash_index_t *hi;
-
- SVN_ERR_ASSERT(branch_get_eid_by_path(from_branch, from_path) >= 0);
- SVN_ERR_ASSERT((branch_get_eid_by_path(to_branch, to_path) >= 0) == (! include_self));
-
- for (hi = apr_hash_first(scratch_pool, from_branch->eid_to_path);
- hi; hi = apr_hash_next(hi))
- {
- const char *this_from_path = apr_hash_this_val(hi);
- const char *remainder = svn_relpath_skip_ancestor(from_path, this_from_path);
-
- if (remainder && (include_self || remainder[0]))
- {
- const char *this_to_path = svn_relpath_join(to_path, remainder,
- scratch_pool);
- int new_eid = family_add_new_element(to_branch->definition->family);
-
- branch_mapping_set(to_branch, new_eid, this_to_path);
- }
- }
-
- return SVN_NO_ERROR;
-}
-
-/* In TO_BRANCH, update the path mappings to reflect a branching of a
- * subtree from FROM_BRANCH:FROM_PATH to TO_BRANCH:TO_PATH.
- *
- * FROM_BRANCH and TO_BRANCH must be different branch instances in the
- * same branch family.
- *
- * FROM_PATH MUST be an existing path in FROM_BRANCH, and may be the
- * root path of FROM_BRANCH.
- *
- * TO_PATH MUST be a path in TO_BRANCH at which nothing currently exists
- * if INCLUDE_SELF, or an existing path if not INCLUDE_SELF.
- *
- * If INCLUDE_SELF is true, include the element at FROM_PATH, otherwise
- * only act on children (recursively) of FROM_PATH.
- */
-static svn_error_t *
-branch_mappings_branch(svn_branch_instance_t *from_branch,
- const char *from_path,
- svn_branch_instance_t *to_branch,
- const char *to_path,
- svn_boolean_t include_self,
- apr_pool_t *scratch_pool)
-{
- apr_hash_index_t *hi;
-
- SVN_ERR_ASSERT(from_branch->definition->family == to_branch->definition->family);
- SVN_ERR_ASSERT(branch_get_eid_by_path(from_branch, from_path) >= 0);
- SVN_ERR_ASSERT((branch_get_eid_by_path(to_branch, to_path) >= 0) == (! include_self));
-
- for (hi = apr_hash_first(scratch_pool, from_branch->eid_to_path);
- hi; hi = apr_hash_next(hi))
- {
- const int *eid_p = apr_hash_this_key(hi);
- const char *this_from_path = apr_hash_this_val(hi);
- const char *remainder = svn_relpath_skip_ancestor(from_path, this_from_path);
-
- if (remainder && (include_self || remainder[0]))
- {
- const char *this_to_path = svn_relpath_join(to_path, remainder,
- scratch_pool);
-
- branch_mapping_set(to_branch, *eid_p, this_to_path);
- }
- }
-
- return SVN_NO_ERROR;
-}
-
-/* Return an array of pointers to the branch instances that are sub-branches
- * of BRANCH. */
-static apr_array_header_t *
-branch_get_sub_branches(const svn_branch_instance_t *branch,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- const char *branch_root_rrpath = branch_get_root_path(branch);
- apr_array_header_t *sub_branches = apr_array_make(result_pool, 0, sizeof(void *));
- int i;
-
- for (i = 0; i < branch->definition->family->sub_families->nelts; i++)
- {
- svn_branch_family_t *family
- = APR_ARRAY_IDX(branch->definition->family->sub_families, i, void *);
- int b;
-
- for (b = 0; b < family->branch_instances->nelts; b++)
- {
- svn_branch_instance_t *sub_branch
- = APR_ARRAY_IDX(family->branch_instances, b, void *);
- const char *sub_branch_root_rrpath = branch_get_root_path(sub_branch);
-
- if (svn_relpath_skip_ancestor(branch_root_rrpath, sub_branch_root_rrpath))
- {
- APR_ARRAY_PUSH(sub_branches, void *) = sub_branch;
- }
- }
- }
- return sub_branches;
-}
-
-/* Delete the branch instance object BRANCH and any nested branch instances.
- */
-static svn_error_t *
-branch_instance_delete_r(svn_branch_instance_t *branch,
- apr_pool_t *scratch_pool)
-{
- apr_array_header_t *subbranches
- = branch_get_sub_branches(branch, scratch_pool, scratch_pool);
- int i;
-
- /* Delete nested branch instances, recursively */
- for (i = 0; i < subbranches->nelts; i++)
- {
- svn_branch_instance_t *b = APR_ARRAY_IDX(subbranches, i, void *);
-
- branch_instance_delete_r(b, scratch_pool);
- }
-
- /* Remove the record of this branch instance */
- for (i = 0; i < branch->definition->family->branch_instances->nelts; i++)
- {
- svn_branch_instance_t *b = APR_ARRAY_IDX(subbranches, i, void *);
-
- if (b == branch)
- {
- svn_sort__array_delete(branch->definition->family->branch_instances,
- i, 1);
- }
- }
-
- return SVN_NO_ERROR;
-}
-
-/* Copy the branch instance object BRANCH and any nested branch instances.
- *
- * ### Currently, the mapping will be empty.
- * TODO: Duplicate the mapping, based on a new path.
- */
-static svn_error_t *
-branch_instance_copy_r(svn_branch_instance_t **new_branch_p,
- svn_branch_instance_t *branch,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- apr_array_header_t *subbranches
- = branch_get_sub_branches(branch, scratch_pool, scratch_pool);
- int i;
- svn_branch_instance_t *new_branch;
-
- /* Duplicate this branch instance */
- new_branch = svn_branch_instance_create(branch->definition, branch->rev_root,
- result_pool);
- /* ### branch_mapping_dup(new_branch, branch) */
-
- /* Record this new branch instance in its family */
- APR_ARRAY_PUSH(branch->definition->family->branch_instances, void *)
- = new_branch;
-
- /* Copy nested branch instances, recursively */
- for (i = 0; i < subbranches->nelts; i++)
- {
- svn_branch_instance_t *b = APR_ARRAY_IDX(subbranches, i, void *);
-
- branch_instance_copy_r(&b, b, result_pool, scratch_pool);
- }
-
- *new_branch_p = new_branch;
- return SVN_NO_ERROR;
-}
-
-/* Create a new, empty family in OUTER_FAMILY.
- */
-static svn_branch_family_t *
-family_add_new_subfamily(svn_branch_family_t *outer_family)
-{
- svn_branch_repos_t *repos = outer_family->repos;
- int fid = repos->next_fid++;
- svn_branch_family_t *family
- = svn_branch_family_create(repos, fid,
- fid * 10, fid * 10,
- fid * 100, fid * 100,
- outer_family->pool);
-
- /* Register the family */
- APR_ARRAY_PUSH(outer_family->sub_families, void *) = family;
-
- return family;
-}
-
-/* Create a new branch definition in FAMILY, with root element ROOT_EID.
- */
-static svn_branch_definition_t *
-family_add_new_branch_definition(svn_branch_family_t *family,
- int root_eid)
-{
- int bid = family->next_bid++;
- svn_branch_definition_t *branch_definition
- = svn_branch_definition_create(family, bid, root_eid, family->pool);
-
- /* The root EID must be an existing EID. */
- SVN_ERR_ASSERT_NO_RETURN(root_eid >= family->first_eid
- /*&& root_eid < family->next_eid*/);
- /* ROOT_RRPATH must not be within another branch of the family. */
-
- /* Register the branch */
- APR_ARRAY_PUSH(family->branch_definitions, void *) = branch_definition;
-
- return branch_definition;
-}
-
-/* Create a new branch instance of BRANCH_DEFINITION, with no path
- * mappings except for its root element at ROOT_RRPATH.
- */
-static svn_branch_instance_t *
-branch_add_new_branch_instance(svn_branch_definition_t *branch_definition,
- svn_branch_revision_root_t *rev_root,
- const char *root_rrpath)
-{
- svn_branch_family_t *family = branch_definition->family;
- svn_branch_instance_t *branch_instance
- = svn_branch_instance_create(branch_definition, rev_root, family->pool);
-
- APR_ARRAY_PUSH(family->branch_instances, void *) = branch_instance;
-
- /* Initialize the root element */
- branch_mapping_update(branch_instance, branch_definition->root_eid,
- root_rrpath);
- return branch_instance;
-}
-
-/* Assign a new element id in FAMILY.
- */
-static int
-family_add_new_element(svn_branch_family_t *family)
-{
- int eid = family->next_eid++;
-
- return eid;
-}
-
-/* Find the existing family with id FID in FAMILY (recursively, including
- * FAMILY itself). Assume FID is unique among all families.
- *
- * Return NULL if not found.
- */
-static svn_branch_family_t *
-family_get_subfamily_by_id(svn_branch_family_t *family,
- int fid)
-{
- int i;
-
- SVN_ERR_ASSERT_NO_RETURN(fid >= 0 && fid < family->repos->next_fid);
-
- if (family->fid == fid)
- return family;
-
- for (i = 0; i < family->sub_families->nelts; i++)
- {
- svn_branch_family_t *f
- = APR_ARRAY_IDX(family->sub_families, i, svn_branch_family_t *);
-
- f = family_get_subfamily_by_id(f, fid);
- if (f)
- return f;
- }
-
- return NULL;
-}
-
-/* The default branching metadata for a new repository. */
-static const char *default_repos_info
- = "r: fids 0 1 root-fid 0\n"
- "f0: bids 0 1 eids 0 1 parent-fid 0\n"
- "f0b0: root-eid 0\n"
- "f0b0e0: \n";
-
-/* Create a new branch *NEW_BRANCH that belongs to FAMILY, initialized
- * with info parsed from STREAM, allocated in RESULT_POOL.
- */
-static svn_error_t *
-parse_branch_info(svn_branch_instance_t **new_branch,
- svn_branch_family_t *family,
- svn_branch_revision_root_t *rev_root,
- svn_stream_t *stream,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- svn_branch_definition_t *branch_definition;
- svn_branch_instance_t *branch_instance;
- svn_stringbuf_t *line;
- svn_boolean_t eof;
- int n;
- int fid, bid, root_eid;
- int eid;
-
- SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, scratch_pool));
- SVN_ERR_ASSERT(! eof);
- n = sscanf(line->data, "f%db%d: root-eid %d\n",
- &fid, &bid, &root_eid);
- SVN_ERR_ASSERT(n == 3);
-
- SVN_ERR_ASSERT(fid == family->fid);
- branch_definition = svn_branch_definition_create(family, bid, root_eid,
- result_pool);
- branch_instance = svn_branch_instance_create(branch_definition, rev_root,
- result_pool);
-
- for (eid = family->first_eid; eid < family->next_eid; eid++)
- {
- int this_fid, this_bid, this_eid;
- int this_path_start_pos;
- char *this_path;
-
- SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, scratch_pool));
- SVN_ERR_ASSERT(! eof);
- n = sscanf(line->data, "f%db%de%d: %n\n",
- &this_fid, &this_bid, &this_eid, &this_path_start_pos);
- SVN_ERR_ASSERT(n == 3);
- this_path = line->data + this_path_start_pos;
- if (strcmp(this_path, "(null)") != 0)
- {
- branch_mapping_update(branch_instance, this_eid, this_path);
- }
- }
-
- *new_branch = branch_instance;
- return SVN_NO_ERROR;
-}
-
-/* Create a new family *NEW_FAMILY as a sub-family of FAMILY, initialized
- * with info parsed from STREAM, allocated in RESULT_POOL.
- */
-static svn_error_t *
-parse_family_info(svn_branch_family_t **new_family,
- int *parent_fid,
- svn_branch_repos_t *repos,
- svn_stream_t *stream,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- svn_stringbuf_t *line;
- svn_boolean_t eof;
- int n;
- int fid, first_bid, next_bid, first_eid, next_eid;
-
- SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, scratch_pool));
- SVN_ERR_ASSERT(!eof);
- n = sscanf(line->data, "f%d: bids %d %d eids %d %d parent-fid %d\n",
- &fid,
- &first_bid, &next_bid, &first_eid, &next_eid,
- parent_fid);
- SVN_ERR_ASSERT(n == 6);
-
- *new_family = svn_branch_family_create(repos, fid,
- first_bid, next_bid,
- first_eid, next_eid,
- result_pool);
-
- return SVN_NO_ERROR;
-}
-
-/* Create a new revision-root object *REV_ROOT_P, initialized with info
- * parsed from STREAM, allocated in RESULT_POOL.
- */
-static svn_error_t *
-parse_revision_info(svn_branch_revision_root_t **rev_root_p,
- int *next_fid_p,
- svn_branch_repos_t *repos,
- svn_stream_t *stream,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- svn_branch_revision_root_t *rev_root = NULL;
- int root_fid;
- svn_stringbuf_t *line;
- svn_boolean_t eof;
- int n, i;
- svn_branch_family_t *root_family = NULL;
-
- SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, scratch_pool));
- SVN_ERR_ASSERT(! eof);
- n = sscanf(line->data, "r: fids %*d %d root-fid %d",
- /* 0, */ next_fid_p, &root_fid);
- SVN_ERR_ASSERT(n == 2);
-
- /* parse the families */
- for (i = 0; i < *next_fid_p; i++)
- {
- svn_branch_family_t *family;
- int bid, parent_fid;
-
- SVN_ERR(parse_family_info(&family, &parent_fid, repos, stream,
- result_pool, scratch_pool));
-
- if (family->fid == root_fid)
- {
- rev_root = svn_branch_revision_root_create(repos, NULL /*root_branch*/,
- result_pool);
- root_family = family;
- }
- else
- {
- svn_branch_family_t *parent_family
- = family_get_subfamily_by_id(root_family, parent_fid);
-
- SVN_ERR_ASSERT(parent_family);
- APR_ARRAY_PUSH(parent_family->sub_families, void *) = family;
- }
-
- /* parse the branches */
- for (bid = family->first_bid; bid < family->next_bid; ++bid)
- {
- svn_branch_instance_t *branch;
-
- SVN_ERR(parse_branch_info(&branch, family, rev_root, stream,
- family->pool, scratch_pool));
- APR_ARRAY_PUSH(family->branch_instances, void *) = branch;
- if (family->fid == root_fid)
- {
- branch->rev_root->root_branch = branch;
- }
- }
- }
-
- *rev_root_p = rev_root;
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-write_per_revision_info(svn_stream_t *stream,
- svn_branch_revision_root_t *rev_root,
- int next_fid,
- apr_pool_t *scratch_pool);
-
-/* Create a new revision-root object and read the move-tracking /
- * branch-tracking metadata from the repository into it.
- */
-static svn_error_t *
-fetch_per_revision_info(svn_branch_revision_root_t **rev_root_p,
- int *next_fid_p,
- svn_branch_repos_t *repos,
- svn_ra_session_t *ra_session,
- svn_revnum_t revision,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- svn_string_t *value;
- svn_stream_t *stream;
- svn_branch_revision_root_t *rev_root;
-
- /* Read initial state from repository */
- SVN_ERR(svn_ra_rev_prop(ra_session, revision, "svn-br-info", &value,
- scratch_pool));
- if (! value && revision == 0)
- {
- value = svn_string_create(default_repos_info, scratch_pool);
- SVN_DBG(("fetch_per_revision_info(r%ld): LOADED DEFAULT INFO:\n%s",
- revision, value->data));
- SVN_ERR(svn_ra_change_rev_prop2(ra_session, revision, "svn-br-info",
- NULL, value, scratch_pool));
- }
- SVN_ERR_ASSERT(value);
- stream = svn_stream_from_string(value, scratch_pool);
-
- SVN_ERR(parse_revision_info(&rev_root, next_fid_p, repos, stream,
- result_pool, scratch_pool));
-
- /* Self-test: writing out the info should produce exactly the same string. */
- {
- svn_stringbuf_t *buf = svn_stringbuf_create_empty(scratch_pool);
-
- stream = svn_stream_from_stringbuf(buf, scratch_pool);
- SVN_ERR(write_per_revision_info(stream, rev_root, *next_fid_p,
- scratch_pool));
- SVN_ERR(svn_stream_close(stream));
-
- SVN_ERR_ASSERT(svn_string_compare(value,
- svn_stringbuf__morph_into_string(buf)));
- }
-
- *rev_root_p = rev_root;
- return SVN_NO_ERROR;
-}
-
-/* Create a new repository object and read the move-tracking /
- * branch-tracking metadata from the repository into it.
- */
-static svn_error_t *
-fetch_repos_info(svn_branch_repos_t **repos_p,
- svn_ra_session_t *ra_session,
- svn_revnum_t base_revision,
- svn_editor3_t *editor,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- svn_branch_repos_t *repos
- = svn_branch_repos_create(ra_session, editor, result_pool);
- svn_revnum_t r;
-
- if (base_revision == SVN_INVALID_REVNUM)
- {
- SVN_ERR(svn_ra_get_latest_revnum(ra_session, &base_revision,
- scratch_pool));
- }
-
- repos->next_fid = 0;
- for (r = 0; r <= base_revision; r++)
- {
- svn_branch_revision_root_t *rev_root;
- int next_fid;
-
- SVN_ERR(fetch_per_revision_info(&rev_root, &next_fid,
- repos, ra_session, r,
- result_pool, scratch_pool));
- APR_ARRAY_PUSH(repos->rev_roots, void *) = rev_root;
- repos->next_fid = MAX(repos->next_fid, next_fid);
- }
-
- *repos_p = repos;
- return SVN_NO_ERROR;
-}
-
-/* Return a mutable state for the youngest revision in REPOS.
- */
-static svn_error_t *
-get_mutable_state(svn_branch_revision_root_t **rev_root_p,
- svn_branch_repos_t *repos,
- svn_revnum_t base_revision,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- int next_fid;
-
- SVN_ERR(fetch_per_revision_info(rev_root_p, &next_fid,
- repos, repos->ra_session, base_revision,
- result_pool, scratch_pool));
- return SVN_NO_ERROR;
-}
-
-/* Write to STREAM a parseable representation of BRANCH.
- */
-static svn_error_t *
-write_branch_info(svn_stream_t *stream,
- svn_branch_instance_t *branch,
- apr_pool_t *scratch_pool)
-{
- svn_branch_family_t *family = branch->definition->family;
- int eid;
-
- SVN_ERR(svn_stream_printf(stream, scratch_pool,
- "f%db%d: root-eid %d\n",
- family->fid, branch->definition->bid,
- branch->definition->root_eid));
- for (eid = family->first_eid; eid < family->next_eid; eid++)
- {
- const char *path = apr_hash_get(branch->eid_to_path, &eid, sizeof (eid));
- if (path)
- {
- SVN_ERR(svn_stream_printf(stream, scratch_pool,
- "f%db%de%d: %s\n",
- family->fid, branch->definition->bid, eid,
- path));
- }
- else
- {
- /* ### TODO: instead of writing this out, write nothing; but the
- parser can't currently handle that. */
- SVN_ERR(svn_stream_printf(stream, scratch_pool,
- "f%db%de%d: %s\n",
- family->fid, branch->definition->bid, eid,
- "(null)"));
- }
- }
- return SVN_NO_ERROR;
-}
-
-/* Write to STREAM a parseable representation of FAMILY whose parent
- * family id is PARENT_FID. Recursively write all sub-families.
- */
-static svn_error_t *
-write_family_info(svn_stream_t *stream,
- svn_branch_family_t *family,
- int parent_fid,
- apr_pool_t *scratch_pool)
-{
- int i;
-
- SVN_ERR(svn_stream_printf(stream, scratch_pool,
- "f%d: bids %d %d eids %d %d parent-fid %d\n",
- family->fid,
- family->first_bid, family->next_bid,
- family->first_eid, family->next_eid,
- parent_fid));
-
- for (i = 0; i < family->branch_instances->nelts; i++)
- {
- svn_branch_instance_t *branch
- = APR_ARRAY_IDX(family->branch_instances, i, void *);
-
- SVN_ERR(write_branch_info(stream, branch, scratch_pool));
- }
-
- if (family->sub_families)
- {
- for (i = 0; i < family->sub_families->nelts; i++)
- {
- svn_branch_family_t *f
- = APR_ARRAY_IDX(family->sub_families, i, void *);
-
- SVN_ERR(write_family_info(stream, f, family->fid, scratch_pool));
- }
- }
- return SVN_NO_ERROR;
-}
-
-/* Write to STREAM a parseable representation of REV_ROOT.
- */
-static svn_error_t *
-write_per_revision_info(svn_stream_t *stream,
- svn_branch_revision_root_t *rev_root,
- int next_fid,
- apr_pool_t *scratch_pool)
-{
- SVN_ERR(svn_stream_printf(stream, scratch_pool,
- "r: fids %d %d root-fid %d\n",
- 0, next_fid,
- rev_root->root_branch->definition->family->fid));
-
- SVN_ERR(write_family_info(stream, rev_root->root_branch->definition->family,
- 0 /*parent_fid*/, scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
-/* Store the move-tracking / branch-tracking metadata from REV_ROOT into the
- * repository.
- */
-static svn_error_t *
-store_repos_info(svn_branch_revision_root_t *rev_root,
- apr_pool_t *scratch_pool)
-{
- svn_branch_repos_t *repos = rev_root->repos;
- svn_stringbuf_t *buf = svn_stringbuf_create_empty(scratch_pool);
- svn_stream_t *stream = svn_stream_from_stringbuf(buf, scratch_pool);
- svn_revnum_t youngest_rev;
-
- SVN_ERR(write_per_revision_info(stream, rev_root, repos->next_fid,
- scratch_pool));
-
- SVN_ERR(svn_stream_close(stream));
- /*SVN_DBG(("store_repos_info: %s", buf->data));*/
- SVN_ERR(svn_ra_get_latest_revnum(repos->ra_session, &youngest_rev,
- scratch_pool));
- SVN_ERR(svn_ra_change_rev_prop2(repos->ra_session, youngest_rev, "svn-br-info",
- NULL, svn_stringbuf__morph_into_string(buf),
- scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
-/* Set *INNER_BRANCH_P and *INNER_EID_P to the branch and element located
- * at LOC.
- *
- * LOC should be a member of an immediate sub-branch of OUTER_BRANCH,
- * including the root of such a sub-branch, but not the root of a
- * sub-sub-branch.
- *
- * If not found, set *INNER_BRANCH_P and *INNER_EID_P respectively to NULL
- * and -1.
- */
-static svn_error_t *
-branch_find_subbranch_element_by_location(svn_branch_instance_t **inner_branch_p,
- int *inner_eid_p,
- svn_branch_instance_t *outer_branch,
- svn_editor3_txn_path_t loc,
- apr_pool_t *scratch_pool)
-{
- const char *outer_branch_root_rrpath = branch_get_root_path(outer_branch);
- const char *loc_rrpath = txn_path_to_relpath(loc, scratch_pool);
- apr_array_header_t *branch_instances;
- int i;
-
- if (! svn_relpath_skip_ancestor(outer_branch_root_rrpath, loc_rrpath))
- {
- return svn_error_createf(SVN_ERR_BRANCHING, NULL,
- _("location %s is not within branch %d (root path '%s')"),
- loc_rrpath, outer_branch->definition->bid,
- outer_branch_root_rrpath);
- }
-
- branch_instances = branch_get_sub_branches(outer_branch,
- scratch_pool, scratch_pool);
- /* Find the sub-branch that encloses LOC_RRPATH */
- for (i = 0; i < branch_instances->nelts; i++)
- {
- svn_branch_instance_t *sub_branch
- = APR_ARRAY_IDX(branch_instances, i, void *);
- const char *sub_branch_root_path = branch_get_root_path(sub_branch);
-
- if (svn_relpath_skip_ancestor(sub_branch_root_path, loc_rrpath))
- {
- /* The path we're looking for is path-wise in this sub-branch. */
- /* ### TODO: Check it's not a sub-sub-branch. */
- *inner_branch_p = sub_branch;
- *inner_eid_p = branch_get_eid_by_path(sub_branch, loc_rrpath);
- return SVN_NO_ERROR;
- }
- }
-
- *inner_branch_p = NULL;
- *inner_eid_p = -1;
- return SVN_NO_ERROR;
-}
-
-/* Find the (deepest) branch of which the path RRPATH is either the root
- * path or a normal, non-sub-branch path. An element need not exist at
- * RRPATH.
- *
- * Set *BRANCH_P to the deepest branch within ROOT_BRANCH (recursively,
- * including itself) that contains the path RRPATH.
- *
- * If EID_P is not null then set *EID_P to the element id of RRPATH in
- * *BRANCH_P, or to -1 if no element exists at RRPATH in that branch.
- *
- * If RRPATH is not within any branch in ROOT_BRANCH, set *BRANCH_P to
- * NULL and (if EID_P is not null) *EID_P to -1.
- */
-static void
-branch_find_nested_branch_element_by_path(
- svn_branch_instance_t **branch_p,
- int *eid_p,
- svn_branch_instance_t *root_branch,
- const char *rrpath,
- apr_pool_t *scratch_pool)
-{
- const char *branch_root_path = branch_get_root_path(root_branch);
- apr_array_header_t *branch_instances;
- int i;
-
- if (! svn_relpath_skip_ancestor(branch_root_path, rrpath))
- {
- /* The path we're looking for is not (path-wise) in this branch. */
- *branch_p = NULL;
- if (eid_p)
- *eid_p = -1;
- return;
- }
-
- /* The path we're looking for is (path-wise) in this branch. See if it
- is also in a sub-branch (recursively). */
- branch_instances = branch_get_sub_branches(root_branch,
- scratch_pool, scratch_pool);
- for (i = 0; i < branch_instances->nelts; i++)
- {
- svn_branch_instance_t *this_branch
- = APR_ARRAY_IDX(branch_instances, i, void *);
- svn_branch_instance_t *sub_branch;
- int sub_branch_eid;
-
- branch_find_nested_branch_element_by_path(&sub_branch, &sub_branch_eid,
- this_branch, rrpath,
- scratch_pool);
- if (sub_branch)
- {
- *branch_p = sub_branch;
- if (eid_p)
- *eid_p = sub_branch_eid;
- return;
- }
- }
-
- *branch_p = root_branch;
- if (eid_p)
- *eid_p = branch_get_eid_by_path(root_branch, rrpath);
-}
-
-/* Find the deepest branch in REPOS (recursively) of which RRPATH_REV is
- * either the root element or a normal, non-sub-branch element.
- *
- * RRPATH_REV is a repository-relative path with an optional "@REV" suffix.
- *
- * Return the location of the element at RRPATH_REV in that branch, or with
- * EID=-1 if no element exists there.
- *
- * The result will never be NULL.
- */
-static svn_error_t *
-repos_get_el_rev_by_loc(svn_branch_el_rev_id_t **el_rev_p,
- const svn_branch_repos_t *repos,
- const char *rrpath_rev,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- svn_branch_el_rev_id_t *el_rev = apr_palloc(result_pool, sizeof(*el_rev));
- const char *rrpath;
- svn_opt_revision_t rev;
- const svn_branch_revision_root_t *rev_root;
-
- SVN_ERR(svn_opt_parse_path(&rev, &rrpath, rrpath_rev, scratch_pool));
- if (rev.kind == svn_opt_revision_number)
- {
- el_rev->rev = rev.value.number;
- }
- else
- {
- el_rev->rev = repos->rev_roots->nelts - 1;
- }
- rev_root = APR_ARRAY_IDX(repos->rev_roots, el_rev->rev, void *);
- branch_find_nested_branch_element_by_path(&el_rev->branch, &el_rev->eid,
- rev_root->root_branch, rrpath,
- scratch_pool);
-
- /* Any path must at least be within the repository root branch */
- SVN_ERR_ASSERT_NO_RETURN(el_rev->branch);
- *el_rev_p = el_rev;
- return SVN_NO_ERROR;
-}
-
-/* Find the deepest branch in REV_ROOT of which RRPATH is
- * either the root element or a normal, non-sub-branch element.
- * If EID_P is not null, set *EID_P to the EID of RRPATH in that branch.
- *
- * An element need not exist at RRPATH.
- *
- * The result will never be NULL.
- */
-static svn_branch_instance_t *
-revision_get_branch_by_path(int *eid_p,
- svn_branch_revision_root_t *rev_root,
- const char *rrpath,
- apr_pool_t *scratch_pool)
-{
- svn_branch_instance_t *branch;
-
- branch_find_nested_branch_element_by_path(&branch, eid_p,
- rev_root->root_branch, rrpath,
- scratch_pool);
-
- /* Any path must at least be within the repository root branch */
- SVN_ERR_ASSERT_NO_RETURN(branch);
- return branch;
-}
-
-/* */
-static svn_boolean_t
-same_branch(const svn_branch_instance_t *branch1,
- const svn_branch_instance_t *branch2)
-{
- return (branch1 == branch2);
-}
-
-/* If the location LOC is not in the branch BRANCH,
- * throw an error (branch nesting violation).
- */
-static svn_error_t *
-verify_path_in_branch(const svn_branch_instance_t *branch,
- const char *rrpath,
- apr_pool_t *scratch_pool)
-{
- svn_branch_instance_t *target_branch
- = revision_get_branch_by_path(NULL, branch->rev_root, rrpath, scratch_pool);
-
- if (! same_branch(target_branch, branch))
- return svn_error_createf(SVN_ERR_BRANCHING, NULL,
- _("path '%s' is in branch '%s', "
- "not in this branch '%s'"),
- rrpath,
- branch_get_root_path(target_branch),
- branch_get_root_path(branch));
- return SVN_NO_ERROR;
-}
-
-/* If the location LOC is not in the branch BRANCH,
- * throw an error (branch nesting violation).
- */
-static svn_error_t *
-verify_location_in_branch(const svn_branch_instance_t *branch,
- svn_editor3_txn_path_t loc,
- apr_pool_t *scratch_pool)
-{
- svn_branch_repos_t *repos = branch->rev_root->repos;
- const char *rrpath = txn_path_to_relpath(loc, scratch_pool);
- svn_branch_revision_root_t *rev_root;
- svn_branch_instance_t *target_branch;
-
- if (SVN_IS_VALID_REVNUM(loc.peg.rev))
- rev_root = APR_ARRAY_IDX(repos->rev_roots, loc.peg.rev, void *);
- else
- rev_root = branch->rev_root;
- target_branch = revision_get_branch_by_path(NULL, rev_root, rrpath,
- scratch_pool);
-
- if (! same_branch(target_branch, branch))
- return svn_error_createf(SVN_ERR_BRANCHING, NULL,
- _("location '%s' is in branch '%s', "
- "not in this branch '%s'"),
- txn_path_str(loc, scratch_pool),
- branch_get_root_path(target_branch),
- branch_get_root_path(branch));
- return SVN_NO_ERROR;
-}
-
-/* Set *PATHS_P to an array of (const char *) repos-relative paths of
- * all the child elements (recursively) of BRANCH:LOC_RRPATH, excluding
- * itself.
- *
- * LOC_RRPATH must be a path inside BRANCH. If no element of BRANCH
- * exists at LOC_RRPATH, return an empty list.
- */
-static svn_error_t *
-branch_get_subtree_paths(apr_array_header_t **paths_p,
- svn_branch_instance_t *branch,
- const char *loc_rrpath,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- apr_hash_index_t *hi;
-
- SVN_ERR_ASSERT(svn_relpath_skip_ancestor(branch_get_root_path(branch),
- loc_rrpath) != NULL);
-
- *paths_p = apr_array_make(result_pool, 0, sizeof(char *));
- for (hi = apr_hash_first(scratch_pool, branch->eid_to_path);
- hi; hi = apr_hash_next(hi))
- {
- const char *path = apr_hash_this_val(hi);
- const char *remainder = svn_relpath_skip_ancestor(loc_rrpath, path);
-
- if (remainder && remainder[0])
- {
- APR_ARRAY_PUSH(*paths_p, const char *) = path;
- }
- }
- return SVN_NO_ERROR;
-}
-
-/* List all branch instances in FAMILY.
- *
- * If RECURSIVE is true, include branches in nested families.
- */
-static svn_error_t *
-family_list_branch_instances(svn_branch_family_t *family,
- svn_boolean_t recursive,
- apr_pool_t *scratch_pool)
-{
- int b;
-
- printf("family %d (BIDs %d:%d, EIDs %d:%d)\n",
- family->fid,
- family->first_bid, family->next_bid,
- family->first_eid, family->next_eid);
-
- for (b = 0; b < family->branch_instances->nelts; b++)
- {
- svn_branch_instance_t *branch
- = APR_ARRAY_IDX(family->branch_instances, b, svn_branch_instance_t *);
- int eid;
-
- printf(" branch %d (root element %d -> '/%s')\n",
- branch->definition->bid, branch->definition->root_eid,
- branch_get_root_path(branch));
- for (eid = family->first_eid; eid < family->next_eid; eid++)
- {
- const char *rrpath = apr_hash_get(branch->eid_to_path,
- &eid, sizeof(eid));
-
- if (rrpath)
- {
- const char *relpath
- = svn_relpath_skip_ancestor(branch_get_root_path(branch),
- rrpath);
-
- printf(" e%d -> %s\n",
- eid, relpath[0] ? relpath : ".");
- }
- }
- }
-
- if (recursive && family->sub_families)
- {
- int f;
-
- for (f = 0; f < family->sub_families->nelts; f++)
- {
- svn_branch_family_t *sub_family
- = APR_ARRAY_IDX(family->sub_families, f, svn_branch_family_t *);
-
- SVN_ERR(family_list_branch_instances(sub_family, recursive,
- scratch_pool));
- }
- }
-
- return SVN_NO_ERROR;
-}
-
-/* In BRANCH, make a new directory at PARENT_LOC:NEW_NAME. */
-static svn_error_t *
-svn_branch_mkdir(svn_branch_instance_t *branch,
- svn_editor3_txn_path_t parent_loc,
- const char *new_name,
- apr_pool_t *scratch_pool)
-{
- svn_editor3_t *editor = branch->definition->family->repos->editor;
- svn_editor3_txn_path_t loc = txn_path_join(parent_loc, new_name, scratch_pool);
- const char *loc_rrpath = txn_path_to_relpath(loc, scratch_pool);
- int eid;
-
- SVN_ERR(verify_path_in_branch(branch, loc_rrpath, scratch_pool));
-
- eid = family_add_new_element(branch->definition->family);
-
- SVN_ERR(svn_editor3_mk(editor, svn_node_dir, parent_loc, new_name));
- branch_mapping_update(branch, eid, loc_rrpath);
- return SVN_NO_ERROR;
-}
-
-/* Adjust BRANCH and its subbranches (recursively),
- * to reflect deletion of a subtree from FROM_PATH.
- *
- * FROM_PATH MUST be the location of a non-root element of BRANCH.
- * If FROM_PATH is the root of a subbranch and/or contains nested
- * subbranches, also delete them.
- */
-static svn_error_t *
-branch_delete_subtree_r(svn_branch_instance_t *branch,
- const char *from_path,
- apr_pool_t *scratch_pool)
-{
- int eid;
- apr_array_header_t *subbranches;
- int i;
-
- /* FROM_PATH MUST be the location of a non-root element of BRANCH. */
- eid = branch_get_eid_by_path(branch, from_path);
- if (eid < 0)
- return svn_error_createf(SVN_ERR_BRANCHING, NULL,
- _("in branch %d, can't delete '%s': not found"),
- branch->definition->bid, from_path);
- if (eid == branch->definition->root_eid)
- return svn_error_createf(SVN_ERR_BRANCHING, NULL,
- _("in branch %d, can't delete '%s': is root of this branch"),
- branch->definition->bid, from_path);
-
- /* Delete any nested subbranches at or inside FROM_PATH. */
- subbranches = branch_get_sub_branches(branch, scratch_pool, scratch_pool);
- for (i = 0; i < subbranches->nelts; i++)
- {
- svn_branch_instance_t *subbranch
- = APR_ARRAY_IDX(subbranches, i, void *);
- const char *subbranch_root_path = branch_get_root_path(subbranch);
- const char *subbranch_within_from_path
- = svn_relpath_skip_ancestor(from_path, subbranch_root_path);
-
- if (subbranch_within_from_path)
- {
- /* Delete the whole subbranch (recursively) */
- SVN_ERR(branch_instance_delete_r(subbranch, scratch_pool));
- }
- }
-
- /* update the path mappings in this branch */
- SVN_ERR(branch_mappings_delete(branch, from_path, TRUE /*include_self*/,
- scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
-/* Adjust BRANCH and its subbranches (recursively),
- * to reflect a move of a subtree from FROM_PATH to TO_PATH.
- *
- * FROM_PATH must be an existing element of BRANCH. (It may be the root.)
- * If FROM_PATH is the root of a subbranch and/or contains nested
- * subbranches, also move them.
- *
- * TO_PATH must be a non-existing path in an existing parent directory in
- * BRANCH.
- */
-static svn_error_t *
-branch_move_subtree_r(svn_branch_instance_t *branch,
- const char *from_path,
- const char *to_path,
- apr_pool_t *scratch_pool)
-{
- apr_array_header_t *subbranches;
- int i;
-
- /* update the path mappings in this branch */
- SVN_ERR(branch_mappings_move(branch, from_path, to_path, scratch_pool));
-
- /* handle subbranches */
- subbranches = branch_get_sub_branches(branch, scratch_pool, scratch_pool);
- for (i = 0; i < subbranches->nelts; i++)
- {
- svn_branch_instance_t *subbranch
- = APR_ARRAY_IDX(subbranches, i, void *);
- const char *subbranch_root_path = branch_get_root_path(subbranch);
- const char *subbranch_within_from_path
- = svn_relpath_skip_ancestor(from_path, subbranch_root_path);
-
- if (subbranch_within_from_path)
- {
- const char *subbranch_root_to_path
- = svn_relpath_join(to_path, subbranch_within_from_path,
- scratch_pool);
-
- /* Move the whole subbranch (recursively) */
- SVN_ERR(branch_move_subtree_r(subbranch,
- subbranch_root_path,
- subbranch_root_to_path,
- scratch_pool));
- }
- }
- return SVN_NO_ERROR;
-}
-
-/* Adjust OUTER_BRANCH and its subbranches (recursively),
- * to reflect branching a subtree from FROM_BRANCH:FROM_PATH to
- * create a new subbranch of OUTER_BRANCH at TO_PATH.
- *
- * FROM_BRANCH must be an immediate child branch of OUTER_BRANCH.
- *
- * FROM_PATH must be an existing element of FROM_BRANCH. It may be the
- * root of FROM_BRANCH. It must not be the root of a subbranch of
- * FROM_BRANCH.
- *
- * TO_PATH must be a non-existing path in an existing parent directory in
- * OUTER_BRANCH.
- */
-static svn_error_t *
-branch_branch_subtree_r(svn_branch_instance_t **new_branch_p,
- svn_branch_instance_t *outer_branch,
- svn_branch_instance_t *from_branch,
- const char *from_path,
- const char *to_path,
- apr_pool_t *scratch_pool)
-{
- int inner_eid = branch_get_eid_by_path(from_branch, from_path);
- int to_outer_eid;
- svn_branch_definition_t *new_branch_def;
- svn_branch_instance_t *new_branch;
- apr_array_header_t *subbranches;
- int i;
-
- /* FROM_BRANCH must be an immediate child branch of OUTER_BRANCH. */
- /* SVN_ERR_ASSERT(...); */
-
- /* SVN_ERR_ASSERT(...); */
-
- /* assign new eid to root node (outer branch) */
- to_outer_eid = family_add_new_element(outer_branch->definition->family);
- branch_mapping_update(outer_branch, to_outer_eid, to_path);
-
- /* create new inner branch definition & instance */
- /* ### On sub-branches, should not add new branch definition, only instance. */
- new_branch_def
- = family_add_new_branch_definition(from_branch->definition->family,
- inner_eid);
- new_branch = branch_add_new_branch_instance(new_branch_def,
- from_branch->rev_root, to_path);
-
- /* populate new branch instance with path mappings */
- SVN_ERR(branch_mappings_branch(from_branch, from_path,
- new_branch, to_path,
- FALSE /*include_self*/, scratch_pool));
-
- /* branch any subbranches of FROM_BRANCH */
- subbranches = branch_get_sub_branches(from_branch, scratch_pool, scratch_pool);
- for (i = 0; i < subbranches->nelts; i++)
- {
- svn_branch_instance_t *subbranch
- = APR_ARRAY_IDX(subbranches, i, void *);
- const char *subbranch_root_path = branch_get_root_path(subbranch);
- const char *subbranch_within_from_path
- = svn_relpath_skip_ancestor(from_path, subbranch_root_path);
-
- if (subbranch_within_from_path)
- {
- const char *subbranch_root_to_path
- = svn_relpath_join(to_path, subbranch_within_from_path,
- scratch_pool);
-
- /* branch this subbranch into NEW_BRANCH (recursing) */
- SVN_ERR(branch_branch_subtree_r(NULL,
- new_branch,
- subbranch, subbranch_root_path,
- subbranch_root_to_path,
- scratch_pool));
- }
- }
-
- if (new_branch_p)
- *new_branch_p = new_branch;
- return SVN_NO_ERROR;
-}
-
-/* Adjust BRANCH and its subbranches (recursively),
- * to reflect a copy of a subtree from FROM_PATH to TO_PATH.
- *
- * FROM_PATH must be an existing element of BRANCH. (It may be the root.)
- * If FROM_PATH is the root of a subbranch and/or contains nested
- * subbranches, also copy them (by branching).
- *
- * TO_PATH must be a non-existing path in an existing parent directory in
- * BRANCH.
- */
-static svn_error_t *
-branch_copy_subtree_r(svn_branch_instance_t *branch,
- const char *from_path,
- const char *to_path,
- apr_pool_t *scratch_pool)
-{
- apr_array_header_t *subbranches;
- int i;
-
- /* assign new EIDs and update the path mappings in this branch */
- SVN_ERR(branch_mappings_copy(branch, from_path,
- branch, to_path,
- TRUE /*include_self*/, scratch_pool));
-
- /* handle subbranches */
- subbranches = branch_get_sub_branches(branch, scratch_pool, scratch_pool);
- for (i = 0; i < subbranches->nelts; i++)
- {
- svn_branch_instance_t *subbranch
- = APR_ARRAY_IDX(subbranches, i, void *);
- const char *subbranch_root_path = branch_get_root_path(subbranch);
- const char *subbranch_within_from_path
- = svn_relpath_skip_ancestor(from_path, subbranch_root_path);
-
- if (subbranch_within_from_path)
- {
- const char *subbranch_root_to_path
- = svn_relpath_join(to_path, subbranch_within_from_path,
- scratch_pool);
-
- /* branch the whole subbranch (recursively) */
- SVN_ERR(branch_branch_subtree_r(NULL,
- branch,
- subbranch, subbranch_root_path,
- subbranch_root_to_path,
- scratch_pool));
- }
- }
- return SVN_NO_ERROR;
-}
-
-/* Return TRUE iff EL_REV is the root element of its branch. */
-static svn_boolean_t
-svn_branch_el_rev_is_root(const svn_branch_el_rev_id_t *el_rev)
-{
- return el_rev->eid == el_rev->branch->definition->root_eid;
-}
-
-/* Return the repos-relpath for element EL_REV, or NULL if EL_REV
- * is not currently present in BRANCH.
- *
- * EL_REV->EID MUST be a valid EID belonging to BRANCH's family, but the
- * element need not be present in any branch.
- */
-static const char *
-svn_branch_el_rev_get_rrpath(const svn_branch_el_rev_id_t *el_rev)
-{
- /* EL_REV->BRANCH presently points to mappings for the specific rev. */
- return branch_get_path_by_eid(el_rev->branch, el_rev->eid);
-}
-
-/* */
-static int
-svn_branch_el_rev_get_parent_eid(const svn_branch_el_rev_id_t *el_rev,
- apr_pool_t *scratch_pool)
-{
- int parent_eid;
-
- if (svn_branch_el_rev_is_root(el_rev))
- {
- parent_eid = -1;
- }
- else
- {
- const char *rrpath = svn_branch_el_rev_get_rrpath(el_rev);
-
- rrpath = svn_relpath_dirname(rrpath, scratch_pool);
- parent_eid = branch_get_eid_by_path(el_rev->branch, rrpath);
- }
-
- return parent_eid;
-}
-
-/* */
-static const char *
-svn_branch_el_rev_get_basename(const svn_branch_el_rev_id_t *el_rev,
- apr_pool_t *result_pool)
-{
- const char *name;
-
- if (svn_branch_el_rev_is_root(el_rev))
- {
- name = "";
- }
- else
- {
- const char *rrpath = svn_branch_el_rev_get_rrpath(el_rev);
-
- name = svn_relpath_basename(rrpath, result_pool);
- }
-
- return name;
-}
+ SVN_ERR(svn_ra_get_latest_revnum(mtcc->ra_session, &mtcc->head_revision,
+ scratch_pool));
-/* */
-static svn_error_t *
-svn_branch_el_rev_get_node_content(svn_editor3_node_content_t **content_p,
- const svn_branch_el_rev_id_t *el_rev,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- const char *rrpath = svn_branch_el_rev_get_rrpath(el_rev);
- svn_editor3_node_content_t *content = NULL;
- struct fb_baton
- {
- svn_ra_session_t *session;
- } fbb = { el_rev->branch->definition->family->repos->ra_session };
-
- if (rrpath)
- {
- content = apr_palloc(result_pool, sizeof(*content));
- SVN_ERR(svn_ra_fetch(&content->kind,
- &content->props,
- &content->text, NULL,
- &fbb, rrpath, el_rev->rev,
- result_pool, scratch_pool));
- }
+ if (! SVN_IS_VALID_REVNUM(base_revision))
+ mtcc->base_revision = mtcc->head_revision;
+ else if (base_revision > mtcc->head_revision)
+ return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+ _("No such revision %ld (HEAD is %ld)"),
+ base_revision, mtcc->head_revision);
+ else
+ mtcc->base_revision = base_revision;
- *content_p = content;
+ SVN_ERR(svn_ra_get_commit_editor_ev3(mtcc->ra_session, &mtcc->editor,
+ revprops,
+ commit_callback, commit_baton,
+ NULL /*lock_tokens*/, FALSE /*keep_locks*/,
+ result_pool));
+ *mtcc_p = mtcc;
return SVN_NO_ERROR;
}
-/* */
static svn_error_t *
-svn_branch_el_rev_get(svn_branch_el_rev_content_t **content_p,
- const svn_branch_el_rev_id_t *el_rev,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+mtcc_commit(mtcc_t *mtcc,
+ apr_pool_t *scratch_pool)
{
- const char *rrpath = svn_branch_el_rev_get_rrpath(el_rev);
- svn_branch_el_rev_content_t *content = NULL;
+ svn_error_t *err;
- if (rrpath)
+#if 0
+ /* No changes -> no revision. Easy out */
+ if (MTCC_UNMODIFIED(mtcc))
{
- content = apr_palloc(result_pool, sizeof(*content));
- content->parent_eid = svn_branch_el_rev_get_parent_eid(el_rev,
- scratch_pool);
- content->name = svn_branch_el_rev_get_basename(el_rev, result_pool);
- SVN_ERR(svn_branch_el_rev_get_node_content(&content->content, el_rev,
- result_pool, scratch_pool));
+ svn_editor3_abort(mtcc->editor);
+ svn_pool_destroy(mtcc->pool);
+ return SVN_NO_ERROR;
}
+#endif
- *content_p = content;
- return SVN_NO_ERROR;
-}
+#if 0
+ const char *session_url;
-/* */
-static svn_boolean_t
-svn_editor3_node_content_equal(const svn_editor3_node_content_t *content_left,
- const svn_editor3_node_content_t *content_right,
- apr_pool_t *scratch_pool)
-{
- apr_array_header_t *prop_diffs;
+ SVN_ERR(svn_ra_get_session_url(mtcc->ra_session, &session_url, scratch_pool));
- if (content_left->kind != content_right->kind)
- {
- /*SVN_DBG(("node_content_equal: kind %d != %d", content_left->kind, content_right->kind));*/
- return FALSE;
- }
- svn_error_clear(svn_prop_diffs(&prop_diffs,
- content_left->props, content_right->props,
- scratch_pool));
- if (prop_diffs->nelts != 0)
- {
- /*SVN_DBG(("node_content_equal: props different"));*/
- return FALSE;
- }
- switch (content_left->kind)
+ if (mtcc->root_op->kind != OP_OPEN_DIR)
{
- case svn_node_dir:
- break;
- case svn_node_file:
- if (! svn_stringbuf_compare(content_left->text, content_right->text))
- {
- /*SVN_DBG(("node_content_equal: text different"));*/
- return FALSE;
- }
- break;
- case svn_node_symlink:
- if (strcmp(content_left->target, content_right->target) != 0)
+ const char *name;
+
+ svn_uri_split(&session_url, &name, session_url, scratch_pool);
+
+ if (*name)
{
- return FALSE;
+ SVN_ERR(mtcc_reparent(session_url, mtcc, scratch_pool));
+
+ SVN_ERR(svn_ra_reparent(mtcc->ra_session, session_url, scratch_pool));
}
- break;
- default:
- break;
}
+#endif
+
+ err = svn_editor3_complete(mtcc->editor);
- return TRUE;
+ return svn_error_trace(err);
}
-/* Return the relative path to element EID within SUBTREE. */
-static const char *
-element_relpath_in_subtree(const svn_branch_el_rev_id_t *subtree,
- int eid)
+static svn_error_t *
+commit_callback(const svn_commit_info_t *commit_info,
+ void *baton,
+ apr_pool_t *pool)
{
- const char *subtree_path = branch_get_path_by_eid(subtree->branch, subtree->eid);
- const char *element_path = branch_get_path_by_eid(subtree->branch, eid);
- const char *relpath = NULL;
+ SVN_ERR(svn_cmdline_printf(pool, "r%ld committed by %s at %s\n",
+ commit_info->revision,
+ (commit_info->author
+ ? commit_info->author : "(no author)"),
+ commit_info->date));
+ return SVN_NO_ERROR;
+}
- SVN_ERR_ASSERT_NO_RETURN(subtree_path);
+typedef enum action_code_t {
+ ACTION_LIST_BRANCHES,
+ ACTION_LIST_BRANCHES_R,
+ ACTION_BRANCH,
+ ACTION_BRANCHIFY,
+ ACTION_DISSOLVE,
+ ACTION_MERGE,
+ ACTION_MV,
+ ACTION_MKDIR,
+ ACTION_CP,
+ ACTION_RM
+} action_code_t;
- if (element_path)
- relpath = svn_relpath_skip_ancestor(subtree_path, element_path);
+struct action {
+ action_code_t action;
- return relpath;
-}
+ /* revision (copy-from-rev of path[0] for cp) */
+ svn_revnum_t rev;
-/* */
-static svn_boolean_t
-svn_branch_el_rev_content_equal(const svn_branch_el_rev_content_t *content_left,
- const svn_branch_el_rev_content_t *content_right,
- apr_pool_t *scratch_pool)
-{
- if (content_left->parent_eid != content_right->parent_eid)
- {
- /*SVN_DBG(("el_rev_content_equal: parent e%d != e%d", content_left->parent_eid, content_right->parent_eid));*/
- return FALSE;
- }
- if (strcmp(content_left->name, content_right->name) != 0)
- {
- /*SVN_DBG(("el_rev_content_equal: name %s != %s", content_left->name, content_right->name));*/
- return FALSE;
- }
- if (! svn_editor3_node_content_equal(content_left->content,
- content_right->content,
- scratch_pool))
- {
- /*SVN_DBG(("el_rev_content_equal: content differs"));*/
- return FALSE;
- }
+ /* action path[0] path[1] path[2]
+ * ------ ------- ------- -------
+ * list_br path
+ * branch source target
+ * branchify path
+ * dissolve path
+ * merge from to yca@rev
+ * mv source target
+ * mkdir target
+ * cp source target
+ * rm target
+ */
+ const char *path[3];
+};
- return TRUE;
-}
+/* ====================================================================== */
-/* */
-static svn_boolean_t
-branch_element_equal(int eid,
- const svn_branch_el_rev_content_t *content_left,
- const svn_branch_el_rev_content_t *content_right,
- apr_pool_t *scratch_pool)
+/* Find the deepest branch in the repository of which RRPATH_REV is
+ * either the root element or a normal, non-sub-branch element.
+ *
+ * RRPATH_REV is a repository-relative path with an optional "@REV" suffix.
+ * When "@REV" is not present, find in the current txn.
+ *
+ * Return the location of the element at RRPATH_REV in that branch, or with
+ * EID=-1 if no element exists there.
+ *
+ * The result will never be NULL, as every path is within at least the root
+ * branch.
+ */
+static svn_error_t *
+find_el_rev_by_rrpath_rev(svn_branch_el_rev_id_t **el_rev_p,
+ svn_editor3_t *editor,
+ const char *rrpath_rev,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- svn_boolean_t same;
+ const char *rrpath;
+ svn_opt_revision_t rev_spec;
- if (!content_left && !content_right)
- {
- same = TRUE;
- }
- else if (!content_left || !content_right
- || !svn_branch_el_rev_content_equal(content_left, content_right,
- scratch_pool))
+ SVN_ERR(svn_opt_parse_path(&rev_spec, &rrpath, rrpath_rev, scratch_pool));
+ if (rev_spec.kind == svn_opt_revision_number)
{
- /*if (!content_right)
- SVN_DBG((" e%d left-only", eid));
- else if (!content_left)
- SVN_DBG((" e%d right-only", eid));
- else
- SVN_DBG((" e%d different: parent? %+d, name? %+d, content?",
- eid, content_right->parent_eid - content_left->parent_eid,
- strcmp(content_left->name, content_right->name)));*/
- same = FALSE;
+ svn_revnum_t revnum = rev_spec.value.number;
+
+ SVN_ERR(svn_editor3_find_el_rev_by_path_rev(el_rev_p,
+ editor, rrpath, revnum,
+ result_pool, scratch_pool));
}
else
{
- /*SVN_DBG((" e%d same", eid));*/
- same = TRUE;
+ svn_branch_el_rev_id_t *el_rev = apr_palloc(result_pool, sizeof(*el_rev));
+
+ svn_editor3_find_branch_element_by_rrpath(
+ &el_rev->branch, &el_rev->eid,
+ editor, rrpath, scratch_pool);
+ el_rev->rev = SVN_INVALID_REVNUM;
+ *el_rev_p = el_rev;
}
- return same;
+ return SVN_NO_ERROR;
}
-/* Return (left, right) pairs of element content that differ between
- * subtrees LEFT and RIGHT.
+/* List all branch instances in FAMILY.
+ *
+ * If RECURSIVE is true, include branches in nested families.
*/
static svn_error_t *
-branch_subtree_differences(apr_hash_t **h_left_p,
- const svn_branch_el_rev_id_t *left,
- const svn_branch_el_rev_id_t *right,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+family_list_branch_instances(svn_branch_family_t *family,
+ svn_boolean_t recursive,
+ apr_pool_t *scratch_pool)
{
- apr_hash_t *h_left = apr_hash_make(result_pool);
- int first_eid, next_eid;
- int e;
-
- /*SVN_DBG(("branch_element_differences(b%d r%ld, b%d r%ld, e%d)",
- left->branch->definition->bid, left->rev,
- right->branch->definition->bid, right->rev, right->eid));*/
- SVN_ERR_ASSERT(left->branch->definition->family->fid
- == right->branch->definition->family->fid);
+ int b;
- first_eid = left->branch->definition->family->first_eid;
- next_eid = MAX(left->branch->definition->family->next_eid,
- right->branch->definition->family->next_eid);
+ printf("family %d (BIDs %d:%d, EIDs %d:%d)\n",
+ family->fid,
+ family->first_bid, family->next_bid,
+ family->first_eid, family->next_eid);
- for (e = first_eid; e < next_eid; e++)
+ for (b = 0; b < family->branch_instances->nelts; b++)
{
- svn_branch_el_rev_content_t *content_left = NULL;
- svn_branch_el_rev_content_t *content_right = NULL;
+ svn_branch_instance_t *branch
+ = APR_ARRAY_IDX(family->branch_instances, b, svn_branch_instance_t *);
+ int eid;
- if (e < left->branch->definition->family->next_eid
- && element_relpath_in_subtree(left, e))
- {
- svn_branch_el_rev_id_t el_rev = *left;
- el_rev.eid = e;
- SVN_ERR(svn_branch_el_rev_get(&content_left, &el_rev,
- result_pool, scratch_pool));
- }
- if (e < right->branch->definition->family->next_eid
- && element_relpath_in_subtree(right, e))
+ printf(" branch %d (root element %d -> '/%s')\n",
+ branch->sibling_defn->bid, branch->sibling_defn->root_eid,
+ svn_branch_get_root_rrpath(branch));
+ for (eid = family->first_eid; eid < family->next_eid; eid++)
{
- svn_branch_el_rev_id_t el_rev = *right;
- el_rev.eid = e;
- SVN_ERR(svn_branch_el_rev_get(&content_right, &el_rev,
- result_pool, scratch_pool));
+ const char *rrpath = svn_branch_get_rrpath_by_eid(branch, eid,
+ scratch_pool);
+
+ if (rrpath)
+ {
+ const char *relpath
+ = svn_relpath_skip_ancestor(svn_branch_get_root_rrpath(branch),
+ rrpath);
+
+ printf(" e%d -> %s\n",
+ eid, relpath[0] ? relpath : ".");
+ }
}
+ }
+
+ if (recursive && family->sub_families)
+ {
+ int f;
- if (! branch_element_equal(e, content_left, content_right, scratch_pool))
+ for (f = 0; f < family->sub_families->nelts; f++)
{
- int *eid_stored = apr_pmemdup(result_pool, &e, sizeof(e));
- svn_branch_el_rev_content_t **contents
- = apr_palloc(result_pool, 2 * sizeof(void *));
+ svn_branch_family_t *sub_family
+ = APR_ARRAY_IDX(family->sub_families, f, svn_branch_family_t *);
- contents[0] = content_left;
- contents[1] = content_right;
- apr_hash_set(h_left, eid_stored, sizeof(*eid_stored), contents);
+ SVN_ERR(family_list_branch_instances(sub_family, recursive,
+ scratch_pool));
}
}
- *h_left_p = h_left;
return SVN_NO_ERROR;
}
@@ -2413,8 +342,10 @@ element_merge(svn_branch_el_rev_content_
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- svn_boolean_t same1 = branch_element_equal(eid, yca, side1, scratch_pool);
- svn_boolean_t same2 = branch_element_equal(eid, yca, side2, scratch_pool);
+ svn_boolean_t same1 = svn_branch_el_rev_content_equal(eid, yca, side1,
+ scratch_pool);
+ svn_boolean_t same2 = svn_branch_el_rev_content_equal(eid, yca, side2,
+ scratch_pool);
svn_boolean_t conflict = FALSE;
svn_branch_el_rev_content_t *result;
@@ -2498,32 +429,32 @@ element_merge(svn_branch_el_rev_content_
* Merge any sub-branches in the same way, recursively.
*/
static svn_error_t *
-branch_merge_subtree_r(const svn_branch_el_rev_id_t *src,
+branch_merge_subtree_r(svn_editor3_t *editor,
+ const svn_branch_el_rev_id_t *src,
const svn_branch_el_rev_id_t *tgt,
const svn_branch_el_rev_id_t *yca,
apr_pool_t *scratch_pool)
{
- /*svn_editor3_t *editor = src->branch->definition->family->repos->editor;*/
apr_hash_t *diff_yca_src, *diff_yca_tgt;
svn_boolean_t had_conflict = FALSE;
int first_eid, next_eid, eid;
- SVN_ERR_ASSERT(src->branch->definition->family->fid
- == tgt->branch->definition->family->fid);
- SVN_ERR_ASSERT(src->branch->definition->family->fid
- == yca->branch->definition->family->fid);
+ SVN_ERR_ASSERT(src->branch->sibling_defn->family->fid
+ == tgt->branch->sibling_defn->family->fid);
+ SVN_ERR_ASSERT(src->branch->sibling_defn->family->fid
+ == yca->branch->sibling_defn->family->fid);
SVN_ERR_ASSERT(src->eid == tgt->eid);
SVN_ERR_ASSERT(src->eid == yca->eid);
SVN_DBG(("merge src: r%2ld f%d b%2d e%3d",
- src->rev, src->branch->definition->family->fid,
- src->branch->definition->bid, src->eid));
+ src->rev, src->branch->sibling_defn->family->fid,
+ src->branch->sibling_defn->bid, src->eid));
SVN_DBG(("merge tgt: r%2ld f%d b%2d e%3d",
- tgt->rev, tgt->branch->definition->family->fid,
- tgt->branch->definition->bid, tgt->eid));
+ tgt->rev, tgt->branch->sibling_defn->family->fid,
+ tgt->branch->sibling_defn->bid, tgt->eid));
SVN_DBG(("merge yca: r%2ld f%d b%2d e%3d",
- yca->rev, yca->branch->definition->family->fid,
- yca->branch->definition->bid, yca->eid));
+ yca->rev, yca->branch->sibling_defn->family->fid,
+ yca->branch->sibling_defn->bid, yca->eid));
/*
for (eid, diff1) in element_differences(YCA, FROM):
@@ -2534,19 +465,19 @@ branch_merge_subtree_r(const svn_branch_
result := diff1.right
# else no change
*/
- SVN_ERR(branch_subtree_differences(&diff_yca_src,
- yca, src,
- scratch_pool, scratch_pool));
+ SVN_ERR(svn_branch_subtree_differences(&diff_yca_src,
+ editor, yca, src,
+ scratch_pool, scratch_pool));
/* ### We only need to query for YCA:TO differences in elements that are
different in YCA:FROM, but right now we ask for all differences. */
- SVN_ERR(branch_subtree_differences(&diff_yca_tgt,
- yca, tgt,
- scratch_pool, scratch_pool));
-
- first_eid = yca->branch->definition->family->first_eid;
- next_eid = yca->branch->definition->family->next_eid;
- next_eid = MAX(next_eid, src->branch->definition->family->next_eid);
- next_eid = MAX(next_eid, tgt->branch->definition->family->next_eid);
+ SVN_ERR(svn_branch_subtree_differences(&diff_yca_tgt,
+ editor, yca, tgt,
+ scratch_pool, scratch_pool));
+
+ first_eid = yca->branch->sibling_defn->family->first_eid;
+ next_eid = yca->branch->sibling_defn->family->next_eid;
+ next_eid = MAX(next_eid, src->branch->sibling_defn->family->next_eid);
+ next_eid = MAX(next_eid, tgt->branch->sibling_defn->family->next_eid);
for (eid = first_eid; eid < next_eid; eid++)
{
@@ -2558,7 +489,7 @@ branch_merge_subtree_r(const svn_branch_
svn_branch_el_rev_content_t *e_src;
svn_branch_el_rev_content_t *e_tgt;
svn_branch_el_rev_content_t *result;
- svn_boolean_t conflict = FALSE;
+ svn_boolean_t conflict;
/* If an element hasn't changed in the source branch, there is
no need to do anything with it in the target branch. */
@@ -2585,21 +516,29 @@ branch_merge_subtree_r(const svn_branch_
SVN_DBG(("merged: e%d => parent=e%d, name=%s, content=...",
eid, result->parent_eid, result->name));
- /*SVN_ERR(svn_editor3_alter(editor, loc.peg.rev, nbid,
- new_parent_nbid, result->name,
- result->content));*/
+ SVN_ERR(svn_editor3_alter(editor, tgt->rev, eid,
[... 542 lines stripped ...]