You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2011/12/18 18:36:29 UTC
svn commit: r1220465 [5/13] - in /subversion/branches/file-handle-cache: ./
build/ build/ac-macros/ contrib/client-side/emacs/
contrib/server-side/mod_dontdothat/ notes/
subversion/bindings/javahl/tests/org/apache/subversion/javahl/
subversion/bindings...
Modified: subversion/branches/file-handle-cache/subversion/libsvn_client/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/libsvn_client/mergeinfo.c?rev=1220465&r1=1220464&r2=1220465&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/libsvn_client/mergeinfo.c (original)
+++ subversion/branches/file-handle-cache/subversion/libsvn_client/mergeinfo.c Sun Dec 18 17:36:24 2011
@@ -38,6 +38,7 @@
#include "svn_client.h"
#include "svn_hash.h"
+#include "private/svn_opt_private.h"
#include "private/svn_mergeinfo_private.h"
#include "private/svn_wc_private.h"
#include "private/svn_ra_private.h"
@@ -67,6 +68,16 @@ svn_client__merge_path_dup(const svn_cli
return new;
}
+svn_client__merge_path_t *
+svn_client__merge_path_create(const char *abspath,
+ apr_pool_t *pool)
+{
+ svn_client__merge_path_t *result = apr_pcalloc(pool, sizeof(*result));
+
+ result->abspath = apr_pstrdup(pool, abspath);
+ return result;
+}
+
svn_error_t *
svn_client__parse_mergeinfo(svn_mergeinfo_t *mergeinfo,
svn_wc_context_t *wc_ctx,
@@ -136,13 +147,56 @@ svn_client__record_wc_mergeinfo(const ch
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_client__record_wc_mergeinfo_catalog(apr_hash_t *result_catalog,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+ if (apr_hash_count(result_catalog))
+ {
+ int i;
+ apr_array_header_t *sorted_cat =
+ svn_sort__hash(result_catalog, svn_sort_compare_items_as_paths,
+ scratch_pool);
+ for (i = 0; i < sorted_cat->nelts; i++)
+ {
+ svn_sort__item_t elt = APR_ARRAY_IDX(sorted_cat, i,
+ svn_sort__item_t);
+ svn_error_t *err;
+
+ svn_pool_clear(iterpool);
+ err = svn_client__record_wc_mergeinfo(elt.key, elt.value, TRUE,
+ ctx, iterpool);
+
+ if (err && err->apr_err == SVN_ERR_ENTRY_NOT_FOUND)
+ {
+ /* PATH isn't just missing, it's not even versioned as far
+ as this working copy knows. But it was included in
+ MERGES, which means that the server knows about it.
+ Likely we don't have access to the source due to authz
+ restrictions. For now just clear the error and
+ continue... */
+ svn_error_clear(err);
+ }
+ else
+ {
+ SVN_ERR(err);
+ }
+ }
+ }
+ svn_pool_destroy(iterpool);
+ return SVN_NO_ERROR;
+}
+
/*-----------------------------------------------------------------------*/
/*** Retrieving mergeinfo. ***/
svn_error_t *
svn_client__get_wc_mergeinfo(svn_mergeinfo_t *mergeinfo,
- svn_boolean_t *inherited,
+ svn_boolean_t *inherited_p,
svn_mergeinfo_inheritance_t inherit,
const char *local_abspath,
const char *limit_abspath,
@@ -156,6 +210,7 @@ svn_client__get_wc_mergeinfo(svn_mergein
svn_mergeinfo_t wc_mergeinfo;
svn_revnum_t base_revision;
apr_pool_t *iterpool;
+ svn_boolean_t inherited;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
if (limit_abspath)
@@ -258,7 +313,7 @@ svn_client__get_wc_mergeinfo(svn_mergein
if (svn_path_is_empty(walk_relpath))
{
/* Mergeinfo is explicit. */
- *inherited = FALSE;
+ inherited = FALSE;
*mergeinfo = wc_mergeinfo;
}
else
@@ -266,7 +321,7 @@ svn_client__get_wc_mergeinfo(svn_mergein
/* Mergeinfo may be inherited. */
if (wc_mergeinfo)
{
- *inherited = TRUE;
+ inherited = TRUE;
SVN_ERR(svn_mergeinfo__add_suffix_to_mergeinfo(mergeinfo,
wc_mergeinfo,
walk_relpath,
@@ -275,7 +330,7 @@ svn_client__get_wc_mergeinfo(svn_mergein
}
else
{
- *inherited = FALSE;
+ inherited = FALSE;
*mergeinfo = NULL;
}
}
@@ -285,7 +340,7 @@ svn_client__get_wc_mergeinfo(svn_mergein
/* Remove non-inheritable mergeinfo and paths mapped to empty ranges
which may occur if WCPATH's mergeinfo is not explicit. */
- if (*inherited
+ if (inherited
&& apr_hash_count(*mergeinfo)) /* Nothing to do for empty mergeinfo. */
{
SVN_ERR(svn_mergeinfo_inheritable2(mergeinfo, *mergeinfo, NULL,
@@ -294,6 +349,9 @@ svn_client__get_wc_mergeinfo(svn_mergein
svn_mergeinfo__remove_empty_rangelists(*mergeinfo, result_pool);
}
+ if (inherited_p)
+ *inherited_p = inherited;
+
return SVN_NO_ERROR;
}
@@ -324,14 +382,15 @@ svn_client__get_wc_mergeinfo_catalog(svn
{
if (walked_path)
*walked_path = "";
- *inherited = FALSE;
+ if (inherited)
+ *inherited = FALSE;
return SVN_NO_ERROR;
}
SVN_ERR(svn_client__path_relative_to_root(&target_repos_rel_path,
ctx->wc_ctx,
local_abspath,
- repos_root, FALSE,
+ NULL, FALSE,
NULL, scratch_pool,
scratch_pool));
@@ -382,7 +441,7 @@ svn_client__get_wc_mergeinfo_catalog(svn
SVN_ERR(svn_client__path_relative_to_root(&key_path, ctx->wc_ctx,
key_path,
- repos_root, FALSE,
+ NULL, FALSE,
NULL, result_pool,
scratch_pool));
SVN_ERR(svn_mergeinfo_parse(&subtree_mergeinfo, propval->data,
@@ -534,7 +593,7 @@ svn_client__get_wc_or_repos_mergeinfo(sv
svn_error_t *
svn_client__get_wc_or_repos_mergeinfo_catalog(
svn_mergeinfo_catalog_t *target_mergeinfo_catalog,
- svn_boolean_t *inherited,
+ svn_boolean_t *inherited_p,
svn_boolean_t *from_repos,
svn_boolean_t include_descendants,
svn_boolean_t repos_only,
@@ -576,8 +635,9 @@ svn_client__get_wc_or_repos_mergeinfo_ca
if (!repos_only)
{
+ svn_boolean_t inherited;
SVN_ERR(svn_client__get_wc_mergeinfo_catalog(&target_mergeinfo_cat_wc,
- inherited,
+ &inherited,
include_descendants,
inherit,
local_abspath,
@@ -586,11 +646,13 @@ svn_client__get_wc_or_repos_mergeinfo_ca
ctx,
result_pool,
scratch_pool));
+ if (inherited_p)
+ *inherited_p = inherited;
/* If we want LOCAL_ABSPATH's inherited mergeinfo, were we able to
get it from the working copy? If not, then we must ask the
repository. */
- if (! ((*inherited)
+ if (! (inherited
|| (inherit == svn_mergeinfo_explicit)
|| (repos_relpath
&& target_mergeinfo_cat_wc
@@ -648,7 +710,8 @@ svn_client__get_wc_or_repos_mergeinfo_ca
repos_relpath,
APR_HASH_KEY_STRING))
{
- *inherited = TRUE;
+ if (inherited_p)
+ *inherited_p = TRUE;
if (from_repos)
*from_repos = TRUE;
}
@@ -756,7 +819,7 @@ should_elide_mergeinfo(svn_boolean_t *el
svn_mergeinfo_t parent_mergeinfo,
svn_mergeinfo_t child_mergeinfo,
const char *path_suffix,
- apr_pool_t *pool)
+ apr_pool_t *scratch_pool)
{
/* Easy out: No child mergeinfo to elide. */
if (child_mergeinfo == NULL)
@@ -781,20 +844,18 @@ should_elide_mergeinfo(svn_boolean_t *el
/* Both CHILD_MERGEINFO and PARENT_MERGEINFO are non-NULL and
non-empty. */
svn_mergeinfo_t path_tweaked_parent_mergeinfo;
- apr_pool_t *subpool = svn_pool_create(pool);
/* If we need to adjust the paths in PARENT_MERGEINFO do it now. */
if (path_suffix)
SVN_ERR(svn_mergeinfo__add_suffix_to_mergeinfo(
&path_tweaked_parent_mergeinfo, parent_mergeinfo,
- path_suffix, subpool, subpool));
+ path_suffix, scratch_pool, scratch_pool));
else
path_tweaked_parent_mergeinfo = parent_mergeinfo;
SVN_ERR(svn_mergeinfo__equals(elides,
path_tweaked_parent_mergeinfo,
- child_mergeinfo, TRUE, subpool));
- svn_pool_destroy(subpool);
+ child_mergeinfo, TRUE, scratch_pool));
}
return SVN_NO_ERROR;
@@ -911,7 +972,7 @@ svn_client__elide_mergeinfo(const char *
return SVN_NO_ERROR;
/* Get TARGET_WCPATH's inherited mergeinfo from the WC. */
- err = svn_client__get_wc_mergeinfo(&mergeinfo, &inherited,
+ err = svn_client__get_wc_mergeinfo(&mergeinfo, NULL,
svn_mergeinfo_nearest_ancestor,
target_abspath,
limit_abspath,
@@ -936,7 +997,7 @@ svn_client__elide_mergeinfo(const char *
if (!mergeinfo && !wc_elision_limit_path)
{
err = svn_client__get_wc_or_repos_mergeinfo(
- &mergeinfo, &inherited, NULL, TRUE,
+ &mergeinfo, NULL, NULL, TRUE,
svn_mergeinfo_nearest_ancestor,
NULL, target_wcpath, ctx, pool);
if (err)
@@ -1000,12 +1061,10 @@ get_mergeinfo(svn_mergeinfo_catalog_t *m
const char *url;
svn_boolean_t use_url = svn_path_is_url(path_or_url);
svn_revnum_t peg_rev;
- svn_opt_revision_t opt_rev;
- opt_rev.kind = svn_opt_revision_unspecified;
SVN_ERR(svn_client__ra_session_from_path(&ra_session, &peg_rev, &url,
path_or_url, NULL, peg_revision,
- &opt_rev, ctx, scratch_pool));
+ peg_revision, ctx, scratch_pool));
/* If PATH_OR_URL is as working copy path determine if we will need to
contact the repository for the requested PEG_REVISION. */
@@ -1050,11 +1109,9 @@ get_mergeinfo(svn_mergeinfo_catalog_t *m
}
else /* ! svn_path_is_url() */
{
- svn_boolean_t inherited;
-
/* Acquire return values. */
SVN_ERR(svn_client__get_wc_or_repos_mergeinfo_catalog(
- mergeinfo_catalog, &inherited, NULL, include_descendants, FALSE,
+ mergeinfo_catalog, NULL, NULL, include_descendants, FALSE,
ignore_invalid_mergeinfo, svn_mergeinfo_inherited,
ra_session, path_or_url, ctx,
result_pool, scratch_pool));
@@ -1064,142 +1121,74 @@ get_mergeinfo(svn_mergeinfo_catalog_t *m
}
/*** In-memory mergeinfo elision ***/
-
-/* TODO(reint): Document. */
-struct elide_mergeinfo_catalog_dir_baton {
- const char *inherited_mergeinfo_path;
- svn_mergeinfo_t mergeinfo_catalog;
-};
-
-/* The root doesn't have mergeinfo (unless it is actually one of the
- paths passed to svn_delta_path_driver, in which case the callback
- is called directly instead of this). */
-static svn_error_t *
-elide_mergeinfo_catalog_open_root(void *eb,
- svn_revnum_t base_revision,
- apr_pool_t *dir_pool,
- void **root_baton)
-{
- struct elide_mergeinfo_catalog_dir_baton *b = apr_pcalloc(dir_pool,
- sizeof(*b));
- b->mergeinfo_catalog = eb;
- *root_baton = b;
- return SVN_NO_ERROR;
-}
-
-/* Make a directory baton for PATH. It should have the same
- inherited_mergeinfo_path as its parent... unless we just called
- elide_mergeinfo_catalog_cb on its parent with its path. */
-static svn_error_t *
-elide_mergeinfo_catalog_open_directory(const char *path,
- void *parent_baton,
- svn_revnum_t base_revision,
- apr_pool_t *dir_pool,
- void **child_baton)
-{
- struct elide_mergeinfo_catalog_dir_baton *b, *pb = parent_baton;
-
- b = apr_pcalloc(dir_pool, sizeof(*b));
- b->mergeinfo_catalog = pb->mergeinfo_catalog;
-
- if (apr_hash_get(b->mergeinfo_catalog, path, APR_HASH_KEY_STRING))
- b->inherited_mergeinfo_path = apr_pstrdup(dir_pool, path);
- else
- b->inherited_mergeinfo_path = pb->inherited_mergeinfo_path;
-
- *child_baton = b;
- return SVN_NO_ERROR;
-}
-
-/* TODO(reint): Document. */
-struct elide_mergeinfo_catalog_cb_baton {
- apr_array_header_t *elidable_paths;
- svn_mergeinfo_t mergeinfo_catalog;
- apr_pool_t *result_pool;
-};
-
-/* Implements svn_delta_path_driver_cb_func_t. */
-static svn_error_t *
-elide_mergeinfo_catalog_cb(void **dir_baton,
- void *parent_baton,
- void *callback_baton,
- const char *path,
- apr_pool_t *pool)
+svn_error_t *
+svn_client__elide_mergeinfo_catalog(svn_mergeinfo_catalog_t mergeinfo_catalog,
+ apr_pool_t *scratch_pool)
{
- struct elide_mergeinfo_catalog_cb_baton *cb = callback_baton;
- struct elide_mergeinfo_catalog_dir_baton *pb = parent_baton;
- const char *path_suffix;
- svn_boolean_t elides;
-
- /* pb == NULL would imply that there was an *empty* path in the
- paths given to the driver (which is different from "/"). */
- SVN_ERR_ASSERT(pb != NULL);
-
- /* We'll just act like everything is a file. */
- *dir_baton = NULL;
-
- /* Is there even any inherited mergeinfo to elide? */
- /* (Note that svn_delta_path_driver will call open_directory before
- the callback for the root (only).) */
- if (!pb->inherited_mergeinfo_path
- || strcmp(path, "/") == 0)
- return SVN_NO_ERROR;
+ apr_array_header_t *sorted_hash;
+ apr_array_header_t *elidable_paths = apr_array_make(scratch_pool, 1,
+ sizeof(const char *));
+ apr_array_header_t *dir_stack = apr_array_make(scratch_pool, 1,
+ sizeof(const char *));
+ apr_pool_t *iterpool;
+ int i;
- path_suffix = svn_dirent_is_child(pb->inherited_mergeinfo_path,
- path, NULL);
- SVN_ERR_ASSERT(path_suffix != NULL);
+ /* Here's the general algorithm:
+ Walk through the paths sorted in tree order. For each path, pop
+ the dir_stack until it is either empty or the top item contains a parent
+ of the current path. Check to see if that mergeinfo is then elidable,
+ and build the list of elidable mergeinfo based upon that determination.
+ Finally, push the path of interest onto the stack, and continue. */
+ sorted_hash = svn_sort__hash(mergeinfo_catalog,
+ svn_sort_compare_items_as_paths,
+ scratch_pool);
+ iterpool = svn_pool_create(scratch_pool);
+ for (i = 0; i < sorted_hash->nelts; i++)
+ {
+ svn_sort__item_t *item = &APR_ARRAY_IDX(sorted_hash, i,
+ svn_sort__item_t);
+ const char *path = item->key;
+
+ if (dir_stack->nelts > 0)
+ {
+ const char *top;
+ const char *path_suffix;
+ svn_boolean_t elides = FALSE;
+
+ svn_pool_clear(iterpool);
- SVN_ERR(should_elide_mergeinfo(&elides,
- apr_hash_get(cb->mergeinfo_catalog,
- pb->inherited_mergeinfo_path,
- APR_HASH_KEY_STRING),
- apr_hash_get(cb->mergeinfo_catalog,
- path,
- APR_HASH_KEY_STRING),
- path_suffix,
- pool));
+ /* Pop off any paths which are not ancestors of PATH. */
+ do
+ {
+ top = APR_ARRAY_IDX(dir_stack, dir_stack->nelts - 1,
+ const char *);
+ path_suffix = svn_dirent_is_child(top, path, NULL);
- if (elides)
- APR_ARRAY_PUSH(cb->elidable_paths, const char *) =
- apr_pstrdup(cb->result_pool, path);
+ if (!path_suffix)
+ apr_array_pop(dir_stack);
+ }
+ while (dir_stack->nelts > 0 && !path_suffix);
- return SVN_NO_ERROR;
-}
+ /* If we have a path suffix, it means we haven't popped the stack
+ clean. */
+ if (path_suffix)
+ {
+ SVN_ERR(should_elide_mergeinfo(&elides,
+ apr_hash_get(mergeinfo_catalog, top,
+ APR_HASH_KEY_STRING),
+ apr_hash_get(mergeinfo_catalog, path,
+ APR_HASH_KEY_STRING),
+ path_suffix,
+ iterpool));
-svn_error_t *
-svn_client__elide_mergeinfo_catalog(svn_mergeinfo_t mergeinfo_catalog,
- apr_pool_t *pool)
-{
- apr_array_header_t *paths;
- apr_array_header_t *elidable_paths = apr_array_make(pool, 1,
- sizeof(const char *));
- svn_delta_editor_t *editor = svn_delta_default_editor(pool);
- struct elide_mergeinfo_catalog_cb_baton cb = { 0 };
- void *eb;
- int i;
- svn_delta_shim_callbacks_t *shim_callbacks =
- svn_delta_shim_callbacks_default(pool);
+ if (elides)
+ APR_ARRAY_PUSH(elidable_paths, const char *) = path;
+ }
+ }
- cb.elidable_paths = elidable_paths;
- cb.mergeinfo_catalog = mergeinfo_catalog;
- cb.result_pool = pool;
-
- editor->open_root = elide_mergeinfo_catalog_open_root;
- editor->open_directory = elide_mergeinfo_catalog_open_directory;
-
- eb = mergeinfo_catalog;
- SVN_ERR(svn_editor__insert_shims((const svn_delta_editor_t **)&editor, &eb,
- editor, eb, shim_callbacks, pool, pool));
-
- /* Walk over the paths, and build up a list of elidable ones. */
- SVN_ERR(svn_hash_keys(&paths, mergeinfo_catalog, pool));
- SVN_ERR(svn_delta_path_driver(editor,
- eb,
- SVN_INVALID_REVNUM,
- paths,
- elide_mergeinfo_catalog_cb,
- &cb,
- pool));
+ APR_ARRAY_PUSH(dir_stack, const char *) = path;
+ }
+ svn_pool_destroy(iterpool);
/* Now remove the elidable paths from the catalog. */
for (i = 0; i < elidable_paths->nelts; i++)
@@ -1357,11 +1346,12 @@ filter_log_entry_with_rangelist(void *ba
/* If the paths changed by LOG_ENTRY->REVISION are provided we can determine
if LOG_ENTRY->REVISION, while only partially represented in
- BATON->RANGELIST, is in fact completely applied to all affected paths. */
+ BATON->RANGELIST, is in fact completely applied to all affected paths.
+ ### And ... what if it is, or if it isn't? What do we do with the answer?
+ And how do we cope if the changed paths are not provided? */
if ((log_entry->non_inheritable || !fleb->filtering_merged)
&& log_entry->changed_paths2)
{
- int i;
apr_hash_index_t *hi;
svn_boolean_t all_subtrees_have_this_rev = TRUE;
apr_array_header_t *this_rev_rangelist =
@@ -1373,11 +1363,11 @@ filter_log_entry_with_rangelist(void *ba
hi;
hi = apr_hash_next(hi))
{
+ int i;
const char *path = svn__apr_hash_index_key(hi);
svn_log_changed_path2_t *change = svn__apr_hash_index_val(hi);
const char *target_fspath_affected;
svn_mergeinfo_t nearest_ancestor_mergeinfo;
- apr_hash_index_t *hi2;
svn_boolean_t found_this_revision = FALSE;
const char *merge_source_rel_target;
const char *merge_source_fspath;
@@ -1449,6 +1439,8 @@ filter_log_entry_with_rangelist(void *ba
if (nearest_ancestor_mergeinfo)
{
+ apr_hash_index_t *hi2;
+
for (hi2 = apr_hash_first(iterpool, nearest_ancestor_mergeinfo);
hi2;
hi2 = apr_hash_next(hi2))
@@ -1471,15 +1463,30 @@ filter_log_entry_with_rangelist(void *ba
iterpool));
if (intersection->nelts)
{
- SVN_ERR(svn_rangelist_intersect(&intersection,
- rangelist,
- this_rev_rangelist,
- TRUE, iterpool));
- if (intersection->nelts)
+ if (ancestor_is_self)
{
+ /* TARGET_PATH_AFFECTED has explicit mergeinfo,
+ so we don't need to worry if that mergeinfo
+ is inheritable or not. */
found_this_revision = TRUE;
break;
}
+ else
+ {
+ /* TARGET_PATH_AFFECTED inherited its mergeinfo,
+ se we have to ignore non-inheritable
+ ranges. */
+ SVN_ERR(svn_rangelist_intersect(
+ &intersection,
+ rangelist,
+ this_rev_rangelist,
+ TRUE, iterpool));
+ if (intersection->nelts)
+ {
+ found_this_revision = TRUE;
+ break;
+ }
+ }
}
}
}
@@ -1527,7 +1534,6 @@ logs_for_mergeinfo_rangelist(const char
svn_merge_range_t *oldest_range, *youngest_range;
apr_array_header_t *revision_ranges;
svn_opt_revision_t oldest_rev, youngest_rev;
- svn_opt_revision_range_t *range;
struct filter_log_entry_baton_t fleb;
if (! rangelist->nelts)
@@ -1576,10 +1582,8 @@ logs_for_mergeinfo_rangelist(const char
/* Drive the log. */
revision_ranges = apr_array_make(scratch_pool, 1,
sizeof(svn_opt_revision_range_t *));
- range = apr_pcalloc(scratch_pool, sizeof(*range));
- range->end = youngest_rev;
- range->start = oldest_rev;
- APR_ARRAY_PUSH(revision_ranges, svn_opt_revision_range_t *) = range;
+ APR_ARRAY_PUSH(revision_ranges, svn_opt_revision_range_t *)
+ = svn_opt__revision_range_create(&oldest_rev, &youngest_rev, scratch_pool);
SVN_ERR(svn_client_log5(target, &youngest_rev, revision_ranges,
0, discover_changed_paths, FALSE, FALSE, revprops,
filter_log_entry_with_rangelist, &fleb, ctx,
Modified: subversion/branches/file-handle-cache/subversion/libsvn_client/mergeinfo.h
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/libsvn_client/mergeinfo.h?rev=1220465&r1=1220464&r2=1220465&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/libsvn_client/mergeinfo.h (original)
+++ subversion/branches/file-handle-cache/subversion/libsvn_client/mergeinfo.h Sun Dec 18 17:36:24 2011
@@ -40,7 +40,9 @@ typedef struct svn_client__merge_path_t
{
const char *abspath; /* Absolute working copy path. */
svn_boolean_t missing_child; /* ABSPATH has an immediate child which
- is missing. */
+ is missing, but is not switched. */
+ svn_boolean_t switched_child; /* ABSPATH has an immediate child which
+ is switched. */
svn_boolean_t switched; /* ABSPATH is switched. */
svn_boolean_t has_noninheritable; /* ABSPATH has svn:mergeinfo set on it
which includes non-inheritable
@@ -79,6 +81,13 @@ typedef struct svn_client__merge_path_t
to the merge, and the operational
depth of the merge is
svn_depth_immediates. */
+ svn_boolean_t record_mergeinfo; /* Mergeinfo needs to be recorded
+ on ABSPATH to describe the
+ merge. */
+ svn_boolean_t record_noninheritable; /* Non-inheritable mergeinfo needs to
+ be recorded on ABSPATH to describe
+ the merge. Implies RECORD_MERGEINFO
+ is true. */
} svn_client__merge_path_t;
/* Return a deep copy of the merge-path structure OLD, allocated in POOL. */
@@ -86,13 +95,21 @@ svn_client__merge_path_t *
svn_client__merge_path_dup(const svn_client__merge_path_t *old,
apr_pool_t *pool);
+/* Create a new merge path structure, allocated in POOL. Initialize the
+ * 'abspath' member to a deep copy of ABSPATH and all other fields to zero
+ * bytes. */
+svn_client__merge_path_t *
+svn_client__merge_path_create(const char *abspath,
+ apr_pool_t *pool);
+
/*** Functions ***/
/* Find explicit or inherited WC mergeinfo for LOCAL_ABSPATH, and return it
in *MERGEINFO (NULL if no mergeinfo is set). Set *INHERITED to
- whether the mergeinfo was inherited (TRUE or FALSE).
+ whether the mergeinfo was inherited (TRUE or FALSE), if INHERITED is
+ non-null.
This function will search for inherited mergeinfo in the parents of
LOCAL_ABSPATH only if the base revision of LOCAL_ABSPATH falls within
@@ -226,7 +243,7 @@ svn_client__get_repos_mergeinfo_catalog(
If TARGET_WCPATH inherited its mergeinfo from a working copy ancestor
or if it was obtained from the repository, set *INHERITED to TRUE, set it
- to FALSE otherwise. */
+ to FALSE otherwise, if INHERITED is non-null. */
svn_error_t *
svn_client__get_wc_or_repos_mergeinfo(svn_mergeinfo_t *target_mergeinfo,
svn_boolean_t *inherited,
@@ -313,6 +330,13 @@ svn_client__record_wc_mergeinfo(const ch
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool);
+/* Write mergeinfo into the WC. RESULT_CATALOG maps (const char *) WC paths
+ * to (svn_mergeinfo_t) mergeinfo. */
+svn_error_t *
+svn_client__record_wc_mergeinfo_catalog(apr_hash_t *result_catalog,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *scratch_pool);
+
/* Elide any svn:mergeinfo set on TARGET_WCPATH to its nearest working
copy (or possibly repository) ancestor with equivalent mergeinfo.
@@ -352,10 +376,18 @@ svn_client__elide_mergeinfo(const char *
svn_client_ctx_t *ctx,
apr_pool_t *pool);
-/* TODO(reint): Document. */
+/* Simplify a mergeinfo catalog, if possible, via elision.
+
+ For each path in MERGEINFO_CATALOG, check if the path's mergeinfo can
+ elide to the path's nearest path-wise parent in MERGEINFO_CATALOG. If
+ so, remove that path from MERGEINFO_CATALOG. Elidability is determined
+ as per svn_client__elide_mergeinfo except that elision to the repository
+ is not considered.
+
+ SCRATCH_POOL is used for temporary allocations. */
svn_error_t *
-svn_client__elide_mergeinfo_catalog(svn_mergeinfo_t mergeinfo_catalog,
- apr_pool_t *pool);
+svn_client__elide_mergeinfo_catalog(svn_mergeinfo_catalog_t mergeinfo_catalog,
+ apr_pool_t *scratch_pool);
/* Set *MERGEINFO_CHANGES to TRUE if LOCAL_ABSPATH has locally modified
mergeinfo, set *MERGEINFO_CHANGES to FALSE otherwise. */
Modified: subversion/branches/file-handle-cache/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/libsvn_client/patch.c?rev=1220465&r1=1220464&r2=1220465&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/file-handle-cache/subversion/libsvn_client/patch.c Sun Dec 18 17:36:24 2011
@@ -811,13 +811,20 @@ write_file(void *baton, const char *buf,
* with the fewest path components, the shortest basename, and the shortest
* total file name length (in that order). In case of a tie, return the new
* filename. This heuristic is also used by Larry Wall's UNIX patch (except
- * that it prompts for a filename in case of a tie). */
+ * that it prompts for a filename in case of a tie).
+ * Additionally, for compatibility with git, if one of the filenames
+ * is "/dev/null", use the other filename. */
static const char *
choose_target_filename(const svn_patch_t *patch)
{
apr_size_t old;
apr_size_t new;
+ if (strcmp(patch->old_filename, "/dev/null") == 0)
+ return patch->new_filename;
+ if (strcmp(patch->new_filename, "/dev/null") == 0)
+ return patch->old_filename;
+
old = svn_path_component_count(patch->old_filename);
new = svn_path_component_count(patch->new_filename);
@@ -1692,7 +1699,7 @@ apply_hunk(patch_target_t *target, targe
&eol_str, &eof,
iterpool, iterpool));
lines_read++;
- if (! eof && lines_read > hi->fuzz &&
+ if (lines_read > hi->fuzz &&
lines_read <= svn_diff_hunk_get_modified_length(hi->hunk) - hi->fuzz)
{
apr_size_t len;
@@ -2723,6 +2730,7 @@ delete_empty_dirs(apr_array_header_t *ta
SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
target_info = APR_ARRAY_IDX(targets_info, i, patch_target_info_t *);
+
parent = svn_dirent_dirname(target_info->local_abspath, iterpool);
if (apr_hash_get(non_empty_dirs, parent, APR_HASH_KEY_STRING))
@@ -2825,54 +2833,36 @@ delete_empty_dirs(apr_array_header_t *ta
return SVN_NO_ERROR;
}
-/* Baton for apply_patches(). */
-typedef struct apply_patches_baton_t {
- /* The path to the patch file. */
- const char *patch_abspath;
-
- /* The abspath to the working copy the patch should be applied to. */
- const char *abs_wc_path;
-
- /* Indicates whether we're doing a dry run. */
- svn_boolean_t dry_run;
-
- /* Number of leading components to strip from patch target paths. */
- int strip_count;
-
- /* Whether to apply the patch in reverse. */
- svn_boolean_t reverse;
-
- /* Indicates whether we should ignore whitespace when matching context
- * lines */
- svn_boolean_t ignore_whitespace;
-
- /* As in svn_client_patch(). */
- svn_boolean_t remove_tempfiles;
-
- /* As in svn_client_patch(). */
- svn_client_patch_func_t patch_func;
- void *patch_baton;
-
- /* The client context. */
- svn_client_ctx_t *ctx;
-} apply_patches_baton_t;
-
-/* Callback for use with svn_wc__call_with_write_lock().
- * This function is the main entry point into the patch code. */
+/* This function is the main entry point into the patch code. */
static svn_error_t *
-apply_patches(void *baton,
- apr_pool_t *result_pool,
+apply_patches(/* The path to the patch file. */
+ const char *patch_abspath,
+ /* The abspath to the working copy the patch should be applied to. */
+ const char *abs_wc_path,
+ /* Indicates whether we're doing a dry run. */
+ svn_boolean_t dry_run,
+ /* Number of leading components to strip from patch target paths. */
+ int strip_count,
+ /* Whether to apply the patch in reverse. */
+ svn_boolean_t reverse,
+ /* Whether to ignore whitespace when matching context lines. */
+ svn_boolean_t ignore_whitespace,
+ /* As in svn_client_patch(). */
+ svn_boolean_t remove_tempfiles,
+ /* As in svn_client_patch(). */
+ svn_client_patch_func_t patch_func,
+ void *patch_baton,
+ /* The client context. */
+ svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
svn_patch_t *patch;
apr_pool_t *iterpool;
svn_patch_file_t *patch_file;
apr_array_header_t *targets_info;
- apply_patches_baton_t *btn = baton;
/* Try to open the patch file. */
- SVN_ERR(svn_diff_open_patch_file(&patch_file, btn->patch_abspath,
- scratch_pool));
+ SVN_ERR(svn_diff_open_patch_file(&patch_file, patch_abspath, scratch_pool));
/* Apply patches. */
targets_info = apr_array_make(scratch_pool, 0,
@@ -2882,23 +2872,21 @@ apply_patches(void *baton,
{
svn_pool_clear(iterpool);
- if (btn->ctx->cancel_func)
- SVN_ERR(btn->ctx->cancel_func(btn->ctx->cancel_baton));
+ if (ctx->cancel_func)
+ SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file,
- btn->reverse, btn->ignore_whitespace,
+ reverse, ignore_whitespace,
iterpool, iterpool));
if (patch)
{
patch_target_t *target;
- SVN_ERR(apply_one_patch(&target, patch, btn->abs_wc_path,
- btn->ctx->wc_ctx, btn->strip_count,
- btn->ignore_whitespace,
- btn->remove_tempfiles,
- btn->patch_func, btn->patch_baton,
- btn->ctx->cancel_func,
- btn->ctx->cancel_baton,
+ SVN_ERR(apply_one_patch(&target, patch, abs_wc_path,
+ ctx->wc_ctx, strip_count,
+ ignore_whitespace, remove_tempfiles,
+ patch_func, patch_baton,
+ ctx->cancel_func, ctx->cancel_baton,
iterpool, iterpool));
if (! target->filtered)
{
@@ -2908,35 +2896,32 @@ apply_patches(void *baton,
target_info->local_abspath = apr_pstrdup(scratch_pool,
target->local_abspath);
target_info->deleted = target->deleted;
- APR_ARRAY_PUSH(targets_info,
- patch_target_info_t *) = target_info;
if (! target->skipped)
{
+ APR_ARRAY_PUSH(targets_info,
+ patch_target_info_t *) = target_info;
+
if (target->has_text_changes
|| target->added
|| target->deleted)
- SVN_ERR(install_patched_target(target, btn->abs_wc_path,
- btn->ctx, btn->dry_run,
- iterpool));
+ SVN_ERR(install_patched_target(target, abs_wc_path,
+ ctx, dry_run, iterpool));
if (target->has_prop_changes && (!target->deleted))
- SVN_ERR(install_patched_prop_targets(target, btn->ctx,
- btn->dry_run,
- iterpool));
+ SVN_ERR(install_patched_prop_targets(target, ctx,
+ dry_run, iterpool));
- SVN_ERR(write_out_rejected_hunks(target, btn->dry_run,
- iterpool));
+ SVN_ERR(write_out_rejected_hunks(target, dry_run, iterpool));
}
- SVN_ERR(send_patch_notification(target, btn->ctx, iterpool));
+ SVN_ERR(send_patch_notification(target, ctx, iterpool));
}
}
}
while (patch);
/* Delete directories which are empty after patching, if any. */
- SVN_ERR(delete_empty_dirs(targets_info, btn->ctx, btn->dry_run,
- scratch_pool));
+ SVN_ERR(delete_empty_dirs(targets_info, ctx, dry_run, scratch_pool));
SVN_ERR(svn_diff_close_patch_file(patch_file, iterpool));
svn_pool_destroy(iterpool);
@@ -2957,7 +2942,6 @@ svn_client_patch(const char *patch_abspa
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
- apply_patches_baton_t baton;
svn_node_kind_t kind;
if (strip_count < 0)
@@ -2994,19 +2978,10 @@ svn_client_patch(const char *patch_abspa
svn_dirent_local_style(wc_dir_abspath,
scratch_pool));
- baton.patch_abspath = patch_abspath;
- baton.abs_wc_path = wc_dir_abspath;
- baton.dry_run = dry_run;
- baton.ctx = ctx;
- baton.strip_count = strip_count;
- baton.reverse = reverse;
- baton.ignore_whitespace = ignore_whitespace;
- baton.remove_tempfiles = remove_tempfiles;
- baton.patch_func = patch_func;
- baton.patch_baton = patch_baton;
-
- return svn_error_trace(
- svn_wc__call_with_write_lock(apply_patches, &baton,
- ctx->wc_ctx, wc_dir_abspath, FALSE,
- scratch_pool, scratch_pool));
+ SVN_WC__CALL_WITH_WRITE_LOCK(
+ apply_patches(patch_abspath, wc_dir_abspath, dry_run, strip_count,
+ reverse, ignore_whitespace, remove_tempfiles,
+ patch_func, patch_baton, ctx, scratch_pool),
+ ctx->wc_ctx, wc_dir_abspath, FALSE /* lock_anchor */, scratch_pool);
+ return SVN_NO_ERROR;
}
Modified: subversion/branches/file-handle-cache/subversion/libsvn_client/prop_commands.c
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/libsvn_client/prop_commands.c?rev=1220465&r1=1220464&r2=1220465&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/libsvn_client/prop_commands.c (original)
+++ subversion/branches/file-handle-cache/subversion/libsvn_client/prop_commands.c Sun Dec 18 17:36:24 2011
@@ -248,37 +248,6 @@ propset_on_url(const char *propname,
return editor->close_edit(edit_baton, pool);
}
-/* Baton for set_props_cb */
-struct set_props_baton
-{
- svn_client_ctx_t *ctx;
- const char *local_abspath;
- svn_depth_t depth;
- svn_node_kind_t kind;
- const char *propname;
- const svn_string_t *propval;
- svn_boolean_t skip_checks;
- const apr_array_header_t *changelist_filter;
-};
-
-/* Working copy lock callback for svn_client_propset4 */
-static svn_error_t *
-set_props_cb(void *baton,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- struct set_props_baton *bt = baton;
-
- SVN_ERR(svn_wc_prop_set4(bt->ctx->wc_ctx, bt->local_abspath, bt->propname,
- bt->propval, bt->depth, bt->skip_checks,
- bt->changelist_filter,
- bt->ctx->cancel_func, bt->ctx->cancel_baton,
- bt->ctx->notify_func2, bt->ctx->notify_baton2,
- scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
/* Check that PROPNAME is a valid name for a versioned property. Return an
* error if it is not valid, specifically if it is:
* - the name of a standard Subversion rev-prop; or
@@ -342,7 +311,6 @@ svn_client_propset_local(const char *pro
svn_node_kind_t kind;
const char *target_abspath;
svn_error_t *err;
- struct set_props_baton baton;
const char *target = APR_ARRAY_IDX(targets, i, const char *);
svn_pool_clear(iterpool);
@@ -374,18 +342,12 @@ svn_client_propset_local(const char *pro
else
SVN_ERR(err);
- baton.ctx = ctx;
- baton.local_abspath = target_abspath;
- baton.depth = depth;
- baton.kind = kind;
- baton.propname = propname;
- baton.propval = propval;
- baton.skip_checks = skip_checks;
- baton.changelist_filter = changelists;
-
- SVN_ERR(svn_wc__call_with_write_lock(set_props_cb, &baton,
- ctx->wc_ctx, target_abspath,
- FALSE, iterpool, iterpool));
+ SVN_WC__CALL_WITH_WRITE_LOCK(
+ svn_wc_prop_set4(ctx->wc_ctx, target_abspath, propname,
+ propval, depth, skip_checks, changelists,
+ ctx->cancel_func, ctx->cancel_baton,
+ ctx->notify_func2, ctx->notify_baton2, iterpool),
+ ctx->wc_ctx, target_abspath, FALSE /* lock_anchor */, iterpool);
}
svn_pool_destroy(iterpool);
Modified: subversion/branches/file-handle-cache/subversion/libsvn_client/ra.c
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/libsvn_client/ra.c?rev=1220465&r1=1220464&r2=1220465&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/libsvn_client/ra.c (original)
+++ subversion/branches/file-handle-cache/subversion/libsvn_client/ra.c Sun Dec 18 17:36:24 2011
@@ -40,6 +40,7 @@
#include "svn_private_config.h"
#include "private/svn_wc_private.h"
+#include "private/svn_client_private.h"
/* This is the baton that we pass svn_ra_open3(), and is associated with
@@ -387,17 +388,6 @@ svn_client_open_ra_session(svn_ra_sessio
-/* Convert a path or URL for display: if it is a local path, convert it to
- * the local path style; if it is a URL, return it unchanged. */
-static const char *
-path_or_url_local_style(const char *path_or_url,
- apr_pool_t *pool)
-{
- if (svn_path_is_url(path_or_url))
- return path_or_url;
- return svn_dirent_local_style(path_or_url, pool);
-}
-
/* Given PATH_OR_URL, which contains either a working copy path or an
absolute URL, a peg revision PEG_REVISION, and a desired revision
REVISION, find the path at which that object exists in REVISION,
@@ -406,13 +396,18 @@ path_or_url_local_style(const char *path
PEG_REVISION and REVISION, and return @c
SVN_ERR_CLIENT_UNRELATED_RESOURCES if it is not the same node.
- If PEG_REVISION's kind is svn_opt_revision_unspecified, interpret it
- as "head" for a URL or "working" for a working-copy path.
+ If PEG_REVISION->kind is 'unspecified', the peg revision is 'head'
+ for a URL or 'working' for a WC path. If REVISION->kind is
+ 'unspecified', the operative revision is the peg revision.
Store the actual revision number of the object in *REV_P, and the
final resulting URL in *URL_P. REV_P and/or URL_P may be NULL if not
wanted.
+ RA_SESSION should be an open RA session pointing at the URL of
+ PATH_OR_URL, or NULL, in which case this function will open its own
+ temporary session.
+
Use authentication baton cached in CTX to authenticate against the
repository.
@@ -429,26 +424,21 @@ resolve_rev_and_url(svn_revnum_t *rev_p,
{
svn_opt_revision_t peg_rev = *peg_revision;
svn_opt_revision_t start_rev = *revision;
- svn_opt_revision_t *good_rev;
const char *url;
svn_revnum_t rev;
+ /* Default revisions: peg -> working or head; operative -> peg. */
SVN_ERR(svn_opt_resolve_revisions(&peg_rev, &start_rev,
svn_path_is_url(path_or_url),
- TRUE,
+ TRUE /* notice_local_mods */,
pool));
/* Run the history function to get the object's (possibly
different) url in REVISION. */
- SVN_ERR(svn_client__repos_locations(&url, &good_rev, NULL, NULL,
+ SVN_ERR(svn_client__repos_locations(&url, &rev, NULL, NULL,
ra_session, path_or_url, &peg_rev,
&start_rev, NULL, ctx, pool));
- /* Resolve good_rev into a real revnum. */
- if (good_rev->kind == svn_opt_revision_unspecified)
- good_rev->kind = svn_opt_revision_head;
- SVN_ERR(svn_client__get_revision_number(&rev, NULL, ctx->wc_ctx, url,
- ra_session, good_rev, pool));
if (rev_p)
*rev_p = rev;
if (url_p)
@@ -583,12 +573,106 @@ svn_client__repos_location_segments(apr_
return SVN_NO_ERROR;
}
+/* Set *START_URL and *END_URL to the URLs that the object URL@PEG_REVNUM
+ * had in revisions START_REVNUM and END_REVNUM. Return an error if the
+ * node cannot be traced back to one of the requested revisions.
+ *
+ * START_URL and/or END_URL may be NULL if not wanted. START_REVNUM and
+ * END_REVNUM must be valid revision numbers except that END_REVNUM may
+ * be SVN_INVALID_REVNUM if END_URL is NULL. RA_SESSION is required.
+ */
+static svn_error_t *
+repos_locations(const char **start_url,
+ const char **end_url,
+ svn_ra_session_t *ra_session,
+ const char *url,
+ svn_revnum_t peg_revnum,
+ svn_revnum_t start_revnum,
+ svn_revnum_t end_revnum,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const char *repos_url, *start_path, *end_path;
+ apr_array_header_t *revs;
+ apr_hash_t *rev_locs;
+
+ SVN_ERR_ASSERT(peg_revnum != SVN_INVALID_REVNUM);
+ SVN_ERR_ASSERT(start_revnum != SVN_INVALID_REVNUM);
+ SVN_ERR_ASSERT(end_revnum != SVN_INVALID_REVNUM || end_url == NULL);
+
+ /* Avoid a network request in the common easy case. */
+ if (start_revnum == peg_revnum
+ && (end_revnum == peg_revnum || end_revnum == SVN_INVALID_REVNUM))
+ {
+ if (start_url)
+ *start_url = url;
+ if (end_url)
+ *end_url = url;
+ return SVN_NO_ERROR;
+ }
+
+ SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_url, scratch_pool));
+
+ revs = apr_array_make(scratch_pool, 2, sizeof(svn_revnum_t));
+ APR_ARRAY_PUSH(revs, svn_revnum_t) = start_revnum;
+ if (end_revnum != start_revnum && end_revnum != SVN_INVALID_REVNUM)
+ APR_ARRAY_PUSH(revs, svn_revnum_t) = end_revnum;
+
+ SVN_ERR(svn_ra_get_locations(ra_session, &rev_locs, "", peg_revnum,
+ revs, scratch_pool));
+
+ /* We'd better have all the paths we were looking for! */
+ if (start_url)
+ {
+ start_path = apr_hash_get(rev_locs, &start_revnum, sizeof(svn_revnum_t));
+ if (! start_path)
+ return svn_error_createf
+ (SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
+ _("Unable to find repository location for '%s' in revision %ld"),
+ url, start_revnum);
+ *start_url = svn_path_url_add_component2(repos_url, start_path + 1,
+ result_pool);
+ }
+
+ if (end_url)
+ {
+ end_path = apr_hash_get(rev_locs, &end_revnum, sizeof(svn_revnum_t));
+ if (! end_path)
+ return svn_error_createf
+ (SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
+ _("The location for '%s' for revision %ld does not exist in the "
+ "repository or refers to an unrelated object"),
+ url, end_revnum);
+
+ *end_url = svn_path_url_add_component2(repos_url, end_path + 1,
+ result_pool);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client__repos_location(const char **op_url,
+ svn_ra_session_t *ra_session,
+ const char *peg_url,
+ svn_revnum_t peg_revnum,
+ svn_revnum_t op_revnum,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ SVN_ERR(repos_locations(op_url, NULL,
+ ra_session, peg_url, peg_revnum,
+ op_revnum, SVN_INVALID_REVNUM,
+ result_pool, scratch_pool));
+ return SVN_NO_ERROR;
+}
svn_error_t *
svn_client__repos_locations(const char **start_url,
- svn_opt_revision_t **start_revision,
+ svn_revnum_t *start_revision,
const char **end_url,
- svn_opt_revision_t **end_revision,
+ svn_revnum_t *end_revision,
svn_ra_session_t *ra_session,
const char *path,
const svn_opt_revision_t *revision,
@@ -597,16 +681,11 @@ svn_client__repos_locations(const char *
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
- const char *repos_url;
const char *url;
- const char *start_path = NULL;
- const char *end_path = NULL;
const char *local_abspath_or_url;
svn_revnum_t peg_revnum = SVN_INVALID_REVNUM;
svn_revnum_t start_revnum, end_revnum;
svn_revnum_t youngest_rev = SVN_INVALID_REVNUM;
- apr_array_header_t *revs;
- apr_hash_t *rev_locs;
apr_pool_t *subpool = svn_pool_create(pool);
/* Ensure that we are given some real revision data to work with.
@@ -708,99 +787,49 @@ svn_client__repos_locations(const char *
ra_session, end, pool));
/* Set the output revision variables. */
- *start_revision = apr_pcalloc(pool, sizeof(**start_revision));
- (*start_revision)->kind = svn_opt_revision_number;
- (*start_revision)->value.number = start_revnum;
- if (end->kind != svn_opt_revision_unspecified)
+ if (start_revision)
{
- *end_revision = apr_pcalloc(pool, sizeof(**end_revision));
- (*end_revision)->kind = svn_opt_revision_number;
- (*end_revision)->value.number = end_revnum;
+ *start_revision = start_revnum;
}
-
- if (start_revnum == peg_revnum && end_revnum == peg_revnum)
+ if (end_revision && end->kind != svn_opt_revision_unspecified)
{
- /* Avoid a network request in the common easy case. */
- *start_url = url;
- if (end->kind != svn_opt_revision_unspecified)
- *end_url = url;
- svn_pool_destroy(subpool);
- return SVN_NO_ERROR;
+ *end_revision = end_revnum;
}
- SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_url, subpool));
-
- revs = apr_array_make(subpool, 2, sizeof(svn_revnum_t));
- APR_ARRAY_PUSH(revs, svn_revnum_t) = start_revnum;
- if (end_revnum != start_revnum)
- APR_ARRAY_PUSH(revs, svn_revnum_t) = end_revnum;
-
- SVN_ERR(svn_ra_get_locations(ra_session, &rev_locs, "", peg_revnum,
- revs, subpool));
-
- /* We'd better have all the paths we were looking for! */
- start_path = apr_hash_get(rev_locs, &start_revnum, sizeof(svn_revnum_t));
- if (! start_path)
- return svn_error_createf
- (SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
- _("Unable to find repository location for '%s' in revision %ld"),
- path_or_url_local_style(path, pool), start_revnum);
-
- end_path = apr_hash_get(rev_locs, &end_revnum, sizeof(svn_revnum_t));
- if (! end_path)
- return svn_error_createf
- (SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
- _("The location for '%s' for revision %ld does not exist in the "
- "repository or refers to an unrelated object"),
- path_or_url_local_style(path, pool), end_revnum);
-
- /* Set our return variables */
- *start_url = svn_path_url_add_component2(repos_url, start_path + 1, pool);
- if (end->kind != svn_opt_revision_unspecified)
- *end_url = svn_path_url_add_component2(repos_url, end_path + 1, pool);
-
+ SVN_ERR(repos_locations(start_url, end_url,
+ ra_session, url, peg_revnum,
+ start_revnum, end_revnum,
+ pool, subpool));
svn_pool_destroy(subpool);
return SVN_NO_ERROR;
}
svn_error_t *
-svn_client__get_youngest_common_ancestor(const char **ancestor_path,
+svn_client__get_youngest_common_ancestor(const char **ancestor_relpath,
+ const char **ancestor_url,
svn_revnum_t *ancestor_revision,
- const char *path_or_url1,
+ const char *url1,
svn_revnum_t rev1,
- const char *path_or_url2,
+ const char *url2,
svn_revnum_t rev2,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
apr_pool_t *sesspool = svn_pool_create(pool);
- svn_ra_session_t *session1, *session2;
+ svn_ra_session_t *session;
+ const char *repos_root_url;
apr_hash_t *history1, *history2;
apr_hash_index_t *hi;
svn_revnum_t yc_revision = SVN_INVALID_REVNUM;
- const char *yc_path = NULL;
- svn_opt_revision_t revision1, revision2;
+ const char *yc_relpath = NULL;
svn_boolean_t has_rev_zero_history1;
svn_boolean_t has_rev_zero_history2;
- revision1.kind = revision2.kind = svn_opt_revision_number;
- revision1.value.number = rev1;
- revision2.value.number = rev2;
-
- /* Open RA sessions for the two locations.
- * ### TODO: As they are assumed to be in the same repository, we
- * should share a single session, tracking the two URLs separately. */
- {
- SVN_ERR(svn_client__ra_session_from_path(&session1, NULL, NULL,
- path_or_url1, NULL,
- &revision1, &revision1,
- ctx, sesspool));
- SVN_ERR(svn_client__ra_session_from_path(&session2, NULL, NULL,
- path_or_url2, NULL,
- &revision2, &revision2,
- ctx, sesspool));
- }
+ /* Open an RA session for the two locations. */
+ SVN_ERR(svn_client_open_ra_session(&session, url1, ctx, sesspool));
+ SVN_ERR(svn_ra_get_repos_root2(session, &repos_root_url, pool));
+
/* We're going to cheat and use history-as-mergeinfo because it
saves us a bunch of annoying custom data comparisons and such. */
SVN_ERR(svn_client__get_history_as_mergeinfo(&history1,
@@ -808,13 +837,14 @@ svn_client__get_youngest_common_ancestor
rev1,
SVN_INVALID_REVNUM,
SVN_INVALID_REVNUM,
- session1, ctx, pool));
+ session, ctx, pool));
+ SVN_ERR(svn_ra_reparent(session, url2, pool));
SVN_ERR(svn_client__get_history_as_mergeinfo(&history2,
&has_rev_zero_history2,
rev2,
SVN_INVALID_REVNUM,
SVN_INVALID_REVNUM,
- session2, ctx, pool));
+ session, ctx, pool));
/* Close the source and target sessions. */
svn_pool_destroy(sesspool);
@@ -843,7 +873,7 @@ svn_client__get_youngest_common_ancestor
|| (yc_range->end > yc_revision))
{
yc_revision = yc_range->end;
- yc_path = path + 1;
+ yc_relpath = path + 1;
}
}
}
@@ -851,13 +881,52 @@ svn_client__get_youngest_common_ancestor
/* It's possible that PATH_OR_URL1 and PATH_OR_URL2's only common
history is revision 0. */
- if (!yc_path && has_rev_zero_history1 && has_rev_zero_history2)
+ if (!yc_relpath && has_rev_zero_history1 && has_rev_zero_history2)
{
- yc_path = "/";
+ yc_relpath = "";
yc_revision = 0;
}
- *ancestor_path = yc_path;
- *ancestor_revision = yc_revision;
+ if (ancestor_relpath)
+ *ancestor_relpath = yc_relpath;
+ if (ancestor_url)
+ *ancestor_url
+ = yc_relpath ? svn_path_url_add_component2(repos_root_url, yc_relpath,
+ pool) : NULL;
+ if (ancestor_revision)
+ *ancestor_revision = yc_revision;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client__youngest_common_ancestor(const char **ancestor_url,
+ svn_revnum_t *ancestor_rev,
+ const char *path_or_url1,
+ const svn_opt_revision_t *revision1,
+ const char *path_or_url2,
+ const svn_opt_revision_t *revision2,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *sesspool = svn_pool_create(scratch_pool);
+ svn_ra_session_t *session;
+ const char *url1, *url2;
+ svn_revnum_t rev1, rev2;
+
+ /* Resolve the two locations */
+ SVN_ERR(svn_client__ra_session_from_path(&session, &rev1, &url1,
+ path_or_url1, NULL,
+ revision1, revision1,
+ ctx, sesspool));
+ SVN_ERR(resolve_rev_and_url(&rev2, &url2, session,
+ path_or_url2, revision2, revision2,
+ ctx, scratch_pool));
+
+ SVN_ERR(svn_client__get_youngest_common_ancestor(
+ NULL, ancestor_url, ancestor_rev,
+ url1, rev1, url2, rev2, ctx, result_pool));
+
+ svn_pool_destroy(sesspool);
return SVN_NO_ERROR;
}
Modified: subversion/branches/file-handle-cache/subversion/libsvn_client/switch.c
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/libsvn_client/switch.c?rev=1220465&r1=1220464&r2=1220465&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/libsvn_client/switch.c (original)
+++ subversion/branches/file-handle-cache/subversion/libsvn_client/switch.c Sun Dec 18 17:36:24 2011
@@ -197,7 +197,7 @@ switch_internal(svn_revnum_t *result_rev
### okay? */
if (! ignore_ancestry)
{
- const char *target_url, *yc_path;
+ const char *target_url, *yc_url;
svn_revnum_t target_rev, yc_rev;
SVN_ERR(svn_wc__node_get_url(&target_url, ctx->wc_ctx, local_abspath,
@@ -206,11 +206,11 @@ switch_internal(svn_revnum_t *result_rev
local_abspath, pool));
/* ### It would be nice if this function could reuse the existing
ra session instead of opening two for its own use. */
- SVN_ERR(svn_client__get_youngest_common_ancestor(&yc_path, &yc_rev,
+ SVN_ERR(svn_client__get_youngest_common_ancestor(NULL, &yc_url, &yc_rev,
switch_rev_url, revnum,
target_url, target_rev,
ctx, pool));
- if (! (yc_path && SVN_IS_VALID_REVNUM(yc_rev)))
+ if (! (yc_url && SVN_IS_VALID_REVNUM(yc_rev)))
return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
_("'%s' shares no common ancestry with '%s'"),
switch_url, local_abspath);
Modified: subversion/branches/file-handle-cache/subversion/libsvn_client/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/file-handle-cache/subversion/libsvn_client/util.c?rev=1220465&r1=1220464&r2=1220465&view=diff
==============================================================================
--- subversion/branches/file-handle-cache/subversion/libsvn_client/util.c (original)
+++ subversion/branches/file-handle-cache/subversion/libsvn_client/util.c Sun Dec 18 17:36:24 2011
@@ -102,17 +102,15 @@ svn_client__path_relative_to_root(const
SVN_ERR_ASSERT(repos_relpath != NULL);
}
- /* Merge handling passes a root that is not the repos root */
else if (repos_root != NULL)
{
- if (!svn_uri__is_ancestor(repos_root, abspath_or_url))
+ repos_relpath = svn_uri_skip_ancestor(repos_root, abspath_or_url,
+ result_pool);
+ if (!repos_relpath)
return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
_("URL '%s' is not a child of repository "
"root URL '%s'"),
abspath_or_url, repos_root);
-
- repos_relpath = svn_uri_skip_ancestor(repos_root, abspath_or_url,
- result_pool);
}
else
{