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 2017/07/26 12:44:34 UTC

svn commit: r1803040 - in /subversion/branches/shelve-checkpoint3: ./ subversion/include/ subversion/libsvn_client/ subversion/svn/ tools/client-side/

Author: julianfoad
Date: Wed Jul 26 12:44:33 2017
New Revision: 1803040

URL: http://svn.apache.org/viewvc?rev=1803040&view=rev
Log:
On the 'shelve-checkpoint3' branch: Initial prototype of Checkpointing
backed by a local repository embedded within the WC.

* BRANCH-README
  Update.

* build.conf
  (libsvn_client): Now depends on libsvn_repos and libsvn_fs.

* subversion/include/svn_client.h
  (svn_client_checkpoint_init,
   svn_client_checkpoint_uninit,
   svn_client_checkpoint_squash,
   svn_client_checkpoint_get_current,
   svn_client_checkpoint_save,
   svn_client_checkpoint_revert,
   svn_client_checkpoint_list): New.

* subversion/libsvn_client/checkpoint3.c
  New file.

* subversion/libsvn_client/client.h
* subversion/libsvn_client/import.c
  (svn_client__import_internal): Expose this internal interface.

* subversion/svn/checkpoint3-cmd.c
  New file.

* subversion/svn/cl.h
  (svn_cl__checkpoint): New.

* subversion/svn/svn.c
  (svn_cl__cmd_table): Add the 'checkpoint' command.

* tools/client-side/bash_completion
  (_svn): Add the 'checkpoint' command.

Added:
    subversion/branches/shelve-checkpoint3/subversion/libsvn_client/checkpoint3.c   (with props)
    subversion/branches/shelve-checkpoint3/subversion/svn/checkpoint3-cmd.c   (with props)
Modified:
    subversion/branches/shelve-checkpoint3/BRANCH-README
    subversion/branches/shelve-checkpoint3/build.conf
    subversion/branches/shelve-checkpoint3/subversion/include/svn_client.h
    subversion/branches/shelve-checkpoint3/subversion/libsvn_client/client.h
    subversion/branches/shelve-checkpoint3/subversion/libsvn_client/import.c
    subversion/branches/shelve-checkpoint3/subversion/svn/cl.h
    subversion/branches/shelve-checkpoint3/subversion/svn/svn.c
    subversion/branches/shelve-checkpoint3/tools/client-side/bash_completion

Modified: subversion/branches/shelve-checkpoint3/BRANCH-README
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/BRANCH-README?rev=1803040&r1=1803039&r2=1803040&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/BRANCH-README (original)
+++ subversion/branches/shelve-checkpoint3/BRANCH-README Wed Jul 26 12:44:33 2017
@@ -1,13 +1,12 @@
-This branch is for development of Shelving and Checkpointing.
-
-Specifically, this branch is for Checkpointing backed by a local repository
+This branch is for prototyping Checkpointing backed by a local repository
 embedded within the WC, referred to as design "option 3" in [1].
 
-Branch type: dev branch off trunk; updated by full merges from trunk.
+Branch type: dev branch off 'shelve' branch; updated by full merges from
+there; not intended to be merged to trunk.
 
-Initially this is prototyping, to explore the general shape of the design and
-user interface. As such, it does not take care over details of APIs and error
-handling and so on.
+Initially this is prototyping, to explore the general shape of the design
+and user interface. As such, the coding style is hacky and does not comply
+with Subversion coding requirements.
 
 References:
    [0] dev@ thread "[RFC] Shelving and Checkpointing", J Foad, 2017-07-10.

Modified: subversion/branches/shelve-checkpoint3/build.conf
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/build.conf?rev=1803040&r1=1803039&r2=1803040&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/build.conf (original)
+++ subversion/branches/shelve-checkpoint3/build.conf Wed Jul 26 12:44:33 2017
@@ -243,7 +243,7 @@ link-cmd = $(LINK_CXX_LIB)
 description = Subversion Client Library
 type = lib
 path = subversion/libsvn_client
-libs = libsvn_wc libsvn_ra libsvn_delta libsvn_diff libsvn_subr apriconv apr
+libs = libsvn_wc libsvn_ra libsvn_delta libsvn_diff libsvn_repos libsvn_fs libsvn_subr apriconv apr
 install = lib
 msvc-export = svn_client.h private/svn_client_mtcc.h private/svn_client_private.h
 

