diff options
Diffstat (limited to 'subversion/libsvn_client')
-rw-r--r-- | subversion/libsvn_client/commit_util.c | 118 | ||||
-rw-r--r-- | subversion/libsvn_client/export.c | 5 | ||||
-rw-r--r-- | subversion/libsvn_client/merge.c | 159 | ||||
-rw-r--r-- | subversion/libsvn_client/prop_commands.c | 18 |
4 files changed, 196 insertions, 104 deletions
diff --git a/subversion/libsvn_client/commit_util.c b/subversion/libsvn_client/commit_util.c index 1e2c50cd9e617..a32ec5d3ef807 100644 --- a/subversion/libsvn_client/commit_util.c +++ b/subversion/libsvn_client/commit_util.c @@ -892,7 +892,7 @@ harvest_status_callback(void *status_baton, if (matches_changelists && (is_harvest_root || baton->changelists) && state_flags - && is_added + && (is_added || (is_deleted && is_op_root && status->copied)) && baton->danglers) { /* If a node is added, its parent must exist in the repository at the @@ -966,17 +966,19 @@ struct handle_descendants_baton void *cancel_baton; svn_client__check_url_kind_t check_url_func; void *check_url_baton; + svn_client__committables_t *committables; }; /* Helper for the commit harvesters */ static svn_error_t * handle_descendants(void *baton, - const void *key, apr_ssize_t klen, void *val, - apr_pool_t *pool) + const void *key, apr_ssize_t klen, void *val, + apr_pool_t *pool) { struct handle_descendants_baton *hdb = baton; apr_array_header_t *commit_items = val; apr_pool_t *iterpool = svn_pool_create(pool); + const char *repos_root_url = key; int i; for (i = 0; i < commit_items->nelts; i++) @@ -1002,32 +1004,64 @@ handle_descendants(void *baton, for (j = 0; j < absent_descendants->nelts; j++) { - int k; - svn_boolean_t found_item = FALSE; svn_node_kind_t kind; + svn_client_commit_item3_t *desc_item; const char *relpath = APR_ARRAY_IDX(absent_descendants, j, const char *); const char *local_abspath = svn_dirent_join(item->path, relpath, iterpool); - /* If the path has a commit operation, we do nothing. - (It will be deleted by the operation) */ - for (k = 0; k < commit_items->nelts; k++) + /* ### Need a sub-iterpool? */ + + + /* We found a 'not present' descendant during a copy (at op_depth>0), + this is most commonly caused by copying some mixed revision tree. + + In this case not present can imply that the node does not exist + in the parent revision, or that the node does. But we want to copy + the working copy state in which it does not exist, but might be + replaced. */ + + desc_item = svn_hash_gets(hdb->committables->by_path, local_abspath); + + /* If the path has a commit operation (possibly at an higher + op_depth, we might want to turn an add in a replace. */ + if (desc_item) { - svn_client_commit_item3_t *cmt_item = - APR_ARRAY_IDX(commit_items, k, svn_client_commit_item3_t *); + const char *dir; + svn_boolean_t found_intermediate = FALSE; + + if (desc_item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE) + continue; /* We already have a delete or replace */ + else if (!(desc_item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)) + continue; /* Not a copy/add, just a modification */ - if (! strcmp(cmt_item->path, local_abspath)) + dir = svn_dirent_dirname(local_abspath, iterpool); + + while (strcmp(dir, item->path)) { - found_item = TRUE; - break; + svn_client_commit_item3_t *i_item; + + i_item = svn_hash_gets(hdb->committables->by_path, dir); + + if (i_item) + { + if ((i_item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE) + || (i_item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)) + { + found_intermediate = TRUE; + break; + } + } + dir = svn_dirent_dirname(dir, iterpool); } - } - if (found_item) - continue; /* We have an explicit delete or replace for this path */ + if (found_intermediate) + continue; /* Some intermediate ancestor is an add or delete */ - /* ### Need a sub-iterpool? */ + /* Fall through to detect if we need to turn the add in a + replace. */ + } if (hdb->check_url_func) { @@ -1045,25 +1079,35 @@ handle_descendants(void *baton, else kind = svn_node_unknown; /* 'Ok' for a delete of something */ - { - /* Add a new commit item that describes the delete */ - apr_pool_t *result_pool = commit_items->pool; - svn_client_commit_item3_t *new_item - = svn_client_commit_item3_create(result_pool); - - new_item->path = svn_dirent_join(item->path, relpath, - result_pool); - new_item->kind = kind; - new_item->url = svn_path_url_add_component2(item->url, relpath, - result_pool); - new_item->revision = SVN_INVALID_REVNUM; - new_item->state_flags = SVN_CLIENT_COMMIT_ITEM_DELETE; - new_item->incoming_prop_changes = apr_array_make(result_pool, 1, - sizeof(svn_prop_t *)); - - APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) - = new_item; - } + if (desc_item) + { + /* Extend the existing add/copy item to create a replace */ + desc_item->state_flags |= SVN_CLIENT_COMMIT_ITEM_DELETE; + continue; + } + + /* Add a new commit item that describes the delete */ + + SVN_ERR(add_committable(hdb->committables, + svn_dirent_join(item->path, relpath, + iterpool), + kind, + repos_root_url, + svn_uri_skip_ancestor( + repos_root_url, + svn_path_url_add_component2(item->url, + relpath, + iterpool), + iterpool), + SVN_INVALID_REVNUM, + NULL /* copyfrom_relpath */, + SVN_INVALID_REVNUM, + NULL /* moved_from_abspath */, + SVN_CLIENT_COMMIT_ITEM_DELETE, + NULL /* lock tokens */, + NULL /* lock */, + commit_items->pool, + iterpool)); } } @@ -1181,6 +1225,7 @@ svn_client__harvest_committables(svn_client__committables_t **committables, hdb.cancel_baton = ctx->cancel_baton; hdb.check_url_func = check_url_func; hdb.check_url_baton = check_url_baton; + hdb.committables = *committables; SVN_ERR(svn_iter_apr_hash(NULL, (*committables)->by_repository, handle_descendants, &hdb, iterpool)); @@ -1274,6 +1319,7 @@ harvest_copy_committables(void *baton, void *item, apr_pool_t *pool) hdb.cancel_baton = btn->ctx->cancel_baton; hdb.check_url_func = btn->check_url_func; hdb.check_url_baton = btn->check_url_baton; + hdb.committables = btn->committables; SVN_ERR(svn_iter_apr_hash(NULL, btn->committables->by_repository, handle_descendants, &hdb, pool)); diff --git a/subversion/libsvn_client/export.c b/subversion/libsvn_client/export.c index d6022ed68f291..c14a5f0bc0178 100644 --- a/subversion/libsvn_client/export.c +++ b/subversion/libsvn_client/export.c @@ -267,7 +267,9 @@ export_node(void *baton, scratch_pool)); } - if (status->file_external) + /* Skip file externals if they are a descendant of the export, + BUT NOT if we are explictly exporting the file external. */ + if (status->file_external && strcmp(eib->origin_abspath, local_abspath) != 0) return SVN_NO_ERROR; /* Produce overwrite errors for the export root */ @@ -1587,3 +1589,4 @@ svn_client_export5(svn_revnum_t *result_rev, return SVN_NO_ERROR; } + diff --git a/subversion/libsvn_client/merge.c b/subversion/libsvn_client/merge.c index cb07f8303c2b3..b314e8409b2a3 100644 --- a/subversion/libsvn_client/merge.c +++ b/subversion/libsvn_client/merge.c @@ -322,6 +322,10 @@ typedef struct merge_cmd_baton_t { const char *diff3_cmd; const apr_array_header_t *merge_options; + /* Array of file extension patterns to preserve as extensions in + generated conflict files. */ + const apr_array_header_t *ext_patterns; + /* RA sessions used throughout a merge operation. Opened/re-parented as needed. @@ -2023,17 +2027,36 @@ merge_file_changed(const char *relpath, { svn_boolean_t has_local_mods; enum svn_wc_merge_outcome_t content_outcome; + const char *target_label; + const char *left_label; + const char *right_label; + const char *path_ext = ""; + + if (merge_b->ext_patterns && merge_b->ext_patterns->nelts) + { + svn_path_splitext(NULL, &path_ext, local_abspath, scratch_pool); + if (! (*path_ext + && svn_cstring_match_glob_list(path_ext, + merge_b->ext_patterns))) + { + path_ext = ""; + } + } /* xgettext: the '.working', '.merge-left.r%ld' and '.merge-right.r%ld' strings are used to tag onto a file name in case of a merge conflict */ - const char *target_label = _(".working"); - const char *left_label = apr_psprintf(scratch_pool, - _(".merge-left.r%ld"), - left_source->revision); - const char *right_label = apr_psprintf(scratch_pool, - _(".merge-right.r%ld"), - right_source->revision); + + target_label = apr_psprintf(scratch_pool, _(".working%s%s"), + *path_ext ? "." : "", path_ext); + left_label = apr_psprintf(scratch_pool, + _(".merge-left.r%ld%s%s"), + left_source->revision, + *path_ext ? "." : "", path_ext); + right_label = apr_psprintf(scratch_pool, + _(".merge-right.r%ld%s%s"), + right_source->revision, + *path_ext ? "." : "", path_ext); SVN_ERR(svn_wc_text_modified_p2(&has_local_mods, ctx->wc_ctx, local_abspath, FALSE, scratch_pool)); @@ -3062,7 +3085,6 @@ merge_dir_deleted(const char *relpath, struct merge_dir_baton_t *db = dir_baton; const char *local_abspath = svn_dirent_join(merge_b->target->abspath, relpath, scratch_pool); - struct dir_delete_baton_t *delb; svn_boolean_t same; apr_hash_t *working_props; @@ -3093,66 +3115,69 @@ merge_dir_deleted(const char *relpath, scratch_pool, scratch_pool)); if (merge_b->force_delete) - same = TRUE; + { + /* In this legacy mode we just assume that a directory delete + matches any directory. db->delete_state is NULL */ + same = TRUE; + } else { + struct dir_delete_baton_t *delb; + /* Compare the properties */ SVN_ERR(properties_same_p(&same, left_props, working_props, scratch_pool)); - } + delb = db->delete_state; + assert(delb != NULL); - delb = db->delete_state; - assert(delb != NULL); - - if (! same) - { - delb->found_edit = TRUE; - } - else - { - store_path(delb->compared_abspaths, local_abspath); - } + if (! same) + { + delb->found_edit = TRUE; + } + else + { + store_path(delb->compared_abspaths, local_abspath); + } - if (delb->del_root != db) - return SVN_NO_ERROR; + if (delb->del_root != db) + return SVN_NO_ERROR; - if (delb->found_edit) - same = FALSE; - else if (merge_b->force_delete) - same = TRUE; - else - { - apr_array_header_t *ignores; - svn_error_t *err; - same = TRUE; + if (delb->found_edit) + same = FALSE; + else + { + apr_array_header_t *ignores; + svn_error_t *err; + same = TRUE; - SVN_ERR(svn_wc_get_default_ignores(&ignores, merge_b->ctx->config, - scratch_pool)); + SVN_ERR(svn_wc_get_default_ignores(&ignores, merge_b->ctx->config, + scratch_pool)); - /* None of the descendants was modified, but maybe there are - descendants we haven't walked? - - Note that we aren't interested in changes, as we already verified - changes in the paths touched by the merge. And the existance of - other paths is enough to mark the directory edited */ - err = svn_wc_walk_status(merge_b->ctx->wc_ctx, local_abspath, - svn_depth_infinity, TRUE /* get-all */, - FALSE /* no-ignore */, - TRUE /* ignore-text-mods */, ignores, - verify_touched_by_del_check, delb, - merge_b->ctx->cancel_func, - merge_b->ctx->cancel_baton, - scratch_pool); + /* None of the descendants was modified, but maybe there are + descendants we haven't walked? + + Note that we aren't interested in changes, as we already verified + changes in the paths touched by the merge. And the existence of + other paths is enough to mark the directory edited */ + err = svn_wc_walk_status(merge_b->ctx->wc_ctx, local_abspath, + svn_depth_infinity, TRUE /* get-all */, + FALSE /* no-ignore */, + TRUE /* ignore-text-mods */, ignores, + verify_touched_by_del_check, delb, + merge_b->ctx->cancel_func, + merge_b->ctx->cancel_baton, + scratch_pool); + + if (err) + { + if (err->apr_err != SVN_ERR_CEASE_INVOCATION) + return svn_error_trace(err); - if (err) - { - if (err->apr_err != SVN_ERR_CEASE_INVOCATION) - return svn_error_trace(err); + svn_error_clear(err); + } - svn_error_clear(err); + same = ! delb->found_edit; } - - same = ! delb->found_edit; } if (same && !merge_b->dry_run) @@ -9668,6 +9693,7 @@ do_merge(apr_hash_t **modified_subtrees, merge_cmd_baton_t merge_cmd_baton = { 0 }; svn_config_t *cfg; const char *diff3_cmd; + const char *preserved_exts_str; int i; svn_boolean_t checked_mergeinfo_capability = FALSE; svn_ra_session_t *ra_session1 = NULL, *ra_session2 = NULL; @@ -9728,6 +9754,11 @@ do_merge(apr_hash_t **modified_subtrees, if (diff3_cmd != NULL) SVN_ERR(svn_path_cstring_to_utf8(&diff3_cmd, diff3_cmd, scratch_pool)); + /* See which files the user wants to preserve the extension of when + conflict files are made. */ + svn_config_get(cfg, &preserved_exts_str, SVN_CONFIG_SECTION_MISCELLANY, + SVN_CONFIG_OPTION_PRESERVED_CF_EXTS, ""); + /* Build the merge context baton (or at least the parts of it that don't need to be reset for each merge source). */ merge_cmd_baton.force_delete = force_delete; @@ -9743,6 +9774,11 @@ do_merge(apr_hash_t **modified_subtrees, merge_cmd_baton.pool = iterpool; merge_cmd_baton.merge_options = merge_options; merge_cmd_baton.diff3_cmd = diff3_cmd; + merge_cmd_baton.ext_patterns = *preserved_exts_str + ? svn_cstring_split(preserved_exts_str, "\n\r\t\v ", + FALSE, scratch_pool) + : NULL; + merge_cmd_baton.use_sleep = use_sleep; /* Do we already know the specific subtrees with mergeinfo we want @@ -10447,15 +10483,10 @@ merge_locked(conflict_report_t **conflict_report, } else { - merge_source_t source; - - source.loc1 = source1_loc; - source.loc2 = source2_loc; - source.ancestral = FALSE; - /* Build a single-item merge_source_t array. */ merge_sources = apr_array_make(scratch_pool, 1, sizeof(merge_source_t *)); - APR_ARRAY_PUSH(merge_sources, merge_source_t *) = &source; + APR_ARRAY_PUSH(merge_sources, merge_source_t *) + = merge_source_create(source1_loc, source2_loc, FALSE, scratch_pool); } err = do_merge(NULL, NULL, conflict_report, &use_sleep, @@ -10761,7 +10792,7 @@ log_find_operative_revs(void *baton, UNMERGED_CATALOG represents the history (as mergeinfo) from TARGET_LOC that is not represented in SOURCE_LOC's explicit/inherited mergeinfo as represented by MERGED_CATALOG. - MERGEINFO_CATALOG may be empty if the source has no explicit or inherited + MERGED_CATALOG may be empty if the source has no explicit or inherited mergeinfo. Check that all of the unmerged revisions in UNMERGED_CATALOG's @@ -11464,7 +11495,7 @@ find_reintegrate_merge(merge_source_t **source_p, prefix. */ svn_mergeinfo_catalog_t final_unmerged_catalog = apr_hash_make(scratch_pool); - SVN_ERR(find_unsynced_ranges(source_loc, yc_ancestor, + SVN_ERR(find_unsynced_ranges(source_loc, &target->loc, unmerged_to_source_mergeinfo_catalog, merged_to_source_mergeinfo_catalog, final_unmerged_catalog, diff --git a/subversion/libsvn_client/prop_commands.c b/subversion/libsvn_client/prop_commands.c index a3e59c866813d..06c4d21dc1e06 100644 --- a/subversion/libsvn_client/prop_commands.c +++ b/subversion/libsvn_client/prop_commands.c @@ -890,8 +890,14 @@ svn_client_propget5(apr_hash_t **props, const char *copy_root_abspath; svn_boolean_t is_copy; - SVN_ERR(svn_dirent_get_absolute(&local_abspath, target, - scratch_pool)); + /* Avoid assertion on the next line when somebody accidentally asks for + a working copy revision on a URL */ + if (svn_path_is_url(target)) + return svn_error_create(SVN_ERR_CLIENT_VERSIONED_PATH_REQUIRED, + NULL, NULL); + + SVN_ERR_ASSERT(svn_dirent_is_absolute(target)); + local_abspath = target; if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind)) { @@ -1232,7 +1238,7 @@ recursive_proplist_receiver(void *baton, Report iprops anyway */ SVN_ERR(b->wrapped_receiver(b->wrapped_receiver_baton, - b->anchor ? b->anchor : local_abspath, + b->anchor ? b->anchor : b->anchor_abspath, NULL /* prop_hash */, b->iprops, scratch_pool)); @@ -1293,6 +1299,12 @@ get_remote_props(const char *path_or_url, const char *copy_root_abspath; svn_boolean_t is_copy; + /* Avoid assertion on the next line when somebody accidentally asks for + a working copy revision on a URL */ + if (svn_path_is_url(path_or_url)) + return svn_error_create(SVN_ERR_CLIENT_VERSIONED_PATH_REQUIRED, + NULL, NULL); + SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url, scratch_pool)); |