Author: julianfoad Date: Tue Apr 21 08:04:57 2015 New Revision: 1675062 URL: http://svn.apache.org/r1675062 Log: On the 'move-tracking-2' branch: Remove 'branch family' and 'branch sibling definition' data types.
The 'family' concept has been redundant since r1673476. The 'sibling' concept, that is the concept of groups of branches having something in common, is not currently used, and so was just confusing. No behavioural change. * subversion/include/private/svn_branch.h (svn_branch_family_t, svn_branch_sibling_t): Delete. (svn_branch_revision_root_t): Move the first and next EID fields to here. (svn_branch_instance_t): Move the root EID field to here. Elsewhere: adjust accordingly. * subversion/libsvn_delta/branch.c Adjust everything accordingly. * subversion/libsvn_delta/compat3e.c Adjust everything accordingly. * subversion/libsvn_delta/editor3e.c Adjust everything accordingly. * subversion/svnmover/svnmover.c Adjust everything accordingly. Modified: subversion/branches/move-tracking-2/subversion/include/private/svn_branch.h subversion/branches/move-tracking-2/subversion/libsvn_delta/branch.c subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c subversion/branches/move-tracking-2/subversion/tests/cmdline/svnmover_tests.py Modified: subversion/branches/move-tracking-2/subversion/include/private/svn_branch.h URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/include/private/svn_branch.h?rev=1675062&r1=1675061&r2=1675062&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/include/private/svn_branch.h (original) +++ subversion/branches/move-tracking-2/subversion/include/private/svn_branch.h Tue Apr 21 08:04:57 2015 @@ -330,20 +330,29 @@ typedef struct svn_branch_subtree_t /* Subtree root EID. (EID must be an existing key in E_MAP.) */ int root_eid; + + /* Subbranches to be included: each subbranch-root element in that is + hierarchically below ROOT_EID in E_MAP should have its subbranch + mapped here. + + A mapping of (int)EID -> (svn_branch_subtree_t *). */ + apr_hash_t *subbranches; } svn_branch_subtree_t; /* Create an empty subtree (no elements populated, not even ROOT_EID). */ svn_branch_subtree_t * -svn_branch_subtree_create(int root_eid, +svn_branch_subtree_create(apr_hash_t *e_map, + int root_eid, apr_pool_t *result_pool); /* Return the subtree of BRANCH rooted at EID. + * Recursive: includes subbranches. */ -svn_branch_subtree_t -svn_branch_map_get_subtree(const svn_branch_instance_t *branch, - int eid, - apr_pool_t *result_pool); +svn_branch_subtree_t * +svn_branch_get_subtree(const svn_branch_instance_t *branch, + int eid, + apr_pool_t *result_pool); /* Declare that the following function requires/implies that in BRANCH's * mapping, for each existing element, the parent also exists. @@ -449,16 +458,17 @@ svn_branch_branch_subtree_r(svn_branch_i const char *new_name, apr_pool_t *scratch_pool); -/* Instantiate a new branch of FROM_BRANCH, selecting only the subtree at - * FROM_EID, at existing branch-root element TO_OUTER_BRANCH:TO_OUTER_EID. +/* Instantiate a new branch of the subtree FROM_SUBTREE, at the + * existing branch-root element TO_OUTER_BRANCH:TO_OUTER_EID. + * Also branch, recursively, the subbranches in FROM_SUBTREE. + * + * TO_OUTER_BRANCH may be the same as or different from FROM_BRANCH. */ svn_error_t * svn_branch_branch_subtree_r2(svn_branch_instance_t **new_branch_p, - svn_branch_instance_t *from_branch, - int from_eid, + svn_branch_subtree_t from_subtree, svn_branch_instance_t *to_outer_branch, svn_branch_eid_t to_outer_eid, - int new_branch_root_eid, apr_pool_t *scratch_pool); /* Create a copy of NEW_SUBTREE in TO_BRANCH, generating a new element Modified: subversion/branches/move-tracking-2/subversion/libsvn_delta/branch.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_delta/branch.c?rev=1675062&r1=1675061&r2=1675062&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_delta/branch.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_delta/branch.c Tue Apr 21 08:04:57 2015 @@ -215,13 +215,16 @@ svn_branch_el_rev_content_equal(const sv */ svn_branch_subtree_t * -svn_branch_subtree_create(int root_eid, +svn_branch_subtree_create(apr_hash_t *e_map, + int root_eid, apr_pool_t *result_pool) { svn_branch_subtree_t *subtree = apr_pcalloc(result_pool, sizeof(*subtree)); - subtree->e_map = apr_hash_make(result_pool); + subtree->e_map = e_map ? apr_hash_copy(result_pool, e_map) + : apr_hash_make(result_pool); subtree->root_eid = root_eid; + subtree->subbranches = apr_hash_make(result_pool); return subtree; } @@ -349,17 +352,28 @@ svn_branch_map_update_as_subbranch_root( branch_map_set(branch, eid, node); } -svn_branch_subtree_t -svn_branch_map_get_subtree(const svn_branch_instance_t *branch, - int eid, - apr_pool_t *result_pool) +svn_branch_subtree_t * +svn_branch_get_subtree(const svn_branch_instance_t *branch, + int eid, + apr_pool_t *result_pool) { - svn_branch_subtree_t new_subtree; + svn_branch_subtree_t *new_subtree; + SVN_ITER_T(svn_branch_instance_t) *bi; SVN_BRANCH_SEQUENCE_POINT(branch); - new_subtree.e_map = apr_hash_copy(result_pool, branch->e_map); - new_subtree.root_eid = eid; + new_subtree = svn_branch_subtree_create(branch->e_map, eid, + result_pool); + + for (SVN_ARRAY_ITER(bi, svn_branch_get_subbranches(branch, eid, + result_pool, result_pool), + result_pool)) + { + svn_branch_subtree_t *this_subtree + = svn_branch_get_subtree(bi->val, bi->val->root_eid, result_pool); + + svn_int_hash_set(new_subtree->subbranches, bi->val->outer_eid, this_subtree); + } return new_subtree; } @@ -568,6 +582,13 @@ svn_branch_map_add_subtree(svn_branch_in apr_hash_index_t *hi; svn_branch_el_rev_content_t *new_root_content; + if (new_subtree.subbranches && apr_hash_count(new_subtree.subbranches)) + { + return svn_error_createf(SVN_ERR_BRANCHING, NULL, + _("Adding or copying a subtree containing " + "subbranches is not implemented")); + } + /* Get a new EID for the root element, if not given. */ if (to_eid == -1) { @@ -598,6 +619,7 @@ svn_branch_map_add_subtree(svn_branch_in as we might not have the node kind in the map.) */ this_subtree.e_map = new_subtree.e_map; this_subtree.root_eid = this_from_eid; + this_subtree.subbranches = apr_hash_make(scratch_pool); SVN_ERR(svn_branch_map_add_subtree(to_branch, -1 /*to_eid*/, to_eid, from_node->name, this_subtree, scratch_pool)); @@ -642,6 +664,23 @@ svn_branch_instantiate_subtree(svn_branc } } + /* branch any subbranches */ + { + SVN_ITER_T(svn_branch_subtree_t) *bi; + + for (SVN_HASH_ITER(bi, scratch_pool, new_subtree.subbranches)) + { + int this_outer_eid = svn_int_hash_this_key(bi->apr_hi); + svn_branch_subtree_t *this_subtree = bi->val; + + /* branch this subbranch into NEW_BRANCH (recursing) */ + SVN_ERR(svn_branch_branch_subtree_r2(NULL, + *this_subtree, + to_branch, this_outer_eid, + bi->iterpool)); + } + } + return SVN_NO_ERROR; } @@ -884,7 +923,7 @@ svn_branch_instance_parse(svn_branch_ins result_pool); /* Read in the structure, leaving the content of each element as null */ - tree = svn_branch_subtree_create(root_eid, scratch_pool); + tree = svn_branch_subtree_create(NULL, root_eid, scratch_pool); for (eid = rev_root->first_eid; eid < rev_root->next_eid; eid++) { int this_eid, this_parent_eid; @@ -1218,6 +1257,7 @@ svn_branch_branch_subtree_r(svn_branch_i const char *new_name, apr_pool_t *scratch_pool) { + svn_branch_subtree_t *from_subtree; int to_outer_eid; /* Source element must exist */ @@ -1230,6 +1270,11 @@ svn_branch_branch_subtree_r(svn_branch_i from_branch, scratch_pool), from_eid); } + /* Fetch the subtree to be branched before creating the new subbranch root + element, as we don't want to recurse (endlessly) into that in the case + where it is an immediate subbranch of FROM_BRANCH. */ + from_subtree = svn_branch_get_subtree(from_branch, from_eid, scratch_pool); + /* assign new eid to root node (outer branch) */ to_outer_eid = svn_branch_allocate_new_eid(to_outer_branch->rev_root); @@ -1237,9 +1282,8 @@ svn_branch_branch_subtree_r(svn_branch_i to_outer_parent_eid, new_name); SVN_ERR(svn_branch_branch_subtree_r2(new_branch_p, - from_branch, from_eid, + *from_subtree, to_outer_branch, to_outer_eid, - from_eid, scratch_pool)); return SVN_NO_ERROR; @@ -1247,46 +1291,22 @@ svn_branch_branch_subtree_r(svn_branch_i svn_error_t * svn_branch_branch_subtree_r2(svn_branch_instance_t **new_branch_p, - svn_branch_instance_t *from_branch, - int from_eid, + svn_branch_subtree_t from_subtree, svn_branch_instance_t *to_outer_branch, svn_branch_eid_t to_outer_eid, - int new_branch_root_eid, apr_pool_t *scratch_pool) { - svn_branch_subtree_t from_subtree - = svn_branch_map_get_subtree(from_branch, from_eid, scratch_pool); svn_branch_instance_t *new_branch; /* create new inner branch instance */ new_branch = svn_branch_add_new_branch_instance(to_outer_branch, to_outer_eid, - new_branch_root_eid, + from_subtree.root_eid, scratch_pool); /* Populate the new branch mapping */ SVN_ERR(svn_branch_instantiate_subtree(new_branch, -1, "", from_subtree, scratch_pool)); - /* branch any subbranches under FROM_BRANCH:FROM_EID */ - { - SVN_ITER_T(svn_branch_instance_t) *bi; - - for (SVN_ARRAY_ITER(bi, svn_branch_get_subbranches( - from_branch, from_subtree.root_eid, - scratch_pool, scratch_pool), scratch_pool)) - { - svn_branch_instance_t *subbranch = bi->val; - - /* branch this subbranch into NEW_BRANCH (recursing) */ - SVN_ERR(svn_branch_branch_subtree_r2(NULL, - subbranch, - subbranch->root_eid, - new_branch, subbranch->outer_eid, - subbranch->root_eid, - bi->iterpool)); - } - } - if (new_branch_p) *new_branch_p = new_branch; return SVN_NO_ERROR; @@ -1318,8 +1338,7 @@ svn_branch_branch_into(svn_branch_instan const char *new_name, apr_pool_t *scratch_pool) { - svn_branch_subtree_t from_subtree - = svn_branch_map_get_subtree(from_branch, from_eid, scratch_pool); + svn_branch_subtree_t *from_subtree; /* Source element must exist */ if (! svn_branch_get_path_by_eid(from_branch, from_eid, scratch_pool)) @@ -1331,29 +1350,11 @@ svn_branch_branch_into(svn_branch_instan from_branch, scratch_pool), from_eid); } + from_subtree = svn_branch_get_subtree(from_branch, from_eid, scratch_pool); + /* Populate the new branch mapping */ SVN_ERR(svn_branch_instantiate_subtree(to_branch, to_parent_eid, new_name, - from_subtree, scratch_pool)); - - /* branch any subbranches under FROM_BRANCH:FROM_EID */ - { - SVN_ITER_T(svn_branch_instance_t) *bi; - - for (SVN_ARRAY_ITER(bi, svn_branch_get_subbranches( - from_branch, from_subtree.root_eid, - scratch_pool, scratch_pool), scratch_pool)) - { - svn_branch_instance_t *subbranch = bi->val; - - /* branch this subbranch into NEW_BRANCH (recursing) */ - SVN_ERR(svn_branch_branch_subtree_r2(NULL, - subbranch, - subbranch->root_eid, - to_branch, subbranch->outer_eid, - subbranch->root_eid, - bi->iterpool)); - } - } + *from_subtree, scratch_pool)); return SVN_NO_ERROR; } @@ -1371,7 +1372,7 @@ svn_branch_copy_subtree_r(const svn_bran /* copy the subtree, assigning new EIDs */ SVN_ERR(svn_branch_map_add_subtree(to_branch, -1 /*to_eid*/, to_parent_eid, to_name, - svn_branch_map_get_subtree( + *svn_branch_get_subtree( from_el_rev->branch, from_el_rev->eid, scratch_pool), scratch_pool)); 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=1675062&r1=1675061&r2=1675062&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c (original) +++ subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c Tue Apr 21 08:04:57 2015 @@ -708,11 +708,14 @@ merge_subbranch(svn_editor3_t *editor, } else if (subbr_src) /* added on source branch */ { - SVN_ERR(svn_branch_branch_subtree_r2( - NULL, - src_subbranch, src_subbranch->root_eid, + svn_branch_subtree_t *from_subtree + = svn_branch_get_subtree(src_subbranch, + src_subbranch->root_eid, + scratch_pool); + + SVN_ERR(svn_branch_branch_subtree_r2(NULL, + *from_subtree, tgt->branch, eid, - src_subbranch->root_eid, scratch_pool)); } else if (subbr_tgt) /* added on target branch */ @@ -886,8 +889,7 @@ branch_merge_subtree_r(svn_editor3_t *ed * * None of SRC, TGT and YCA is a subbranch root element. * - * ### TODO: - * If ... contains nested subbranches, these will also be merged. + * Nested subbranches will also be merged. */ static svn_error_t * svn_branch_merge(svn_editor3_t *editor, @@ -1244,8 +1246,8 @@ move_by_branch_and_delete(svn_editor3_t const char *to_name, apr_pool_t *scratch_pool) { - svn_branch_subtree_t subtree - = svn_branch_map_get_subtree(el_rev->branch, el_rev->eid, scratch_pool); + svn_branch_subtree_t *subtree + = svn_branch_get_subtree(el_rev->branch, el_rev->eid, scratch_pool); /* This is supposed to be used for moving to a *different* branch. In fact, this method would also work for moving within one @@ -1266,10 +1268,9 @@ move_by_branch_and_delete(svn_editor3_t el_rev->branch->outer_branch, el_rev->branch->outer_eid)); } SVN_ERR(svn_branch_instantiate_subtree(to_branch, - to_parent_eid, to_name, subtree, + to_parent_eid, to_name, *subtree, scratch_pool)); - /* ### We need to move nested branches too. */ return SVN_NO_ERROR; } Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/svnmover_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/svnmover_tests.py?rev=1675062&r1=1675061&r2=1675062&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/tests/cmdline/svnmover_tests.py (original) +++ subversion/branches/move-tracking-2/subversion/tests/cmdline/svnmover_tests.py Tue Apr 21 08:04:57 2015 @@ -507,6 +507,38 @@ def merges(sbox): '-U', repo_url, 'merge', 'trunk@5', 'branches/br1', 'trunk@2') + +###################################################################### + +# Expected output of 'svnmover diff' + +def reported_element_del_line(rpath, branch_text=''): + return 'D ' + re.escape(rpath) + branch_text + +def reported_element_add_line(rpath, branch_text=''): + return 'A ' + re.escape(rpath) + branch_text + +def reported_branch_del_line(subbranch_fullpath): + return r'--- deleted branch \^.* at /%s' % (re.escape(subbranch_fullpath),) + +def reported_branch_add_line(subbranch_fullpath): + return r'--- added branch \^.* at /%s' % (re.escape(subbranch_fullpath),) + +def reported_br_params(path1, path2): + """Return (SUBBRANCH_RPATH, SUBBRANCH_FULLPATH). + + Parameters are either (OUTER_BRANCH_FULLPATH, SUBBRANCH_RPATH) or for + a first-level branch (SUBBRANCH_RPATH, None). 'FULLPATH' means relpath + from the repo root; 'RPATH' means relpath from the outer branch. + """ + if path2 is None: + subbranch_rpath = path1 + subbranch_fullpath = path1 + else: + subbranch_rpath = path2 + subbranch_fullpath = path1 + '/' + path2 + return subbranch_rpath, subbranch_fullpath + def reported_br_diff(path1, path2): """Return expected header lines for diff of a branch, or subtree in a branch. @@ -526,18 +558,21 @@ def reported_del(path): def reported_br_del(path1, path2=None): """Return expected lines for deletion of a (sub)branch. - Parameters are either (OUTER_BRANCH_FULLPATH, SUBBRANCH_RPATH) or for - a first-level branch just (SUBBRANCH_RPATH). 'FULLPATH' means relpath - from the repo root; 'RPATH' means relpath from the outer branch. + Params are (SUBBRANCH_RPATH) or (OUTER_BRANCH_FULLPATH, SUBBRANCH_RPATH). """ - if path2 is None: - subbranch_rpath = path1 - subbranch_fullpath = path1 - else: - subbranch_rpath = path2 - subbranch_fullpath = path1 + '/' + path2 - return ['D ' + re.escape(subbranch_rpath) + r' \(branch \^\..*\)', - r'--- deleted branch \^.* at /%s' % (re.escape(subbranch_fullpath),)] + subbranch_rpath, subbranch_fullpath = reported_br_params(path1, path2) + return [reported_element_del_line(subbranch_rpath, r' \(branch \^\..*\)'), + reported_branch_del_line(subbranch_fullpath)] + +def reported_br_nested_del(path1, path2=None): + """Return expected lines for deletion of a subbranch that is nested inside + an outer branch that is also deleted: there is no accompanying 'deleted + element' line. + + Params are (SUBBRANCH_RPATH) or (OUTER_BRANCH_FULLPATH, SUBBRANCH_RPATH). + """ + subbranch_rpath, subbranch_fullpath = reported_br_params(path1, path2) + return [reported_branch_del_line(subbranch_fullpath)] def reported_add(path): """Return expected lines for addition of an element. @@ -549,16 +584,21 @@ def reported_add(path): def reported_br_add(path1, path2=None): """Return expected lines for addition of a (sub)branch. - Parameters are as for 'reported_br_del'. + Params are (SUBBRANCH_RPATH) or (OUTER_BRANCH_FULLPATH, SUBBRANCH_RPATH). """ - if path2 is None: - subbranch_rpath = path1 - subbranch_fullpath = path1 - else: - subbranch_rpath = path2 - subbranch_fullpath = path1 + '/' + path2 - return ['A ' + re.escape(subbranch_rpath) + r' \(branch \^\..*\)', - r'--- added branch \^.* at /%s' % (re.escape(subbranch_fullpath),)] + subbranch_rpath, subbranch_fullpath = reported_br_params(path1, path2) + return [reported_element_add_line(subbranch_rpath, r' \(branch \^\..*\)'), + reported_branch_add_line(subbranch_fullpath)] + +def reported_br_nested_add(path1, path2=None): + """Return expected lines for addition of a subbranch that is nested inside + an outer branch that is also added: there is no accompanying 'added + element' line. + + Params are (SUBBRANCH_RPATH) or (OUTER_BRANCH_FULLPATH, SUBBRANCH_RPATH). + """ + subbranch_rpath, subbranch_fullpath = reported_br_params(path1, path2) + return [reported_branch_add_line(subbranch_fullpath)] def reported_move(path1, path2, branch_text=''): """Return expected lines for a move, optionally of a (sub)branch. @@ -580,6 +620,9 @@ def reported_br_move(path1, path2): """ return reported_move(path1, path2, r' \(branch \^\..*\)') + +###################################################################### + #@XFail() # There is a bug in the conversion to old-style commits: # in r6 'bar' is plain-added instead of copied. def merge_edits_with_move(sbox): @@ -1127,6 +1170,32 @@ def merge_added_subbranch(sbox): reported_br_add('branches/foo', 'lib2'), 'merge trunk branches/foo trunk@' + str(yca_rev)) +def branch_to_subbranch_of_self(sbox): + "branch to subbranch of self" + # When branching, put the new branch inside the source subtree. This should + # not lead to infinite recursion. + # * source is a { whole branch | subtree of a branch } + # * target is a new path in { the source subtree | + # a subbranch in the source branch } + sbox_build_svnmover(sbox, content=initial_content_in_trunk) + + # branch 'trunk' to 'trunk/foo' + test_svnmover2(sbox, '', None, + 'branch trunk trunk/foo') + # add another subbranch nested under that + test_svnmover2(sbox, 'trunk', None, + 'branch lib foo/lib2') + + # branch 'trunk' to 'trunk/foo/lib2/x' + # + # This should not recurse infinitely + test_svnmover2(sbox, '', + reported_br_diff('trunk/foo/lib2', 'trunk/foo/lib2') + + reported_br_add('trunk/foo/lib2', 'x') + + reported_br_nested_add('trunk/foo/lib2/x', 'foo') + + reported_br_nested_add('trunk/foo/lib2/x/foo', 'lib2'), + 'branch trunk trunk/foo/lib2/x') + ###################################################################### @@ -1145,6 +1214,7 @@ test_list = [ None, subbranches1, merge_deleted_subbranch, merge_added_subbranch, + branch_to_subbranch_of_self, ] if __name__ == '__main__':