Modified: subversion/branches/shelve-checkpoint3/subversion/include/svn_client.h
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/include/svn_client.h?rev=1803040&r1=1803039&r2=1803040&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/include/svn_client.h (original)
+++ subversion/branches/shelve-checkpoint3/subversion/include/svn_client.h Wed Jul 26 12:44:33 2017
@@ -6716,6 +6716,90 @@ svn_client_cat(svn_stream_t *out,
 
 
 
+/** Checkpointing commands
+ *
+ * @defgroup svn_client_checkpoint_funcs Client Checkpointing Functions
+ * @{
+ */
+
+/**
+ *
+ * @since New in 1.11.
+ */
+svn_error_t *
+svn_client_checkpoint_init(const char *local_abspath,
+                           svn_client_ctx_t *ctx,
+                           apr_pool_t *scratch_pool);
+
+/**
+ *
+ * @since New in 1.11.
+ */
+svn_error_t *
+svn_client_checkpoint_uninit(const char *local_abspath,
+                             svn_client_ctx_t *ctx,
+                             apr_pool_t *scratch_pool);
+
+/**
+ *
+ * @since New in 1.11.
+ */
+svn_error_t *
+svn_client_checkpoint_squash(const char *local_abspath,
+                             svn_client_ctx_t *ctx,
+                             apr_pool_t *scratch_pool);
+
+/**
+ *
+ * @since New in 1.11.
+ */
+svn_error_t *
+svn_client_checkpoint_get_current(int *checkpoint_number_p,
+                                  const char *local_abspath,
+                                  svn_client_ctx_t *ctx,
+                                  apr_pool_t *scratch_pool);
+
+/**
+ * Set *checkpoint_number to the new checkpoint revision number,
+ * or to -1 if no change was saved.
+ *
+ * @since New in 1.11.
+ */
+svn_error_t *
+svn_client_checkpoint_save(int *checkpoint_number,
+                           const char *local_abspath,
+                           /*const apr_array_header_t *paths,
+                           svn_depth_t depth,
+                           const apr_array_header_t *changelists,*/
+                           svn_client_ctx_t *ctx,
+                           apr_pool_t *scratch_pool);
+
+/**
+ *
+ * @since New in 1.11.
+ */
+svn_error_t *
+svn_client_checkpoint_revert(int checkpoint_number,
+                             const char *local_abspath,
+                             svn_boolean_t dry_run,
+                             svn_client_ctx_t *ctx,
+                             apr_pool_t *scratch_pool);
+
+/**
+ *
+ * @since New in 1.11.
+ */
+svn_error_t *
+svn_client_checkpoint_list(apr_array_header_t **checkpoints,
+                           const char *wc_root_abspath,
+                           svn_client_ctx_t *ctx,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool);
+
+/** @} */
+
+
+
 /** Shelving commands
  *
  * @defgroup svn_client_shelve_funcs Client Shelving Functions

Added: subversion/branches/shelve-checkpoint3/subversion/libsvn_client/checkpoint3.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_client/checkpoint3.c?rev=1803040&view=auto
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_client/checkpoint3.c (added)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_client/checkpoint3.c Wed Jul 26 12:44:33 2017
@@ -0,0 +1,709 @@
+/*
+ * checkpoint3.c:  implementation of 'checkpoint' by commits in a local repo
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+/* ==================================================================== */
+
+
+
+/*** Includes. ***/
+
+#include <string.h>
+#include <apr_strings.h>
+#include <apr_hash.h>
+#include "svn_hash.h"
+#include "svn_wc.h"
+#include "svn_ra.h"
+#include "svn_client.h"
+#include "svn_string.h"
+#include "svn_pools.h"
+#include "svn_error.h"
+#include "svn_error_codes.h"
+#include "svn_dirent_uri.h"
+#include "svn_path.h"
+#include "svn_sorts.h"
+#include "svn_props.h"
+#include "svn_repos.h"
+
+#include "client.h"
+#include "private/svn_wc_private.h"
+#include "private/svn_ra_private.h"
+#include "private/svn_sorts_private.h"
+
+#include "svn_private_config.h"
+
+
+/* -------------------- checkpoint repo -------------------- */
+
+/* Return the abspatch to the checkpoints repo.
+ *
+ * It need not necessarily exist.
+ */
+static char *
+checkpoints_repo_dir(const char *wc_root_abspath,
+                     apr_pool_t *scratch_pool)
+{
+  return svn_path_join_many(scratch_pool,
+                            wc_root_abspath, ".svn", "checkpoints",
+                            SVN_VA_NULL);
+}
+
+/* ### temp: we should not be accessing the repo via URL but directly */
+static char *
+checkpoints_repo_url(const char *wc_root_abspath,
+                     apr_pool_t *scratch_pool)
+{
+  return apr_pstrcat(scratch_pool,
+                     "file://", wc_root_abspath, "/.svn/checkpoints",
+                     SVN_VA_NULL);
+}
+
+static char *
+original_repos_url(const char *wc_root_abspath,
+                   apr_pool_t *scratch_pool)
+{
+  return apr_pstrcat(scratch_pool,
+                     "file://", wc_root_abspath, "/../repo",
+                     SVN_VA_NULL);
+}
+
+/* Create the repo if it is not already present.
+ *
+ * Open the repo and return it in *REPOS_P.
+ */
+static svn_error_t *
+checkpoints_repo_create(svn_repos_t **repos_p,
+                        const char *wc_root_abspath,
+                        const char *uuid,
+                        apr_pool_t *scratch_pool)
+{
+  const char *repo_dir
+    = checkpoints_repo_dir(wc_root_abspath, scratch_pool);
+
+  SVN_ERR(svn_repos_create(repos_p, repo_dir,
+                           NULL, NULL, NULL, NULL, scratch_pool));
+  SVN_ERR(svn_fs_set_uuid(svn_repos_fs(*repos_p), uuid, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/* Open the checkpoints repo.
+ */
+static svn_error_t *
+checkpoints_repo_open(svn_repos_t **repos_p,
+                      const char *wc_root_abspath,
+                      apr_pool_t *result_pool,
+                      apr_pool_t *scratch_pool)
+{
+  const char *repo_dir
+    = checkpoints_repo_dir(wc_root_abspath, scratch_pool);
+
+  SVN_ERR(svn_repos_open3(repos_p, repo_dir,
+                          NULL, result_pool, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/*  */
+static svn_error_t *
+checkpoints_repo_destroy(const char *wc_root_abspath,
+                         apr_pool_t *scratch_pool)
+{
+  printf("  (destroying the repo is not implemented yet)\n");
+  return SVN_NO_ERROR;
+}
+
+/* Prune revisions later than NEW_HEAD from the repo at REPO_DIR.
+ * ### Ultra hacky!
+ */
+static svn_error_t *
+checkpoints_repo_prune(const char *repo_dir,
+                       svn_revnum_t new_head,
+                       apr_pool_t *scratch_pool)
+{
+  char *current_file_path = svn_path_join(repo_dir, "db/current", scratch_pool);
+  char *rep_cache_db_path = svn_path_join(repo_dir, "db/rep-cache.db", scratch_pool);
+  int old_head, r;
+
+  SVN_ERR(svn_io_read_version_file(&old_head, current_file_path, scratch_pool));
+  SVN_ERR(svn_io_write_version_file(current_file_path, new_head, scratch_pool));
+
+  /* Remove later rev files (at least the revprop files need to be gone) */
+  for (r = old_head; r > new_head; r--)
+    {
+      char *rev_file_path
+        = apr_psprintf(scratch_pool, "%s/db/revs/0/%d", repo_dir, r);
+      char *revprop_file_path
+        = apr_psprintf(scratch_pool, "%s/db/revprops/0/%d", repo_dir, r);
+
+      printf("pruning checkpoint %d\n", r - 1);
+      SVN_ERR(svn_io_remove_file2(rev_file_path, FALSE /*ignore_enoent*/,
+                                  scratch_pool));
+      SVN_ERR(svn_io_remove_file2(revprop_file_path, FALSE /*ignore_enoent*/,
+                                  scratch_pool));
+    }
+  /* Remove later revs from the rep cache */
+  /* ### For now, remove the whole rep cache */
+  SVN_ERR(svn_io_remove_file2(rep_cache_db_path, TRUE /*ignore_enoent*/,
+                              scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/* -------------------- transfers -------------------- */
+
+/* Update the WC to r(checkpoint_number + 1).
+ */
+static svn_error_t *
+checkpoint_update(int checkpoint_number,
+                  const char *wc_root_abspath,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *scratch_pool)
+{
+  apr_array_header_t *paths = apr_array_make(scratch_pool, 1, sizeof(char *));
+  svn_opt_revision_t revision = {svn_opt_revision_number};
+
+  APR_ARRAY_PUSH(paths, const char *) = wc_root_abspath;
+  revision.value.number = checkpoint_number + 1;
+
+  SVN_ERR(svn_client_update4(NULL /*result_revs*/,
+                             paths, &revision,
+                             svn_depth_infinity,
+                             FALSE /*depth_is_sticky*/,
+                             TRUE /*ignore_externals*/,
+                             TRUE /*allow_unver_obstructions*/,
+                             TRUE /*adds_as_modification*/,
+                             FALSE /*make_parents*/,
+                             ctx, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* Copy the WC base into the repo.
+ *
+ * ### Uses 'import' from disk into a commit editor.
+ * ### Lots of problems with that: loses props, adds unversioned files, etc.
+ * ### Instead, must export content and props directly from WC base.
+ */
+static svn_error_t *
+copy_base(const char *wc_root_abspath,
+          svn_repos_t *repos,
+          svn_client_ctx_t *ctx,
+          apr_pool_t *scratch_pool)
+{
+  const svn_delta_editor_t *editor;
+  void *edit_baton;
+  const char *repos_url = checkpoints_repo_url(wc_root_abspath, scratch_pool);
+  /* List of in-repo path components from repo root to WC root. */
+  apr_array_header_t *new_entries = apr_array_make(scratch_pool, 4,
+                                                   sizeof(const char *));
+  svn_boolean_t updated_repository;
+
+  SVN_ERR(svn_repos_get_commit_editor5(&editor, &edit_baton,
+                                       repos,
+                                       NULL /*txn*/,
+                                       "" /*repos_url_decoded*/,
+                                       "" /*base_path*/,
+                                       apr_hash_make(scratch_pool) /*revprop_table*/,
+                                       NULL, NULL, /*commit cb*/
+                                       NULL, NULL, /*authz cb*/
+                                       scratch_pool));
+
+  SVN_ERR(svn_client__import_internal(
+            &updated_repository,
+            wc_root_abspath,
+            repos_url, /* used just for a notification */
+            new_entries, editor, edit_baton,
+            svn_depth_infinity, 0 /*base_rev*/,
+            apr_hash_make(scratch_pool) /*excludes*/,
+            NULL /*autoprops*/,
+            NULL /*local_ignores_arr*/, NULL /*global_ignores*/,
+            TRUE /*no_ignore*/,
+            TRUE /*no_autoprops*/,
+            TRUE /*ignore_unknown_node_types*/,
+            NULL, NULL, /*filter cb*/
+            ctx, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/* Switch the WC base to point to the new repo.
+ */
+static svn_error_t *
+switch_base(const char *wc_root_abspath,
+            svn_repos_t *repos,
+            svn_client_ctx_t *ctx,
+            apr_pool_t *scratch_pool)
+{
+  const char *orig_repos_root_url;
+  const char *repos_url = checkpoints_repo_url(wc_root_abspath, scratch_pool);
+
+  SVN_ERR(svn_client_get_repos_root(&orig_repos_root_url, NULL /* uuid */,
+                                    wc_root_abspath,
+                                    ctx, scratch_pool, scratch_pool));
+  SVN_ERR(svn_client_relocate2(wc_root_abspath,
+                               orig_repos_root_url, repos_url,
+                               TRUE /*ignore_externals*/,
+                               ctx, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/* Switch the WC base to point to the original repo.
+ */
+static svn_error_t *
+switch_to_original_base(const char *wc_root_abspath,
+                        svn_repos_t *repos,
+                        svn_client_ctx_t *ctx,
+                        apr_pool_t *scratch_pool)
+{
+  const char *orig_repos_url = original_repos_url(wc_root_abspath, scratch_pool);
+  const char *repos_url = checkpoints_repo_url(wc_root_abspath, scratch_pool);
+
+  SVN_ERR(svn_client_relocate2(wc_root_abspath,
+                               repos_url, orig_repos_url,
+                               TRUE /*ignore_externals*/,
+                               ctx, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/*
+ * Assumes no uncommitted mods.
+ */
+static svn_error_t *
+squash_to_working_state(const char *wc_root_abspath,
+                        svn_client_ctx_t *ctx,
+                        apr_pool_t *scratch_pool)
+{
+  apr_pool_t *repos_pool = svn_pool_create(scratch_pool);
+  svn_repos_t *repos;
+  svn_opt_revision_t peg_revision1 = {svn_opt_revision_head};
+  apr_array_header_t *ranges_to_merge
+    = apr_array_make(scratch_pool, 1, sizeof(void *));
+  svn_opt_revision_range_t range = { {svn_opt_revision_number, {1}},
+                                     {svn_opt_revision_head} };
+
+  SVN_ERR(checkpoints_repo_open(&repos, wc_root_abspath,
+                                repos_pool, scratch_pool));
+
+  /* update to r1 */
+  printf("  (squash: updating to r1)\n");
+  SVN_ERR(checkpoint_update(0 /*checkpoint_number*/, wc_root_abspath,
+                            ctx, scratch_pool));
+
+  /* merge all committed changes into WC, with no mergeinfo */
+  printf("  (squash: merging checkpointed changes into WC)\n");
+  APR_ARRAY_PUSH(ranges_to_merge, void *) = &range;
+  SVN_ERR(svn_client_merge_peg5("" /*sourcepath1*/,
+                                ranges_to_merge,
+                                &peg_revision1,
+                                "" /*targetpath*/,
+                                svn_depth_infinity,
+                                TRUE /*ignore_mergeinfo*/,
+                                FALSE /*diff_ignore_ancestry*/,
+                                FALSE /*force_delete*/,
+                                FALSE /*record_only*/,
+                                FALSE /*dry_run*/,
+                                FALSE /*allow_mixed_rev*/,
+                                NULL /*options*/,
+                                ctx, scratch_pool));
+
+  /* Close the repo */
+  svn_pool_destroy(repos_pool);
+
+  return SVN_NO_ERROR;
+}
+
+/* Start a series of checkpoints.
+ *
+ * Create a local repo.
+ * Copy the WC base into it.
+ * Switch the WC to point at it.
+ *
+ * Assumptions (for initial prototype):
+ *   WC is clean
+ *   WC is single-rev
+ *   WC base is at r1!
+ *   WC root URL is repos root URL
+ */
+static svn_error_t *
+checkpoints_init(const char *wc_root_abspath,
+                 svn_client_ctx_t *ctx,
+                 apr_pool_t *scratch_pool)
+{
+  const char *uuid;
+  apr_pool_t *repos_pool = svn_pool_create(scratch_pool);
+  svn_repos_t *repos;
+
+  SVN_ERR(svn_client_uuid_from_path2(&uuid, wc_root_abspath,
+                                     ctx, scratch_pool, scratch_pool));
+
+  printf("creating repo\n");
+  SVN_ERR(checkpoints_repo_create(&repos, wc_root_abspath, uuid, repos_pool));
+
+  printf("copying base\n");
+  SVN_ERR(copy_base(wc_root_abspath, repos, ctx, scratch_pool));
+
+  printf("switching base\n");
+  SVN_ERR(switch_base(wc_root_abspath, repos, ctx, scratch_pool));
+
+  /* Close the repo */
+  svn_pool_destroy(repos_pool);
+  return SVN_NO_ERROR;
+}
+
+/* End a series of checkpoints.
+ *
+ * Switch the WC base to point at the original repo and base revision(s).
+ * Make the WC working state be the checkpoint final state.
+ * Destroy the local repo.
+ *
+ * Assumptions (for initial prototype):
+ */
+static svn_error_t *
+checkpoints_uninit(const char *wc_root_abspath,
+                   svn_client_ctx_t *ctx,
+                   apr_pool_t *scratch_pool)
+{
+  apr_pool_t *repos_pool = svn_pool_create(scratch_pool);
+  svn_repos_t *repos;
+
+  SVN_ERR(checkpoints_repo_open(&repos, wc_root_abspath,
+                                repos_pool, scratch_pool));
+
+  printf("switching back to original base\n");
+  SVN_ERR(switch_to_original_base(wc_root_abspath, repos, ctx, scratch_pool));
+
+  /* Close the repo */
+  svn_pool_destroy(repos_pool);
+
+  printf("destroying the checkpoints repo\n");
+  SVN_ERR(checkpoints_repo_destroy(wc_root_abspath, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* Set *CURRENT to the current checkpoint number.
+ */
+static svn_error_t *
+read_current(int *current,
+             const char *wc_root_abspath,
+             svn_client_ctx_t *ctx,
+             apr_pool_t *scratch_pool)
+{
+  apr_pool_t *repos_pool = svn_pool_create(scratch_pool);
+  svn_repos_t *repos;
+  svn_revnum_t youngest;
+
+  SVN_ERR(checkpoints_repo_open(&repos, wc_root_abspath,
+                                repos_pool, scratch_pool));
+  SVN_ERR(svn_fs_youngest_rev(&youngest, svn_repos_fs(repos), scratch_pool));
+  *current = (youngest - 1);
+
+  /* Close the repo */
+  svn_pool_destroy(repos_pool);
+  return SVN_NO_ERROR;
+}
+
+/* -------------------- checkpoint save -------------------- */
+
+typedef struct commit_baton_t {
+  svn_revnum_t revision;
+} commit_baton_t;
+
+static svn_error_t *
+commit_callback(const svn_commit_info_t *commit_info,
+                void *baton,
+                apr_pool_t *scratch_pool)
+{
+  commit_baton_t *cb = baton;
+
+  cb->revision = commit_info->revision;
+  return SVN_NO_ERROR;
+}
+
+/* Write a checkpoint of the whole WC.
+ */
+static svn_error_t *
+checkpoint_save(int *checkpoint_number,
+                /*const apr_array_header_t *paths,
+                  svn_depth_t depth,
+                  const apr_array_header_t *changelists,*/
+                const char *wc_root_abspath,
+                svn_client_ctx_t *ctx,
+                apr_pool_t *scratch_pool)
+{
+  apr_array_header_t *paths = apr_array_make(scratch_pool, 1, sizeof(char *));
+  commit_baton_t cb = { 0 };
+
+  APR_ARRAY_PUSH(paths, const char *) = wc_root_abspath;
+
+  /* ### TODO: if not at latest checkpoint, first prune later checkpoints */
+
+  ctx->log_msg_func3 = NULL;
+  ctx->log_msg_func2 = NULL;
+  ctx->log_msg_func = NULL;
+  SVN_ERR(svn_client_commit6(
+            paths,
+            svn_depth_infinity /*depth*/,
+            TRUE /*keep_locks*/,
+            TRUE /*keep_changelists*/,
+            TRUE /*commit_as_operations*/,
+            FALSE, /* include_file_externals */
+            FALSE, /* include_dir_externals */
+            NULL /*changelists*/,
+            NULL /*revprop_table*/,
+            commit_callback, &cb,
+            ctx, scratch_pool));
+
+  if (checkpoint_number)
+    *checkpoint_number = (cb.revision - 1);
+  return SVN_NO_ERROR;
+}
+
+/* -------------------- checkpoint ... -------------------- */
+
+/*  */
+static svn_error_t *
+checkpoint_revert(int checkpoint_number,
+                  const char *wc_root_abspath,
+                  svn_boolean_t dry_run,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *scratch_pool)
+{
+  apr_array_header_t *paths = apr_array_make(scratch_pool, 1, sizeof(char *));
+
+  APR_ARRAY_PUSH(paths, const char *) = wc_root_abspath;
+
+  /* Revert the WC local mods */
+  SVN_ERR(svn_client_revert3(paths,
+                             svn_depth_infinity,
+                             NULL /*changelists*/,
+                             FALSE /*clear_changelists*/,
+                             FALSE /*metadata_only*/,
+                             ctx, scratch_pool));
+
+  SVN_ERR(checkpoint_update(checkpoint_number, wc_root_abspath,
+                            ctx, scratch_pool));
+
+  /* Prune later revisions from the repo */
+  SVN_ERR(checkpoints_repo_prune(
+            checkpoints_repo_dir(wc_root_abspath, scratch_pool),
+            checkpoint_number + 1, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* -------------------- checkpoint ... -------------------- */
+
+svn_error_t *
+svn_client_checkpoint_init(const char *local_abspath,
+                           svn_client_ctx_t *ctx,
+                           apr_pool_t *scratch_pool)
+{
+  const char *wc_root_abspath;
+
+  SVN_ERR(svn_client_get_wc_root(&wc_root_abspath, local_abspath,
+                                 ctx, scratch_pool, scratch_pool));
+  SVN_ERR(checkpoints_init(wc_root_abspath, ctx, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_checkpoint_squash(const char *local_abspath,
+                             svn_client_ctx_t *ctx,
+                             apr_pool_t *scratch_pool)
+{
+  const char *wc_root_abspath;
+
+  SVN_ERR(svn_client_get_wc_root(&wc_root_abspath, local_abspath,
+                                 ctx, scratch_pool, scratch_pool));
+
+  printf("checkpointing any outstanding changes\n");
+  SVN_ERR(checkpoint_save(NULL /*checkpoint_number*/,
+                          wc_root_abspath, ctx, scratch_pool));
+
+  printf("squashing checkpoints to a working state\n");
+  SVN_ERR(squash_to_working_state(wc_root_abspath,
+                                  ctx, scratch_pool));
+
+  /* Prune later revisions from the repo */
+  SVN_ERR(checkpoints_repo_prune(
+            checkpoints_repo_dir(wc_root_abspath, scratch_pool),
+            1 /*new_head revision*/, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_checkpoint_uninit(const char *local_abspath,
+                             svn_client_ctx_t *ctx,
+                             apr_pool_t *scratch_pool)
+{
+  const char *wc_root_abspath;
+
+  SVN_ERR(svn_client_checkpoint_squash(local_abspath, ctx, scratch_pool));
+
+  SVN_ERR(svn_client_get_wc_root(&wc_root_abspath, local_abspath,
+                                 ctx, scratch_pool, scratch_pool));
+
+  SVN_ERR(checkpoints_uninit(wc_root_abspath, ctx, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_checkpoint_get_current(int *checkpoint_number_p,
+                                  const char *local_abspath,
+                                  svn_client_ctx_t *ctx,
+                                  apr_pool_t *scratch_pool)
+{
+  const char *wc_root_abspath;
+
+  SVN_ERR(svn_client_get_wc_root(&wc_root_abspath, local_abspath,
+                                 ctx, scratch_pool, scratch_pool));
+
+  SVN_ERR(read_current(checkpoint_number_p, wc_root_abspath, ctx, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_checkpoint_save(int *checkpoint_number,
+                           const char *local_abspath,
+                           svn_client_ctx_t *ctx,
+                           apr_pool_t *scratch_pool)
+{
+  const char *wc_root_abspath;
+
+  SVN_ERR(svn_client_get_wc_root(&wc_root_abspath, local_abspath,
+                                 ctx, scratch_pool, scratch_pool));
+
+  SVN_ERR(checkpoint_save(checkpoint_number,
+                          wc_root_abspath, ctx, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_checkpoint_revert(int checkpoint_number,
+                             const char *local_abspath,
+                             svn_boolean_t dry_run,
+                             svn_client_ctx_t *ctx,
+                             apr_pool_t *scratch_pool)
+{
+  const char *wc_root_abspath;
+
+  SVN_ERR(svn_client_get_wc_root(&wc_root_abspath, local_abspath,
+                                 ctx, scratch_pool, scratch_pool));
+
+  /* ### TODO: Save the current state (of whole WC) */
+
+  /* Restore the requested checkpoint */
+  SVN_ERR(checkpoint_revert(checkpoint_number, wc_root_abspath,
+                            dry_run,
+                            ctx, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* -------------------- checkpoint list -------------------- */
+
+#if 0
+typedef struct path_change_baton_t
+{
+  apr_array_header_t *changes;
+  apr_pool_t *result_pool;
+} path_change_baton_t;
+
+/*  */
+static svn_error_t *
+path_change_func(void *baton,
+                 svn_repos_path_change_t *change,
+                 apr_pool_t *scratch_pool)
+{
+  path_change_baton_t *b = baton;
+
+  APR_ARRAY_PUSH(b->changes, void *) = svn_repos_path_change_dup(change, b->result_pool);
+  return SVN_NO_ERROR;
+}
+#endif
+
+typedef struct log_entry_baton_t
+{
+  /*path_change_baton_t *pb;*/
+  apr_array_header_t *entries;
+  apr_pool_t *result_pool;
+} log_entry_baton_t;
+
+/*  */
+static svn_error_t *
+log_entry_func(void *baton,
+               svn_repos_log_entry_t *repos_log_entry,
+               apr_pool_t *scratch_pool)
+{
+  log_entry_baton_t *b = baton;
+  svn_log_entry_t *std_log_entry = svn_log_entry_create(b->result_pool);
+
+  std_log_entry->revision = repos_log_entry->revision;
+  std_log_entry->revprops = svn_prop_hash_dup(repos_log_entry->revprops,
+                                              b->result_pool);
+  /*std_log_entry->changed_paths2 = b->pb->changes;*/
+  /*b->pb->changes = apr_hash_make(b->pb->result_pool);*/
+  APR_ARRAY_PUSH(b->entries, void *) = std_log_entry;
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_checkpoint_list(apr_array_header_t **checkpoints,
+                           const char *wc_root_abspath,
+                           svn_client_ctx_t *ctx,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool)
+{
+  /*path_change_baton_t pb;*/
+  log_entry_baton_t lb;
+  apr_pool_t *repos_pool = svn_pool_create(scratch_pool);
+  svn_repos_t *repos;
+
+  SVN_ERR(checkpoints_repo_open(&repos, wc_root_abspath,
+                                repos_pool, scratch_pool));
+
+  /*pb.changes = apr_array_make(scratch_pool, 0, sizeof(void *));*/
+  /*pb.result_pool = result_pool;*/
+  /*lb.pb = &pb;*/
+  lb.entries = apr_array_make(scratch_pool, 0, sizeof(void *));
+  lb.result_pool = result_pool;
+
+  SVN_ERR(svn_repos_get_logs5(repos, NULL /*paths*/,
+                              SVN_INVALID_REVNUM /*start*/, 1 /*end*/,
+                              0 /*limit*/,
+                              TRUE /*strict_node_history*/,
+                              FALSE /*include_merged_revisions*/,
+                              NULL /*revprops*/,
+                              NULL, NULL, /*authz_read*/
+                              NULL, NULL, /*path_change_func, &pb,*/
+                              log_entry_func, &lb,
+                              scratch_pool));
+
+  *checkpoints = lb.entries;
+
+  /* Close the repo */
+  svn_pool_destroy(repos_pool);
+  return SVN_NO_ERROR;
+}
+

Propchange: subversion/branches/shelve-checkpoint3/subversion/libsvn_client/checkpoint3.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/shelve-checkpoint3/subversion/libsvn_client/checkpoint3.c
------------------------------------------------------------------------------
    svn:mime-type = text/x-csrc

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_client/client.h
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_client/client.h?rev=1803040&r1=1803039&r2=1803040&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_client/client.h (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_client/client.h Wed Jul 26 12:44:33 2017
@@ -1267,6 +1267,28 @@ svn_client__merge_locked(svn_client__con
                          apr_pool_t *result_pool,
                          apr_pool_t *scratch_pool);
 
+/* */
+svn_error_t *
+svn_client__import_internal(svn_boolean_t *updated_repository,
+       const char *local_abspath,
+       const char *url,
+       const apr_array_header_t *new_entries,
+       const svn_delta_editor_t *editor,
+       void *edit_baton,
+       svn_depth_t depth,
+       svn_revnum_t base_rev,
+       apr_hash_t *excludes,
+       apr_hash_t *autoprops,
+       apr_array_header_t *local_ignores,
+       apr_array_header_t *global_ignores,
+       svn_boolean_t no_ignore,
+       svn_boolean_t no_autoprops,
+       svn_boolean_t ignore_unknown_node_types,
+       svn_client_import_filter_func_t filter_callback,
+       void *filter_baton,
+       svn_client_ctx_t *ctx,
+       apr_pool_t *pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_client/import.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_client/import.c?rev=1803040&r1=1803039&r2=1803040&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_client/import.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_client/import.c Wed Jul 26 12:44:33 2017
@@ -631,8 +631,8 @@ import_dir(const svn_delta_editor_t *edi
  * called, it returns a directory baton for that directory, which is
  * not necessarily the root.)
  */
-static svn_error_t *
-import(svn_boolean_t *updated_repository,
+svn_error_t *
+svn_client__import_internal(svn_boolean_t *updated_repository,
        const char *local_abspath,
        const char *url,
        const apr_array_header_t *new_entries,
@@ -989,7 +989,7 @@ svn_client_import5(const char *path,
     }
 
   /* If an error occurred during the commit, properly abort the edit.  */
-  err = svn_error_trace(import(&updated_repository,
+  err = svn_error_trace(svn_client__import_internal(&updated_repository,
                                local_abspath, url, new_entries, editor,
                                edit_baton, depth, base_rev, excludes,
                                autoprops, local_ignores_arr, global_ignores,

Added: subversion/branches/shelve-checkpoint3/subversion/svn/checkpoint3-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/svn/checkpoint3-cmd.c?rev=1803040&view=auto
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/svn/checkpoint3-cmd.c (added)
+++ subversion/branches/shelve-checkpoint3/subversion/svn/checkpoint3-cmd.c Wed Jul 26 12:44:33 2017
@@ -0,0 +1,307 @@
+/*
+ * checkpoint-cmd.c -- Checkpoint commands.
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+#include "svn_client.h"
+#include "svn_error_codes.h"
+#include "svn_error.h"
+#include "svn_path.h"
+#include "svn_utf.h"
+#include "svn_hash.h"
+
+#include "cl.h"
+
+#include "svn_private_config.h"
+#include "private/svn_sorts_private.h"
+
+
+/*  */
+static svn_error_t *
+checkpoint_init(const char *local_abspath,
+                svn_client_ctx_t *ctx,
+                apr_pool_t *scratch_pool)
+{
+  SVN_ERR(svn_client_checkpoint_init(local_abspath, ctx, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/*  */
+static svn_error_t *
+checkpoint_list(const char *local_abspath,
+                svn_boolean_t diffstat,
+                svn_client_ctx_t *ctx,
+                apr_pool_t *scratch_pool)
+{
+  apr_array_header_t *checkpoints;
+  /*int current_checkpoint_number;*/
+  svn_boolean_t first = TRUE;
+  int i;
+
+  SVN_ERR(svn_client_checkpoint_list(&checkpoints,
+                                     local_abspath,
+                                     ctx, scratch_pool, scratch_pool));
+
+  /*SVN_ERR(svn_client_checkpoint_get_current(&current_checkpoint_number,
+                                            local_abspath, ctx, scratch_pool));
+  current_checkpoint_name = apr_psprintf(scratch_pool, "%d.patch",
+                                         current_checkpoint_number);*/
+
+  for (i = 0; i < checkpoints->nelts; i++)
+    {
+      svn_log_entry_t *log_entry = APR_ARRAY_IDX(checkpoints, i, void *);
+      int number = (log_entry->revision - 1);
+      const char *name = apr_psprintf(scratch_pool, "%d", number);
+      char marker = (first ? '*' : ' ');
+      svn_string_t *date = svn_hash_gets(log_entry->revprops, "svn:date");
+
+      printf("%c %s %.16s\n",
+             marker, name, date ? date->data : "");
+
+      if (diffstat)
+        {
+          printf("\n");
+        }
+      first = FALSE;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/*  */
+static svn_error_t *
+checkpoint_save(/*const apr_array_header_t *paths,
+                svn_depth_t depth,
+                const apr_array_header_t *changelists,*/
+                svn_boolean_t quiet,
+                const char *local_abspath,
+                svn_client_ctx_t *ctx,
+                apr_pool_t *scratch_pool)
+{
+  int checkpoint_number;
+
+  SVN_ERR(svn_client_checkpoint_save(&checkpoint_number,
+                                     /*paths, depth, changelists,*/
+                                     local_abspath, ctx, scratch_pool));
+  if (! quiet)
+    {
+      if (checkpoint_number >= 0)
+        SVN_ERR(svn_cmdline_printf(scratch_pool, "saved checkpoint %d\n",
+                                   checkpoint_number));
+      else
+        SVN_ERR(svn_cmdline_printf(scratch_pool, "no changes\n"));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/*  */
+static svn_error_t *
+checkpoint_squash(/*const char *arg,
+                    svn_boolean_t dry_run,
+                    svn_boolean_t quiet,*/
+                  const char *local_abspath,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *scratch_pool)
+{
+  SVN_ERR(svn_client_checkpoint_squash(local_abspath, ctx, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/*  */
+static svn_error_t *
+checkpoint_revert(const char *arg,
+                  svn_boolean_t dry_run,
+                  svn_boolean_t quiet,
+                  const char *local_abspath,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *scratch_pool)
+{
+  int old_checkpoint_number;
+  int new_checkpoint_number;
+
+  SVN_ERR(svn_client_checkpoint_get_current(&old_checkpoint_number,
+                                            local_abspath, ctx, scratch_pool));
+  if (arg)
+    {
+      SVN_ERR(svn_cstring_atoi(&new_checkpoint_number, arg));
+    }
+  else
+    {
+      new_checkpoint_number = old_checkpoint_number;
+    }
+
+  SVN_ERR(svn_client_checkpoint_revert(new_checkpoint_number,
+                                       local_abspath,
+                                       dry_run, ctx, scratch_pool));
+#if 0
+  int i;
+  /* Delete any newer checkpoints */
+  for (i = old_checkpoint_number; i > new_checkpoint_number; i--)
+    {
+      SVN_ERR(svn_client_checkpoint_delete(i, local_abspath,
+                                           dry_run, ctx, scratch_pool));
+      if (! quiet)
+        SVN_ERR(svn_cmdline_printf(scratch_pool, "deleted checkpoint %d\n",
+                                   i));
+    }
+#endif
+
+  if (!quiet)
+    SVN_ERR(svn_cmdline_printf(scratch_pool, "reverted to checkpoint %d\n",
+                               new_checkpoint_number));
+
+  return SVN_NO_ERROR;
+}
+
+/* First argument should be the subsubcommand. */
+static svn_error_t *
+get_subsubcommand(const char **subsubcommand,
+                  apr_getopt_t *os,
+                  apr_pool_t *result_pool,
+                  apr_pool_t *scratch_pool)
+{
+  apr_array_header_t *args;
+
+  SVN_ERR(svn_opt_parse_num_args(&args, os, 1, scratch_pool));
+  SVN_ERR(svn_utf_cstring_to_utf8(subsubcommand,
+                                  APR_ARRAY_IDX(args, 0, const char *),
+                                  result_pool));
+  return SVN_NO_ERROR;
+}
+
+/* This implements the `svn_opt_subcommand_t' interface. */
+svn_error_t *
+svn_cl__checkpoint(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 *subsubcommand;
+  apr_array_header_t *targets;
+  const char *local_abspath;
+
+  SVN_ERR(get_subsubcommand(&subsubcommand, os, pool, pool));
+
+  /* Parse the remaining arguments as paths. */
+  SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
+                                                      opt_state->targets,
+                                                      ctx, FALSE, pool));
+  SVN_ERR(svn_dirent_get_absolute(&local_abspath, "", pool));
+
+  if (opt_state->quiet)
+    ctx->notify_func2 = NULL;
+
+  if (strcmp(subsubcommand, "init") == 0)
+    {
+      if (targets->nelts)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("Too many arguments"));
+
+      SVN_ERR(checkpoint_init(local_abspath, ctx, pool));
+    }
+  else if (strcmp(subsubcommand, "list") == 0
+           || strcmp(subsubcommand, "log") == 0)
+    {
+      if (targets->nelts)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("Too many arguments"));
+
+      SVN_ERR(checkpoint_list(local_abspath,
+                              ! opt_state->quiet /*diffstat*/,
+                              ctx, pool));
+    }
+  else if (strcmp(subsubcommand, "save") == 0)
+    {
+      if (targets->nelts)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("Too many arguments"));
+
+      /* ### TODO: Semantics for checkpointing selected paths.
+      svn_depth_t depth = opt_state->depth;
+
+      if (! targets->nelts)
+        return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, NULL, NULL);
+
+      SVN_ERR(svn_cl__check_targets_are_local_paths(targets));
+
+      if (depth == svn_depth_unknown)
+        depth = svn_depth_infinity;
+
+      SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool));
+      */
+
+      SVN_ERR(checkpoint_save(/*targets, depth, opt_state->changelists,*/
+                              opt_state->quiet, local_abspath, ctx, pool));
+    }
+  else if (strcmp(subsubcommand, "squash") == 0)
+    {
+      if (targets->nelts)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("Too many arguments"));
+
+      SVN_ERR(checkpoint_squash(/*NULL, opt_state->dry_run, opt_state->quiet,*/
+                                local_abspath, ctx, pool));
+    }
+  else if (strcmp(subsubcommand, "revert") == 0)
+    {
+      if (targets->nelts)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("Too many arguments"));
+
+      SVN_ERR(checkpoint_revert(NULL, opt_state->dry_run, opt_state->quiet,
+                                local_abspath, ctx, pool));
+    }
+  else if (strcmp(subsubcommand, "rollback") == 0)
+    {
+      const char *arg;
+
+      if (targets->nelts != 1)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, NULL);
+
+      /* Which checkpoint number? */
+      arg = APR_ARRAY_IDX(targets, 0, char *);
+
+      SVN_ERR(checkpoint_revert(arg, opt_state->dry_run, opt_state->quiet,
+                                local_abspath, ctx, pool));
+    }
+  else if (strcmp(subsubcommand, "finish") == 0
+           || strcmp(subsubcommand, "uninit") == 0)
+    {
+      if (targets->nelts)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("Too many arguments"));
+
+      SVN_ERR(svn_client_checkpoint_uninit(local_abspath, ctx, pool));
+    }
+  else
+    {
+      return svn_error_createf(SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
+                               _("checkpoint: Unknown checkpoint command '%s'; "
+                                 "try 'svn help checkpoint'"),
+                               subsubcommand);
+    }
+
+  return SVN_NO_ERROR;
+}

Propchange: subversion/branches/shelve-checkpoint3/subversion/svn/checkpoint3-cmd.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/shelve-checkpoint3/subversion/svn/checkpoint3-cmd.c
------------------------------------------------------------------------------
    svn:mime-type = text/x-csrc

Modified: subversion/branches/shelve-checkpoint3/subversion/svn/cl.h
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/svn/cl.h?rev=1803040&r1=1803039&r2=1803040&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/svn/cl.h (original)
+++ subversion/branches/shelve-checkpoint3/subversion/svn/cl.h Wed Jul 26 12:44:33 2017
@@ -272,6 +272,7 @@ svn_opt_subcommand_t
   svn_cl__cat,
   svn_cl__changelist,
   svn_cl__checkout,
+  svn_cl__checkpoint,
   svn_cl__cleanup,
   svn_cl__commit,
   svn_cl__copy,

Modified: subversion/branches/shelve-checkpoint3/subversion/svn/svn.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/svn/svn.c?rev=1803040&r1=1803039&r2=1803040&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/svn/svn.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/svn/svn.c Wed Jul 26 12:44:33 2017
@@ -611,6 +611,30 @@ const svn_opt_subcommand_desc2_t svn_cl_
      "  reporting the action taken.\n"),
     {'r', 'q', 'N', opt_depth, opt_force, opt_ignore_externals} },
 
+  { "checkpoint", svn_cl__checkpoint, {0}, N_
+    ("Checkpoint the local changes.\n"
+     "usage: 0. checkpoint init\n"
+     "       1. checkpoint save\n"
+     "       2. checkpoint revert\n"
+     "       3. checkpoint rollback NUMBER\n"
+     "       4. checkpoint list|log\n"
+     "       5. checkpoint squash\n"
+     "       6. checkpoint finish|uninit\n"
+     "\n"
+     "  0. Initialize checkpointing.\n"
+     "     ### WC must be a checkout of r1 of repo root\n"
+     "     ### required before using other checkpointing commands\n"
+     "  1. Save the working state as a new checkpoint.\n"
+     "  2. Revert the working state to the current checkpoint.\n"
+     "  3. Roll back the working state to checkpoint NUMBER.\n"
+     "  4. List all checkpoints.\n"
+     "  5. Squash all checkpoints to just a base and working state.\n"
+     "  6. Return to a plain WC based on the original repository.\n"
+     "     ### doesn't yet delete the checkpoint repo\n"),
+    {'q',
+     /*'-N', opt_depth, opt_targets, opt_changelist,*/
+     /*SVN_CL__LOG_MSG_OPTIONS*/} },
+
   { "cleanup", svn_cl__cleanup, {0}, N_
     ("Recursively clean up the working copy, removing write locks, resuming\n"
      "unfinished operations, etc.\n"

Modified: subversion/branches/shelve-checkpoint3/tools/client-side/bash_completion
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/tools/client-side/bash_completion?rev=1803040&r1=1803039&r2=1803040&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/tools/client-side/bash_completion (original)
+++ subversion/branches/shelve-checkpoint3/tools/client-side/bash_completion Wed Jul 26 12:44:33 2017
@@ -249,6 +249,7 @@ _svn()
 	cmds="$cmds plist propset pset relocate resolve resolved revert status"
 	cmds="$cmds switch unlock update upgrade"
 	cmds="$cmds shelve shelves unshelve"
+	cmds="$cmds checkpoint"
 
 	# help options have a strange command status...
 	local helpOpts='--help -h'
@@ -1029,6 +1030,9 @@ _svn()
 	shelves)
 		cmdOpts="$qOpts"
 		;;
+	checkpoint)
+		cmdOpts="$qOpts"
+		;;
 	*)
 		;;
 	esac