summaryrefslogtreecommitdiff
path: root/subversion/libsvn_client/update.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_client/update.c')
-rw-r--r--subversion/libsvn_client/update.c168
1 files changed, 114 insertions, 54 deletions
diff --git a/subversion/libsvn_client/update.c b/subversion/libsvn_client/update.c
index 0b006cc..3895aa2 100644
--- a/subversion/libsvn_client/update.c
+++ b/subversion/libsvn_client/update.c
@@ -196,10 +196,16 @@ record_conflict(svn_wc_conflict_result_t **result,
Add the paths of any conflict victims to CONFLICTED_PATHS, if that
is not null.
+
+ Use RA_SESSION_P to run the update if it is not NULL. If it is then
+ open a new ra session and place it in RA_SESSION_P. This allows
+ repeated calls to update_internal to reuse the same session.
*/
static svn_error_t *
update_internal(svn_revnum_t *result_rev,
+ svn_boolean_t *timestamp_sleep,
apr_hash_t *conflicted_paths,
+ svn_ra_session_t **ra_session_p,
const char *local_abspath,
const char *anchor_abspath,
const svn_opt_revision_t *revision,
@@ -208,10 +214,10 @@ update_internal(svn_revnum_t *result_rev,
svn_boolean_t ignore_externals,
svn_boolean_t allow_unver_obstructions,
svn_boolean_t adds_as_modification,
- svn_boolean_t *timestamp_sleep,
svn_boolean_t notify_summary,
svn_client_ctx_t *ctx,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
const svn_delta_editor_t *update_editor;
void *update_edit_baton;
@@ -229,7 +235,7 @@ update_internal(svn_revnum_t *result_rev,
const char *diff3_cmd;
apr_hash_t *wcroot_iprops;
svn_opt_revision_t opt_rev;
- svn_ra_session_t *ra_session;
+ svn_ra_session_t *ra_session = *ra_session_p;
const char *preserved_exts_str;
apr_array_header_t *preserved_exts;
struct svn_client__dirent_fetcher_baton_t dfb;
@@ -248,7 +254,7 @@ update_internal(svn_revnum_t *result_rev,
depth_is_sticky = FALSE;
if (strcmp(local_abspath, anchor_abspath))
- target = svn_dirent_basename(local_abspath, pool);
+ target = svn_dirent_basename(local_abspath, scratch_pool);
else
target = "";
@@ -256,8 +262,8 @@ update_internal(svn_revnum_t *result_rev,
SVN_ERR(svn_wc__node_get_base(NULL, NULL, &repos_relpath, &repos_root_url,
&repos_uuid, NULL,
ctx->wc_ctx, anchor_abspath,
- TRUE, FALSE,
- pool, pool));
+ TRUE /* ignore_enoent */,
+ scratch_pool, scratch_pool));
/* It does not make sense to update conflict victims. */
if (repos_relpath)
@@ -266,11 +272,11 @@ update_internal(svn_revnum_t *result_rev,
svn_boolean_t text_conflicted, prop_conflicted;
anchor_url = svn_path_url_add_component2(repos_root_url, repos_relpath,
- pool);
+ scratch_pool);
err = svn_wc_conflicted_p3(&text_conflicted, &prop_conflicted,
NULL,
- ctx->wc_ctx, local_abspath, pool);
+ ctx->wc_ctx, local_abspath, scratch_pool);
if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
return svn_error_trace(err);
@@ -293,9 +299,9 @@ update_internal(svn_revnum_t *result_rev,
target_conflicted
? svn_wc_notify_skip_conflicted
: svn_wc_notify_update_skip_working_only,
- pool);
+ scratch_pool);
- ctx->notify_func2(ctx->notify_baton2, nt, pool);
+ ctx->notify_func2(ctx->notify_baton2, nt, scratch_pool);
}
return SVN_NO_ERROR;
}
@@ -312,32 +318,33 @@ update_internal(svn_revnum_t *result_rev,
local_abspath,
ctx->cancel_func, ctx->cancel_baton,
ctx->notify_func2, ctx->notify_baton2,
- pool));
+ scratch_pool));
/* Target excluded, we are done now */
return SVN_NO_ERROR;
}
SVN_ERR(svn_wc_read_kind2(&target_kind, ctx->wc_ctx, local_abspath,
- TRUE, TRUE, pool));
+ TRUE, TRUE, scratch_pool));
if (target_kind == svn_node_dir)
{
SVN_ERR(svn_wc_crop_tree2(ctx->wc_ctx, local_abspath, depth,
ctx->cancel_func, ctx->cancel_baton,
ctx->notify_func2, ctx->notify_baton2,
- pool));
+ scratch_pool));
}
}
/* check whether the "clean c/o" optimization is applicable */
- SVN_ERR(is_empty_wc(&clean_checkout, local_abspath, anchor_abspath, pool));
+ SVN_ERR(is_empty_wc(&clean_checkout, local_abspath, anchor_abspath,
+ scratch_pool));
/* Get the external diff3, if any. */
svn_config_get(cfg, &diff3_cmd, SVN_CONFIG_SECTION_HELPERS,
SVN_CONFIG_OPTION_DIFF3_CMD, NULL);
if (diff3_cmd != NULL)
- SVN_ERR(svn_path_cstring_to_utf8(&diff3_cmd, diff3_cmd, pool));
+ SVN_ERR(svn_path_cstring_to_utf8(&diff3_cmd, diff3_cmd, scratch_pool));
/* See if the user wants last-commit timestamps instead of current ones. */
SVN_ERR(svn_config_get_bool(cfg, &use_commit_times,
@@ -349,7 +356,7 @@ update_internal(svn_revnum_t *result_rev,
svn_config_get(cfg, &preserved_exts_str, SVN_CONFIG_SECTION_MISCELLANY,
SVN_CONFIG_OPTION_PRESERVED_CF_EXTS, "");
preserved_exts = *preserved_exts_str
- ? svn_cstring_split(preserved_exts_str, "\n\r\t\v ", FALSE, pool)
+ ? svn_cstring_split(preserved_exts_str, "\n\r\t\v ", FALSE, scratch_pool)
: NULL;
/* Let everyone know we're starting a real update (unless we're
@@ -358,19 +365,52 @@ update_internal(svn_revnum_t *result_rev,
{
svn_wc_notify_t *notify
= svn_wc_create_notify(local_abspath, svn_wc_notify_update_started,
- pool);
+ scratch_pool);
notify->kind = svn_node_none;
notify->content_state = notify->prop_state
= svn_wc_notify_state_inapplicable;
notify->lock_state = svn_wc_notify_lock_state_inapplicable;
- (*ctx->notify_func2)(ctx->notify_baton2, notify, pool);
+ ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool);
}
- /* Open an RA session for the URL */
- SVN_ERR(svn_client__open_ra_session_internal(&ra_session, &corrected_url,
- anchor_url,
- anchor_abspath, NULL, TRUE,
- TRUE, ctx, pool, pool));
+ /* Try to reuse the RA session by reparenting it to the anchor_url.
+ * This code is probably overly cautious since we only use this
+ * currently when parents are missing and so all the anchor_urls
+ * have to be in the same repo. */
+ if (ra_session)
+ {
+ svn_error_t *err = svn_ra_reparent(ra_session, anchor_url, scratch_pool);
+ if (err)
+ {
+ if (err->apr_err == SVN_ERR_RA_ILLEGAL_URL)
+ {
+ /* session changed repos, can't reuse it */
+ svn_error_clear(err);
+ ra_session = NULL;
+ }
+ else
+ {
+ return svn_error_trace(err);
+ }
+ }
+ else
+ {
+ corrected_url = NULL;
+ }
+ }
+
+ /* Open an RA session for the URL if one isn't already available */
+ if (!ra_session)
+ {
+ SVN_ERR(svn_client__open_ra_session_internal(&ra_session, &corrected_url,
+ anchor_url,
+ anchor_abspath, NULL,
+ TRUE /* write_dav_props */,
+ TRUE /* read_dav_props */,
+ ctx,
+ result_pool, scratch_pool));
+ *ra_session_p = ra_session;
+ }
/* If we got a corrected URL from the RA subsystem, we'll need to
relocate our working copy first. */
@@ -380,12 +420,13 @@ update_internal(svn_revnum_t *result_rev,
/* To relocate everything inside our repository we need the old and new
repos root. */
- SVN_ERR(svn_ra_get_repos_root2(ra_session, &new_repos_root_url, pool));
+ SVN_ERR(svn_ra_get_repos_root2(ra_session, &new_repos_root_url,
+ scratch_pool));
/* svn_client_relocate2() will check the uuid */
SVN_ERR(svn_client_relocate2(anchor_abspath, repos_root_url,
new_repos_root_url, ignore_externals,
- ctx, pool));
+ ctx, scratch_pool));
/* Store updated repository root for externals */
repos_root_url = new_repos_root_url;
@@ -406,10 +447,10 @@ update_internal(svn_revnum_t *result_rev,
to take a URL as easily as a local path? */
SVN_ERR(svn_client__get_revision_number(&revnum, NULL, ctx->wc_ctx,
local_abspath, ra_session, &opt_rev,
- pool));
+ scratch_pool));
SVN_ERR(svn_ra_has_capability(ra_session, &server_supports_depth,
- SVN_RA_CAPABILITY_DEPTH, pool));
+ SVN_RA_CAPABILITY_DEPTH, scratch_pool));
dfb.ra_session = ra_session;
dfb.target_revision = revnum;
@@ -417,7 +458,7 @@ update_internal(svn_revnum_t *result_rev,
SVN_ERR(svn_client__get_inheritable_props(&wcroot_iprops, local_abspath,
revnum, depth, ra_session,
- ctx, pool, pool));
+ ctx, scratch_pool, scratch_pool));
/* Fetch the update editor. If REVISION is invalid, that's okay;
the RA driver will call editor->set_target_revision later on. */
@@ -436,7 +477,7 @@ update_internal(svn_revnum_t *result_rev,
NULL, NULL,
ctx->cancel_func, ctx->cancel_baton,
ctx->notify_func2, ctx->notify_baton2,
- pool, pool));
+ scratch_pool, scratch_pool));
/* Tell RA to do an update of URL+TARGET to REVISION; if we pass an
invalid revnum, that means RA will use the latest revision. */
@@ -447,15 +488,16 @@ update_internal(svn_revnum_t *result_rev,
: svn_depth_unknown),
FALSE /* send_copyfrom_args */,
FALSE /* ignore_ancestry */,
- update_editor, update_edit_baton, pool, pool));
+ update_editor, update_edit_baton,
+ scratch_pool, scratch_pool));
/* Past this point, we assume the WC is going to be modified so we will
* need to sleep for timestamps. */
*timestamp_sleep = TRUE;
/* Drive the reporter structure, describing the revisions within
- PATH. When we call reporter->finish_report, the
- update_editor will be driven by svn_repos_dir_delta2. */
+ LOCAL_ABSPATH. When this calls reporter->finish_report, the
+ reporter will drive the update_editor. */
SVN_ERR(svn_wc_crawl_revisions5(ctx->wc_ctx, local_abspath, reporter,
report_baton, TRUE,
depth, (! depth_is_sticky),
@@ -463,7 +505,7 @@ update_internal(svn_revnum_t *result_rev,
use_commit_times,
ctx->cancel_func, ctx->cancel_baton,
ctx->notify_func2, ctx->notify_baton2,
- pool));
+ scratch_pool));
/* We handle externals after the update is complete, so that
handling external items (and any errors therefrom) doesn't delay
@@ -476,13 +518,14 @@ update_internal(svn_revnum_t *result_rev,
SVN_ERR(svn_wc__externals_gather_definitions(&new_externals,
&new_depths,
ctx->wc_ctx, local_abspath,
- depth, pool, pool));
+ depth,
+ scratch_pool, scratch_pool));
SVN_ERR(svn_client__handle_externals(new_externals,
new_depths,
repos_root_url, local_abspath,
- depth, timestamp_sleep,
- ctx, pool));
+ depth, timestamp_sleep, ra_session,
+ ctx, scratch_pool));
}
/* Let everyone know we're finished here (unless we're asked not to). */
@@ -490,13 +533,13 @@ update_internal(svn_revnum_t *result_rev,
{
svn_wc_notify_t *notify
= svn_wc_create_notify(local_abspath, svn_wc_notify_update_completed,
- pool);
+ scratch_pool);
notify->kind = svn_node_none;
notify->content_state = notify->prop_state
= svn_wc_notify_state_inapplicable;
notify->lock_state = svn_wc_notify_lock_state_inapplicable;
notify->revision = revnum;
- (*ctx->notify_func2)(ctx->notify_baton2, notify, pool);
+ ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool);
}
/* If the caller wants the result revision, give it to them. */
@@ -508,6 +551,7 @@ update_internal(svn_revnum_t *result_rev,
svn_error_t *
svn_client__update_internal(svn_revnum_t *result_rev,
+ svn_boolean_t *timestamp_sleep,
const char *local_abspath,
const svn_opt_revision_t *revision,
svn_depth_t depth,
@@ -517,7 +561,7 @@ svn_client__update_internal(svn_revnum_t *result_rev,
svn_boolean_t adds_as_modification,
svn_boolean_t make_parents,
svn_boolean_t innerupdate,
- svn_boolean_t *timestamp_sleep,
+ svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
@@ -536,16 +580,21 @@ svn_client__update_internal(svn_revnum_t *result_rev,
const char *parent_abspath = local_abspath;
apr_array_header_t *missing_parents =
apr_array_make(pool, 4, sizeof(const char *));
+ apr_pool_t *iterpool;
+
+ iterpool = svn_pool_create(pool);
while (1)
{
+ svn_pool_clear(iterpool);
+
/* Try to lock. If we can't lock because our target (or its
parent) isn't a working copy, we'll try to walk up the
tree to find a working copy, remembering this path's
parent as one we need to flesh out. */
err = svn_wc__acquire_write_lock(&lockroot_abspath, ctx->wc_ctx,
parent_abspath, !innerupdate,
- pool, pool);
+ pool, iterpool);
if (!err)
break;
if ((err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
@@ -567,12 +616,14 @@ svn_client__update_internal(svn_revnum_t *result_rev,
const char *missing_parent =
APR_ARRAY_IDX(missing_parents, i, const char *);
- err = update_internal(result_rev, conflicted_paths,
- missing_parent, anchor_abspath,
- &peg_revision, svn_depth_empty, FALSE,
- ignore_externals, allow_unver_obstructions,
- adds_as_modification, timestamp_sleep,
- FALSE, ctx, pool);
+ svn_pool_clear(iterpool);
+
+ err = update_internal(result_rev, timestamp_sleep, conflicted_paths,
+ &ra_session, missing_parent,
+ anchor_abspath, &peg_revision, svn_depth_empty,
+ FALSE, ignore_externals,
+ allow_unver_obstructions, adds_as_modification,
+ FALSE, ctx, pool, iterpool);
if (err)
goto cleanup;
anchor_abspath = missing_parent;
@@ -583,6 +634,8 @@ svn_client__update_internal(svn_revnum_t *result_rev,
peg_revision.kind = svn_opt_revision_number;
peg_revision.value.number = *result_rev;
}
+
+ svn_pool_destroy(iterpool);
}
else
{
@@ -592,16 +645,17 @@ svn_client__update_internal(svn_revnum_t *result_rev,
anchor_abspath = lockroot_abspath;
}
- err = update_internal(result_rev, conflicted_paths,
+ err = update_internal(result_rev, timestamp_sleep, conflicted_paths,
+ &ra_session,
local_abspath, anchor_abspath,
&peg_revision, depth, depth_is_sticky,
ignore_externals, allow_unver_obstructions,
- adds_as_modification, timestamp_sleep,
- TRUE, ctx, pool);
+ adds_as_modification,
+ TRUE, ctx, pool, pool);
/* Give the conflict resolver callback the opportunity to
* resolve any conflicts that were raised. */
- if (! err && ctx->conflict_func2)
+ if (! err && ctx->conflict_func2 && apr_hash_count(conflicted_paths))
{
err = svn_client__resolve_conflicts(NULL, conflicted_paths, ctx, pool);
}
@@ -633,6 +687,7 @@ svn_client_update4(apr_array_header_t **result_revs,
const char *path = NULL;
svn_boolean_t sleep = FALSE;
svn_error_t *err = SVN_NO_ERROR;
+ svn_boolean_t found_valid_target = FALSE;
if (result_revs)
*result_revs = apr_array_make(pool, paths->nelts, sizeof(svn_revnum_t));
@@ -664,14 +719,13 @@ svn_client_update4(apr_array_header_t **result_revs,
err = svn_dirent_get_absolute(&local_abspath, path, iterpool);
if (err)
goto cleanup;
- err = svn_client__update_internal(&result_rev, local_abspath,
+ err = svn_client__update_internal(&result_rev, &sleep, local_abspath,
revision, depth, depth_is_sticky,
ignore_externals,
allow_unver_obstructions,
adds_as_modification,
make_parents,
- FALSE, &sleep,
- ctx,
+ FALSE, NULL, ctx,
iterpool);
if (err)
@@ -691,15 +745,21 @@ svn_client_update4(apr_array_header_t **result_revs,
notify = svn_wc_create_notify(path,
svn_wc_notify_skip,
iterpool);
- (*ctx->notify_func2)(ctx->notify_baton2, notify, iterpool);
+ ctx->notify_func2(ctx->notify_baton2, notify, iterpool);
}
}
+ else
+ found_valid_target = TRUE;
+
if (result_revs)
APR_ARRAY_PUSH(*result_revs, svn_revnum_t) = result_rev;
}
svn_pool_destroy(iterpool);
cleanup:
+ if (!err && !found_valid_target)
+ return svn_error_create(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
+ _("None of the targets are working copies"));
if (sleep)
{
const char *wcroot_abspath;