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 2018/11/15 16:12:55 UTC
svn commit: r1846666 - in /subversion/trunk/subversion:
include/private/svn_client_private.h libsvn_client/copy_foreign.c
Author: julianfoad
Date: Thu Nov 15 16:12:54 2018
New Revision: 1846666
URL: http://svn.apache.org/viewvc?rev=1846666&view=rev
Log:
Start issue SVN-4786: Create a WC working-mods editor.
* subversion/include/private/svn_client_private.h
(svn_client__wc_editor): New.
* subversion/libsvn_client/copy_foreign.c
Extract existing editor and expand it to handle more cases.
Modified:
subversion/trunk/subversion/include/private/svn_client_private.h
subversion/trunk/subversion/libsvn_client/copy_foreign.c
Modified: subversion/trunk/subversion/include/private/svn_client_private.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_client_private.h?rev=1846666&r1=1846665&r2=1846666&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_client_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_client_private.h Thu Nov 15 16:12:54 2018
@@ -434,6 +434,24 @@ svn_client__repos_to_wc_copy_dir(svn_boo
svn_client_ctx_t *ctx,
apr_pool_t *pool);
+/** Return an editor for applying local modifications to a WC.
+ *
+ * Return an editor in @a *editor_p, @a *edit_baton_p that will apply
+ * local modifications to the WC subdirectory at @a dst_abspath.
+ *
+ * Send notifications via @a notify_func / @a notify_baton.
+ *
+ * Ignore changes to non-regular property (entry-props, DAV/WC-props).
+ */
+svn_error_t *
+svn_client__wc_editor(const svn_delta_editor_t **editor_p,
+ void **edit_baton_p,
+ const char *dst_abspath,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool);
+
/** Send committable changes found in the WC to a delta-editor.
*
* Committable changes are found in TARGETS:DEPTH:CHANGELISTS.
Modified: subversion/trunk/subversion/libsvn_client/copy_foreign.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/copy_foreign.c?rev=1846666&r1=1846665&r2=1846666&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/copy_foreign.c (original)
+++ subversion/trunk/subversion/libsvn_client/copy_foreign.c Thu Nov 15 16:12:54 2018
@@ -45,12 +45,33 @@
#include "private/svn_wc_private.h"
#include "svn_private_config.h"
+
+/* ------------------------------------------------------------------ */
+
+/* WC Modifications Editor.
+ *
+ * TODO:
+ * - tests
+ * - use for all existing scenarios ('svn add', 'svn propset', etc.)
+ * - copy-from (half done: in dir_add only, untested)
+ * - text-delta
+ * - Instead of 'root_dir_add' option, probably the driver should anchor
+ * at the parent dir.
+ * - Instead of 'ignore_mergeinfo' option, implement that as a wrapper.
+ */
+
struct edit_baton_t
{
apr_pool_t *pool;
const char *anchor_abspath;
+ /* True => 'open_root' method will act as 'add_directory' */
+ svn_boolean_t root_dir_add;
+ /* True => filter out any incoming svn:mergeinfo property changes */
+ svn_boolean_t ignore_mergeinfo_changes;
+
svn_wc_context_t *wc_ctx;
+ svn_client_ctx_t *ctx;
svn_wc_notify_func2_t notify_func;
void *notify_baton;
};
@@ -64,12 +85,33 @@ struct dir_baton_t
const char *local_abspath;
- svn_boolean_t created;
+ svn_boolean_t created; /* already under version control in the WC */
apr_hash_t *properties;
int users;
};
+/* */
+static svn_error_t *
+get_path(const char **local_abspath_p,
+ const char *anchor_abspath,
+ const char *path,
+ apr_pool_t *result_pool)
+{
+ svn_boolean_t under_root;
+
+ SVN_ERR(svn_dirent_is_under_root(&under_root, local_abspath_p,
+ anchor_abspath, path, result_pool));
+ if (! under_root)
+ {
+ return svn_error_createf(
+ SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
+ _("Path '%s' is not in the working copy"),
+ svn_dirent_local_style(path, result_pool));
+ }
+ return SVN_NO_ERROR;
+}
+
/* svn_delta_editor_t function */
static svn_error_t *
edit_open(void *edit_baton,
@@ -86,7 +128,9 @@ edit_open(void *edit_baton,
db->users = 1;
db->local_abspath = eb->anchor_abspath;
- SVN_ERR(svn_io_make_dir_recursively(eb->anchor_abspath, dir_pool));
+ db->created = !(eb->root_dir_add);
+ if (eb->root_dir_add)
+ SVN_ERR(svn_io_make_dir_recursively(eb->anchor_abspath, dir_pool));
*root_baton = db;
@@ -101,19 +145,38 @@ edit_close(void *edit_baton,
return SVN_NO_ERROR;
}
+/* */
static svn_error_t *
-dir_add(const char *path,
- void *parent_baton,
- const char *copyfrom_path,
- svn_revnum_t copyfrom_revision,
- apr_pool_t *result_pool,
- void **child_baton)
+delete_entry(const char *path,
+ svn_revnum_t revision,
+ void *parent_baton,
+ apr_pool_t *scratch_pool)
+{
+ struct dir_baton_t *pb = parent_baton;
+ struct edit_baton_t *eb = pb->eb;
+ const char *local_abspath;
+
+ SVN_ERR(get_path(&local_abspath,
+ eb->anchor_abspath, path, scratch_pool));
+ SVN_ERR(svn_wc_delete4(eb->wc_ctx, local_abspath,
+ FALSE /*keep_local*/,
+ TRUE /*delete_unversioned*/,
+ NULL, NULL, /*cancellation*/
+ eb->notify_func, eb->notify_baton, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+/* */
+static svn_error_t *
+dir_open_or_add(const char *path,
+ void *parent_baton,
+ struct dir_baton_t **child_baton)
{
struct dir_baton_t *pb = parent_baton;
struct edit_baton_t *eb = pb->eb;
apr_pool_t *dir_pool = svn_pool_create(pb->pool);
struct dir_baton_t *db = apr_pcalloc(dir_pool, sizeof(*db));
- svn_boolean_t under_root;
pb->users++;
@@ -122,18 +185,60 @@ dir_add(const char *path,
db->pool = dir_pool;
db->users = 1;
- SVN_ERR(svn_dirent_is_under_root(&under_root, &db->local_abspath,
- eb->anchor_abspath, path, db->pool));
- if (! under_root)
- {
- return svn_error_createf(
- SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
- _("Path '%s' is not in the working copy"),
- svn_dirent_local_style(path, db->pool));
- }
+ SVN_ERR(get_path(&db->local_abspath,
+ eb->anchor_abspath, path, db->pool));
+
+ *child_baton = db;
+ return SVN_NO_ERROR;
+}
+
+/* An svn_delta_editor_t function. */
+static svn_error_t *
+dir_open(const char *path,
+ void *parent_baton,
+ svn_revnum_t base_revision,
+ apr_pool_t *result_pool,
+ void **child_baton)
+{
+ struct dir_baton_t *db;
+
+ SVN_ERR(dir_open_or_add(path, parent_baton, &db));
+ db->created = TRUE;
+
+ *child_baton = db;
+ return SVN_NO_ERROR;
+}
+static svn_error_t *
+dir_add(const char *path,
+ void *parent_baton,
+ const char *copyfrom_path,
+ svn_revnum_t copyfrom_revision,
+ apr_pool_t *result_pool,
+ void **child_baton)
+{
+ struct dir_baton_t *db;
+
+ SVN_ERR(dir_open_or_add(path, parent_baton, &db));
SVN_ERR(svn_io_make_dir_recursively(db->local_abspath, db->pool));
+ if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_revision))
+ {
+ svn_opt_revision_t copy_src_peg_revision;
+
+ copy_src_peg_revision.kind = svn_opt_revision_number;
+ copy_src_peg_revision.value.number = copyfrom_revision;
+
+ SVN_ERR(svn_client__repos_to_wc_copy_dir(NULL /*timestamp_sleep*/,
+ copyfrom_path,
+ ©_src_peg_revision,
+ ©_src_peg_revision,
+ db->local_abspath,
+ TRUE /*ignore_externals*/,
+ NULL /*ra_session*/,
+ db->eb->ctx, db->pool));
+ }
+
*child_baton = db;
return SVN_NO_ERROR;
}
@@ -151,7 +256,7 @@ dir_change_prop(void *dir_baton,
prop_kind = svn_property_kind2(name);
if (prop_kind != svn_prop_regular_kind
- || ! strcmp(name, SVN_PROP_MERGEINFO))
+ || (eb->ignore_mergeinfo_changes && ! strcmp(name, SVN_PROP_MERGEINFO)))
{
/* We can't handle DAV, ENTRY and merge specific props here */
return SVN_NO_ERROR;
@@ -159,8 +264,7 @@ dir_change_prop(void *dir_baton,
if (! db->created)
{
- /* We can still store them in the hash for immediate addition
- with the svn_wc_add_from_disk3() call */
+ /* Store properties to be added later in svn_wc_add_from_disk3() */
if (! db->properties)
db->properties = apr_hash_make(db->pool);
@@ -170,7 +274,6 @@ dir_change_prop(void *dir_baton,
}
else
{
- /* We have already notified for this directory, so don't do that again */
SVN_ERR(svn_wc_prop_set4(eb->wc_ctx, db->local_abspath, name, value,
svn_depth_empty, FALSE, NULL,
NULL, NULL, /* Cancellation */
@@ -246,6 +349,7 @@ struct file_baton_t
struct edit_baton_t *eb;
const char *local_abspath;
+ svn_boolean_t created; /* already under version control in the WC */
apr_hash_t *properties;
svn_boolean_t writing;
@@ -254,19 +358,16 @@ struct file_baton_t
const char *tmp_path;
};
+/* */
static svn_error_t *
-file_add(const char *path,
- void *parent_baton,
- const char *copyfrom_path,
- svn_revnum_t copyfrom_revision,
- apr_pool_t *result_pool,
- void **file_baton)
+file_open_or_add(const char *path,
+ void *parent_baton,
+ struct file_baton_t **file_baton)
{
struct dir_baton_t *pb = parent_baton;
struct edit_baton_t *eb = pb->eb;
apr_pool_t *file_pool = svn_pool_create(pb->pool);
struct file_baton_t *fb = apr_pcalloc(file_pool, sizeof(*fb));
- svn_boolean_t under_root;
pb->users++;
@@ -274,15 +375,40 @@ file_add(const char *path,
fb->eb = eb;
fb->pb = pb;
- SVN_ERR(svn_dirent_is_under_root(&under_root, &fb->local_abspath,
- eb->anchor_abspath, path, fb->pool));
- if (! under_root)
- {
- return svn_error_createf(
- SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
- _("Path '%s' is not in the working copy"),
- svn_dirent_local_style(path, fb->pool));
- }
+ SVN_ERR(get_path(&fb->local_abspath,
+ eb->anchor_abspath, path, fb->pool));
+
+ *file_baton = fb;
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+file_open(const char *path,
+ void *parent_baton,
+ svn_revnum_t base_revision,
+ apr_pool_t *result_pool,
+ void **file_baton)
+{
+ struct file_baton_t *fb;
+
+ SVN_ERR(file_open_or_add(path, parent_baton, &fb));
+ fb->created = TRUE;
+
+ *file_baton = fb;
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+file_add(const char *path,
+ void *parent_baton,
+ const char *copyfrom_path,
+ svn_revnum_t copyfrom_revision,
+ apr_pool_t *result_pool,
+ void **file_baton)
+{
+ struct file_baton_t *fb;
+
+ SVN_ERR(file_open_or_add(path, parent_baton, &fb));
*file_baton = fb;
return SVN_NO_ERROR;
@@ -295,25 +421,36 @@ file_change_prop(void *file_baton,
apr_pool_t *scratch_pool)
{
struct file_baton_t *fb = file_baton;
+ struct edit_baton_t *eb = fb->eb;
svn_prop_kind_t prop_kind;
prop_kind = svn_property_kind2(name);
if (prop_kind != svn_prop_regular_kind
- || ! strcmp(name, SVN_PROP_MERGEINFO))
+ || (eb->ignore_mergeinfo_changes && ! strcmp(name, SVN_PROP_MERGEINFO)))
{
/* We can't handle DAV, ENTRY and merge specific props here */
return SVN_NO_ERROR;
}
- /* We store all properties in the hash for immediate addition
- with the svn_wc_add_from_disk3() call */
- if (! fb->properties)
- fb->properties = apr_hash_make(fb->pool);
-
- if (value != NULL)
- svn_hash_sets(fb->properties, apr_pstrdup(fb->pool, name),
- svn_string_dup(value, fb->pool));
+ if (! fb->created)
+ {
+ /* Store properties to be added later in svn_wc_add_from_disk3() */
+ if (! fb->properties)
+ fb->properties = apr_hash_make(fb->pool);
+
+ if (value != NULL)
+ svn_hash_sets(fb->properties, apr_pstrdup(fb->pool, name),
+ svn_string_dup(value, fb->pool));
+ }
+ else
+ {
+ SVN_ERR(svn_wc_prop_set4(eb->wc_ctx, fb->local_abspath, name, value,
+ svn_depth_empty, FALSE, NULL,
+ NULL, NULL, /* Cancellation */
+ NULL, NULL, /* Notification */
+ scratch_pool));
+ }
return SVN_NO_ERROR;
}
@@ -346,16 +483,36 @@ file_textdelta(void *file_baton,
}
static svn_error_t *
+ensure_added_file(struct file_baton_t *fb,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton_t *eb = fb->eb;
+
+ if (fb->created)
+ return SVN_NO_ERROR;
+
+ if (fb->pb)
+ SVN_ERR(ensure_added(fb->pb, scratch_pool));
+
+ fb->created = TRUE;
+
+ /* Add the file with all the already collected properties */
+ SVN_ERR(svn_wc_add_from_disk3(eb->wc_ctx, fb->local_abspath, fb->properties,
+ TRUE /* skip checks */,
+ eb->notify_func, eb->notify_baton,
+ fb->pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
file_close(void *file_baton,
const char *text_checksum,
apr_pool_t *scratch_pool)
{
struct file_baton_t *fb = file_baton;
- struct edit_baton_t *eb = fb->eb;
struct dir_baton_t *pb = fb->pb;
- SVN_ERR(ensure_added(pb, fb->pool));
-
if (text_checksum)
{
svn_checksum_t *expected_checksum;
@@ -376,10 +533,7 @@ file_close(void *file_baton,
fb->pool)));
}
- SVN_ERR(svn_wc_add_from_disk3(eb->wc_ctx, fb->local_abspath, fb->properties,
- TRUE /* skip checks */,
- eb->notify_func, eb->notify_baton,
- fb->pool));
+ SVN_ERR(ensure_added_file(fb, fb->pool));
svn_pool_destroy(fb->pool);
SVN_ERR(maybe_done(pb));
@@ -387,46 +541,117 @@ file_close(void *file_baton,
return SVN_NO_ERROR;
}
+/* Return an editor for applying local modifications to a WC.
+ *
+ * If @a root_dir_add is true, then create and schedule for addition
+ * the root directory of this edit, else assume it is already a versioned,
+ * existing directory.
+ *
+ * If @a ignore_mergeinfo_changes is true, ignore any incoming changes
+ * to the 'svn:mergeinfo' property.
+ */
+static svn_error_t *
+svn_client__wc_editor_internal(const svn_delta_editor_t **editor_p,
+ void **edit_baton_p,
+ const char *dst_abspath,
+ svn_boolean_t root_dir_add,
+ svn_boolean_t ignore_mergeinfo_changes,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool)
+{
+ svn_delta_editor_t *editor = svn_delta_default_editor(result_pool);
+ struct edit_baton_t *eb = apr_pcalloc(result_pool, sizeof(*eb));
+
+ eb->pool = result_pool;
+ eb->anchor_abspath = apr_pstrdup(result_pool, dst_abspath);
+ eb->root_dir_add = root_dir_add;
+ eb->ignore_mergeinfo_changes = ignore_mergeinfo_changes;
+
+ eb->wc_ctx = ctx->wc_ctx;
+ eb->ctx = ctx;
+ eb->notify_func = notify_func;
+ eb->notify_baton = notify_baton;
+
+ editor->open_root = edit_open;
+ editor->close_edit = edit_close;
+
+ editor->delete_entry = delete_entry;
+
+ editor->open_directory = dir_open;
+ editor->add_directory = dir_add;
+ editor->change_dir_prop = dir_change_prop;
+ editor->close_directory = dir_close;
+
+ editor->open_file = file_open;
+ editor->add_file = file_add;
+ editor->change_file_prop = file_change_prop;
+ editor->apply_textdelta = file_textdelta;
+ editor->close_file = file_close;
+
+ *editor_p = editor;
+ *edit_baton_p = eb;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client__wc_editor(const svn_delta_editor_t **editor_p,
+ void **edit_baton_p,
+ const char *dst_abspath,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool)
+{
+ SVN_ERR(svn_client__wc_editor_internal(editor_p, edit_baton_p,
+ dst_abspath,
+ FALSE /*root_dir_add*/,
+ FALSE /*ignore_mergeinfo_changes*/,
+ notify_func, notify_baton,
+ ctx, result_pool));
+ return SVN_NO_ERROR;
+}
+
+/** Copy a directory tree from a remote repository.
+ *
+ * Copy from RA_SESSION:LOCATION, depth DEPTH, to WC_CTX:DST_ABSPATH.
+ *
+ * Create the directory DST_ABSPATH, if not present. Its parent should be
+ * already under version control in the WC and in a suitable state for
+ * scheduling the addition of a child.
+ *
+ * Ignore any incoming non-regular properties (entry-props, DAV/WC-props).
+ * Remove any incoming 'svn:mergeinfo' properties.
+ */
static svn_error_t *
copy_foreign_dir(svn_ra_session_t *ra_session,
svn_client__pathrev_t *location,
- svn_wc_context_t *wc_ctx,
const char *dst_abspath,
svn_depth_t depth,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
+ svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
- struct edit_baton_t eb;
- svn_delta_editor_t *editor = svn_delta_default_editor(scratch_pool);
+ const svn_delta_editor_t *editor;
+ void *eb;
const svn_delta_editor_t *wrapped_editor;
void *wrapped_baton;
const svn_ra_reporter3_t *reporter;
void *reporter_baton;
- eb.pool = scratch_pool;
- eb.anchor_abspath = dst_abspath;
-
- eb.wc_ctx = wc_ctx;
- eb.notify_func = notify_func;
- eb.notify_baton = notify_baton;
-
- editor->open_root = edit_open;
- editor->close_edit = edit_close;
-
- editor->add_directory = dir_add;
- editor->change_dir_prop = dir_change_prop;
- editor->close_directory = dir_close;
-
- editor->add_file = file_add;
- editor->change_file_prop = file_change_prop;
- editor->apply_textdelta = file_textdelta;
- editor->close_file = file_close;
+ SVN_ERR(svn_client__wc_editor_internal(&editor, &eb,
+ dst_abspath,
+ TRUE /*root_dir_add*/,
+ TRUE /*ignore_mergeinfo_changes*/,
+ notify_func, notify_baton,
+ ctx, scratch_pool));
SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
- editor, &eb,
+ editor, eb,
&wrapped_editor, &wrapped_baton,
scratch_pool));
@@ -544,11 +769,11 @@ svn_client__copy_foreign(const char *url
else
{
SVN_ERR(copy_foreign_dir(ra_session, loc,
- ctx->wc_ctx, dst_abspath,
+ dst_abspath,
depth,
ctx->notify_func2, ctx->notify_baton2,
ctx->cancel_func, ctx->cancel_baton,
- scratch_pool));
+ ctx, scratch_pool));
}
return SVN_NO_ERROR;