You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2010/09/15 21:32:38 UTC
svn commit: r997472 [9/41] - in /subversion/branches/py-tests-as-modules: ./
build/ build/ac-macros/ build/generator/ build/generator/templates/
contrib/server-side/ notes/ notes/tree-conflicts/ notes/wc-ng/
subversion/bindings/javahl/native/ subversio...
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/diff.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/diff.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/diff.c Wed Sep 15 19:32:26 2010
@@ -190,38 +190,453 @@ maybe_append_eol(const svn_string_t *tok
}
}
+/* Adjust PATH 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.
+ * 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,
+ const char *path,
+ const char *orig_target,
+ svn_ra_session_t *ra_session,
+ svn_wc_context_t *wc_ctx,
+ const char *wc_root_abspath,
+ apr_pool_t *pool)
+{
+ const char *local_abspath;
+ const char *orig_relpath;
+ const char *child_relpath;
+
+ if (! ra_session)
+ {
+ /* We're doing a WC-WC diff, so we can retrieve all information we
+ * need from the working copy. */
+ SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
+ SVN_ERR(svn_wc__node_get_repos_relpath(adjusted_path, wc_ctx,
+ local_abspath, pool, pool));
+ return SVN_NO_ERROR;
+ }
+
+ /* Now deal with the repos-repos and repos-wc diff cases.
+ * We need to make PATH 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
+ {
+ 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 is either a child of the working copy involved in the diff (in
+ * the repos-wc diff case), or it's a relative path we can readily use
+ * (in either of the repos-repos and repos-wc diff cases). */
+ child_relpath = NULL;
+ if (wc_root_abspath)
+ {
+ SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
+ child_relpath = svn_dirent_is_child(wc_root_abspath, local_abspath, pool);
+ }
+ if (child_relpath == NULL)
+ child_relpath = path;
+
+ *adjusted_path = svn_relpath_join(orig_relpath, child_relpath, pool);
+
+ return SVN_NO_ERROR;
+}
+
+/* Adjust PATH, ORIG_PATH_1 and ORIG_PATH_2, representing the changed file
+ * and the two original targets passed to the diff command, to handle the
+ * case when we're dealing with different anchors. RELATIVE_TO_DIR is the
+ * directory the diff target should be considered relative to. All
+ * allocations are done in POOL. */
+static svn_error_t *
+adjust_paths_for_diff_labels(const char **path,
+ const char **orig_path_1,
+ const char **orig_path_2,
+ const char *relative_to_dir,
+ apr_pool_t *pool)
+{
+ apr_size_t len;
+ const char *new_path = *path;
+ const char *new_path1 = *orig_path_1;
+ const char *new_path2 = *orig_path_2;
+
+ /* ### Holy cow. Due to anchor/target weirdness, we can't
+ simply join diff_cmd_baton->orig_path_1 with path, ditto for
+ orig_path_2. That will work when they're directory URLs, but
+ not for file URLs. Nor can we just use anchor1 and anchor2
+ from do_diff(), at least not without some more logic here.
+ What a nightmare.
+
+ For now, to distinguish the two paths, we'll just put the
+ unique portions of the original targets in parentheses after
+ the received path, with ellipses for handwaving. This makes
+ the labels a bit clumsy, but at least distinctive. Better
+ solutions are possible, they'll just take more thought. */
+
+ len = strlen(svn_dirent_get_longest_ancestor(new_path1, new_path2, pool));
+ new_path1 = new_path1 + len;
+ new_path2 = new_path2 + len;
+
+ /* ### Should diff labels print paths in local style? Is there
+ already a standard for this? In any case, this code depends on
+ a particular style, so not calling svn_dirent_local_style() on the
+ paths below.*/
+ if (new_path1[0] == '\0')
+ new_path1 = apr_psprintf(pool, "%s", new_path);
+ else if (new_path1[0] == '/')
+ new_path1 = apr_psprintf(pool, "%s\t(...%s)", new_path, new_path1);
+ else
+ new_path1 = apr_psprintf(pool, "%s\t(.../%s)", new_path, new_path1);
+
+ if (new_path2[0] == '\0')
+ new_path2 = apr_psprintf(pool, "%s", new_path);
+ else if (new_path2[0] == '/')
+ new_path2 = apr_psprintf(pool, "%s\t(...%s)", new_path, new_path2);
+ else
+ new_path2 = apr_psprintf(pool, "%s\t(.../%s)", new_path, new_path2);
+
+ if (relative_to_dir)
+ {
+ /* Possibly adjust the paths shown in the output (see issue #2723). */
+ const char *child_path = svn_dirent_is_child(relative_to_dir, new_path,
+ pool);
+
+ if (child_path)
+ new_path = child_path;
+ else if (!svn_path_compare_paths(relative_to_dir, new_path))
+ new_path = ".";
+ else
+ return MAKE_ERR_BAD_RELATIVE_PATH(new_path, relative_to_dir);
+
+ child_path = svn_dirent_is_child(relative_to_dir, new_path1, pool);
+
+ if (child_path)
+ new_path1 = child_path;
+ else if (!svn_path_compare_paths(relative_to_dir, new_path1))
+ new_path1 = ".";
+ else
+ return MAKE_ERR_BAD_RELATIVE_PATH(new_path1, relative_to_dir);
+
+ child_path = svn_dirent_is_child(relative_to_dir, new_path2, pool);
+
+ if (child_path)
+ new_path2 = child_path;
+ else if (!svn_path_compare_paths(relative_to_dir, new_path2))
+ new_path2 = ".";
+ else
+ return MAKE_ERR_BAD_RELATIVE_PATH(new_path2, relative_to_dir);
+ }
+ *path = new_path;
+ *orig_path_1 = new_path1;
+ *orig_path_2 = new_path2;
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Generate a label for the diff output for file PATH at revision REVNUM.
+ If REVNUM is invalid then it is assumed to be the current working
+ copy. Assumes the paths are already in the desired style (local
+ vs internal). Allocate the label in POOL. */
+static const char *
+diff_label(const char *path,
+ svn_revnum_t revnum,
+ apr_pool_t *pool)
+{
+ const char *label;
+ if (revnum != SVN_INVALID_REVNUM)
+ label = apr_psprintf(pool, _("%s\t(revision %ld)"), path, revnum);
+ else
+ label = apr_psprintf(pool, _("%s\t(working copy)"), path);
+
+ return label;
+}
+
+/* Print a git diff header for an addition within a diff between PATH1 and
+ * PATH2 to the stream OS using HEADER_ENCODING.
+ * All allocations are done in RESULT_POOL. */
+static svn_error_t *
+print_git_diff_header_added(svn_stream_t *os, const char *header_encoding,
+ const char *path1, const char *path2,
+ apr_pool_t *result_pool)
+{
+ SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+ "diff --git a/%s b/%s%s",
+ path1, path2, APR_EOL_STR));
+ SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+ "new file mode 10644" APR_EOL_STR));
+ return SVN_NO_ERROR;
+}
+
+/* Print a git diff header for a deletion within a diff between PATH1 and
+ * PATH2 to the stream OS using HEADER_ENCODING.
+ * All allocations are done in RESULT_POOL. */
+static svn_error_t *
+print_git_diff_header_deleted(svn_stream_t *os, const char *header_encoding,
+ const char *path1, const char *path2,
+ apr_pool_t *result_pool)
+{
+ SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+ "diff --git a/%s b/%s%s",
+ path1, path2, APR_EOL_STR));
+ SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+ "deleted file mode 10644"
+ APR_EOL_STR));
+ return SVN_NO_ERROR;
+}
+
+/* Print a git diff header for a copy from COPYFROM_PATH to PATH to the stream
+ * OS using HEADER_ENCODING. All allocations are done in RESULT_POOL. */
+static svn_error_t *
+print_git_diff_header_copied(svn_stream_t *os, const char *header_encoding,
+ const char *copyfrom_path, const char *path,
+ apr_pool_t *result_pool)
+{
+ SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+ "diff --git a/%s b/%s%s",
+ copyfrom_path, path, APR_EOL_STR));
+ SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+ "copy from %s%s", copyfrom_path,
+ APR_EOL_STR));
+ SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+ "copy to %s%s", path, APR_EOL_STR));
+ return SVN_NO_ERROR;
+}
+
+/* Print a git diff header for a rename from COPYFROM_PATH to PATH to the
+ * stream OS using HEADER_ENCODING. All allocations are done in RESULT_POOL. */
+static svn_error_t *
+print_git_diff_header_renamed(svn_stream_t *os, const char *header_encoding,
+ const char *copyfrom_path, const char *path,
+ apr_pool_t *result_pool)
+{
+ SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+ "diff --git a/%s b/%s%s",
+ copyfrom_path, path, APR_EOL_STR));
+ SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+ "rename from %s%s", copyfrom_path,
+ APR_EOL_STR));
+ SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+ "rename to %s%s", path, APR_EOL_STR));
+ return SVN_NO_ERROR;
+}
+
+/* Print a git diff header for a modification within a diff between PATH1 and
+ * PATH2 to the stream OS using HEADER_ENCODING.
+ * All allocations are done in RESULT_POOL. */
+static svn_error_t *
+print_git_diff_header_modified(svn_stream_t *os, const char *header_encoding,
+ const char *path1, const char *path2,
+ apr_pool_t *result_pool)
+{
+ SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+ "diff --git a/%s b/%s%s",
+ path1, path2, APR_EOL_STR));
+ return SVN_NO_ERROR;
+}
+
+/* Print a git diff header showing the OPERATION to the stream OS using
+ * HEADER_ENCODING. Return suitable diff labels for the git diff in *LABEL1
+ * and *LABEL2. PATH is the path being diffed, ORIG_TARGET1 and ORIG_TARGET2
+ * are the paths passed to the original diff command. REV1 and REV2 are
+ * 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,
+ const char **label1, const char **label2,
+ svn_diff_operation_kind_t operation,
+ const char *path,
+ const char *path1,
+ const char *path2,
+ svn_revnum_t rev1,
+ svn_revnum_t rev2,
+ const char *copyfrom_path,
+ 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;
+ const char *repos_relpath2;
+
+ SVN_ERR(adjust_relative_to_repos_root(&repos_relpath1, path, path1,
+ ra_session, wc_ctx,
+ wc_root_abspath,
+ scratch_pool));
+ SVN_ERR(adjust_relative_to_repos_root(&repos_relpath2, path, path2,
+ ra_session, wc_ctx,
+ wc_root_abspath,
+ scratch_pool));
+
+ if (operation == svn_diff_op_deleted)
+ {
+ SVN_ERR(print_git_diff_header_deleted(os, header_encoding,
+ repos_relpath1, repos_relpath2,
+ scratch_pool));
+ *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", repos_relpath1),
+ rev1, scratch_pool);
+ *label2 = diff_label("/dev/null", rev2, scratch_pool);
+
+ }
+ else if (operation == svn_diff_op_copied)
+ {
+ SVN_ERR(print_git_diff_header_copied(os, header_encoding,
+ copyfrom_path, repos_relpath2,
+ scratch_pool));
+ *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", copyfrom_path),
+ rev1, scratch_pool);
+ *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", repos_relpath2),
+ rev2, scratch_pool);
+ }
+ else if (operation == svn_diff_op_added)
+ {
+ SVN_ERR(print_git_diff_header_added(os, header_encoding,
+ repos_relpath1, repos_relpath2,
+ scratch_pool));
+ *label1 = diff_label("/dev/null", rev1, scratch_pool);
+ *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", repos_relpath2),
+ rev2, scratch_pool);
+ }
+ else if (operation == svn_diff_op_modified)
+ {
+ SVN_ERR(print_git_diff_header_modified(os, header_encoding,
+ repos_relpath1, repos_relpath2,
+ scratch_pool));
+ *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", repos_relpath1),
+ rev1, scratch_pool);
+ *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", repos_relpath2),
+ rev2, scratch_pool);
+ }
+ else if (operation == svn_diff_op_moved)
+ {
+ SVN_ERR(print_git_diff_header_renamed(os, header_encoding,
+ copyfrom_path, repos_relpath2,
+ scratch_pool));
+ *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", copyfrom_path),
+ rev1, scratch_pool);
+ *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", repos_relpath2),
+ rev2, scratch_pool);
+ }
+
+ /* ### Print git headers for renames, too, in the future. */
+
+ return SVN_NO_ERROR;
+}
+
/* A helper func that writes out verbal descriptions of property diffs
to FILE. Of course, the apr_file_t will probably be the 'outfile'
- passed to svn_client_diff5, which is probably stdout. */
+ passed to svn_client_diff5, which is probably stdout.
+
+ ### FIXME needs proper docstring
+
+ 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.
+
+ 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,
const char *path,
+ const char *orig_path1,
+ const char *orig_path2,
+ svn_revnum_t rev1,
+ svn_revnum_t rev2,
const char *encoding,
apr_file_t *file,
const char *relative_to_dir,
+ svn_boolean_t show_diff_header,
+ 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;
+ const char *path1 = apr_pstrdup(pool, orig_path1);
+ const char *path2 = apr_pstrdup(pool, orig_path2);
- if (relative_to_dir)
+ /* If we're creating a diff on the wc root, path would be empty. */
+ if (path[0] == '\0')
+ path = apr_psprintf(pool, ".");
+
+ if (use_git_diff_format)
{
- /* Possibly adjust the path shown in the output (see issue #2723). */
- const char *child_path = svn_dirent_is_child(relative_to_dir, path,
- pool);
+ SVN_ERR(adjust_relative_to_repos_root(&path1, path, orig_path1,
+ ra_session, wc_ctx,
+ wc_root_abspath,
+ pool));
+ SVN_ERR(adjust_relative_to_repos_root(&path2, path, orig_path2,
+ ra_session, wc_ctx,
+ wc_root_abspath,
+ pool));
+ }
- if (child_path)
- path = child_path;
- else if (!svn_path_compare_paths(relative_to_dir, path))
- path = ".";
- else
- return MAKE_ERR_BAD_RELATIVE_PATH(path, relative_to_dir);
+ if (show_diff_header)
+ {
+ const char *label1;
+ const char *label2;
+ const char *adjusted_path1 = apr_pstrdup(pool, path1);
+ const char *adjusted_path2 = apr_pstrdup(pool, path2);
+
+ SVN_ERR(adjust_paths_for_diff_labels(&path, &adjusted_path1,
+ &adjusted_path2,
+ relative_to_dir, pool));
+
+ label1 = diff_label(adjusted_path1, rev1, pool);
+ label2 = diff_label(adjusted_path2, rev2, pool);
+
+ /* ### Should we show the paths in platform specific format,
+ * ### diff_content_changed() does not! */
+
+ SVN_ERR(file_printf_from_utf8(file, encoding,
+ "Index: %s" APR_EOL_STR
+ "%s" APR_EOL_STR,
+ path, equal_string));
+
+ if (use_git_diff_format)
+ {
+ svn_stream_t *os;
+
+ os = svn_stream_from_aprfile2(file, TRUE, pool);
+ SVN_ERR(print_git_diff_header(os, &label1, &label2,
+ svn_diff_op_modified, path,
+ orig_path1, orig_path2,
+ rev1, rev2, NULL,
+ encoding, ra_session, wc_ctx,
+ wc_root_abspath, pool));
+ SVN_ERR(svn_stream_close(os));
+ }
+
+ SVN_ERR(file_printf_from_utf8(file, encoding,
+ "--- %s" APR_EOL_STR
+ "+++ %s" APR_EOL_STR,
+ label1,
+ label2));
}
SVN_ERR(file_printf_from_utf8(file, encoding,
_("%sProperty changes on: %s%s"),
APR_EOL_STR,
- svn_dirent_local_style(path, pool),
+ use_git_diff_format ? path1 : path,
APR_EOL_STR));
SVN_ERR(file_printf_from_utf8(file, encoding, "%s" APR_EOL_STR,
@@ -306,93 +721,6 @@ display_prop_diffs(const apr_array_heade
return SVN_NO_ERROR;
}
-#ifdef SVN_EXPERIMENTAL_PATCH
-
-/*
- * Print a git diff header for PATH to the stream OS using HEADER_ENCODING.
- * All allocations are done in RESULT_POOL. */
-static svn_error_t *
-print_git_diff_header_added(svn_stream_t *os, const char *header_encoding,
- const char *path, apr_pool_t *result_pool)
-{
- SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
- "diff --git a/%s b/%s%s",
- path, path, APR_EOL_STR));
- SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
- "new file mode 10644" APR_EOL_STR));
- return SVN_NO_ERROR;
-}
-
-/*
- * Print a git diff header for PATH to the stream OS using HEADER_ENCODING.
- * All allocations are done in RESULT_POOL. */
-static svn_error_t *
-print_git_diff_header_deleted(svn_stream_t *os, const char *header_encoding,
- const char *path, apr_pool_t *result_pool)
-{
- SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
- "diff --git a/%s b/%s%s",
- path, path, APR_EOL_STR));
- SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
- "deleted file mode 10644"
- APR_EOL_STR));
- return SVN_NO_ERROR;
-}
-
-/*
- * Print a git diff header for PATH to the stream OS using HEADER_ENCODING.
- * COPYFROM_PATH is the origin of the operation. All allocations are done
- * in RESULT_POOL. */
-static svn_error_t *
-print_git_diff_header_copied(svn_stream_t *os, const char *header_encoding,
- const char *path, const char *copyfrom_path,
- apr_pool_t *result_pool)
-{
- SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
- "diff --git a/%s b/%s%s",
- copyfrom_path, path, APR_EOL_STR));
- SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
- "copy from %s%s", copyfrom_path,
- APR_EOL_STR));
- SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
- "copy to %s%s", path, APR_EOL_STR));
- return SVN_NO_ERROR;
-}
-
-/*
- * Print a git diff header for PATH to the stream OS using HEADER_ENCODING.
- * COPYFROM_PATH is the origin of the operation. All allocations are done
- * in RESULT_POOL. */
-static svn_error_t *
-print_git_diff_header_moved(svn_stream_t *os, const char *header_encoding,
- const char *path, const char *copyfrom_path,
- apr_pool_t *result_pool)
-{
- SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
- "diff --git a/%s b/%s%s",
- copyfrom_path, path, APR_EOL_STR));
- SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
- "rename from %s%s", copyfrom_path,
- APR_EOL_STR));
- SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
- "rename to %s%s", path, APR_EOL_STR));
- return SVN_NO_ERROR;
-}
-
-/*
- * Print a git diff header for PATH to the stream OS using HEADER_ENCODING.
- * All allocations are done in RESULT_POOL. */
-static svn_error_t *
-print_git_diff_header_modified(svn_stream_t *os, const char *header_encoding,
- const char *path, apr_pool_t *result_pool)
-{
- SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
- "diff --git a/%s b/%s%s",
- path, path, APR_EOL_STR));
- return SVN_NO_ERROR;
-}
-#endif
-
/*-----------------------------------------------------------------*/
/*** Callbacks for 'svn diff', invoked by the repos-diff editor. ***/
@@ -451,25 +779,25 @@ struct diff_cmd_baton {
/* The directory that diff target paths should be considered as
relative to for output generation (see issue #2723). */
const char *relative_to_dir;
-};
-/* Generate a label for the diff output for file PATH at revision REVNUM.
- If REVNUM is invalid then it is assumed to be the current working
- copy. Assumes the paths are already in the desired style (local
- vs internal). Allocate the label in POOL. */
-static const char *
-diff_label(const char *path,
- svn_revnum_t revnum,
- apr_pool_t *pool)
-{
- const char *label;
- if (revnum != SVN_INVALID_REVNUM)
- label = apr_psprintf(pool, _("%s\t(revision %ld)"), path, revnum);
- else
- label = apr_psprintf(pool, _("%s\t(working copy)"), path);
+ /* Whether we're producing a git-style diff. */
+ svn_boolean_t use_git_diff_format;
+
+ svn_wc_context_t *wc_ctx;
+
+ /* 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. */
+ apr_hash_t *visited_paths;
+};
- return label;
-}
/* An svn_wc_diff_callbacks4_t function. Used for both file and directory
property diffs. */
@@ -485,16 +813,42 @@ diff_props_changed(const char *local_dir
{
struct diff_cmd_baton *diff_cmd_baton = diff_baton;
apr_array_header_t *props;
+ svn_boolean_t show_diff_header;
apr_pool_t *subpool = svn_pool_create(diff_cmd_baton->pool);
SVN_ERR(svn_categorize_props(propchanges, NULL, NULL, &props, subpool));
+ if (apr_hash_get(diff_cmd_baton->visited_paths, path, APR_HASH_KEY_STRING))
+ show_diff_header = FALSE;
+ else
+ show_diff_header = TRUE;
+
if (props->nelts > 0)
- SVN_ERR(display_prop_diffs(props, original_props, path,
- diff_cmd_baton->header_encoding,
- diff_cmd_baton->outfile,
- diff_cmd_baton->relative_to_dir,
- subpool));
+ {
+ /* We're using the revnums from the diff_cmd_baton since there's
+ * no revision argument to the svn_wc_diff_callback_t
+ * dir_props_changed(). */
+ SVN_ERR(display_prop_diffs(props, original_props, path,
+ diff_cmd_baton->orig_path_1,
+ diff_cmd_baton->orig_path_2,
+ diff_cmd_baton->revnum1,
+ diff_cmd_baton->revnum2,
+ diff_cmd_baton->header_encoding,
+ diff_cmd_baton->outfile,
+ diff_cmd_baton->relative_to_dir,
+ show_diff_header,
+ 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
+ * visited. */
+ if (show_diff_header)
+ apr_hash_set(diff_cmd_baton->visited_paths, path,
+ APR_HASH_KEY_STRING, path);
+ }
if (state)
*state = svn_wc_notify_state_unknown;
@@ -518,6 +872,7 @@ diff_content_changed(const char *path,
const char *mimetype1,
const char *mimetype2,
svn_diff_operation_kind_t operation,
+ const char *copyfrom_path,
void *diff_baton)
{
struct diff_cmd_baton *diff_cmd_baton = diff_baton;
@@ -529,80 +884,17 @@ diff_content_changed(const char *path,
const char *label1, *label2;
svn_boolean_t mt1_binary = FALSE, mt2_binary = FALSE;
const char *path1, *path2;
- apr_size_t len;
/* Get a stream from our output file. */
os = svn_stream_from_aprfile2(diff_cmd_baton->outfile, TRUE, subpool);
/* Generate the diff headers. */
- /* ### Holy cow. Due to anchor/target weirdness, we can't
- simply join diff_cmd_baton->orig_path_1 with path, ditto for
- orig_path_2. That will work when they're directory URLs, but
- not for file URLs. Nor can we just use anchor1 and anchor2
- from do_diff(), at least not without some more logic here.
- What a nightmare.
-
- For now, to distinguish the two paths, we'll just put the
- unique portions of the original targets in parentheses after
- the received path, with ellipses for handwaving. This makes
- the labels a bit clumsy, but at least distinctive. Better
- solutions are possible, they'll just take more thought. */
-
- path1 = diff_cmd_baton->orig_path_1;
- path2 = diff_cmd_baton->orig_path_2;
- len = strlen(svn_dirent_get_longest_ancestor(path1, path2, subpool));
- path1 = path1 + len;
- path2 = path2 + len;
-
- /* ### Should diff labels print paths in local style? Is there
- already a standard for this? In any case, this code depends on
- a particular style, so not calling svn_dirent_local_style() on the
- paths below.*/
- if (path1[0] == '\0')
- path1 = apr_psprintf(subpool, "%s", path);
- else if (path1[0] == '/')
- path1 = apr_psprintf(subpool, "%s\t(...%s)", path, path1);
- else
- path1 = apr_psprintf(subpool, "%s\t(.../%s)", path, path1);
-
- if (path2[0] == '\0')
- path2 = apr_psprintf(subpool, "%s", path);
- else if (path2[0] == '/')
- path2 = apr_psprintf(subpool, "%s\t(...%s)", path, path2);
- else
- path2 = apr_psprintf(subpool, "%s\t(.../%s)", path, path2);
-
- if (diff_cmd_baton->relative_to_dir)
- {
- /* Possibly adjust the paths shown in the output (see issue #2723). */
- const char *child_path = svn_dirent_is_child(rel_to_dir, path, subpool);
-
- if (child_path)
- path = child_path;
- else if (!svn_path_compare_paths(rel_to_dir, path))
- path = ".";
- else
- return MAKE_ERR_BAD_RELATIVE_PATH(path, rel_to_dir);
+ path1 = apr_pstrdup(subpool, diff_cmd_baton->orig_path_1);
+ path2 = apr_pstrdup(subpool, diff_cmd_baton->orig_path_2);
- child_path = svn_dirent_is_child(rel_to_dir, path1, subpool);
-
- if (child_path)
- path1 = child_path;
- else if (!svn_path_compare_paths(rel_to_dir, path1))
- path1 = ".";
- else
- return MAKE_ERR_BAD_RELATIVE_PATH(path1, rel_to_dir);
-
- child_path = svn_dirent_is_child(rel_to_dir, path2, subpool);
-
- if (child_path)
- path2 = child_path;
- else if (!svn_path_compare_paths(rel_to_dir, path2))
- path2 = ".";
- else
- return MAKE_ERR_BAD_RELATIVE_PATH(path2, rel_to_dir);
- }
+ SVN_ERR(adjust_paths_for_diff_labels(&path, &path1, &path2,
+ rel_to_dir, subpool));
label1 = diff_label(path1, rev1, subpool);
label2 = diff_label(path2, rev2, subpool);
@@ -687,60 +979,43 @@ diff_content_changed(const char *path,
diff_cmd_baton->options.for_internal,
subpool));
- if (svn_diff_contains_diffs(diff) || diff_cmd_baton->force_empty)
+ if (svn_diff_contains_diffs(diff) || diff_cmd_baton->force_empty ||
+ diff_cmd_baton->use_git_diff_format)
{
/* Print out the diff header. */
SVN_ERR(svn_stream_printf_from_utf8
(os, diff_cmd_baton->header_encoding, subpool,
"Index: %s" APR_EOL_STR "%s" APR_EOL_STR,
path, equal_string));
-#ifdef SVN_EXPERIMENTAL_PATCH
- /* Add git headers and adjust the labels.
- * ### Once we're using the git format everywhere, we can create
- * ### one func that sets the correct labels in one place. */
- if (operation == svn_diff_op_deleted)
- {
- SVN_ERR(print_git_diff_header_deleted(
- os,
- diff_cmd_baton->header_encoding,
- path, subpool));
-
- label1 = diff_label(apr_psprintf(subpool, "a/%s", path1), rev1,
- subpool);
- label2 = diff_label("/dev/null", rev2, subpool);
- }
- else if (operation == svn_diff_op_added)
- {
- SVN_ERR(print_git_diff_header_added(
- os,
- diff_cmd_baton->header_encoding,
- path, subpool));
- label1 = diff_label("/dev/null", rev1, subpool);
- label2 = diff_label(apr_psprintf(subpool, "b/%s", path2), rev2,
- subpool);
- }
- else if (operation == svn_diff_op_modified)
- {
- SVN_ERR(print_git_diff_header_modified(
- os,
- diff_cmd_baton->header_encoding,
- path, subpool));
- label1 = diff_label(apr_psprintf(subpool, "a/%s", path1), rev1,
- subpool);
- label2 = diff_label(apr_psprintf(subpool, "b/%s", path2), rev2,
- subpool);
- }
+ if (diff_cmd_baton->use_git_diff_format)
+ SVN_ERR(print_git_diff_header(os, &label1, &label2, operation,
+ path, diff_cmd_baton->orig_path_1,
+ diff_cmd_baton->orig_path_2,
+ rev1, rev2,
+ copyfrom_path,
+ diff_cmd_baton->header_encoding,
+ diff_cmd_baton->ra_session,
+ diff_cmd_baton->wc_ctx,
+ diff_cmd_baton->wc_root_abspath,
+ subpool));
- /* ### Print git headers for copies and renames too. */
-#endif
/* Output the actual diff */
- SVN_ERR(svn_diff_file_output_unified3
- (os, diff, tmpfile1, tmpfile2, label1, label2,
- diff_cmd_baton->header_encoding, rel_to_dir,
- diff_cmd_baton->options.for_internal->show_c_function,
- subpool));
+ if (svn_diff_contains_diffs(diff) || diff_cmd_baton->force_empty)
+ SVN_ERR(svn_diff_file_output_unified3
+ (os, diff, tmpfile1, tmpfile2, label1, label2,
+ diff_cmd_baton->header_encoding, rel_to_dir,
+ diff_cmd_baton->options.for_internal->show_c_function,
+ 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);
+
}
+
+ /* Close the stream (flush) */
+ SVN_ERR(svn_stream_close(os));
}
/* ### todo: someday we'll need to worry about whether we're going
@@ -775,7 +1050,7 @@ diff_file_changed(const char *local_dir_
SVN_ERR(diff_content_changed(path,
tmpfile1, tmpfile2, rev1, rev2,
mimetype1, mimetype2,
- svn_diff_op_modified, diff_baton));
+ svn_diff_op_modified, NULL, diff_baton));
if (prop_changes->nelts > 0)
SVN_ERR(diff_props_changed(local_dir_abspath, prop_state, tree_conflicted,
path, prop_changes,
@@ -822,11 +1097,17 @@ diff_file_added(const char *local_dir_ab
user see that *something* happened. */
diff_cmd_baton->force_empty = TRUE;
- if (tmpfile1)
+ if (tmpfile1 && copyfrom_path)
+ SVN_ERR(diff_content_changed(path,
+ tmpfile1, tmpfile2, rev1, rev2,
+ mimetype1, mimetype2,
+ svn_diff_op_copied, copyfrom_path,
+ diff_baton));
+ else if (tmpfile1)
SVN_ERR(diff_content_changed(path,
tmpfile1, tmpfile2, rev1, rev2,
mimetype1, mimetype2,
- svn_diff_op_added, diff_baton));
+ svn_diff_op_added, NULL, diff_baton));
if (prop_changes->nelts > 0)
SVN_ERR(diff_props_changed(local_dir_abspath, prop_state, tree_conflicted,
path, prop_changes,
@@ -864,7 +1145,7 @@ diff_file_deleted_with_diff(const char *
tmpfile1, tmpfile2, diff_cmd_baton->revnum1,
diff_cmd_baton->revnum2,
mimetype1, mimetype2,
- svn_diff_op_deleted, diff_baton));
+ svn_diff_op_deleted, NULL, diff_baton));
/* We don't list all the deleted properties. */
@@ -1048,84 +1329,89 @@ convert_to_url(const char **url,
return SVN_NO_ERROR;
}
-/** Helper structure: for passing around the diff parameters */
-struct diff_parameters
+/* 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)
{
- /* First input path */
- const char *path1;
-
- /* Revision of first input path */
- const svn_opt_revision_t *revision1;
-
- /* Second input path */
- const char *path2;
+ svn_boolean_t wc_root_found;
+ apr_pool_t *iterpool;
- /* Revision of second input path */
- const svn_opt_revision_t *revision2;
-
- /* Peg revision */
- const svn_opt_revision_t *peg_revision;
-
- /* Desired depth */
- svn_depth_t depth;
-
- /* Ignore ancestry */
- svn_boolean_t ignore_ancestry;
+ wc_root_found = FALSE;
+ iterpool = svn_pool_create(scratch_pool);
+ while (! wc_root_found && *local_abspath)
+ {
+ svn_error_t *err;
- /* Ignore deleted */
- svn_boolean_t no_diff_deleted;
+ svn_pool_clear(iterpool);
- /* Don't follow copyfrom when diffing copies. */
- svn_boolean_t show_copies_as_adds;
+ 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);
+ }
- /* Changelists of interest */
- const apr_array_header_t *changelists;
-};
+ if (svn_dirent_is_root(local_abspath, strlen(local_abspath)))
+ break;
-/** Helper structure: filled by check_paths() */
-struct diff_paths
-{
- /* path1 can only be found in the repository? */
- svn_boolean_t is_repos1;
+ if (! wc_root_found)
+ local_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
+ }
+ svn_pool_destroy(iterpool);
- /* path2 can only be found in the repository? */
- svn_boolean_t is_repos2;
-};
+ if (wc_root_found)
+ return apr_pstrdup(result_pool, local_abspath);
+ return NULL;
+}
-/** Check if paths are urls and if the revisions are local, and, for
- pegged revisions, ensure that at least one revision is non-local.
- Fills the PATHS structure. */
-static svn_error_t *
-check_paths(const struct diff_parameters *params,
- struct diff_paths *paths)
+/** 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.
+ * If PATH1 can only be found in the repository, set *IS_REPOS1 to TRUE.
+ * If PATH2 can only be found in the repository, set *IS_REPOS2 to TRUE. */
+static svn_error_t *
+check_paths(svn_boolean_t *is_repos1,
+ svn_boolean_t *is_repos2,
+ const char *path1,
+ const char *path2,
+ const svn_opt_revision_t *revision1,
+ const svn_opt_revision_t *revision2,
+ const svn_opt_revision_t *peg_revision)
{
svn_boolean_t is_local_rev1, is_local_rev2;
/* Verify our revision arguments in light of the paths. */
- if ((params->revision1->kind == svn_opt_revision_unspecified)
- || (params->revision2->kind == svn_opt_revision_unspecified))
+ if ((revision1->kind == svn_opt_revision_unspecified)
+ || (revision2->kind == svn_opt_revision_unspecified))
return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL,
_("Not all required revisions are specified"));
/* Revisions can be said to be local or remote. BASE and WORKING,
for example, are local. */
is_local_rev1 =
- ((params->revision1->kind == svn_opt_revision_base)
- || (params->revision1->kind == svn_opt_revision_working));
+ ((revision1->kind == svn_opt_revision_base)
+ || (revision1->kind == svn_opt_revision_working));
is_local_rev2 =
- ((params->revision2->kind == svn_opt_revision_base)
- || (params->revision2->kind == svn_opt_revision_working));
+ ((revision2->kind == svn_opt_revision_base)
+ || (revision2->kind == svn_opt_revision_working));
- if (params->peg_revision->kind != svn_opt_revision_unspecified)
+ if (peg_revision->kind != svn_opt_revision_unspecified)
{
if (is_local_rev1 && is_local_rev2)
return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL,
_("At least one revision must be non-local "
"for a pegged diff"));
- paths->is_repos1 = ! is_local_rev1;
- paths->is_repos2 = ! is_local_rev2;
+ *is_repos1 = ! is_local_rev1;
+ *is_repos2 = ! is_local_rev2;
}
else
{
@@ -1133,154 +1419,133 @@ check_paths(const struct diff_parameters
URLs. We don't do that here, though. We simply record that it
needs to be done, which is information that helps us choose our
diff helper function. */
- paths->is_repos1 = ! is_local_rev1 || svn_path_is_url(params->path1);
- paths->is_repos2 = ! is_local_rev2 || svn_path_is_url(params->path2);
+ *is_repos1 = ! is_local_rev1 || svn_path_is_url(path1);
+ *is_repos2 = ! is_local_rev2 || svn_path_is_url(path2);
}
return SVN_NO_ERROR;
}
-/** Helper structure filled by diff_prepare_repos_repos */
-struct diff_repos_repos_t
-{
- /* URL created from path1 */
- const char *url1;
-
- /* URL created from path2 */
- const char *url2;
-
- /* The BASE_PATH for the diff */
- const char *base_path;
-
- /* url1 and url2 are the same */
- svn_boolean_t same_urls;
-
- /* Revision of url1 */
- svn_revnum_t rev1;
-
- /* Revision of url2 */
- svn_revnum_t rev2;
-
- /* Anchor based on url1 */
- const char *anchor1;
-
- /* Anchor based on url2 */
- const char *anchor2;
-
- /* Target based on url1 */
- const char *target1;
-
- /* Target based on url2 */
- const char *target2;
-
- /* RA session pointing at anchor1. */
- svn_ra_session_t *ra_session;
-};
-
-/** Helper function: prepare a repos repos diff. Fills DRR
- * structure. */
-static svn_error_t *
-diff_prepare_repos_repos(const struct diff_parameters *params,
- struct diff_repos_repos_t *drr,
+/** Prepare a repos repos diff between PATH1 and PATH2@PEG_REVISION,
+ * in the revision range REVISION1:REVISION2.
+ * Return URLs and peg revisions in *URL1, *REV1 and in *URL2, *REV2.
+ * Return suitable anchors in *ANCHOR1 and *ANCHOR2, and targets in
+ * *TARGET1 and *TARGET2, based on *URL1 and *URL2.
+ * Set *BASE_PATH corresponding to the URL opened in the new *RA_SESSION
+ * which is pointing at *ANCHOR1.
+ * Use client context CTX. Do all allocations in POOL. */
+static svn_error_t *
+diff_prepare_repos_repos(const char **url1,
+ const char **url2,
+ const char **base_path,
+ svn_revnum_t *rev1,
+ svn_revnum_t *rev2,
+ const char **anchor1,
+ const char **anchor2,
+ const char **target1,
+ const char **target2,
+ svn_ra_session_t **ra_session,
svn_client_ctx_t *ctx,
+ const char *path1,
+ const char *path2,
+ const svn_opt_revision_t *revision1,
+ const svn_opt_revision_t *revision2,
+ const svn_opt_revision_t *peg_revision,
apr_pool_t *pool)
{
- svn_ra_session_t *ra_session;
svn_node_kind_t kind1, kind2;
- const char *params_path2_abspath;
- const char *params_path1_abspath;
+ const char *path2_abspath;
+ const char *path1_abspath;
- if (!svn_path_is_url(params->path2))
- SVN_ERR(svn_dirent_get_absolute(¶ms_path2_abspath, params->path2,
+ if (!svn_path_is_url(path2))
+ SVN_ERR(svn_dirent_get_absolute(&path2_abspath, path2,
pool));
else
- params_path2_abspath = params->path2;
+ path2_abspath = path2;
- if (!svn_path_is_url(params->path1))
- SVN_ERR(svn_dirent_get_absolute(¶ms_path1_abspath, params->path1,
+ if (!svn_path_is_url(path1))
+ SVN_ERR(svn_dirent_get_absolute(&path1_abspath, path1,
pool));
else
- params_path1_abspath = params->path1;
+ path1_abspath = path1;
/* Figure out URL1 and URL2. */
- SVN_ERR(convert_to_url(&drr->url1, ctx->wc_ctx, params_path1_abspath,
+ SVN_ERR(convert_to_url(url1, ctx->wc_ctx, path1_abspath,
pool, pool));
- SVN_ERR(convert_to_url(&drr->url2, ctx->wc_ctx, params_path2_abspath,
+ SVN_ERR(convert_to_url(url2, ctx->wc_ctx, path2_abspath,
pool, pool));
- drr->same_urls = (strcmp(drr->url1, drr->url2) == 0);
/* We need exactly one BASE_PATH, so we'll let the BASE_PATH
calculated for PATH2 override the one for PATH1 (since the diff
will be "applied" to URL2 anyway). */
- drr->base_path = NULL;
- if (strcmp(drr->url1, params->path1) != 0)
- drr->base_path = params->path1;
- if (strcmp(drr->url2, params->path2) != 0)
- drr->base_path = params->path2;
+ *base_path = NULL;
+ if (strcmp(*url1, path1) != 0)
+ *base_path = path1;
+ if (strcmp(*url2, path2) != 0)
+ *base_path = path2;
- SVN_ERR(svn_client__open_ra_session_internal(&ra_session, drr->url2,
+ SVN_ERR(svn_client__open_ra_session_internal(ra_session, NULL, *url2,
NULL, NULL, FALSE,
TRUE, ctx, pool));
/* If we are performing a pegged diff, we need to find out what our
actual URLs will be. */
- if (params->peg_revision->kind != svn_opt_revision_unspecified)
+ if (peg_revision->kind != svn_opt_revision_unspecified)
{
svn_opt_revision_t *start_ignore, *end_ignore;
- SVN_ERR(svn_client__repos_locations(&drr->url1, &start_ignore,
- &drr->url2, &end_ignore,
- ra_session,
- params->path2,
- params->peg_revision,
- params->revision1,
- params->revision2,
+ SVN_ERR(svn_client__repos_locations(url1, &start_ignore,
+ url2, &end_ignore,
+ *ra_session,
+ path2,
+ peg_revision,
+ revision1,
+ revision2,
ctx, pool));
- /* Reparent the session, since drr->url2 might have changed as a result
+ /* Reparent the session, since *URL2 might have changed as a result
the above call. */
- SVN_ERR(svn_ra_reparent(ra_session, drr->url2, pool));
+ SVN_ERR(svn_ra_reparent(*ra_session, *url2, pool));
}
/* Resolve revision and get path kind for the second target. */
- SVN_ERR(svn_client__get_revision_number(&drr->rev2, NULL, ctx->wc_ctx,
- (params->path2 == drr->url2) ? NULL : params_path2_abspath,
- ra_session, params->revision2, pool));
- SVN_ERR(svn_ra_check_path(ra_session, "", drr->rev2, &kind2, pool));
+ SVN_ERR(svn_client__get_revision_number(rev2, NULL, ctx->wc_ctx,
+ (path2 == *url2) ? NULL : path2_abspath,
+ *ra_session, revision2, pool));
+ SVN_ERR(svn_ra_check_path(*ra_session, "", *rev2, &kind2, pool));
if (kind2 == svn_node_none)
return svn_error_createf
(SVN_ERR_FS_NOT_FOUND, NULL,
_("'%s' was not found in the repository at revision %ld"),
- drr->url2, drr->rev2);
+ *url2, *rev2);
/* Do the same for the first target. */
- SVN_ERR(svn_ra_reparent(ra_session, drr->url1, pool));
- SVN_ERR(svn_client__get_revision_number(&drr->rev1, NULL, ctx->wc_ctx,
- (params->path1 == drr->url1) ? NULL : params_path1_abspath,
- ra_session, params->revision1, pool));
- SVN_ERR(svn_ra_check_path(ra_session, "", drr->rev1, &kind1, pool));
+ SVN_ERR(svn_ra_reparent(*ra_session, *url1, pool));
+ SVN_ERR(svn_client__get_revision_number(rev1, NULL, ctx->wc_ctx,
+ (strcmp(path1, *url1) == 0) ? NULL : path1_abspath,
+ *ra_session, revision1, pool));
+ SVN_ERR(svn_ra_check_path(*ra_session, "", *rev1, &kind1, pool));
if (kind1 == svn_node_none)
return svn_error_createf
(SVN_ERR_FS_NOT_FOUND, NULL,
_("'%s' was not found in the repository at revision %ld"),
- drr->url1, drr->rev1);
+ *url1, *rev1);
/* Choose useful anchors and targets for our two URLs. */
- drr->anchor1 = drr->url1;
- drr->anchor2 = drr->url2;
- drr->target1 = "";
- drr->target2 = "";
+ *anchor1 = *url1;
+ *anchor2 = *url2;
+ *target1 = "";
+ *target2 = "";
if ((kind1 == svn_node_file) || (kind2 == svn_node_file))
{
- svn_uri_split(drr->url1, &drr->anchor1, &drr->target1, pool);
- drr->target1 = svn_path_uri_decode(drr->target1, pool);
- svn_uri_split(drr->url2, &drr->anchor2, &drr->target2, pool);
- drr->target2 = svn_path_uri_decode(drr->target2, pool);
- if (drr->base_path)
- drr->base_path = svn_dirent_dirname(drr->base_path, pool);
- SVN_ERR(svn_ra_reparent(ra_session, drr->anchor1, pool));
+ svn_uri_split(anchor1, target1, *url1, pool);
+ *target1 = svn_path_uri_decode(*target1, pool);
+ svn_uri_split(anchor2, target2, *url2, pool);
+ *target2 = svn_path_uri_decode(*target2, pool);
+ if (*base_path)
+ *base_path = svn_dirent_dirname(*base_path, pool);
+ SVN_ERR(svn_ra_reparent(*ra_session, *anchor1, pool));
}
- drr->ra_session = ra_session;
return SVN_NO_ERROR;
}
@@ -1339,6 +1604,7 @@ diff_wc_wc(const char *path1,
svn_depth_t depth,
svn_boolean_t ignore_ancestry,
svn_boolean_t show_copies_as_adds,
+ svn_boolean_t use_git_diff_format,
const apr_array_header_t *changelists,
const svn_wc_diff_callbacks4_t *callbacks,
struct diff_cmd_baton *callback_baton,
@@ -1387,9 +1653,8 @@ diff_wc_wc(const char *path1,
path1,
callbacks, callback_baton,
depth,
- ignore_ancestry,
- show_copies_as_adds,
- changelists,
+ ignore_ancestry, show_copies_as_adds,
+ use_git_diff_format, changelists,
ctx->cancel_func, ctx->cancel_baton,
pool));
return SVN_NO_ERROR;
@@ -1398,18 +1663,24 @@ diff_wc_wc(const char *path1,
/* Perform a diff between two repository paths.
- DIFF_PARAM.PATH1 and DIFF_PARAM.PATH2 may be either URLs or the working
- copy paths. DIFF_PARAM.REVISION1 and DIFF_PARAM.REVISION2 are their
- respective revisions. If DIFF_PARAM.PEG_REVISION is specified,
- DIFF_PARAM.PATH2 is the path at the peg revision, and the actual two
- paths compared are determined by following copy history from PATH2.
+ PATH1 and PATH2 may be either URLs or the working copy paths.
+ REVISION1 and REVISION2 are their respective revisions.
+ If PEG_REVISION is specified, PATH2 is the path at the peg revision,
+ and the actual two paths compared are determined by following copy
+ history from PATH2.
All other options are the same as those passed to svn_client_diff5(). */
static svn_error_t *
-diff_repos_repos(const struct diff_parameters *diff_param,
- const svn_wc_diff_callbacks4_t *callbacks,
+diff_repos_repos(const svn_wc_diff_callbacks4_t *callbacks,
struct diff_cmd_baton *callback_baton,
svn_client_ctx_t *ctx,
+ const char *path1,
+ const char *path2,
+ const svn_opt_revision_t *revision1,
+ const svn_opt_revision_t *revision2,
+ const svn_opt_revision_t *peg_revision,
+ svn_depth_t depth,
+ svn_boolean_t ignore_ancestry,
apr_pool_t *pool)
{
svn_ra_session_t *extra_ra_session;
@@ -1420,44 +1691,59 @@ diff_repos_repos(const struct diff_param
const svn_delta_editor_t *diff_editor;
void *diff_edit_baton;
- struct diff_repos_repos_t drr;
+ const char *url1;
+ const char *url2;
+ const char *base_path;
+ svn_revnum_t rev1;
+ svn_revnum_t rev2;
+ const char *anchor1;
+ const char *anchor2;
+ const char *target1;
+ const char *target2;
+ svn_ra_session_t *ra_session;
/* Prepare info for the repos repos diff. */
- SVN_ERR(diff_prepare_repos_repos(diff_param, &drr, ctx, pool));
+ SVN_ERR(diff_prepare_repos_repos(&url1, &url2, &base_path, &rev1, &rev2,
+ &anchor1, &anchor2, &target1, &target2,
+ &ra_session, ctx, path1, path2,
+ revision1, revision2, peg_revision,
+ pool));
/* Get actual URLs. */
- callback_baton->orig_path_1 = drr.url1;
- callback_baton->orig_path_2 = drr.url2;
+ callback_baton->orig_path_1 = url1;
+ callback_baton->orig_path_2 = url2;
/* Get numeric revisions. */
- callback_baton->revnum1 = drr.rev1;
- callback_baton->revnum2 = drr.rev2;
+ callback_baton->revnum1 = rev1;
+ callback_baton->revnum2 = rev2;
+
+ callback_baton->ra_session = ra_session;
/* Now, we open an extra RA session to the correct anchor
location for URL1. This is used during the editor calls to fetch file
contents. */
- SVN_ERR(svn_client__open_ra_session_internal(&extra_ra_session, drr.anchor1,
- NULL, NULL, FALSE, TRUE, ctx,
- pool));
+ SVN_ERR(svn_client__open_ra_session_internal(&extra_ra_session, NULL,
+ anchor1, NULL, NULL, FALSE,
+ TRUE, ctx, pool));
/* Set up the repos_diff editor on BASE_PATH, if available.
Otherwise, we just use "". */
SVN_ERR(svn_client__get_diff_editor
- (drr.base_path ? drr.base_path : "",
- NULL, callbacks, callback_baton, diff_param->depth,
- FALSE /* doesn't matter for diff */, extra_ra_session, drr.rev1,
+ (base_path ? base_path : "",
+ NULL, callbacks, callback_baton, depth,
+ FALSE /* doesn't matter for diff */, extra_ra_session, rev1,
NULL /* no notify_func */, NULL /* no notify_baton */,
ctx->cancel_func, ctx->cancel_baton,
&diff_editor, &diff_edit_baton, pool));
/* We want to switch our txn into URL2 */
SVN_ERR(svn_ra_do_diff3
- (drr.ra_session, &reporter, &reporter_baton, drr.rev2, drr.target1,
- diff_param->depth, diff_param->ignore_ancestry, TRUE,
- drr.url2, diff_editor, diff_edit_baton, pool));
+ (ra_session, &reporter, &reporter_baton, rev2, target1,
+ depth, ignore_ancestry, TRUE,
+ url2, diff_editor, diff_edit_baton, pool));
/* Drive the reporter; do the diff. */
- SVN_ERR(reporter->set_path(reporter_baton, "", drr.rev1,
+ SVN_ERR(reporter->set_path(reporter_baton, "", rev1,
svn_depth_infinity,
FALSE, NULL,
pool));
@@ -1485,6 +1771,7 @@ diff_repos_wc(const char *path1,
svn_depth_t depth,
svn_boolean_t ignore_ancestry,
svn_boolean_t show_copies_as_adds,
+ svn_boolean_t use_git_diff_format,
const apr_array_header_t *changelists,
const svn_wc_diff_callbacks4_t *callbacks,
struct diff_cmd_baton *callback_baton,
@@ -1558,9 +1845,13 @@ diff_repos_wc(const char *path1,
}
/* Establish RA session to path2's anchor */
- SVN_ERR(svn_client__open_ra_session_internal(&ra_session, anchor_url,
+ SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, anchor_url,
NULL, NULL, FALSE, TRUE,
ctx, pool));
+ callback_baton->ra_session = ra_session;
+ if (use_git_diff_format)
+ 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,
@@ -1570,6 +1861,7 @@ diff_repos_wc(const char *path1,
depth,
ignore_ancestry,
show_copies_as_adds,
+ use_git_diff_format,
rev2_is_base,
reverse,
changelists,
@@ -1578,7 +1870,7 @@ diff_repos_wc(const char *path1,
/* Tell the RA layer we want a delta to change our txn to URL1 */
SVN_ERR(svn_client__get_revision_number(&rev, NULL, ctx->wc_ctx,
- (path1 == url1) ? NULL : abspath1,
+ (strcmp(path1, url1) == 0) ? NULL : abspath1,
ra_session, revision1, pool));
if (!reverse)
@@ -1613,57 +1905,61 @@ diff_repos_wc(const char *path1,
/* This is basically just the guts of svn_client_diff[_peg]5(). */
static svn_error_t *
-do_diff(const struct diff_parameters *diff_param,
- const svn_wc_diff_callbacks4_t *callbacks,
+do_diff(const svn_wc_diff_callbacks4_t *callbacks,
struct diff_cmd_baton *callback_baton,
svn_client_ctx_t *ctx,
+ const char *path1,
+ const char *path2,
+ const svn_opt_revision_t *revision1,
+ const svn_opt_revision_t *revision2,
+ const svn_opt_revision_t *peg_revision,
+ svn_depth_t depth,
+ svn_boolean_t ignore_ancestry,
+ svn_boolean_t show_copies_as_adds,
+ svn_boolean_t use_git_diff_format,
+ const apr_array_header_t *changelists,
apr_pool_t *pool)
{
- struct diff_paths diff_paths;
+ svn_boolean_t is_repos1;
+ svn_boolean_t is_repos2;
/* Check if paths/revisions are urls/local. */
- SVN_ERR(check_paths(diff_param, &diff_paths));
+ SVN_ERR(check_paths(&is_repos1, &is_repos2, path1, path2,
+ revision1, revision2, peg_revision));
- if (diff_paths.is_repos1)
+ if (is_repos1)
{
- if (diff_paths.is_repos2)
+ if (is_repos2)
{
- SVN_ERR(diff_repos_repos(diff_param, callbacks, callback_baton,
- ctx, pool));
+ SVN_ERR(diff_repos_repos(callbacks, callback_baton, ctx,
+ path1, path2, revision1, revision2,
+ peg_revision, depth, ignore_ancestry,
+ pool));
}
else /* path2 is a working copy path */
{
- SVN_ERR(diff_repos_wc(diff_param->path1, diff_param->revision1,
- diff_param->peg_revision,
- diff_param->path2, diff_param->revision2,
- FALSE, diff_param->depth,
- diff_param->ignore_ancestry,
- diff_param->show_copies_as_adds,
- diff_param->changelists,
+ SVN_ERR(diff_repos_wc(path1, revision1, peg_revision,
+ path2, revision2, FALSE, depth,
+ ignore_ancestry, show_copies_as_adds,
+ use_git_diff_format, changelists,
callbacks, callback_baton, ctx, pool));
}
}
else /* path1 is a working copy path */
{
- if (diff_paths.is_repos2)
+ if (is_repos2)
{
- SVN_ERR(diff_repos_wc(diff_param->path2, diff_param->revision2,
- diff_param->peg_revision,
- diff_param->path1, diff_param->revision1,
- TRUE, diff_param->depth,
- diff_param->ignore_ancestry,
- diff_param->show_copies_as_adds,
- diff_param->changelists,
+ SVN_ERR(diff_repos_wc(path2, revision2, peg_revision,
+ path1, revision1, TRUE, depth,
+ ignore_ancestry, show_copies_as_adds,
+ use_git_diff_format, changelists,
callbacks, callback_baton, ctx, pool));
}
else /* path2 is a working copy path */
{
- SVN_ERR(diff_wc_wc(diff_param->path1, diff_param->revision1,
- diff_param->path2, diff_param->revision2,
- diff_param->depth,
- diff_param->ignore_ancestry,
- diff_param->show_copies_as_adds,
- diff_param->changelists,
+ SVN_ERR(diff_wc_wc(path1, revision1, path2, revision2,
+ depth, ignore_ancestry, show_copies_as_adds,
+ use_git_diff_format, changelists,
callbacks, callback_baton, ctx, pool));
}
}
@@ -1673,10 +1969,16 @@ do_diff(const struct diff_parameters *di
/* Perform a diff summary between two repository paths. */
static svn_error_t *
-diff_summarize_repos_repos(const struct diff_parameters *diff_param,
- svn_client_diff_summarize_func_t summarize_func,
+diff_summarize_repos_repos(svn_client_diff_summarize_func_t summarize_func,
void *summarize_baton,
svn_client_ctx_t *ctx,
+ const char *path1,
+ const char *path2,
+ const svn_opt_revision_t *revision1,
+ const svn_opt_revision_t *revision2,
+ const svn_opt_revision_t *peg_revision,
+ svn_depth_t depth,
+ svn_boolean_t ignore_ancestry,
apr_pool_t *pool)
{
svn_ra_session_t *extra_ra_session;
@@ -1687,32 +1989,45 @@ diff_summarize_repos_repos(const struct
const svn_delta_editor_t *diff_editor;
void *diff_edit_baton;
- struct diff_repos_repos_t drr;
+ const char *url1;
+ const char *url2;
+ const char *base_path;
+ svn_revnum_t rev1;
+ svn_revnum_t rev2;
+ const char *anchor1;
+ const char *anchor2;
+ const char *target1;
+ const char *target2;
+ svn_ra_session_t *ra_session;
/* Prepare info for the repos repos diff. */
- SVN_ERR(diff_prepare_repos_repos(diff_param, &drr, ctx, pool));
+ SVN_ERR(diff_prepare_repos_repos(&url1, &url2, &base_path, &rev1, &rev2,
+ &anchor1, &anchor2, &target1, &target2,
+ &ra_session, ctx,
+ path1, path2, revision1, revision2,
+ peg_revision, pool));
/* Now, we open an extra RA session to the correct anchor
location for URL1. This is used to get the kind of deleted paths. */
- SVN_ERR(svn_client__open_ra_session_internal(&extra_ra_session, drr.anchor1,
- NULL, NULL, FALSE, TRUE,
- ctx, pool));
+ SVN_ERR(svn_client__open_ra_session_internal(&extra_ra_session, NULL,
+ anchor1, NULL, NULL, FALSE,
+ TRUE, ctx, pool));
/* Set up the repos_diff editor. */
SVN_ERR(svn_client__get_diff_summarize_editor
- (drr.target2, summarize_func,
- summarize_baton, extra_ra_session, drr.rev1, ctx->cancel_func,
+ (target2, summarize_func,
+ summarize_baton, extra_ra_session, rev1, ctx->cancel_func,
ctx->cancel_baton, &diff_editor, &diff_edit_baton, pool));
/* We want to switch our txn into URL2 */
SVN_ERR(svn_ra_do_diff3
- (drr.ra_session, &reporter, &reporter_baton, drr.rev2, drr.target1,
- diff_param->depth, diff_param->ignore_ancestry,
- FALSE /* do not create text delta */, drr.url2, diff_editor,
+ (ra_session, &reporter, &reporter_baton, rev2, target1,
+ depth, ignore_ancestry,
+ FALSE /* do not create text delta */, url2, diff_editor,
diff_edit_baton, pool));
/* Drive the reporter; do the diff. */
- SVN_ERR(reporter->set_path(reporter_baton, "", drr.rev1,
+ SVN_ERR(reporter->set_path(reporter_baton, "", rev1,
svn_depth_infinity,
FALSE, NULL, pool));
return reporter->finish_report(reporter_baton, pool);
@@ -1720,20 +2035,30 @@ diff_summarize_repos_repos(const struct
/* This is basically just the guts of svn_client_diff_summarize[_peg]2(). */
static svn_error_t *
-do_diff_summarize(const struct diff_parameters *diff_param,
- svn_client_diff_summarize_func_t summarize_func,
+do_diff_summarize(svn_client_diff_summarize_func_t summarize_func,
void *summarize_baton,
svn_client_ctx_t *ctx,
+ const char *path1,
+ const char *path2,
+ const svn_opt_revision_t *revision1,
+ const svn_opt_revision_t *revision2,
+ const svn_opt_revision_t *peg_revision,
+ svn_depth_t depth,
+ svn_boolean_t ignore_ancestry,
apr_pool_t *pool)
{
- struct diff_paths diff_paths;
+ svn_boolean_t is_repos1;
+ svn_boolean_t is_repos2;
/* Check if paths/revisions are urls/local. */
- SVN_ERR(check_paths(diff_param, &diff_paths));
+ SVN_ERR(check_paths(&is_repos1, &is_repos2, path1, path2,
+ revision1, revision2, peg_revision));
- if (diff_paths.is_repos1 && diff_paths.is_repos2)
- return diff_summarize_repos_repos(diff_param, summarize_func,
- summarize_baton, ctx, pool);
+ if (is_repos1 && is_repos2)
+ return diff_summarize_repos_repos(summarize_func, summarize_baton, ctx,
+ path1, path2, revision1, revision2,
+ peg_revision, depth, ignore_ancestry,
+ pool);
else
return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
_("Summarizing diff can only compare repository "
@@ -1854,6 +2179,7 @@ svn_client_diff5(const apr_array_header_
svn_boolean_t no_diff_deleted,
svn_boolean_t show_copies_as_adds,
svn_boolean_t ignore_content_type,
+ svn_boolean_t use_git_diff_format,
const char *header_encoding,
apr_file_t *outfile,
apr_file_t *errfile,
@@ -1861,8 +2187,6 @@ svn_client_diff5(const apr_array_header_
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
- struct diff_parameters diff_params;
-
struct diff_cmd_baton diff_cmd_baton;
svn_wc_diff_callbacks4_t diff_callbacks;
@@ -1870,18 +2194,6 @@ svn_client_diff5(const apr_array_header_
svn_opt_revision_t peg_revision;
peg_revision.kind = svn_opt_revision_unspecified;
- /* fill diff_param */
- diff_params.path1 = path1;
- diff_params.revision1 = revision1;
- diff_params.path2 = path2;
- diff_params.revision2 = revision2;
- diff_params.peg_revision = &peg_revision;
- diff_params.depth = depth;
- diff_params.ignore_ancestry = ignore_ancestry;
- diff_params.no_diff_deleted = no_diff_deleted;
- diff_params.show_copies_as_adds = show_copies_as_adds;
- diff_params.changelists = changelists;
-
/* setup callback and baton */
diff_callbacks.file_changed = diff_file_changed;
diff_callbacks.file_added = diff_file_added;
@@ -1908,8 +2220,16 @@ svn_client_diff5(const apr_array_header_
diff_cmd_baton.force_empty = FALSE;
diff_cmd_baton.force_binary = ignore_content_type;
diff_cmd_baton.relative_to_dir = relative_to_dir;
-
- return do_diff(&diff_params, &diff_callbacks, &diff_cmd_baton, ctx, pool);
+ diff_cmd_baton.use_git_diff_format = use_git_diff_format;
+ 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,
+ depth, ignore_ancestry, show_copies_as_adds,
+ use_git_diff_format, changelists, pool);
}
svn_error_t *
@@ -1924,6 +2244,7 @@ svn_client_diff_peg5(const apr_array_hea
svn_boolean_t no_diff_deleted,
svn_boolean_t show_copies_as_adds,
svn_boolean_t ignore_content_type,
+ svn_boolean_t use_git_diff_format,
const char *header_encoding,
apr_file_t *outfile,
apr_file_t *errfile,
@@ -1931,23 +2252,9 @@ svn_client_diff_peg5(const apr_array_hea
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
- struct diff_parameters diff_params;
-
struct diff_cmd_baton diff_cmd_baton;
svn_wc_diff_callbacks4_t diff_callbacks;
- /* fill diff_param */
- diff_params.path1 = path;
- diff_params.revision1 = start_revision;
- diff_params.path2 = path;
- diff_params.revision2 = end_revision;
- diff_params.peg_revision = peg_revision;
- diff_params.depth = depth;
- diff_params.ignore_ancestry = ignore_ancestry;
- diff_params.no_diff_deleted = no_diff_deleted;
- diff_params.show_copies_as_adds = show_copies_as_adds;
- diff_params.changelists = changelists;
-
/* setup callback and baton */
diff_callbacks.file_changed = diff_file_changed;
diff_callbacks.file_added = diff_file_added;
@@ -1974,8 +2281,16 @@ svn_client_diff_peg5(const apr_array_hea
diff_cmd_baton.force_empty = FALSE;
diff_cmd_baton.force_binary = ignore_content_type;
diff_cmd_baton.relative_to_dir = relative_to_dir;
-
- return do_diff(&diff_params, &diff_callbacks, &diff_cmd_baton, ctx, pool);
+ diff_cmd_baton.use_git_diff_format = use_git_diff_format;
+ 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,
+ depth, ignore_ancestry, show_copies_as_adds,
+ use_git_diff_format, changelists, pool);
}
svn_error_t *
@@ -1991,25 +2306,14 @@ svn_client_diff_summarize2(const char *p
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
- struct diff_parameters diff_params;
-
/* We will never do a pegged diff from here. */
svn_opt_revision_t peg_revision;
peg_revision.kind = svn_opt_revision_unspecified;
- /* fill diff_param */
- diff_params.path1 = path1;
- diff_params.revision1 = revision1;
- diff_params.path2 = path2;
- diff_params.revision2 = revision2;
- diff_params.peg_revision = &peg_revision;
- diff_params.depth = depth;
- diff_params.ignore_ancestry = ignore_ancestry;
- diff_params.no_diff_deleted = FALSE;
- diff_params.changelists = changelists;
-
- return do_diff_summarize(&diff_params, summarize_func, summarize_baton,
- ctx, pool);
+ /* ### CHANGELISTS parameter isn't used */
+ return do_diff_summarize(summarize_func, summarize_baton, ctx,
+ path1, path2, revision1, revision2, &peg_revision,
+ depth, ignore_ancestry, pool);
}
svn_error_t *
@@ -2025,21 +2329,10 @@ svn_client_diff_summarize_peg2(const cha
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
- struct diff_parameters diff_params;
-
- /* fill diff_param */
- diff_params.path1 = path;
- diff_params.revision1 = start_revision;
- diff_params.path2 = path;
- diff_params.revision2 = end_revision;
- diff_params.peg_revision = peg_revision;
- diff_params.depth = depth;
- diff_params.ignore_ancestry = ignore_ancestry;
- diff_params.no_diff_deleted = FALSE;
- diff_params.changelists = changelists;
-
- return do_diff_summarize(&diff_params, summarize_func, summarize_baton,
- ctx, pool);
+ /* ### CHANGELISTS parameter isn't used */
+ return do_diff_summarize(summarize_func, summarize_baton, ctx,
+ path, path, start_revision, end_revision,
+ peg_revision, depth, ignore_ancestry, pool);
}
svn_client_diff_summarize_t *
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/export.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/export.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/export.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/export.c Wed Sep 15 19:32:26 2010
@@ -326,11 +326,11 @@ copy_versioned_files(const char *from,
from_abspath, pool));
if (is_added)
{
- const char *copyfrom_url;
- SVN_ERR(svn_wc__node_get_copyfrom_info(©from_url, NULL, NULL,
- ctx->wc_ctx, from_abspath,
- pool, pool));
- if (! copyfrom_url)
+ const char *is_copied;
+ SVN_ERR(svn_wc__node_get_copyfrom_info(&is_copied, NULL, NULL,
+ NULL, NULL, ctx->wc_ctx,
+ from_abspath, pool, pool));
+ if (! is_copied)
return SVN_NO_ERROR;
}
}
@@ -349,21 +349,26 @@ copy_versioned_files(const char *from,
if (from_kind == svn_node_dir)
{
+ apr_fileperms_t perm = APR_OS_DEFAULT;
+
/* Try to make the new directory. If this fails because the
directory already exists, check our FORCE flag to see if we
care. */
- /* Skip retrieving the umask on windows. Apr does not implement setting
+ /* Keep the source directory's permissions if applicable.
+ Skip retrieving the umask on windows. Apr does not implement setting
filesystem privileges on Windows.
Retrieving the file permissions with APR_FINFO_PROT | APR_FINFO_OWNER
is documented to be 'incredibly expensive' */
-#ifdef WIN32
- err = svn_io_dir_make(to, APR_OS_DEFAULT, pool);
-#else
- apr_finfo_t finfo;
- SVN_ERR(svn_io_stat(&finfo, from, APR_FINFO_PROT, pool));
- err = svn_io_dir_make(to, finfo.protection, pool);
+#ifndef WIN32
+ if (revision->kind == svn_opt_revision_working)
+ {
+ apr_finfo_t finfo;
+ SVN_ERR(svn_io_stat(&finfo, from, APR_FINFO_PROT, pool));
+ perm = finfo.protection;
+ }
#endif
+ err = svn_io_dir_make(to, perm, pool);
if (err)
{
if (! APR_STATUS_IS_EEXIST(err->apr_err))
@@ -708,7 +713,12 @@ add_file(const char *path,
struct edit_baton *eb = pb->edit_baton;
struct file_baton *fb = apr_pcalloc(pool, sizeof(*fb));
const char *full_path = svn_dirent_join(eb->root_path, path, pool);
- const char *full_url = svn_uri_join(eb->root_url, path, pool);
+
+ /* PATH is not canonicalized, i.e. it may still contain spaces etc.
+ * but EB->root_url is. */
+ const char *full_url = svn_path_url_add_component2(eb->root_url,
+ path,
+ pool);
fb->edit_baton = eb;
fb->path = full_path;
@@ -937,6 +947,11 @@ svn_client_export5(svn_revnum_t *result_
SVN_ERR_ASSERT(peg_revision != NULL);
SVN_ERR_ASSERT(revision != NULL);
+ if (svn_path_is_url(to))
+ return svn_error_return(svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("'%s' is not a local path"),
+ to));
+
peg_revision = svn_cl__rev_default_to_head_or_working(peg_revision, from);
revision = svn_cl__rev_default_to_peg(revision, peg_revision);
@@ -1083,7 +1098,8 @@ svn_client_export5(svn_revnum_t *result_
SVN_ERR(svn_client__fetch_externals(eb->externals,
from, to_abspath,
repos_root_url, depth, TRUE,
- &use_sleep, ctx, pool));
+ native_eol, &use_sleep,
+ ctx, pool));
}
}
else if (kind == svn_node_none)
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/externals.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/externals.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/externals.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/externals.c Wed Sep 15 19:32:26 2010
@@ -62,6 +62,9 @@ struct handle_external_item_change_baton
/* Passed through to svn_client_* functions. */
svn_client_ctx_t *ctx;
+ /* Passed to svn_client_exportX() */
+ const char *native_eol;
+
svn_boolean_t *timestamp_sleep;
svn_boolean_t is_export;
@@ -116,7 +119,7 @@ relegate_dir_external(void *baton,
svn_error_clear(err);
err = SVN_NO_ERROR;
- svn_dirent_split(b->local_abspath, &parent_dir, &dirname, scratch_pool);
+ svn_dirent_split(&parent_dir, &dirname, b->local_abspath, scratch_pool);
/* Reserve the new dir name. */
SVN_ERR(svn_io_open_uniquely_named(NULL, &new_path,
@@ -221,8 +224,8 @@ switch_dir_external(const char *path,
/* Get the repos root of the new URL. */
SVN_ERR(svn_client__open_ra_session_internal
- (&ra_session, url, NULL, NULL, FALSE, TRUE,
- ctx, subpool));
+ (&ra_session, NULL, url, NULL, NULL,
+ FALSE, TRUE, ctx, subpool));
SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root,
subpool));
@@ -274,9 +277,10 @@ switch_dir_external(const char *path,
baton.cancel_baton = ctx->cancel_baton;
/* Buh-bye, old and busted ... */
- SVN_ERR(svn_wc__call_with_write_lock(relegate_dir_external, &baton,
- ctx->wc_ctx, local_abspath,
- pool, pool));
+ SVN_ERR(svn_wc__acquire_write_lock(NULL, ctx->wc_ctx, local_abspath,
+ FALSE, pool, pool));
+
+ SVN_ERR(relegate_dir_external(&baton, pool, pool));
}
else
{
@@ -362,7 +366,7 @@ switch_file_external(const char *path,
url, dest_wc_repos_root_url);
SVN_ERR(svn_wc__acquire_write_lock(NULL, ctx->wc_ctx, anchor_abspath,
- subpool, subpool));
+ FALSE, subpool, subpool));
}
err = svn_wc_read_kind(&kind, ctx->wc_ctx, local_abspath, FALSE, subpool);
@@ -439,8 +443,8 @@ switch_file_external(const char *path,
if (err)
goto cleanup;
- err = svn_wc_register_file_external(ctx->wc_ctx, local_abspath, url,
- peg_revision, revision, subpool);
+ err = svn_wc__register_file_external(ctx->wc_ctx, local_abspath, url,
+ peg_revision, revision, subpool);
if (err)
goto cleanup;
}
@@ -854,7 +858,8 @@ handle_external_item_change(const void *
SVN_ERR(svn_client_export4(NULL, new_item->url, local_abspath,
&(new_item->peg_revision),
&(new_item->revision),
- TRUE, FALSE, svn_depth_infinity, NULL,
+ TRUE, FALSE, svn_depth_infinity,
+ ib->native_eol,
ib->ctx, ib->iter_pool));
else
SVN_ERR(svn_client__checkout_internal
@@ -872,7 +877,8 @@ handle_external_item_change(const void *
SVN_ERR(svn_client_export4(NULL, new_item->url, local_abspath,
&(new_item->peg_revision),
&(new_item->revision),
- FALSE, TRUE, svn_depth_infinity, NULL,
+ FALSE, TRUE, svn_depth_infinity,
+ ib->native_eol,
ib->ctx, ib->iter_pool));
else
SVN_ERR(switch_file_external(local_abspath,
@@ -909,7 +915,7 @@ handle_external_item_change(const void *
if (! lock_existed)
{
SVN_ERR(svn_wc__acquire_write_lock(NULL, ib->ctx->wc_ctx,
- local_abspath,
+ local_abspath, FALSE,
ib->iter_pool,
ib->iter_pool));
}
@@ -1067,6 +1073,9 @@ struct handle_externals_desc_change_bato
svn_boolean_t *timestamp_sleep;
svn_boolean_t is_export;
+ /* Passed to svn_client_exportX() */
+ const char *native_eol;
+
apr_pool_t *pool;
};
@@ -1157,6 +1166,7 @@ handle_externals_desc_change(const void
ib.repos_root_url = cb->repos_root_url;
ib.ctx = cb->ctx;
ib.is_export = cb->is_export;
+ ib.native_eol = cb->native_eol;
ib.timestamp_sleep = cb->timestamp_sleep;
ib.pool = cb->pool;
ib.iter_pool = svn_pool_create(cb->pool);
@@ -1261,6 +1271,7 @@ svn_client__handle_externals(apr_hash_t
cb.ctx = ctx;
cb.timestamp_sleep = timestamp_sleep;
cb.is_export = FALSE;
+ cb.native_eol = NULL;
cb.pool = pool;
return svn_hash_diff(cb.externals_old, cb.externals_new,
@@ -1275,6 +1286,7 @@ svn_client__fetch_externals(apr_hash_t *
const char *repos_root_url,
svn_depth_t requested_depth,
svn_boolean_t is_export,
+ const char *native_eol,
svn_boolean_t *timestamp_sleep,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
@@ -1292,6 +1304,7 @@ svn_client__fetch_externals(apr_hash_t *
cb.to_abspath = to_abspath;
cb.repos_root_url = repos_root_url;
cb.timestamp_sleep = timestamp_sleep;
+ cb.native_eol = native_eol;
cb.is_export = is_export;
cb.pool = pool;
@@ -1367,7 +1380,7 @@ svn_client__do_external_status(svn_clien
SVN_ERR(svn_client_status5(NULL, ctx, fullpath,
&(external->revision),
depth, get_all, update,
- no_ignore, FALSE, NULL,
+ no_ignore, FALSE, FALSE, NULL,
status_func, status_baton,
iterpool));
}