diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-08-05 16:22:51 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-08-05 16:22:51 +0000 |
commit | cf46733632c7279a9fd0fe6ce26f9185a4ae82a9 (patch) | |
tree | da27775a2161723ef342e91af41a8b51fedef405 /subversion/libsvn_client/update.c | |
parent | bb0ef45f7c46b0ae221b26265ef98a768c33f820 (diff) | |
download | subversion-tarball-master.tar.gz |
subversion-1.9.7HEADsubversion-1.9.7master
Diffstat (limited to 'subversion/libsvn_client/update.c')
-rw-r--r-- | subversion/libsvn_client/update.c | 168 |
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; |