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 2015/11/26 18:54:57 UTC

svn commit: r1716749 - in /subversion/trunk/tools/dev/svnmover: svnmover.c svnmover.h

Author: julianfoad
Date: Thu Nov 26 17:54:57 2015
New Revision: 1716749

URL: http://svn.apache.org/viewvc?rev=1716749&view=rev
Log:
Extend 'svnmover's mixed-revision support to nested branches, and add an
'svnmover info' command to show info about one element, following r1716710.

* tools/dev/svnmover/svnmover.h
  (svnmover_wc_t): Update the comment.

* tools/dev/svnmover/svnmover.c
  (svnmover_wc_set_base_rev,
   svnmover_wc_get_base_rev,
   svnmover_wc_set_base_revs,
   svnmover_wc_get_base_revs,
   update_wc_base): Work with nested branches.
  (wc_checkout,
   find_el_rev_by_rrpath_rev): Update calls to track those changes.
  (action_code_t,
   action_defn_t): Add an 'info' subcommand.
  (do_info): New.
  (execute): Implement the 'info' subcommand.

Modified:
    subversion/trunk/tools/dev/svnmover/svnmover.c
    subversion/trunk/tools/dev/svnmover/svnmover.h

Modified: subversion/trunk/tools/dev/svnmover/svnmover.c
URL: http://svn.apache.org/viewvc/subversion/trunk/tools/dev/svnmover/svnmover.c?rev=1716749&r1=1716748&r2=1716749&view=diff
==============================================================================
--- subversion/trunk/tools/dev/svnmover/svnmover.c (original)
+++ subversion/trunk/tools/dev/svnmover/svnmover.c Thu Nov 26 17:54:57 2015
@@ -188,76 +188,131 @@ svnmover_notify_v(const char *fmt,
 /* Set the WC base revision of element EID to BASE_REV.
  */
 static void
-svnmover_wc_set_base_rev(svnmover_wc_t *wc, int eid, svn_revnum_t base_rev)
+svnmover_wc_set_base_rev(svnmover_wc_t *wc,
+                         svn_branch__state_t *branch,
+                         int eid,
+                         svn_revnum_t base_rev)
 {
+  apr_hash_t *branch_base_revs = svn_hash_gets(wc->base_revs, branch->bid);
   void *val = apr_pmemdup(wc->pool, &base_rev, sizeof(base_rev));
 
-  svn_eid__hash_set(wc->base_revs, eid, val);
+  if (!branch_base_revs)
+    {
+      branch_base_revs = apr_hash_make(wc->pool);
+      svn_hash_sets(wc->base_revs, apr_pstrdup(wc->pool, branch->bid),
+                    branch_base_revs);
+    }
+  svn_eid__hash_set(branch_base_revs, eid, val);
 }
 
 /* Get the WC base revision of element EID, or SVN_INVALID_REVNUM if
  * element EID is not present in the WC base.
  */
 static svn_revnum_t
-svnmover_wc_get_base_rev(svnmover_wc_t *wc, int eid, apr_pool_t *scratch_pool)
+svnmover_wc_get_base_rev(svnmover_wc_t *wc,
+                         svn_branch__state_t *branch,
+                         int eid,
+                         apr_pool_t *scratch_pool)
 {
+  apr_hash_t *branch_base_revs = svn_hash_gets(wc->base_revs, branch->bid);
   svn_error_t *err;
   svn_element__content_t *element;
+  svn_revnum_t *base_rev_p;
 
-  err = svn_branch__state_get_element(wc->base->branch, &element, eid,
-                                      scratch_pool);
+  if (!branch_base_revs)
+    {
+      return SVN_INVALID_REVNUM;
+    }
+  err = svn_branch__state_get_element(branch, &element, eid, scratch_pool);
   if (err || !element)
     {
       svn_error_clear(err);
       return SVN_INVALID_REVNUM;
     }
 
-  return *(svn_revnum_t *)svn_eid__hash_get(wc->base_revs, eid);
+  base_rev_p = svn_eid__hash_get(branch_base_revs, eid);
+  if (! base_rev_p)
+    return SVN_INVALID_REVNUM;
+  return *base_rev_p;
 }
 
-/* Set the WC base revision of each element in ELEMENTS to BASE_REV.
+/* Set the WC base revision to BASE_REV for each element in WC base branch
+ * BRANCH, including nested branches.
  */
 static svn_error_t *
-svnmover_wc_set_base_revs(svnmover_wc_t *wc,
-                          svn_element__tree_t *elements,
-                          svn_revnum_t base_rev,
-                          apr_pool_t *scratch_pool)
+svnmover_wc_set_base_revs_r(svnmover_wc_t *wc,
+                            svn_branch__state_t *branch,
+                            svn_revnum_t base_rev,
+                            apr_pool_t *scratch_pool)
 {
+  svn_element__tree_t *elements;
   apr_hash_index_t *hi;
 
-  wc->base_revs = apr_hash_make(wc->pool);
+  SVN_ERR(svn_branch__state_get_elements(branch, &elements, scratch_pool));
   for (hi = apr_hash_first(scratch_pool, elements->e_map);
        hi; hi = apr_hash_next(hi))
     {
       int eid = svn_eid__hash_this_key(hi);
+      svn_element__content_t *element;
+
+      svnmover_wc_set_base_rev(wc, branch, eid, base_rev);
 
-      svnmover_wc_set_base_rev(wc, eid, base_rev);
+      /* recurse into nested branches */
+      SVN_ERR(svn_branch__state_get_element(branch, &element, eid,
+                                            scratch_pool));
+      if (element->payload->is_subbranch_root)
+        {
+          const char *subbranch_id
+            = svn_branch__id_nest(branch->bid, eid, scratch_pool);
+          svn_branch__state_t *subbranch
+            = svn_branch__txn_get_branch_by_id(branch->txn, subbranch_id,
+                                               scratch_pool);
+
+          SVN_ERR(svnmover_wc_set_base_revs_r(wc, subbranch,
+                                              base_rev, scratch_pool));
+        }
     }
 
   return SVN_NO_ERROR;
 }
 
-/* Get the lowest and highest base revision numbers in WC.
+/* Set the WC base revision to BASE_REV for each element in WC base branch
+ * BRANCH, including nested branches.
  */
 static svn_error_t *
-svnmover_wc_get_base_revs(svnmover_wc_t *wc,
-                          svn_revnum_t *base_rev_min,
-                          svn_revnum_t *base_rev_max,
+svnmover_wc_set_base_revs(svnmover_wc_t *wc,
+                          svn_branch__state_t *branch,
+                          svn_revnum_t base_rev,
                           apr_pool_t *scratch_pool)
 {
+  wc->base_revs = apr_hash_make(wc->pool);
+  SVN_ERR(svnmover_wc_set_base_revs_r(wc, branch, base_rev, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/* Get the lowest and highest base revision numbers in WC base branch
+ * BRANCH, including nested branches.
+ */
+static svn_error_t *
+svnmover_wc_get_base_revs_r(svnmover_wc_t *wc,
+                            svn_revnum_t *base_rev_min,
+                            svn_revnum_t *base_rev_max,
+                            svn_branch__state_t *branch,
+                            apr_pool_t *scratch_pool)
+{
   svn_element__tree_t *base_elements;
   apr_hash_index_t *hi;
 
-  SVN_ERR(svn_branch__state_get_elements(wc->base->branch, &base_elements,
+  SVN_ERR(svn_branch__state_get_elements(branch, &base_elements,
                                          scratch_pool));
 
-  *base_rev_min = SVN_INVALID_REVNUM;
-  *base_rev_max = SVN_INVALID_REVNUM;
   for (hi = apr_hash_first(scratch_pool, base_elements->e_map);
        hi; hi = apr_hash_next(hi))
     {
       int eid = svn_eid__hash_this_key(hi);
-      svn_revnum_t rev = svnmover_wc_get_base_rev(wc, eid, scratch_pool);
+      svn_revnum_t rev = svnmover_wc_get_base_rev(wc, branch, eid,
+                                                  scratch_pool);
+      svn_element__content_t *element;
 
       if (*base_rev_min == SVN_INVALID_REVNUM
           || rev < *base_rev_min)
@@ -265,11 +320,41 @@ svnmover_wc_get_base_revs(svnmover_wc_t
       if (*base_rev_max == SVN_INVALID_REVNUM
           || rev > *base_rev_max)
         *base_rev_max = rev;
+
+      /* recurse into nested branches */
+      SVN_ERR(svn_branch__state_get_element(branch, &element, eid,
+                                            scratch_pool));
+      if (element->payload->is_subbranch_root)
+        {
+          const char *subbranch_id
+            = svn_branch__id_nest(branch->bid, eid, scratch_pool);
+          svn_branch__state_t *subbranch
+            = svn_branch__txn_get_branch_by_id(branch->txn, subbranch_id,
+                                               scratch_pool);
+
+          SVN_ERR(svnmover_wc_get_base_revs_r(wc, base_rev_min, base_rev_max,
+                                              subbranch, scratch_pool));
+        }
     }
 
   return SVN_NO_ERROR;
 }
 
+/* Get the lowest and highest base revision numbers in WC.
+ */
+static svn_error_t *
+svnmover_wc_get_base_revs(svnmover_wc_t *wc,
+                          svn_revnum_t *base_rev_min,
+                          svn_revnum_t *base_rev_max,
+                          apr_pool_t *scratch_pool)
+{
+  *base_rev_min = SVN_INVALID_REVNUM;
+  *base_rev_max = SVN_INVALID_REVNUM;
+  SVN_ERR(svnmover_wc_get_base_revs_r(wc, base_rev_min, base_rev_max,
+                                      wc->base->branch, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
 /* Update the WC to revision BASE_REVISION (SVN_INVALID_REVNUM means HEAD).
  *
  * Requires these fields in WC:
@@ -299,7 +384,6 @@ wc_checkout(svnmover_wc_t *wc,
   svn_branch__compat_fetch_func_t fetch_func;
   void *fetch_baton;
   svn_branch__txn_t *base_txn;
-  svn_element__tree_t *base_elements;
 
   /* Validate and store the new base revision number */
   if (! SVN_IS_VALID_REVNUM(base_revision))
@@ -341,9 +425,7 @@ wc_checkout(svnmover_wc_t *wc,
     return svn_error_createf(SVN_BRANCH__ERR, NULL,
                              "Cannot check out WC: branch %s not found in r%ld",
                              base_branch_id, base_revision);
-  SVN_ERR(svn_branch__state_get_elements(wc->base->branch, &base_elements,
-                                         scratch_pool));
-  SVN_ERR(svnmover_wc_set_base_revs(wc, base_elements,
+  SVN_ERR(svnmover_wc_set_base_revs(wc, wc->base->branch,
                                     base_revision, scratch_pool));
 
   wc->working = apr_pcalloc(wc->pool, sizeof(*wc->working));
@@ -849,20 +931,30 @@ update_wc_eids(svnmover_wc_t *wc,
  * The committed elements are determined by diffing base against working.
  * ### TODO: When we allow committing a subset of the WC, we'll need to
  *     pass in a list of the committed elements.
+ *
+ * BASE_BRANCH and/or WORK_BRANCH may be null.
  */
 static svn_error_t *
-update_wc_base(svnmover_wc_t *wc,
-               svn_revnum_t new_rev,
-               apr_pool_t *scratch_pool)
+update_wc_base_r(svnmover_wc_t *wc,
+                 svn_branch__state_t *base_branch,
+                 svn_branch__state_t *work_branch,
+                 svn_revnum_t new_rev,
+                 apr_pool_t *scratch_pool)
 {
   svn_element__tree_t *base_elements, *working_elements;
   apr_hash_t *committed_elements;
   apr_hash_index_t *hi;
 
-  SVN_ERR(svn_branch__state_get_elements(wc->base->branch, &base_elements,
-                                         scratch_pool));
-  SVN_ERR(svn_branch__state_get_elements(wc->working->branch, &working_elements,
-                                         scratch_pool));
+  if (base_branch)
+    SVN_ERR(svn_branch__state_get_elements(base_branch, &base_elements,
+                                           scratch_pool));
+  else
+    base_elements = svn_element__tree_create(NULL, 0, scratch_pool);
+  if (work_branch)
+    SVN_ERR(svn_branch__state_get_elements(work_branch, &working_elements,
+                                           scratch_pool));
+  else
+    working_elements = svn_element__tree_create(NULL, 0, scratch_pool);
   SVN_ERR(svnmover_element_differences(&committed_elements,
                                        base_elements, working_elements,
                                        scratch_pool, scratch_pool));
@@ -871,22 +963,84 @@ update_wc_base(svnmover_wc_t *wc,
        hi; hi = apr_hash_next(hi))
     {
       int eid = svn_eid__hash_this_key(hi);
-      svn_element__content_t *content;
+      svn_element__content_t *content = NULL;
 
-      SVN_ERR(svn_branch__state_get_element(wc->working->branch, &content,
-                                            eid, scratch_pool));
+      if (work_branch)
+        SVN_ERR(svn_branch__state_get_element(work_branch, &content,
+                                              eid, scratch_pool));
       if (content)
-        SVN_ERR(svn_branch__state_alter_one(wc->base->branch, eid,
+        SVN_ERR(svn_branch__state_alter_one(base_branch, eid,
                                             content->parent_eid, content->name,
                                             content->payload, scratch_pool));
       else
-        SVN_ERR(svn_branch__state_delete_one(wc->base->branch, eid, scratch_pool));
-      svnmover_wc_set_base_rev(wc, eid, new_rev);
+        SVN_ERR(svn_branch__state_delete_one(base_branch, eid, scratch_pool));
+      svnmover_wc_set_base_rev(wc, base_branch, eid, new_rev);
+
+      /* recurse into nested branches that exist in working */
+      if (content && content->payload->is_subbranch_root)
+        {
+          svn_branch__state_t *base_subbranch = NULL;
+          svn_branch__state_t *work_subbranch = NULL;
+
+          if (base_branch)
+            {
+              base_subbranch
+                = svn_branch__txn_get_branch_by_id(
+                    base_branch->txn,
+                    svn_branch__id_nest(base_branch->bid, eid, scratch_pool),
+                    scratch_pool);
+            }
+          if (work_branch)
+            {
+              work_subbranch
+                = svn_branch__txn_get_branch_by_id(
+                    work_branch->txn,
+                    svn_branch__id_nest(work_branch->bid, eid, scratch_pool),
+                    scratch_pool);
+            }
+          if (work_subbranch && !base_subbranch)
+            {
+              const char *new_branch_id
+                = svn_branch__id_nest(base_branch->bid, eid, scratch_pool);
+
+              SVN_ERR(svn_branch__txn_open_branch(base_branch->txn,
+                                                  &base_subbranch,
+                                                  work_subbranch->predecessor,
+                                                  new_branch_id,
+                                                  svn_branch__root_eid(work_subbranch),
+                                                  scratch_pool, scratch_pool));
+            }
+          SVN_ERR(update_wc_base_r(wc, base_subbranch, work_subbranch,
+                                   new_rev, scratch_pool));
+        }
     }
 
   return SVN_NO_ERROR;
 }
 
+/* Update the WC base value of each committed element to match the
+ * corresponding WC working element value.
+ * Update the WC base revision for each committed element to NEW_REV.
+ *
+ * The committed elements are determined by diffing base against working.
+ * ### TODO: When we allow committing a subset of the WC, we'll need to
+ *     pass in a list of the committed elements.
+ *
+ * ### This should be equivalent to 'replay(base, base, working)'. Use that
+ *     instead.
+ */
+static svn_error_t *
+update_wc_base(svnmover_wc_t *wc,
+               svn_revnum_t new_rev,
+               apr_pool_t *scratch_pool)
+{
+  svn_branch__state_t *base_branch = wc->base->branch;
+  svn_branch__state_t *work_branch = wc->working->branch;
+  SVN_ERR(update_wc_base_r(wc, base_branch, work_branch,
+                           new_rev, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
 /* Commit the changes from WC into the repository.
  *
  * Open a new commit txn to the repo. Replay the changes from WC into it.
@@ -1003,6 +1157,7 @@ wc_commit(svn_revnum_t *new_rev_p,
 
 typedef enum action_code_t {
   ACTION_INFO_WC,
+  ACTION_INFO,
   ACTION_LIST_CONFLICTS,
   ACTION_RESOLVED_CONFLICT,
   ACTION_DIFF,
@@ -1046,6 +1201,8 @@ static const action_defn_t action_defn[]
 {
   {ACTION_INFO_WC,          "info-wc", 0, "",
     "print information about the WC"},
+  {ACTION_INFO,             "info", 1, "PATH",
+    "show info about the element at PATH"},
   {ACTION_LIST_CONFLICTS,   "conflicts", 0, "",
     "list unresolved conflicts"},
   {ACTION_RESOLVED_CONFLICT,"resolved", 1, "CONFLICT_ID",
@@ -1194,7 +1351,8 @@ find_el_rev_by_rrpath_rev(svn_branch__el
         }
       else
         {
-          el_rev->rev = svnmover_wc_get_base_rev(wc, el_rev->eid, scratch_pool);
+          el_rev->rev = svnmover_wc_get_base_rev(wc, el_rev->branch,
+                                                 el_rev->eid, scratch_pool);
         }
       *el_rev_p = el_rev;
     }
@@ -2918,6 +3076,54 @@ do_migrate(svnmover_wc_t *wc,
   return SVN_NO_ERROR;
 }
 
+/* Show info about element E.
+ *
+ * TODO: Show different info for a repo element versus a WC element.
+ */
+static svn_error_t *
+do_info(svnmover_wc_t *wc,
+        svn_branch__el_rev_id_t *e,
+        apr_pool_t *scratch_pool)
+{
+  svnmover_notify("Element Id: %d%s",
+                  e->eid,
+                  is_branch_root_element(e->branch, e->eid)
+                    ? " (branch root)" : "");
+
+  /* Show WC info for a WC working element, or repo info for a repo element */
+  if (e->rev == SVN_INVALID_REVNUM)
+    {
+      svn_branch__state_t *base_branch, *work_branch;
+      svn_revnum_t base_rev;
+      svn_element__content_t *e_base, *e_work;
+      svn_boolean_t is_modified;
+
+      base_branch = svn_branch__txn_get_branch_by_id(
+                      wc->base->branch->txn, e->branch->bid, scratch_pool);
+      work_branch = svn_branch__txn_get_branch_by_id(
+                      wc->working->branch->txn, e->branch->bid, scratch_pool);
+      base_rev = svnmover_wc_get_base_rev(wc, base_branch, e->eid, scratch_pool);
+      SVN_ERR(svn_branch__state_get_element(base_branch, &e_base,
+                                            e->eid, scratch_pool));
+      SVN_ERR(svn_branch__state_get_element(work_branch, &e_work,
+                                            e->eid, scratch_pool));
+      is_modified = !svn_element__content_equal(e_base, e_work,
+                                                scratch_pool);
+
+      svnmover_notify("Base Revision: %ld", base_rev);
+      svnmover_notify("Base Branch:    %s", base_branch->bid);
+      svnmover_notify("Working Branch: %s", work_branch->bid);
+      svnmover_notify("Modified:       %s", is_modified ? "yes" : "no");
+    }
+  else
+    {
+      svnmover_notify("Revision: %ld", e->rev);
+      svnmover_notify("Branch:    %s", e->branch->bid);
+    }
+
+  return SVN_NO_ERROR;
+}
+
 
 typedef struct arg_t
 {
@@ -3087,6 +3293,33 @@ execute(svnmover_wc_t *wc,
           }
           break;
 
+        case ACTION_INFO:
+          VERIFY_EID_EXISTS("info", 0);
+          {
+            /* If it's a nested branch root, show info for the outer element
+               first, and then for the inner element. */
+            if (is_branch_root_element(arg[0]->el_rev->branch,
+                                       arg[0]->el_rev->eid))
+              {
+                svn_branch__state_t *outer_branch;
+                int outer_eid;
+
+                svn_branch__get_outer_branch_and_eid(&outer_branch, &outer_eid,
+                                                     arg[0]->el_rev->branch,
+                                                     iterpool);
+                if (outer_branch)
+                  {
+                    svn_branch__el_rev_id_t *outer_e
+                      = svn_branch__el_rev_id_create(outer_branch, outer_eid,
+                                                     arg[0]->el_rev->rev,
+                                                     iterpool);
+                    SVN_ERR(do_info(wc, outer_e, iterpool));
+                  }
+              }
+            SVN_ERR(do_info(wc, arg[0]->el_rev, iterpool));
+          }
+          break;
+
         case ACTION_LIST_CONFLICTS:
           {
             if (svnmover_any_conflicts(wc->conflicts))

Modified: subversion/trunk/tools/dev/svnmover/svnmover.h
URL: http://svn.apache.org/viewvc/subversion/trunk/tools/dev/svnmover/svnmover.h?rev=1716749&r1=1716748&r2=1716749&view=diff
==============================================================================
--- subversion/trunk/tools/dev/svnmover/svnmover.h (original)
+++ subversion/trunk/tools/dev/svnmover/svnmover.h Thu Nov 26 17:54:57 2015
@@ -119,8 +119,11 @@ typedef struct svnmover_wc_t
   svn_branch__txn_t *edit_txn;
   conflict_storage_t *conflicts;
 
+  /* The base revisions, for (at least) all EIDs in BASE:
+     branch_id -> hash { eid -> revnum } */
+  apr_hash_t *base_revs;
+
   /* Base and working versions. */
-  apr_hash_t *base_revs;  /* eid -> revnum, for (at least) all eids in BASE */
   svnmover_wc_version_t *base, *working;
 
   /* Textual list of commands the commands that were executed, suitable