subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From julianf...@apache.org
Subject svn commit: r1827503 - in /subversion/trunk/subversion: include/svn_client.h libsvn_client/shelf.c svn/shelf-cmd.c tests/cmdline/shelf_tests.py
Date Thu, 22 Mar 2018 15:01:07 GMT
Author: julianfoad
Date: Thu Mar 22 15:01:07 2018
New Revision: 1827503

URL: http://svn.apache.org/viewvc?rev=1827503&view=rev
Log:
Shelving: refuse to unshelve if there are conflicts.

* subversion/include/svn_client.h,
  subversion/libsvn_client/shelf.c
  (svn_client_shelf_apply): Document better.
  (patch_filter_baton_t, patch_filter,
   patch_notify_baton_t, patch_notify,
   svn_client_shelf_test_apply_file): New.

* subversion/svn/shelf-cmd.c
  (test_apply): New.
  (shelf_restore): Error if any path would have a conflict, unless forced.

* subversion/tests/cmdline/shelf_tests.py
  (state_from_status): Move to top of file...
  (shelve_unshelve_verify): ... and use to simplify here.
  (unshelve_refuses_if_conflicts): New.
  (test_list): Run it.

Modified:
    subversion/trunk/subversion/include/svn_client.h
    subversion/trunk/subversion/libsvn_client/shelf.c
    subversion/trunk/subversion/svn/shelf-cmd.c
    subversion/trunk/subversion/tests/cmdline/shelf_tests.py

