[prev in list] [next in list] [prev in thread] [next in thread]
List: subversion-commits
Subject: svn commit: r1831884 - in /subversion/trunk/subversion: include/svn_client.h libsvn_client/shelf.c s
From: julianfoad () apache ! org
Date: 2018-05-19 10:36:24
Message-ID: 20180519103624.9EECC3A00C5 () svn01-us-west ! apache ! org
[Download RAW message or body]
Author: julianfoad
Date: Sat May 19 10:36:24 2018
New Revision: 1831884
URL: http://svn.apache.org/viewvc?rev=1831884&view=rev
Log:
Shelving: Use whole-file storage and 3-way merge.
Use whole-file storage completely, instead of patch storage, and use
3-way merge to apply changes to a working file (and dir props).
Don't discriminate 'binary' files at storage time. When unshelving
(applying) a change, treat 'binary' files by the choose-one-or-the-other
method; raise a conflict if the working file differs from the stored
base.
In other words, this is closer to how a normal merge works.
TODO:
- The svn_client_shelf_export_patch() API is disabled for now.
- Handling of conflicts is weak.
* subversion/include/svn_client.h
(svn_client_shelf_test_apply_file): Avoid using the term 'patch' in the
doc string.
* subversion/libsvn_client/shelf.c
Implement storage of base and working text and props. Remove storage in
patch files.
* subversion/svn/shelf-cmd.c
Remove detection of 'reject' notifications from patching. Avoid using the
term 'patch' in doc strings.
* subversion/tests/cmdline/shelf_tests.py
(shelve_empty_deletes): Remove XFail, as now passes.
Modified:
subversion/trunk/subversion/include/svn_client.h
subversion/trunk/subversion/libsvn_client/shelf.c
subversion/trunk/subversion/svn/shelf-cmd.c
subversion/trunk/subversion/tests/cmdline/shelf_tests.py
Modified: subversion/trunk/subversion/include/svn_client.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_client.h?rev=1831884&r1=1831883&r2=1831884&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_client.h (original)
+++ subversion/trunk/subversion/include/svn_client.h Sat May 19 10:36:24 2018
@@ -7078,11 +7078,11 @@ svn_client_shelf_apply(svn_client_shelf_
svn_boolean_t dry_run,
apr_pool_t *scratch_pool);
-/** Test whether we can successfully apply the patch for @a file_relpath
+/** Test whether we can successfully apply the changes for @a file_relpath
* in @a shelf_version to the WC.
*
- * Try applying the shelf-version to the WC and set @a *conflict_p to
- * true if any conflict occurs, else to false.
+ * Set @a *conflict_p to true if the changes conflict with the WC state,
+ * else to false.
*
* If @a file_relpath is not found in @a shelf_version, set @a *conflict_p
* to FALSE.
Modified: subversion/trunk/subversion/libsvn_client/shelf.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/shelf.c?rev=1831884&r1=1831883&r2=1831884&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/shelf.c (original)
+++ subversion/trunk/subversion/libsvn_client/shelf.c Sat May 19 10:36:24 2018
@@ -114,7 +114,7 @@ shelf_name_from_filename(char **name,
return SVN_NO_ERROR;
}
-/* Set *PATCH_ABSPATH to the abspath of the file storage dir for SHELF
+/* Set *ABSPATH to the abspath of the file storage dir for SHELF
* version VERSION, no matter whether it exists.
*/
static svn_error_t *
@@ -154,7 +154,9 @@ shelf_version_create(svn_client_shelf_ve
return SVN_NO_ERROR;
}
-/* */
+/* Set *ABSPATH to the abspath of the metadata file for SHELF_VERSION
+ * node at RELPATH, no matter whether it exists.
+ */
static svn_error_t *
get_metadata_abspath(char **abspath,
svn_client_shelf_version_t *shelf_version,
@@ -168,7 +170,25 @@ get_metadata_abspath(char **abspath,
return SVN_NO_ERROR;
}
-/* */
+/* Set *ABSPATH to the abspath of the base text file for SHELF_VERSION
+ * node at RELPATH, no matter whether it exists.
+ */
+static svn_error_t *
+get_base_file_abspath(char **base_abspath,
+ svn_client_shelf_version_t *shelf_version,
+ const char *wc_relpath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ wc_relpath = apr_psprintf(scratch_pool, "%s.base", wc_relpath);
+ *base_abspath = svn_dirent_join(shelf_version->files_dir_abspath, wc_relpath,
+ result_pool);
+ return SVN_NO_ERROR;
+}
+
+/* Set *ABSPATH to the abspath of the working text file for SHELF_VERSION
+ * node at RELPATH, no matter whether it exists.
+ */
static svn_error_t *
get_working_file_abspath(char **work_abspath,
svn_client_shelf_version_t *shelf_version,
@@ -182,19 +202,35 @@ get_working_file_abspath(char **work_abs
return SVN_NO_ERROR;
}
-/* Set *PATCH_ABSPATH to the abspath of the patch file for SHELF_VERSION
+/* Set *ABSPATH to the abspath of the base props file for SHELF_VERSION
* node at RELPATH, no matter whether it exists.
*/
static svn_error_t *
-get_patch_abspath(const char **abspath,
- svn_client_shelf_version_t *shelf_version,
- const char *wc_relpath,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+get_base_props_abspath(char **base_abspath,
+ svn_client_shelf_version_t *shelf_version,
+ const char *wc_relpath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- wc_relpath = apr_psprintf(scratch_pool, "%s.patch", wc_relpath);
- *abspath = svn_dirent_join(shelf_version->files_dir_abspath, wc_relpath,
- result_pool);
+ wc_relpath = apr_psprintf(scratch_pool, "%s.base-props", wc_relpath);
+ *base_abspath = svn_dirent_join(shelf_version->files_dir_abspath, wc_relpath,
+ result_pool);
+ return SVN_NO_ERROR;
+}
+
+/* Set *ABSPATH to the abspath of the working props file for SHELF_VERSION
+ * node at RELPATH, no matter whether it exists.
+ */
+static svn_error_t *
+get_working_props_abspath(char **work_abspath,
+ svn_client_shelf_version_t *shelf_version,
+ const char *wc_relpath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ wc_relpath = apr_psprintf(scratch_pool, "%s.work-props", wc_relpath);
+ *work_abspath = svn_dirent_join(shelf_version->files_dir_abspath, wc_relpath,
+ result_pool);
return SVN_NO_ERROR;
}
@@ -581,48 +617,128 @@ note_shelved(apr_array_header_t *shelved
return SVN_NO_ERROR;
}
-/* Set *IS_BINARY to true iff the pristine or working version of
- * LOCAL_ABSPATH has a MIME-type that we regard as 'binary'.
+/* Read BASE_PROPS and WORK_PROPS from the WC, setting each to null if
+ * the node has no base or working version (respectively).
*/
static svn_error_t *
-is_binary_file(svn_boolean_t *is_binary,
- const char *local_abspath,
- svn_client_ctx_t *ctx,
- apr_pool_t *scratch_pool)
+read_props_from_wc(apr_hash_t **base_props,
+ apr_hash_t **work_props,
+ enum svn_wc_status_kind node_status,
+ const char *from_wc_abspath,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- apr_hash_t *props;
- const svn_string_t *value;
+ if (node_status != svn_wc_status_added)
+ SVN_ERR(svn_wc_get_pristine_props(base_props, ctx->wc_ctx, from_wc_abspath,
+ result_pool, scratch_pool));
+ else
+ *base_props = NULL;
+ if (node_status != svn_wc_status_deleted)
+ SVN_ERR(svn_wc_prop_list2(work_props, ctx->wc_ctx, from_wc_abspath,
+ result_pool, scratch_pool));
+ else
+ *work_props = NULL;
+ return SVN_NO_ERROR;
+}
- SVN_ERR(svn_wc_get_pristine_props(&props, ctx->wc_ctx,
- local_abspath,
- scratch_pool, scratch_pool));
- value = props ? svn_hash_gets(props, SVN_PROP_MIME_TYPE)
- : NULL;
- *is_binary = value && svn_mime_type_is_binary(value->data);
+/* Write BASE_PROPS and WORK_PROPS to storage in SHELF_VERSION:WC_RELPATH.
+ */
+static svn_error_t *
+write_props_to_shelf(svn_client_shelf_version_t *shelf_version,
+ const char *wc_relpath,
+ apr_hash_t *base_props,
+ apr_hash_t *work_props,
+ apr_pool_t *scratch_pool)
+{
+ char *stored_props_abspath;
+ svn_stream_t *stream;
+
+ if (base_props)
+ {
+ SVN_ERR(get_base_props_abspath(&stored_props_abspath,
+ shelf_version, wc_relpath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_stream_open_writable(&stream, stored_props_abspath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_hash_write2(base_props, stream, NULL, scratch_pool));
+ SVN_ERR(svn_stream_close(stream));
+ }
+
+ if (work_props)
+ {
+ SVN_ERR(get_working_props_abspath(&stored_props_abspath,
+ shelf_version, wc_relpath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_stream_open_writable(&stream, stored_props_abspath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_hash_write2(work_props, stream, NULL, scratch_pool));
+ SVN_ERR(svn_stream_close(stream));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Read BASE_PROPS and WORK_PROPS from storage in SHELF_VERSION:WC_RELPATH.
+ */
+static svn_error_t *
+read_props_from_shelf(apr_hash_t **base_props,
+ apr_hash_t **work_props,
+ enum svn_wc_status_kind node_status,
+ svn_client_shelf_version_t *shelf_version,
+ const char *wc_relpath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ char *stored_props_abspath;
+ svn_stream_t *stream;
- SVN_ERR(svn_wc_prop_get2(&value, ctx->wc_ctx, local_abspath,
- SVN_PROP_MIME_TYPE,
- scratch_pool, scratch_pool));
- if (value && svn_mime_type_is_binary(value->data))
- *is_binary = TRUE;
+ if (node_status != svn_wc_status_added)
+ {
+ *base_props = apr_hash_make(result_pool);
+ SVN_ERR(get_base_props_abspath(&stored_props_abspath,
+ shelf_version, wc_relpath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_stream_open_readonly(&stream, stored_props_abspath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_hash_read2(*base_props, stream, NULL, scratch_pool));
+ SVN_ERR(svn_stream_close(stream));
+ }
+ else
+ *base_props = NULL;
+
+ if (node_status != svn_wc_status_deleted)
+ {
+ *work_props = apr_hash_make(result_pool);
+ SVN_ERR(get_working_props_abspath(&stored_props_abspath,
+ shelf_version, wc_relpath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_stream_open_readonly(&stream, stored_props_abspath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_hash_read2(*work_props, stream, NULL, scratch_pool));
+ SVN_ERR(svn_stream_close(stream));
+ }
+ else
+ *work_props = NULL;
return SVN_NO_ERROR;
}
-/* Copy the WC working file at FROM_WC_ABSPATH to a storage location within
- * the shelf-version storage area in SHELF_VERSION.
- * If STORE_WHOLE_FILE is true, we will store the whole file (and we will
- * not be storing a patch of the file text).
+/* Store metadata for any node, and base and working files if it's a file.
+ *
+ * Copy the WC base and working files at FROM_WC_ABSPATH to the storage
+ * area in SHELF_VERSION.
*/
static svn_error_t *
store_file(const char *from_wc_abspath,
const char *wc_relpath,
svn_client_shelf_version_t *shelf_version,
const svn_wc_status3_t *status,
- svn_boolean_t store_whole_file,
+ svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
char *stored_abspath;
+ apr_hash_t *base_props, *work_props;
SVN_ERR(get_working_file_abspath(&stored_abspath,
shelf_version, wc_relpath,
@@ -633,10 +749,47 @@ store_file(const char *from_wc_abspath,
SVN_ERR(status_write(shelf_version, wc_relpath,
status, scratch_pool));
- if (store_whole_file)
+ /* properties */
+ SVN_ERR(read_props_from_wc(&base_props, &work_props,
+ status->node_status,
+ from_wc_abspath, ctx,
+ scratch_pool, scratch_pool));
+ SVN_ERR(write_props_to_shelf(shelf_version, wc_relpath,
+ base_props, work_props,
+ scratch_pool));
+
+ /* file text */
+ if (status->kind == svn_node_file)
{
- SVN_ERR(svn_io_copy_file(from_wc_abspath, stored_abspath,
- TRUE /*copy_perms*/, scratch_pool));
+ svn_stream_t *wc_base_stream;
+ svn_node_kind_t work_kind;
+
+ /* Copy the base file (copy-from base, if copied/moved), if present */
+ SVN_ERR(svn_wc_get_pristine_contents2(&wc_base_stream,
+ ctx->wc_ctx, from_wc_abspath,
+ scratch_pool, scratch_pool));
+ if (wc_base_stream)
+ {
+ char *stored_base_abspath;
+ svn_stream_t *stored_base_stream;
+
+ SVN_ERR(get_base_file_abspath(&stored_base_abspath,
+ shelf_version, wc_relpath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_stream_open_writable(&stored_base_stream,
+ stored_base_abspath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_stream_copy3(wc_base_stream, stored_base_stream,
+ NULL, NULL, scratch_pool));
+ }
+
+ /* Copy the working file, if present */
+ SVN_ERR(svn_io_check_path(from_wc_abspath, &work_kind, scratch_pool));
+ if (work_kind == svn_node_file)
+ {
+ SVN_ERR(svn_io_copy_file(from_wc_abspath, stored_abspath,
+ TRUE /*copy_perms*/, scratch_pool));
+ }
}
return SVN_NO_ERROR;
}
@@ -649,9 +802,6 @@ walk_callback(void *baton,
apr_pool_t *scratch_pool)
{
walk_baton_t *wb = baton;
- svn_opt_revision_t peg_revision = {svn_opt_revision_unspecified, {0}};
- svn_opt_revision_t start_revision = {svn_opt_revision_base, {0}};
- svn_opt_revision_t end_revision = {svn_opt_revision_working, {0}};
const char *wc_relpath = svn_dirent_skip_ancestor(wb->wc_root_abspath,
local_abspath);
@@ -662,68 +812,9 @@ walk_callback(void *baton,
case svn_wc_status_added:
case svn_wc_status_replaced:
{
- svn_boolean_t binary = FALSE;
- svn_boolean_t store_whole_file = FALSE;
-
- if (status->kind == svn_node_file)
- {
- SVN_ERR(is_binary_file(&binary, local_abspath,
- wb->ctx, scratch_pool));
- if (status->node_status == svn_wc_status_added
- || (binary && status->node_status != svn_wc_status_deleted))
- {
- store_whole_file = TRUE;
- }
- }
- /* Store all files (working version, for now) as complete files. */
+ /* Store metadata, and base and working versions if it's a file */
SVN_ERR(store_file(local_abspath, wc_relpath, wb->shelf_version,
- status, store_whole_file, scratch_pool));
- /* Store a patch */
- {
- const char *patch_abspath;
- apr_int32_t flag;
- apr_file_t *outfile;
- svn_stream_t *outstream;
- svn_stream_t *errstream;
-
- SVN_ERR(get_patch_abspath(&patch_abspath,
- wb->shelf_version, wc_relpath,
- scratch_pool, scratch_pool));
-
- /* Get streams for the output and any error output of the diff. */
- /* ### svn_stream_open_writable() doesn't work here: the buffering
- goes wrong so that diff headers appear after their hunks.
- For now, fix by opening the file without APR_BUFFERED. */
- flag = APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE;
- SVN_ERR(svn_io_file_open(&outfile, patch_abspath,
- flag, APR_FPROT_OS_DEFAULT, scratch_pool));
- outstream = svn_stream_from_aprfile2(outfile, FALSE /*disown*/,
- scratch_pool);
- errstream = svn_stream_empty(scratch_pool);
-
- SVN_ERR(svn_client_diff_peg7(NULL /*options*/,
- local_abspath,
- &peg_revision,
- &start_revision,
- &end_revision,
- wb->wc_root_abspath,
- svn_depth_empty,
- TRUE /*notice_ancestry*/,
- FALSE /*no_diff_added*/,
- FALSE /*no_diff_deleted*/,
- TRUE /*show_copies_as_adds*/,
- FALSE /*ignore_content_type*/,
- FALSE /*ignore_properties*/,
- store_whole_file /*properties_only*/,
- binary /*use_git_diff_format*/,
- FALSE /*pretty_print_mergeinfo*/,
- SVN_APR_LOCALE_CHARSET,
- outstream, errstream,
- NULL /*changelists*/,
- wb->ctx, scratch_pool));
- SVN_ERR(svn_stream_close(outstream));
- SVN_ERR(svn_stream_close(errstream));
- }
+ status, wb->ctx, scratch_pool));
wb->any_shelved = TRUE;
break;
}
@@ -837,11 +928,7 @@ wc_walk_status_multi(const apr_array_hea
*
* @a paths, @a depth, @a changelists: The selection of local paths to diff.
*
- * @a paths are relative to CWD (or absolute). Paths in patch are relative
- * to WC root (@a wc_root_abspath).
- *
- * ### TODO: Ignore any external diff cmd as configured in config file.
- * This might also solve the buffering problem.
+ * @a paths are relative to CWD (or absolute).
*/
static svn_error_t *
shelf_write_changes(svn_boolean_t *any_shelved,
@@ -968,7 +1055,7 @@ svn_client_shelf_delete(const char *name
SVN_ERR(svn_client_shelf_open_existing(&shelf, name,
local_abspath, ctx, scratch_pool));
- /* Remove the patches. */
+ /* Remove the versions. */
for (i = shelf->max_version; i > 0; i--)
{
SVN_ERR(shelf_version_delete(shelf, i, scratch_pool));
@@ -1053,6 +1140,147 @@ svn_client_shelf_paths_changed(apr_hash_
return SVN_NO_ERROR;
}
+/* Send a notification */
+static svn_error_t *
+send_notification(const char *local_abspath,
+ svn_wc_notify_action_t action,
+ svn_node_kind_t kind,
+ svn_wc_notify_state_t content_state,
+ svn_wc_notify_state_t prop_state,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ apr_pool_t *scratch_pool)
+{
+ if (notify_func)
+ {
+ svn_wc_notify_t *notify
+ = svn_wc_create_notify(local_abspath, action, scratch_pool);
+
+ notify->kind = kind;
+ notify->content_state = content_state;
+ notify->prop_state = prop_state;
+ notify_func(notify_baton, notify, scratch_pool);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Merge a shelved change into WC_ABSPATH.
+ */
+static svn_error_t *
+wc_file_merge(const char *wc_abspath,
+ const char *left_file,
+ const char *right_file,
+ /*const*/ apr_hash_t *left_props,
+ /*const*/ apr_hash_t *right_props,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc_notify_state_t property_state;
+ svn_boolean_t has_local_mods;
+ enum svn_wc_merge_outcome_t content_outcome;
+ const char *target_label, *left_label, *right_label;
+ apr_array_header_t *prop_changes;
+
+ /* xgettext: the '.working', '.merge-left' and '.merge-right' strings
+ are used to tag onto a file name in case of a merge conflict */
+ target_label = apr_psprintf(scratch_pool, _(".working"));
+ left_label = apr_psprintf(scratch_pool, _(".merge-left"));
+ right_label = apr_psprintf(scratch_pool, _(".merge-right"));
+
+ SVN_ERR(svn_prop_diffs(&prop_changes, right_props, left_props, scratch_pool));
+ SVN_ERR(svn_wc_text_modified_p2(&has_local_mods, ctx->wc_ctx,
+ wc_abspath, FALSE, scratch_pool));
+
+ /* Do property merge and text merge in one step so that keyword expansion
+ takes into account the new property values. */
+ SVN_WC__CALL_WITH_WRITE_LOCK(
+ svn_wc_merge5(&content_outcome, &property_state, ctx->wc_ctx,
+ left_file, right_file, wc_abspath,
+ left_label, right_label, target_label,
+ NULL, NULL, /*left, right conflict-versions*/
+ FALSE /*dry_run*/, NULL /*diff3_cmd*/,
+ NULL /*merge_options*/,
+ left_props, prop_changes,
+ NULL, NULL,
+ ctx->cancel_func, ctx->cancel_baton,
+ scratch_pool),
+ ctx->wc_ctx, wc_abspath,
+ FALSE /*lock_anchor*/, scratch_pool);
+
+ return SVN_NO_ERROR;
+}
+
+/* Merge a shelved change (of properties) into the dir at WC_ABSPATH.
+ */
+static svn_error_t *
+wc_dir_props_merge(const char *wc_abspath,
+ /*const*/ apr_hash_t *left_props,
+ /*const*/ apr_hash_t *right_props,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ apr_array_header_t *prop_changes;
+ svn_wc_notify_state_t property_state;
+
+ SVN_ERR(svn_prop_diffs(&prop_changes, right_props, left_props, scratch_pool));
+ SVN_WC__CALL_WITH_WRITE_LOCK(
+ svn_wc_merge_props3(&property_state, ctx->wc_ctx,
+ wc_abspath,
+ NULL, NULL, /*left, right conflict-versions*/
+ left_props, prop_changes,
+ FALSE /*dry_run*/,
+ NULL, NULL,
+ ctx->cancel_func, ctx->cancel_baton,
+ scratch_pool),
+ ctx->wc_ctx, wc_abspath,
+ FALSE /*lock_anchor*/, scratch_pool);
+
+ return SVN_NO_ERROR;
+}
+
+/* Apply a shelved "delete" to TO_WC_ABSPATH.
+ */
+static svn_error_t *
+wc_node_delete(const char *to_wc_abspath,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *scratch_pool)
+{
+ SVN_WC__CALL_WITH_WRITE_LOCK(
+ svn_wc_delete4(ctx->wc_ctx,
+ to_wc_abspath,
+ FALSE /*keep_local*/,
+ TRUE /*delete_unversioned_target*/,
+ NULL, NULL, NULL, NULL, /*cancel, notify*/
+ scratch_pool),
+ ctx->wc_ctx, to_wc_abspath,
+ TRUE /*lock_anchor*/, scratch_pool);
+ return SVN_NO_ERROR;
+}
+
+/* Apply a shelved "add" to TO_WC_ABSPATH.
+ * The node must already exist on disk, in a versioned parent dir.
+ */
+static svn_error_t *
+wc_node_add(const char *to_wc_abspath,
+ apr_hash_t *work_props,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *scratch_pool)
+{
+ /* If it was not already versioned, schedule the node for addition.
+ (Do not apply autoprops, because this isn't a user-facing "add" but
+ restoring a previously saved state.) */
+ SVN_WC__CALL_WITH_WRITE_LOCK(
+ svn_wc_add_from_disk3(ctx->wc_ctx,
+ to_wc_abspath, work_props,
+ FALSE /* skip checks */,
+ NULL, NULL, scratch_pool),
+ ctx->wc_ctx, to_wc_abspath,
+ TRUE /*lock_anchor*/, scratch_pool);
+ return SVN_NO_ERROR;
+}
+
/* Baton for apply_file_visitor(). */
struct apply_files_baton_t
{
@@ -1083,15 +1311,23 @@ apply_file_visitor(void *baton,
{
struct apply_files_baton_t *b = baton;
const char *wc_root_abspath = b->shelf_version->shelf->wc_root_abspath;
- char *stored_abspath;
+ char *stored_base_abspath, *stored_work_abspath;
+ apr_hash_t *base_props, *work_props;
const char *to_wc_abspath = svn_dirent_join(wc_root_abspath, relpath,
scratch_pool);
const char *to_dir_abspath = svn_dirent_dirname(to_wc_abspath, scratch_pool);
- svn_node_kind_t kind;
- SVN_ERR(get_working_file_abspath(&stored_abspath,
+ SVN_ERR(get_base_file_abspath(&stored_base_abspath,
+ b->shelf_version, relpath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(get_working_file_abspath(&stored_work_abspath,
b->shelf_version, relpath,
scratch_pool, scratch_pool));
+ SVN_ERR(read_props_from_shelf(&base_props, &work_props,
+ s->node_status,
+ b->shelf_version, relpath,
+ scratch_pool, scratch_pool));
+
if (b->file_relpath && strcmp(relpath, b->file_relpath) != 0)
{
return SVN_NO_ERROR;
@@ -1116,44 +1352,67 @@ apply_file_visitor(void *baton,
return SVN_NO_ERROR;
}
- /* If we stored a whole file, copy it into the WC and ensure it's versioned.
- ### TODO: merge it if possible
- ### TODO: handle deletes
- ### TODO: handle directories
- ### TODO: handle props
- */
- SVN_ERR(svn_io_check_path(stored_abspath, &kind, scratch_pool));
- if (kind == svn_node_file
- && s->kind == svn_node_file
- && s->node_status != svn_wc_status_deleted)
- {
- SVN_ERR(svn_io_make_dir_recursively(to_dir_abspath, scratch_pool));
- SVN_ERR(svn_io_copy_file(stored_abspath, to_wc_abspath,
- TRUE /*copy_perms*/, scratch_pool));
- /* If it was not already versioned, schedule the file for addition.
- (Do not apply autoprops, because this isn't a user-facing "add" but
- restoring a previously saved state.) */
- SVN_ERR(svn_client_add5(to_wc_abspath, svn_depth_infinity,
- TRUE /*force: ok if already versioned*/,
- TRUE /*no_ignore*/,
- TRUE /*no_autoprops*/,
- TRUE /*add_parents*/,
- b->ctx, scratch_pool));
+ /* Handle 'delete' and the delete half of 'replace' */
+ if (s->node_status == svn_wc_status_deleted
+ || s->node_status == svn_wc_status_replaced)
+ {
+ SVN_ERR(wc_node_delete(to_wc_abspath, b->ctx, scratch_pool));
+ SVN_ERR(send_notification(to_wc_abspath, svn_wc_notify_update_delete,
+ s->kind,
+ svn_wc_notify_state_inapplicable,
+ svn_wc_notify_state_inapplicable,
+ b->ctx->notify_func2, b->ctx->notify_baton2,
+ scratch_pool));
}
- /* Apply the changes stored in the per-node patch file */
+
+ /* If we can merge a file, do so. */
+ if (s->node_status == svn_wc_status_modified)
{
- const char *patch_abspath;
+ if (s->kind == svn_node_dir)
+ {
+ SVN_ERR(wc_dir_props_merge(to_wc_abspath,
+ base_props, work_props,
+ b->ctx, scratch_pool, scratch_pool));
+ }
+ else if (s->kind == svn_node_file)
+ {
+ SVN_ERR(wc_file_merge(to_wc_abspath,
+ stored_base_abspath, stored_work_abspath,
+ base_props, work_props,
+ b->ctx, scratch_pool));
+ }
+ SVN_ERR(send_notification(to_wc_abspath, svn_wc_notify_update_update,
+ s->kind,
+ (s->kind == svn_node_dir)
+ ? svn_wc_notify_state_inapplicable
+ : svn_wc_notify_state_merged,
+ (s->kind == svn_node_dir)
+ ? svn_wc_notify_state_merged
+ : svn_wc_notify_state_unknown,
+ b->ctx->notify_func2, b->ctx->notify_baton2,
+ scratch_pool));
+ }
- SVN_ERR(get_patch_abspath(&patch_abspath,
- b->shelf_version, relpath,
- scratch_pool, scratch_pool));
- SVN_ERR(svn_client_patch(patch_abspath,
- wc_root_abspath,
- FALSE /*dry_run*/, 0 /*strip*/,
- FALSE /*reverse*/,
- FALSE /*ignore_whitespace*/,
- TRUE /*remove_tempfiles*/, NULL, NULL,
- b->ctx, scratch_pool));
+ /* For an added file, copy it into the WC and ensure it's versioned. */
+ if (s->node_status == svn_wc_status_added)
+ {
+ if (s->kind == svn_node_dir)
+ {
+ SVN_ERR(svn_io_make_dir_recursively(to_wc_abspath, scratch_pool));
+ }
+ else if (s->kind == svn_node_file)
+ {
+ SVN_ERR(svn_io_make_dir_recursively(to_dir_abspath, scratch_pool));
+ SVN_ERR(svn_io_copy_file(stored_work_abspath, to_wc_abspath,
+ TRUE /*copy_perms*/, scratch_pool));
+ }
+ SVN_ERR(wc_node_add(to_wc_abspath, work_props, b->ctx, scratch_pool));
+ SVN_ERR(send_notification(to_wc_abspath, svn_wc_notify_update_add,
+ s->kind,
+ svn_wc_notify_state_inapplicable,
+ svn_wc_notify_state_inapplicable,
+ b->ctx->notify_func2, b->ctx->notify_baton2,
+ scratch_pool));
}
return SVN_NO_ERROR;
@@ -1174,18 +1433,8 @@ diff_visitor(void *baton,
svn_wc_status3_t *s,
apr_pool_t *scratch_pool)
{
- struct diff_baton_t *b = baton;
- const char *patch_abspath;
- svn_stream_t *instream;
-
- SVN_ERR(get_patch_abspath(&patch_abspath,
- b->shelf_version, relpath,
- scratch_pool, scratch_pool));
- SVN_ERR(svn_stream_open_readonly(&instream, patch_abspath,
- scratch_pool, scratch_pool));
- SVN_ERR(svn_stream_copy3(instream,
- svn_stream_disown(b->outstream, scratch_pool),
- NULL, NULL, scratch_pool));
+ /* ### TODO */
+
return SVN_NO_ERROR;
}
Modified: subversion/trunk/subversion/svn/shelf-cmd.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/shelf-cmd.c?rev=1831884&r1=1831883&r2=1831884&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/shelf-cmd.c (original)
+++ subversion/trunk/subversion/svn/shelf-cmd.c Sat May 19 10:36:24 2018
@@ -169,7 +169,7 @@ compare_shelf_infos_by_mtime(const svn_s
? -1 : (a_val->mtime > b_val->mtime) ? 1 : 0;
}
-/* Return a list of shelves sorted by patch file mtime, oldest first.
+/* Return a list of shelves sorted by their mtime, oldest first.
*/
static svn_error_t *
list_sorted_by_date(apr_array_header_t **list,
@@ -406,7 +406,7 @@ print_status(void *baton,
}
/* Set BATON->modified to true if TARGET has any local modification or
- * any status that means we should not attempt to patch it.
+ * any status that means we should not attempt to apply changes to it.
*
* A callback of type svn_client_status_func_t. */
static svn_error_t *
@@ -518,7 +518,7 @@ shelve(int *new_version_p,
: _("None of the local modifications could be shelved"));
}
- /* Un-apply the patch, if required. */
+ /* Un-apply the changes, if required. */
if (!keep_local)
{
SVN_ERR(svn_client_shelf_unapply(new_version,
@@ -591,27 +591,6 @@ test_apply(svn_client_shelf_version_t *s
return SVN_NO_ERROR;
}
-/* Intercept patch notifications to detect when there is a conflict */
-struct patch_notify_baton_t
-{
- svn_wc_notify_func2_t notify_func;
- void *notify_baton;
- svn_boolean_t rejects;
-};
-
-/* Intercept patch notifications to detect when there is a conflict */
-static void
-patch_notify(void *baton,
- const svn_wc_notify_t *notify,
- apr_pool_t *pool)
-{
- struct patch_notify_baton_t *b = baton;
-
- if (notify->action == svn_wc_notify_patch_rejected_hunk)
- b->rejects = TRUE;
- b->notify_func(b->notify_baton, notify, pool);
-}
-
/** Restore/unshelve a given or newest version of changes.
*
* Restore local modifications from shelf @a name version @a arg,
@@ -635,7 +614,6 @@ shelf_restore(const char *name,
apr_time_t time_now = apr_time_now();
svn_client_shelf_t *shelf;
svn_client_shelf_version_t *shelf_version;
- struct patch_notify_baton_t b;
SVN_ERR(svn_client_shelf_open_existing(&shelf, name, local_abspath,
ctx, scratch_pool));
@@ -670,22 +648,8 @@ shelf_restore(const char *name,
"path would conflict"));
}
- b.rejects = FALSE;
- b.notify_func = ctx->notify_func2;
- b.notify_baton = ctx->notify_baton2;
- ctx->notify_func2 = patch_notify;
- ctx->notify_baton2 = &b;
-
SVN_ERR(svn_client_shelf_apply(shelf_version,
dry_run, scratch_pool));
- ctx->notify_func2 = b.notify_func;
- ctx->notify_baton2 = b.notify_baton;
-
- if (b.rejects)
- {
- return svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL,
- _("Unshelve/restore failed due to conflicts"));
- }
if (! dry_run)
{
Modified: subversion/trunk/subversion/tests/cmdline/shelf_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/shelf_tests.py?rev=1831884&r1=1831883&r2=1831884&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/shelf_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/shelf_tests.py Sat May 19 10:36:24 2018
@@ -152,7 +152,6 @@ def shelve_empty_adds(sbox):
#----------------------------------------------------------------------
-@XFail()
def shelve_empty_deletes(sbox):
"shelve empty deletes"
sbox.build(empty=True)
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic