Author: stsp
Date: Thu Apr 21 08:55:21 2016
New Revision: 1740257

URL: http://svn.apache.org/viewvc?rev=1740257&view=rev
Log:
Implement a general "incoming add vs local add" resolution option which does
not only apply to files, but also to directories (and other file/dir x dir/file
permutations of the same problem).

* subversion/include/svn_client.h
  (svn_client_conflict_option_merge_incoming_added_file_ignore): Rename to...
  (svn_client_conflict_option_merge_incoming_add_ignore): ... this to make
   the name generic.

* subversion/libsvn_client/conflicts.c
  (resolve_merge_incoming_added_file_ignore): Rename to ...
  (resolve_merge_incoming_add_ignore): ... this. There is no node-kind
   specific code in this function.
  (configure_option_merge_incoming_added_file_ignore): Rename to ...
  (configure_option_merge_incoming_add_ignore): ... this, and apply
   the option regardless of node kind.
  (svn_client_conflict_tree_get_resolution_options): Track rename.

* subversion/svn/conflict-callbacks.c
  (builtin_resolver_options): Track renamed option ID and update the
   short description shown in the conflict menu.

* subversion/tests/libsvn_client/conflicts-test.c
  (test_option_merge_incoming_added_file_ignore): Use renamed option ID.
  (create_wc_with_dir_add_vs_dir_add_merge_conflict): New helper function.
  (test_option_merge_incoming_added_dir_ignore, test_funcs): New test.

Modified:
    subversion/trunk/subversion/include/svn_client.h
    subversion/trunk/subversion/libsvn_client/conflicts.c
    subversion/trunk/subversion/svn/conflict-callbacks.c
    subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c

Modified: subversion/trunk/subversion/include/svn_client.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_client.h?rev=1740257&r1=1740256&r2=1740257&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_client.h (original)
+++ subversion/trunk/subversion/include/svn_client.h Thu Apr 21 08:55:21 2016
@@ -4406,8 +4406,10 @@ typedef enum svn_client_conflict_option_
   /* Options for local delete/replace vs incoming edit on update. */
   svn_client_conflict_option_update_any_moved_away_children,
 
+  /* Options for incoming add vs local 'obstruction' on merge. */
+  svn_client_conflict_option_merge_incoming_add_ignore,
+
   /* Options for incoming file add vs local file 'obstruction' on merge. */
-  svn_client_conflict_option_merge_incoming_added_file_ignore,
   svn_client_conflict_option_merge_incoming_added_file_text_merge,
   svn_client_conflict_option_merge_incoming_added_file_replace,
   svn_client_conflict_option_merge_incoming_added_file_replace_and_merge,

Modified: subversion/trunk/subversion/libsvn_client/conflicts.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/conflicts.c?rev=1740257&r1=1740256&r2=1740257&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/conflicts.c (original)
+++ subversion/trunk/subversion/libsvn_client/conflicts.c Thu Apr 21 08:55:21 
2016
@@ -3595,9 +3595,9 @@ resolve_update_moved_away_node(svn_clien
 
 /* Implements conflict_option_resolve_func_t. */
 static svn_error_t *
-resolve_merge_incoming_added_file_ignore(svn_client_conflict_option_t *option,
-                                         svn_client_conflict_t *conflict,
-                                         apr_pool_t *scratch_pool)
+resolve_merge_incoming_add_ignore(svn_client_conflict_option_t *option,
+                                  svn_client_conflict_t *conflict,
+                                  apr_pool_t *scratch_pool)
 {
   const char *local_abspath;
   const char *lock_abspath;
@@ -3611,7 +3611,7 @@ resolve_merge_incoming_added_file_ignore
                                                  scratch_pool, scratch_pool));
 
   /* All other options for this conflict actively fetch the incoming
-   * new file. We can ignore the incoming new file by doing nothing. */
+   * new node. We can ignore the incoming new node by doing nothing. */
 
   /* Resolve to current working copy state. */
   err = svn_wc__del_tree_conflict(ctx->wc_ctx, local_abspath, scratch_pool);
@@ -4381,34 +4381,27 @@ configure_option_update_raise_moved_away
   return SVN_NO_ERROR;
 }
 
-/* Configure 'incoming added file ignore' resolution option for a tree
- * conflict. */
+/* Configure 'incoming add ignore' resolution option for a tree conflict. */
 static svn_error_t *