Modified: subversion/trunk/subversion/include/svn_client.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_client.h?rev=1827503&r1=1827502&r2=1827503&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_client.h (original)
+++ subversion/trunk/subversion/include/svn_client.h Thu Mar 22 15:01:07 2018
@@ -7064,6 +7064,10 @@ svn_client_shelf_get_all_versions(apr_ar
 
 /** Apply @a shelf_version to the WC.
  *
+ * If @a dry_run is true, try applying the shelf-version to the WC and
+ * report the full set of notifications about successes and conflicts,
+ * but leave the WC untouched.
+ *
  * @since New in 1.X.
  * @warning EXPERIMENTAL.
  */
@@ -7073,6 +7077,24 @@ svn_client_shelf_apply(svn_client_shelf_
                        svn_boolean_t dry_run,
                        apr_pool_t *scratch_pool);
 
+/** Test whether we can successfully apply the patch for @a file_relpath
+ * in @a shelf_version to the WC.
+ *
+ * Try applying the shelf-version to the WC and set @a *conflict_p to
+ * true if any conflict occurs, else to false.
+ *
+ * Leave the WC untouched.
+ *
+ * @since New in 1.X.
+ * @warning EXPERIMENTAL.
+ */
+SVN_EXPERIMENTAL
+svn_error_t *
+svn_client_shelf_test_apply_file(svn_boolean_t *conflict_p,
+                                 svn_client_shelf_version_t *shelf_version,
+                                 const char *file_relpath,
+                                 apr_pool_t *scratch_pool);
+
 /** Reverse-apply @a shelf_version to the WC.
  *
  * @since New in 1.X.

Modified: subversion/trunk/subversion/libsvn_client/shelf.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/shelf.c?rev=1827503&r1=1827502&r2=1827503&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/shelf.c (original)
+++ subversion/trunk/subversion/libsvn_client/shelf.c Thu Mar 22 15:01:07 2018
@@ -592,6 +592,82 @@ svn_client_shelf_paths_changed(apr_hash_
   return SVN_NO_ERROR;
 }
 
+/* A filter to only apply the patch to a particular file. */
+struct patch_filter_baton_t
+{
+  /* The single path to be selected for patching */
+  const char *path;
+};
+
+static svn_error_t *
+patch_filter(void *baton,
+             svn_boolean_t *filtered,
+             const char *canon_path_from_patchfile,
+             const char *patch_abspath,
+             const char *reject_abspath,
+             apr_pool_t *scratch_pool)
+{
+  struct patch_filter_baton_t *fb = baton;
+
+  *filtered = (strcmp(canon_path_from_patchfile, fb->path) != 0);
+  return SVN_NO_ERROR;
+}
+
+/* Intercept patch notifications to detect when there is a conflict */
+struct patch_notify_baton_t
+{
+  svn_boolean_t conflict;
+};
+
+/* Intercept patch notifications to detect when there is a conflict */
+static void
+patch_notify(void *baton,
+             const svn_wc_notify_t *notify,
+             apr_pool_t *pool)
+{
+  struct patch_notify_baton_t *nb = baton;
+
+  if (notify->action == svn_wc_notify_patch_rejected_hunk
+      || notify->action == svn_wc_notify_skip)
+    nb->conflict = TRUE;
+}
+
+svn_error_t *
+svn_client_shelf_test_apply_file(svn_boolean_t *conflict_p,
+                                 svn_client_shelf_version_t *shelf_version,
+                                 const char *file_relpath,
+                                 apr_pool_t *scratch_pool)
+{
+  svn_client_ctx_t *ctx = shelf_version->shelf->ctx;
+  svn_wc_notify_func2_t ctx_notify_func;
+  void *ctx_notify_baton;
+  struct patch_filter_baton_t fb;
+  struct patch_notify_baton_t nb;
+
+  fb.path = file_relpath;
+
+  nb.conflict = FALSE;
+  ctx_notify_func = ctx->notify_func2;
+  ctx_notify_baton = ctx->notify_baton2;
+  ctx->notify_func2 = patch_notify;
+  ctx->notify_baton2 = &nb;
+
+  SVN_ERR(svn_client_patch(shelf_version->patch_abspath,
+                           shelf_version->shelf->wc_root_abspath,
+                           TRUE /*dry_run*/, 0 /*strip*/,
+                           FALSE /*reverse*/,
+                           FALSE /*ignore_whitespace*/,
+                           TRUE /*remove_tempfiles*/,
+                           patch_filter, &fb,
+                           shelf_version->shelf->ctx, scratch_pool));
+
+  ctx->notify_func2 = ctx_notify_func;
+  ctx->notify_baton2 = ctx_notify_baton;
+
+  *conflict_p = nb.conflict;
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_client_shelf_apply(svn_client_shelf_version_t *shelf_version,
                        svn_boolean_t dry_run,

Modified: subversion/trunk/subversion/svn/shelf-cmd.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/shelf-cmd.c?rev=1827503&r1=1827502&r2=1827503&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/shelf-cmd.c (original)
+++ subversion/trunk/subversion/svn/shelf-cmd.c Thu Mar 22 15:01:07 2018
@@ -564,7 +564,34 @@ shelve(int *new_version_p,
   return SVN_NO_ERROR;
 }
 
-/* Throw an error if any paths affected by SHELF:VERSION are currently
+/* Throw an error if any path affected by SHELF_VERSION gives a conflict
+ * when applied (as a dry-run) to the WC. */
+static svn_error_t *
+test_apply(svn_client_shelf_version_t *shelf_version,
+           svn_client_ctx_t *ctx,
+           apr_pool_t *scratch_pool)
+{
+  apr_hash_t *paths;
+  apr_hash_index_t *hi;
+
+  SVN_ERR(svn_client_shelf_paths_changed(&paths, shelf_version,
+                                         scratch_pool, scratch_pool));
+  for (hi = apr_hash_first(scratch_pool, paths); hi; hi = apr_hash_next(hi))
+    {
+      const char *path = apr_hash_this_key(hi);
+      svn_boolean_t conflict;
+
+      SVN_ERR(svn_client_shelf_test_apply_file(&conflict, shelf_version, path,
+                                               scratch_pool));
+      if (conflict)
+        return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+                                 _("Conflict in applying shelf '%s' path '%s'"),
+                                 shelf_version->shelf->name, path);
+    }
+  return SVN_NO_ERROR;
+}
+
+/* Throw an error if any paths affected by SHELF_VERSION are currently
  * modified in the WC. */
 static svn_error_t *
 check_no_modified_paths(const char *paths_base_abspath,
@@ -642,13 +669,15 @@ patch_notify(void *baton,
  * or the newest version is @a arg is null.
  *
  * If @a dry_run is true, don't actually do it.
+ *
+ * Error if any path would have a conflict, unless @a force_if_conflict.
  */
 static svn_error_t *
 shelf_restore(const char *name,
               const char *arg,
               svn_boolean_t dry_run,
               svn_boolean_t quiet,
-              svn_boolean_t force_already_modified,
+              svn_boolean_t force_if_conflict,
               const char *local_abspath,
               svn_client_ctx_t *ctx,
               apr_pool_t *scratch_pool)
@@ -685,10 +714,11 @@ shelf_restore(const char *name,
       SVN_ERR(stats(shelf, version, shelf_version, time_now,
                     TRUE /*with_logmsg*/, scratch_pool));
     }
-  if (! force_already_modified)
+  if (! force_if_conflict)
     {
-      SVN_ERR(check_no_modified_paths(shelf->wc_root_abspath,
-                                      shelf_version, quiet, ctx, scratch_pool));
+      SVN_ERR_W(test_apply(shelf_version, ctx, scratch_pool),
+                _("Cannot unshelve/restore, as at least one "
+                  "path would conflict"));
     }
 
   b.rejects = FALSE;

Modified: subversion/trunk/subversion/tests/cmdline/shelf_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/shelf_tests.py?rev=1827503&r1=1827502&r2=1827503&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/shelf_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/shelf_tests.py Thu Mar 22 15:01:07 2018
@@ -44,6 +44,11 @@ Item = wc.StateItem
 
 #----------------------------------------------------------------------
 
+def state_from_status(wc_dir):
+  _, output, _ = svntest.main.run_svn(None, 'status', '-v', '-u', '-q',
+                                      wc_dir)
+  return svntest.wc.State.from_status(output, wc_dir)
+
 def shelve_unshelve_verify(sbox):
   """Round-trip: shelve; verify all changes are reverted;
      unshelve; verify all changes are restored.
@@ -52,9 +57,7 @@ def shelve_unshelve_verify(sbox):
   wc_dir = sbox.wc_dir
 
   # Save the modified state
-  _, output, _ = svntest.main.run_svn(None, 'status', '-v', '-u', '-q',
-                                      wc_dir)
-  modified_state = svntest.wc.State.from_status(output, wc_dir)
+  modified_state = state_from_status(wc_dir)
 
   # Shelve; check there are no longer any modifications
   svntest.actions.run_and_verify_svn(None, [],
@@ -184,11 +187,6 @@ def shelve_from_inner_path(sbox):
 
 #----------------------------------------------------------------------
 
-def state_from_status(wc_dir):
-  _, output, _ = svntest.main.run_svn(None, 'status', '-v', '-u', '-q',
-                                      wc_dir)
-  return svntest.wc.State.from_status(output, wc_dir)
-
 def save_revert_restore(sbox, modifier1, modifier2):
   "Save 2 checkpoints; revert; restore 1st"
 
@@ -255,6 +253,49 @@ def shelve_mergeinfo(sbox):
 
   shelve_unshelve(sbox, modifier)
 
+#----------------------------------------------------------------------
+
+def unshelve_refuses_if_conflicts(sbox):
+  "unshelve refuses if conflicts"
+
+  def modifier1(sbox):
+    sbox.simple_append('alpha', 'A-mod1\nB\nC\nD\n', truncate=True)
+    sbox.simple_append('beta', 'A-mod1\nB\nC\nD\n', truncate=True)
+
+  def modifier2(sbox):
+    sbox.simple_append('beta', 'A-mod2\nB\nC\nD\n', truncate=True)
+
+  sbox.build(empty=True)
+  was_cwd = os.getcwd()
+  os.chdir(sbox.wc_dir)
+  sbox.wc_dir = ''
+  wc_dir = ''
+
+  sbox.simple_add_text('A\nB\nC\nD\n', 'alpha')
+  sbox.simple_add_text('A\nB\nC\nD\n', 'beta')
+  sbox.simple_commit()
+  initial_state = state_from_status(wc_dir)
+
+  # Make initial mods; remember this modified state
+  modifier1(sbox)
+  modified_state1 = state_from_status(wc_dir)
+  assert modified_state1 != initial_state
+
+  # Shelve; check there are no longer any local mods
+  svntest.actions.run_and_verify_svn(None, [],
+                                     'shelve', 'foo')
+  svntest.actions.run_and_verify_status(wc_dir, initial_state)
+
+  # Make a different local mod that will conflict with the shelf
+  modifier2(sbox)
+  modified_state2 = state_from_status(wc_dir)
+
+  # Try to unshelve; check it fails with an error about a conflict
+  svntest.actions.run_and_verify_svn(None, '.*[Cc]onflict.*',
+                                     'unshelve', 'foo')
+  # Check nothing changed in the attempt
+  svntest.actions.run_and_verify_status(wc_dir, modified_state2)
+
 
 ########################################################################
 # Run the tests
@@ -270,6 +311,7 @@ test_list = [ None,
               shelve_from_inner_path,
               checkpoint_basic,
               shelve_mergeinfo,
+              unshelve_refuses_if_conflicts,
              ]
 
 if __name__ == '__main__':



Mime
View raw message