You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2013/01/06 03:33:39 UTC
svn commit: r1429457 [5/21] - in /subversion/branches/tree-read-api: ./
build/ build/ac-macros/ build/generator/templates/ build/win32/
contrib/server-side/svncutter/ doc/ subversion/bindings/cxxhl/include/
subversion/bindings/cxxhl/include/svncxxhl/ s...
Modified: subversion/branches/tree-read-api/subversion/libsvn_client/export.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_client/export.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_client/export.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_client/export.c Sun Jan 6 02:33:34 2013
@@ -43,8 +43,13 @@
#include "svn_private_config.h"
#include "private/svn_subr_private.h"
+#include "private/svn_delta_private.h"
#include "private/svn_wc_private.h"
+#ifndef ENABLE_EV2_IMPL
+#define ENABLE_EV2_IMPL 0
+#endif
+
/*** Code. ***/
@@ -859,26 +864,6 @@ close_file(void *file_baton,
}
static svn_error_t *
-fetch_kind_func(svn_kind_t *kind,
- void *baton,
- const char *path,
- svn_revnum_t base_revision,
- apr_pool_t *scratch_pool)
-{
- /* We know the root of the edit is a directory. */
- if (path[0] == '\0')
- *kind = svn_kind_dir;
-
- /* ### TODO: We could possibly fetch the kind of the object in question
- from the server with a second ra_session, but right now this
- seems to work. */
- else
- *kind = svn_kind_unknown;
-
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
fetch_props_func(apr_hash_t **props,
void *baton,
const char *path,
@@ -908,16 +893,14 @@ fetch_base_func(const char **filename,
}
static svn_error_t *
-get_editor(const svn_delta_editor_t **export_editor,
- void **edit_baton,
- struct edit_baton *eb,
- svn_client_ctx_t *ctx,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+get_editor_ev1(const svn_delta_editor_t **export_editor,
+ void **edit_baton,
+ struct edit_baton *eb,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
svn_delta_editor_t *editor = svn_delta_default_editor(result_pool);
- svn_delta_shim_callbacks_t *shim_callbacks =
- svn_delta_shim_callbacks_default(result_pool);
editor->set_target_revision = set_target_revision;
editor->open_root = open_root;
@@ -936,19 +919,453 @@ get_editor(const svn_delta_editor_t **ex
edit_baton,
result_pool));
- shim_callbacks->fetch_kind_func = fetch_kind_func;
- shim_callbacks->fetch_props_func = fetch_props_func;
- shim_callbacks->fetch_base_func = fetch_base_func;
- shim_callbacks->fetch_baton = eb;
-
- SVN_ERR(svn_editor__insert_shims(export_editor, edit_baton,
- *export_editor, *edit_baton,
- NULL, NULL, shim_callbacks,
- result_pool, scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+
+/*** The Ev2 Implementation ***/
+
+static svn_error_t *
+add_file_ev2(void *baton,
+ const char *relpath,
+ const svn_checksum_t *checksum,
+ svn_stream_t *contents,
+ apr_hash_t *props,
+ svn_revnum_t replaces_rev,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+ const char *full_path = svn_dirent_join(eb->root_path, relpath,
+ scratch_pool);
+ /* RELPATH is not canonicalized, i.e. it may still contain spaces etc.
+ * but EB->root_url is. */
+ const char *full_url = svn_path_url_add_component2(eb->root_url,
+ relpath,
+ scratch_pool);
+ const svn_string_t *val;
+ /* The four svn: properties we might actually care about. */
+ const svn_string_t *eol_style_val = NULL;
+ const svn_string_t *keywords_val = NULL;
+ const svn_string_t *executable_val = NULL;
+ svn_boolean_t special = FALSE;
+ /* Any keyword vals to be substituted */
+ const char *revision = NULL;
+ const char *author = NULL;
+ apr_time_t date = 0;
+
+ /* Look at any properties for additional information. */
+ if ( (val = apr_hash_get(props, SVN_PROP_EOL_STYLE, APR_HASH_KEY_STRING)) )
+ eol_style_val = val;
+
+ if ( !eb->ignore_keywords && (val = apr_hash_get(props, SVN_PROP_KEYWORDS,
+ APR_HASH_KEY_STRING)) )
+ keywords_val = val;
+
+ if ( (val = apr_hash_get(props, SVN_PROP_EXECUTABLE, APR_HASH_KEY_STRING)) )
+ executable_val = val;
+
+ /* Try to fill out the baton's keywords-structure too. */
+ if ( (val = apr_hash_get(props, SVN_PROP_ENTRY_COMMITTED_REV,
+ APR_HASH_KEY_STRING)) )
+ revision = val->data;
+
+ if ( (val = apr_hash_get(props, SVN_PROP_ENTRY_COMMITTED_DATE,
+ APR_HASH_KEY_STRING)) )
+ SVN_ERR(svn_time_from_cstring(&date, val->data, scratch_pool));
+
+ if ( (val = apr_hash_get(props, SVN_PROP_ENTRY_LAST_AUTHOR,
+ APR_HASH_KEY_STRING)) )
+ author = val->data;
+
+ if ( (val = apr_hash_get(props, SVN_PROP_SPECIAL, APR_HASH_KEY_STRING)) )
+ special = TRUE;
+
+ if (special)
+ {
+ svn_stream_t *tmp_stream;
+
+ SVN_ERR(svn_subst_create_specialfile(&tmp_stream, full_path,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_stream_copy3(contents, tmp_stream, eb->cancel_func,
+ eb->cancel_baton, scratch_pool));
+ }
+ else
+ {
+ svn_stream_t *tmp_stream;
+ const char *tmppath;
+
+ /* Create a temporary file in the same directory as the file. We're going
+ to rename the thing into place when we're done. */
+ SVN_ERR(svn_stream_open_unique(&tmp_stream, &tmppath,
+ svn_dirent_dirname(full_path,
+ scratch_pool),
+ svn_io_file_del_none,
+ scratch_pool, scratch_pool));
+
+ /* Possibly wrap the stream to be translated, as dictated by
+ the props. */
+ if (eol_style_val || keywords_val)
+ {
+ svn_subst_eol_style_t style;
+ const char *eol = NULL;
+ svn_boolean_t repair = FALSE;
+ apr_hash_t *final_kw = NULL;
+
+ if (eol_style_val)
+ {
+ SVN_ERR(get_eol_style(&style, &eol, eol_style_val->data,
+ eb->native_eol));
+ repair = TRUE;
+ }
+
+ if (keywords_val)
+ SVN_ERR(svn_subst_build_keywords2(&final_kw, keywords_val->data,
+ revision, full_url, date,
+ author, scratch_pool));
+
+ /* Writing through a translated stream is more efficient than
+ reading through one, so we wrap TMP_STREAM and not CONTENTS. */
+ tmp_stream = svn_subst_stream_translated(tmp_stream, eol, repair,
+ final_kw, TRUE, /* expand */
+ scratch_pool);
+ }
+
+ SVN_ERR(svn_stream_copy3(contents, tmp_stream, eb->cancel_func,
+ eb->cancel_baton, scratch_pool));
+
+ /* Move the file into place. */
+ SVN_ERR(svn_io_file_rename(tmppath, full_path, scratch_pool));
+ }
+
+ if (executable_val)
+ SVN_ERR(svn_io_set_file_executable(full_path, TRUE, FALSE, scratch_pool));
+
+ if (date && (! special))
+ SVN_ERR(svn_io_set_file_affected_time(date, full_path, scratch_pool));
+
+ if (eb->notify_func)
+ {
+ svn_wc_notify_t *notify = svn_wc_create_notify(full_path,
+ svn_wc_notify_update_add,
+ scratch_pool);
+ notify->kind = svn_node_file;
+ (*eb->notify_func)(eb->notify_baton, notify, scratch_pool);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+add_directory_ev2(void *baton,
+ const char *relpath,
+ const apr_array_header_t *children,
+ apr_hash_t *props,
+ svn_revnum_t replaces_rev,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+ svn_node_kind_t kind;
+ const char *full_path = svn_dirent_join(eb->root_path, relpath,
+ scratch_pool);
+ svn_string_t *val;
+
+ SVN_ERR(svn_io_check_path(full_path, &kind, scratch_pool));
+ if (kind == svn_node_none)
+ SVN_ERR(svn_io_dir_make(full_path, APR_OS_DEFAULT, scratch_pool));
+ else if (kind == svn_node_file)
+ return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
+ _("'%s' exists and is not a directory"),
+ svn_dirent_local_style(full_path, scratch_pool));
+ else if (! (kind == svn_node_dir && eb->force))
+ return svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
+ _("'%s' already exists"),
+ svn_dirent_local_style(full_path, scratch_pool));
+
+ if ( (val = apr_hash_get(props, SVN_PROP_EXTERNALS, APR_HASH_KEY_STRING)) )
+ SVN_ERR(add_externals(eb->externals, full_path, val));
+
+ if (eb->notify_func)
+ {
+ svn_wc_notify_t *notify = svn_wc_create_notify(full_path,
+ svn_wc_notify_update_add,
+ scratch_pool);
+ notify->kind = svn_node_dir;
+ (*eb->notify_func)(eb->notify_baton, notify, scratch_pool);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+target_revision_func(void *baton,
+ svn_revnum_t target_revision,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+
+ *eb->target_revision = target_revision;
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+get_editor_ev2(const svn_delta_editor_t **export_editor,
+ void **edit_baton,
+ struct edit_baton *eb,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_editor_t *editor;
+ struct svn_delta__extra_baton *exb = apr_pcalloc(result_pool, sizeof(*exb));
+ svn_boolean_t *found_abs_paths = apr_palloc(result_pool,
+ sizeof(*found_abs_paths));
+
+ exb->baton = eb;
+ exb->target_revision = target_revision_func;
+
+ SVN_ERR(svn_editor_create(&editor, eb, ctx->cancel_func, ctx->cancel_baton,
+ result_pool, scratch_pool));
+ SVN_ERR(svn_editor_setcb_add_directory(editor, add_directory_ev2,
+ scratch_pool));
+ SVN_ERR(svn_editor_setcb_add_file(editor, add_file_ev2, scratch_pool));
+
+ *found_abs_paths = TRUE;
+
+ SVN_ERR(svn_delta__delta_from_editor(export_editor, edit_baton,
+ editor, NULL, NULL, found_abs_paths,
+ NULL, NULL,
+ fetch_props_func, eb,
+ fetch_base_func, eb,
+ exb, result_pool));
+
+ /* Create the root of the export. */
+ SVN_ERR(open_root_internal(eb->root_path, eb->force, eb->notify_func,
+ eb->notify_baton, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+export_file_ev2(const char *from_path_or_url,
+ const char *to_path,
+ struct edit_baton *eb,
+ svn_client__pathrev_t *loc,
+ svn_ra_session_t *ra_session,
+ svn_boolean_t overwrite,
+ apr_pool_t *scratch_pool)
+{
+ svn_boolean_t from_is_url = svn_path_is_url(from_path_or_url);
+ apr_hash_t *props;
+ svn_stream_t *tmp_stream;
+ svn_node_kind_t to_kind;
+
+ if (svn_path_is_empty(to_path))
+ {
+ if (from_is_url)
+ to_path = svn_uri_basename(from_path_or_url, scratch_pool);
+ else
+ to_path = svn_dirent_basename(from_path_or_url, NULL);
+ eb->root_path = to_path;
+ }
+ else
+ {
+ SVN_ERR(append_basename_if_dir(&to_path, from_path_or_url,
+ from_is_url, scratch_pool));
+ eb->root_path = to_path;
+ }
+
+ SVN_ERR(svn_io_check_path(to_path, &to_kind, scratch_pool));
+
+ if ((to_kind == svn_node_file || to_kind == svn_node_unknown) &&
+ ! overwrite)
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("Destination file '%s' exists, and "
+ "will not be overwritten unless forced"),
+ svn_dirent_local_style(to_path, scratch_pool));
+ else if (to_kind == svn_node_dir)
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("Destination '%s' exists. Cannot "
+ "overwrite directory with non-directory"),
+ svn_dirent_local_style(to_path, scratch_pool));
+
+ tmp_stream = svn_stream_buffered(scratch_pool);
+
+ SVN_ERR(svn_ra_get_file(ra_session, "", loc->rev,
+ tmp_stream, NULL, &props, scratch_pool));
+
+ /* Since you cannot actually root an editor at a file, we manually drive
+ * a function of our editor. */
+ SVN_ERR(add_file_ev2(eb, "", NULL, tmp_stream, props, SVN_INVALID_REVNUM,
+ scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+export_file(const char *from_path_or_url,
+ const char *to_path,
+ struct edit_baton *eb,
+ svn_client__pathrev_t *loc,
+ svn_ra_session_t *ra_session,
+ svn_boolean_t overwrite,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_t *props;
+ apr_hash_index_t *hi;
+ struct file_baton *fb = apr_pcalloc(scratch_pool, sizeof(*fb));
+ svn_node_kind_t to_kind;
+ svn_boolean_t from_is_url = svn_path_is_url(from_path_or_url);
+
+ if (svn_path_is_empty(to_path))
+ {
+ if (from_is_url)
+ to_path = svn_uri_basename(from_path_or_url, scratch_pool);
+ else
+ to_path = svn_dirent_basename(from_path_or_url, NULL);
+ eb->root_path = to_path;
+ }
+ else
+ {
+ SVN_ERR(append_basename_if_dir(&to_path, from_path_or_url,
+ from_is_url, scratch_pool));
+ eb->root_path = to_path;
+ }
+
+ SVN_ERR(svn_io_check_path(to_path, &to_kind, scratch_pool));
+
+ if ((to_kind == svn_node_file || to_kind == svn_node_unknown) &&
+ ! overwrite)
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("Destination file '%s' exists, and "
+ "will not be overwritten unless forced"),
+ svn_dirent_local_style(to_path, scratch_pool));
+ else if (to_kind == svn_node_dir)
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("Destination '%s' exists. Cannot "
+ "overwrite directory with non-directory"),
+ svn_dirent_local_style(to_path, scratch_pool));
+
+ /* Since you cannot actually root an editor at a file, we
+ * manually drive a few functions of our editor. */
+
+ /* This is the equivalent of a parentless add_file(). */
+ fb->edit_baton = eb;
+ fb->path = eb->root_path;
+ fb->url = eb->root_url;
+ fb->pool = scratch_pool;
+
+ /* Copied from apply_textdelta(). */
+ SVN_ERR(svn_stream_open_unique(&fb->tmp_stream, &fb->tmppath,
+ svn_dirent_dirname(fb->path, scratch_pool),
+ svn_io_file_del_none,
+ fb->pool, fb->pool));
+
+ /* Step outside the editor-likeness for a moment, to actually talk
+ * to the repository. */
+ /* ### note: the stream will not be closed */
+ SVN_ERR(svn_ra_get_file(ra_session, "", loc->rev,
+ fb->tmp_stream,
+ NULL, &props, scratch_pool));
+
+ /* Push the props into change_file_prop(), to update the file_baton
+ * with information. */
+ for (hi = apr_hash_first(scratch_pool, props); hi; hi = apr_hash_next(hi))
+ {
+ const char *propname = svn__apr_hash_index_key(hi);
+ const svn_string_t *propval = svn__apr_hash_index_val(hi);
+
+ SVN_ERR(change_file_prop(fb, propname, propval, scratch_pool));
+ }
+
+ /* And now just use close_file() to do all the keyword and EOL
+ * work, and put the file into place. */
+ SVN_ERR(close_file(fb, NULL, scratch_pool));
- return SVN_NO_ERROR;
+ return SVN_NO_ERROR;
}
+static svn_error_t *
+export_directory(const char *from_path_or_url,
+ const char *to_path,
+ struct edit_baton *eb,
+ svn_client__pathrev_t *loc,
+ svn_ra_session_t *ra_session,
+ svn_boolean_t overwrite,
+ svn_boolean_t ignore_externals,
+ svn_boolean_t ignore_keywords,
+ svn_depth_t depth,
+ const char *native_eol,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *scratch_pool)
+{
+ void *edit_baton;
+ const svn_delta_editor_t *export_editor;
+ const svn_ra_reporter3_t *reporter;
+ void *report_baton;
+ svn_boolean_t use_sleep = FALSE;
+ svn_node_kind_t kind;
+
+ if (!ENABLE_EV2_IMPL)
+ SVN_ERR(get_editor_ev1(&export_editor, &edit_baton, eb, ctx,
+ scratch_pool, scratch_pool));
+ else
+ SVN_ERR(get_editor_ev2(&export_editor, &edit_baton, eb, ctx,
+ scratch_pool, scratch_pool));
+
+ /* Manufacture a basic 'report' to the update reporter. */
+ SVN_ERR(svn_ra_do_update2(ra_session,
+ &reporter, &report_baton,
+ loc->rev,
+ "", /* no sub-target */
+ depth,
+ FALSE, /* don't want copyfrom-args */
+ export_editor, edit_baton, scratch_pool));
+
+ SVN_ERR(reporter->set_path(report_baton, "", loc->rev,
+ /* Depth is irrelevant, as we're
+ passing start_empty=TRUE anyway. */
+ svn_depth_infinity,
+ TRUE, /* "help, my dir is empty!" */
+ NULL, scratch_pool));
+
+ SVN_ERR(reporter->finish_report(report_baton, scratch_pool));
+
+ /* Special case: Due to our sly export/checkout method of updating an
+ * empty directory, no target will have been created if the exported
+ * item is itself an empty directory (export_editor->open_root never
+ * gets called, because there are no "changes" to make to the empty
+ * dir we reported to the repository).
+ *
+ * So we just create the empty dir manually; but we do it via
+ * open_root_internal(), in order to get proper notification.
+ */
+ SVN_ERR(svn_io_check_path(to_path, &kind, scratch_pool));
+ if (kind == svn_node_none)
+ SVN_ERR(open_root_internal
+ (to_path, overwrite, ctx->notify_func2,
+ ctx->notify_baton2, scratch_pool));
+
+ if (! ignore_externals && depth == svn_depth_infinity)
+ {
+ const char *repos_root_url;
+ const char *to_abspath;
+
+ SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_url,
+ scratch_pool));
+ SVN_ERR(svn_dirent_get_absolute(&to_abspath, to_path, scratch_pool));
+ SVN_ERR(svn_client__export_externals(eb->externals,
+ from_path_or_url,
+ to_abspath, repos_root_url,
+ depth, native_eol,
+ ignore_keywords, &use_sleep,
+ ctx, scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
/*** Public Interfaces ***/
@@ -1009,135 +1426,19 @@ svn_client_export5(svn_revnum_t *result_
if (kind == svn_node_file)
{
- apr_hash_t *props;
- apr_hash_index_t *hi;
- struct file_baton *fb = apr_pcalloc(pool, sizeof(*fb));
- svn_node_kind_t to_kind;
-
- if (svn_path_is_empty(to_path))
- {
- if (from_is_url)
- to_path = svn_uri_basename(from_path_or_url, pool);
- else
- to_path = svn_dirent_basename(from_path_or_url, NULL);
- eb->root_path = to_path;
- }
+ if (!ENABLE_EV2_IMPL)
+ SVN_ERR(export_file(from_path_or_url, to_path, eb, loc, ra_session,
+ overwrite, pool));
else
- {
- SVN_ERR(append_basename_if_dir(&to_path, from_path_or_url,
- from_is_url, pool));
- eb->root_path = to_path;
- }
-
- SVN_ERR(svn_io_check_path(to_path, &to_kind, pool));
-
- if ((to_kind == svn_node_file || to_kind == svn_node_unknown) &&
- ! overwrite)
- return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
- _("Destination file '%s' exists, and "
- "will not be overwritten unless forced"),
- svn_dirent_local_style(to_path, pool));
- else if (to_kind == svn_node_dir)
- return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
- _("Destination '%s' exists. Cannot "
- "overwrite directory with non-directory"),
- svn_dirent_local_style(to_path, pool));
-
- /* Since you cannot actually root an editor at a file, we
- * manually drive a few functions of our editor. */
-
- /* This is the equivalent of a parentless add_file(). */
- fb->edit_baton = eb;
- fb->path = eb->root_path;
- fb->url = eb->root_url;
- fb->pool = pool;
-
- /* Copied from apply_textdelta(). */
- SVN_ERR(svn_stream_open_unique(&fb->tmp_stream, &fb->tmppath,
- svn_dirent_dirname(fb->path, pool),
- svn_io_file_del_none,
- fb->pool, fb->pool));
-
- /* Step outside the editor-likeness for a moment, to actually talk
- * to the repository. */
- /* ### note: the stream will not be closed */
- SVN_ERR(svn_ra_get_file(ra_session, "", loc->rev,
- fb->tmp_stream,
- NULL, &props, pool));
-
- /* Push the props into change_file_prop(), to update the file_baton
- * with information. */
- for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
- {
- const char *propname = svn__apr_hash_index_key(hi);
- const svn_string_t *propval = svn__apr_hash_index_val(hi);
-
- SVN_ERR(change_file_prop(fb, propname, propval, pool));
- }
-
- /* And now just use close_file() to do all the keyword and EOL
- * work, and put the file into place. */
- SVN_ERR(close_file(fb, NULL, pool));
+ SVN_ERR(export_file_ev2(from_path_or_url, to_path, eb, loc,
+ ra_session, overwrite, pool));
}
else if (kind == svn_node_dir)
{
- void *edit_baton;
- const svn_delta_editor_t *export_editor;
- const svn_ra_reporter3_t *reporter;
- void *report_baton;
- svn_boolean_t use_sleep = FALSE;
-
- SVN_ERR(get_editor(&export_editor, &edit_baton, eb, ctx,
- pool, pool));
-
- /* Manufacture a basic 'report' to the update reporter. */
- SVN_ERR(svn_ra_do_update2(ra_session,
- &reporter, &report_baton,
- loc->rev,
- "", /* no sub-target */
- depth,
- FALSE, /* don't want copyfrom-args */
- export_editor, edit_baton, pool));
-
- SVN_ERR(reporter->set_path(report_baton, "", loc->rev,
- /* Depth is irrelevant, as we're
- passing start_empty=TRUE anyway. */
- svn_depth_infinity,
- TRUE, /* "help, my dir is empty!" */
- NULL, pool));
-
- SVN_ERR(reporter->finish_report(report_baton, pool));
-
- /* Special case: Due to our sly export/checkout method of
- * updating an empty directory, no target will have been created
- * if the exported item is itself an empty directory
- * (export_editor->open_root never gets called, because there
- * are no "changes" to make to the empty dir we reported to the
- * repository).
- *
- * So we just create the empty dir manually; but we do it via
- * open_root_internal(), in order to get proper notification.
- */
- SVN_ERR(svn_io_check_path(to_path, &kind, pool));
- if (kind == svn_node_none)
- SVN_ERR(open_root_internal
- (to_path, overwrite, ctx->notify_func2,
- ctx->notify_baton2, pool));
-
- if (! ignore_externals && depth == svn_depth_infinity)
- {
- const char *repos_root_url;
- const char *to_abspath;
-
- SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_url, pool));
- SVN_ERR(svn_dirent_get_absolute(&to_abspath, to_path, pool));
- SVN_ERR(svn_client__export_externals(eb->externals,
- from_path_or_url,
- to_abspath, repos_root_url,
- depth, native_eol,
- ignore_keywords, &use_sleep,
- ctx, pool));
- }
+ SVN_ERR(export_directory(from_path_or_url, to_path,
+ eb, loc, ra_session, overwrite,
+ ignore_externals, ignore_keywords, depth,
+ native_eol, ctx, pool));
}
else if (kind == svn_node_none)
{
Modified: subversion/branches/tree-read-api/subversion/libsvn_client/externals.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_client/externals.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_client/externals.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_client/externals.c Sun Jan 6 02:33:34 2013
@@ -399,8 +399,8 @@ switch_file_external(const char *local_a
{
const char *wcroot_abspath;
- SVN_ERR(svn_wc__get_wc_root(&wcroot_abspath, ctx->wc_ctx, dir_abspath,
- subpool, subpool));
+ SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath, ctx->wc_ctx, dir_abspath,
+ subpool, subpool));
if (!svn_dirent_is_ancestor(wcroot_abspath, def_dir_abspath))
return svn_error_createf(
@@ -484,7 +484,8 @@ switch_file_external(const char *local_a
ctx, subpool));
/* Get the external file's iprops. */
SVN_ERR(svn_ra_get_inherited_props(ra_session, &inherited_props, "",
- switch_loc->rev, subpool, subpool));
+ switch_loc->rev, TRUE,
+ subpool, subpool));
SVN_ERR(svn_ra_reparent(ra_session, svn_uri_dirname(url, subpool),
subpool));
Modified: subversion/branches/tree-read-api/subversion/libsvn_client/info.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_client/info.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_client/info.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_client/info.c Sun Jan 6 02:33:34 2013
@@ -382,8 +382,8 @@ svn_client_get_wc_root(const char **wcro
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- return svn_wc__get_wc_root(wcroot_abspath, ctx->wc_ctx, local_abspath,
- result_pool, scratch_pool);
+ return svn_wc__get_wcroot(wcroot_abspath, ctx->wc_ctx, local_abspath,
+ result_pool, scratch_pool);
}
Modified: subversion/branches/tree-read-api/subversion/libsvn_client/iprops.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_client/iprops.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_client/iprops.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_client/iprops.c Sun Jan 6 02:33:34 2013
@@ -41,10 +41,12 @@
/*** Code. ***/
/* Determine if LOCAL_ABSPATH needs an inherited property cache. If it does,
- then set *NEEDS_CACHE to TRUE, set it to FALSE otherwise. */
+ then set *NEEDS_CACHE to TRUE, set it to FALSE otherwise. All other args
+ are as per svn_client__get_inheritable_props(). */
static svn_error_t *
need_to_cache_iprops(svn_boolean_t *needs_cache,
const char *local_abspath,
+ svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
@@ -71,7 +73,25 @@ need_to_cache_iprops(svn_boolean_t *need
}
}
- *needs_cache = (is_wc_root || is_switched);
+ /* Starting assumption. */
+ *needs_cache = FALSE;
+
+ if (is_wc_root || is_switched)
+ {
+ const char *session_url;
+ const char *session_root_url;
+
+ /* Looks likely that we need an inherited properties cache...Unless
+ LOCAL_ABSPATH is a WC root that points to the repos root. Then it
+ doesn't need a cache because it has nowhere to inherit from. Check
+ for that case. */
+ SVN_ERR(svn_ra_get_session_url(ra_session, &session_url, scratch_pool));
+ SVN_ERR(svn_ra_get_repos_root2(ra_session, &session_root_url,
+ scratch_pool));
+
+ if (strcmp(session_root_url, session_url) != 0)
+ *needs_cache = TRUE;
+ }
return SVN_NO_ERROR;
}
@@ -81,6 +101,7 @@ svn_client__get_inheritable_props(apr_ha
const char *local_abspath,
svn_revnum_t revision,
svn_depth_t depth,
+ svn_boolean_t use_relpath_keys,
svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
@@ -111,7 +132,7 @@ svn_client__get_inheritable_props(apr_ha
svn_boolean_t needs_cached_iprops;
SVN_ERR(need_to_cache_iprops(&needs_cached_iprops, local_abspath,
- ctx, iterpool));
+ ra_session, ctx, iterpool));
if (needs_cached_iprops)
{
const char *target_abspath = apr_pstrdup(scratch_pool,
@@ -163,8 +184,8 @@ svn_client__get_inheritable_props(apr_ha
}
SVN_ERR(svn_ra_get_inherited_props(ra_session, &inherited_props,
- "", revision, result_pool,
- iterpool));
+ "", revision, use_relpath_keys,
+ result_pool, iterpool));
apr_hash_set(*wcroot_iprops,
apr_pstrdup(result_pool, child_abspath),
APR_HASH_KEY_STRING,
Modified: subversion/branches/tree-read-api/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_client/merge.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_client/merge.c Sun Jan 6 02:33:34 2013
@@ -313,6 +313,23 @@ typedef struct merge_cmd_baton_t {
meet the criteria or DRY_RUN is true. */
apr_hash_t *paths_with_deleted_mergeinfo;
+ /* The list of absolute skipped paths, which should be examined and
+ cleared after each invocation of the callback. The paths
+ are absolute. Is NULL if MERGE_B->SOURCES_ANCESTRAL and
+ MERGE_B->REINTEGRATE_MERGE are both false. */
+ apr_hash_t *skipped_abspaths;
+
+ /* The list of absolute merged paths. Unused if MERGE_B->SOURCES_ANCESTRAL
+ and MERGE_B->REINTEGRATE_MERGE are both false. */
+ apr_hash_t *merged_abspaths;
+
+ /* A hash of (const char *) absolute WC paths mapped to the same which
+ represent the roots of subtrees added by the merge. */
+ apr_hash_t *added_abspaths;
+
+ /* A list of tree conflict victim absolute paths which may be NULL. */
+ apr_hash_t *tree_conflicted_abspaths;
+
/* The diff3_cmd in ctx->config, if any, else null. We could just
extract this as needed, but since more than one caller uses it,
we just set it up when this baton is created. */
@@ -504,7 +521,7 @@ dry_run_added_parent_p(const merge_cmd_b
apr_pool_t *scratch_pool)
{
const char *abspath = local_abspath;
- int i;
+ apr_size_t i;
if (!merge_b->dry_run)
return FALSE;
@@ -1234,8 +1251,14 @@ filter_self_referential_mergeinfo(apr_ar
}
/* Prepare a set of property changes PROPCHANGES to be used for a merge
- operation on LOCAL_ABSPATH. Store the result in *PROP_UPDATES.
+ operation on LOCAL_ABSPATH.
+ Remove all non-regular prop-changes (entry-props and WC-props).
+ Remove all non-mergeinfo prop-changes if it's a record-only merge.
+ Remove self-referential mergeinfo (### in some cases...)
+ Remove foreign-repository mergeinfo (### in some cases...)
+
+ Store the resulting property changes in *PROP_UPDATES.
Store information on where mergeinfo is updated in MERGE_B.
Used for both file and directory property merges. */
@@ -1251,6 +1274,8 @@ prepare_merge_props_changed(const apr_ar
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+ /* We only want to merge "regular" version properties: by
+ definition, 'svn merge' shouldn't touch any data within .svn/ */
SVN_ERR(svn_categorize_props(propchanges, NULL, NULL, &props,
result_pool));
@@ -1275,8 +1300,6 @@ prepare_merge_props_changed(const apr_ar
props = mergeinfo_props;
}
- /* We only want to merge "regular" version properties: by
- definition, 'svn merge' shouldn't touch any data within .svn/ */
if (props->nelts)
{
/* If this is a forward merge then don't add new mergeinfo to
@@ -1430,8 +1453,6 @@ merge_dir_props_changed(svn_wc_notify_st
SVN_ERR(prepare_merge_props_changed(&props, local_abspath, propchanges,
merge_b, scratch_pool, scratch_pool));
- /* We only want to merge "regular" version properties: by
- definition, 'svn merge' shouldn't touch any pristine data */
if (props->nelts)
{
const svn_wc_conflict_version_t *left;
@@ -1720,14 +1741,9 @@ merge_file_changed(svn_wc_notify_state_t
if (prop_state)
*prop_state = svn_wc_notify_state_unchanged;
- if (prop_changes->nelts > 0)
- {
- /* Filter entry-props and unneeded properties in case of a record only
- merge */
- SVN_ERR(prepare_merge_props_changed(&prop_changes, local_abspath,
- prop_changes, merge_b,
- scratch_pool, scratch_pool));
- }
+ SVN_ERR(prepare_merge_props_changed(&prop_changes, local_abspath,
+ prop_changes, merge_b,
+ scratch_pool, scratch_pool));
SVN_ERR(make_conflict_versions(&left, &right, local_abspath,
svn_node_file, &merge_b->merge_source, merge_b->target, merge_b->pool));
@@ -1920,6 +1936,21 @@ merge_file_added(svn_wc_notify_state_t *
{
case svn_node_none:
{
+ svn_node_kind_t parent_kind;
+
+ /* Does the parent exist on disk (vs missing). If no we should
+ report an obstruction. Or svn_wc_add_repos_file4() will just
+ do its work and the workqueue will create the missing dirs */
+ SVN_ERR(svn_io_check_path(
+ svn_dirent_dirname(mine_abspath, scratch_pool),
+ &parent_kind, scratch_pool));
+
+ if (parent_kind != svn_node_dir)
+ {
+ *content_state = svn_wc_notify_state_obstructed;
+ return SVN_NO_ERROR;
+ }
+
if (! merge_b->dry_run)
{
const char *copyfrom_url;
@@ -2013,8 +2044,6 @@ merge_file_added(svn_wc_notify_state_t *
merge_b->ctx->cancel_func,
merge_b->ctx->cancel_baton,
scratch_pool));
-
- /* ### delete 'yours' ? */
}
}
if (content_state)
@@ -2723,9 +2752,45 @@ merge_dir_opened(svn_boolean_t *tree_con
if (obstr_state != svn_wc_notify_state_inapplicable)
{
- if (skip_children)
- *skip_children = TRUE;
- /* But don't skip THIS, to allow a skip notification */
+ /* In Subversion <= 1.7 we always skipped descendants here */
+ if (obstr_state == svn_wc_notify_state_obstructed)
+ {
+ svn_boolean_t is_wcroot;
+
+ SVN_ERR(svn_wc_check_root(&is_wcroot, NULL, NULL,
+ merge_b->ctx->wc_ctx,
+ local_abspath, scratch_pool));
+
+ if (is_wcroot)
+ {
+ const char *skipped_path;
+
+ skipped_path = apr_pstrdup(apr_hash_pool_get(
+ merge_b->skipped_abspaths),
+ local_abspath);
+
+ apr_hash_set(merge_b->skipped_abspaths, skipped_path,
+ APR_HASH_KEY_STRING, skipped_path);
+
+ *skip = TRUE;
+ *skip_children = TRUE;
+
+ if (merge_b->ctx->notify_func2)
+ {
+ svn_wc_notify_t *notify;
+
+ notify = svn_wc_create_notify(
+ skipped_path,
+ svn_wc_notify_update_skip_obstruction,
+ scratch_pool);
+ notify->kind = svn_node_dir;
+ notify->content_state = obstr_state;
+ merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2,
+ notify, scratch_pool);
+ }
+ }
+ }
+
return SVN_NO_ERROR;
}
@@ -2747,8 +2812,7 @@ merge_dir_opened(svn_boolean_t *tree_con
if (parent_depth != svn_depth_unknown &&
parent_depth < svn_depth_immediates)
{
- if (skip_children)
- *skip_children = TRUE;
+ /* In Subversion <= 1.7 we skipped descendants here */
return SVN_NO_ERROR;
}
}
@@ -2845,25 +2909,6 @@ typedef struct notification_receiver_bat
/* The number of operative notifications received. */
apr_uint32_t nbr_operative_notifications;
- /* The list of absolute merged paths. Is NULL if MERGE_B->SOURCES_ANCESTRAL
- and MERGE_B->REINTEGRATE_MERGE are both false. */
- apr_hash_t *merged_abspaths;
-
- /* The list of absolute skipped paths, which should be examined and
- cleared after each invocation of the callback. The paths
- are absolute. Is NULL if MERGE_B->SOURCES_ANCESTRAL and
- MERGE_B->REINTEGRATE_MERGE are both false. */
- apr_hash_t *skipped_abspaths;
-
- /* A hash of (const char *) absolute WC paths mapped to the same which
- represent the roots of subtrees added by the merge. May be NULL. */
- apr_hash_t *added_abspaths;
-
- /* A list of tree conflict victim absolute paths which may be NULL. Is NULL
- if MERGE_B->SOURCES_ANCESTRAL and MERGE_B->REINTEGRATE_MERGE are both
- false. */
- apr_hash_t *tree_conflicted_abspaths;
-
/* Flag indicating whether it is a single file merge or not. */
svn_boolean_t is_single_file_merge;
@@ -3084,6 +3129,7 @@ notification_receiver(void *baton, const
apr_pool_t *pool)
{
notification_receiver_baton_t *notify_b = baton;
+ merge_cmd_baton_t *merge_b = notify_b->merge_b;
svn_boolean_t is_operative_notification = IS_OPERATIVE_NOTIFICATION(notify);
const char *notify_abspath;
@@ -3105,7 +3151,7 @@ notification_receiver(void *baton, const
* not yet implemented.
* ### We should stash the info about which moves have been followed and
* retrieve that info here, instead of querying the WC again here. */
- notify_abspath = svn_dirent_join(notify_b->merge_b->target->abspath,
+ notify_abspath = svn_dirent_join(merge_b->target->abspath,
notify->path, pool);
if (notify->action == svn_wc_notify_update_update
&& notify->kind == svn_node_file)
@@ -3114,7 +3160,7 @@ notification_receiver(void *baton, const
const char *moved_to_abspath;
err = svn_wc__node_was_moved_away(&moved_to_abspath, NULL,
- notify_b->merge_b->ctx->wc_ctx,
+ merge_b->ctx->wc_ctx,
notify_abspath, pool, pool);
if (err)
{
@@ -3135,8 +3181,8 @@ notification_receiver(void *baton, const
}
/* Update the lists of merged, skipped, tree-conflicted and added paths. */
- if (notify_b->merge_b->merge_source.ancestral
- || notify_b->merge_b->reintegrate_merge)
+ if (merge_b->merge_source.ancestral
+ || merge_b->reintegrate_merge)
{
if (notify->content_state == svn_wc_notify_state_merged
|| notify->content_state == svn_wc_notify_state_changed
@@ -3147,10 +3193,7 @@ notification_receiver(void *baton, const
const char *merged_path = apr_pstrdup(notify_b->pool,
notify_abspath);
- if (notify_b->merged_abspaths == NULL)
- notify_b->merged_abspaths = apr_hash_make(notify_b->pool);
-
- apr_hash_set(notify_b->merged_abspaths, merged_path,
+ apr_hash_set(merge_b->merged_abspaths, merged_path,
APR_HASH_KEY_STRING, merged_path);
}
@@ -3159,10 +3202,7 @@ notification_receiver(void *baton, const
const char *skipped_path = apr_pstrdup(notify_b->pool,
notify_abspath);
- if (notify_b->skipped_abspaths == NULL)
- notify_b->skipped_abspaths = apr_hash_make(notify_b->pool);
-
- apr_hash_set(notify_b->skipped_abspaths, skipped_path,
+ apr_hash_set(merge_b->skipped_abspaths, skipped_path,
APR_HASH_KEY_STRING, skipped_path);
}
@@ -3171,30 +3211,26 @@ notification_receiver(void *baton, const
const char *tree_conflicted_path = apr_pstrdup(notify_b->pool,
notify_abspath);
- if (notify_b->tree_conflicted_abspaths == NULL)
- notify_b->tree_conflicted_abspaths =
- apr_hash_make(notify_b->pool);
-
- apr_hash_set(notify_b->tree_conflicted_abspaths,
+ apr_hash_set(merge_b->tree_conflicted_abspaths,
tree_conflicted_path, APR_HASH_KEY_STRING,
tree_conflicted_path);
}
if (notify->action == svn_wc_notify_update_add)
{
- update_the_list_of_added_subtrees(notify_b->merge_b->target->abspath,
+ update_the_list_of_added_subtrees(merge_b->target->abspath,
notify_abspath,
- &(notify_b->added_abspaths),
+ &(merge_b->added_abspaths),
notify_b->pool, pool);
}
if (notify->action == svn_wc_notify_update_delete
- && notify_b->added_abspaths)
+ && merge_b->added_abspaths)
{
/* Issue #4166: If a previous merge added NOTIFY_ABSPATH, but we
are now deleting it, then remove it from the list of added
paths. */
- apr_hash_set(notify_b->added_abspaths, notify_abspath,
+ apr_hash_set(merge_b->added_abspaths, notify_abspath,
APR_HASH_KEY_STRING, NULL);
}
}
@@ -3202,7 +3238,7 @@ notification_receiver(void *baton, const
/* Notify that a merge is beginning, if we haven't already done so.
* (A single-file merge is notified separately: see single_file_merge_notify().) */
/* If our merge sources are ancestors of one another... */
- if (notify_b->merge_b->merge_source.ancestral)
+ if (merge_b->merge_source.ancestral)
{
/* See if this is an operative directory merge. */
if (!(notify_b->is_single_file_merge) && is_operative_notification)
@@ -3237,8 +3273,8 @@ notification_receiver(void *baton, const
notify_merge_begin(child->abspath,
APR_ARRAY_IDX(child->remaining_ranges, 0,
svn_merge_range_t *),
- notify_b->merge_b->same_repos,
- notify_b->merge_b->ctx, pool);
+ merge_b->same_repos,
+ merge_b->ctx, pool);
}
}
}
@@ -3248,9 +3284,9 @@ notification_receiver(void *baton, const
&& notify_b->nbr_operative_notifications == 1
&& is_operative_notification)
{
- notify_merge_begin(notify_b->merge_b->target->abspath, NULL,
- notify_b->merge_b->same_repos,
- notify_b->merge_b->ctx, pool);
+ notify_merge_begin(merge_b->target->abspath, NULL,
+ merge_b->same_repos,
+ merge_b->ctx, pool);
}
if (notify_b->wrapped_func)
@@ -4429,13 +4465,24 @@ find_gaps_in_merge_source_history(svn_re
if (rangelist->nelts > 1) /* Copy */
{
+ const svn_merge_range_t *gap;
/* As mentioned above, multiple gaps *shouldn't* be possible. */
SVN_ERR_ASSERT(apr_hash_count(implicit_src_mergeinfo) == 1);
+ gap = APR_ARRAY_IDX(rangelist, rangelist->nelts - 1,
+ const svn_merge_range_t *);
+
*gap_start = MIN(source->loc1->rev, source->loc2->rev);
- *gap_end = (APR_ARRAY_IDX(rangelist,
- rangelist->nelts - 1,
- svn_merge_range_t *))->start;
+ *gap_end = gap->start;
+
+ /* ### Issue #4132:
+ ### This assertion triggers in merge_tests.py svnmucc_abuse_1()
+ ### when a node is replaced by an older copy of itself.
+
+ BH: I think we should review this and the 'rename' case to find
+ out which behavior we really want, and if we can really
+ determine what happened this way. */
+ SVN_ERR_ASSERT(*gap_start < *gap_end);
}
else if (apr_hash_count(implicit_src_mergeinfo) > 1) /* Rename */
{
@@ -4896,7 +4943,7 @@ update_wc_mergeinfo(svn_mergeinfo_catalo
Record override mergeinfo on any paths skipped during a merge.
- Set empty mergeinfo on each path in SKIPPED_ABSPATHS so the path
+ Set empty mergeinfo on each path in MERGE_B->SKIPPED_ABSPATHS so the path
does not incorrectly inherit mergeinfo that will later be describing
the merge.
@@ -4910,14 +4957,12 @@ static svn_error_t *
record_skips(const char *mergeinfo_path,
const svn_rangelist_t *rangelist,
svn_boolean_t is_rollback,
- apr_hash_t *skipped_abspaths,
merge_cmd_baton_t *merge_b,
apr_pool_t *scratch_pool)
{
apr_hash_index_t *hi;
apr_hash_t *merges;
- apr_size_t nbr_skips = (skipped_abspaths != NULL ?
- apr_hash_count(skipped_abspaths) : 0);
+ apr_size_t nbr_skips = apr_hash_count(merge_b->skipped_abspaths);
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
if (nbr_skips == 0)
@@ -4926,7 +4971,7 @@ record_skips(const char *mergeinfo_path,
merges = apr_hash_make(scratch_pool);
/* Override the mergeinfo for child paths which weren't actually merged. */
- for (hi = apr_hash_first(scratch_pool, skipped_abspaths); hi;
+ for (hi = apr_hash_first(scratch_pool, merge_b->skipped_abspaths); hi;
hi = apr_hash_next(hi))
{
const char *skipped_abspath = svn__apr_hash_index_key(hi);
@@ -7209,8 +7254,7 @@ do_file_merge(svn_mergeinfo_catalog_t re
self-referential mergeinfo, but don't record mergeinfo if
TARGET_WCPATH was skipped. */
if (filtered_rangelist->nelts
- && (!notify_b->skipped_abspaths
- || (apr_hash_count(notify_b->skipped_abspaths) == 0)))
+ && (apr_hash_count(notify_b->merge_b->skipped_abspaths) == 0))
{
apr_hash_t *merges = apr_hash_make(iterpool);
@@ -7303,7 +7347,7 @@ process_children_with_new_mergeinfo(merg
svn_mergeinfo_t path_explicit_mergeinfo;
svn_client__merge_path_t *new_child;
- apr_pool_clear(iterpool);
+ svn_pool_clear(iterpool);
/* Get the path's new explicit mergeinfo... */
SVN_ERR(svn_client__get_wc_mergeinfo(&path_explicit_mergeinfo, NULL,
@@ -7410,11 +7454,11 @@ subtree_touched_by_merge(const char *loc
notification_receiver_baton_t *notify_b,
apr_pool_t *pool)
{
- return (path_is_subtree(local_abspath, notify_b->merged_abspaths, pool)
- || path_is_subtree(local_abspath, notify_b->skipped_abspaths, pool)
- || path_is_subtree(local_abspath, notify_b->added_abspaths, pool)
- || path_is_subtree(local_abspath,
- notify_b->tree_conflicted_abspaths,
+ merge_cmd_baton_t *merge_b = notify_b->merge_b;
+ return (path_is_subtree(local_abspath, merge_b->merged_abspaths, pool)
+ || path_is_subtree(local_abspath, merge_b->skipped_abspaths, pool)
+ || path_is_subtree(local_abspath, merge_b->added_abspaths, pool)
+ || path_is_subtree(local_abspath, merge_b->tree_conflicted_abspaths,
pool));
}
@@ -7698,9 +7742,8 @@ flag_subtrees_needing_mergeinfo(svn_bool
continue;
/* Don't record mergeinfo on skipped paths. */
- if (notify_b->skipped_abspaths
- && apr_hash_get(notify_b->skipped_abspaths, child->abspath,
- APR_HASH_KEY_STRING))
+ if (apr_hash_get(notify_b->merge_b->skipped_abspaths, child->abspath,
+ APR_HASH_KEY_STRING))
continue;
/* ### ptb: Yes, we could combine the following into a single
@@ -7751,7 +7794,7 @@ flag_subtrees_needing_mergeinfo(svn_bool
if (!merge_b->reintegrate_merge
&& child->missing_child
&& !path_is_subtree(child->abspath,
- notify_b->skipped_abspaths,
+ notify_b->merge_b->skipped_abspaths,
iterpool))
{
child->missing_child = FALSE;
@@ -7980,8 +8023,7 @@ record_mergeinfo_for_dir_merge(svn_merge
don't incorrectly inherit the mergeinfo we are about to set. */
if (i == 0)
SVN_ERR(record_skips(mergeinfo_fspath, child_merge_rangelist,
- is_rollback, notify_b->skipped_abspaths,
- merge_b, iterpool));
+ is_rollback, merge_b, iterpool));
/* We may need to record non-inheritable mergeinfo that applies
only to CHILD->ABSPATH. */
@@ -8188,7 +8230,7 @@ record_mergeinfo_for_added_subtrees(
svn_mergeinfo_t parent_mergeinfo;
svn_mergeinfo_t added_path_mergeinfo;
- apr_pool_clear(iterpool);
+ svn_pool_clear(iterpool);
dir_abspath = svn_dirent_dirname(added_abspath, iterpool);
/* Grab the added path's explicit mergeinfo. */
@@ -8511,6 +8553,8 @@ remove_noop_subtree_ranges(const merge_s
svn_merge_range_t *youngest_gap_rev;
svn_rangelist_t *inoperative_ranges;
apr_pool_t *iterpool;
+ const char *longest_common_subtree_ancestor = NULL;
+ svn_error_t *err;
assert(session_url_is(ra_session, source->loc2->url, scratch_pool));
@@ -8549,6 +8593,19 @@ remove_noop_subtree_ranges(const merge_s
svn_pool_clear(iterpool);
+ /* Issue #4269: Keep track of the longest common ancestor of all the
+ subtrees which require merges. This may be a child of
+ TARGET->ABSPATH, which will allow us to narrow the log request
+ below. */
+ if (child->remaining_ranges && child->remaining_ranges->nelts)
+ {
+ if (longest_common_subtree_ancestor)
+ longest_common_subtree_ancestor = svn_dirent_get_longest_ancestor(
+ longest_common_subtree_ancestor, child->abspath, scratch_pool);
+ else
+ longest_common_subtree_ancestor = child->abspath;
+ }
+
/* CHILD->REMAINING_RANGES will be NULL if child is absent. */
if (child->remaining_ranges && child->remaining_ranges->nelts)
SVN_ERR(svn_rangelist_merge2(subtree_remaining_ranges,
@@ -8589,24 +8646,53 @@ remove_noop_subtree_ranges(const merge_s
sizeof(svn_revnum_t *));
log_gap_baton.pool = svn_pool_create(scratch_pool);
+ /* Find the longest common ancestor of all subtrees relative to
+ RA_SESSION's URL. */
+ if (longest_common_subtree_ancestor)
+ longest_common_subtree_ancestor =
+ svn_dirent_skip_ancestor(target->abspath,
+ longest_common_subtree_ancestor);
+ else
+ longest_common_subtree_ancestor = "";
+
/* Invoke the svn_log_entry_receiver_t receiver log_noop_revs() from
oldest to youngest. The receiver is optimized to add ranges to
log_gap_baton.merged_ranges and log_gap_baton.operative_ranges, but
requires that the revs arrive oldest to youngest -- see log_noop_revs()
and rangelist_merge_revision(). */
- SVN_ERR(get_log(ra_session, "", oldest_gap_rev->start + 1,
- youngest_gap_rev->end, TRUE,
- log_noop_revs, &log_gap_baton, scratch_pool));
-
- inoperative_ranges = svn_rangelist__initialize(oldest_gap_rev->start,
- youngest_gap_rev->end,
- TRUE, scratch_pool);
- SVN_ERR(svn_rangelist_remove(&(inoperative_ranges),
- log_gap_baton.operative_ranges,
- inoperative_ranges, FALSE, scratch_pool));
+ err = get_log(ra_session, longest_common_subtree_ancestor,
+ oldest_gap_rev->start + 1, youngest_gap_rev->end, TRUE,
+ log_noop_revs, &log_gap_baton, scratch_pool);
+
+ /* It's possible that the only subtrees with mergeinfo in TARGET don't have
+ any corresponding subtree in SOURCE between SOURCE->REV1 < SOURCE->REV2.
+ So it's also possible that we may ask for the logs of non-existent paths.
+ If we do, then assume that no subtree requires any ranges that are not
+ already required by the TARGET. */
+ if (err)
+ {
+ if (err->apr_err != SVN_ERR_FS_NOT_FOUND
+ && longest_common_subtree_ancestor[0] != '\0')
+ return svn_error_trace(err);
- SVN_ERR(svn_rangelist_merge2(log_gap_baton.merged_ranges, inoperative_ranges,
- scratch_pool, scratch_pool));
+ /* Asked about a non-existent subtree in SOURCE. */
+ svn_error_clear(err);
+ log_gap_baton.merged_ranges =
+ svn_rangelist__initialize(oldest_gap_rev->start,
+ youngest_gap_rev->end,
+ TRUE, scratch_pool);
+ }
+ else
+ {
+ inoperative_ranges = svn_rangelist__initialize(oldest_gap_rev->start,
+ youngest_gap_rev->end,
+ TRUE, scratch_pool);
+ SVN_ERR(svn_rangelist_remove(&(inoperative_ranges),
+ log_gap_baton.operative_ranges,
+ inoperative_ranges, FALSE, scratch_pool));
+ SVN_ERR(svn_rangelist_merge2(log_gap_baton.merged_ranges, inoperative_ranges,
+ scratch_pool, scratch_pool));
+ }
for (i = 1; i < children_with_mergeinfo->nelts; i++)
{
@@ -8962,7 +9048,7 @@ do_mergeinfo_aware_dir_merge(svn_mergein
err = record_mergeinfo_for_added_subtrees(
&range, mergeinfo_path, depth,
squelch_mergeinfo_notifications,
- notify_b->added_abspaths, merge_b, scratch_pool);
+ merge_b->added_abspaths, merge_b, scratch_pool);
}
}
@@ -9204,13 +9290,14 @@ do_merge(apr_hash_t **modified_subtrees,
/* Do we already know the specific subtrees with mergeinfo we want
to record-only mergeinfo on? */
if (record_only && record_only_paths)
- notify_baton.merged_abspaths = record_only_paths;
+ merge_cmd_baton.merged_abspaths = record_only_paths;
else
- notify_baton.merged_abspaths = NULL;
+ merge_cmd_baton.merged_abspaths = apr_hash_make(result_pool);
+
+ merge_cmd_baton.skipped_abspaths = apr_hash_make(result_pool);
+ merge_cmd_baton.added_abspaths = apr_hash_make(result_pool);
+ merge_cmd_baton.tree_conflicted_abspaths = apr_hash_make(result_pool);
- notify_baton.skipped_abspaths = NULL;
- notify_baton.added_abspaths = NULL;
- notify_baton.tree_conflicted_abspaths = NULL;
notify_baton.children_with_mergeinfo = NULL;
notify_baton.cur_ancestor_abspath = NULL;
notify_baton.merge_b = &merge_cmd_baton;
@@ -9298,22 +9385,18 @@ do_merge(apr_hash_t **modified_subtrees,
/* ### Why only if the target is a dir and not a file? */
if (modified_subtrees)
{
- if (notify_baton.merged_abspaths)
- *modified_subtrees =
+ *modified_subtrees =
apr_hash_overlay(result_pool, *modified_subtrees,
- notify_baton.merged_abspaths);
- if (notify_baton.added_abspaths)
- *modified_subtrees =
+ merge_cmd_baton.merged_abspaths);
+ *modified_subtrees =
apr_hash_overlay(result_pool, *modified_subtrees,
- notify_baton.added_abspaths);
- if (notify_baton.skipped_abspaths)
- *modified_subtrees =
+ merge_cmd_baton.added_abspaths);
+ *modified_subtrees =
apr_hash_overlay(result_pool, *modified_subtrees,
- notify_baton.skipped_abspaths);
- if (notify_baton.tree_conflicted_abspaths)
- *modified_subtrees =
+ merge_cmd_baton.skipped_abspaths);
+ *modified_subtrees =
apr_hash_overlay(result_pool, *modified_subtrees,
- notify_baton.tree_conflicted_abspaths);
+ merge_cmd_baton.tree_conflicted_abspaths);
}
}
Modified: subversion/branches/tree-read-api/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_client/patch.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_client/patch.c Sun Jan 6 02:33:34 2013
@@ -915,7 +915,7 @@ init_patch_target(patch_target_t **patch
if (target->kind_on_disk == svn_node_file)
{
SVN_ERR(svn_io_file_open(&target->file, target->local_abspath,
- APR_READ | APR_BINARY | APR_BUFFERED,
+ APR_READ | APR_BUFFERED,
APR_OS_DEFAULT, result_pool));
SVN_ERR(svn_wc_text_modified_p2(&target->local_mods, wc_ctx,
target->local_abspath, FALSE,
@@ -2288,9 +2288,10 @@ create_missing_parents(patch_target_t *t
if (ctx->cancel_func)
SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
- SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, local_abspath,
- ctx->notify_func2, ctx->notify_baton2,
- iterpool));
+ SVN_ERR(svn_wc_add_from_disk2(ctx->wc_ctx, local_abspath,
+ NULL /*props*/,
+ ctx->notify_func2, ctx->notify_baton2,
+ iterpool));
}
}
}
@@ -2402,8 +2403,9 @@ install_patched_target(patch_target_t *t
* Suppress notification, we'll do that later (and also
* during dry-run). Don't allow cancellation because
* we'd rather notify about what we did before aborting. */
- SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, target->local_abspath,
- NULL, NULL, pool));
+ SVN_ERR(svn_wc_add_from_disk2(ctx->wc_ctx, target->local_abspath,
+ NULL /*props*/,
+ NULL, NULL, pool));
}
/* Restore the target's executable bit if necessary. */
@@ -2494,10 +2496,11 @@ install_patched_prop_targets(patch_targe
{
SVN_ERR(svn_io_file_create(target->local_abspath, "",
scratch_pool));
- SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, target->local_abspath,
- /* suppress notification */
- NULL, NULL,
- iterpool));
+ SVN_ERR(svn_wc_add_from_disk2(ctx->wc_ctx, target->local_abspath,
+ NULL /*props*/,
+ /* suppress notification */
+ NULL, NULL,
+ iterpool));
}
target->added = TRUE;
}
@@ -2617,8 +2620,8 @@ check_dir_empty(svn_boolean_t *empty, co
int i;
/* Working copy root cannot be deleted, so never consider it empty. */
- SVN_ERR(svn_wc__strictly_is_wc_root(&is_wc_root, wc_ctx, local_abspath,
- scratch_pool));
+ SVN_ERR(svn_wc__is_wcroot(&is_wc_root, wc_ctx, local_abspath,
+ scratch_pool));
if (is_wc_root)
{
*empty = FALSE;
Modified: subversion/branches/tree-read-api/subversion/libsvn_client/prop_commands.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_client/prop_commands.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_client/prop_commands.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_client/prop_commands.c Sun Jan 6 02:33:34 2013
@@ -639,7 +639,7 @@ remote_propget(apr_hash_t *props,
/* We will filter out all but PROPNAME later, making a final copy
in RESULT_POOL, so pass SCRATCH_POOL for both pools. */
SVN_ERR(svn_ra_get_inherited_props(ra_session, inherited_props,
- target_relative, revnum,
+ target_relative, revnum, FALSE,
scratch_pool, scratch_pool));
}
@@ -1125,7 +1125,7 @@ remote_proplist(const char *target_prefi
if (get_target_inherited_props)
SVN_ERR(svn_ra_get_inherited_props(ra_session, &inherited_props,
- target_relative, revnum,
+ target_relative, revnum, FALSE,
result_pool, scratch_pool));
else
inherited_props = NULL;