-configure_option_merge_incoming_added_file_ignore(
-  svn_client_conflict_t *conflict,
-  apr_array_header_t *options,
-  apr_pool_t *scratch_pool)
+configure_option_merge_incoming_add_ignore(svn_client_conflict_t *conflict,
+                                           apr_array_header_t *options,
+                                           apr_pool_t *scratch_pool)
 {
   svn_wc_operation_t operation;
   svn_wc_conflict_action_t incoming_change;
   svn_wc_conflict_reason_t local_change;
-  svn_node_kind_t victim_node_kind;
   const char *incoming_new_repos_relpath;
   svn_revnum_t incoming_new_pegrev;
-  svn_node_kind_t incoming_new_kind;
 
   operation = svn_client_conflict_get_operation(conflict);
   incoming_change = svn_client_conflict_get_incoming_change(conflict);
   local_change = svn_client_conflict_get_local_change(conflict);
-  victim_node_kind = svn_client_conflict_tree_get_victim_node_kind(conflict);
   SVN_ERR(svn_client_conflict_get_incoming_new_repos_location(
             &incoming_new_repos_relpath, &incoming_new_pegrev,
-            &incoming_new_kind, conflict, scratch_pool,
+            NULL, conflict, scratch_pool,
             scratch_pool));
 
   if (operation == svn_wc_operation_merge &&
-      victim_node_kind == svn_node_file &&
-      incoming_new_kind == svn_node_file &&
       incoming_change == svn_wc_conflict_action_add &&
       local_change == svn_wc_conflict_reason_obstructed)
     {
@@ -4417,7 +4410,7 @@ configure_option_merge_incoming_added_fi
 
       option = apr_pcalloc(options->pool, sizeof(*option));
       option->id =
-        svn_client_conflict_option_merge_incoming_added_file_ignore;
+        svn_client_conflict_option_merge_incoming_add_ignore;
       SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath, conflict->ctx->wc_ctx,
                                  conflict->local_abspath, scratch_pool,
                                  scratch_pool));
@@ -4425,7 +4418,7 @@ configure_option_merge_incoming_added_fi
         apr_psprintf(options->pool, _("ignore and do not add '^/%s@%ld' here"),
           incoming_new_repos_relpath, incoming_new_pegrev);
       option->conflict = conflict;
-      option->do_resolve_func = resolve_merge_incoming_added_file_ignore;
+      option->do_resolve_func = resolve_merge_incoming_add_ignore;
       APR_ARRAY_PUSH(options, const svn_client_conflict_option_t *) = option;
     }
 
@@ -4626,8 +4619,8 @@ svn_client_conflict_tree_get_resolution_
   SVN_ERR(configure_option_update_move_destination(conflict, *options));
   SVN_ERR(configure_option_update_raise_moved_away_children(conflict,
                                                             *options));
-  SVN_ERR(configure_option_merge_incoming_added_file_ignore(conflict, *options,
-                                                            scratch_pool));
+  SVN_ERR(configure_option_merge_incoming_add_ignore(conflict, *options,
+                                                     scratch_pool));
   SVN_ERR(configure_option_merge_incoming_added_file_text_merge(conflict,
                                                                 *options,
                                                                 scratch_pool));

Modified: subversion/trunk/subversion/svn/conflict-callbacks.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/conflict-callbacks.c?rev=1740257&r1=1740256&r2=1740257&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/conflict-callbacks.c (original)
+++ subversion/trunk/subversion/svn/conflict-callbacks.c Thu Apr 21 08:55:21 
2016
@@ -419,9 +419,11 @@ static const resolver_option_t builtin_r
   { "u", N_("update any moved-away children"), NULL,
     svn_client_conflict_option_update_any_moved_away_children },
 
+  /* Options for incoming add vs local add upon merge. */
+  { "i", N_("ignore incoming addition"), NULL,
+    svn_client_conflict_option_merge_incoming_add_ignore },
+
   /* Options for incoming file add vs local file add upon merge. */
-  { "i", N_("ignore the incoming file"), NULL,
-    svn_client_conflict_option_merge_incoming_added_file_ignore },
   { "m", N_("merge the files"), NULL,
     svn_client_conflict_option_merge_incoming_added_file_text_merge },
   { "R", N_("replace my file with incoming file"), NULL,

Modified: subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c?rev=1740257&r1=1740256&r2=1740257&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c Thu Apr 21 
08:55:21 2016
@@ -182,7 +182,7 @@ test_option_merge_incoming_added_file_ig
                                   ctx, b->pool, b->pool));
   SVN_ERR(svn_client_conflict_tree_resolve_by_id(
             conflict,
-            svn_client_conflict_option_merge_incoming_added_file_ignore,
+            svn_client_conflict_option_merge_incoming_add_ignore,
             b->pool));
 
   /* Ensure that the file has the expected status. */
