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/06/07 18:17:53 UTC

svn commit: r1833135 - in /subversion/trunk/subversion: include/svn_client.h libsvn_client/shelf.c svn/shelf-cmd.c

Author: julianfoad
Date: Thu Jun  7 18:17:53 2018
New Revision: 1833135

URL: http://svn.apache.org/viewvc?rev=1833135&view=rev
Log:
Shelving: better reporting of shelved and not-shelved changes.

* subversion/include/svn_client.h,
  subversion/libsvn_client/shelf.c
  (svn_client_shelf_save_new_version3): New.
  (svn_client_shelf_save_new_version2): Deprecate.

* subversion/svn/shelf-cmd.c
  Use callbacks to report shelved and not-shelved paths.

Modified:
    subversion/trunk/subversion/include/svn_client.h
    subversion/trunk/subversion/libsvn_client/shelf.c
    subversion/trunk/subversion/svn/shelf-cmd.c

Modified: subversion/trunk/subversion/include/svn_client.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_client.h?rev=1833135&r1=1833134&r2=1833135&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_client.h (original)
+++ subversion/trunk/subversion/include/svn_client.h Thu Jun  7 18:17:53 2018
@@ -6954,21 +6954,51 @@ svn_client_shelf_delete(const char *name
 /** Save the local modifications found by @a paths, @a depth,
  * @a changelists as a new version of @a shelf.
  *
- * Return the new shelf-version in @a *new_version_p.
+ * If any paths are shelved, create a new shelf-version and return the new
+ * shelf-version in @a *new_version_p, else set @a *new_version_p to null.
+ * @a new_version_p may be null if that output is not wanted; a new shelf-
+ * version is still saved and may be found through @a shelf.
  *
  * @a paths are relative to the CWD, or absolute.
  *
+ * For each successfully shelved path: call @a shelved_func (if not null)
+ * with @a shelved_baton.
+ *
+ * If any paths cannot be shelved: if @a not_shelved_func is given, call
+ * it with @a not_shelved_baton for each such path, and still create a new
+ * shelf-version if any paths are shelved.
+ *
+ * This function does not revert the changes from the WC; use
+ * svn_client_shelf_unapply() for that.
+ *
+ * @since New in 1.X.
+ * @warning EXPERIMENTAL.
+ */
+SVN_EXPERIMENTAL
+svn_error_t *
+svn_client_shelf_save_new_version3(svn_client_shelf_version_t **new_version_p,
+                                   svn_client_shelf_t *shelf,
+                                   const apr_array_header_t *paths,
+                                   svn_depth_t depth,
+                                   const apr_array_header_t *changelists,
+                                   svn_client_status_func_t shelved_func,
+                                   void *shelved_baton,
+                                   svn_client_status_func_t not_shelved_func,
+                                   void *not_shelved_baton,
+                                   apr_pool_t *scratch_pool);
+
+/** @deprecated Use svn_client_shelf_save_new_version3() instead.
+ *
+ * If any paths cannot be shelved, throw an error.
+ *
  * If there are no local modifications in the specified locations, do not
  * create a new version of @a shelf; set @a *new_version_p to null and
  * return SVN_NO_ERROR. In this case @a shelf->max_version after the call
  * is the same as before the call.
  *
- * @a *new_version_p may be null if that output is not wanted.
- *
- * @since New in 1.X.
  * @warning EXPERIMENTAL.
  */
-SVN_EXPERIMENTAL
+SVN_DEPRECATED
 svn_error_t *
 svn_client_shelf_save_new_version2(svn_client_shelf_version_t **new_version_p,
                                    svn_client_shelf_t *shelf,

Modified: subversion/trunk/subversion/libsvn_client/shelf.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/shelf.c?rev=1833135&r1=1833134&r2=1833135&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/shelf.c (original)
+++ subversion/trunk/subversion/libsvn_client/shelf.c Thu Jun  7 18:17:53 2018
@@ -728,23 +728,61 @@ svn_client_shelf_version_status_walk(svn
   return SVN_NO_ERROR;
 }
 
-/* A baton for use with walk_callback(). */
+/* A baton for use with write_changes_visitor(). */
 typedef struct write_changes_baton_t {
   const char *wc_root_abspath;
   svn_client_shelf_version_t *shelf_version;
   svn_client_ctx_t *ctx;
   svn_boolean_t any_shelved;  /* were any paths successfully shelved? */
-  apr_array_header_t *unshelvable;  /* paths unshelvable */
+  svn_client_status_func_t was_shelved_func;
+  void *was_shelved_baton;
+  svn_client_status_func_t was_not_shelved_func;
+  void *was_not_shelved_baton;
   apr_pool_t *pool;  /* pool for data in 'unshelvable', etc. */
 } write_changes_baton_t;
 
 /*  */
 static svn_error_t *
-note_shelved(apr_array_header_t *shelved,
-             const char *relpath,
-             apr_pool_t *pool)
+notify_shelved(write_changes_baton_t *wb,
+               const char *wc_relpath,
+               const char *local_abspath,
+               const svn_wc_status3_t *wc_status,
+               apr_pool_t *scratch_pool)
+{
+  if (wb->was_shelved_func)
+    {
+      svn_client_status_t *cst;
+
+      SVN_ERR(svn_client__create_status(&cst, wb->ctx->wc_ctx, local_abspath,
+                                        wc_status,
+                                        scratch_pool, scratch_pool));
+      SVN_ERR(wb->was_shelved_func(wb->was_shelved_baton,
+                                   wc_relpath, cst, scratch_pool));
+    }
+
+  wb->any_shelved = TRUE;
+  return SVN_NO_ERROR;
+}
+
+/*  */
+static svn_error_t *
+notify_not_shelved(write_changes_baton_t *wb,
+                   const char *wc_relpath,
+                   const char *local_abspath,
+                   const svn_wc_status3_t *wc_status,
+                   apr_pool_t *scratch_pool)
 {
-  APR_ARRAY_PUSH(shelved, const char *) = apr_pstrdup(pool, relpath);
+  if (wb->was_not_shelved_func)
+    {
+      svn_client_status_t *cst;
+
+      SVN_ERR(svn_client__create_status(&cst, wb->ctx->wc_ctx, local_abspath,
+                                        wc_status,
+                                        scratch_pool, scratch_pool));
+      SVN_ERR(wb->was_not_shelved_func(wb->was_not_shelved_baton,
+                                       wc_relpath, cst, scratch_pool));
+    }
+
   return SVN_NO_ERROR;
 }
 
@@ -944,7 +982,8 @@ write_changes_visitor(void *baton,
         if (status->kind != svn_node_file
             || status->copied)
           {
-            SVN_ERR(note_shelved(wb->unshelvable, wc_relpath, wb->pool));
+            SVN_ERR(notify_not_shelved(wb, wc_relpath, local_abspath,
+                                       status, scratch_pool));
             break;
           }
         /* fall through */
@@ -953,7 +992,8 @@ write_changes_visitor(void *baton,
         /* Store metadata, and base and working versions if it's a file */
         SVN_ERR(store_file(local_abspath, wc_relpath, wb->shelf_version,
                            status, wb->ctx, scratch_pool));
-        wb->any_shelved = TRUE;
+        SVN_ERR(notify_shelved(wb, wc_relpath, local_abspath,
+                               status, scratch_pool));
         break;
       }
 
@@ -964,14 +1004,16 @@ write_changes_visitor(void *baton,
                 && status->prop_status != svn_wc_status_none))
           {
             /* Incomplete, but local modifications */
-            SVN_ERR(note_shelved(wb->unshelvable, wc_relpath, wb->pool));
+            SVN_ERR(notify_not_shelved(wb, wc_relpath, local_abspath,
+                                       status, scratch_pool));
           }
         break;
 
       case svn_wc_status_conflicted:
       case svn_wc_status_missing:
       case svn_wc_status_obstructed:
-        SVN_ERR(note_shelved(wb->unshelvable, wc_relpath, wb->pool));
+        SVN_ERR(notify_not_shelved(wb, wc_relpath, local_abspath,
+                                   status, scratch_pool));
         break;
 
       case svn_wc_status_normal:
@@ -1070,11 +1112,14 @@ wc_walk_status_multi(const apr_array_hea
  */
 static svn_error_t *
 shelf_write_changes(svn_boolean_t *any_shelved,
-                    apr_array_header_t **unshelvable,
                     svn_client_shelf_version_t *shelf_version,
                     const apr_array_header_t *paths,
                     svn_depth_t depth,
                     const apr_array_header_t *changelists,
+                    svn_client_status_func_t shelved_func,
+                    void *shelved_baton,
+                    svn_client_status_func_t not_shelved_func,
+                    void *not_shelved_baton,
                     const char *wc_root_abspath,
                     svn_client_ctx_t *ctx,
                     apr_pool_t *result_pool,
@@ -1086,7 +1131,10 @@ shelf_write_changes(svn_boolean_t *any_s
   wb.shelf_version = shelf_version;
   wb.ctx = ctx;
   wb.any_shelved = FALSE;
-  wb.unshelvable = apr_array_make(result_pool, 0, sizeof(char *));
+  wb.was_shelved_func = shelved_func;
+  wb.was_shelved_baton = shelved_baton;
+  wb.was_not_shelved_func = not_shelved_func;
+  wb.was_not_shelved_baton = not_shelved_baton;
   wb.pool = result_pool;
 
   /* Walk the WC */
@@ -1095,7 +1143,6 @@ shelf_write_changes(svn_boolean_t *any_s
                                ctx, scratch_pool));
 
   *any_shelved = wb.any_shelved;
-  *unshelvable = wb.unshelvable;
   return SVN_NO_ERROR;
 }
 
@@ -1682,35 +1729,31 @@ svn_client_shelf_export_patch(svn_client
 }
 
 svn_error_t *
-svn_client_shelf_save_new_version2(svn_client_shelf_version_t **new_version_p,
+svn_client_shelf_save_new_version3(svn_client_shelf_version_t **new_version_p,
                                    svn_client_shelf_t *shelf,
                                    const apr_array_header_t *paths,
                                    svn_depth_t depth,
                                    const apr_array_header_t *changelists,
+                                   svn_client_status_func_t shelved_func,
+                                   void *shelved_baton,
+                                   svn_client_status_func_t not_shelved_func,
+                                   void *not_shelved_baton,
                                    apr_pool_t *scratch_pool)
 {
   int next_version = shelf->max_version + 1;
   svn_client_shelf_version_t *new_shelf_version;
   svn_boolean_t any_shelved;
-  apr_array_header_t *unshelvable;
 
   SVN_ERR(shelf_version_create(&new_shelf_version,
                                shelf, next_version, scratch_pool));
-  SVN_ERR(shelf_write_changes(&any_shelved, &unshelvable,
+  SVN_ERR(shelf_write_changes(&any_shelved,
                               new_shelf_version,
                               paths, depth, changelists,
+                              shelved_func, shelved_baton,
+                              not_shelved_func, not_shelved_baton,
                               shelf->wc_root_abspath,
                               shelf->ctx, scratch_pool, scratch_pool));
 
-  if (unshelvable->nelts > 0)
-    {
-      return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
-                               Q_("%d path could not be shelved",
-                                  "%d paths could not be shelved",
-                                  unshelvable->nelts),
-                               unshelvable->nelts);
-    }
-
   if (any_shelved)
     {
       shelf->max_version = next_version;
@@ -1728,6 +1771,66 @@ svn_client_shelf_save_new_version2(svn_c
   return SVN_NO_ERROR;
 }
 
+/* A compatibility callback for counting not-shelved paths. */
+static svn_error_t *
+was_not_shelved(void *baton,
+                const char *path,
+                const svn_client_status_t *status,
+                apr_pool_t *scratch_pool)
+{
+  int *num_paths_not_shelved = baton;
+
+  ++(*num_paths_not_shelved);
+  return SVN_NO_ERROR;
+}
+
+/* A compatibility wrapper. */
+static svn_error_t *
+save_new_version2(svn_client_shelf_version_t **new_version_p,
+                  svn_client_shelf_t *shelf,
+                  const apr_array_header_t *paths,
+                  svn_depth_t depth,
+                  const apr_array_header_t *changelists,
+                  apr_pool_t *scratch_pool)
+{
+  svn_client_shelf_version_t *previous_version;
+  int num_paths_not_shelved = 0;
+
+  SVN_ERR(svn_client_shelf_get_newest_version(&previous_version, shelf,
+                                              scratch_pool, scratch_pool));
+  SVN_ERR(svn_client_shelf_save_new_version3(new_version_p, shelf,
+                                             paths, depth, changelists,
+                                             NULL, NULL,
+                                             was_not_shelved, &num_paths_not_shelved,
+                                             scratch_pool));
+  if (num_paths_not_shelved)
+    {
+      SVN_ERR(svn_client_shelf_delete_newer_versions(shelf, previous_version,
+                                                     scratch_pool));
+      return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+                               Q_("%d path could not be shelved",
+                                  "%d paths could not be shelved",
+                                  num_paths_not_shelved),
+                               num_paths_not_shelved);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_shelf_save_new_version2(svn_client_shelf_version_t **new_version_p,
+                                   svn_client_shelf_t *shelf,
+                                   const apr_array_header_t *paths,
+                                   svn_depth_t depth,
+                                   const apr_array_header_t *changelists,
+                                   apr_pool_t *scratch_pool)
+{
+  SVN_ERR(save_new_version2(new_version_p, shelf,
+                            paths, depth, changelists,
+                            scratch_pool));
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_client_shelf_save_new_version(svn_client_shelf_t *shelf,
                                   const apr_array_header_t *paths,
@@ -1735,9 +1838,9 @@ svn_client_shelf_save_new_version(svn_cl
                                   const apr_array_header_t *changelists,
                                   apr_pool_t *scratch_pool)
 {
-  SVN_ERR(svn_client_shelf_save_new_version2(NULL, shelf,
-                                             paths, depth, changelists,
-                                             scratch_pool));
+  SVN_ERR(save_new_version2(NULL, shelf,
+                            paths, depth, changelists,
+                            scratch_pool));
   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=1833135&r1=1833134&r2=1833135&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/shelf-cmd.c (original)
+++ subversion/trunk/subversion/svn/shelf-cmd.c Thu Jun  7 18:17:53 2018
@@ -331,45 +331,6 @@ name_of_youngest(const char **name_p,
   return SVN_NO_ERROR;
 }
 
-/*
- * PATHS are relative to WC_ROOT_ABSPATH.
- */
-static svn_error_t *
-run_status_on_wc_paths(const char *paths_base_abspath,
-                       const apr_array_header_t *paths,
-                       svn_depth_t depth,
-                       const apr_array_header_t *changelists,
-                       svn_client_status_func_t status_func,
-                       void *status_baton,
-                       svn_client_ctx_t *ctx,
-                       apr_pool_t *scratch_pool)
-{
-  int i;
-
-  for (i = 0; i < paths->nelts; i++)
-    {
-      const char *path = APR_ARRAY_IDX(paths, i, const char *);
-      const char *abspath = svn_dirent_join(paths_base_abspath, path,
-                                            scratch_pool);
-
-      SVN_ERR(svn_client_status6(NULL /*result_rev*/,
-                                 ctx, abspath,
-                                 NULL /*revision*/,
-                                 depth,
-                                 FALSE /*get_all*/,
-                                 FALSE /*check_out_of_date*/,
-                                 TRUE /*check_working_copy*/,
-                                 TRUE /*no_ignore*/,
-                                 TRUE /*ignore_externals*/,
-                                 FALSE /*depth_as_sticky*/,
-                                 changelists,
-                                 status_func, status_baton,
-                                 scratch_pool));
-    }
-
-  return SVN_NO_ERROR;
-}
-
 struct status_baton
 {
   /* These fields correspond to the ones in the
@@ -377,9 +338,9 @@ struct status_baton
   const char *target_abspath;
   const char *target_path;
 
-  const char *header;
-  svn_boolean_t quiet;  /* don't display statuses while checking them */
-  svn_boolean_t modified;  /* set to TRUE when any modification is found */
+  svn_boolean_t quiet;  /* don't display statuses while shelving them */
+  int num_paths_shelved;
+  int num_paths_not_shelved;
   svn_client_ctx_t *ctx;
 };
 
@@ -388,7 +349,7 @@ static svn_error_t *
 print_status(void *baton,
              const char *path,
              const svn_client_status_t *status,
-             apr_pool_t *pool)
+             apr_pool_t *scratch_pool)
 {
   struct status_baton *sb = baton;
   unsigned int conflicts;
@@ -402,37 +363,39 @@ print_status(void *baton,
                               FALSE /*repos_locks*/,
                               &conflicts, &conflicts, &conflicts,
                               sb->ctx,
-                              pool);
+                              scratch_pool);
 }
 
-/* Set BATON->modified to true if TARGET has any local modification or
- * any status that means we should not attempt to apply changes to it.
- *
- * A callback of type svn_client_status_func_t. */
+/* A callback function for shelved paths. */
 static svn_error_t *
-modification_checker(void *baton,
-                     const char *target,
-                     const svn_client_status_t *status,
-                     apr_pool_t *scratch_pool)
+was_shelved(void *baton,
+            const char *path,
+            const svn_client_status_t *status,
+            apr_pool_t *scratch_pool)
 {
   struct status_baton *sb = baton;
 
-  if (status->conflicted
-      || ! (status->node_status == svn_wc_status_none
-            || status->node_status == svn_wc_status_unversioned
-            || status->node_status == svn_wc_status_normal))
+  if (!sb->quiet)
     {
-      if (!sb->quiet)
-        {
-          if (!sb->modified)  /* print the header only once */
-            {
-              SVN_ERR(svn_cmdline_printf(scratch_pool, "%s", sb->header));
-            }
-          SVN_ERR(print_status(baton, target, status, scratch_pool));
-        }
-
-      sb->modified = TRUE;
+      SVN_ERR(print_status(baton, path, status, scratch_pool));
     }
+
+  ++sb->num_paths_shelved;
+  return SVN_NO_ERROR;
+}
+
+/* A callback function for not-shelved paths. */
+static svn_error_t *
+was_not_shelved(void *baton,
+                const char *path,
+                const svn_client_status_t *status,
+                apr_pool_t *scratch_pool)
+{
+  struct status_baton *sb = baton;
+
+  SVN_ERR(print_status(baton, path, status, scratch_pool));
+  SVN_ERR(svn_cmdline_printf(scratch_pool, "      >   not shelved\n"));
+  ++sb->num_paths_not_shelved;
   return SVN_NO_ERROR;
 }
 
@@ -466,7 +429,6 @@ shelve(int *new_version_p,
   svn_client_shelf_t *shelf;
   svn_client_shelf_version_t *previous_version;
   svn_client_shelf_version_t *new_version;
-  const char *cwd_abspath;
   struct status_baton sb;
 
   SVN_ERR(svn_client_shelf_open_or_create(&shelf,
@@ -485,37 +447,40 @@ shelve(int *new_version_p,
                     TRUE /*with_logmsg*/, scratch_pool));
     }
 
-  sb.header = (keep_local
-               ? _("--- Modifications to save:\n")
-               : _("--- Modifications to shelve:\n"));
+  sb.target_abspath = shelf->wc_root_abspath;
+  sb.target_path = "";
   sb.quiet = quiet;
-  sb.modified = FALSE;
+  sb.num_paths_shelved = 0;
+  sb.num_paths_not_shelved = 0;
   sb.ctx = ctx;
-  SVN_ERR(svn_dirent_get_absolute(&cwd_abspath, "", scratch_pool));
-  SVN_ERR(run_status_on_wc_paths(cwd_abspath, paths, depth, changelists,
-                                 modification_checker, &sb,
-                                 ctx, scratch_pool));
-
-  if (!sb.modified)
-    {
-      SVN_ERR(svn_client_shelf_close(shelf, scratch_pool));
-      return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
-                               _("No local modifications found"));
-    }
 
   if (! quiet)
     SVN_ERR(svn_cmdline_printf(scratch_pool,
                                keep_local ? _("--- Saving...\n")
                                           : _("--- Shelving...\n")));
-  SVN_ERR(svn_client_shelf_save_new_version2(&new_version, shelf,
+  SVN_ERR(svn_client_shelf_save_new_version3(&new_version, shelf,
                                              paths, depth, changelists,
+                                             was_shelved, &sb,
+                                             was_not_shelved, &sb,
                                              scratch_pool));
-  if (! new_version)
+  if (sb.num_paths_not_shelved > 0)
+    {
+      SVN_ERR(svn_client_shelf_delete_newer_versions(shelf, previous_version,
+                                                     scratch_pool));
+      SVN_ERR(svn_client_shelf_close(shelf, scratch_pool));
+      return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+                               Q_("%d path could not be shelved",
+                                  "%d paths could not be shelved",
+                                  sb.num_paths_not_shelved),
+                               sb.num_paths_not_shelved);
+    }
+  if (sb.num_paths_shelved == 0
+      || ! new_version)
     {
       SVN_ERR(svn_client_shelf_close(shelf, scratch_pool));
       return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
-        keep_local ? _("None of the local modifications could be saved")
-                   : _("None of the local modifications could be shelved"));
+        keep_local ? _("No local modifications could be saved")
+                   : _("No local modifications could be shelved"));
     }
 
   /* Un-apply the changes, if required. */