Modified: subversion/branches/inheritable-props/subversion/libsvn_client/diff.c URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_client/diff.c?rev=1312079&r1=1312078&r2=1312079&view=diff ============================================================================== --- subversion/branches/inheritable-props/subversion/libsvn_client/diff.c (original) +++ subversion/branches/inheritable-props/subversion/libsvn_client/diff.c Wed Apr 11 02:56:02 2012 @@ -805,6 +805,17 @@ struct diff_cmd_baton { }; +/* A helper function that marks a path as visited. It copies PATH + * into the correct pool before referencing it from the hash table. */ +static void +mark_path_as_visited(struct diff_cmd_baton *diff_cmd_baton, const char *path) +{ + const char *p; + + p = apr_pstrdup(apr_hash_pool_get(diff_cmd_baton->visited_paths), path); + apr_hash_set(diff_cmd_baton->visited_paths, p, APR_HASH_KEY_STRING, p); +} + /* An helper for diff_dir_props_changed, diff_file_changed and diff_file_added */ static svn_error_t * @@ -855,8 +866,7 @@ diff_props_changed(svn_wc_notify_state_t /* We've printed the diff header so now we can mark the path as * visited. */ if (show_diff_header) - apr_hash_set(diff_cmd_baton->visited_paths, path, - APR_HASH_KEY_STRING, path); + mark_path_as_visited(diff_cmd_baton, path); } if (state) @@ -1072,9 +1082,7 @@ diff_content_changed(const char *path, subpool)); /* We have a printed a diff for this path, mark it as visited. */ - apr_hash_set(diff_cmd_baton->visited_paths, path, - APR_HASH_KEY_STRING, path); - + mark_path_as_visited(diff_cmd_baton, path); } } @@ -1494,6 +1502,44 @@ check_diff_target_exists(const char *url return SVN_NO_ERROR; } + +/* Return in *RESOLVED_URL the URL which PATH_OR_URL@PEG_REVISION has in + * REVISION. If the object has no location in REVISION, set *RESOLVED_URL + * to NULL. */ +static svn_error_t * +resolve_pegged_diff_target_url(const char **resolved_url, + svn_ra_session_t *ra_session, + const char *path_or_url, + const svn_opt_revision_t *peg_revision, + const svn_opt_revision_t *revision, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + svn_error_t *err; + + /* Check if the PATH_OR_URL exists at REVISION. */ + err = svn_client__repos_locations(resolved_url, NULL, + NULL, NULL, + ra_session, + path_or_url, + peg_revision, + revision, + NULL, + ctx, scratch_pool); + if (err) + { + if (err->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES) + { + svn_error_clear(err); + *resolved_url = NULL; + } + else + return svn_error_trace(err); + } + + return SVN_NO_ERROR; +} + /** Prepare a repos repos diff between PATH_OR_URL1 and * PATH_OR_URL2@PEG_REVISION, in the revision range REVISION1:REVISION2. * Return URLs and peg revisions in *URL1, *REV1 and in *URL2, *REV2. @@ -1560,34 +1606,38 @@ diff_prepare_repos_repos(const char **ur actual URLs will be. */ if (peg_revision->kind != svn_opt_revision_unspecified) { - svn_error_t *err; + const char *resolved_url1; + const char *resolved_url2; - err = svn_client__repos_locations(url1, NULL, - url2, NULL, - *ra_session, - path_or_url2, - peg_revision, - revision1, - revision2, - ctx, pool); - if (err) + SVN_ERR(resolve_pegged_diff_target_url(&resolved_url2, *ra_session, + path_or_url2, peg_revision, + revision2, ctx, pool)); + + SVN_ERR(svn_ra_reparent(*ra_session, *url1, pool)); + SVN_ERR(resolve_pegged_diff_target_url(&resolved_url1, *ra_session, + path_or_url1, peg_revision, + revision1, ctx, pool)); + + /* Either or both URLs might have changed as a result of resolving + * the PATH_OR_URL@PEG_REVISION's history. If only one of the URLs + * could be resolved, use the same URL for URL1 and URL2, so we can + * show a diff that adds or removes the object (see issue #4153). */ + if (resolved_url2) { - if (err->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES) - { - /* Don't give up just yet. A missing path might translate - * into an addition in the diff. Below, we verify that each - * URL exists on at least one side of the diff. */ - svn_error_clear(err); - } - else - return svn_error_trace(err); + *url2 = resolved_url2; + if (!resolved_url1) + *url1 = resolved_url2; } - else + if (resolved_url1) { - /* Reparent the session, since *URL2 might have changed as a result - the above call. */ - SVN_ERR(svn_ra_reparent(*ra_session, *url2, pool)); + *url1 = resolved_url1; + if (!resolved_url2) + *url2 = resolved_url1; } + + /* Reparent the session, since *URL2 might have changed as a result + the above call. */ + SVN_ERR(svn_ra_reparent(*ra_session, *url2, pool)); } /* Resolve revision and get path kind for the second target. */ @@ -1731,6 +1781,478 @@ unsupported_diff_error(svn_error_t *chil "that is not yet supported")); } +/* Try to get properties for LOCAL_ABSPATH and return them in the property + * hash *PROPS. If there are no properties because LOCAL_ABSPATH is not + * versioned, return an empty property hash. */ +static svn_error_t * +get_props(apr_hash_t **props, + const char *local_abspath, + svn_wc_context_t *wc_ctx, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + svn_error_t *err; + + err = svn_wc_prop_list2(props, wc_ctx, local_abspath, result_pool, + scratch_pool); + if (err) + { + if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND || + err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY || + err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED) + { + svn_error_clear(err); + *props = apr_hash_make(result_pool); + } + else + return svn_error_trace(err); + } + + return SVN_NO_ERROR; +} + +/* Produce a diff between two arbitrary files at LOCAL_ABSPATH1 and + * LOCAL_ABSPATH2, using the diff callbacks from CALLBACKS. + * Use PATH as the name passed to diff callbacks. + * FILE1_IS_EMPTY and FILE2_IS_EMPTY are used as hints which diff callback + * function to use to compare the files (added/deleted/changed). + * + * If ORIGINAL_PROPS_OVERRIDE is not NULL, use it as original properties + * instead of reading properties from LOCAL_ABSPATH1. This is required when + * a file replaces a directory, where LOCAL_ABSPATH1 is an empty file that + * file content must be diffed against, but properties to diff against come + * from the replaced directory. */ +static svn_error_t * +do_arbitrary_files_diff(const char *local_abspath1, + const char *local_abspath2, + const char *path, + svn_boolean_t file1_is_empty, + svn_boolean_t file2_is_empty, + apr_hash_t *original_props_override, + const svn_wc_diff_callbacks4_t *callbacks, + struct diff_cmd_baton *diff_cmd_baton, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + apr_hash_t *original_props; + apr_hash_t *modified_props; + apr_array_header_t *prop_changes; + svn_string_t *original_mime_type = NULL; + svn_string_t *modified_mime_type = NULL; + + if (ctx->cancel_func) + SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); + + if (diff_cmd_baton->ignore_prop_diff) + { + original_props = apr_hash_make(scratch_pool); + modified_props = apr_hash_make(scratch_pool); + } + else + { + /* Try to get properties from either file. It's OK if the files do not + * have properties, or if they are unversioned. */ + if (original_props_override) + original_props = original_props_override; + else + SVN_ERR(get_props(&original_props, local_abspath1, ctx->wc_ctx, + scratch_pool, scratch_pool)); + SVN_ERR(get_props(&modified_props, local_abspath2, ctx->wc_ctx, + scratch_pool, scratch_pool)); + } + + SVN_ERR(svn_prop_diffs(&prop_changes, modified_props, original_props, + scratch_pool)); + + if (!diff_cmd_baton->force_binary) + { + /* Try to determine the mime-type of each file. */ + original_mime_type = apr_hash_get(original_props, SVN_PROP_MIME_TYPE, + APR_HASH_KEY_STRING); + if (!file1_is_empty && !original_mime_type) + { + const char *mime_type; + SVN_ERR(svn_io_detect_mimetype2(&mime_type, local_abspath1, + ctx->mimetypes_map, scratch_pool)); + + if (mime_type) + original_mime_type = svn_string_create(mime_type, scratch_pool); + } + + modified_mime_type = apr_hash_get(modified_props, SVN_PROP_MIME_TYPE, + APR_HASH_KEY_STRING); + if (!file2_is_empty && !modified_mime_type) + { + const char *mime_type; + SVN_ERR(svn_io_detect_mimetype2(&mime_type, local_abspath1, + ctx->mimetypes_map, scratch_pool)); + + if (mime_type) + modified_mime_type = svn_string_create(mime_type, scratch_pool); + } + } + + /* Produce the diff. */ + if (file1_is_empty && !file2_is_empty) + SVN_ERR(callbacks->file_added(NULL, NULL, NULL, path, + local_abspath1, local_abspath2, + /* ### TODO get real revision info + * for versioned files? */ + SVN_INVALID_REVNUM, SVN_INVALID_REVNUM, + original_mime_type ? + original_mime_type->data : NULL, + modified_mime_type ? + modified_mime_type->data : NULL, + /* ### TODO get copyfrom? */ + NULL, SVN_INVALID_REVNUM, + prop_changes, original_props, + diff_cmd_baton, scratch_pool)); + else if (!file1_is_empty && file2_is_empty) + SVN_ERR(callbacks->file_deleted(NULL, NULL, path, + local_abspath1, local_abspath2, + original_mime_type ? + original_mime_type->data : NULL, + modified_mime_type ? + modified_mime_type->data : NULL, + original_props, + diff_cmd_baton, scratch_pool)); + else + SVN_ERR(callbacks->file_changed(NULL, NULL, NULL, path, + local_abspath1, local_abspath2, + /* ### TODO get real revision info + * for versioned files? */ + SVN_INVALID_REVNUM, SVN_INVALID_REVNUM, + original_mime_type ? + original_mime_type->data : NULL, + modified_mime_type ? + modified_mime_type->data : NULL, + prop_changes, original_props, + diff_cmd_baton, scratch_pool)); + + return SVN_NO_ERROR; +} + +struct arbitrary_diff_walker_baton { + /* The root directories of the trees being compared. */ + const char *root1_abspath; + const char *root2_abspath; + + /* TRUE if recursing within an added subtree of root2_abspath that + * does not exist in root1_abspath. */ + svn_boolean_t recursing_within_added_subtree; + + /* TRUE if recursing within an administrative (.i.e. .svn) directory. */ + svn_boolean_t recursing_within_adm_dir; + + /* The absolute path of the adm dir if RECURSING_WITHIN_ADM_DIR is TRUE. + * Else this is NULL.*/ + const char *adm_dir_abspath; + + /* A path to an empty file used for diffs that add/delete files. */ + const char *empty_file_abspath; + + const svn_wc_diff_callbacks4_t *callbacks; + struct diff_cmd_baton *callback_baton; + svn_client_ctx_t *ctx; + apr_pool_t *pool; +} arbitrary_diff_walker_baton; + +/* Forward declaration needed because this function has a cyclic + * dependency with do_arbitrary_dirs_diff(). */ +static svn_error_t * +arbitrary_diff_walker(void *baton, const char *local_abspath, + 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. + * + * If ROOT_ABSPATH1 and ROOT_ABSPATH2 are not NULL, show paths in diffs + * relative to these roots, rather than relative to LOCAL_ABSPATH1 and + * LOCAL_ABSPATH2. This is needed when crawling a subtree that exists + * only within LOCAL_ABSPATH2. */ +static svn_error_t * +do_arbitrary_dirs_diff(const char *local_abspath1, + const char *local_abspath2, + const char *root_abspath1, + const char *root_abspath2, + const svn_wc_diff_callbacks4_t *callbacks, + struct diff_cmd_baton *callback_baton, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + apr_file_t *empty_file; + svn_node_kind_t kind1; + + struct arbitrary_diff_walker_baton b; + + /* If LOCAL_ABSPATH1 is not a directory, crawl LOCAL_ABSPATH2 instead + * and compare it to LOCAL_ABSPATH1, showing only additions. + * This case can only happen during recursion from arbitrary_diff_walker(), + * because do_arbitrary_nodes_diff() prevents this from happening at + * the root of the comparison. */ + SVN_ERR(svn_io_check_resolved_path(local_abspath1, &kind1, scratch_pool)); + b.recursing_within_added_subtree = (kind1 != svn_node_dir); + + b.root1_abspath = root_abspath1 ? root_abspath1 : local_abspath1; + b.root2_abspath = root_abspath2 ? root_abspath2 : local_abspath2; + b.recursing_within_adm_dir = FALSE; + b.adm_dir_abspath = NULL; + b.callbacks = callbacks; + b.callback_baton = callback_baton; + b.ctx = ctx; + b.pool = scratch_pool; + + SVN_ERR(svn_io_open_unique_file3(&empty_file, &b.empty_file_abspath, + 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)); + + 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 + * 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; + const char *local_abspath1; + const char *local_abspath2; + svn_node_kind_t kind1; + svn_node_kind_t kind2; + const char *child_relpath; + apr_hash_t *dirents1; + apr_hash_t *dirents2; + apr_hash_t *merged_dirents; + apr_array_header_t *sorted_dirents; + 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)) + return SVN_NO_ERROR; + else + { + b->recursing_within_adm_dir = FALSE; + b->adm_dir_abspath = NULL; + } + } + else if (strcmp(svn_dirent_basename(local_abspath, scratch_pool), + SVN_WC_ADM_DIR_NAME) == 0) + { + b->recursing_within_adm_dir = TRUE; + b->adm_dir_abspath = apr_pstrdup(b->pool, local_abspath); + return SVN_NO_ERROR; + } + + if (b->recursing_within_added_subtree) + child_relpath = svn_dirent_skip_ancestor(b->root2_abspath, local_abspath); + else + child_relpath = svn_dirent_skip_ancestor(b->root1_abspath, local_abspath); + if (!child_relpath) + return SVN_NO_ERROR; + + local_abspath1 = svn_dirent_join(b->root1_abspath, child_relpath, + scratch_pool); + SVN_ERR(svn_io_check_resolved_path(local_abspath1, &kind1, scratch_pool)); + + local_abspath2 = svn_dirent_join(b->root2_abspath, child_relpath, + 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 (kind2 == svn_node_dir) + { + apr_hash_t *original_props; + apr_hash_t *modified_props; + apr_array_header_t *prop_changes; + + /* Show any property changes for this directory. */ + SVN_ERR(get_props(&original_props, local_abspath1, b->ctx->wc_ctx, + scratch_pool, scratch_pool)); + SVN_ERR(get_props(&modified_props, local_abspath2, b->ctx->wc_ctx, + scratch_pool, scratch_pool)); + SVN_ERR(svn_prop_diffs(&prop_changes, modified_props, original_props, + scratch_pool)); + if (prop_changes->nelts > 0) + SVN_ERR(diff_props_changed(NULL, NULL, child_relpath, + b->recursing_within_added_subtree, + prop_changes, original_props, + b->callback_baton, scratch_pool)); + + /* Read directory entries. */ + SVN_ERR(svn_io_get_dirents3(&dirents2, local_abspath2, + TRUE, /* only_check_type */ + scratch_pool, scratch_pool)); + } + else + dirents2 = apr_hash_make(scratch_pool); + + /* Compare dirents1 to dirents2 and show added/deleted/changed files. */ + merged_dirents = apr_hash_merge(scratch_pool, dirents1, dirents2, + NULL, NULL); + sorted_dirents = svn_sort__hash(merged_dirents, + svn_sort_compare_items_as_paths, + scratch_pool); + iterpool = svn_pool_create(scratch_pool); + for (i = 0; i < sorted_dirents->nelts; i++) + { + svn_sort__item_t elt = APR_ARRAY_IDX(sorted_dirents, i, svn_sort__item_t); + const char *name = elt.key; + svn_io_dirent2_t *dirent1; + svn_io_dirent2_t *dirent2; + const char *child1_abspath; + const char *child2_abspath; + + svn_pool_clear(iterpool); + + if (b->ctx->cancel_func) + SVN_ERR(b->ctx->cancel_func(b->ctx->cancel_baton)); + + if (strcmp(name, SVN_WC_ADM_DIR_NAME) == 0) + continue; + + dirent1 = apr_hash_get(dirents1, name, APR_HASH_KEY_STRING); + if (!dirent1) + { + dirent1 = svn_io_dirent2_create(iterpool); + dirent1->kind = svn_node_none; + } + dirent2 = apr_hash_get(dirents2, name, APR_HASH_KEY_STRING); + if (!dirent2) + { + dirent2 = svn_io_dirent2_create(iterpool); + dirent2->kind = svn_node_none; + } + + child1_abspath = svn_dirent_join(local_abspath1, name, iterpool); + child2_abspath = svn_dirent_join(local_abspath2, name, iterpool); + + if (dirent1->special) + SVN_ERR(svn_io_check_resolved_path(child1_abspath, &dirent1->kind, + iterpool)); + if (dirent2->special) + SVN_ERR(svn_io_check_resolved_path(child1_abspath, &dirent2->kind, + iterpool)); + + if (dirent1->kind == svn_node_dir && + dirent2->kind == svn_node_dir) + continue; + + /* Files that exist only in dirents1. */ + if (dirent1->kind == svn_node_file && + (dirent2->kind == svn_node_dir || dirent2->kind == svn_node_none)) + SVN_ERR(do_arbitrary_files_diff(child1_abspath, b->empty_file_abspath, + svn_relpath_join(child_relpath, name, + iterpool), + FALSE, TRUE, NULL, + b->callbacks, b->callback_baton, + b->ctx, iterpool)); + + /* Files that exist only in dirents2. */ + if (dirent2->kind == svn_node_file && + (dirent1->kind == svn_node_dir || dirent1->kind == svn_node_none)) + { + apr_hash_t *original_props; + + SVN_ERR(get_props(&original_props, child1_abspath, b->ctx->wc_ctx, + scratch_pool, scratch_pool)); + SVN_ERR(do_arbitrary_files_diff(b->empty_file_abspath, child2_abspath, + svn_relpath_join(child_relpath, name, + iterpool), + TRUE, FALSE, original_props, + b->callbacks, b->callback_baton, + b->ctx, iterpool)); + } + + /* Files that exist in dirents1 and dirents2. */ + if (dirent1->kind == svn_node_file && dirent2->kind == svn_node_file) + SVN_ERR(do_arbitrary_files_diff(child1_abspath, child2_abspath, + svn_relpath_join(child_relpath, name, + iterpool), + FALSE, FALSE, NULL, + b->callbacks, b->callback_baton, + b->ctx, scratch_pool)); + + /* 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 && + (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, + b->callbacks, b->callback_baton, + b->ctx, iterpool)); + } + + svn_pool_destroy(iterpool); + + 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. */ +static svn_error_t * +do_arbitrary_nodes_diff(const char *local_abspath1, + const char *local_abspath2, + const svn_wc_diff_callbacks4_t *callbacks, + struct diff_cmd_baton *callback_baton, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + svn_node_kind_t kind1; + svn_node_kind_t kind2; + + SVN_ERR(svn_io_check_resolved_path(local_abspath1, &kind1, scratch_pool)); + SVN_ERR(svn_io_check_resolved_path(local_abspath2, &kind2, scratch_pool)); + if (kind1 != kind2) + return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL, + _("'%s' is not the same node kind as '%s'"), + local_abspath1, local_abspath2); + + if (kind1 == svn_node_file) + SVN_ERR(do_arbitrary_files_diff(local_abspath1, local_abspath2, + svn_dirent_basename(local_abspath2, + scratch_pool), + FALSE, FALSE, NULL, + callbacks, callback_baton, + ctx, scratch_pool)); + else if (kind1 == svn_node_dir) + SVN_ERR(do_arbitrary_dirs_diff(local_abspath1, local_abspath2, + NULL, NULL, + callbacks, callback_baton, + ctx, scratch_pool)); + else + return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL, + _("'%s' is not a file or directory"), + kind1 == svn_node_none ? + local_abspath1 : local_abspath2); + return SVN_NO_ERROR; +} + /* Perform a diff between two working-copy paths. @@ -1762,16 +2284,18 @@ diff_wc_wc(const char *path1, SVN_ERR(svn_dirent_get_absolute(&abspath1, path1, pool)); - /* Currently we support only the case where path1 and path2 are the - same path. */ if ((strcmp(path1, path2) != 0) || (! ((revision1->kind == svn_opt_revision_base) && (revision2->kind == svn_opt_revision_working)))) - return unsupported_diff_error - (svn_error_create - (SVN_ERR_INCORRECT_PARAMS, NULL, - _("Only diffs between a path's text-base " - "and its working files are supported at this time"))); + { + const char *abspath2; + + SVN_ERR(svn_dirent_get_absolute(&abspath2, path2, pool)); + return svn_error_trace(do_arbitrary_nodes_diff(abspath1, abspath2, + callbacks, + callback_baton, + ctx, pool)); + } /* Resolve named revisions to real numbers. */ err = svn_client__get_revision_number(&callback_baton->revnum1, NULL, @@ -2167,8 +2691,8 @@ diff_summarize_wc_wc(svn_client_diff_sum return unsupported_diff_error (svn_error_create (SVN_ERR_INCORRECT_PARAMS, NULL, - _("Only diffs between a path's text-base " - "and its working files are supported at this time"))); + _("Summarized diffs are only supported between a path's text-base " + "and its working files at this time"))); /* Find the node kind of PATH1 so that we know whether the diff drive will be anchored at PATH1 or its parent dir. */
Modified: subversion/branches/inheritable-props/subversion/libsvn_client/export.c URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_client/export.c?rev=1312079&r1=1312078&r2=1312079&view=diff ============================================================================== --- subversion/branches/inheritable-props/subversion/libsvn_client/export.c (original) +++ subversion/branches/inheritable-props/subversion/libsvn_client/export.c Wed Apr 11 02:56:02 2012 @@ -1236,7 +1236,7 @@ svn_client_export5(svn_revnum_t *result_ SVN_ERR(svn_editor__insert_shims(&export_editor, &edit_baton, export_editor, edit_baton, - shim_callbacks, pool, pool)); + NULL, shim_callbacks, pool, pool)); /* Manufacture a basic 'report' to the update reporter. */ SVN_ERR(svn_ra_do_update2(ra_session, Modified: subversion/branches/inheritable-props/subversion/libsvn_client/info.c URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_client/info.c?rev=1312079&r1=1312078&r2=1312079&view=diff ============================================================================== --- subversion/branches/inheritable-props/subversion/libsvn_client/info.c (original) +++ subversion/branches/inheritable-props/subversion/libsvn_client/info.c Wed Apr 11 02:56:02 2012 @@ -66,19 +66,16 @@ static svn_error_t * build_info_from_dirent(svn_client_info2_t **info, const svn_dirent_t *dirent, svn_lock_t *lock, - const char *URL, - svn_revnum_t revision, - const char *repos_UUID, - const char *repos_root, + const svn_client__pathrev_t *pathrev, apr_pool_t *pool) { svn_client_info2_t *tmpinfo = apr_pcalloc(pool, sizeof(*tmpinfo)); - tmpinfo->URL = URL; - tmpinfo->rev = revision; + tmpinfo->URL = pathrev->url; + tmpinfo->rev = pathrev->rev; tmpinfo->kind = dirent->kind; - tmpinfo->repos_UUID = repos_UUID; - tmpinfo->repos_root_URL = repos_root; + tmpinfo->repos_UUID = pathrev->repos_uuid; + tmpinfo->repos_root_URL = pathrev->repos_root_url; tmpinfo->last_changed_rev = dirent->created_rev; tmpinfo->last_changed_date = dirent->time; tmpinfo->last_changed_author = dirent->last_author; @@ -111,11 +108,8 @@ build_info_from_dirent(svn_client_info2_ */ static svn_error_t * push_dir_info(svn_ra_session_t *ra_session, - const char *session_URL, + const svn_client__pathrev_t *pathrev, const char *dir, - svn_revnum_t rev, - const char *repos_UUID, - const char *repos_root, svn_client_info_receiver2_t receiver, void *receiver_baton, svn_depth_t depth, @@ -128,15 +122,16 @@ push_dir_info(svn_ra_session_t *ra_sessi apr_pool_t *subpool = svn_pool_create(pool); SVN_ERR(svn_ra_get_dir2(ra_session, &tmpdirents, NULL, NULL, - dir, rev, DIRENT_FIELDS, pool)); + dir, pathrev->rev, DIRENT_FIELDS, pool)); for (hi = apr_hash_first(pool, tmpdirents); hi; hi = apr_hash_next(hi)) { - const char *path, *URL, *fs_path; + const char *path, *fs_path; svn_lock_t *lock; svn_client_info2_t *info; const char *name = svn__apr_hash_index_key(hi); svn_dirent_t *the_ent = svn__apr_hash_index_val(hi); + svn_client__pathrev_t *child_pathrev; svn_pool_clear(subpool); @@ -144,14 +139,13 @@ push_dir_info(svn_ra_session_t *ra_sessi SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); path = svn_relpath_join(dir, name, subpool); - URL = svn_path_url_add_component2(session_URL, name, subpool); - fs_path = svn_fspath__canonicalize( - svn_uri_skip_ancestor(repos_root, URL, subpool), subpool); + child_pathrev = svn_client__pathrev_join_relpath(pathrev, name, subpool); + fs_path = svn_client__pathrev_fspath(child_pathrev, subpool); lock = apr_hash_get(locks, fs_path, APR_HASH_KEY_STRING); - SVN_ERR(build_info_from_dirent(&info, the_ent, lock, URL, rev, - repos_UUID, repos_root, subpool)); + SVN_ERR(build_info_from_dirent(&info, the_ent, lock, child_pathrev, + subpool)); if (depth >= svn_depth_immediates || (depth == svn_depth_files && the_ent->kind == svn_node_file)) @@ -161,8 +155,7 @@ push_dir_info(svn_ra_session_t *ra_sessi if (depth == svn_depth_infinity && the_ent->kind == svn_node_dir) { - SVN_ERR(push_dir_info(ra_session, URL, path, - rev, repos_UUID, repos_root, + SVN_ERR(push_dir_info(ra_session, child_pathrev, path, receiver, receiver_baton, depth, ctx, locks, subpool)); } @@ -338,9 +331,7 @@ svn_client_info3(const char *abspath_or_ apr_pool_t *pool) { svn_ra_session_t *ra_session; - svn_revnum_t rev; - const char *url; - const char *repos_root_URL, *repos_UUID; + svn_client__pathrev_t *pathrev; svn_lock_t *lock; svn_boolean_t related; const char *base_name; @@ -370,18 +361,14 @@ svn_client_info3(const char *abspath_or_ /* Trace rename history (starting at path_or_url@peg_revision) and return RA session to the possibly-renamed URL as it exists in REVISION. The ra_session returned will be anchored on this "final" URL. */ - SVN_ERR(svn_client__ra_session_from_path(&ra_session, &rev, - &url, abspath_or_url, NULL, - peg_revision, - revision, ctx, pool)); + SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &pathrev, + abspath_or_url, NULL, peg_revision, + revision, ctx, pool)); - SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_URL, pool)); - SVN_ERR(svn_ra_get_uuid2(ra_session, &repos_UUID, pool)); - - svn_uri_split(NULL, &base_name, url, pool); + svn_uri_split(NULL, &base_name, pathrev->url, pool); /* Get the dirent for the URL itself. */ - err = ra_stat_compatible(ra_session, rev, &the_ent, DIRENT_FIELDS, + err = ra_stat_compatible(ra_session, pathrev->rev, &the_ent, DIRENT_FIELDS, ctx, pool); if (err && err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED) { @@ -407,7 +394,7 @@ svn_client_info3(const char *abspath_or_ if (! the_ent) return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL, _("URL '%s' non-existent in revision %ld"), - url, rev); + pathrev->url, pathrev->rev); /* Check if the URL exists in HEAD and refers to the same resource. In this case, we check the repository for a lock on this URL. @@ -417,7 +404,8 @@ svn_client_info3(const char *abspath_or_ ### check in a loop which only terminates if the HEAD revision is the same ### before and after this check. That could, however, lead to a ### starvation situation instead. */ - SVN_ERR(same_resource_in_head(&related, url, rev, ra_session, ctx, pool)); + SVN_ERR(same_resource_in_head(&related, pathrev->url, pathrev->rev, + ra_session, ctx, pool)); if (related) { err = svn_ra_get_lock(ra_session, &lock, "", pool); @@ -437,8 +425,7 @@ svn_client_info3(const char *abspath_or_ lock = NULL; /* Push the URL's dirent (and lock) at the callback.*/ - SVN_ERR(build_info_from_dirent(&info, the_ent, lock, url, rev, - repos_UUID, repos_root_URL, pool)); + SVN_ERR(build_info_from_dirent(&info, the_ent, lock, pathrev, pool)); SVN_ERR(receiver(receiver_baton, base_name, info, pool)); /* Possibly recurse, using the original RA session. */ @@ -466,8 +453,7 @@ pre_1_2_recurse: else locks = apr_hash_make(pool); /* use an empty hash */ - SVN_ERR(push_dir_info(ra_session, url, "", rev, - repos_UUID, repos_root_URL, + SVN_ERR(push_dir_info(ra_session, pathrev, "", receiver, receiver_baton, depth, ctx, locks, pool)); }