@@ -449,6 +449,172 @@ test_option_merge_incoming_added_file_re
   return SVN_NO_ERROR;
 }
 
+/* 
+ * The following tests verify resolution of "incoming dir add vs.
+ * local dir obstruction upon merge" tree conflicts.
+ */
+static const char *new_dir_name = "newdir";
+
+/* A helper function which prepares a working copy for the tests below. */
+static svn_error_t *
+create_wc_with_dir_add_vs_dir_add_merge_conflict(svn_test__sandbox_t *b)
+{
+  static const char *new_dir_path;
+  static const char *new_file_path;
+  svn_client_ctx_t *ctx;
+  static const char *trunk_url;
+  svn_opt_revision_t opt_rev;
+  svn_client_status_t *status;
+  struct status_baton sb;
+  svn_client_conflict_t *conflict;
+  svn_boolean_t tree_conflicted;
+
+  SVN_ERR(sbox_add_and_commit_greek_tree(b));
+
+  /* Create a branch of node "A". */
+  SVN_ERR(sbox_wc_copy(b, trunk_path, branch_path));
+  SVN_ERR(sbox_wc_commit(b, ""));
+
+  /* Add new directories on trunk and the branch which occupy the same path
+   * but have different content and properties. */
+  new_dir_path = svn_relpath_join(trunk_path, new_dir_name, b->pool);
+  SVN_ERR(sbox_wc_mkdir(b, new_dir_path));
+  new_file_path = svn_relpath_join(trunk_path,
+                                   svn_relpath_join(new_dir_name,
+                                                    new_file_name, b->pool),
+                                   b->pool);
+  SVN_ERR(sbox_file_write(b, new_file_path,
+                          "This is a new file on the trunk\n"));
+  SVN_ERR(sbox_wc_add(b, new_file_path));
+  SVN_ERR(sbox_wc_commit(b, ""));
+  new_dir_path = svn_relpath_join(branch_path, new_dir_name, b->pool);
+  SVN_ERR(sbox_wc_mkdir(b, new_dir_path));
+  new_file_path = svn_relpath_join(branch_path,
+                                   svn_relpath_join(new_dir_name,
+                                                    new_file_name, b->pool),
+                                   b->pool);
+  SVN_ERR(sbox_file_write(b, new_file_path,
+                          /* NB: Ensure that the file content's length
+                           * differs between the two branches! Tests are
+                           * run with sleep for timestamps disabled. */
+                          "This is a new file on the branch\n"));
+  SVN_ERR(sbox_wc_add(b, new_file_path));
+  SVN_ERR(sbox_wc_commit(b, ""));
+
+  /* Run a merge from the trunk to the branch. */
+  SVN_ERR(svn_test__create_client_ctx(&ctx, b, b->pool));
+
+  SVN_ERR(sbox_wc_update(b, "", SVN_INVALID_REVNUM));
+  trunk_url = apr_pstrcat(b->pool, b->repos_url, "/", trunk_path, SVN_VA_NULL);
+
+  opt_rev.kind = svn_opt_revision_head;
+  opt_rev.value.number = SVN_INVALID_REVNUM;
+  /* This should raise an "incoming add vs local obstruction" tree conflict. */
+  SVN_ERR(svn_client_merge_peg5(trunk_url, NULL, &opt_rev,
+                                sbox_wc_path(b, branch_path),
+                                svn_depth_infinity,
+                                FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
+                                NULL, ctx, b->pool));
+
+  /* Ensure that the directory has the expected status. */
+  opt_rev.kind = svn_opt_revision_working;
+  sb.result_pool = b->pool;
+  SVN_ERR(svn_client_status6(NULL, ctx, sbox_wc_path(b, new_dir_path),
+                             &opt_rev, svn_depth_unknown, TRUE, TRUE,
+                             TRUE, TRUE, FALSE, TRUE, NULL,
+                             status_func, &sb, b->pool));
+  status = sb.status;
+  SVN_TEST_ASSERT(status->kind == svn_node_dir);
+  SVN_TEST_ASSERT(status->versioned);
+  SVN_TEST_ASSERT(status->conflicted);
+  SVN_TEST_ASSERT(status->node_status == svn_wc_status_normal);
+  SVN_TEST_ASSERT(status->prop_status == svn_wc_status_none);
+  SVN_TEST_ASSERT(!status->copied);
+  SVN_TEST_ASSERT(!status->switched);
+  SVN_TEST_ASSERT(!status->file_external);
+  SVN_TEST_ASSERT(status->moved_from_abspath == NULL);
+  SVN_TEST_ASSERT(status->moved_to_abspath == NULL);
+
+  SVN_ERR(svn_client_conflict_get(&conflict, sbox_wc_path(b, new_dir_path),
+                                  ctx, b->pool, b->pool));
+
+  /* Ensure that the expected tree conflict is present. */
+  SVN_ERR(svn_client_conflict_get_conflicted(NULL, NULL, &tree_conflicted,
+                                             conflict, b->pool, b->pool));
+  SVN_TEST_ASSERT(tree_conflicted);
+  SVN_TEST_ASSERT(svn_client_conflict_get_local_change(conflict) ==
+                  svn_wc_conflict_reason_obstructed);
+  SVN_TEST_ASSERT(svn_client_conflict_get_incoming_change(conflict) ==
+                  svn_wc_conflict_action_add);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_option_merge_incoming_added_dir_ignore(const svn_test_opts_t *opts,
+                                            apr_pool_t *pool)
+{
+  svn_client_ctx_t *ctx;
+  svn_client_conflict_t *conflict;
+  const char *new_dir_path;
+  svn_boolean_t text_conflicted;
+  apr_array_header_t *props_conflicted;
+  svn_boolean_t tree_conflicted;
+  struct status_baton sb;
+  struct svn_client_status_t *status;
+  svn_opt_revision_t opt_rev;
+  svn_test__sandbox_t *b = apr_palloc(pool, sizeof(*b));
+
+  SVN_ERR(svn_test__sandbox_create(b, "incoming_added_dir_ignore",
+                                   opts, pool));
+
+  SVN_ERR(create_wc_with_dir_add_vs_dir_add_merge_conflict(b));
+
+  /* Resolve the tree conflict. */
+  SVN_ERR(svn_test__create_client_ctx(&ctx, b, b->pool));
+  new_dir_path = svn_relpath_join(branch_path, new_dir_name, b->pool);
+  SVN_ERR(svn_client_conflict_get(&conflict, sbox_wc_path(b, new_dir_path),
+                                  ctx, b->pool, b->pool));
+  SVN_ERR(svn_client_conflict_tree_resolve_by_id(
+            conflict,
+            svn_client_conflict_option_merge_incoming_add_ignore,
+            b->pool));
+
+  /* Ensure that the directory has the expected status. */
+  opt_rev.kind = svn_opt_revision_working;
+  sb.result_pool = b->pool;
+  SVN_ERR(svn_client_status6(NULL, ctx, sbox_wc_path(b, new_dir_path),
+                             &opt_rev, svn_depth_unknown, TRUE, TRUE,
+                             TRUE, TRUE, FALSE, TRUE, NULL,
+                             status_func, &sb, b->pool));
+  status = sb.status;
+  SVN_TEST_ASSERT(status->kind == svn_node_dir);
+  SVN_TEST_ASSERT(status->versioned);
+  SVN_TEST_ASSERT(!status->conflicted);
+  SVN_TEST_ASSERT(status->node_status == svn_wc_status_normal);
+  SVN_TEST_ASSERT(status->text_status == svn_wc_status_normal);
+  SVN_TEST_ASSERT(status->prop_status == svn_wc_status_none);
+  SVN_TEST_ASSERT(!status->copied);
+  SVN_TEST_ASSERT(!status->switched);
+  SVN_TEST_ASSERT(!status->file_external);
+  SVN_TEST_ASSERT(status->moved_from_abspath == NULL);
+  SVN_TEST_ASSERT(status->moved_to_abspath == NULL);
+
+  SVN_ERR(svn_client_conflict_get(&conflict, sbox_wc_path(b, new_dir_path),
+                                  ctx, b->pool, b->pool));
+
+  /* The file should not be in conflict. */
+  SVN_ERR(svn_client_conflict_get_conflicted(&text_conflicted,
+                                             &props_conflicted,
+                                             &tree_conflicted,
+                                             conflict, b->pool, b->pool));
+  SVN_TEST_ASSERT(!text_conflicted &&
+                  props_conflicted->nelts == 0 &&
+                  !tree_conflicted);
+
+  return SVN_NO_ERROR;
+}
+
 /* ========================================================================== 
*/
 
 
@@ -465,6 +631,8 @@ static struct svn_test_descriptor_t test
                        "test incoming add file replace"),
     SVN_TEST_OPTS_PASS(test_option_merge_incoming_added_file_replace_and_merge,
                        "test incoming add file replace and merge"),
+    SVN_TEST_OPTS_PASS(test_option_merge_incoming_added_dir_ignore,
+                       "test incoming add dir ignore"),
     SVN_TEST_NULL
   };
 


Reply via email to