You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2012/04/23 14:33:03 UTC
svn commit: r1329209 [10/38] - in /subversion/branches/javahl-ra: ./ build/
build/ac-macros/ build/generator/ build/generator/templates/ build/win32/
contrib/client-side/emacs/ contrib/client-side/vim/
contrib/server-side/mod_dontdothat/ notes/ notes/a...
Modified: subversion/branches/javahl-ra/subversion/libsvn_client/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/mergeinfo.c?rev=1329209&r1=1329208&r2=1329209&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/mergeinfo.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/mergeinfo.c Mon Apr 23 12:32:48 2012
@@ -38,10 +38,12 @@
#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"
#include "private/svn_fspath.h"
+#include "private/svn_client_private.h"
#include "client.h"
#include "mergeinfo.h"
#include "svn_private_config.h"
@@ -67,6 +69,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 +148,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 +211,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)
@@ -238,7 +294,7 @@ svn_client__get_wc_mergeinfo(svn_mergein
scratch_pool));
/* Look in LOCAL_ABSPATH's parent for inherited mergeinfo if
- LOCAL_ABSPATH's has no base revision because it is an uncommitted
+ LOCAL_ABSPATH has no base revision because it is an uncommitted
addition, or if its base revision falls within the inclusive
range of its parent's last changed revision to the parent's base
revision; otherwise stop looking for inherited mergeinfo. */
@@ -258,7 +314,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 +322,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 +331,7 @@ svn_client__get_wc_mergeinfo(svn_mergein
}
else
{
- *inherited = FALSE;
+ inherited = FALSE;
*mergeinfo = NULL;
}
}
@@ -285,7 +341,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 +350,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,7 +383,8 @@ svn_client__get_wc_mergeinfo_catalog(svn
{
if (walked_path)
*walked_path = "";
- *inherited = FALSE;
+ if (inherited)
+ *inherited = FALSE;
return SVN_NO_ERROR;
}
@@ -405,7 +465,7 @@ svn_client__get_wc_mergeinfo_catalog(svn
svn_error_t *
svn_client__get_repos_mergeinfo(svn_mergeinfo_t *target_mergeinfo,
svn_ra_session_t *ra_session,
- const char *rel_path,
+ const char *url,
svn_revnum_t rev,
svn_mergeinfo_inheritance_t inherit,
svn_boolean_t squelch_incapable,
@@ -417,7 +477,7 @@ svn_client__get_repos_mergeinfo(svn_merg
SVN_ERR(svn_client__get_repos_mergeinfo_catalog(&tgt_mergeinfo_cat,
ra_session,
- rel_path, rev, inherit,
+ url, rev, inherit,
squelch_incapable, FALSE,
pool, pool));
@@ -437,7 +497,7 @@ svn_client__get_repos_mergeinfo(svn_merg
svn_error_t *
svn_client__get_repos_mergeinfo_catalog(svn_mergeinfo_catalog_t *mergeinfo_cat,
svn_ra_session_t *ra_session,
- const char *rel_path,
+ const char *url,
svn_revnum_t rev,
svn_mergeinfo_inheritance_t inherit,
svn_boolean_t squelch_incapable,
@@ -448,13 +508,18 @@ svn_client__get_repos_mergeinfo_catalog(
svn_error_t *err;
svn_mergeinfo_t repos_mergeinfo_cat;
apr_array_header_t *rel_paths = apr_array_make(scratch_pool, 1,
- sizeof(rel_path));
+ sizeof(const char *));
+ const char *old_session_url;
- APR_ARRAY_PUSH(rel_paths, const char *) = rel_path;
+ APR_ARRAY_PUSH(rel_paths, const char *) = "";
/* Fetch the mergeinfo. */
+ SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url,
+ ra_session, url, scratch_pool));
err = svn_ra_get_mergeinfo(ra_session, &repos_mergeinfo_cat, rel_paths,
rev, inherit, include_descendants, result_pool);
+ err = svn_error_compose_create(
+ err, svn_ra_reparent(ra_session, old_session_url, scratch_pool));
if (err)
{
if (squelch_incapable && err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE)
@@ -474,11 +539,9 @@ svn_client__get_repos_mergeinfo_catalog(
else
{
const char *session_relpath;
- const char *session_url;
- SVN_ERR(svn_ra_get_session_url(ra_session, &session_url, scratch_pool));
SVN_ERR(svn_ra_get_path_relative_to_root(ra_session, &session_relpath,
- session_url, scratch_pool));
+ url, scratch_pool));
if (session_relpath[0] == '\0')
*mergeinfo_cat = repos_mergeinfo_cat;
@@ -534,7 +597,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,
@@ -565,7 +628,7 @@ svn_client__get_wc_or_repos_mergeinfo_ca
a URL and without that we cannot get accurate mergeinfo for
TARGET_WCPATH. */
SVN_ERR(svn_wc__node_get_origin(NULL, &target_rev, &repos_relpath,
- &repos_root, NULL,
+ &repos_root, NULL, NULL,
ctx->wc_ctx, local_abspath, FALSE,
scratch_pool, scratch_pool));
@@ -576,8 +639,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 +650,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
@@ -620,16 +686,9 @@ svn_client__get_wc_or_repos_mergeinfo_ca
if (!apr_hash_get(original_props, SVN_PROP_MERGEINFO,
APR_HASH_KEY_STRING))
{
- const char *session_url = NULL;
apr_pool_t *sesspool = NULL;
- if (ra_session)
- {
- SVN_ERR(svn_client__ensure_ra_session_url(&session_url,
- ra_session,
- url, result_pool));
- }
- else
+ if (! ra_session)
{
sesspool = svn_pool_create(scratch_pool);
SVN_ERR(svn_client__open_ra_session_internal(
@@ -639,7 +698,7 @@ svn_client__get_wc_or_repos_mergeinfo_ca
SVN_ERR(svn_client__get_repos_mergeinfo_catalog(
&target_mergeinfo_cat_repos, ra_session,
- "", target_rev, inherit,
+ url, target_rev, inherit,
TRUE, include_descendants,
result_pool, scratch_pool));
@@ -648,7 +707,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;
}
@@ -660,11 +720,6 @@ svn_client__get_wc_or_repos_mergeinfo_ca
{
svn_pool_destroy(sesspool);
}
- else if (session_url)
- {
- SVN_ERR(svn_ra_reparent(ra_session, session_url,
- result_pool));
- }
}
}
}
@@ -693,24 +748,26 @@ svn_client__get_wc_or_repos_mergeinfo_ca
svn_error_t *
svn_client__get_history_as_mergeinfo(svn_mergeinfo_t *mergeinfo_p,
- svn_boolean_t *has_rev_zero_history,
- svn_revnum_t peg_revnum,
- svn_revnum_t range_youngest,
- svn_revnum_t range_oldest,
- svn_ra_session_t *ra_session,
- svn_client_ctx_t *ctx,
- apr_pool_t *pool)
+ svn_boolean_t *has_rev_zero_history,
+ const svn_client__pathrev_t *pathrev,
+ svn_revnum_t range_youngest,
+ svn_revnum_t range_oldest,
+ svn_ra_session_t *ra_session,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
{
apr_array_header_t *segments;
/* Fetch the location segments for our URL@PEG_REVNUM. */
if (! SVN_IS_VALID_REVNUM(range_youngest))
- range_youngest = peg_revnum;
+ range_youngest = pathrev->rev;
if (! SVN_IS_VALID_REVNUM(range_oldest))
range_oldest = 0;
- SVN_ERR(svn_client__repos_location_segments(&segments, ra_session, "",
- peg_revnum, range_youngest,
- range_oldest, ctx, pool));
+
+ SVN_ERR(svn_client__repos_location_segments(&segments, ra_session,
+ pathrev->url, pathrev->rev,
+ range_youngest, range_oldest,
+ ctx, pool));
if (has_rev_zero_history)
{
@@ -756,7 +813,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 +838,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 +966,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 +991,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,37 +1055,27 @@ 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. */
if (!use_url)
{
- const char *repos_root_url;
- const char *repos_relpath;
- const char *origin_url = NULL;
+ svn_client__pathrev_t *origin;
SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url,
scratch_pool));
- SVN_ERR(svn_wc__node_get_origin(NULL, &rev, &repos_relpath,
- &repos_root_url, NULL,
- ctx->wc_ctx, local_abspath, FALSE,
- scratch_pool, scratch_pool));
-
- if(repos_relpath)
- origin_url = svn_path_url_add_component2(repos_root_url, repos_relpath,
- scratch_pool);
-
- if (!origin_url
- || strcmp(origin_url, url) != 0
+ SVN_ERR(svn_client__wc_node_get_origin(&origin, local_abspath, ctx,
+ scratch_pool, scratch_pool));
+ rev = origin ? origin->rev : SVN_INVALID_REVNUM;
+ if (!origin
+ || strcmp(origin->url, url) != 0
|| peg_rev != rev)
{
- use_url = TRUE; /* Don't rely on local merginfo */
+ use_url = TRUE; /* Don't rely on local mergeinfo */
}
}
@@ -1044,17 +1089,15 @@ get_mergeinfo(svn_mergeinfo_catalog_t *m
{
rev = peg_rev;
SVN_ERR(svn_client__get_repos_mergeinfo_catalog(
- mergeinfo_catalog, ra_session, "", rev, svn_mergeinfo_inherited,
+ mergeinfo_catalog, ra_session, url, rev, svn_mergeinfo_inherited,
FALSE, include_descendants,
result_pool, scratch_pool));
}
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 +1107,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)
+svn_error_t *
+svn_client__elide_mergeinfo_catalog(svn_mergeinfo_catalog_t mergeinfo_catalog,
+ apr_pool_t *scratch_pool)
{
- 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;
-};
+ 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;
-/* 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)
-{
- 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;
+ /* 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;
- /* 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;
+ if (dir_stack->nelts > 0)
+ {
+ const char *top;
+ const char *path_suffix;
+ svn_boolean_t elides = FALSE;
- path_suffix = svn_dirent_is_child(pb->inherited_mergeinfo_path,
- path, NULL);
- SVN_ERR_ASSERT(path_suffix != NULL);
+ 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 +1332,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 +1349,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 +1425,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 +1449,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,
+ so 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 +1520,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 +1568,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,
@@ -1648,7 +1638,6 @@ svn_client_mergeinfo_log(svn_boolean_t f
apr_pool_t *scratch_pool)
{
apr_pool_t *sesspool = svn_pool_create(scratch_pool);
- svn_ra_session_t *source_session, *target_session;
const char *log_target = NULL;
const char *repos_root;
const char *target_repos_rel;
@@ -1724,38 +1713,32 @@ svn_client_mergeinfo_log(svn_boolean_t f
* should share a single session, tracking the two URLs separately. */
if (!finding_merged)
{
- svn_revnum_t target_peg_revnum;
+ svn_ra_session_t *target_session;
+ svn_client__pathrev_t *pathrev;
- SVN_ERR(svn_client__ra_session_from_path(&target_session,
- &target_peg_revnum, NULL,
- target_path_or_url, NULL,
- target_peg_revision,
- target_peg_revision,
- ctx, sesspool));
-
- SVN_ERR(svn_client__get_history_as_mergeinfo(&target_history, NULL,
- target_peg_revnum,
- SVN_INVALID_REVNUM,
- SVN_INVALID_REVNUM,
- target_session, ctx,
- scratch_pool));
+ SVN_ERR(svn_client__ra_session_from_path2(
+ &target_session, &pathrev,
+ target_path_or_url, NULL,
+ target_peg_revision, target_peg_revision,
+ ctx, sesspool));
+ SVN_ERR(svn_client__get_history_as_mergeinfo(
+ &target_history, NULL,
+ pathrev, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
+ target_session, ctx, scratch_pool));
}
{
- svn_revnum_t source_peg_revnum;
+ svn_ra_session_t *source_session;
+ svn_client__pathrev_t *pathrev;
- SVN_ERR(svn_client__ra_session_from_path(&source_session,
- &source_peg_revnum, NULL,
- source_path_or_url, NULL,
- source_peg_revision,
- source_peg_revision,
- ctx, sesspool));
-
- SVN_ERR(svn_client__get_history_as_mergeinfo(&source_history, NULL,
- source_peg_revnum,
- SVN_INVALID_REVNUM,
- SVN_INVALID_REVNUM,
- source_session, ctx,
- scratch_pool));
+ SVN_ERR(svn_client__ra_session_from_path2(
+ &source_session, &pathrev,
+ source_path_or_url, NULL,
+ source_peg_revision, source_peg_revision,
+ ctx, sesspool));
+ SVN_ERR(svn_client__get_history_as_mergeinfo(
+ &source_history, NULL,
+ pathrev, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
+ source_session, ctx, scratch_pool));
}
/* Close the source and target sessions. */
svn_pool_destroy(sesspool);
@@ -1883,7 +1866,7 @@ svn_client_mergeinfo_log(svn_boolean_t f
else
{
/* Map SUBTREE_PATH to an empty rangelist if there was nothing
- fully merged. e.g. Only empty or non-inheritable mergienfo
+ fully merged. e.g. Only empty or non-inheritable mergeinfo
on the subtree or mergeinfo unrelated to the source. */
apr_hash_set(inheritable_subtree_merges, subtree_path,
APR_HASH_KEY_STRING,
Modified: subversion/branches/javahl-ra/subversion/libsvn_client/mergeinfo.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/mergeinfo.h?rev=1329209&r1=1329208&r2=1329209&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/mergeinfo.h (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/mergeinfo.h Mon Apr 23 12:32:48 2012
@@ -26,6 +26,7 @@
#include "svn_wc.h"
#include "svn_client.h"
+#include "private/svn_client_private.h"
/*** Data Structures ***/
@@ -40,7 +41,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 +82,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 +96,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
@@ -153,37 +171,40 @@ svn_client__get_wc_mergeinfo_catalog(svn
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
-/* Obtain any mergeinfo for repository filesystem path REL_PATH
- (relative to RA_SESSION's session URL) from the repository, and set
+/* Obtain any mergeinfo for URL from the repository, and set
it in *TARGET_MERGEINFO.
INHERIT indicates whether explicit, explicit or inherited, or only
- inherited mergeinfo for REL_PATH is obtained.
+ inherited mergeinfo for URL is obtained.
- If REL_PATH does not exist at REV, SVN_ERR_FS_NOT_FOUND or
+ If URL does not exist at REV, SVN_ERR_FS_NOT_FOUND or
SVN_ERR_RA_DAV_REQUEST_FAILED is returned and *TARGET_MERGEINFO
is untouched.
- If there is no mergeinfo available for REL_PATH, or if the server
+ If there is no mergeinfo available for URL, or if the server
doesn't support a mergeinfo capability and SQUELCH_INCAPABLE is
TRUE, set *TARGET_MERGEINFO to NULL. If the server doesn't support
a mergeinfo capability and SQUELCH_INCAPABLE is FALSE, return an
- SVN_ERR_UNSUPPORTED_FEATURE error. */
+ SVN_ERR_UNSUPPORTED_FEATURE error.
+
+ RA_SESSION is an open RA session to the repository in which URL lives;
+ it may be temporarily reparented by this function.
+*/
svn_error_t *
svn_client__get_repos_mergeinfo(svn_mergeinfo_t *target_mergeinfo,
svn_ra_session_t *ra_session,
- const char *rel_path,
+ const char *url,
svn_revnum_t rev,
svn_mergeinfo_inheritance_t inherit,
svn_boolean_t squelch_incapable,
apr_pool_t *pool);
/* If INCLUDE_DESCENDANTS is FALSE, behave exactly like
- svn_client__get_repos_mergeinfo() except the mergeinfo for REL_PATH
+ svn_client__get_repos_mergeinfo() except the mergeinfo for URL
is put in the mergeinfo catalog MERGEINFO_CAT, with the key being
- the repository root-relative path of REL_PATH.
+ the repository root-relative path of URL.
- If INCLUDE_DESCENDANTS is true, then any subtrees under REL_PATH
+ If INCLUDE_DESCENDANTS is true, then any subtrees under URL
with explicit mergeinfo are also included in MERGEINFO_CAT. The
keys for the subtree mergeinfo are the repository root-relative
paths of the subtrees. If no mergeinfo is found, then
@@ -191,7 +212,7 @@ svn_client__get_repos_mergeinfo(svn_merg
svn_error_t *
svn_client__get_repos_mergeinfo_catalog(svn_mergeinfo_catalog_t *mergeinfo_cat,
svn_ra_session_t *ra_session,
- const char *rel_path,
+ const char *url,
svn_revnum_t rev,
svn_mergeinfo_inheritance_t inherit,
svn_boolean_t squelch_incapable,
@@ -226,7 +247,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,
@@ -269,7 +290,7 @@ svn_client__get_wc_or_repos_mergeinfo_ca
apr_pool_t *scratch_pool);
/* Set *MERGEINFO_P to a mergeinfo constructed solely from the
- natural history of RA_SESSION's session URL at PEG_REVNUM.
+ natural history of PATHREV.
If RANGE_YOUNGEST and RANGE_OLDEST are valid, use them to bound the
revision ranges of returned mergeinfo. They are governed by the same
@@ -277,11 +298,15 @@ svn_client__get_wc_or_repos_mergeinfo_ca
svn_ra_get_location_segments().
If HAS_REV_ZERO_HISTORY is not NULL, then set *HAS_REV_ZERO_HISTORY to
- TRUE if the natural history includes revision 0, else to FALSE. */
+ TRUE if the natural history includes revision 0, else to FALSE.
+
+ RA_SESSION is an open RA session to the repository in which URL lives;
+ it may be temporarily reparented by this function.
+*/
svn_error_t *
svn_client__get_history_as_mergeinfo(svn_mergeinfo_t *mergeinfo_p,
svn_boolean_t *has_rev_zero_history,
- svn_revnum_t peg_revnum,
+ const svn_client__pathrev_t *pathrev,
svn_revnum_t range_youngest,
svn_revnum_t range_oldest,
svn_ra_session_t *ra_session,
@@ -313,6 +338,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 +384,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/javahl-ra/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/patch.c?rev=1329209&r1=1329208&r2=1329209&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/patch.c Mon Apr 23 12:32:48 2012
@@ -1699,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;
@@ -2718,7 +2718,7 @@ delete_empty_dirs(apr_array_header_t *ta
empty_dirs = apr_hash_make(scratch_pool);
non_empty_dirs = apr_hash_make(scratch_pool);
iterpool = svn_pool_create(scratch_pool);
- for (i = 0; i < targets_info->nelts; i++)
+ for (i = 0; i < deleted_targets->nelts; i++)
{
svn_boolean_t parent_empty;
patch_target_info_t *target_info;
@@ -2729,7 +2729,7 @@ delete_empty_dirs(apr_array_header_t *ta
if (ctx->cancel_func)
SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
- target_info = APR_ARRAY_IDX(targets_info, i, patch_target_info_t *);
+ target_info = APR_ARRAY_IDX(deleted_targets, i, patch_target_info_t *);
parent = svn_dirent_dirname(target_info->local_abspath, iterpool);
@@ -2833,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,
@@ -2890,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)
{
@@ -2925,27 +2905,23 @@ apply_patches(void *baton,
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);
@@ -2966,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)
@@ -3003,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/javahl-ra/subversion/libsvn_client/prop_commands.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/prop_commands.c?rev=1329209&r1=1329208&r2=1329209&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/prop_commands.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/prop_commands.c Mon Apr 23 12:32:48 2012
@@ -41,6 +41,7 @@
#include "svn_private_config.h"
#include "private/svn_wc_private.h"
+#include "private/svn_ra_private.h"
#include "private/svn_client_private.h"
@@ -74,7 +75,7 @@ is_revision_prop_name(const char *name)
static svn_error_t *
error_if_wcprop_name(const char *name)
{
- if (svn_property_kind(NULL, name) == svn_prop_wc_kind)
+ if (svn_property_kind2(name) == svn_prop_wc_kind)
{
return svn_error_createf
(SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
@@ -117,7 +118,8 @@ get_file_for_validation(const svn_string
static
svn_error_t *
-do_url_propset(const char *propname,
+do_url_propset(const char *url,
+ const char *propname,
const svn_string_t *propval,
const svn_node_kind_t kind,
const svn_revnum_t base_revision_for_url,
@@ -133,8 +135,10 @@ do_url_propset(const char *propname,
if (kind == svn_node_file)
{
void *file_baton;
- SVN_ERR(editor->open_file("", root_baton, base_revision_for_url,
- pool, &file_baton));
+ const char *uri_basename = svn_uri_basename(url, pool);
+
+ SVN_ERR(editor->open_file(uri_basename, root_baton,
+ base_revision_for_url, pool, &file_baton));
SVN_ERR(editor->change_file_prop(file_baton, propname, propval, pool));
SVN_ERR(editor->close_file(file_baton, NULL, pool));
}
@@ -158,7 +162,7 @@ propset_on_url(const char *propname,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
- enum svn_prop_kind prop_kind = svn_property_kind(NULL, propname);
+ enum svn_prop_kind prop_kind = svn_property_kind2(propname);
svn_ra_session_t *ra_session;
svn_node_kind_t node_kind;
const char *message;
@@ -186,6 +190,18 @@ propset_on_url(const char *propname,
_("Path '%s' does not exist in revision %ld"),
target, base_revision_for_url);
+ if (node_kind == svn_node_file)
+ {
+ /* We need to reparent our session one directory up, since editor
+ semantics require the root is a directory.
+
+ ### How does this interact with authz? */
+ const char *parent_url;
+ parent_url = svn_uri_dirname(target, pool);
+
+ SVN_ERR(svn_ra_reparent(ra_session, parent_url, pool));
+ }
+
/* Setting an inappropriate property is not allowed (unless
overridden by 'skip_checks', in some circumstances). Deleting an
inappropriate property is allowed, however, since older clients
@@ -227,6 +243,9 @@ propset_on_url(const char *propname,
message, ctx, pool));
/* Fetch RA commit editor. */
+ SVN_ERR(svn_ra__register_editor_shim_callbacks(ra_session,
+ svn_client__get_shim_callbacks(ctx->wc_ctx,
+ NULL, pool)));
SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
commit_revprops,
commit_callback,
@@ -234,8 +253,8 @@ propset_on_url(const char *propname,
NULL, TRUE, /* No lock tokens */
pool));
- err = do_url_propset(propname, propval, node_kind, base_revision_for_url,
- editor, edit_baton, pool);
+ err = do_url_propset(target, propname, propval, node_kind,
+ base_revision_for_url, editor, edit_baton, pool);
if (err)
{
@@ -248,37 +267,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 +330,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);
@@ -357,7 +344,7 @@ svn_client_propset_local(const char *pro
iterpool);
if ((err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
- || kind == svn_node_unknown || kind == svn_node_none)
+ || (!err && (kind == svn_node_unknown || kind == svn_node_none)))
{
if (ctx->notify_func2)
{
@@ -374,18 +361,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);
@@ -999,7 +980,7 @@ remote_proplist(const char *target_prefi
svn_string_t *value = svn__apr_hash_index_val(hi);
svn_prop_kind_t prop_kind;
- prop_kind = svn_property_kind(NULL, name);
+ prop_kind = svn_property_kind2(name);
if (prop_kind == svn_prop_regular_kind)
{
Modified: subversion/branches/javahl-ra/subversion/libsvn_client/ra.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/ra.c?rev=1329209&r1=1329208&r2=1329209&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/ra.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/ra.c Mon Apr 23 12:32:48 2012
@@ -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
@@ -51,10 +52,6 @@ typedef struct callback_baton_t
this base directory. */
const char *base_dir_abspath;
- /* When true, makes sure temporary files are created
- outside the working copy. */
- svn_boolean_t read_only_wc;
-
/* An array of svn_client_commit_item3_t * structures, present only
during working copy commits. */
const apr_array_header_t *commit_items;
@@ -62,9 +59,6 @@ typedef struct callback_baton_t
/* A client context. */
svn_client_ctx_t *ctx;
- /* The pool to use for session-related items. */
- apr_pool_t *pool;
-
} callback_baton_t;
@@ -292,8 +286,6 @@ svn_client__open_ra_session_internal(svn
cbtable->get_client_string = get_client_string;
cb->base_dir_abspath = base_dir_abspath;
- cb->read_only_wc = read_only_wc;
- cb->pool = pool;
cb->commit_items = commit_items;
cb->ctx = ctx;
@@ -387,17 +379,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,20 +387,22 @@ 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.
-
- 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.
+ 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 location of the object in *RESOLVED_LOC_P.
+
+ 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.
Use POOL for all allocations. */
static svn_error_t *
-resolve_rev_and_url(svn_revnum_t *rev_p,
- const char **url_p,
+resolve_rev_and_url(svn_client__pathrev_t **resolved_loc_p,
svn_ra_session_t *ra_session,
const char *path_or_url,
const svn_opt_revision_t *peg_revision,
@@ -432,9 +415,10 @@ resolve_rev_and_url(svn_revnum_t *rev_p,
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
@@ -443,29 +427,25 @@ resolve_rev_and_url(svn_revnum_t *rev_p,
ra_session, path_or_url, &peg_rev,
&start_rev, NULL, ctx, pool));
- if (rev_p)
- *rev_p = rev;
- if (url_p)
- *url_p = url;
-
+ SVN_ERR(svn_client__pathrev_create_with_session(resolved_loc_p,
+ ra_session, rev, url, pool));
return SVN_NO_ERROR;
}
svn_error_t *
-svn_client__ra_session_from_path(svn_ra_session_t **ra_session_p,
- svn_revnum_t *rev_p,
- const char **url_p,
- const char *path_or_url,
- const char *base_dir_abspath,
- const svn_opt_revision_t *peg_revision,
- const svn_opt_revision_t *revision,
- svn_client_ctx_t *ctx,
- apr_pool_t *pool)
+svn_client__ra_session_from_path2(svn_ra_session_t **ra_session_p,
+ svn_client__pathrev_t **resolved_loc_p,
+ const char *path_or_url,
+ const char *base_dir_abspath,
+ const svn_opt_revision_t *peg_revision,
+ const svn_opt_revision_t *revision,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
{
svn_ra_session_t *ra_session;
const char *initial_url;
const char *corrected_url;
- const char *resolved_url;
+ svn_client__pathrev_t *resolved_loc;
SVN_ERR(svn_client_url_from_path2(&initial_url, path_or_url, ctx, pool,
pool));
@@ -484,16 +464,41 @@ svn_client__ra_session_from_path(svn_ra_
if (corrected_url && svn_path_is_url(path_or_url))
path_or_url = corrected_url;
- SVN_ERR(resolve_rev_and_url(rev_p, &resolved_url, ra_session,
+ SVN_ERR(resolve_rev_and_url(&resolved_loc, ra_session,
path_or_url, peg_revision, revision,
ctx, pool));
/* Make the session point to the real URL. */
- SVN_ERR(svn_ra_reparent(ra_session, resolved_url, pool));
+ SVN_ERR(svn_ra_reparent(ra_session, resolved_loc->url, pool));
*ra_session_p = ra_session;
+ if (resolved_loc_p)
+ *resolved_loc_p = resolved_loc;
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client__ra_session_from_path(svn_ra_session_t **ra_session_p,
+ svn_revnum_t *rev_p,
+ const char **url_p,
+ const char *path_or_url,
+ const char *base_dir_abspath,
+ const svn_opt_revision_t *peg_revision,
+ const svn_opt_revision_t *revision,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ svn_client__pathrev_t *resolved_loc;
+
+ SVN_ERR(svn_client__ra_session_from_path2(ra_session_p, &resolved_loc,
+ path_or_url, base_dir_abspath,
+ peg_revision, revision,
+ ctx, pool));
+ if (rev_p)
+ *rev_p = resolved_loc->rev;
if (url_p)
- *url_p = resolved_url;
+ *url_p = resolved_loc->url;
return SVN_NO_ERROR;
}
@@ -505,7 +510,6 @@ svn_client__ensure_ra_session_url(const
const char *session_url,
apr_pool_t *pool)
{
- *old_session_url = NULL;
SVN_ERR(svn_ra_get_session_url(ra_session, old_session_url, pool));
if (! session_url)
SVN_ERR(svn_ra_get_repos_root2(ra_session, &session_url, pool));
@@ -556,7 +560,7 @@ compare_segments(const void *a, const vo
svn_error_t *
svn_client__repos_location_segments(apr_array_header_t **segments,
svn_ra_session_t *ra_session,
- const char *path,
+ const char *url,
svn_revnum_t peg_revision,
svn_revnum_t start_revision,
svn_revnum_t end_revision,
@@ -564,19 +568,129 @@ svn_client__repos_location_segments(apr_
apr_pool_t *pool)
{
struct gls_receiver_baton_t gls_receiver_baton;
+ const char *old_session_url;
+
*segments = apr_array_make(pool, 8, sizeof(svn_location_segment_t *));
gls_receiver_baton.segments = *segments;
gls_receiver_baton.ctx = ctx;
gls_receiver_baton.pool = pool;
- SVN_ERR(svn_ra_get_location_segments(ra_session, path, peg_revision,
+ SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url, ra_session,
+ url, pool));
+ SVN_ERR(svn_ra_get_location_segments(ra_session, "", peg_revision,
start_revision, end_revision,
gls_receiver, &gls_receiver_baton,
pool));
+ SVN_ERR(svn_ra_reparent(ra_session, old_session_url, pool));
qsort((*segments)->elts, (*segments)->nelts,
(*segments)->elt_size, compare_segments);
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 an open RA session parented at URL.
+ */
+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 = apr_pstrdup(result_pool, url);
+ if (end_url)
+ *end_url = apr_pstrdup(result_pool, 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(svn_client__pathrev_t **op_loc_p,
+ svn_ra_session_t *ra_session,
+ const svn_client__pathrev_t *peg_loc,
+ svn_revnum_t op_revnum,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const char *old_session_url;
+ const char *op_url;
+
+ SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url, ra_session,
+ peg_loc->url, scratch_pool));
+ SVN_ERR(repos_locations(&op_url, NULL, ra_session,
+ peg_loc->url, peg_loc->rev,
+ op_revnum, SVN_INVALID_REVNUM,
+ result_pool, scratch_pool));
+ SVN_ERR(svn_ra_reparent(ra_session, old_session_url, scratch_pool));
+
+ *op_loc_p = svn_client__pathrev_create(peg_loc->repos_root_url,
+ peg_loc->repos_uuid,
+ op_revnum, op_url, result_pool);
+ return SVN_NO_ERROR;
+}
svn_error_t *
svn_client__repos_locations(const char **start_url,
@@ -591,16 +705,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.
@@ -632,7 +741,7 @@ svn_client__repos_locations(const char *
svn_boolean_t is_copy;
SVN_ERR(svn_wc__node_get_origin(&is_copy, &peg_revnum, &repos_relpath,
- &repos_root_url, NULL,
+ &repos_root_url, NULL, NULL,
ctx->wc_ctx, local_abspath_or_url,
FALSE, subpool, subpool));
@@ -711,110 +820,62 @@ svn_client__repos_locations(const char *
*end_revision = end_revnum;
}
- if (start_revnum == peg_revnum && end_revnum == peg_revnum)
- {
- /* 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;
- }
-
- 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_revnum_t *ancestor_revision,
- const char *path_or_url1,
- svn_revnum_t rev1,
- const char *path_or_url2,
- svn_revnum_t rev2,
+svn_client__get_youngest_common_ancestor(svn_client__pathrev_t **ancestor_p,
+ const svn_client__pathrev_t *loc1,
+ const svn_client__pathrev_t *loc2,
svn_client_ctx_t *ctx,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- apr_pool_t *sesspool = svn_pool_create(pool);
- svn_ra_session_t *session1, *session2;
+ apr_pool_t *sesspool = svn_pool_create(scratch_pool);
+ svn_ra_session_t *session;
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));
- }
+ if (strcmp(loc1->repos_root_url, loc2->repos_root_url) != 0)
+ {
+ *ancestor_p = NULL;
+ return SVN_NO_ERROR;
+ }
+
+ /* Open an RA session for the two locations. */
+ SVN_ERR(svn_client_open_ra_session(&session, loc1->url, ctx, sesspool));
+
/* 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,
&has_rev_zero_history1,
- rev1,
+ loc1,
SVN_INVALID_REVNUM,
SVN_INVALID_REVNUM,
- session1, ctx, pool));
+ session, ctx, scratch_pool));
SVN_ERR(svn_client__get_history_as_mergeinfo(&history2,
&has_rev_zero_history2,
- rev2,
+ loc2,
SVN_INVALID_REVNUM,
SVN_INVALID_REVNUM,
- session2, ctx, pool));
+ session, ctx, scratch_pool));
/* Close the source and target sessions. */
svn_pool_destroy(sesspool);
/* Loop through the first location's history, check for overlapping
paths and ranges in the second location's history, and
remembering the youngest matching location. */
- for (hi = apr_hash_first(pool, history1); hi; hi = apr_hash_next(hi))
+ for (hi = apr_hash_first(scratch_pool, history1); hi; hi = apr_hash_next(hi))
{
const char *path = svn__apr_hash_index_key(hi);
apr_ssize_t path_len = svn__apr_hash_index_klen(hi);
@@ -827,7 +888,7 @@ svn_client__get_youngest_common_ancestor
/* We have a path match. Now, did our two histories share
any revisions at that path? */
SVN_ERR(svn_rangelist_intersect(&common, ranges1, ranges2,
- TRUE, pool));
+ TRUE, scratch_pool));
if (common->nelts)
{
svn_merge_range_t *yc_range =
@@ -836,7 +897,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;
}
}
}
@@ -844,13 +905,62 @@ 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 (yc_relpath)
+ {
+ *ancestor_p = svn_client__pathrev_create_with_relpath(
+ loc1->repos_root_url, loc1->repos_uuid,
+ yc_revision, yc_relpath, result_pool);
+ }
+ else
+ {
+ *ancestor_p = NULL;
+ }
+ 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;
+ svn_client__pathrev_t *loc1, *loc2, *ancestor;
+
+ /* Resolve the two locations */
+ SVN_ERR(svn_client__ra_session_from_path2(&session, &loc1,
+ path_or_url1, NULL,
+ revision1, revision1,
+ ctx, sesspool));
+ SVN_ERR(resolve_rev_and_url(&loc2, session,
+ path_or_url2, revision2, revision2,
+ ctx, scratch_pool));
+
+ SVN_ERR(svn_client__get_youngest_common_ancestor(
+ &ancestor, loc1, loc2, ctx, result_pool, scratch_pool));
+
+ if (ancestor)
+ {
+ *ancestor_url = ancestor->url;
+ *ancestor_rev = ancestor->rev;
+ }
+ else
+ {
+ *ancestor_url = NULL;
+ *ancestor_rev = SVN_INVALID_REVNUM;
+ }
+ svn_pool_destroy(sesspool);
return SVN_NO_ERROR;
}