Modified: subversion/branches/ev2-export/subversion/libsvn_client/diff_local.c URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/diff_local.c?rev=1449262&r1=1449261&r2=1449262&view=diff ============================================================================== --- subversion/branches/ev2-export/subversion/libsvn_client/diff_local.c (original) +++ subversion/branches/ev2-export/subversion/libsvn_client/diff_local.c Sat Feb 23 01:25:38 2013 @@ -287,9 +287,16 @@ arbitrary_diff_walker(void *baton, const const apr_finfo_t *finfo, apr_pool_t *scratch_pool); -/* Produce a diff between two arbitrary directories at LOCAL_ABSPATH1 and - * LOCAL_ABSPATH2, using the provided diff callbacks to show file changes - * and, for versioned nodes, property changes. +/* Another forward declaration. */ +static svn_error_t * +arbitrary_diff_this_dir(struct arbitrary_diff_walker_baton *b, + const char *local_abspath, + svn_depth_t depth, + apr_pool_t *scratch_pool); + +/* Produce a diff of depth DEPTH between two arbitrary directories at + * LOCAL_ABSPATH1 and LOCAL_ABSPATH2, using the provided diff callbacks + * to show file changes and, for versioned nodes, property changes. * * If ROOT_ABSPATH1 and ROOT_ABSPATH2 are not NULL, show paths in diffs * relative to these roots, rather than relative to LOCAL_ABSPATH1 and @@ -300,6 +307,7 @@ do_arbitrary_dirs_diff(const char *local const char *local_abspath2, const char *root_abspath1, const char *root_abspath2, + svn_depth_t depth, const svn_wc_diff_callbacks4_t *callbacks, void *diff_baton, svn_client_ctx_t *ctx, @@ -331,22 +339,25 @@ do_arbitrary_dirs_diff(const char *local NULL, svn_io_file_del_on_pool_cleanup, scratch_pool, scratch_pool)); - SVN_ERR(svn_io_dir_walk2(b.recursing_within_added_subtree ? local_abspath2 - : local_abspath1, - 0, arbitrary_diff_walker, &b, scratch_pool)); - + if (depth <= svn_depth_immediates) + SVN_ERR(arbitrary_diff_this_dir(&b, local_abspath1, depth, scratch_pool)); + else if (depth == svn_depth_infinity) + SVN_ERR(svn_io_dir_walk2(b.recursing_within_added_subtree ? local_abspath2 + : local_abspath1, + 0, arbitrary_diff_walker, &b, scratch_pool)); return SVN_NO_ERROR; } -/* An implementation of svn_io_walk_func_t. - * Note: LOCAL_ABSPATH is the path being crawled and can be on either side +/* Produce a diff of depth DEPTH for the directory at LOCAL_ABSPATH, + * using information from the arbitrary_diff_walker_baton B. + * LOCAL_ABSPATH is the path being crawled and can be on either side * of the diff depending on baton->recursing_within_added_subtree. */ static svn_error_t * -arbitrary_diff_walker(void *baton, const char *local_abspath, - const apr_finfo_t *finfo, - apr_pool_t *scratch_pool) +arbitrary_diff_this_dir(struct arbitrary_diff_walker_baton *b, + const char *local_abspath, + svn_depth_t depth, + apr_pool_t *scratch_pool) { - struct arbitrary_diff_walker_baton *b = baton; const char *local_abspath1; const char *local_abspath2; svn_node_kind_t kind1; @@ -359,12 +370,6 @@ arbitrary_diff_walker(void *baton, const int i; apr_pool_t *iterpool; - if (b->ctx->cancel_func) - SVN_ERR(b->ctx->cancel_func(b->ctx->cancel_baton)); - - if (finfo->filetype != APR_DIR) - return SVN_NO_ERROR; - if (b->recursing_within_adm_dir) { if (svn_dirent_skip_ancestor(b->adm_dir_abspath, local_abspath)) @@ -398,12 +403,15 @@ arbitrary_diff_walker(void *baton, const scratch_pool); SVN_ERR(svn_io_check_resolved_path(local_abspath2, &kind2, scratch_pool)); - if (kind1 == svn_node_dir) - SVN_ERR(svn_io_get_dirents3(&dirents1, local_abspath1, - TRUE, /* only_check_type */ - scratch_pool, scratch_pool)); - else - dirents1 = apr_hash_make(scratch_pool); + if (depth > svn_depth_empty) + { + if (kind1 == svn_node_dir) + SVN_ERR(svn_io_get_dirents3(&dirents1, local_abspath1, + TRUE, /* only_check_type */ + scratch_pool, scratch_pool)); + else + dirents1 = apr_hash_make(scratch_pool); + } if (kind2 == svn_node_dir) { @@ -425,14 +433,20 @@ arbitrary_diff_walker(void *baton, const b->diff_baton, scratch_pool)); - /* Read directory entries. */ - SVN_ERR(svn_io_get_dirents3(&dirents2, local_abspath2, - TRUE, /* only_check_type */ - scratch_pool, scratch_pool)); + if (depth > svn_depth_empty) + { + /* Read directory entries. */ + SVN_ERR(svn_io_get_dirents3(&dirents2, local_abspath2, + TRUE, /* only_check_type */ + scratch_pool, scratch_pool)); + } } - else + else if (depth > svn_depth_empty) dirents2 = apr_hash_make(scratch_pool); + if (depth <= svn_depth_empty) + return SVN_NO_ERROR; + /* Compare dirents1 to dirents2 and show added/deleted/changed files. */ merged_dirents = apr_hash_merge(scratch_pool, dirents1, dirents2, NULL, NULL); @@ -482,7 +496,25 @@ arbitrary_diff_walker(void *baton, const if (dirent1->kind == svn_node_dir && dirent2->kind == svn_node_dir) - continue; + { + if (depth == svn_depth_immediates) + { + /* Not using the walker, so show property diffs on these dirs. */ + SVN_ERR(do_arbitrary_dirs_diff(child1_abspath, child2_abspath, + b->root1_abspath, b->root2_abspath, + svn_depth_empty, + b->callbacks, b->diff_baton, + b->ctx, iterpool)); + } + else + { + /* Either the walker will visit these directories (with + * depth=infinity) and they will be processed as 'this dir' + * later, or we're showing file children only (depth=files). */ + continue; + } + + } /* Files that exist only in dirents1. */ if (dirent1->kind == svn_node_file && @@ -521,10 +553,14 @@ arbitrary_diff_walker(void *baton, const /* Directories that only exist in dirents2. These aren't crawled * by this walker so we have to crawl them separately. */ - if (dirent2->kind == svn_node_dir && + if (depth > svn_depth_files && + dirent2->kind == svn_node_dir && (dirent1->kind == svn_node_file || dirent1->kind == svn_node_none)) SVN_ERR(do_arbitrary_dirs_diff(child1_abspath, child2_abspath, b->root1_abspath, b->root2_abspath, + depth <= svn_depth_immediates + ? svn_depth_empty + : svn_depth_infinity , b->callbacks, b->diff_baton, b->ctx, iterpool)); } @@ -534,14 +570,32 @@ arbitrary_diff_walker(void *baton, const return SVN_NO_ERROR; } -/* Produce a diff between two files or two directories at LOCAL_ABSPATH1 - * and LOCAL_ABSPATH2, using the provided diff callbacks to show changes - * in files. The files and directories involved may be part of a working - * copy or they may be unversioned. For versioned files, show property - * changes, too. */ +/* An implementation of svn_io_walk_func_t. + * Note: LOCAL_ABSPATH is the path being crawled and can be on either side + * of the diff depending on baton->recursing_within_added_subtree. */ +static svn_error_t * +arbitrary_diff_walker(void *baton, const char *local_abspath, + const apr_finfo_t *finfo, + apr_pool_t *scratch_pool) +{ + struct arbitrary_diff_walker_baton *b = baton; + + if (b->ctx->cancel_func) + SVN_ERR(b->ctx->cancel_func(b->ctx->cancel_baton)); + + if (finfo->filetype != APR_DIR) + return SVN_NO_ERROR; + + SVN_ERR(arbitrary_diff_this_dir(b, local_abspath, svn_depth_infinity, + scratch_pool)); + + return SVN_NO_ERROR; +} + svn_error_t * svn_client__arbitrary_nodes_diff(const char *local_abspath1, const char *local_abspath2, + svn_depth_t depth, const svn_wc_diff_callbacks4_t *callbacks, void *diff_baton, svn_client_ctx_t *ctx, @@ -558,6 +612,9 @@ svn_client__arbitrary_nodes_diff(const c _("'%s' is not the same node kind as '%s'"), local_abspath1, local_abspath2); + if (depth == svn_depth_unknown) + depth = svn_depth_infinity; + if (kind1 == svn_node_file) SVN_ERR(do_arbitrary_files_diff(local_abspath1, local_abspath2, svn_dirent_basename(local_abspath1, @@ -567,7 +624,7 @@ svn_client__arbitrary_nodes_diff(const c ctx, scratch_pool)); else if (kind1 == svn_node_dir) SVN_ERR(do_arbitrary_dirs_diff(local_abspath1, local_abspath2, - NULL, NULL, + NULL, NULL, depth, callbacks, diff_baton, ctx, scratch_pool)); else
Modified: subversion/branches/ev2-export/subversion/libsvn_client/diff_summarize.c URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/diff_summarize.c?rev=1449262&r1=1449261&r2=1449262&view=diff ============================================================================== --- subversion/branches/ev2-export/subversion/libsvn_client/diff_summarize.c (original) +++ subversion/branches/ev2-export/subversion/libsvn_client/diff_summarize.c Sat Feb 23 01:25:38 2013 @@ -77,6 +77,8 @@ send_summary(struct summarize_baton_t *b case svn_client_diff_summarize_kind_deleted: summarize_kind = svn_client_diff_summarize_kind_added; break; + default: + break; } } @@ -180,6 +182,9 @@ cb_dir_closed(svn_wc_notify_state_t *con struct summarize_baton_t *b = diff_baton; svn_boolean_t prop_change; + if (! svn_relpath_skip_ancestor(b->target, path)) + return SVN_NO_ERROR; + prop_change = apr_hash_get(b->prop_changes, path, APR_HASH_KEY_STRING) != NULL; if (dir_was_added || prop_change) SVN_ERR(send_summary(b, path, Modified: subversion/branches/ev2-export/subversion/libsvn_client/externals.c URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/externals.c?rev=1449262&r1=1449261&r2=1449262&view=diff ============================================================================== --- subversion/branches/ev2-export/subversion/libsvn_client/externals.c (original) +++ subversion/branches/ev2-export/subversion/libsvn_client/externals.c Sat Feb 23 01:25:38 2013 @@ -212,9 +212,21 @@ switch_dir_external(const char *local_ab To do so, we need to know the repository root URL of the external working copy as it currently sits. */ - SVN_ERR(svn_wc__node_get_repos_info(&repos_root_url, &repos_uuid, - ctx->wc_ctx, local_abspath, - pool, subpool)); + err = svn_wc__node_get_repos_info(NULL, NULL, + &repos_root_url, &repos_uuid, + ctx->wc_ctx, local_abspath, + pool, subpool); + if (err) + { + if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND + && err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY) + return svn_error_trace(err); + + svn_error_clear(err); + repos_root_url = NULL; + repos_uuid = NULL; + } + if (repos_root_url) { /* If the new external target URL is not obviously a @@ -315,7 +327,8 @@ switch_dir_external(const char *local_ab FALSE, FALSE, timestamp_sleep, ctx, pool)); - SVN_ERR(svn_wc__node_get_repos_info(&repos_root_url, + SVN_ERR(svn_wc__node_get_repos_info(NULL, NULL, + &repos_root_url, &repos_uuid, ctx->wc_ctx, local_abspath, pool, pool)); @@ -739,6 +752,7 @@ handle_external_item_change(svn_client_c const char *local_repos_root_url; const char *local_repos_uuid; const char *ext_repos_relpath; + svn_error_t *err; /* * The working copy library currently requires that all files @@ -749,11 +763,22 @@ handle_external_item_change(svn_client_c * sure both URLs point to the same repository. See issue #4087. */ - SVN_ERR(svn_wc__node_get_repos_info(&local_repos_root_url, - &local_repos_uuid, - ctx->wc_ctx, - parent_dir_abspath, - scratch_pool, scratch_pool)); + err = svn_wc__node_get_repos_info(NULL, NULL, + &local_repos_root_url, + &local_repos_uuid, + ctx->wc_ctx, parent_dir_abspath, + scratch_pool, scratch_pool); + if (err) + { + if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND + && err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY) + return svn_error_trace(err); + + svn_error_clear(err); + local_repos_root_url = NULL; + local_repos_uuid = NULL; + } + ext_repos_relpath = svn_uri_skip_ancestor(new_loc->repos_root_url, new_url, scratch_pool); if (local_repos_uuid == NULL || local_repos_root_url == NULL || @@ -991,12 +1016,12 @@ svn_client__handle_externals(apr_hash_t * external and the DEFINING_ABSPATH which we can remove? */ parent_abspath = item_abspath; do { - svn_wc_status3_t *parent_status; + svn_node_kind_t kind; parent_abspath = svn_dirent_dirname(parent_abspath, iterpool); - SVN_ERR(svn_wc_status3(&parent_status, ctx->wc_ctx, parent_abspath, - iterpool, iterpool)); - if (parent_status->node_status == svn_wc_status_unversioned) + SVN_ERR(svn_wc_read_kind(&kind, ctx->wc_ctx, parent_abspath, FALSE, + iterpool)); + if (kind == svn_node_none) { svn_error_t *err; @@ -1051,7 +1076,7 @@ svn_client__export_externals(apr_hash_t SVN_ERR(svn_wc_parse_externals_description3(&items, local_abspath, desc_text, FALSE, - scratch_pool)); + iterpool)); if (! items->nelts) continue; @@ -1116,187 +1141,3 @@ svn_client__export_externals(apr_hash_t return SVN_NO_ERROR; } - -svn_error_t * -svn_client__do_external_status(svn_client_ctx_t *ctx, - apr_hash_t *external_map, - svn_depth_t depth, - svn_boolean_t get_all, - svn_boolean_t update, - svn_boolean_t no_ignore, - const char *anchor_abspath, - const char *anchor_relpath, - svn_client_status_func_t status_func, - void *status_baton, - apr_pool_t *scratch_pool) -{ - apr_hash_index_t *hi; - apr_pool_t *iterpool = svn_pool_create(scratch_pool); - - /* Loop over the hash of new values (we don't care about the old - ones). This is a mapping of versioned directories to property - values. */ - for (hi = apr_hash_first(scratch_pool, external_map); - hi; - hi = apr_hash_next(hi)) - { - svn_node_kind_t external_kind; - const char *local_abspath = svn__apr_hash_index_key(hi); - const char *defining_abspath = svn__apr_hash_index_val(hi); - svn_node_kind_t kind; - svn_opt_revision_t opt_rev; - const char *status_path; - - svn_pool_clear(iterpool); - - /* Obtain information on the expected external. */ - SVN_ERR(svn_wc__read_external_info(&external_kind, NULL, NULL, NULL, - &opt_rev.value.number, - ctx->wc_ctx, defining_abspath, - local_abspath, FALSE, - iterpool, iterpool)); - - if (external_kind != svn_node_dir) - continue; - - SVN_ERR(svn_io_check_path(local_abspath, &kind, iterpool)); - if (kind != svn_node_dir) - continue; - - if (SVN_IS_VALID_REVNUM(opt_rev.value.number)) - opt_rev.kind = svn_opt_revision_number; - else - opt_rev.kind = svn_opt_revision_unspecified; - - /* Tell the client we're starting an external status set. */ - if (ctx->notify_func2) - ctx->notify_func2( - ctx->notify_baton2, - svn_wc_create_notify(local_abspath, - svn_wc_notify_status_external, - iterpool), iterpool); - - status_path = local_abspath; - if (anchor_abspath) - { - status_path = svn_dirent_join(anchor_relpath, - svn_dirent_skip_ancestor(anchor_abspath, - status_path), - iterpool); - } - - /* And then do the status. */ - SVN_ERR(svn_client_status5(NULL, ctx, status_path, &opt_rev, depth, - get_all, update, no_ignore, FALSE, FALSE, - NULL, status_func, status_baton, - iterpool)); - } - - /* Destroy SUBPOOL and (implicitly) ITERPOOL. */ - svn_pool_destroy(iterpool); - - return SVN_NO_ERROR; -} - -/* Walk through all the external items and list them. */ -static svn_error_t * -list_external_items(apr_array_header_t *external_items, - const char *externals_parent_url, - svn_depth_t depth, - apr_uint32_t dirent_fields, - svn_boolean_t fetch_locks, - svn_client_list_func2_t list_func, - void *baton, - svn_client_ctx_t *ctx, - apr_pool_t *scratch_pool) -{ - const char *externals_parent_repos_root_url; - apr_pool_t *iterpool; - int i; - - SVN_ERR(svn_client_get_repos_root(&externals_parent_repos_root_url, - NULL /* uuid */, - externals_parent_url, ctx, - scratch_pool, scratch_pool)); - - iterpool = svn_pool_create(scratch_pool); - - for (i = 0; i < external_items->nelts; i++) - { - const char *resolved_url; - - svn_wc_external_item2_t *item = - APR_ARRAY_IDX(external_items, i, svn_wc_external_item2_t *); - - svn_pool_clear(iterpool); - - SVN_ERR(svn_wc__resolve_relative_external_url( - &resolved_url, - item, - externals_parent_repos_root_url, - externals_parent_url, - iterpool, iterpool)); - - /* List the external */ - SVN_ERR(wrap_external_error(ctx, item->target_dir, - svn_client__list_internal( - resolved_url, - &item->peg_revision, - &item->revision, - depth, dirent_fields, - fetch_locks, - TRUE, - externals_parent_url, - item->target_dir, - list_func, baton, ctx, - iterpool), - iterpool)); - - } - svn_pool_destroy(iterpool); - - return SVN_NO_ERROR; -} - - -svn_error_t * -svn_client__list_externals(apr_hash_t *externals, - svn_depth_t depth, - apr_uint32_t dirent_fields, - svn_boolean_t fetch_locks, - svn_client_list_func2_t list_func, - void *baton, - svn_client_ctx_t *ctx, - apr_pool_t *scratch_pool) -{ - apr_pool_t *iterpool = svn_pool_create(scratch_pool); - apr_hash_index_t *hi; - - for (hi = apr_hash_first(scratch_pool, externals); - hi; - hi = apr_hash_next(hi)) - { - const char *externals_parent_url = svn__apr_hash_index_key(hi); - svn_string_t *externals_desc = svn__apr_hash_index_val(hi); - apr_array_header_t *external_items; - - svn_pool_clear(iterpool); - - SVN_ERR(svn_wc_parse_externals_description3(&external_items, - externals_parent_url, - externals_desc->data, - FALSE, iterpool)); - - if (! external_items->nelts) - continue; - - SVN_ERR(list_external_items(external_items, externals_parent_url, depth, - dirent_fields, fetch_locks, list_func, - baton, ctx, iterpool)); - - } - svn_pool_destroy(iterpool); - - return SVN_NO_ERROR; -} - Modified: subversion/branches/ev2-export/subversion/libsvn_client/import.c URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/import.c?rev=1449262&r1=1449261&r2=1449262&view=diff ============================================================================== --- subversion/branches/ev2-export/subversion/libsvn_client/import.c (original) +++ subversion/branches/ev2-export/subversion/libsvn_client/import.c Sat Feb 23 01:25:38 2013 @@ -679,13 +679,10 @@ svn_client_import5(const char *path, const char *local_abspath; apr_array_header_t *new_entries = apr_array_make(scratch_pool, 4, sizeof(const char *)); - const char *temp; - const char *dir; apr_hash_t *commit_revprops; apr_pool_t *iterpool = svn_pool_create(scratch_pool); apr_hash_t *autoprops = NULL; apr_array_header_t *global_ignores; - apr_hash_t *local_ignores_hash; apr_array_header_t *local_ignores_arr; const char *edit_relpath; const char *repos_root; @@ -744,11 +741,12 @@ svn_client_import5(const char *path, while (kind == svn_node_none) { + const char *dir; + svn_pool_clear(iterpool); - svn_uri_split(&temp, &dir, url, scratch_pool); + svn_uri_split(&url, &dir, url, scratch_pool); APR_ARRAY_PUSH(new_entries, const char *) = dir; - url = temp; SVN_ERR(svn_ra_reparent(ra_session, url, iterpool)); SVN_ERR(svn_ra_check_path(ra_session, "", SVN_INVALID_REVNUM, &kind, @@ -756,37 +754,21 @@ svn_client_import5(const char *path, } /* Reverse the order of the components we added to our NEW_ENTRIES array. */ - if (new_entries->nelts) - { - int i, j; - const char *component; - for (i = 0; i < (new_entries->nelts / 2); i++) - { - j = new_entries->nelts - i - 1; - component = - APR_ARRAY_IDX(new_entries, i, const char *); - APR_ARRAY_IDX(new_entries, i, const char *) = - APR_ARRAY_IDX(new_entries, j, const char *); - APR_ARRAY_IDX(new_entries, j, const char *) = - component; - } - } + svn_sort__array_reverse(new_entries, scratch_pool); /* The repository doesn't know about the reserved administrative directory. */ - if (new_entries->nelts - /* What's this, what's this? This assignment is here because we - use the value to construct the error message just below. It - may not be aesthetically pleasing, but it's less ugly than - calling APR_ARRAY_IDX twice. */ - && svn_wc_is_adm_dir(temp = APR_ARRAY_IDX(new_entries, - new_entries->nelts - 1, - const char *), - scratch_pool)) - return svn_error_createf - (SVN_ERR_CL_ADM_DIR_RESERVED, NULL, - _("'%s' is a reserved name and cannot be imported"), - svn_dirent_local_style(temp, scratch_pool)); + if (new_entries->nelts) + { + const char *last_component + = APR_ARRAY_IDX(new_entries, new_entries->nelts - 1, const char *); + + if (svn_wc_is_adm_dir(last_component, scratch_pool)) + return svn_error_createf + (SVN_ERR_CL_ADM_DIR_RESERVED, NULL, + _("'%s' is a reserved name and cannot be imported"), + svn_dirent_local_style(last_component, scratch_pool)); + } SVN_ERR(svn_client__ensure_revprop_table(&commit_revprops, revprop_table, log_msg, ctx, scratch_pool)); @@ -812,6 +794,7 @@ svn_client_import5(const char *path, { svn_opt_revision_t rev; apr_array_header_t *config_ignores; + apr_hash_t *local_ignores_hash; SVN_ERR(svn_client__get_inherited_ignores(&global_ignores, url, ctx, scratch_pool, iterpool)); Modified: subversion/branches/ev2-export/subversion/libsvn_client/list.c URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/list.c?rev=1449262&r1=1449261&r2=1449262&view=diff ============================================================================== --- subversion/branches/ev2-export/subversion/libsvn_client/list.c (original) +++ subversion/branches/ev2-export/subversion/libsvn_client/list.c Sat Feb 23 01:25:38 2013 @@ -33,8 +33,36 @@ #include "private/svn_fspath.h" #include "private/svn_ra_private.h" +#include "private/svn_wc_private.h" #include "svn_private_config.h" +/* Prototypes for referencing before declaration */ +static svn_error_t * +list_externals(apr_hash_t *externals, + svn_depth_t depth, + apr_uint32_t dirent_fields, + svn_boolean_t fetch_locks, + svn_client_list_func2_t list_func, + void *baton, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool); + +static svn_error_t * +list_internal(const char *path_or_url, + const svn_opt_revision_t *peg_revision, + const svn_opt_revision_t *revision, + svn_depth_t depth, + apr_uint32_t dirent_fields, + svn_boolean_t fetch_locks, + svn_boolean_t include_externals, + const char *external_parent_url, + const char *external_target, + svn_client_list_func2_t list_func, + void *baton, + svn_client_ctx_t *ctx, + apr_pool_t *pool); + + /* Get the directory entries of DIR at REV (relative to the root of RA_SESSION), getting at least the fields specified by DIRENT_FIELDS. Use the cancellation function/baton of CTX to check for cancellation. @@ -273,20 +301,53 @@ svn_client__ra_stat_compatible(svn_ra_se return SVN_NO_ERROR; } -svn_error_t * -svn_client__list_internal(const char *path_or_url, - const svn_opt_revision_t *peg_revision, - const svn_opt_revision_t *revision, - svn_depth_t depth, - apr_uint32_t dirent_fields, - svn_boolean_t fetch_locks, - svn_boolean_t include_externals, - const char *external_parent_url, - const char *external_target, - svn_client_list_func2_t list_func, - void *baton, - svn_client_ctx_t *ctx, - apr_pool_t *pool) +/* List the file/directory entries for PATH_OR_URL at REVISION. + The actual node revision selected is determined by the path as + it exists in PEG_REVISION. + + If DEPTH is svn_depth_infinity, then list all file and directory entries + recursively. Else if DEPTH is svn_depth_files, list all files under + PATH_OR_URL (if any), but not subdirectories. Else if DEPTH is + svn_depth_immediates, list all files and include immediate + subdirectories (at svn_depth_empty). Else if DEPTH is + svn_depth_empty, just list PATH_OR_URL with none of its entries. + + DIRENT_FIELDS controls which fields in the svn_dirent_t's are + filled in. To have them totally filled in use SVN_DIRENT_ALL, + otherwise simply bitwise OR together the combination of SVN_DIRENT_* + fields you care about. + + If FETCH_LOCKS is TRUE, include locks when reporting directory entries. + + If INCLUDE_EXTERNALS is TRUE, also list all external items + reached by recursion. DEPTH value passed to the original list target + applies for the externals also. EXTERNAL_PARENT_URL is url of the + directory which has the externals definitions. EXTERNAL_TARGET is the + target subdirectory of externals definitions. + + Report directory entries by invoking LIST_FUNC/BATON. + Pass EXTERNAL_PARENT_URL and EXTERNAL_TARGET to LIST_FUNC when external + items are listed, otherwise both are set to NULL. + + Use authentication baton cached in CTX to authenticate against the + repository. + + Use POOL for all allocations. +*/ +static svn_error_t * +list_internal(const char *path_or_url, + const svn_opt_revision_t *peg_revision, + const svn_opt_revision_t *revision, + svn_depth_t depth, + apr_uint32_t dirent_fields, + svn_boolean_t fetch_locks, + svn_boolean_t include_externals, + const char *external_parent_url, + const char *external_target, + svn_client_list_func2_t list_func, + void *baton, + svn_client_ctx_t *ctx, + apr_pool_t *pool) { svn_ra_session_t *ra_session; svn_client__pathrev_t *loc; @@ -361,14 +422,145 @@ svn_client__list_internal(const char *pa { /* The 'externals' hash populated by get_dir_contents() is processed here. */ - SVN_ERR(svn_client__list_externals(externals, depth, dirent_fields, - fetch_locks, list_func, baton, - ctx, pool)); + SVN_ERR(list_externals(externals, depth, dirent_fields, + fetch_locks, list_func, baton, + ctx, pool)); } return SVN_NO_ERROR; } +static svn_error_t * +wrap_list_error(const svn_client_ctx_t *ctx, + const char *target_abspath, + svn_error_t *err, + apr_pool_t *scratch_pool) +{ + if (err && err->apr_err != SVN_ERR_CANCELLED) + { + if (ctx->notify_func2) + { + svn_wc_notify_t *notifier = svn_wc_create_notify( + target_abspath, + svn_wc_notify_failed_external, + scratch_pool); + notifier->err = err; + ctx->notify_func2(ctx->notify_baton2, notifier, scratch_pool); + } + svn_error_clear(err); + return SVN_NO_ERROR; + } + + return err; +} + + +/* Walk through all the external items and list them. */ +static svn_error_t * +list_external_items(apr_array_header_t *external_items, + const char *externals_parent_url, + svn_depth_t depth, + apr_uint32_t dirent_fields, + svn_boolean_t fetch_locks, + svn_client_list_func2_t list_func, + void *baton, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + const char *externals_parent_repos_root_url; + apr_pool_t *iterpool; + int i; + + SVN_ERR(svn_client_get_repos_root(&externals_parent_repos_root_url, + NULL /* uuid */, + externals_parent_url, ctx, + scratch_pool, scratch_pool)); + + iterpool = svn_pool_create(scratch_pool); + + for (i = 0; i < external_items->nelts; i++) + { + const char *resolved_url; + + svn_wc_external_item2_t *item = + APR_ARRAY_IDX(external_items, i, svn_wc_external_item2_t *); + + svn_pool_clear(iterpool); + + SVN_ERR(svn_wc__resolve_relative_external_url( + &resolved_url, + item, + externals_parent_repos_root_url, + externals_parent_url, + iterpool, iterpool)); + + /* List the external */ + SVN_ERR(wrap_list_error(ctx, item->target_dir, + list_internal(resolved_url, + &item->peg_revision, + &item->revision, + depth, dirent_fields, + fetch_locks, + TRUE, + externals_parent_url, + item->target_dir, + list_func, baton, ctx, + iterpool), + iterpool)); + + } + svn_pool_destroy(iterpool); + + return SVN_NO_ERROR; +} + +/* List external items defined on each external in EXTERNALS, a const char * + externals_parent_url(url of the directory which has the externals + definitions) of all externals mapping to the svn_string_t * externals_desc + (externals description text). All other options are the same as those + passed to svn_client_list(). */ +static svn_error_t * +list_externals(apr_hash_t *externals, + svn_depth_t depth, + apr_uint32_t dirent_fields, + svn_boolean_t fetch_locks, + svn_client_list_func2_t list_func, + void *baton, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + apr_hash_index_t *hi; + + for (hi = apr_hash_first(scratch_pool, externals); + hi; + hi = apr_hash_next(hi)) + { + const char *externals_parent_url = svn__apr_hash_index_key(hi); + svn_string_t *externals_desc = svn__apr_hash_index_val(hi); + apr_array_header_t *external_items; + + svn_pool_clear(iterpool); + + SVN_ERR(svn_wc_parse_externals_description3(&external_items, + externals_parent_url, + externals_desc->data, + FALSE, iterpool)); + + if (! external_items->nelts) + continue; + + SVN_ERR(list_external_items(external_items, externals_parent_url, depth, + dirent_fields, fetch_locks, list_func, + baton, ctx, iterpool)); + + } + svn_pool_destroy(iterpool); + + return SVN_NO_ERROR; +} + + svn_error_t * svn_client_list3(const char *path_or_url, const svn_opt_revision_t *peg_revision, @@ -383,11 +575,11 @@ svn_client_list3(const char *path_or_url apr_pool_t *pool) { - return svn_error_trace(svn_client__list_internal(path_or_url, peg_revision, - revision, - depth, dirent_fields, - fetch_locks, - include_externals, - NULL, NULL, list_func, - baton, ctx, pool)); + return svn_error_trace(list_internal(path_or_url, peg_revision, + revision, + depth, dirent_fields, + fetch_locks, + include_externals, + NULL, NULL, list_func, + baton, ctx, pool)); } Modified: subversion/branches/ev2-export/subversion/libsvn_client/locking_commands.c URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/locking_commands.c?rev=1449262&r1=1449261&r2=1449262&view=diff ============================================================================== --- subversion/branches/ev2-export/subversion/libsvn_client/locking_commands.c (original) +++ subversion/branches/ev2-export/subversion/libsvn_client/locking_commands.c Sat Feb 23 01:25:38 2013 @@ -189,6 +189,14 @@ condense_targets(const char **common_par return SVN_NO_ERROR; } +/* Lock info. Used in organize_lock_targets. + ### Maybe return this instead of the ugly hashes? */ +struct wc_lock_item_t +{ + svn_revnum_t revision; + const char *lock_token; +}; + /* Set *COMMON_PARENT_URL to the nearest common parent URL of all TARGETS. * If TARGETS are local paths, then the entry for each path is examined * and *COMMON_PARENT is set to the common parent URL for all the @@ -225,7 +233,7 @@ organize_lock_targets(const char **commo const apr_array_header_t *targets, svn_boolean_t do_lock, svn_boolean_t force, - svn_client_ctx_t *ctx, + svn_wc_context_t *wc_ctx, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { @@ -234,6 +242,7 @@ organize_lock_targets(const char **commo apr_hash_t *rel_targets_ret = apr_hash_make(result_pool); apr_hash_t *rel_fs_paths = NULL; apr_array_header_t *rel_targets; + apr_hash_t *wc_info = apr_hash_make(scratch_pool); svn_boolean_t url_mode; int i; @@ -289,20 +298,38 @@ organize_lock_targets(const char **commo sizeof(const char *)); for (i = 0; i < rel_targets->nelts; i++) { - const char *rel_target, *local_abspath, *target_url; + const char *rel_target; + const char *repos_relpath; + const char *repos_root_url; + const char *target_url; + struct wc_lock_item_t *wli; + const char *local_abspath; svn_pool_clear(iterpool); rel_target = APR_ARRAY_IDX(rel_targets, i, const char *); - local_abspath = svn_dirent_join(common_dirent, rel_target, iterpool); - SVN_ERR(svn_wc__node_get_url(&target_url, ctx->wc_ctx, local_abspath, - scratch_pool, iterpool)); - if (! target_url) - return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, NULL, - _("'%s' has no URL"), + local_abspath = svn_dirent_join(common_dirent, rel_target, scratch_pool); + wli = apr_pcalloc(scratch_pool, sizeof(*wli)); + + SVN_ERR(svn_wc__node_get_base(&wli->revision, &repos_relpath, + &repos_root_url, NULL, + &wli->lock_token, + wc_ctx, local_abspath, + result_pool, iterpool)); + + /* Node exists in BASE? */ + if (! repos_root_url || !repos_relpath) + return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL, + _("The node '%s' was not found."), svn_dirent_local_style(local_abspath, iterpool)); + apr_hash_set(wc_info, local_abspath, APR_HASH_KEY_STRING, wli); + + target_url = svn_path_url_add_component2(repos_root_url, + repos_relpath, + scratch_pool); + APR_ARRAY_PUSH(target_urls, const char *) = target_url; } @@ -320,7 +347,8 @@ organize_lock_targets(const char **commo rel_fs_paths = apr_hash_make(result_pool); for (i = 0; i < rel_targets->nelts; i++) { - const char *rel_target, *rel_url, *abs_path; + const char *rel_target, *rel_url; + const char *local_abspath; svn_pool_clear(iterpool); @@ -336,35 +364,49 @@ organize_lock_targets(const char **commo revision of the dirent target with which it is associated (if our caller is locking) or to a (possible empty) lock token string (if the caller is unlocking). */ - abs_path = svn_dirent_join(common_dirent, rel_target, iterpool); + local_abspath = svn_dirent_join(common_dirent, rel_target, iterpool); if (do_lock) /* Lock. */ { svn_revnum_t *revnum; + struct wc_lock_item_t *wli; revnum = apr_palloc(result_pool, sizeof(* revnum)); - SVN_ERR(svn_wc__node_get_base(revnum, NULL, NULL, NULL, - ctx->wc_ctx, abs_path, - result_pool, iterpool)); + + wli = apr_hash_get(wc_info, local_abspath, APR_HASH_KEY_STRING); + + SVN_ERR_ASSERT(wli != NULL); + + *revnum = wli->revision; + apr_hash_set(rel_targets_ret, rel_url, APR_HASH_KEY_STRING, revnum); } else /* Unlock. */ { - const char *lock_token = NULL; + const char *lock_token; + struct wc_lock_item_t *wli; /* If not forcing the unlock, get the lock token. */ if (! force) { - SVN_ERR(svn_wc__node_get_lock_info(&lock_token, NULL, NULL, - NULL, ctx->wc_ctx, - abs_path, result_pool, - iterpool)); - if (! lock_token) + wli = apr_hash_get(wc_info, local_abspath, + APR_HASH_KEY_STRING); + + SVN_ERR_ASSERT(wli != NULL); + + if (! wli->lock_token) return svn_error_createf( SVN_ERR_CLIENT_MISSING_LOCK_TOKEN, NULL, _("'%s' is not locked in this working copy"), - abs_path); + svn_dirent_local_style(local_abspath, + scratch_pool)); + + lock_token = wli->lock_token + ? apr_pstrdup(result_pool, wli->lock_token) + : NULL; } + else + lock_token = NULL; /* If breaking a lock, we shouldn't pass any lock token. */ apr_hash_set(rel_targets_ret, rel_url, APR_HASH_KEY_STRING, @@ -444,7 +486,7 @@ svn_client_lock(const apr_array_header_t SVN_ERR(organize_lock_targets(&common_parent_url, &base_dir, &path_revs, &urls_to_paths, targets, TRUE, steal_lock, - ctx, pool, pool)); + ctx->wc_ctx, pool, pool)); /* Open an RA session to the common parent of TARGETS. */ if (base_dir) @@ -484,7 +526,7 @@ svn_client_unlock(const apr_array_header SVN_ERR(organize_lock_targets(&common_parent_url, &base_dir, &path_tokens, &urls_to_paths, targets, FALSE, break_lock, - ctx, pool, pool)); + ctx->wc_ctx, pool, pool)); /* Open an RA session. */ if (base_dir)
