You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2010/08/28 14:59:32 UTC
svn commit: r990358 - /subversion/trunk/subversion/libsvn_client/diff.c
Author: stsp
Date: Sat Aug 28 12:59:32 2010
New Revision: 990358
URL: http://svn.apache.org/viewvc?rev=990358&view=rev
Log:
Re-implement the horrid adjust_relative_to_repos_root() diff helper function.
* subversion/libsvn_client/diff.c
(adjust_relative_to_repos_root): Rewrite in a way that's a lot easier
to follow. Add a new parameter WC_ROOT_ABSPATH which is needed to handle
the repos-wc diff case.
(print_git_diff_header, display_prop_diffs): Likewise, add new parameter
WC_ROOT_ABSPATH and pass it on to adjust_relative_to_repos_root().
(diff_cmd_baton): New member WC_ROOT_ABSPATH.
(diff_content_changed, diff_props_changed): Adjust callers.
(find_wc_root): A helper function to find the root directory of a working
copy. Could probably be promoted to become part of some API if needed.
(diff_repos_wc): Store the absolute path of the working copy root directory
in the diff baton for later use.
(svn_client_diff5, svn_client_diff_peg5): Initialise new member.
Modified:
subversion/trunk/subversion/libsvn_client/diff.c
Modified: subversion/trunk/subversion/libsvn_client/diff.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/diff.c?rev=990358&r1=990357&r2=990358&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/diff.c (original)
+++ subversion/trunk/subversion/libsvn_client/diff.c Sat Aug 28 12:59:32 2010
@@ -190,10 +190,14 @@ maybe_append_eol(const svn_string_t *tok
}
}
-/* Adjust PATH_OR_URL to be relative to the repository root, using RA_SESSION
- * and WC_CTX, and return the result in *ADJUSTED_PATH.
+/* Adjust PATH_OR_URL to be relative to the repository root beneath
+ * ORIG_TARGET, using RA_SESSION and WC_CTX, and return the result
+ * in *ADJUSTED_PATH.
* ORIG_TARGET is one of the original targets passed to the diff command,
* and may be used to derive leading path components missing from PATH_OR_URL.
+ * IS_REPOS_REPOS_DIFF indicates whether we're doing a repos-repos diff.
+ * WC_ROOT_ABSPATH is the absolute path to the root directory of a working
+ * copy involved in a repos-wc diff, and may be NULL.
* Do all allocations in POOL. */
static svn_error_t *
adjust_relative_to_repos_root(const char **adjusted_path,
@@ -202,124 +206,74 @@ adjust_relative_to_repos_root(const char
svn_ra_session_t *ra_session,
svn_wc_context_t *wc_ctx,
svn_boolean_t is_repos_repos_diff,
+ const char *wc_root_abspath,
apr_pool_t *pool)
{
const char *local_abspath;
- const char *repos_root_url;
- const char *node_url;
+ const char *orig_relpath;
+ const char *child_relpath;
- if (ra_session)
+ if (! ra_session)
{
- const char *wc_root_abspath;
- svn_boolean_t wc_root_found;
- apr_pool_t *iterpool;
-
- if (is_repos_repos_diff)
- {
- /* Ask the repository for the adjusted path. */
- if (svn_path_is_url(path_or_url))
- {
- SVN_ERR(svn_ra_get_path_relative_to_root(ra_session,
- adjusted_path,
- path_or_url, pool));
- }
- else
- {
- const char *orig_anchor;
-
- SVN_ERR(svn_ra_get_path_relative_to_root(ra_session,
- &orig_anchor,
- orig_target, pool));
- *adjusted_path = svn_relpath_join(orig_anchor, path_or_url, pool);
- }
-
- return SVN_NO_ERROR;
- }
-
- /* Now deal with the repos->wc and wc->repos cases, where PATH_OR_URL
- * is a path. The path can either be pointing inside a working copy,
- * (or be a working copy root), or it is relative to the URL of the
- * original target. */
-
- /* Check if the path is pointing to or is inside a working copy. */
+ /* We're doing a WC-WC diff, so we can retreive all information we
+ * need from the working copy. */
SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url, pool));
- wc_root_abspath = local_abspath;
- wc_root_found = FALSE;
- iterpool = svn_pool_create(pool);
- while (! wc_root_found && *wc_root_abspath)
- {
- svn_error_t *err;
-
- svn_pool_clear(iterpool);
+ SVN_ERR(svn_wc__node_get_repos_relpath(adjusted_path, wc_ctx,
+ local_abspath, pool, pool));
+ return SVN_NO_ERROR;
+ }
- err = svn_wc_is_wc_root2(&wc_root_found, wc_ctx, wc_root_abspath,
- iterpool);
- if (err)
- {
- /* Ignore all errors. It could be no working copy, or a missing
- * item, or permission denied -- whatever. We don't care,
- * because if all we get is errors, the path is most certainly
- * unrelated to a working copy. */
- svn_error_clear(err);
- }
- if (svn_dirent_is_root(wc_root_abspath, strlen(wc_root_abspath)))
- break;
- if (! wc_root_found)
- wc_root_abspath = svn_dirent_dirname(wc_root_abspath, pool);
- }
- svn_pool_destroy(iterpool);
+ /* Another easy case: We got a URL, so just ask the RA layer. */
+ if (svn_path_is_url(path_or_url))
+ {
+ SVN_ERR(svn_ra_get_path_relative_to_root(ra_session,
+ adjusted_path,
+ path_or_url, pool));
+ return SVN_NO_ERROR;
+ }
- if (wc_root_found)
- {
- const char *wc_url;
- const char *wc_anchor;
- const char *in_wc_relpath;
-
- /* The path is inside a working copy, so it's anchored beneath
- * the URL corresponding to the working copy.
- * ### Is it possible that we find a working copy by accident? */
- SVN_ERR(svn_wc__node_get_url(&wc_url, wc_ctx, wc_root_abspath,
- pool, pool));
- SVN_ERR(svn_ra_get_path_relative_to_root(ra_session, &wc_anchor,
- wc_url, pool));
- in_wc_relpath = svn_dirent_is_child(wc_root_abspath, local_abspath,
- pool);
- *adjusted_path = svn_relpath_join(wc_anchor, in_wc_relpath, pool);
- }
- else
- {
- const char *orig_anchor;
- const char *orig_abspath;
+ /* If we're doing a repos-repos diff, there are no local paths involved.
+ * Ask the repository how ORIG_TARGET looks relative to the repository root.
+ * PATH_OR_URL is a child of it. */
+ if (is_repos_repos_diff)
+ {
+ SVN_ERR(svn_ra_get_path_relative_to_root(ra_session,
+ &orig_relpath,
+ orig_target, pool));
+ *adjusted_path = svn_relpath_join(orig_relpath, path_or_url, pool);
- /* The path is not inside an existing WC, so it's anchored
- * beneath the original target. */
- if (! svn_path_is_url(orig_target))
- {
- SVN_ERR(svn_dirent_get_absolute(&orig_abspath, orig_target,
- pool));
- SVN_ERR(svn_wc__node_get_repos_info(&repos_root_url, NULL,
- wc_ctx, orig_abspath,
- TRUE, TRUE, pool, pool));
- SVN_ERR(svn_wc__node_get_url(&orig_target, wc_ctx, orig_abspath,
- pool, pool));
- }
- SVN_ERR(svn_ra_get_path_relative_to_root(ra_session, &orig_anchor,
- orig_target, pool));
- *adjusted_path = svn_relpath_join(orig_anchor, path_or_url, pool);
- }
+ return SVN_NO_ERROR;
}
+
+ /* Now deal with the repos->wc diff case.
+ * We need to make PATH_OR_URL appear as a child of ORIG_TARGET.
+ * ORIG_TARGET is either a URL or a path to a working copy. First,
+ * find out what ORIG_TARGET looks like relative to the repository root.*/
+ if (svn_path_is_url(orig_target))
+ SVN_ERR(svn_ra_get_path_relative_to_root(ra_session,
+ &orig_relpath,
+ orig_target, pool));
else
{
- /* We're doing a WC-WC diff, so we can retreive all information we
- * need from the working copy. */
+ const char *orig_abspath;
+
+ SVN_ERR(svn_dirent_get_absolute(&orig_abspath, orig_target, pool));
+ SVN_ERR(svn_wc__node_get_repos_relpath(&orig_relpath, wc_ctx,
+ orig_abspath, pool, pool));
+ }
+
+ /* PATH_OR_URL is either a child of the working copy involved in the diff,
+ * or it's a relative path we can readily use. */
+ child_relpath = NULL;
+ if (wc_root_abspath)
+ {
SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url, pool));
- SVN_ERR(svn_wc__node_get_repos_info(&repos_root_url, NULL,
- wc_ctx, local_abspath,
- TRUE, TRUE, pool, pool));
- SVN_ERR(svn_wc__node_get_url(&node_url, wc_ctx, local_abspath, pool,
- pool));
- *adjusted_path = svn_uri_is_child(repos_root_url, node_url, pool);
+ child_relpath = svn_dirent_is_child(wc_root_abspath, local_abspath, pool);
}
+ if (child_relpath == NULL)
+ child_relpath = path_or_url;
+
+ *adjusted_path = svn_relpath_join(orig_relpath, child_relpath, pool);
return SVN_NO_ERROR;
}
@@ -447,6 +401,7 @@ print_git_diff_header(svn_stream_t *os,
const char *header_encoding,
svn_ra_session_t *ra_session,
svn_wc_context_t *wc_ctx,
+ const char *wc_root_abspath,
apr_pool_t *scratch_pool);
/* A helper func that writes out verbal descriptions of property diffs
@@ -458,7 +413,10 @@ print_git_diff_header(svn_stream_t *os,
If USE_GIT_DIFF_FORMAT is TRUE, pring git diff headers, which always
show paths relative to the repository root. RA_SESSION and WC_CTX are
needed to normalize paths relative the repository root, and are ignored
- if USE_GIT_DIFF_FORMAT is FALSE. */
+ if USE_GIT_DIFF_FORMAT is FALSE.
+
+ WC_ROOT_ABSPATH is the absolute path to the root directory of a working
+ copy involved in a repos-wc diff, and may be NULL. */
static svn_error_t *
display_prop_diffs(const apr_array_header_t *propchanges,
apr_hash_t *original_props,
@@ -474,6 +432,7 @@ display_prop_diffs(const apr_array_heade
svn_boolean_t use_git_diff_format,
svn_ra_session_t *ra_session,
svn_wc_context_t *wc_ctx,
+ const char *wc_root_abspath,
apr_pool_t *pool)
{
int i;
@@ -490,11 +449,13 @@ display_prop_diffs(const apr_array_heade
ra_session, wc_ctx,
svn_path_is_url(path1) &&
svn_path_is_url(path2),
+ wc_root_abspath,
pool));
SVN_ERR(adjust_relative_to_repos_root(&path2, path, orig_path2,
ra_session, wc_ctx,
svn_path_is_url(path1) &&
svn_path_is_url(path2),
+ wc_root_abspath,
pool));
}
@@ -529,7 +490,8 @@ display_prop_diffs(const apr_array_heade
svn_diff_op_modified, path,
orig_path1, orig_path2,
rev1, rev2, NULL,
- encoding, ra_session, wc_ctx, pool));
+ encoding, ra_session, wc_ctx,
+ wc_root_abspath, pool));
SVN_ERR(svn_stream_close(os));
}
@@ -719,6 +681,8 @@ print_git_diff_header_modified(svn_strea
* revisions being diffed. COPYFROM_PATH indicates where the diffed item
* was copied from. RA_SESSION and WC_CTX are used to adjust paths in the
* headers to be relative to the repository root.
+ * WC_ROOT_ABSPATH is the absolute path to the root directory of a working
+ * copy involved in a repos-wc diff, and may be NULL.
* Use SCRATCH_POOL for temporary allocations. */
static svn_error_t *
print_git_diff_header(svn_stream_t *os,
@@ -733,6 +697,7 @@ print_git_diff_header(svn_stream_t *os,
const char *header_encoding,
svn_ra_session_t *ra_session,
svn_wc_context_t *wc_ctx,
+ const char *wc_root_abspath,
apr_pool_t *scratch_pool)
{
const char *repos_relpath1;
@@ -742,11 +707,13 @@ print_git_diff_header(svn_stream_t *os,
ra_session, wc_ctx,
svn_path_is_url(path1) &&
svn_path_is_url(path2),
+ wc_root_abspath,
scratch_pool));
SVN_ERR(adjust_relative_to_repos_root(&repos_relpath2, path, path2,
ra_session, wc_ctx,
svn_path_is_url(path1) &&
svn_path_is_url(path2),
+ wc_root_abspath,
scratch_pool));
if (operation == svn_diff_op_deleted)
@@ -871,6 +838,10 @@ struct diff_cmd_baton {
/* The RA session used during diffs involving the repository. */
svn_ra_session_t *ra_session;
+ /* During a repos-wc diff, this is the absolute path to the root
+ * directory of the working copy involved in the diff. */
+ const char *wc_root_abspath;
+
/* A hashtable using the visited paths as keys.
* ### This is needed for us to know if we need to print a diff header for
* ### a path that has property changes. */
@@ -919,6 +890,7 @@ diff_props_changed(const char *local_dir
diff_cmd_baton->use_git_diff_format,
diff_cmd_baton->ra_session,
diff_cmd_baton->wc_ctx,
+ diff_cmd_baton->wc_root_abspath,
subpool));
/* We've printed the diff header so now we can mark the path as
@@ -1075,6 +1047,7 @@ diff_content_changed(const char *path,
diff_cmd_baton->header_encoding,
diff_cmd_baton->ra_session,
diff_cmd_baton->wc_ctx,
+ diff_cmd_baton->wc_root_abspath,
subpool));
/* Output the actual diff */
@@ -1406,6 +1379,49 @@ convert_to_url(const char **url,
return SVN_NO_ERROR;
}
+/* Return the absolute path to the root of the working copy which
+ * LOCAL_ABSPATH is located in, or NULL if LOCAL_ABSPATH is not within
+ * a working copy. Use working copy context WC_CTX.
+ * Allocate the result in RESULT_POOL.
+ * Use SCRATCH_POOL for temporary allocations. */
+static const char *
+find_wc_root(const char *local_abspath, svn_wc_context_t *wc_ctx,
+ apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+ svn_boolean_t wc_root_found;
+ apr_pool_t *iterpool;
+
+ wc_root_found = FALSE;
+ iterpool = svn_pool_create(scratch_pool);
+ while (! wc_root_found && *local_abspath)
+ {
+ svn_error_t *err;
+
+ svn_pool_clear(iterpool);
+
+ err = svn_wc_is_wc_root2(&wc_root_found, wc_ctx, local_abspath,
+ iterpool);
+ if (err)
+ {
+ /* Ignore all errors. We don't care, because if all we get is
+ * errors, the path is not in a working copy. */
+ svn_error_clear(err);
+ }
+
+ if (svn_dirent_is_root(local_abspath, strlen(local_abspath)))
+ break;
+
+ if (! wc_root_found)
+ local_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
+ }
+ svn_pool_destroy(iterpool);
+
+ if (wc_root_found)
+ return apr_pstrdup(result_pool, local_abspath);
+
+ return NULL;
+}
+
/** Check if paths PATH1 and PATH2 are urls and if the revisions REVISION1
* and REVISION2 are local. If PEG_REVISION is not unspecified, ensure that
* at least one of the two revisions is non-local.
@@ -1883,6 +1899,8 @@ diff_repos_wc(const char *path1,
NULL, NULL, FALSE, TRUE,
ctx, pool));
callback_baton->ra_session = ra_session;
+ callback_baton->wc_root_abspath = find_wc_root(anchor_abspath, ctx->wc_ctx,
+ pool, pool);
SVN_ERR(svn_wc_get_diff_editor6(&diff_editor, &diff_edit_baton,
ctx->wc_ctx,
@@ -2255,6 +2273,7 @@ svn_client_diff5(const apr_array_header_
diff_cmd_baton.wc_ctx = ctx->wc_ctx;
diff_cmd_baton.visited_paths = apr_hash_make(pool);
diff_cmd_baton.ra_session = NULL;
+ diff_cmd_baton.wc_root_abspath = NULL;
return do_diff(&diff_callbacks, &diff_cmd_baton, ctx,
path1, path2, revision1, revision2, &peg_revision,
@@ -2315,6 +2334,7 @@ svn_client_diff_peg5(const apr_array_hea
diff_cmd_baton.wc_ctx = ctx->wc_ctx;
diff_cmd_baton.visited_paths = apr_hash_make(pool);
diff_cmd_baton.ra_session = NULL;
+ diff_cmd_baton.wc_root_abspath = NULL;
return do_diff(&diff_callbacks, &diff_cmd_baton, ctx,
path, path, start_revision, end_revision, peg_revision,