Author: julianfoad Date: Mon Sep 24 16:37:53 2018 New Revision: 1841874 URL: http://svn.apache.org/viewvc?rev=1841874&view=rev Log: Merge the r1841719 group from trunk:
* r1841719, r1841742 Add support for 'local missing' conflicts with directories. Justification: This case already works with files. Now also works with directories. Notes: merge needs --accept=12 Votes: +1: stsp, jcorvel, julianfoad Modified: subversion/branches/1.11.x/ (props changed) subversion/branches/1.11.x/STATUS subversion/branches/1.11.x/subversion/libsvn_client/conflicts.c subversion/branches/1.11.x/subversion/tests/libsvn_client/conflicts-test.c Propchange: subversion/branches/1.11.x/ ------------------------------------------------------------------------------ --- svn:mergeinfo (original) +++ svn:mergeinfo Mon Sep 24 16:37:53 2018 @@ -100,4 +100,4 @@ /subversion/branches/verify-at-commit:1462039-1462408 /subversion/branches/verify-keep-going:1439280-1546110 /subversion/branches/wc-collate-path:1402685-1480384 -/subversion/trunk:1840990-1840991,1840995,1840997,1841059,1841079,1841091,1841098,1841136,1841180,1841272,1841481,1841524-1841525,1841567,1841600-1841602,1841606,1841731,1841736,1841743,1841753-1841754,1841822,1841867 +/subversion/trunk:1840990-1840991,1840995,1840997,1841059,1841079,1841091,1841098,1841136,1841180,1841272,1841481,1841524-1841525,1841567,1841600-1841602,1841606,1841719,1841731,1841736,1841742-1841743,1841753-1841754,1841822,1841867 Modified: subversion/branches/1.11.x/STATUS URL: http://svn.apache.org/viewvc/subversion/branches/1.11.x/STATUS?rev=1841874&r1=1841873&r2=1841874&view=diff ============================================================================== --- subversion/branches/1.11.x/STATUS (original) +++ subversion/branches/1.11.x/STATUS Mon Sep 24 16:37:53 2018 @@ -29,11 +29,3 @@ Veto-blocked changes: Approved changes: ================= - - * r1841719, r1841742 - Add support for 'local missing' conflicts with directories. - Justification: - This case already works with files. Now also works with directories. - Notes: merge needs --accept=12 - Votes: - +1: stsp, jcorvel, julianfoad Modified: subversion/branches/1.11.x/subversion/libsvn_client/conflicts.c URL: http://svn.apache.org/viewvc/subversion/branches/1.11.x/subversion/libsvn_client/conflicts.c?rev=1841874&r1=1841873&r2=1841874&view=diff ============================================================================== --- subversion/branches/1.11.x/subversion/libsvn_client/conflicts.c (original) +++ subversion/branches/1.11.x/subversion/libsvn_client/conflicts.c Mon Sep 24 16:37:53 2018 @@ -3032,7 +3032,7 @@ conflict_tree_get_details_local_missing( move = APR_ARRAY_IDX(details->moves, i, struct repos_move_info *); SVN_ERR(follow_move_chains(details->wc_move_targets, move, ctx, conflict->local_abspath, - svn_node_file, + new_kind, new_repos_relpath, new_rev, scratch_pool, iterpool)); @@ -3064,7 +3064,25 @@ conflict_tree_get_details_local_missing( details->sibling_moves = sibling_moves; details->wc_siblings = wc_siblings; - if (details->wc_siblings && details->wc_siblings->nelts == 1) + if (details->wc_move_targets && apr_hash_count(details->wc_move_targets) == 1) + { + apr_array_header_t *wc_abspaths; + + wc_abspaths = svn_hash_gets(details->wc_move_targets, + details->move_target_repos_relpath); + if (wc_abspaths->nelts == 1) + { + svn_node_kind_t kind = old_rev < new_rev ? new_kind : old_kind; + + if (kind == svn_node_file) + conflict->recommended_option_id = + svn_client_conflict_option_local_move_file_text_merge; + else if (kind == svn_node_dir) + conflict->recommended_option_id = + svn_client_conflict_option_local_move_dir_merge; + } + } + else if (details->wc_siblings && details->wc_siblings->nelts == 1) { svn_node_kind_t kind = old_rev < new_rev ? new_kind : old_kind; @@ -9230,10 +9248,10 @@ resolve_local_move_file_merge(svn_client /* Implements conflict_option_resolve_func_t. */ static svn_error_t * -resolve_sibling_move_dir_merge(svn_client_conflict_option_t *option, - svn_client_conflict_t *conflict, - svn_client_ctx_t *ctx, - apr_pool_t *scratch_pool) +resolve_local_move_dir_merge(svn_client_conflict_option_t *option, + svn_client_conflict_t *conflict, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) { const char *lock_abspath; svn_error_t *err; @@ -9264,9 +9282,19 @@ resolve_sibling_move_dir_merge(svn_clien NULL, conflict, scratch_pool, scratch_pool)); - merge_target_abspath = APR_ARRAY_IDX(details->wc_siblings, - details->preferred_sibling_idx, - const char *); + if (details->wc_move_targets) + { + apr_array_header_t *moves; + + moves = svn_hash_gets(details->wc_move_targets, + details->move_target_repos_relpath); + merge_target_abspath = + APR_ARRAY_IDX(moves, details->wc_move_target_idx, const char *); + } + else + merge_target_abspath = APR_ARRAY_IDX(details->wc_siblings, + details->preferred_sibling_idx, + const char *); /* ### The following WC modifications should be atomic. */ SVN_ERR(svn_wc__acquire_write_lock_for_resolve( @@ -9283,7 +9311,7 @@ resolve_sibling_move_dir_merge(svn_clien if (err) goto unlock_wc; - /* Merge outstanding changes to the sibling merge target. */ + /* Merge outstanding changes to the merge target. */ incoming_old_url = apr_pstrcat(scratch_pool, repos_root_url, "/", incoming_old_repos_relpath, SVN_VA_NULL); incoming_old_opt_rev.kind = svn_opt_revision_number; @@ -10341,10 +10369,11 @@ configure_option_incoming_dir_merge(svn_ /* Configure 'local move file merge' resolution option for * a tree conflict. */ static svn_error_t * -configure_option_local_move_file_merge(svn_client_conflict_t *conflict, - svn_client_ctx_t *ctx, - apr_array_header_t *options, - apr_pool_t *scratch_pool) +configure_option_local_move_file_or_dir_merge( + svn_client_conflict_t *conflict, + svn_client_ctx_t *ctx, + apr_array_header_t *options, + apr_pool_t *scratch_pool) { svn_wc_operation_t operation; svn_wc_conflict_action_t incoming_change; @@ -10370,12 +10399,7 @@ configure_option_local_move_file_merge(s if (operation == svn_wc_operation_merge && incoming_change == svn_wc_conflict_action_edit && - local_change == svn_wc_conflict_reason_missing && - /* We do not support this case for directories yet. */ - (incoming_old_kind == svn_node_file || - incoming_old_kind == svn_node_none) && - (incoming_new_kind == svn_node_file || - incoming_new_kind == svn_node_none)) + local_change == svn_wc_conflict_reason_missing) { struct conflict_tree_local_missing_details *details; const char *wcroot_abspath; @@ -10404,11 +10428,25 @@ configure_option_local_move_file_merge(s svn_dirent_skip_ancestor(wcroot_abspath, moved_to_abspath), scratch_pool)); - add_resolution_option( - options, conflict, - svn_client_conflict_option_local_move_file_text_merge, - _("Apply to move destination"), - description, resolve_local_move_file_merge); + if ((incoming_old_kind == svn_node_file || + incoming_old_kind == svn_node_none) && + (incoming_new_kind == svn_node_file || + incoming_new_kind == svn_node_none)) + { + add_resolution_option( + options, conflict, + svn_client_conflict_option_local_move_file_text_merge, + _("Apply to move destination"), + description, resolve_local_move_file_merge); + } + else + { + add_resolution_option( + options, conflict, + svn_client_conflict_option_local_move_dir_merge, + _("Apply to move destination"), + description, resolve_local_move_dir_merge); + } } } @@ -10491,7 +10529,7 @@ configure_option_sibling_move_merge(svn_ options, conflict, svn_client_conflict_option_sibling_move_dir_merge, _("Apply to corresponding local location"), - description, resolve_sibling_move_dir_merge); + description, resolve_local_move_dir_merge); } } } @@ -11119,8 +11157,9 @@ svn_client_conflict_tree_get_resolution_ scratch_pool)); SVN_ERR(configure_option_incoming_dir_merge(conflict, ctx, *options, scratch_pool)); - SVN_ERR(configure_option_local_move_file_merge(conflict, ctx, *options, - scratch_pool)); + SVN_ERR(configure_option_local_move_file_or_dir_merge(conflict, ctx, + *options, + scratch_pool)); SVN_ERR(configure_option_sibling_move_merge(conflict, ctx, *options, scratch_pool)); Modified: subversion/branches/1.11.x/subversion/tests/libsvn_client/conflicts-test.c URL: http://svn.apache.org/viewvc/subversion/branches/1.11.x/subversion/tests/libsvn_client/conflicts-test.c?rev=1841874&r1=1841873&r2=1841874&view=diff ============================================================================== --- subversion/branches/1.11.x/subversion/tests/libsvn_client/conflicts-test.c (original) +++ subversion/branches/1.11.x/subversion/tests/libsvn_client/conflicts-test.c Mon Sep 24 16:37:53 2018 @@ -5880,6 +5880,185 @@ test_local_missing_abiguous_moves(const } static svn_error_t * +test_local_missing_abiguous_moves_dir(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_test__sandbox_t *b = apr_palloc(pool, sizeof(*b)); + svn_opt_revision_t opt_rev; + svn_client_ctx_t *ctx; + svn_client_conflict_t *conflict; + apr_array_header_t *options; + svn_client_conflict_option_t *option; + apr_array_header_t *possible_moved_to_repos_relpaths; + apr_array_header_t *possible_moved_to_abspaths; + struct status_baton sb; + struct svn_client_status_t *status; + svn_stringbuf_t *buf; + + SVN_ERR(svn_test__sandbox_create(b, "local_missing_ambiguous_moves_dir", + opts, pool)); + + SVN_ERR(sbox_add_and_commit_greek_tree(b)); /* r1 */ + + /* Create a copy of node "A" (the "trunk") to "A1" (the "branch"). */ + SVN_ERR(sbox_wc_copy(b, "A", "A1")); + SVN_ERR(sbox_wc_commit(b, "")); /* r2 */ + + SVN_ERR(sbox_wc_update(b, "", SVN_INVALID_REVNUM)); + /* Copy a dir across branch boundaries (gives ambiguous WC targets later). */ + SVN_ERR(sbox_wc_copy(b, "A/B", "A1/B-copied-from-A")); + /* Create an ambiguous move with the "trunk". */ + SVN_ERR(sbox_wc_copy(b, "A/B", "A/B-copied")); + SVN_ERR(sbox_wc_move(b, "A/B", "A/B-moved")); + SVN_ERR(sbox_wc_commit(b, "")); /* r3 */ + + /* Modify a file in the moved directory on the "branch". */ + SVN_ERR(sbox_file_write(b, "A1/B/lambda", "Modified content." APR_EOL_STR)); + SVN_ERR(sbox_wc_commit(b, "")); /* r4 */ + SVN_ERR(sbox_wc_update(b, "", SVN_INVALID_REVNUM)); + + /* Merge "A1" ("branch") into "A" ("trunk"). */ + opt_rev.kind = svn_opt_revision_head; + opt_rev.value.number = SVN_INVALID_REVNUM; + SVN_ERR(svn_test__create_client_ctx(&ctx, b, pool)); + SVN_ERR(svn_client_merge_peg5(svn_path_url_add_component2(b->repos_url, "A1", + pool), + NULL, &opt_rev, sbox_wc_path(b, "A"), + svn_depth_infinity, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + NULL, ctx, pool)); + + SVN_ERR(svn_client_conflict_get(&conflict, sbox_wc_path(b, "A/B"), + ctx, b->pool, b->pool)); + { + svn_client_conflict_option_id_t expected_opts[] = { + svn_client_conflict_option_postpone, + svn_client_conflict_option_accept_current_wc_state, + -1 /* end of list */ + }; + SVN_ERR(assert_tree_conflict_options(conflict, ctx, expected_opts, + b->pool)); + } + SVN_ERR(svn_client_conflict_tree_get_details(conflict, ctx, b->pool)); + { + svn_client_conflict_option_id_t expected_opts[] = { + svn_client_conflict_option_postpone, + svn_client_conflict_option_accept_current_wc_state, + svn_client_conflict_option_local_move_dir_merge, + -1 /* end of list */ + }; + SVN_ERR(assert_tree_conflict_options(conflict, ctx, expected_opts, + b->pool)); + } + + SVN_ERR(svn_client_conflict_tree_get_resolution_options(&options, conflict, + ctx, b->pool, + b->pool)); + option = svn_client_conflict_option_find_by_id( + options, svn_client_conflict_option_local_move_dir_merge); + SVN_TEST_ASSERT(option != NULL); + + /* + * Possible repository destinations for moved-away 'A/mu' are: + * (1): '^/A/B-copied' + * (2): '^/A/B-moved' + * (3): '^/A1/B-copied-from-A' + */ + SVN_ERR(svn_client_conflict_option_get_moved_to_repos_relpath_candidates( + &possible_moved_to_repos_relpaths, option, b->pool, b->pool)); + SVN_TEST_INT_ASSERT(possible_moved_to_repos_relpaths->nelts, 3); + SVN_TEST_STRING_ASSERT( + APR_ARRAY_IDX(possible_moved_to_repos_relpaths, 0, const char *), + "A/B-copied"); + SVN_TEST_STRING_ASSERT( + APR_ARRAY_IDX(possible_moved_to_repos_relpaths, 1, const char *), + "A/B-moved"); + SVN_TEST_STRING_ASSERT( + APR_ARRAY_IDX(possible_moved_to_repos_relpaths, 2, const char *), + "A1/B-copied-from-A"); + + /* Move target for "A/B-copied" (selected by default) is not ambiguous. */ + SVN_ERR(svn_client_conflict_option_get_moved_to_abspath_candidates( + &possible_moved_to_abspaths, option, b->pool, b->pool)); + SVN_TEST_INT_ASSERT(possible_moved_to_abspaths->nelts, 1); + SVN_TEST_STRING_ASSERT( + APR_ARRAY_IDX(possible_moved_to_abspaths, 0, const char *), + sbox_wc_path(b, "A/B-copied")); + + /* Move target for "A/mu-moved" is not ambiguous. */ + SVN_ERR(svn_client_conflict_option_set_moved_to_repos_relpath(option, 1, + ctx, b->pool)); + SVN_ERR(svn_client_conflict_option_get_moved_to_abspath_candidates( + &possible_moved_to_abspaths, option, b->pool, b->pool)); + SVN_TEST_INT_ASSERT(possible_moved_to_abspaths->nelts, 1); + SVN_TEST_STRING_ASSERT( + APR_ARRAY_IDX(possible_moved_to_abspaths, 0, const char *), + sbox_wc_path(b, "A/B-moved")); + + /* Select move target "A1/mu-copied-from-A". */ + SVN_ERR(svn_client_conflict_option_set_moved_to_repos_relpath(option, 2, + ctx, b->pool)); + + /* + * Possible working copy destinations for moved-away 'A/mu' are: + * (1): 'A/B-copied-from-A' + * (2): 'A1/B-copied-from-A' + */ + SVN_ERR(svn_client_conflict_option_get_moved_to_abspath_candidates( + &possible_moved_to_abspaths, option, b->pool, b->pool)); + SVN_TEST_INT_ASSERT(possible_moved_to_abspaths->nelts, 2); + SVN_TEST_STRING_ASSERT( + APR_ARRAY_IDX(possible_moved_to_abspaths, 0, const char *), + sbox_wc_path(b, "A/B-copied-from-A")); + SVN_TEST_STRING_ASSERT( + APR_ARRAY_IDX(possible_moved_to_abspaths, 1, const char *), + sbox_wc_path(b, "A1/B-copied-from-A")); + + /* Select move target "A/B-moved". */ + SVN_ERR(svn_client_conflict_option_set_moved_to_repos_relpath(option, 1, + ctx, b->pool)); + + /* Resolve the tree conflict. */ + SVN_ERR(svn_client_conflict_tree_resolve_by_id( + conflict, + svn_client_conflict_option_local_move_dir_merge, ctx, + b->pool)); + + /* The node "A/mu" should no longer exist. */ + SVN_TEST_ASSERT_ERROR(svn_client_conflict_get(&conflict, + sbox_wc_path(b, "A/B"), + ctx, pool, pool), + SVN_ERR_WC_PATH_NOT_FOUND); + + /* Ensure that the merged file 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, "A/B-moved/lambda"), + &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_file); + SVN_TEST_ASSERT(status->versioned); + SVN_TEST_ASSERT(!status->conflicted); + SVN_TEST_ASSERT(status->node_status == svn_wc_status_modified); + SVN_TEST_ASSERT(status->text_status == svn_wc_status_modified); + 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); + + /* And it should have expected contents. */ + SVN_ERR(svn_stringbuf_from_file2(&buf, sbox_wc_path(b, "A/B-moved/lambda"), + pool)); + SVN_TEST_STRING_ASSERT(buf->data, "Modified content." APR_EOL_STR); + + return SVN_NO_ERROR; +} + +static svn_error_t * test_file_vs_dir_move_merge_assertion_failure(const svn_test_opts_t *opts, apr_pool_t *pool) { @@ -6110,6 +6289,8 @@ static struct svn_test_descriptor_t test "cherry-pick edit from moved directory"), SVN_TEST_OPTS_PASS(test_local_missing_abiguous_moves, "local missing conflict with ambiguous moves"), + SVN_TEST_OPTS_PASS(test_local_missing_abiguous_moves_dir, + "local missing conflict with ambiguous dir moves"), SVN_TEST_OPTS_PASS(test_file_vs_dir_move_merge_assertion_failure, "file v dir move merge assertion failure"), SVN_TEST_NULL