You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by vm...@apache.org on 2012/05/29 03:39:49 UTC
svn commit: r1343447 [4/27] - in /subversion/branches/javahl-ra: ./ build/
build/ac-macros/ build/generator/ build/generator/templates/ build/win32/
contrib/client-side/emacs/ contrib/server-side/ notes/
notes/api-errata/1.8/ notes/merge-tracking/ subv...
Modified: subversion/branches/javahl-ra/subversion/libsvn_client/diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/diff.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/diff.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/diff.c Tue May 29 01:39:41 2012
@@ -708,8 +708,7 @@ display_prop_diffs(const apr_array_heade
if (!val_has_eol)
{
const char *s = "\\ No newline at end of property" APR_EOL_STR;
- apr_size_t len = strlen(s);
- SVN_ERR(svn_stream_write(outstream, s, &len));
+ SVN_ERR(svn_stream_puts(outstream, s));
}
}
}
@@ -778,7 +777,10 @@ struct diff_cmd_baton {
const char *relative_to_dir;
/* Whether property differences are ignored. */
- svn_boolean_t ignore_prop_diff;
+ svn_boolean_t ignore_properties;
+
+ /* Whether to show only property changes. */
+ svn_boolean_t properties_only;
/* Whether we're producing a git-style diff. */
svn_boolean_t use_git_diff_format;
@@ -798,6 +800,9 @@ struct diff_cmd_baton {
/* The anchor to prefix before wc paths */
const char *anchor;
+ /* Whether the local diff target of a repos->wc diff is a copy. */
+ svn_boolean_t repos_wc_diff_target_is_copy;
+
/* 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. */
@@ -832,7 +837,7 @@ diff_props_changed(svn_wc_notify_state_t
svn_boolean_t show_diff_header;
/* If property differences are ignored, there's nothing to do. */
- if (diff_cmd_baton->ignore_prop_diff)
+ if (diff_cmd_baton->ignore_properties)
return SVN_NO_ERROR;
SVN_ERR(svn_categorize_props(propchanges, NULL, NULL, &props,
@@ -930,6 +935,10 @@ diff_content_changed(const char *path,
const char *path1 = diff_cmd_baton->orig_path_1;
const char *path2 = diff_cmd_baton->orig_path_2;
+ /* If only property differences are shown, there's nothing to do. */
+ if (diff_cmd_baton->properties_only)
+ return SVN_NO_ERROR;
+
/* Generate the diff headers. */
SVN_ERR(adjust_paths_for_diff_labels(&path, &path1, &path2,
rel_to_dir, subpool));
@@ -1126,6 +1135,19 @@ diff_file_changed(svn_wc_notify_state_t
{
struct diff_cmd_baton *diff_cmd_baton = diff_baton;
+ /* During repos->wc diff of a copy revision numbers obtained
+ * from the working copy are always SVN_INVALID_REVNUM. */
+ if (diff_cmd_baton->repos_wc_diff_target_is_copy)
+ {
+ if (rev1 == SVN_INVALID_REVNUM &&
+ diff_cmd_baton->revnum1 != SVN_INVALID_REVNUM)
+ rev1 = diff_cmd_baton->revnum1;
+
+ if (rev2 == SVN_INVALID_REVNUM &&
+ diff_cmd_baton->revnum2 != SVN_INVALID_REVNUM)
+ rev2 = diff_cmd_baton->revnum2;
+ }
+
if (diff_cmd_baton->anchor)
path = svn_dirent_join(diff_cmd_baton->anchor, path, scratch_pool);
if (tmpfile1)
@@ -1172,6 +1194,19 @@ diff_file_added(svn_wc_notify_state_t *c
{
struct diff_cmd_baton *diff_cmd_baton = diff_baton;
+ /* During repos->wc diff of a copy revision numbers obtained
+ * from the working copy are always SVN_INVALID_REVNUM. */
+ if (diff_cmd_baton->repos_wc_diff_target_is_copy)
+ {
+ if (rev1 == SVN_INVALID_REVNUM &&
+ diff_cmd_baton->revnum1 != SVN_INVALID_REVNUM)
+ rev1 = diff_cmd_baton->revnum1;
+
+ if (rev2 == SVN_INVALID_REVNUM &&
+ diff_cmd_baton->revnum2 != SVN_INVALID_REVNUM)
+ rev2 = diff_cmd_baton->revnum2;
+ }
+
if (diff_cmd_baton->anchor)
path = svn_dirent_join(diff_cmd_baton->anchor, path, scratch_pool);
@@ -1409,7 +1444,8 @@ convert_to_url(const char **url,
/** Check if paths PATH_OR_URL1 and PATH_OR_URL2 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.
+ * unspecified, ensure that at least one of the two revisions is not
+ * BASE or WORKING.
* If PATH_OR_URL1 can only be found in the repository, set *IS_REPOS1
* to TRUE. If PATH_OR_URL2 can only be found in the repository, set
* *IS_REPOS2 to TRUE. */
@@ -1430,8 +1466,8 @@ check_paths(svn_boolean_t *is_repos1,
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. */
+ /* Revisions can be said to be local or remote.
+ * BASE and WORKING are local revisions. */
is_local_rev1 =
((revision1->kind == svn_opt_revision_base)
|| (revision1->kind == svn_opt_revision_working));
@@ -1439,25 +1475,18 @@ check_paths(svn_boolean_t *is_repos1,
((revision2->kind == svn_opt_revision_base)
|| (revision2->kind == svn_opt_revision_working));
- 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"));
-
- *is_repos1 = ! is_local_rev1;
- *is_repos2 = ! is_local_rev2;
- }
- else
- {
- /* Working copy paths with non-local revisions get turned into
- 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. */
- *is_repos1 = ! is_local_rev1 || svn_path_is_url(path_or_url1);
- *is_repos2 = ! is_local_rev2 || svn_path_is_url(path_or_url2);
- }
+ if (peg_revision->kind != svn_opt_revision_unspecified &&
+ is_local_rev1 && is_local_rev2)
+ return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL,
+ _("At least one revision must be something other "
+ "than BASE or WORKING when diffing a URL"));
+
+ /* Working copy paths with non-local revisions get turned into
+ 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. */
+ *is_repos1 = ! is_local_rev1 || svn_path_is_url(path_or_url1);
+ *is_repos2 = ! is_local_rev2 || svn_path_is_url(path_or_url2);
return SVN_NO_ERROR;
}
@@ -1528,7 +1557,8 @@ resolve_pegged_diff_target_url(const cha
ctx, scratch_pool);
if (err)
{
- if (err->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES)
+ if (err->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES ||
+ err->apr_err == SVN_ERR_FS_NOT_FOUND)
{
svn_error_clear(err);
*resolved_url = NULL;
@@ -1545,6 +1575,8 @@ resolve_pegged_diff_target_url(const cha
* 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.
+ * Indicate the corresponding node kinds in *KIND1 and *KIND2, and verify
+ * that at least one of the diff targets exists.
* 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. */
@@ -1558,6 +1590,8 @@ diff_prepare_repos_repos(const char **ur
const char **anchor2,
const char **target1,
const char **target2,
+ svn_node_kind_t *kind1,
+ svn_node_kind_t *kind2,
svn_ra_session_t **ra_session,
svn_client_ctx_t *ctx,
const char *path_or_url1,
@@ -1567,7 +1601,6 @@ diff_prepare_repos_repos(const char **ur
const svn_opt_revision_t *peg_revision,
apr_pool_t *pool)
{
- svn_node_kind_t kind1, kind2;
const char *abspath_or_url2;
const char *abspath_or_url1;
@@ -1644,18 +1677,18 @@ diff_prepare_repos_repos(const char **ur
SVN_ERR(svn_client__get_revision_number(rev2, NULL, ctx->wc_ctx,
(path_or_url2 == *url2) ? NULL : abspath_or_url2,
*ra_session, revision2, pool));
- SVN_ERR(svn_ra_check_path(*ra_session, "", *rev2, &kind2, pool));
+ SVN_ERR(svn_ra_check_path(*ra_session, "", *rev2, kind2, pool));
/* Do the same for the first target. */
SVN_ERR(svn_ra_reparent(*ra_session, *url1, pool));
SVN_ERR(svn_client__get_revision_number(rev1, NULL, ctx->wc_ctx,
(strcmp(path_or_url1, *url1) == 0) ? NULL : abspath_or_url1,
*ra_session, revision1, pool));
- SVN_ERR(svn_ra_check_path(*ra_session, "", *rev1, &kind1, pool));
+ SVN_ERR(svn_ra_check_path(*ra_session, "", *rev1, kind1, pool));
/* Either both URLs must exist at their respective revisions,
* or one of them may be missing from one side of the diff. */
- if (kind1 == svn_node_none && kind2 == svn_node_none)
+ if (*kind1 == svn_node_none && *kind2 == svn_node_none)
{
if (strcmp(*url1, *url2) == 0)
return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
@@ -1669,9 +1702,9 @@ diff_prepare_repos_repos(const char **ur
"'%ld'"),
*url1, *url2, *rev1, *rev2);
}
- else if (kind1 == svn_node_none)
+ else if (*kind1 == svn_node_none)
SVN_ERR(check_diff_target_exists(*url1, *rev2, *rev1, *ra_session, pool));
- else if (kind2 == svn_node_none)
+ else if (*kind2 == svn_node_none)
SVN_ERR(check_diff_target_exists(*url2, *rev1, *rev2, *ra_session, pool));
/* Choose useful anchors and targets for our two URLs. */
@@ -1679,57 +1712,9 @@ diff_prepare_repos_repos(const char **ur
*anchor2 = *url2;
*target1 = "";
*target2 = "";
- if ((kind1 == svn_node_none) || (kind2 == svn_node_none))
- {
- svn_node_kind_t kind;
- const char *repos_root;
- const char *new_anchor;
- svn_revnum_t rev;
-
- /* The diff target does not exist on one side of the diff.
- * This can happen if the target was added or deleted within the
- * revision range being diffed.
- * However, we don't know how deep within a added/deleted subtree the
- * diff target is. Find a common parent that exists on both sides of
- * the diff and use it as anchor for the diff operation.
- *
- * ### This can fail due to authz restrictions (like in issue #3242).
- * ### But it is the only option we have right now to try to get
- * ### a usable diff in this situation. */
-
- SVN_ERR(svn_ra_get_repos_root2(*ra_session, &repos_root, pool));
-
- /* Since we already know that one of the URLs does exist,
- * look for an existing parent of the URL which doesn't exist. */
- new_anchor = (kind1 == svn_node_none ? *anchor1 : *anchor2);
- rev = (kind1 == svn_node_none ? *rev1 : *rev2);
- do
- {
- if (strcmp(new_anchor, repos_root) != 0)
- {
- new_anchor = svn_path_uri_decode(svn_uri_dirname(new_anchor,
- pool),
- pool);
- if (*base_path)
- *base_path = svn_dirent_dirname(*base_path, pool);
- }
-
- SVN_ERR(svn_ra_reparent(*ra_session, new_anchor, pool));
- SVN_ERR(svn_ra_check_path(*ra_session, "", rev, &kind, pool));
- }
- while (kind != svn_node_dir);
- *anchor1 = *anchor2 = new_anchor;
- /* Diff targets must be relative to the new anchor. */
- *target1 = svn_uri_skip_ancestor(new_anchor, *url1, pool);
- *target2 = svn_uri_skip_ancestor(new_anchor, *url2, pool);
- SVN_ERR_ASSERT(*target1 && *target2);
- if (kind1 == svn_node_none)
- kind1 = svn_node_dir;
- else
- kind2 = svn_node_dir;
- }
- else if ((kind1 == svn_node_file) || (kind2 == svn_node_file))
+ /* If one of the targets is a file, use the parent directory as anchor. */
+ if (*kind1 == svn_node_file || *kind2 == svn_node_file)
{
svn_uri_split(anchor1, target1, *url1, pool);
svn_uri_split(anchor2, target2, *url2, pool);
@@ -1843,7 +1828,7 @@ do_arbitrary_files_diff(const char *loca
if (ctx->cancel_func)
SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
- if (diff_cmd_baton->ignore_prop_diff)
+ if (diff_cmd_baton->ignore_properties)
{
original_props = apr_hash_make(scratch_pool);
modified_props = apr_hash_make(scratch_pool);
@@ -2334,6 +2319,299 @@ diff_wc_wc(const char *path1,
return SVN_NO_ERROR;
}
+/* Create an array of regular properties in PROP_HASH, filtering entry-props
+ * and wc-props. Allocate the returned array in RESULT_POOL.
+ * Use SCRATCH_POOL for temporary allocations. */
+static apr_array_header_t *
+make_regular_props_array(apr_hash_t *prop_hash,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ apr_array_header_t *regular_props;
+ apr_hash_index_t *hi;
+
+ regular_props = apr_array_make(result_pool, 0, sizeof(svn_prop_t));
+ for (hi = apr_hash_first(scratch_pool, prop_hash); hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *name = svn__apr_hash_index_key(hi);
+ svn_string_t *value = svn__apr_hash_index_val(hi);
+ svn_prop_kind_t prop_kind = svn_property_kind2(name);
+
+ if (prop_kind == svn_prop_regular_kind)
+ {
+ svn_prop_t *prop = apr_palloc(scratch_pool, sizeof(svn_prop_t));
+
+ prop->name = name;
+ prop->value = value;
+ APR_ARRAY_PUSH(regular_props, svn_prop_t) = *prop;
+ }
+ }
+
+ return regular_props;
+}
+
+/* Create a hash of regular properties from PROP_HASH, filtering entry-props
+ * and wc-props. Allocate the returned hash in RESULT_POOL.
+ * Use SCRATCH_POOL for temporary allocations. */
+static apr_hash_t *
+make_regular_props_hash(apr_hash_t *prop_hash,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_t *regular_props;
+ apr_hash_index_t *hi;
+
+ regular_props = apr_hash_make(result_pool);
+ for (hi = apr_hash_first(scratch_pool, prop_hash); hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *name = svn__apr_hash_index_key(hi);
+ svn_string_t *value = svn__apr_hash_index_val(hi);
+ svn_prop_kind_t prop_kind = svn_property_kind2(name);
+
+ if (prop_kind == svn_prop_regular_kind)
+ apr_hash_set(regular_props, name, APR_HASH_KEY_STRING, value);
+ }
+
+ return regular_props;
+}
+
+/* Handle an added or deleted diff target file for a repos<->repos diff.
+ *
+ * Using the provided diff CALLBACKS and the CALLBACK_BATON, show the file
+ * TARGET@PEG_REVISION as added or deleted, depending on SHOW_DELETION.
+ * TARGET is a path relative to RA_SESSION's URL.
+ * REV1 and REV2 are the revisions being compared.
+ * Use SCRATCH_POOL for temporary allocations. */
+static svn_error_t *
+diff_repos_repos_added_or_deleted_file(const char *target,
+ svn_revnum_t peg_revision,
+ svn_revnum_t rev1,
+ svn_revnum_t rev2,
+ svn_boolean_t show_deletion,
+ const char *empty_file,
+ const svn_wc_diff_callbacks4_t
+ *callbacks,
+ struct diff_cmd_baton *callback_baton,
+ svn_ra_session_t *ra_session,
+ apr_pool_t *scratch_pool)
+{
+ const char *file_abspath;
+ svn_stream_t *content;
+ apr_hash_t *prop_hash;
+
+ SVN_ERR(svn_stream_open_unique(&content, &file_abspath, NULL,
+ svn_io_file_del_on_pool_cleanup,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_ra_get_file(ra_session, target, peg_revision, content, NULL,
+ &prop_hash, scratch_pool));
+ SVN_ERR(svn_stream_close(content));
+
+ if (show_deletion)
+ {
+ SVN_ERR(callbacks->file_deleted(NULL, NULL,
+ target, file_abspath, empty_file,
+ apr_hash_get(prop_hash,
+ SVN_PROP_MIME_TYPE,
+ APR_HASH_KEY_STRING),
+ NULL,
+ make_regular_props_hash(
+ prop_hash, scratch_pool, scratch_pool),
+ callback_baton, scratch_pool));
+ }
+ else
+ {
+ SVN_ERR(callbacks->file_added(NULL, NULL, NULL,
+ target, empty_file, file_abspath,
+ rev1, rev2, NULL,
+ apr_hash_get(prop_hash, SVN_PROP_MIME_TYPE,
+ APR_HASH_KEY_STRING),
+ NULL, SVN_INVALID_REVNUM,
+ make_regular_props_array(prop_hash,
+ scratch_pool,
+ scratch_pool),
+ NULL, callback_baton, scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Handle an added or deleted diff target directory for a repos<->repos diff.
+ *
+ * Using the provided diff CALLBACKS and the CALLBACK_BATON, show the
+ * directory TARGET@PEG_REVISION, and all of its children, as added or deleted,
+ * depending on SHOW_DELETION. TARGET is a path relative to RA_SESSION's URL.
+ * REV1 and REV2 are the revisions being compared.
+ * Use SCRATCH_POOL for temporary allocations. */
+static svn_error_t *
+diff_repos_repos_added_or_deleted_dir(const char *target,
+ svn_revnum_t revision,
+ svn_revnum_t rev1,
+ svn_revnum_t rev2,
+ svn_boolean_t show_deletion,
+ const char *empty_file,
+ const svn_wc_diff_callbacks4_t
+ *callbacks,
+ struct diff_cmd_baton *callback_baton,
+ svn_ra_session_t *ra_session,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_t *dirents;
+ apr_hash_t *props;
+ apr_pool_t *iterpool;
+ apr_hash_index_t *hi;
+
+ SVN_ERR(svn_ra_get_dir2(ra_session, &dirents, NULL, &props,
+ target, revision, SVN_DIRENT_KIND,
+ scratch_pool));
+
+ if (show_deletion)
+ SVN_ERR(callbacks->dir_deleted(NULL, NULL, target, callback_baton,
+ scratch_pool));
+ else
+ SVN_ERR(callbacks->dir_added(NULL, NULL, NULL, NULL,
+ target, revision,
+ NULL, SVN_INVALID_REVNUM,
+ callback_baton, scratch_pool));
+ if (props)
+ {
+ if (show_deletion)
+ SVN_ERR(callbacks->dir_props_changed(NULL, NULL, target, FALSE,
+ apr_array_make(scratch_pool, 0,
+ sizeof(svn_prop_t)),
+ make_regular_props_hash(
+ props, scratch_pool,
+ scratch_pool),
+ callback_baton, scratch_pool));
+ else
+ SVN_ERR(callbacks->dir_props_changed(NULL, NULL, target, TRUE,
+ make_regular_props_array(
+ props, scratch_pool,
+ scratch_pool),
+ NULL,
+ callback_baton, scratch_pool));
+ }
+
+ iterpool = svn_pool_create(scratch_pool);
+ for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi))
+ {
+ const char *name = svn__apr_hash_index_key(hi);
+ svn_dirent_t *dirent = svn__apr_hash_index_val(hi);
+ const char *child_target;
+
+ svn_pool_clear(iterpool);
+
+ child_target = svn_relpath_join(target, name, iterpool);
+
+ if (dirent->kind == svn_node_dir)
+ SVN_ERR(diff_repos_repos_added_or_deleted_dir(child_target,
+ revision, rev1, rev2,
+ show_deletion,
+ empty_file,
+ callbacks,
+ callback_baton,
+ ra_session,
+ iterpool));
+ else if (dirent->kind == svn_node_file)
+ SVN_ERR(diff_repos_repos_added_or_deleted_file(child_target,
+ revision, rev1, rev2,
+ show_deletion,
+ empty_file,
+ callbacks,
+ callback_baton,
+ ra_session,
+ iterpool));
+ }
+ svn_pool_destroy(iterpool);
+
+ if (!show_deletion)
+ SVN_ERR(callbacks->dir_closed(NULL, NULL, NULL, target, TRUE,
+ callback_baton, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Handle an added or deleted diff target for a repos<->repos diff.
+ *
+ * Using the provided diff CALLBACKS and the CALLBACK_BATON, show
+ * TARGET@PEG_REVISION, and all of its children, if any, as added or deleted.
+ * TARGET is a path relative to RA_SESSION's URL.
+ * REV1 and REV2 are the revisions being compared.
+ * Use SCRATCH_POOL for temporary allocations. */
+static svn_error_t *
+diff_repos_repos_added_or_deleted_target(const char *target1,
+ const char *target2,
+ svn_revnum_t rev1,
+ svn_revnum_t rev2,
+ svn_node_kind_t kind1,
+ svn_node_kind_t kind2,
+ const svn_wc_diff_callbacks4_t
+ *callbacks,
+ struct diff_cmd_baton *callback_baton,
+ svn_ra_session_t *ra_session,
+ apr_pool_t *scratch_pool)
+{
+ const char *existing_target;
+ svn_revnum_t existing_rev;
+ svn_node_kind_t existing_kind;
+ svn_boolean_t show_deletion;
+ const char *empty_file;
+
+ SVN_ERR_ASSERT(kind1 == svn_node_none || kind2 == svn_node_none);
+
+ /* Are we showing an addition or deletion? */
+ show_deletion = (kind2 == svn_node_none);
+
+ /* Which target is being added/deleted? Is it a file or a directory? */
+ if (show_deletion)
+ {
+ existing_target = target1;
+ existing_rev = rev1;
+ existing_kind = kind1;
+ }
+ else
+ {
+ existing_target = target2;
+ existing_rev = rev2;
+ existing_kind = kind2;
+ }
+
+ /* All file content will be diffed against the empty file. */
+ SVN_ERR(svn_io_open_unique_file3(NULL, &empty_file, NULL,
+ svn_io_file_del_on_pool_cleanup,
+ scratch_pool, scratch_pool));
+
+ if (existing_kind == svn_node_file)
+ {
+ /* Get file content and show a diff against the empty file. */
+ SVN_ERR(diff_repos_repos_added_or_deleted_file(existing_target,
+ existing_rev,
+ rev1, rev2,
+ show_deletion,
+ empty_file,
+ callbacks,
+ callback_baton,
+ ra_session,
+ scratch_pool));
+ }
+ else
+ {
+ /* Walk the added/deleted tree and show a diff for each child. */
+ SVN_ERR(diff_repos_repos_added_or_deleted_dir(existing_target,
+ existing_rev,
+ rev1, rev2,
+ show_deletion,
+ empty_file,
+ callbacks,
+ callback_baton,
+ ra_session,
+ scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+}
/* Perform a diff between two repository paths.
@@ -2370,6 +2648,8 @@ diff_repos_repos(const svn_wc_diff_callb
const char *base_path;
svn_revnum_t rev1;
svn_revnum_t rev2;
+ svn_node_kind_t kind1;
+ svn_node_kind_t kind2;
const char *anchor1;
const char *anchor2;
const char *target1;
@@ -2379,7 +2659,8 @@ diff_repos_repos(const svn_wc_diff_callb
/* Prepare info for the repos repos diff. */
SVN_ERR(diff_prepare_repos_repos(&url1, &url2, &base_path, &rev1, &rev2,
&anchor1, &anchor2, &target1, &target2,
- &ra_session, ctx, path_or_url1, path_or_url2,
+ &kind1, &kind2, &ra_session,
+ ctx, path_or_url1, path_or_url2,
revision1, revision2, peg_revision,
pool));
@@ -2394,6 +2675,21 @@ diff_repos_repos(const svn_wc_diff_callb
callback_baton->ra_session = ra_session;
callback_baton->anchor = base_path;
+ if (kind1 == svn_node_none || kind2 == svn_node_none)
+ {
+ /* One side of the diff does not exist.
+ * Walk the tree that does exist, showing a series of additions
+ * or deletions. */
+ SVN_ERR(diff_repos_repos_added_or_deleted_target(target1, target2,
+ rev1, rev2,
+ kind1, kind2,
+ callbacks,
+ callback_baton,
+ ra_session,
+ pool));
+ return SVN_NO_ERROR;
+ }
+
/* 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. */
@@ -2428,6 +2724,195 @@ diff_repos_repos(const svn_wc_diff_callb
}
+/* Using CALLBACKS, show a REPOS->WC diff for a file TARGET, which in the
+ * working copy is at FILE2_ABSPATH. KIND1 is the node kind of the repository
+ * target (either svn_node_file or svn_node_none). REV is the revision the
+ * working file is diffed against. RA_SESSION points at the URL of the file
+ * in the repository and is used to get the file's repository-version content,
+ * if necessary. If DIFF_WITH_BASE is set, diff against the BASE version of
+ * the local file instead of WORKING.
+ * The other parameters are as in diff_repos_wc(). */
+static svn_error_t *
+diff_repos_wc_file_target(const char *target,
+ const char *file2_abspath,
+ svn_node_kind_t kind1,
+ svn_revnum_t rev,
+ svn_boolean_t reverse,
+ svn_boolean_t show_copies_as_adds,
+ svn_boolean_t diff_with_base,
+ const svn_wc_diff_callbacks4_t *callbacks,
+ void *callback_baton,
+ svn_ra_session_t *ra_session,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *scratch_pool)
+{
+ const char *file1_abspath;
+ svn_stream_t *file1_content;
+ svn_stream_t *file2_content;
+ apr_hash_t *file1_props = NULL;
+ apr_hash_t *file2_props;
+ svn_boolean_t is_copy = FALSE;
+
+ /* Get content and props of file 1 (the remote file). */
+ SVN_ERR(svn_stream_open_unique(&file1_content, &file1_abspath, NULL,
+ svn_io_file_del_on_pool_cleanup,
+ scratch_pool, scratch_pool));
+ if (kind1 == svn_node_file)
+ {
+ if (show_copies_as_adds)
+ SVN_ERR(svn_wc__node_get_origin(&is_copy,
+ NULL, NULL, NULL, NULL, NULL,
+ ctx->wc_ctx, file2_abspath,
+ FALSE, scratch_pool, scratch_pool));
+ /* If showing copies as adds, diff against the empty file. */
+ if (!(show_copies_as_adds && is_copy))
+ SVN_ERR(svn_ra_get_file(ra_session, "", rev, file1_content,
+ NULL, &file1_props, scratch_pool));
+ }
+
+ SVN_ERR(svn_stream_close(file1_content));
+
+ /* Get content and props of file 2 (the local file). */
+ if (diff_with_base)
+ {
+ svn_stream_t *pristine_content;
+
+ SVN_ERR(svn_wc_get_pristine_props(&file2_props, ctx->wc_ctx,
+ file2_abspath, scratch_pool,
+ scratch_pool));
+
+ /* ### We need a filename, but this API returns an opaque stream.
+ * ### This requires us to copy to a temporary file. Maybe libsvn_wc
+ * ### should also provide an API that returns a path to a file that
+ * ### contains pristine content, possibly temporary? */
+ SVN_ERR(svn_wc_get_pristine_contents2(&pristine_content,
+ ctx->wc_ctx,
+ file2_abspath,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(svn_stream_open_unique(&file2_content, &file2_abspath, NULL,
+ svn_io_file_del_on_pool_cleanup,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_stream_copy3(pristine_content, file2_content,
+ ctx->cancel_func, ctx->cancel_baton,
+ scratch_pool));
+ }
+ else
+ {
+ apr_hash_t *keywords = NULL;
+ svn_string_t *keywords_prop;
+ svn_subst_eol_style_t eol_style;
+ const char *eol_str;
+
+ SVN_ERR(svn_wc_prop_list2(&file2_props, ctx->wc_ctx, file2_abspath,
+ scratch_pool, scratch_pool));
+
+ /* We might have to create a normalised version of the working file. */
+ svn_subst_eol_style_from_value(&eol_style, &eol_str,
+ apr_hash_get(file2_props,
+ SVN_PROP_EOL_STYLE,
+ APR_HASH_KEY_STRING));
+ keywords_prop = apr_hash_get(file2_props, SVN_PROP_KEYWORDS,
+ APR_HASH_KEY_STRING);
+ if (keywords_prop)
+ SVN_ERR(svn_subst_build_keywords2(&keywords, keywords_prop->data,
+ NULL, NULL, 0, NULL,
+ scratch_pool));
+ if (svn_subst_translation_required(eol_style, SVN_SUBST_NATIVE_EOL_STR,
+ keywords, FALSE, TRUE))
+ {
+ svn_stream_t *working_content;
+ svn_stream_t *normalized_content;
+
+ SVN_ERR(svn_stream_open_readonly(&working_content, file2_abspath,
+ scratch_pool, scratch_pool));
+
+ /* Create a temporary file and copy normalised data into it. */
+ SVN_ERR(svn_stream_open_unique(&file2_content, &file2_abspath, NULL,
+ svn_io_file_del_on_pool_cleanup,
+ scratch_pool, scratch_pool));
+ normalized_content = svn_subst_stream_translated(
+ file2_content, SVN_SUBST_NATIVE_EOL_STR,
+ TRUE, keywords, FALSE, scratch_pool);
+ SVN_ERR(svn_stream_copy3(working_content, normalized_content,
+ ctx->cancel_func, ctx->cancel_baton,
+ scratch_pool));
+ }
+ }
+
+ if (kind1 == svn_node_file && !(show_copies_as_adds && is_copy))
+ {
+ SVN_ERR(callbacks->file_opened(NULL, NULL, target,
+ reverse ? SVN_INVALID_REVNUM : rev,
+ callback_baton, scratch_pool));
+
+ if (reverse)
+ SVN_ERR(callbacks->file_changed(NULL, NULL, NULL, target,
+ file2_abspath, file1_abspath,
+ SVN_INVALID_REVNUM, rev,
+ apr_hash_get(file2_props,
+ SVN_PROP_MIME_TYPE,
+ APR_HASH_KEY_STRING),
+ apr_hash_get(file1_props,
+ SVN_PROP_MIME_TYPE,
+ APR_HASH_KEY_STRING),
+ make_regular_props_array(
+ file1_props, scratch_pool,
+ scratch_pool),
+ file2_props,
+ callback_baton, scratch_pool));
+ else
+ SVN_ERR(callbacks->file_changed(NULL, NULL, NULL, target,
+ file1_abspath, file2_abspath,
+ rev, SVN_INVALID_REVNUM,
+ apr_hash_get(file1_props,
+ SVN_PROP_MIME_TYPE,
+ APR_HASH_KEY_STRING),
+ apr_hash_get(file2_props,
+ SVN_PROP_MIME_TYPE,
+ APR_HASH_KEY_STRING),
+ make_regular_props_array(
+ file2_props, scratch_pool,
+ scratch_pool),
+ file1_props,
+ callback_baton, scratch_pool));
+ }
+ else
+ {
+ if (reverse)
+ {
+ SVN_ERR(callbacks->file_deleted(NULL, NULL,
+ target, file2_abspath, file1_abspath,
+ apr_hash_get(file2_props,
+ SVN_PROP_MIME_TYPE,
+ APR_HASH_KEY_STRING),
+ NULL,
+ make_regular_props_hash(
+ file2_props, scratch_pool,
+ scratch_pool),
+ callback_baton, scratch_pool));
+ }
+ else
+ {
+ SVN_ERR(callbacks->file_added(NULL, NULL, NULL, target,
+ file1_abspath, file2_abspath,
+ rev, SVN_INVALID_REVNUM,
+ NULL,
+ apr_hash_get(file2_props,
+ SVN_PROP_MIME_TYPE,
+ APR_HASH_KEY_STRING),
+ NULL, SVN_INVALID_REVNUM,
+ make_regular_props_array(
+ file2_props, scratch_pool,
+ scratch_pool),
+ NULL,
+ callback_baton, scratch_pool));
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
/* Perform a diff between a repository path and a working-copy path.
PATH_OR_URL1 may be either a URL or a working copy path. PATH2 is a
@@ -2468,6 +2953,12 @@ diff_repos_wc(const char *path_or_url1,
const char *abspath_or_url1;
const char *abspath2;
const char *anchor_abspath;
+ svn_node_kind_t kind1;
+ svn_node_kind_t kind2;
+ svn_boolean_t is_copy;
+ svn_revnum_t copyfrom_rev;
+ const char *copy_source_repos_relpath;
+ const char *copy_source_repos_root_url;
SVN_ERR_ASSERT(! svn_path_is_url(path2));
@@ -2518,22 +3009,50 @@ diff_repos_wc(const char *path_or_url1,
}
}
- /* Establish RA session to path2's anchor */
- 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)
{
SVN_ERR(svn_wc__get_wc_root(&callback_baton->wc_root_abspath,
ctx->wc_ctx, anchor_abspath,
pool, pool));
}
+
+ /* Open an RA session to URL1 to figure out its node kind. */
+ SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, url1,
+ NULL, NULL, FALSE, TRUE,
+ ctx, pool));
+ /* Resolve the revision to use for URL1. */
+ SVN_ERR(svn_client__get_revision_number(&rev, NULL, ctx->wc_ctx,
+ (strcmp(path_or_url1, url1) == 0)
+ ? NULL : abspath_or_url1,
+ ra_session, revision1, pool));
+ SVN_ERR(svn_ra_check_path(ra_session, "", rev, &kind1, pool));
+
+ /* Figure out the node kind of the local target. */
+ SVN_ERR(svn_io_check_resolved_path(abspath2, &kind2, pool));
+
+ callback_baton->ra_session = ra_session;
callback_baton->anchor = anchor;
- SVN_ERR(svn_ra_has_capability(ra_session, &server_supports_depth,
- SVN_RA_CAPABILITY_DEPTH, pool));
+ if (!reverse)
+ callback_baton->revnum1 = rev;
+ else
+ callback_baton->revnum2 = rev;
+
+ /* If both diff targets can be diffed as files, fetch the file from the
+ * repository and generate a diff against the local version of the file. */
+ if ((kind1 == svn_node_file || kind1 == svn_node_none)
+ && kind2 == svn_node_file)
+ {
+ SVN_ERR(diff_repos_wc_file_target(target, abspath2, kind1, rev,
+ reverse, show_copies_as_adds,
+ rev2_is_base,
+ callbacks, callback_baton,
+ ra_session, ctx, pool));
+ return SVN_NO_ERROR;
+ }
+
+ /* Else, use the diff editor to generate the diff. */
SVN_ERR(svn_wc__get_diff_editor(&diff_editor, &diff_edit_baton,
ctx->wc_ctx,
anchor_abspath,
@@ -2549,42 +3068,88 @@ diff_repos_wc(const char *path_or_url1,
callbacks, callback_baton,
ctx->cancel_func, ctx->cancel_baton,
pool, pool));
-
- /* 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,
- (strcmp(path_or_url1, url1) == 0)
- ? NULL : abspath_or_url1,
- ra_session, revision1, pool));
-
- if (!reverse)
- callback_baton->revnum1 = rev;
- else
- callback_baton->revnum2 = rev;
+ SVN_ERR(svn_ra_reparent(ra_session, anchor_url, pool));
+ SVN_ERR(svn_ra_has_capability(ra_session, &server_supports_depth,
+ SVN_RA_CAPABILITY_DEPTH, pool));
if (depth != svn_depth_infinity)
diff_depth = depth;
else
diff_depth = svn_depth_unknown;
- SVN_ERR(svn_ra_do_diff3(ra_session,
- &reporter, &reporter_baton,
- rev,
- target,
- diff_depth,
- ignore_ancestry,
- TRUE, /* text_deltas */
- url1,
- diff_editor, diff_edit_baton, pool));
-
- /* Create a txn mirror of path2; the diff editor will print
- diffs in reverse. :-) */
- SVN_ERR(svn_wc_crawl_revisions5(ctx->wc_ctx, abspath2,
- reporter, reporter_baton,
- FALSE, depth, TRUE, (! server_supports_depth),
- FALSE,
- ctx->cancel_func, ctx->cancel_baton,
- NULL, NULL, /* notification is N/A */
- pool));
+ /* Check if our diff target is a copied node. */
+ SVN_ERR(svn_wc__node_get_origin(&is_copy,
+ ©from_rev,
+ ©_source_repos_relpath,
+ ©_source_repos_root_url,
+ NULL, NULL,
+ ctx->wc_ctx, abspath2,
+ FALSE, pool, pool));
+ if (is_copy)
+ {
+ const char *copyfrom_url;
+ const char *copyfrom_parent_url;
+ const char *copyfrom_basename;
+ svn_depth_t copy_depth;
+
+ callback_baton->repos_wc_diff_target_is_copy = TRUE;
+
+ /* We're diffing a locally copied/moved directory.
+ * Describe the copy source to the reporter instead of the copy itself.
+ * Doing the latter would generate a single add_directory() call to the
+ * diff editor which results in an unexpected diff (the copy would
+ * be shown as deleted). */
+
+ copyfrom_url = apr_pstrcat(pool, copy_source_repos_root_url, "/",
+ copy_source_repos_relpath, (char *)NULL);
+ svn_uri_split(©from_parent_url, ©from_basename,
+ copyfrom_url, pool);
+ SVN_ERR(svn_ra_reparent(ra_session, copyfrom_parent_url, pool));
+
+ /* Tell the RA layer we want a delta to change our txn to URL1 */
+ SVN_ERR(svn_ra_do_diff3(ra_session,
+ &reporter, &reporter_baton,
+ rev,
+ copyfrom_basename,
+ diff_depth,
+ ignore_ancestry,
+ TRUE, /* text_deltas */
+ url1,
+ diff_editor, diff_edit_baton, pool));
+
+ /* Report the copy source. */
+ SVN_ERR(svn_wc__node_get_depth(©_depth, ctx->wc_ctx, abspath2,
+ pool));
+ SVN_ERR(reporter->set_path(reporter_baton, "", copyfrom_rev,
+ copy_depth, FALSE, NULL, pool));
+
+ /* Finish the report to generate the diff. */
+ SVN_ERR(reporter->finish_report(reporter_baton, pool));
+ }
+ else
+ {
+ /* Tell the RA layer we want a delta to change our txn to URL1 */
+ SVN_ERR(svn_ra_do_diff3(ra_session,
+ &reporter, &reporter_baton,
+ rev,
+ target,
+ diff_depth,
+ ignore_ancestry,
+ TRUE, /* text_deltas */
+ url1,
+ diff_editor, diff_edit_baton, pool));
+
+ /* Create a txn mirror of path2; the diff editor will print
+ diffs in reverse. :-) */
+ SVN_ERR(svn_wc_crawl_revisions5(ctx->wc_ctx, abspath2,
+ reporter, reporter_baton,
+ FALSE, depth, TRUE,
+ (! server_supports_depth),
+ FALSE,
+ ctx->cancel_func, ctx->cancel_baton,
+ NULL, NULL, /* notification is N/A */
+ pool));
+ }
return SVN_NO_ERROR;
}
@@ -2741,6 +3306,8 @@ diff_summarize_repos_repos(svn_client_di
const char *base_path;
svn_revnum_t rev1;
svn_revnum_t rev2;
+ svn_node_kind_t kind1;
+ svn_node_kind_t kind2;
const char *anchor1;
const char *anchor2;
const char *target1;
@@ -2752,10 +3319,29 @@ diff_summarize_repos_repos(svn_client_di
/* Prepare info for the repos repos diff. */
SVN_ERR(diff_prepare_repos_repos(&url1, &url2, &base_path, &rev1, &rev2,
&anchor1, &anchor2, &target1, &target2,
- &ra_session, ctx,
- path_or_url1, path_or_url2, revision1, revision2,
+ &kind1, &kind2, &ra_session,
+ ctx, path_or_url1, path_or_url2,
+ revision1, revision2,
peg_revision, pool));
+ if (kind1 == svn_node_none || kind2 == svn_node_none)
+ {
+ /* One side of the diff does not exist.
+ * Walk the tree that does exist, showing a series of additions
+ * or deletions. */
+ SVN_ERR(svn_client__get_diff_summarize_callbacks(
+ &callbacks, &callback_baton, target1,
+ summarize_func, summarize_baton, pool));
+ SVN_ERR(diff_repos_repos_added_or_deleted_target(target1, target2,
+ rev1, rev2,
+ kind1, kind2,
+ callbacks,
+ callback_baton,
+ ra_session,
+ pool));
+ return SVN_NO_ERROR;
+ }
+
SVN_ERR(svn_client__get_diff_summarize_callbacks(
&callbacks, &callback_baton,
target1, summarize_func, summarize_baton, pool));
@@ -2944,7 +3530,8 @@ svn_client_diff6(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 ignore_prop_diff,
+ svn_boolean_t ignore_properties,
+ svn_boolean_t properties_only,
svn_boolean_t use_git_diff_format,
const char *header_encoding,
svn_stream_t *outstream,
@@ -2954,9 +3541,14 @@ svn_client_diff6(const apr_array_header_
apr_pool_t *pool)
{
struct diff_cmd_baton diff_cmd_baton = { 0 };
+ svn_opt_revision_t peg_revision;
+
+ if (ignore_properties && properties_only)
+ return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+ _("Cannot ignore properties and show only "
+ "properties at the same time"));
/* We will never do a pegged diff from here. */
- svn_opt_revision_t peg_revision;
peg_revision.kind = svn_opt_revision_unspecified;
/* setup callback and baton */
@@ -2974,7 +3566,8 @@ svn_client_diff6(const apr_array_header_
diff_cmd_baton.force_empty = FALSE;
diff_cmd_baton.force_binary = ignore_content_type;
- diff_cmd_baton.ignore_prop_diff = ignore_prop_diff;
+ diff_cmd_baton.ignore_properties = ignore_properties;
+ diff_cmd_baton.properties_only = properties_only;
diff_cmd_baton.relative_to_dir = relative_to_dir;
diff_cmd_baton.use_git_diff_format = use_git_diff_format;
diff_cmd_baton.no_diff_deleted = no_diff_deleted;
@@ -3003,7 +3596,8 @@ svn_client_diff_peg6(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 ignore_prop_diff,
+ svn_boolean_t ignore_properties,
+ svn_boolean_t properties_only,
svn_boolean_t use_git_diff_format,
const char *header_encoding,
svn_stream_t *outstream,
@@ -3014,6 +3608,11 @@ svn_client_diff_peg6(const apr_array_hea
{
struct diff_cmd_baton diff_cmd_baton = { 0 };
+ if (ignore_properties && properties_only)
+ return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+ _("Cannot ignore properties and show only "
+ "properties at the same time"));
+
/* setup callback and baton */
diff_cmd_baton.orig_path_1 = path_or_url;
diff_cmd_baton.orig_path_2 = path_or_url;
@@ -3029,7 +3628,8 @@ svn_client_diff_peg6(const apr_array_hea
diff_cmd_baton.force_empty = FALSE;
diff_cmd_baton.force_binary = ignore_content_type;
- diff_cmd_baton.ignore_prop_diff = ignore_prop_diff;
+ diff_cmd_baton.ignore_properties = ignore_properties;
+ diff_cmd_baton.properties_only = properties_only;
diff_cmd_baton.relative_to_dir = relative_to_dir;
diff_cmd_baton.use_git_diff_format = use_git_diff_format;
diff_cmd_baton.no_diff_deleted = no_diff_deleted;
Modified: subversion/branches/javahl-ra/subversion/libsvn_client/export.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/export.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/export.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/export.c Tue May 29 01:39:41 2012
@@ -1103,20 +1103,19 @@ svn_client_export5(svn_revnum_t *result_
if (from_is_url || ! SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind))
{
- svn_revnum_t revnum;
- const char *url;
+ svn_client__pathrev_t *loc;
svn_ra_session_t *ra_session;
svn_node_kind_t kind;
struct edit_baton *eb = apr_pcalloc(pool, sizeof(*eb));
/* Get the RA connection. */
- SVN_ERR(svn_client__ra_session_from_path(&ra_session, &revnum,
- &url, from_path_or_url, NULL,
- peg_revision,
- revision, ctx, pool));
+ SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
+ from_path_or_url, NULL,
+ peg_revision,
+ revision, ctx, pool));
eb->root_path = to_path;
- eb->root_url = url;
+ eb->root_url = loc->url;
eb->force = overwrite;
eb->target_revision = &edit_revision;
eb->externals = apr_hash_make(pool);
@@ -1127,7 +1126,7 @@ svn_client_export5(svn_revnum_t *result_
eb->notify_func = ctx->notify_func2;
eb->notify_baton = ctx->notify_baton2;
- SVN_ERR(svn_ra_check_path(ra_session, "", revnum, &kind, pool));
+ SVN_ERR(svn_ra_check_path(ra_session, "", loc->rev, &kind, pool));
if (kind == svn_node_file)
{
@@ -1183,7 +1182,7 @@ svn_client_export5(svn_revnum_t *result_
/* Step outside the editor-likeness for a moment, to actually talk
* to the repository. */
/* ### note: the stream will not be closed */
- SVN_ERR(svn_ra_get_file(ra_session, "", revnum,
+ SVN_ERR(svn_ra_get_file(ra_session, "", loc->rev,
fb->tmp_stream,
NULL, &props, pool));
@@ -1242,13 +1241,13 @@ svn_client_export5(svn_revnum_t *result_
/* Manufacture a basic 'report' to the update reporter. */
SVN_ERR(svn_ra_do_update2(ra_session,
&reporter, &report_baton,
- revnum,
+ loc->rev,
"", /* no sub-target */
depth,
FALSE, /* don't want copyfrom-args */
export_editor, edit_baton, pool));
- SVN_ERR(reporter->set_path(report_baton, "", revnum,
+ SVN_ERR(reporter->set_path(report_baton, "", loc->rev,
/* Depth is irrelevant, as we're
passing start_empty=TRUE anyway. */
svn_depth_infinity,
Modified: subversion/branches/javahl-ra/subversion/libsvn_client/externals.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/externals.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/externals.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/externals.c Tue May 29 01:39:41 2012
@@ -24,7 +24,7 @@
/* ==================================================================== */
-
+
/*** Includes. ***/
#include <apr_uri.h>
@@ -41,7 +41,7 @@
#include "svn_private_config.h"
#include "private/svn_wc_private.h"
-
+
/* Closure for handle_external_item_change. */
struct external_change_baton_t
{
@@ -313,9 +313,6 @@ switch_file_external(const char *local_a
const svn_opt_revision_t *revision,
const char *def_dir_abspath,
svn_ra_session_t *ra_session,
- const char *ra_session_url,
- svn_revnum_t ra_revnum,
- const char *repos_root_url,
svn_boolean_t *timestamp_sleep,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
@@ -437,8 +434,7 @@ switch_file_external(const char *local_a
void *report_baton;
const svn_delta_editor_t *switch_editor;
void *switch_baton;
- const char *switch_rev_url;
- const char *repos_uuid;
+ svn_client__pathrev_t *switch_loc;
svn_revnum_t revnum;
/* ### TODO: Provide the real definition path (now available in
### def_dir_abspath) after switching to the new externals store.
@@ -447,22 +443,20 @@ switch_file_external(const char *local_a
const char *definition_abspath = svn_dirent_dirname(local_abspath,subpool);
/* Open an RA session to 'source' URL */
- SVN_ERR(svn_client__ra_session_from_path(&ra_session, &revnum,
- &switch_rev_url,
- url, dir_abspath,
- peg_revision, revision,
- ctx, subpool));
+ SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &switch_loc,
+ url, dir_abspath,
+ peg_revision, revision,
+ ctx, subpool));
SVN_ERR(svn_ra_reparent(ra_session, url, subpool));
- SVN_ERR(svn_ra_get_uuid2(ra_session, &repos_uuid, subpool));
SVN_ERR(svn_wc__get_file_external_editor(&switch_editor, &switch_baton,
&revnum, ctx->wc_ctx,
local_abspath,
definition_abspath /* wri */,
- switch_rev_url,
- repos_root_url,
- repos_uuid,
+ switch_loc->url,
+ switch_loc->repos_root_url,
+ switch_loc->repos_uuid,
use_commit_times,
diff3_cmd, preserved_exts,
definition_abspath /* def */,
@@ -477,16 +471,17 @@ switch_file_external(const char *local_a
/* Tell RA to do an update of URL+TARGET to REVISION; if we pass an
invalid revnum, that means RA will use the latest revision. */
- SVN_ERR(svn_ra_do_switch2(ra_session, &reporter, &report_baton, revnum,
- target, svn_depth_unknown, url,
- switch_editor, switch_baton, subpool));
-
- SVN_ERR(svn_wc__crawl_file_external(ctx->wc_ctx, local_abspath,
- reporter, report_baton,
- TRUE, use_commit_times,
- ctx->cancel_func, ctx->cancel_baton,
- ctx->notify_func2, ctx->notify_baton2,
- subpool));
+ SVN_ERR(svn_ra_do_switch2(ra_session, &reporter, &report_baton,
+ switch_loc->rev,
+ target, svn_depth_unknown, url,
+ switch_editor, switch_baton, subpool));
+
+ SVN_ERR(svn_wc__crawl_file_external(ctx->wc_ctx, local_abspath,
+ reporter, report_baton,
+ TRUE, use_commit_times,
+ ctx->cancel_func, ctx->cancel_baton,
+ ctx->notify_func2, ctx->notify_baton2,
+ subpool));
if (ctx->notify_func2)
{
@@ -603,10 +598,7 @@ handle_external_item_change(const struct
apr_pool_t *scratch_pool)
{
svn_ra_session_t *ra_session;
- svn_revnum_t ra_revnum;
- const char *ra_session_url;
- const char *repos_root_url;
- const char *repos_uuid;
+ svn_client__pathrev_t *new_loc;
const char *new_url;
svn_node_kind_t ext_kind;
@@ -627,29 +619,25 @@ handle_external_item_change(const struct
/* Determine if the external is a file or directory. */
/* Get the RA connection. */
- SVN_ERR(svn_client__ra_session_from_path(&ra_session,
- &ra_revnum,
- &ra_session_url,
- new_url, NULL,
- &(new_item->peg_revision),
- &(new_item->revision), eb->ctx,
- scratch_pool));
-
- SVN_ERR(svn_ra_get_uuid2(ra_session, &repos_uuid, scratch_pool));
- SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_url, scratch_pool));
- SVN_ERR(svn_ra_check_path(ra_session, "", ra_revnum, &ext_kind,
+ SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &new_loc,
+ new_url, NULL,
+ &(new_item->peg_revision),
+ &(new_item->revision), eb->ctx,
+ scratch_pool));
+
+ SVN_ERR(svn_ra_check_path(ra_session, "", new_loc->rev, &ext_kind,
scratch_pool));
if (svn_node_none == ext_kind)
return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
_("URL '%s' at revision %ld doesn't exist"),
- ra_session_url, ra_revnum);
+ new_loc->url, new_loc->rev);
if (svn_node_dir != ext_kind && svn_node_file != ext_kind)
return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
_("URL '%s' at revision %ld is not a file "
"or a directory"),
- ra_session_url, ra_revnum);
+ new_loc->url, new_loc->rev);
/* Not protecting against recursive externals. Detecting them in
@@ -687,7 +675,7 @@ handle_external_item_change(const struct
scratch_pool));
break;
case svn_node_file:
- if (strcmp(eb->repos_root_url, repos_root_url))
+ if (strcmp(eb->repos_root_url, new_loc->repos_root_url))
{
const char *local_repos_root_url;
const char *local_repos_uuid;
@@ -707,11 +695,11 @@ handle_external_item_change(const struct
eb->ctx->wc_ctx,
parent_dir_abspath,
scratch_pool, scratch_pool));
- ext_repos_relpath = svn_uri_skip_ancestor(repos_root_url,
+ ext_repos_relpath = svn_uri_skip_ancestor(new_loc->repos_root_url,
new_url, scratch_pool);
if (local_repos_uuid == NULL || local_repos_root_url == NULL ||
ext_repos_relpath == NULL ||
- strcmp(local_repos_uuid, repos_uuid) != 0)
+ strcmp(local_repos_uuid, new_loc->repos_uuid) != 0)
return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
_("Unsupported external: URL of file external '%s' "
"is not in repository '%s'"),
@@ -720,16 +708,12 @@ handle_external_item_change(const struct
new_url = svn_path_url_add_component2(local_repos_root_url,
ext_repos_relpath,
scratch_pool);
- SVN_ERR(svn_client__ra_session_from_path(&ra_session,
- &ra_revnum,
- &ra_session_url,
- new_url,
- NULL,
- &(new_item->peg_revision),
- &(new_item->revision),
- eb->ctx, scratch_pool));
- SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_url,
- scratch_pool));
+ SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &new_loc,
+ new_url,
+ NULL,
+ &(new_item->peg_revision),
+ &(new_item->revision),
+ eb->ctx, scratch_pool));
}
SVN_ERR(switch_file_external(local_abspath,
@@ -738,9 +722,6 @@ handle_external_item_change(const struct
&new_item->revision,
parent_dir_abspath,
ra_session,
- ra_session_url,
- ra_revnum,
- repos_root_url,
eb->timestamp_sleep, eb->ctx,
scratch_pool));
break;
@@ -1060,7 +1041,7 @@ svn_client__export_externals(apr_hash_t
svn_error_t *
svn_client__do_external_status(svn_client_ctx_t *ctx,
- apr_hash_t *externals_new,
+ apr_hash_t *external_map,
svn_depth_t depth,
svn_boolean_t get_all,
svn_boolean_t update,
@@ -1070,69 +1051,59 @@ svn_client__do_external_status(svn_clien
apr_pool_t *pool)
{
apr_hash_index_t *hi;
- apr_pool_t *subpool = svn_pool_create(pool);
+ apr_pool_t *iterpool = svn_pool_create(pool);
/* Loop over the hash of new values (we don't care about the old
ones). This is a mapping of versioned directories to property
values. */
- for (hi = apr_hash_first(pool, externals_new);
+ for (hi = apr_hash_first(pool, external_map);
hi;
hi = apr_hash_next(hi))
{
- apr_array_header_t *exts;
- const char *path = svn__apr_hash_index_key(hi);
- const char *propval = svn__apr_hash_index_val(hi);
- apr_pool_t *iterpool;
- int i;
+ svn_node_kind_t external_kind;
+ const char *local_abspath = svn__apr_hash_index_key(hi);
+ const char *defining_abspath = svn__apr_hash_index_val(hi);
+ svn_node_kind_t kind;
+ svn_opt_revision_t opt_rev;
- /* Clear the subpool. */
- svn_pool_clear(subpool);
+ svn_pool_clear(iterpool);
- /* Parse the svn:externals property value. This results in a
- hash mapping subdirectories to externals structures. */
- SVN_ERR(svn_wc_parse_externals_description3(&exts, path, propval,
- FALSE, subpool));
+ /* Obtain information on the expected external. */
+ SVN_ERR(svn_wc__read_external_info(&external_kind, NULL, NULL, NULL,
+ &opt_rev.value.number,
+ ctx->wc_ctx, defining_abspath,
+ local_abspath, FALSE,
+ iterpool, iterpool));
- /* Make a sub-pool of SUBPOOL. */
- iterpool = svn_pool_create(subpool);
+ if (external_kind != svn_node_dir)
+ continue;
- /* Loop over the subdir array. */
- for (i = 0; exts && (i < exts->nelts); i++)
- {
- const char *fullpath;
- svn_wc_external_item2_t *external;
- svn_node_kind_t kind;
-
- svn_pool_clear(iterpool);
-
- external = APR_ARRAY_IDX(exts, i, svn_wc_external_item2_t *);
- fullpath = svn_dirent_join(path, external->target_dir, iterpool);
-
- /* If the external target directory doesn't exist on disk,
- just skip it. */
- SVN_ERR(svn_io_check_path(fullpath, &kind, iterpool));
- if (kind != svn_node_dir)
- continue;
-
- /* Tell the client we're starting an external status set. */
- if (ctx->notify_func2)
- (ctx->notify_func2)(
+ SVN_ERR(svn_io_check_path(local_abspath, &kind, iterpool));
+ if (kind != svn_node_dir)
+ continue;
+
+ if (SVN_IS_VALID_REVNUM(opt_rev.value.number))
+ opt_rev.kind = svn_opt_revision_number;
+ else
+ opt_rev.kind = svn_opt_revision_unspecified;
+
+ /* Tell the client we're starting an external status set. */
+ if (ctx->notify_func2)
+ ctx->notify_func2(
ctx->notify_baton2,
- svn_wc_create_notify(fullpath, svn_wc_notify_status_external,
+ svn_wc_create_notify(local_abspath,
+ svn_wc_notify_status_external,
iterpool), iterpool);
- /* And then do the status. */
- SVN_ERR(svn_client_status5(NULL, ctx, fullpath,
- &(external->revision),
- depth, get_all, update,
- no_ignore, FALSE, FALSE, NULL,
- status_func, status_baton,
- iterpool));
- }
+ /* And then do the status. */
+ SVN_ERR(svn_client_status5(NULL, ctx, local_abspath, &opt_rev, depth,
+ get_all, update, no_ignore, FALSE, FALSE,
+ NULL, status_func, status_baton,
+ iterpool));
}
/* Destroy SUBPOOL and (implicitly) ITERPOOL. */
- svn_pool_destroy(subpool);
+ svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
Modified: subversion/branches/javahl-ra/subversion/libsvn_client/list.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/list.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/list.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/list.c Tue May 29 01:39:41 2012
@@ -237,9 +237,8 @@ svn_client_list2(const char *path_or_url
apr_pool_t *pool)
{
svn_ra_session_t *ra_session;
- svn_revnum_t rev;
+ svn_client__pathrev_t *loc;
svn_dirent_t *dirent;
- const char *url;
const char *fs_path;
svn_error_t *err;
apr_hash_t *locks;
@@ -249,20 +248,19 @@ svn_client_list2(const char *path_or_url
dirent_fields |= SVN_DIRENT_KIND;
/* Get an RA plugin for this filesystem object. */
- SVN_ERR(svn_client__ra_session_from_path(&ra_session, &rev,
- &url, path_or_url, NULL,
- peg_revision,
- revision, ctx, pool));
+ SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
+ path_or_url, NULL,
+ peg_revision,
+ revision, ctx, pool));
- SVN_ERR(svn_ra__get_fspath_relative_to_root(ra_session, &fs_path, url,
- pool));
+ fs_path = svn_client__pathrev_fspath(loc, pool);
- SVN_ERR(ra_stat_compatible(ra_session, rev, &dirent, dirent_fields,
+ SVN_ERR(ra_stat_compatible(ra_session, loc->rev, &dirent, dirent_fields,
ctx, pool));
if (! dirent)
return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
_("URL '%s' non-existent in revision %ld"),
- url, rev);
+ loc->url, loc->rev);
/* Maybe get all locks under url. */
if (fetch_locks)
@@ -292,7 +290,7 @@ svn_client_list2(const char *path_or_url
&& (depth == svn_depth_files
|| depth == svn_depth_immediates
|| depth == svn_depth_infinity))
- SVN_ERR(get_dir_contents(dirent_fields, "", rev, ra_session, locks,
+ SVN_ERR(get_dir_contents(dirent_fields, "", loc->rev, ra_session, locks,
fs_path, depth, ctx, list_func, baton, pool));
return SVN_NO_ERROR;
Modified: subversion/branches/javahl-ra/subversion/libsvn_client/locking_commands.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/locking_commands.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/locking_commands.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/locking_commands.c Tue May 29 01:39:41 2012
@@ -44,7 +44,7 @@
/* For use with store_locks_callback, below. */
struct lock_baton
{
- const char *base_path;
+ const char *base_dir_abspath;
apr_hash_t *urls_to_paths;
svn_client_ctx_t *ctx;
apr_pool_t *pool;
@@ -55,8 +55,8 @@ struct lock_baton
* BATON is a 'struct lock_baton *', PATH is the path being locked,
* and LOCK is the lock itself.
*
- * If BATON->base_path is not null, then this function either stores
- * the LOCK on REL_URL or removes any lock tokens from REL_URL
+ * If BATON->base_dir_abspath is not null, then this function either
+ * stores the LOCK on REL_URL or removes any lock tokens from REL_URL
* (depending on whether DO_LOCK is true or false respectively), but
* only if RA_ERR is null, or (in the unlock case) is something other
* than SVN_ERR_FS_LOCK_OWNER_MISMATCH.
@@ -86,20 +86,17 @@ store_locks_callback(void *baton,
notify->lock = lock;
notify->err = ra_err;
- if (lb->base_path)
+ if (lb->base_dir_abspath)
{
char *path = apr_hash_get(lb->urls_to_paths, rel_url,
APR_HASH_KEY_STRING);
const char *local_abspath;
- SVN_ERR(svn_dirent_get_absolute(&local_abspath,
- svn_dirent_join(lb->base_path,
- path, pool),
- pool));
+ local_abspath = svn_dirent_join(lb->base_dir_abspath, path, pool);
/* Notify a valid working copy path */
notify->path = local_abspath;
- notify->path_prefix = lb->base_path;
+ notify->path_prefix = lb->base_dir_abspath;
if (do_lock)
{
@@ -345,8 +342,9 @@ organize_lock_targets(const char **commo
{
svn_revnum_t *revnum;
revnum = apr_palloc(result_pool, sizeof(* revnum));
- SVN_ERR(svn_wc__node_get_base_rev(revnum, ctx->wc_ctx,
- abs_path, result_pool));
+ SVN_ERR(svn_wc__node_get_base(revnum, NULL, NULL, NULL,
+ ctx->wc_ctx, abs_path,
+ result_pool, iterpool));
apr_hash_set(rel_targets_ret, rel_url,
APR_HASH_KEY_STRING, revnum);
}
@@ -456,7 +454,7 @@ svn_client_lock(const apr_array_header_t
NULL, FALSE, FALSE,
ctx, pool));
- cb.base_path = base_dir;
+ cb.base_dir_abspath = base_dir_abspath;
cb.urls_to_paths = urls_to_paths;
cb.ctx = ctx;
cb.pool = pool;
@@ -503,7 +501,7 @@ svn_client_unlock(const apr_array_header
if (! base_dir && !break_lock)
SVN_ERR(fetch_tokens(ra_session, path_tokens, pool));
- cb.base_path = base_dir;
+ cb.base_dir_abspath = base_dir_abspath;
cb.urls_to_paths = urls_to_paths;
cb.ctx = ctx;
cb.pool = pool;
Modified: subversion/branches/javahl-ra/subversion/libsvn_client/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/log.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/log.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/log.c Tue May 29 01:39:41 2012
@@ -101,23 +101,22 @@ svn_client__get_copy_source(const char *
copyfrom_info_t copyfrom_info = { 0 };
apr_pool_t *sesspool = svn_pool_create(pool);
svn_ra_session_t *ra_session;
- svn_revnum_t at_rev;
- const char *at_url;
+ svn_client__pathrev_t *at_loc;
copyfrom_info.is_first = TRUE;
copyfrom_info.path = NULL;
copyfrom_info.rev = SVN_INVALID_REVNUM;
copyfrom_info.pool = pool;
- SVN_ERR(svn_client__ra_session_from_path(&ra_session, &at_rev, &at_url,
- path_or_url, NULL,
- revision, revision,
- ctx, sesspool));
+ SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &at_loc,
+ path_or_url, NULL,
+ revision, revision,
+ ctx, sesspool));
/* Find the copy source. Walk the location segments to find the revision
at which this node was created (copied or added). */
- err = svn_ra_get_location_segments(ra_session, "", at_rev, at_rev,
+ err = svn_ra_get_location_segments(ra_session, "", at_loc->rev, at_loc->rev,
SVN_INVALID_REVNUM,
copyfrom_info_receiver, ©from_info,
pool);
@@ -281,7 +280,6 @@ svn_client_log5(const apr_array_header_t
svn_ra_session_t *ra_session;
const char *url_or_path;
svn_boolean_t has_log_revprops;
- const char *actual_url;
apr_array_header_t *condensed_targets;
svn_opt_revision_t session_opt_rev;
const char *ra_target;
@@ -474,6 +472,8 @@ svn_client_log5(const apr_array_header_t
{
+ svn_client__pathrev_t *actual_loc;
+
/* If this is a revision type that requires access to the working copy,
* we use our initial target path to figure out where to root the RA
* session, otherwise we use our URL. */
@@ -483,7 +483,7 @@ svn_client_log5(const apr_array_header_t
else
ra_target = url_or_path;
- SVN_ERR(svn_client__ra_session_from_path(&ra_session, NULL, &actual_url,
+ SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &actual_loc,
ra_target, NULL,
&peg_rev, &session_opt_rev,
ctx, pool));
@@ -497,7 +497,7 @@ svn_client_log5(const apr_array_header_t
/* Create ra session on first use */
rb.ra_session_pool = pool;
- rb.ra_session_url = actual_url;
+ rb.ra_session_url = actual_loc->url;
}
}