Modified: subversion/branches/better-pristines/subversion/svn/cl.h
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/svn/cl.h?rev=1826407&r1=1826406&r2=1826407&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/svn/cl.h (original)
+++ subversion/branches/better-pristines/subversion/svn/cl.h Sat Mar 10 15:27:24 2018
@@ -256,7 +256,7 @@ typedef struct svn_cl__opt_state_t
const char *show_item; /* print only the given item */
svn_boolean_t adds_as_modification; /* update 'add vs add' no tree conflict */
svn_boolean_t vacuum_pristines; /* remove unreferenced pristines */
- svn_boolean_t list;
+ svn_boolean_t drop; /* drop shelf after successful unshelve */
svn_version_t *compatible_version; /* working copy compatibility version */
} svn_cl__opt_state_t;
@@ -308,6 +308,7 @@ svn_opt_subcommand_t
svn_cl__shelf_diff,
svn_cl__shelf_drop,
svn_cl__shelf_list,
+ svn_cl__shelf_list_by_paths,
svn_cl__shelf_log,
svn_cl__shelf_save,
svn_cl__shelf_shelve,
@@ -320,7 +321,7 @@ svn_opt_subcommand_t
/* See definition in svn.c for documentation. */
-extern const svn_opt_subcommand_desc2_t svn_cl__cmd_table[];
+extern const svn_opt_subcommand_desc3_t svn_cl__cmd_table[];
/* See definition in svn.c for documentation. */
extern const int svn_cl__global_options[];
Modified: subversion/branches/better-pristines/subversion/svn/help-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/svn/help-cmd.c?rev=1826407&r1=1826406&r2=1826407&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/svn/help-cmd.c (original)
+++ subversion/branches/better-pristines/subversion/svn/help-cmd.c Sat Mar 10 15:27:24 2018
@@ -203,7 +203,7 @@ svn_cl__help(apr_getopt_t *os,
svn_stringbuf_appendcstr(version_footer, "* KWallet (KDE)\n");
#endif
- return svn_opt_print_help4(os,
+ return svn_opt_print_help5(os,
"svn", /* ### erm, derive somehow? */
opt_state ? opt_state->version : FALSE,
opt_state ? opt_state->quiet : FALSE,
Modified: subversion/branches/better-pristines/subversion/svn/shelf-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/svn/shelf-cmd.c?rev=1826407&r1=1826406&r2=1826407&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/svn/shelf-cmd.c (original)
+++ subversion/branches/better-pristines/subversion/svn/shelf-cmd.c Sat Mar 10 15:27:24 2018
@@ -28,7 +28,9 @@
#include "svn_client.h"
#include "svn_error_codes.h"
#include "svn_error.h"
+#include "svn_hash.h"
#include "svn_path.h"
+#include "svn_props.h"
#include "svn_utf.h"
#include "cl.h"
@@ -53,6 +55,79 @@ get_next_argument(const char **arg,
return SVN_NO_ERROR;
}
+/* Parse the remaining arguments as paths relative to a WC.
+ *
+ * TARGETS are relative to current working directory.
+ *
+ * Set *targets_by_wcroot to a hash mapping (char *)wcroot_abspath to
+ * (apr_array_header_t *)array of relpaths relative to that WC root.
+ */
+static svn_error_t *
+targets_relative_to_wcs(apr_hash_t **targets_by_wcroot_p,
+ apr_array_header_t *targets,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_t *targets_by_wcroot = apr_hash_make(result_pool);
+ int i;
+
+ /* Make each target relative to the WC root. */
+ for (i = 0; i < targets->nelts; i++)
+ {
+ const char *target = APR_ARRAY_IDX(targets, i, const char *);
+ const char *wcroot_abspath;
+ apr_array_header_t *paths;
+
+ SVN_ERR(svn_dirent_get_absolute(&target, target, result_pool));
+ SVN_ERR(svn_client_get_wc_root(&wcroot_abspath, target,
+ ctx, result_pool, scratch_pool));
+ paths = svn_hash_gets(targets_by_wcroot, wcroot_abspath);
+ if (! paths)
+ {
+ paths = apr_array_make(result_pool, 0, sizeof(char *));
+ svn_hash_sets(targets_by_wcroot, wcroot_abspath, paths);
+ }
+ target = svn_dirent_skip_ancestor(wcroot_abspath, target);
+
+ if (target)
+ APR_ARRAY_PUSH(paths, const char *) = target;
+ }
+ *targets_by_wcroot_p = targets_by_wcroot;
+ return SVN_NO_ERROR;
+}
+
+/* Return targets relative to a WC. Error if they refer to more than one WC. */
+static svn_error_t *
+targets_relative_to_a_wc(const char **wc_root_abspath_p,
+ apr_array_header_t **paths_p,
+ apr_getopt_t *os,
+ const apr_array_header_t *known_targets,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ apr_array_header_t *targets;
+ apr_hash_t *targets_by_wcroot;
+ apr_hash_index_t *hi;
+
+ SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
+ known_targets,
+ ctx, FALSE, result_pool));
+ svn_opt_push_implicit_dot_target(targets, result_pool);
+
+ SVN_ERR(targets_relative_to_wcs(&targets_by_wcroot, targets,
+ ctx, result_pool, scratch_pool));
+ if (apr_hash_count(targets_by_wcroot) != 1)
+ return svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("All targets must be in the same WC"));
+
+ hi = apr_hash_first(scratch_pool, targets_by_wcroot);
+ *wc_root_abspath_p = apr_hash_this_key(hi);
+ *paths_p = apr_hash_this_val(hi);
+ return SVN_NO_ERROR;
+}
+
/* Return a human-friendly description of DURATION.
*/
static char *
@@ -516,8 +591,31 @@ shelve(int *new_version_p,
dry_run, scratch_pool));
}
- SVN_ERR(svn_client_shelf_set_log_message(shelf, revprop_table,
- dry_run, scratch_pool));
+ /* Fetch the log message and any other revprops */
+ if (ctx->log_msg_func3)
+ {
+ const char *tmp_file;
+ apr_array_header_t *commit_items
+ = apr_array_make(scratch_pool, 1, sizeof(void *));
+ const char *message = "";
+
+ SVN_ERR(ctx->log_msg_func3(&message, &tmp_file, commit_items,
+ ctx->log_msg_baton3, scratch_pool));
+ /* Abort the shelving if the log message callback requested so. */
+ if (! message)
+ return SVN_NO_ERROR;
+
+ if (message && !dry_run)
+ {
+ svn_string_t *propval = svn_string_create(message, scratch_pool);
+
+ if (! revprop_table)
+ revprop_table = apr_hash_make(scratch_pool);
+ svn_hash_sets(revprop_table, SVN_PROP_REVISION_LOG, propval);
+ }
+ }
+
+ SVN_ERR(svn_client_shelf_revprop_set_all(shelf, revprop_table, scratch_pool));
if (new_version_p)
*new_version_p = shelf->max_version;
@@ -583,6 +681,27 @@ check_no_modified_paths(const char *path
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,
@@ -603,6 +722,7 @@ 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));
@@ -631,8 +751,22 @@ shelf_restore(const char *name,
SVN_ERR(check_no_modified_paths(shelf->wc_root_abspath,
shelf_version, quiet, ctx, scratch_pool));
+ 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)
{
@@ -859,6 +993,12 @@ svn_cl__shelf_unshelve(apr_getopt_t *os,
opt_state->dry_run, opt_state->quiet,
local_abspath, ctx, scratch_pool));
+ if (opt_state->drop)
+ {
+ SVN_ERR(shelf_drop(name, local_abspath,
+ opt_state->dry_run, opt_state->quiet,
+ ctx, scratch_pool));
+ }
return SVN_NO_ERROR;
}
@@ -885,6 +1025,112 @@ svn_cl__shelf_list(apr_getopt_t *os,
return SVN_NO_ERROR;
}
+/* "svn shelf-list-by-paths [PATH...]"
+ *
+ * TARGET_RELPATHS are all within the same WC, relative to WC_ROOT_ABSPATH.
+ */
+static svn_error_t *
+shelf_list_by_paths(apr_array_header_t *target_relpaths,
+ const char *wc_root_abspath,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *scratch_pool)
+{
+ apr_array_header_t *shelves;
+ apr_hash_t *paths_to_shelf_name = apr_hash_make(scratch_pool);
+ apr_array_header_t *array;
+ int i;
+
+ SVN_ERR(list_sorted_by_date(&shelves,
+ wc_root_abspath, ctx, scratch_pool));
+
+ /* Check paths are valid */
+ for (i = 0; i < target_relpaths->nelts; i++)
+ {
+ char *target_relpath = APR_ARRAY_IDX(target_relpaths, i, char *);
+
+ if (svn_path_is_url(target_relpath))
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("'%s' is not a local path"), target_relpath);
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(target_relpath));
+ }
+
+ /* Find the most recent shelf for each affected path */
+ for (i = 0; i < shelves->nelts; i++)
+ {
+ svn_sort__item_t *item = &APR_ARRAY_IDX(shelves, i, svn_sort__item_t);
+ const char *name = item->key;
+ svn_client_shelf_t *shelf;
+ svn_client_shelf_version_t *shelf_version;
+ apr_hash_t *shelf_paths;
+ int j;
+
+ SVN_ERR(svn_client_shelf_open_existing(&shelf,
+ name, wc_root_abspath,
+ ctx, scratch_pool));
+ SVN_ERR(svn_client_shelf_version_open(&shelf_version,
+ shelf, shelf->max_version,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_client_shelf_paths_changed(&shelf_paths,
+ shelf_version,
+ scratch_pool, scratch_pool));
+ for (j = 0; j < target_relpaths->nelts; j++)
+ {
+ char *target_relpath = APR_ARRAY_IDX(target_relpaths, j, char *);
+ apr_hash_index_t *hi;
+
+ for (hi = apr_hash_first(scratch_pool, shelf_paths);
+ hi; hi = apr_hash_next(hi))
+ {
+ const char *shelf_path = apr_hash_this_key(hi);
+
+ if (svn_relpath_skip_ancestor(target_relpath, shelf_path))
+ {
+ if (! svn_hash_gets(paths_to_shelf_name, shelf_path))
+ {
+ svn_hash_sets(paths_to_shelf_name, shelf_path, shelf->name);
+ }
+ }
+ }
+ }
+ }
+
+ /* Print the results. */
+ array = svn_sort__hash(paths_to_shelf_name,
+ svn_sort_compare_items_as_paths,
+ scratch_pool);
+ for (i = 0; i < array->nelts; i++)
+ {
+ svn_sort__item_t *item = &APR_ARRAY_IDX(array, i, svn_sort__item_t);
+ const char *path = item->key;
+ const char *name = item->value;
+
+ SVN_ERR(svn_cmdline_printf(scratch_pool, "%-20.20s %s\n",
+ name,
+ svn_dirent_local_style(path, scratch_pool)));
+ }
+ return SVN_NO_ERROR;
+}
+
+/* This implements the `svn_opt_subcommand_t' interface. */
+svn_error_t *
+svn_cl__shelf_list_by_paths(apr_getopt_t *os,
+ void *baton,
+ apr_pool_t *pool)
+{
+ svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
+ svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
+ const char *wc_root_abspath;
+ apr_array_header_t *targets;
+
+ /* Parse the remaining arguments as paths. */
+ SVN_ERR(targets_relative_to_a_wc(&wc_root_abspath, &targets,
+ os, opt_state->targets,
+ ctx, pool, pool));
+
+ SVN_ERR(shelf_list_by_paths(targets, wc_root_abspath, ctx, pool));
+ return SVN_NO_ERROR;
+}
+
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__shelf_diff(apr_getopt_t *os,
|