You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ko...@apache.org on 2022/12/13 09:49:30 UTC

svn commit: r1905955 [5/6] - in /subversion/trunk: ./ build/ build/generator/ notes/i525/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_fs_x/ subversion/libsvn_ra/ subversion/libsvn_ra_local/ subversion/lib...

Modified: subversion/trunk/subversion/libsvn_wc/wc_db_update_move.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db_update_move.c?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db_update_move.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db_update_move.c Tue Dec 13 09:49:29 2022
@@ -154,6 +154,7 @@
 #include "conflicts.h"
 #include "workqueue.h"
 #include "token-map.h"
+#include "textbase.h"
 
 /* Helper functions */
 /* Return the absolute path, in local path style, of LOCAL_RELPATH
@@ -970,15 +971,28 @@ tc_editor_add_file(node_move_baton_t *nm
     }
   else
     {
+      const char *src_abspath;
+      const char *install_from;
+      svn_skel_t *cleanup_work_item;
+
+      src_abspath = svn_dirent_join(b->wcroot->abspath, nmb->src_relpath,
+                                    scratch_pool);
+
       /* Update working file. */
+      SVN_ERR(svn_wc__textbase_setaside_wq(&install_from,
+                                           &cleanup_work_item,
+                                           b->db, src_abspath, NULL,
+                                           b->cancel_func, b->cancel_baton,
+                                           scratch_pool, scratch_pool));
       SVN_ERR(svn_wc__wq_build_file_install(&work_item, b->db,
                                             svn_dirent_join(b->wcroot->abspath,
                                                             relpath,
                                                             scratch_pool),
-                                            NULL,
+                                            install_from,
                                             FALSE /*FIXME: use_commit_times?*/,
                                             TRUE  /* record_file_info */,
                                             scratch_pool, scratch_pool));
+      work_item = svn_wc__wq_merge(work_item, cleanup_work_item, scratch_pool);
     }
 
   SVN_ERR(update_move_list_add(b->wcroot, relpath, b->db,
@@ -1369,33 +1383,56 @@ tc_editor_alter_file(node_move_baton_t *
                                                scratch_pool));
       if (!is_locally_modified)
         {
+          const char *src_abspath;
+          const char *install_from;
+          svn_skel_t *cleanup_work_item;
+
+          src_abspath = svn_dirent_join(b->wcroot->abspath, nmb->src_relpath,
+                                        scratch_pool);
+
+          SVN_ERR(svn_wc__textbase_setaside_wq(&install_from,
+                                               &cleanup_work_item,
+                                               b->db, src_abspath, NULL,
+                                               b->cancel_func, b->cancel_baton,
+                                               scratch_pool, scratch_pool));
           SVN_ERR(svn_wc__wq_build_file_install(&work_item, b->db,
                                                 local_abspath,
-                                                NULL,
+                                                install_from,
                                                 FALSE /* FIXME: use_commit_times? */,
                                                 TRUE  /* record_file_info */,
                                                 scratch_pool, scratch_pool));
 
           work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
+          work_items = svn_wc__wq_merge(work_items, cleanup_work_item, scratch_pool);
 
           content_state = svn_wc_notify_state_changed;
         }
       else
         {
+          svn_skel_t *cleanup_queue = NULL;
+
           /*
            * Run a 3-way merge to update the file, using the pre-update
            * pristine text as the merge base, the post-update pristine
            * text as the merge-left version, and the current content of the
            * moved-here working file as the merge-right version.
            */
-          SVN_ERR(svn_wc__db_pristine_get_path(&old_pristine_abspath,
-                                               b->db, b->wcroot->abspath,
+          SVN_ERR(svn_wc__textbase_setaside_wq(&old_pristine_abspath,
+                                               &work_item, b->db,
+                                               local_abspath,
                                                old_version.checksum,
+                                               b->cancel_func, b->cancel_baton,
                                                scratch_pool, scratch_pool));
-          SVN_ERR(svn_wc__db_pristine_get_path(&new_pristine_abspath,
-                                               b->db, b->wcroot->abspath,
+          cleanup_queue = svn_wc__wq_merge(cleanup_queue, work_item, scratch_pool);
+
+          SVN_ERR(svn_wc__textbase_setaside_wq(&new_pristine_abspath,
+                                               &work_item, b->db,
+                                               local_abspath,
                                                new_version.checksum,
+                                               b->cancel_func, b->cancel_baton,
                                                scratch_pool, scratch_pool));
+          cleanup_queue = svn_wc__wq_merge(cleanup_queue, work_item, scratch_pool);
+
           SVN_ERR(svn_wc__internal_merge(&work_item, &conflict_skel,
                                          &merge_outcome, b->db,
                                          old_pristine_abspath,
@@ -1412,6 +1449,7 @@ tc_editor_alter_file(node_move_baton_t *
                                          scratch_pool, scratch_pool));
 
           work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
+          work_items = svn_wc__wq_merge(work_items, cleanup_queue, scratch_pool);
 
           if (merge_outcome == svn_wc_merge_conflict)
             content_state = svn_wc_notify_state_conflicted;
@@ -1599,6 +1637,7 @@ tc_editor_update_incoming_moved_file(nod
           const char *src_abspath;
           const char *label_left;
           const char *label_target;
+          svn_skel_t *cleanup_queue = NULL;
 
           /*
            * Run a 3-way merge to update the file at its post-move location,
@@ -1607,12 +1646,17 @@ tc_editor_update_incoming_moved_file(nod
            * content of the working file at the pre-move location as the
            * merge-left version.
            */
-          SVN_ERR(svn_wc__db_pristine_get_path(&old_pristine_abspath,
-                                               b->db, b->wcroot->abspath,
-                                               src_checksum,
-                                               scratch_pool, scratch_pool));
           src_abspath = svn_dirent_join(b->wcroot->abspath, src_relpath,
                                         scratch_pool);
+
+          SVN_ERR(svn_wc__textbase_setaside_wq(&old_pristine_abspath,
+                                               &work_item, b->db,
+                                               src_abspath,
+                                               src_checksum,
+                                               b->cancel_func, b->cancel_baton,
+                                               scratch_pool, scratch_pool));
+          cleanup_queue = svn_wc__wq_merge(cleanup_queue, work_item, scratch_pool);
+
           label_left = apr_psprintf(scratch_pool, ".r%ld",
                                     b->old_version->peg_rev);
           label_target = apr_psprintf(scratch_pool, ".r%ld",
@@ -1635,6 +1679,7 @@ tc_editor_update_incoming_moved_file(nod
                                          scratch_pool, scratch_pool));
 
           work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
+          work_items = svn_wc__wq_merge(work_items, cleanup_queue, scratch_pool);
 
           if (merge_outcome == svn_wc_merge_conflict)
             content_state = svn_wc_notify_state_conflicted;
@@ -3147,14 +3192,22 @@ tc_editor_update_add_merge_files(added_n
   if (!is_modified)
     {
       svn_skel_t *work_item = NULL;
+      const char *install_from;
+      svn_skel_t *cleanup_work_item;
 
+      SVN_ERR(svn_wc__textbase_setaside_wq(&install_from,
+                                           &cleanup_work_item,
+                                           b->db, local_abspath, NULL,
+                                           b->cancel_func, b->cancel_baton,
+                                           scratch_pool, scratch_pool));
       SVN_ERR(svn_wc__wq_build_file_install(&work_item, b->db,
-                                            local_abspath, NULL,
+                                            local_abspath, install_from,
                                             /* FIXME: use_commit_times? */
                                             FALSE,
                                             TRUE,  /* record_file_info */
                                             scratch_pool, scratch_pool));
       work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
+      work_items = svn_wc__wq_merge(work_items, cleanup_work_item, scratch_pool);
       content_state = svn_wc_notify_state_changed;
     }
   else
@@ -3162,6 +3215,7 @@ tc_editor_update_add_merge_files(added_n
       const char *empty_file_abspath;
       const char *pristine_abspath;
       svn_skel_t *work_item = NULL;
+      svn_skel_t *cleanup_queue = NULL;
 
       /*
        * Run a 3-way merge to update the file, using the empty file
@@ -3172,9 +3226,13 @@ tc_editor_update_add_merge_files(added_n
       SVN_ERR(svn_io_open_unique_file3(NULL, &empty_file_abspath, NULL,
                                        svn_io_file_del_on_pool_cleanup,
                                        scratch_pool, scratch_pool));
-      SVN_ERR(svn_wc__db_pristine_get_path(&pristine_abspath, b->db,
-                                           b->wcroot->abspath, base_checksum,
+      SVN_ERR(svn_wc__textbase_setaside_wq(&pristine_abspath,
+                                           &work_item, b->db,
+                                           local_abspath,
+                                           base_checksum,
+                                           b->cancel_func, b->cancel_baton,
                                            scratch_pool, scratch_pool));
+      cleanup_queue = svn_wc__wq_merge(cleanup_queue, work_item, scratch_pool);
 
       /* Create a property diff which shows all props as added. */
       SVN_ERR(svn_prop_diffs(&propchanges, working_props,
@@ -3196,6 +3254,7 @@ tc_editor_update_add_merge_files(added_n
                                      scratch_pool, scratch_pool));
 
       work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
+      work_items = svn_wc__wq_merge(work_items, cleanup_queue, scratch_pool);
 
       if (merge_outcome == svn_wc_merge_conflict)
         content_state = svn_wc_notify_state_conflicted;
@@ -3373,12 +3432,23 @@ update_locally_added_node(added_node_bat
        * is currently not installed because the base tree is shadowed.
        * Queue an installation of this node into the working copy. */
       if (base_kind == svn_node_file || base_kind == svn_node_symlink)
-        SVN_ERR(svn_wc__wq_build_file_install(&work_item, db, local_abspath,
-                                              NULL,
-                                              /* FIXME: use_commit_times? */
-                                              FALSE,
-                                              TRUE,  /* record_file_info */
-                                              scratch_pool, scratch_pool));
+        {
+          const char *install_from;
+          svn_skel_t *cleanup_work_item;
+
+          SVN_ERR(svn_wc__textbase_setaside_wq(&install_from,
+                                               &cleanup_work_item,
+                                               db, local_abspath, NULL,
+                                               b->cancel_func, b->cancel_baton,
+                                               scratch_pool, scratch_pool));
+          SVN_ERR(svn_wc__wq_build_file_install(&work_item, db, local_abspath,
+                                                install_from,
+                                                /* FIXME: use_commit_times? */
+                                                FALSE,
+                                                TRUE,  /* record_file_info */
+                                                scratch_pool, scratch_pool));
+          work_item = svn_wc__wq_merge(work_item, cleanup_work_item, scratch_pool);
+        }
       else if (base_kind == svn_node_dir)
         SVN_ERR(svn_wc__wq_build_dir_install(&work_item, db, local_abspath,
                                              scratch_pool, scratch_pool));

Modified: subversion/trunk/subversion/libsvn_wc/wc_db_wcroot.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db_wcroot.c?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db_wcroot.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db_wcroot.c Tue Dec 13 09:49:29 2022
@@ -301,6 +301,7 @@ svn_wc__db_pdh_create_wcroot(svn_wc__db_
                              apr_int64_t wc_id,
                              int format,
                              svn_boolean_t verify_format,
+                             svn_boolean_t store_pristine,
                              apr_pool_t *result_pool,
                              apr_pool_t *scratch_pool)
 {
@@ -388,6 +389,7 @@ svn_wc__db_pdh_create_wcroot(svn_wc__db_
   (*wcroot)->owned_locks = apr_array_make(result_pool, 8,
                                           sizeof(svn_wc__db_wclock_t));
   (*wcroot)->access_cache = apr_hash_make(result_pool);
+  (*wcroot)->store_pristine = store_pristine;
 
   /* SDB will be NULL for pre-NG working copies. We only need to run a
      cleanup when the SDB is present.  */
@@ -494,12 +496,45 @@ verify_stats_table(svn_sqlite__db_t *sdb
   return SVN_NO_ERROR;
 }
 
+/* Read and return the settings for WC_ID in SDB. */
+static svn_error_t *
+read_settings(svn_boolean_t *store_pristine_p,
+              svn_sqlite__db_t *sdb,
+              int format,
+              apr_int64_t wc_id,
+              apr_pool_t *scratch_pool)
+{
+  if (format >= SVN_WC__HAS_SETTINGS)
+    {
+      svn_sqlite__stmt_t *stmt;
+      svn_boolean_t have_row;
+
+      SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_SETTINGS));
+      SVN_ERR(svn_sqlite__bindf(stmt, "i", wc_id));
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+      if (have_row)
+        *store_pristine_p = svn_sqlite__column_boolean(stmt, 0);
+      else
+        *store_pristine_p = TRUE;
+
+      SVN_ERR(svn_sqlite__reset(stmt));
+    }
+  else
+    {
+      *store_pristine_p = TRUE;
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* Sqlite transaction helper for opening the db in
    svn_wc__db_wcroot_parse_local_abspath() to avoid multiple
    db operations that each obtain and release a lock */
 static svn_error_t *
 fetch_sdb_info(apr_int64_t *wc_id,
                int *format,
+               svn_boolean_t *store_pristine,
                svn_sqlite__db_t *sdb,
                apr_pool_t *scratch_pool)
 {
@@ -510,7 +545,7 @@ fetch_sdb_info(apr_int64_t *wc_id,
         svn_wc__db_util_fetch_wc_id(wc_id, sdb, scratch_pool),
         svn_sqlite__read_schema_version(format, sdb, scratch_pool),
         verify_stats_table(sdb, *format, scratch_pool),
-        SVN_NO_ERROR,
+        read_settings(store_pristine, sdb, *format, *wc_id, scratch_pool),
         sdb);
 
   return SVN_NO_ERROR;
@@ -763,9 +798,10 @@ try_symlink_as_dir:
 
       apr_int64_t wc_id;
       int format;
+      svn_boolean_t store_pristine;
       svn_error_t *err;
 
-      err = fetch_sdb_info(&wc_id, &format, sdb, scratch_pool);
+      err = fetch_sdb_info(&wc_id, &format, &store_pristine, sdb, scratch_pool);
       if (err)
         {
           if (err->apr_err == SVN_ERR_WC_CORRUPT)
@@ -786,6 +822,7 @@ try_symlink_as_dir:
                                           : local_abspath),
                             sdb, wc_id, format,
                             db->verify_format,
+                            store_pristine,
                             db->state_pool, scratch_pool);
       if (err && (err->apr_err == SVN_ERR_WC_UNSUPPORTED_FORMAT ||
                   err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED) &&
@@ -861,6 +898,7 @@ try_symlink_as_dir:
                                           : local_abspath),
                             NULL, UNKNOWN_WC_ID, wc_format,
                             db->verify_format,
+                            TRUE,
                             db->state_pool, scratch_pool));
     }
 
@@ -1031,10 +1069,11 @@ svn_wc__db_drop_root(svn_wc__db_t *db,
 
 
 svn_error_t *
-svn_wc__format_from_context(int *format,
-                            svn_wc_context_t *wc_ctx,
-                            const char *local_abspath,
-                            apr_pool_t *scratch_pool)
+svn_wc__settings_from_context(int *format_p,
+                              svn_boolean_t *store_pristine_p,
+                              svn_wc_context_t *wc_ctx,
+                              const char *local_abspath,
+                              apr_pool_t *scratch_pool)
 {
   const char *current_path = local_abspath;
 
@@ -1045,7 +1084,8 @@ svn_wc__format_from_context(int *format,
       wcroot = svn_hash_gets(wc_ctx->db->dir_data, current_path);
       if (wcroot)
         {
-          *format = wcroot->format;
+          *format_p = wcroot->format;
+          *store_pristine_p = wcroot->store_pristine;
           return SVN_NO_ERROR;
         }
 
@@ -1053,6 +1093,7 @@ svn_wc__format_from_context(int *format,
     }
   while (!svn_dirent_is_root(current_path, strlen(current_path)));
 
-  *format = SVN_WC__DEFAULT_VERSION;
+  *format_p = SVN_WC__DEFAULT_VERSION;
+  *store_pristine_p = TRUE;
   return SVN_NO_ERROR;
 }

Modified: subversion/trunk/subversion/svn/checkout-cmd.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/checkout-cmd.c?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/checkout-cmd.c (original)
+++ subversion/trunk/subversion/svn/checkout-cmd.c Tue Dec 13 09:49:29 2022
@@ -173,6 +173,7 @@ svn_cl__checkout(apr_getopt_t *os,
                opt_state->ignore_externals,
                opt_state->force,
                opt_state->compatible_version,
+               opt_state->store_pristine,
                ctx, subpool));
     }
   svn_pool_destroy(subpool);

Modified: subversion/trunk/subversion/svn/cl.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/cl.h?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/cl.h (original)
+++ subversion/trunk/subversion/svn/cl.h Tue Dec 13 09:49:29 2022
@@ -276,6 +276,7 @@ typedef struct svn_cl__opt_state_t
       svn_cl__viewspec_svn11
   } viewspec;                     /* value of --x-viewspec */
   svn_version_t *compatible_version; /* working copy compatibility version */
+  svn_boolean_t store_pristine;
 } svn_cl__opt_state_t;
 
 /* Conflict stats for operations such as update and merge. */
@@ -376,6 +377,7 @@ typedef enum svn_cl__longopt_t {
   opt_drop,
   opt_viewspec,
   opt_compatible_version,
+  opt_store_pristine
 } svn_cl__longopt_t;
 
 /* Options for giving a log message.  (Some of these also have other uses.)
@@ -709,6 +711,11 @@ svn_cl__notifier_mark_export(void *baton
 svn_error_t *
 svn_cl__notifier_mark_wc_to_repos_copy(void *baton);
 
+/* Make the notifier for use with BATON suppress progress notifications
+ */
+svn_error_t *
+svn_cl__notifier_suppress_progress_output(void *baton);
+
 /* Baton for use with svn_cl__check_externals_failed_notify_wrapper(). */
 struct svn_cl__check_externals_failed_notify_baton
 {

Modified: subversion/trunk/subversion/svn/info-cmd.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/info-cmd.c?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/info-cmd.c (original)
+++ subversion/trunk/subversion/svn/info-cmd.c Tue Dec 13 09:49:29 2022
@@ -371,7 +371,8 @@ typedef enum
   info_item_depth,
   info_item_changelist,
   info_item_wc_format,
-  info_item_wc_compatible_version
+  info_item_wc_compatible_version,
+  info_item_store_pristine,
 } info_item_t;
 
 /* Mapping between option keywords and info_item_t. */
@@ -401,6 +402,7 @@ static const info_item_map_t info_item_m
     { SVN__STATIC_STRING("wc-format"),           info_item_wc_format },
     { SVN__STATIC_STRING("wc-compatible-version"),
                                                  info_item_wc_compatible_version },
+    { SVN__STATIC_STRING("store-pristine"),      info_item_store_pristine },
   };
 
 static const apr_size_t info_item_map_len =
@@ -607,6 +609,10 @@ print_info_xml(void *baton,
                                                 info->wc_info->wc_format));
         }
 
+      /* "<store-pristine> xx </store-pristine>" */
+      svn_cl__xml_tagged_cdata(&sb, pool, "store-pristine",
+                               info->wc_info->store_pristine ? "yes" : "no");
+
       /* "<schedule> xx </schedule>" */
       svn_cl__xml_tagged_cdata(&sb, pool, "schedule",
                                schedule_str(info->wc_info->schedule));
@@ -763,6 +769,15 @@ print_info(void *baton,
                                  info->wc_info->wc_format));
     }
 
+  if (info->wc_info)
+    {
+      if (info->wc_info->store_pristine)
+        SVN_ERR(svn_cmdline_fputs(_("Working Copy Store Pristine: yes\n"),
+                                  stdout, pool));
+      else
+        SVN_ERR(svn_cmdline_fputs(_("Working Copy Store Pristine: no\n"),
+                                  stdout, pool));
+    }
 
   if (info->URL)
     SVN_ERR(svn_cmdline_printf(pool, _("URL: %s\n"), info->URL));
@@ -1296,6 +1311,19 @@ print_info_item(void *baton,
                   target_path, pool));
       break;
 
+    case info_item_store_pristine:
+      {
+        const char *text;
+
+        if (info->wc_info)
+          text = info->wc_info->store_pristine ? "yes" : "no";
+        else
+          text = NULL;
+
+        SVN_ERR(print_info_item_string(text, target_path, pool));
+      }
+      break;
+
     default:
       SVN_ERR_MALFUNCTION();
     }

Modified: subversion/trunk/subversion/svn/notify.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/notify.c?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/notify.c (original)
+++ subversion/trunk/subversion/svn/notify.c Tue Dec 13 09:49:29 2022
@@ -53,8 +53,10 @@ struct notify_baton
   svn_boolean_t is_export;
   svn_boolean_t is_wc_to_repos_copy;
   svn_boolean_t sent_first_txdelta;
+  svn_boolean_t hydrating_printed_start;
   int in_external;
   svn_revnum_t progress_revision;
+  svn_boolean_t progress_output;
   svn_boolean_t had_print_error; /* Used to not keep printing error messages
                                     when we've already had one print error. */
   svn_boolean_t wc_was_upgraded;
@@ -1207,6 +1209,29 @@ notify_body(struct notify_baton *nb,
       SVN_ERR(svn_cmdline_printf(pool, _("Committing transaction...\n")));
       break;
 
+    case svn_wc_notify_hydrating_start:
+      nb->hydrating_printed_start = FALSE;
+      break;
+
+    case svn_wc_notify_hydrating_file:
+      if (!nb->hydrating_printed_start)
+        {
+          if (nb->progress_output)
+            SVN_ERR(svn_cmdline_printf(pool, _("Fetching text bases ")));
+          nb->hydrating_printed_start = TRUE;
+        }
+      if (nb->progress_output)
+        SVN_ERR(svn_cmdline_printf(pool, "."));
+      break;
+
+    case svn_wc_notify_hydrating_end:
+      if (nb->hydrating_printed_start)
+        {
+          if (nb->progress_output)
+            SVN_ERR(svn_cmdline_printf(pool, _("done\n")));
+        }
+      break;
+
     case svn_wc_notify_warning:
       /* using handle_error rather than handle_warning in order to show the
        * whole error chain; the latter only shows one error in the chain */
@@ -1261,11 +1286,13 @@ svn_cl__get_notifier(svn_wc_notify_func2
 
   nb->received_some_change = FALSE;
   nb->sent_first_txdelta = FALSE;
+  nb->hydrating_printed_start = FALSE;
   nb->is_checkout = FALSE;
   nb->is_export = FALSE;
   nb->is_wc_to_repos_copy = FALSE;
   nb->in_external = 0;
   nb->progress_revision = 0;
+  nb->progress_output = TRUE;
   nb->had_print_error = FALSE;
   nb->conflict_stats = conflict_stats;
   SVN_ERR(svn_dirent_get_absolute(&nb->path_prefix, "", pool));
@@ -1302,6 +1329,15 @@ svn_cl__notifier_mark_wc_to_repos_copy(v
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_cl__notifier_suppress_progress_output(void *baton)
+{
+  struct notify_baton *nb = baton;
+
+  nb->progress_output = FALSE;
+  return SVN_NO_ERROR;
+}
+
 void
 svn_cl__check_externals_failed_notify_wrapper(void *baton,
                                               const svn_wc_notify_t *n,

Modified: subversion/trunk/subversion/svn/schema/info.rnc
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/schema/info.rnc?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/schema/info.rnc (original)
+++ subversion/trunk/subversion/svn/schema/info.rnc Tue Dec 13 09:49:29 2022
@@ -59,6 +59,7 @@ wc-info =
     wcroot-abspath?,
     wc-compatible-version?,
     wc-format?,
+    store-pristine?,
     schedule?,
     changelist?,
     copy-from-url?,
@@ -74,6 +75,7 @@ wc-info =
 wcroot-abspath = element wcroot-abspath { string }
 wc-compatible-version = element wc-compatible-version { string }
 wc-format = element wc-format { xsd:nonNegativeInteger }
+store-pristine = element store-pristine { "yes" | "no" }
 
 schedule =
   element schedule { "normal" | "add" | "delete" | "replace" | "none" }

Modified: subversion/trunk/subversion/svn/svn.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/svn.c?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/svn.c (original)
+++ subversion/trunk/subversion/svn/svn.c Tue Dec 13 09:49:29 2022
@@ -371,6 +371,17 @@ const apr_getopt_option_t svn_cl__option
                        "                             "
                        "version ARG (\"1.8\", \"1.9.5\", etc.)")},
 
+  {"store-pristine", opt_store_pristine, 1,
+                       N_("Configure the working copy to either store local\n"
+                       "                             "
+                       "copies of pristine contents ('yes') or to fetch\n"
+                       "                             "
+                       "them on demand ('no'). Fetching on demand saves\n"
+                       "                             "
+                       "disk space, but may require network access for\n"
+                       "                             "
+                       "commands such as diff or revert. Default: 'yes'.")},
+
   /* Long-opt Aliases
    *
    * These have NULL descriptions, but an option code that matches some
@@ -543,7 +554,7 @@ svn_cl__cmd_table_main[] =
      "  reporting the action taken.\n"
     )},
     {'r', 'q', 'N', opt_depth, opt_force, opt_ignore_externals,
-     opt_compatible_version},
+     opt_compatible_version, opt_store_pristine},
     {{'N', N_("obsolete; same as --depth=files")}} },
 
   { "cleanup", svn_cl__cleanup, {0}, {N_(
@@ -800,7 +811,11 @@ svn_cl__cmd_table_main[] =
                         "                             "
                         "                first version supporting TARGET WC\n"
                         "                             "
-                        "   'changelist' changelist of TARGET in WC")}},
+                        "   'changelist' changelist of TARGET in WC\n"
+                        "                             "
+                        "   'store-pristine'\n"
+                        "                             "
+                        "                TARGET's working copy pristine mode")}},
   },
 
   { "list", svn_cl__list, {"ls"},
@@ -2178,6 +2193,7 @@ sub_main(int *exit_code, int argc, const
   opt_state.accept_which = svn_cl__accept_unspecified;
   opt_state.show_revs = svn_cl__show_revs_invalid;
   opt_state.file_size_unit = SVN_CL__SIZE_UNIT_NONE;
+  opt_state.store_pristine = svn_tristate_unknown;
 
   /* No args?  Show usage. */
   if (argc <= 1)
@@ -2734,6 +2750,15 @@ sub_main(int *exit_code, int argc, const
       case opt_compatible_version:
         SVN_ERR(parse_compatible_version(&opt_state, opt_arg, pool));
         break;
+      case opt_store_pristine:
+        SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+        opt_state.store_pristine = svn_tristate__from_word(utf8_opt_arg);
+        if (opt_state.store_pristine == svn_tristate_unknown)
+          return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                   _("Unknown value '%s' for %s.\n"
+                                     "Supported values: %s"),
+                                   utf8_opt_arg, "--store-pristine", "yes, no");
+        break;
       default:
         /* Hmmm. Perhaps this would be a good place to squirrel away
            opts that commands like svn diff might need. Hmmm indeed. */
@@ -3244,6 +3269,12 @@ sub_main(int *exit_code, int argc, const
     {
       SVN_ERR(svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2,
                                    conflict_stats, pool));
+
+      /* Data-outputting commands should not print progress notifications
+       * (such as hydrating text bases) on stdout. */
+      if (subcommand->cmd_func == svn_cl__cat
+          || subcommand->cmd_func == svn_cl__diff)
+        SVN_ERR(svn_cl__notifier_suppress_progress_output(ctx->notify_baton2));
     }
 
   /* Get password from stdin if necessary */

Modified: subversion/trunk/subversion/tests/cmdline/authz_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/authz_tests.py?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/authz_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/authz_tests.py Tue Dec 13 09:49:29 2022
@@ -1657,11 +1657,26 @@ def remove_access_after_commit(sbox):
 
   # And expect a mixed rev copy
   expected_status.tweak('A/D/G/rho', status='A ', entry_status='  ')
-  svntest.actions.run_and_verify_update(wc_dir,
-                                        expected_output,
-                                        expected_disk,
-                                        expected_status,
-                                        [], True)
+
+  if svntest.actions.get_wc_store_pristine(wc_dir):
+    svntest.actions.run_and_verify_update(wc_dir,
+                                          expected_output,
+                                          expected_disk,
+                                          expected_status,
+                                          [], True)
+  else:
+    # We are unable to fetch the pristine without read access.
+    # So in a working copy without local pristines, the update is
+    # currently expected to fail.
+    if svntest.main.is_ra_type_dav():
+      expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
+    elif svntest.main.is_ra_type_svn():
+      expected_err = ".*svn: E170001: Authorization failed.*"
+    else:
+      raise svntest.Failure
+
+    svntest.actions.run_and_verify_update(wc_dir, None, None, None,
+                                          expected_err, True)
 
 @Issue(4793)
 @Skip(svntest.main.is_ra_type_file)
@@ -1818,6 +1833,36 @@ def log_inaccessible_copyfrom(sbox):
                                      'log', '-r2', '-v',
                                      sbox.repo_url)
 
+@Skip(svntest.main.is_ra_type_file)
+def cat_base_after_repo_access_removed(sbox):
+  "cat_base_after_repo_access_removed"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  svntest.main.write_restrictive_svnserve_conf(sbox.repo_dir)
+  svntest.main.write_authz_file(sbox, { "/"      : "*=rw",
+                                        "/A/D"   : "*="})
+
+  # Local modification so base can't be derived from working version
+  sbox.simple_append('A/D/G/pi', 'appended\n')
+
+  # With repository read access denied, expect we can still access the
+  # text base locally, if and only if text bases are present.
+  if svntest.actions.get_wc_store_pristine(wc_dir):
+    svntest.actions.run_and_verify_svn("This is the file 'pi'.\n", [],
+                                       'cat', sbox.ospath('A/D/G/pi') + '@BASE')
+  else:
+    if svntest.main.is_ra_type_dav():
+      expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
+    elif svntest.main.is_ra_type_svn():
+      expected_err = ".*svn: E170001: Authorization failed.*"
+    else:
+      raise svntest.Failure
+
+    svntest.actions.run_and_verify_svn(None, expected_err,
+                                       'cat', sbox.ospath('A/D/G/pi') + '@BASE')
+
 
 ########################################################################
 # Run the tests
@@ -1860,6 +1905,7 @@ test_list = [ None,
               empty_group,
               delete_file_with_starstar_rules,
               log_inaccessible_copyfrom,
+              cat_base_after_repo_access_removed,
              ]
 serial_only = True
 

Modified: subversion/trunk/subversion/tests/cmdline/basic_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/basic_tests.py?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/basic_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/basic_tests.py Tue Dec 13 09:49:29 2022
@@ -377,6 +377,10 @@ def basic_commit_corruption(sbox):
   mu_path = sbox.ospath('A/mu')
   svntest.main.file_append(mu_path, 'appended mu text')
 
+  # We are about to manually edit mu's text-base, so run "diff" to
+  # guarantee that the text-base is available in all pristine modes.
+  svntest.actions.run_and_verify_svn(None, [], 'diff', mu_path)
+
   # Created expected output tree for 'svn ci'
   expected_output = wc.State(wc_dir, {
     'A/mu' : Item(verb='Sending'),
@@ -444,6 +448,12 @@ def basic_update_corruption(sbox):
   svntest.actions.run_and_verify_svn(None, [],
                                      'co', sbox.repo_url, other_wc)
 
+  # The test manually edits mu's text-base when mu is unmodified.
+  # Unmodified files don't have their text-bases available with
+  # --store-pristine=no, so skip if that is the case.
+  if not svntest.actions.get_wc_store_pristine(other_wc):
+    raise svntest.Skip('Test assumes a working copy with pristine')
+
   # Make a local mod to mu
   mu_path = sbox.ospath('A/mu')
   svntest.main.file_append(mu_path, 'appended mu text')
@@ -2544,6 +2554,9 @@ def basic_auth_test(sbox):
   if svntest.main.options.wc_format_version:
     common_opts += ('--compatible-version',
                     svntest.main.options.wc_format_version)
+  if svntest.main.options.store_pristine:
+    common_opts += ('--store-pristine',
+                    svntest.main.options.store_pristine)
 
   # Checkout with jrandom
   exit_code, output, errput = svntest.main.run_command(

Modified: subversion/trunk/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/diff_tests.py?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/diff_tests.py Tue Dec 13 09:49:29 2022
@@ -3082,16 +3082,16 @@ def diff_external_diffcmd(sbox):
   if sys.platform == 'win32':
     diff_script_path = "%s.bat" % diff_script_path
 
-  expected_output = svntest.verify.ExpectedOutput([
+  expected_output = svntest.verify.RegexListOutput([
     "Index: iota\n",
     "===================================================================\n",
     "-u\n",
     "-L\n",
-    "iota\t(revision 1)\n",
+    r"iota\t\(revision 1\)\n",
     "-L\n",
-    "iota\t(working copy)\n",
-    os.path.abspath(svntest.wc.text_base_path("iota")) + "\n",
-    os.path.abspath("iota") + "\n"])
+    r"iota\t\(working copy\)\n",
+    re.escape(os.path.abspath(svntest.main.get_admin_name())) + '.*' + "\n",
+    re.escape(os.path.abspath("iota")) + "\n"])
 
   # Check that the output of diff corresponds with the expected arguments,
   # in the correct order.

Modified: subversion/trunk/subversion/tests/cmdline/externals_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/externals_tests.py?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/externals_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/externals_tests.py Tue Dec 13 09:49:29 2022
@@ -3431,6 +3431,7 @@ def update_deletes_file_external(sbox):
 
 
 @Issue(4519)
+@Wimp("May trigger an existing issue, see upgrade_tests.py:upgrade_latest_format()")
 def switch_relative_externals(sbox):
   "switch relative externals"
 

Modified: subversion/trunk/subversion/tests/cmdline/move_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/move_tests.py?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/move_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/move_tests.py Tue Dec 13 09:49:29 2022
@@ -1599,21 +1599,26 @@ def move_conflict_details(sbox):
   sbox.simple_append('B/E/new-dir3', 'something')
   sbox.simple_add('B/E/new-dir3')
 
+  store_pristine = svntest.actions.get_wc_store_pristine(sbox.wc_dir)
 
-  expected_output = [
-    " C   %s\n" % sbox.ospath('B'),         # Property conflicted
-    " U   %s\n" % sbox.ospath('B/E'),       # Just updated
-    "C    %s\n" % sbox.ospath('B/E/alpha'), # Text conflicted
-    "   C %s\n" % sbox.ospath('B/E/beta'),
-    "   C %s\n" % sbox.ospath('B/E/new'),
-    "   C %s\n" % sbox.ospath('B/E/new-dir1'),
-    "   C %s\n" % sbox.ospath('B/E/new-dir2'),
-    "   C %s\n" % sbox.ospath('B/E/new-dir3'),
-    "   C %s\n" % sbox.ospath('B/F'),
-    "   C %s\n" % sbox.ospath('B/lambda'),
-    "Updated to revision 2.\n",
-    "Tree conflict at '%s' marked as resolved.\n" % sbox.ospath('A/B')
-  ]
+  expected_output = svntest.verify.RegexListOutput(
+    ([] if store_pristine else ["Fetching text bases [.]+done"])
+    +
+    [re.escape(x) for x in [
+      " C   %s\n" % sbox.ospath('B'),         # Property conflicted
+      " U   %s\n" % sbox.ospath('B/E'),       # Just updated
+      "C    %s\n" % sbox.ospath('B/E/alpha'), # Text conflicted
+      "   C %s\n" % sbox.ospath('B/E/beta'),
+      "   C %s\n" % sbox.ospath('B/E/new'),
+      "   C %s\n" % sbox.ospath('B/E/new-dir1'),
+      "   C %s\n" % sbox.ospath('B/E/new-dir2'),
+      "   C %s\n" % sbox.ospath('B/E/new-dir3'),
+      "   C %s\n" % sbox.ospath('B/F'),
+      "   C %s\n" % sbox.ospath('B/lambda'),
+      "Updated to revision 2.\n",
+      "Tree conflict at '%s' marked as resolved.\n" % sbox.ospath('A/B')
+    ]]
+  )
   svntest.actions.run_and_verify_svn(expected_output, [],
                                      'resolve', sbox.ospath('A/B'),
                                      '--depth', 'empty',

Modified: subversion/trunk/subversion/tests/cmdline/revert_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/revert_tests.py?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/revert_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/revert_tests.py Tue Dec 13 09:49:29 2022
@@ -60,8 +60,8 @@ def run_and_verify_revert(targets, optio
   if reverted_paths is None:
     reverted_paths = targets
   expected_output = expected_output_revert(reverted_paths, skipped_paths)
-  svntest.actions.run_and_verify_svn(expected_output, [],
-                                     *(['revert'] + options + targets))
+  svntest.actions.run_and_verify_revert_output(expected_output,
+                                               *(options + targets))
 
 def revert_replacement_with_props(sbox, wc_copy):
   """Helper implementing the core of
@@ -260,6 +260,34 @@ def revert_reexpand_keyword(sbox):
 
   sbox.build()
   wc_dir = sbox.wc_dir
+
+  # The test expects two different things to happen during revert, depending
+  # on whether an `svn cleanup` or any other command that repairs the
+  # timestamps was called in between:
+  #
+  # - In the first part, we expect a revert to change file contents and
+  #   re-expand its keywords, because a revert happens right after editing
+  #   the file.
+  #
+  # - In the second part, we expect a revert to skip the file with exactly
+  #   the same contents, because there's an in-between operation that has
+  #   recorded the new unmodified timestamp in the db.  (See r1101730 and
+  #   r1101817.)
+  #
+  # This is a problem, because we expect two different things to happen for
+  # two identical on-disk file states.  The only difference is whether any
+  # of the commands that perform the internal timestamp bookkeeping was
+  # called in between.  For example, calling `svn cleanup` after editing the
+  # file makes the first and the second parts of the test behave identically.
+  #
+  # This problem prevents us from properly testing the `--store-pristine=no`
+  # case, because when we walk the text-bases we use that opportunity to
+  # repair timestamps, but that also makes the first and the second reverts
+  # in this test behave identically.  Let's skip testing this case for now,
+  # until we resolve the described problem with opposite expectations.
+  if not svntest.actions.get_wc_store_pristine(wc_dir):
+    raise svntest.Skip()
+
   newfile_path = os.path.join(wc_dir, "newfile")
   unexpanded_contents = "This is newfile: $Rev$.\n"
 

Modified: subversion/trunk/subversion/tests/cmdline/svntest/actions.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/svntest/actions.py?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/svntest/actions.py (original)
+++ subversion/trunk/subversion/tests/cmdline/svntest/actions.py Tue Dec 13 09:49:29 2022
@@ -527,7 +527,7 @@ def expected_noop_update_output(rev):
   """Return an ExpectedOutput object describing what we'd expect to
   see from an update to revision REV that was effectively a no-op (no
   server changes transmitted)."""
-  return verify.createExpectedOutput("Updating '.*':|At revision %d."
+  return verify.createExpectedOutput("Updating '.*':|Fetching text bases [.]+done|At revision %d."
                                      % (rev),
                                      "no-op update")
 
@@ -1931,8 +1931,12 @@ def _run_and_verify_resolve(cmd, expecte
         expected_paths]),
     ],
     match_all=False)
-  run_and_verify_svn(expected_output, [],
-                     cmd, *args)
+  exit_code, out, err = main.run_svn(None, cmd, *args)
+  out = [line for line in out
+         if not re.match(r'Fetching text bases [.]+done\n', line)]
+  verify.verify_outputs("Unexpected output", out, err,
+                        expected_output, [])
+  verify.verify_exit_code("Unexpected return code", exit_code, 0)
 
 def run_and_verify_resolve(expected_paths, *args):
   """Run "svn resolve" with arguments ARGS, and verify that it resolves the
@@ -1955,8 +1959,18 @@ def run_and_verify_revert(expected_paths
   expected_output = verify.UnorderedOutput([
     "Reverted '" + path + "'\n" for path in
     expected_paths])
-  run_and_verify_svn(expected_output, [],
-                     "revert", *args)
+  run_and_verify_revert_output(expected_output, *args)
+
+def run_and_verify_revert_output(expected_output, *args):
+  """Run "svn revert" with arguments ARGS, and verify that it outputs
+     the text in EXPECTED_OUTPUT (and no stderr or exit code).
+  """
+  exit_code, out, err = main.run_svn(None, "revert", *args)
+  out = [line for line in out
+         if not re.match(r'Fetching text bases [.]+done\n', line)]
+  verify.verify_outputs("Unexpected output", out, err,
+                        expected_output, [])
+  verify.verify_exit_code("Unexpected return code", exit_code, 0)
 
 
 ######################################################################
@@ -2075,6 +2089,20 @@ def get_wc_base_rev(wc_dir):
   "Return the BASE revision of the working copy at WC_DIR."
   return run_and_parse_info(wc_dir)[0]['Revision']
 
+def get_wc_store_pristine(wc_dir):
+  "Return whether the working copy at WC_DIR stores pristine contents."
+  _, output, _ = run_and_verify_svn(
+    None, [],
+    'info', '--show-item=store-pristine', '--no-newline',
+    wc_dir)
+
+  if output == ['yes']:
+    return True
+  elif output == ['no']:
+    return False
+  else:
+    raise verify.SVNUnexpectedStdout(output)
+
 def load_dumpfile(filename):
   "Return the contents of the FILENAME assuming that it is a dump file"
   with open(filename, "rb") as fp:

Modified: subversion/trunk/subversion/tests/cmdline/svntest/main.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/svntest/main.py?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/svntest/main.py (original)
+++ subversion/trunk/subversion/tests/cmdline/svntest/main.py Tue Dec 13 09:49:29 2022
@@ -800,6 +800,18 @@ def copy_trust(dst_cfgdir, src_cfgdir):
   for f in os.listdir(src_ssl_dir):
     shutil.copy(os.path.join(src_ssl_dir, f), os.path.join(dst_ssl_dir, f))
 
+def _with_store_pristine(args):
+  if '--store-pristine' in args \
+      or any(str(one_arg).startswith('--store-pristine=') for one_arg in args) \
+      or options.store_pristine is None:
+    return args
+  non_opt_args = [a for a in args if not str(a).startswith('-')]
+  if non_opt_args:
+    subcommand = non_opt_args[0]
+    if subcommand in ['co', 'checkout']:
+      return args + ('--store-pristine', options.store_pristine)
+  return args
+
 def _with_wc_format_version(args):
   if '--compatible-version' in args \
       or any(str(one_arg).startswith('--compatible-version=') for one_arg in args) \
@@ -847,7 +859,8 @@ def run_svn(error_expected, *varargs):
   you're just checking that something does/doesn't come out of
   stdout/stderr, you might want to use actions.run_and_verify_svn()."""
   return run_command(svn_binary, error_expected, False,
-                     *(_with_wc_format_version(_with_auth(_with_config_dir(varargs)))))
+                     *(_with_store_pristine(_with_wc_format_version(
+                       _with_auth(_with_config_dir(varargs))))))
 
 # For running svnadmin.  Ignores the output.
 def run_svnadmin(*varargs):
@@ -1765,6 +1778,11 @@ def wc_format(ver=None):
     return 31
   raise Exception("Unrecognized version number '%s'" % (ver,))
 
+def wc_supports_optional_pristine():
+  if options.wc_format_version is None:
+    return True
+  else:
+    return wc_format(options.wc_format_version) >= 32
 
 ######################################################################
 
@@ -1852,6 +1870,8 @@ class TestSpawningThread(threading.Threa
       args.append('--allow-remote-http-connection')
     if options.svn_bin:
       args.append('--bin=' + options.svn_bin)
+    if options.store_pristine:
+      args.append('--store-pristine=' + options.store_pristine)
 
     result, stdout_lines, stderr_lines = spawn_process(command, 0, False, None,
                                                        *args)
@@ -2291,6 +2311,8 @@ def _create_parser(usage=None):
                     help='Set directory deltification option (for fsfs)')
   parser.add_option('--allow-remote-http-connection', action='store_true',
                     help='Run tests that connect to remote HTTP(S) servers')
+  parser.add_option('--store-pristine', action='store', type='str',
+                    help='Set the WC pristine mode')
 
   # most of the defaults are None, but some are other values, set them here
   parser.set_defaults(

Modified: subversion/trunk/subversion/tests/cmdline/svntest/mergetrees.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/svntest/mergetrees.py?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/svntest/mergetrees.py (original)
+++ subversion/trunk/subversion/tests/cmdline/svntest/mergetrees.py Tue Dec 13 09:49:29 2022
@@ -95,6 +95,8 @@ def expected_merge_output(rev_ranges, ad
   if (two_url):
     lines += ["--- Recording mergeinfo for merge between repository URLs .*\n"]
 
+  lines += ["Fetching text bases [.]+done\n"]
+
   # Address "The Backslash Plague"
   #
   # If ADDITIONAL_LINES are present there are possibly paths in it with

Modified: subversion/trunk/subversion/tests/cmdline/svntest/wc.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/svntest/wc.py?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/svntest/wc.py (original)
+++ subversion/trunk/subversion/tests/cmdline/svntest/wc.py Tue Dec 13 09:49:29 2022
@@ -590,7 +590,7 @@ class State:
 
     desc = { }
     for line in lines:
-      if line.startswith('DBG:'):
+      if line.startswith('DBG:') or re.match('^Fetching text bases [.]+done$', line):
         continue
 
       match = _re_parse_checkout.search(line)

Modified: subversion/trunk/subversion/tests/cmdline/trans_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/trans_tests.py?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/trans_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/trans_tests.py Tue Dec 13 09:49:29 2022
@@ -393,9 +393,16 @@ def keywords_from_birth(sbox):
     '$URL::x%sx$\n' % (' ' * len(url_expand_test_data))
     ]
 
-  fp = open(svntest.wc.text_base_path(fixed_length_keywords_path), 'r')
-  actual_textbase_kw = fp.readlines()
-  fp.close()
+  # Read the text base, either from a locally stored file or from the repo.
+  if svntest.actions.get_wc_store_pristine(wc_dir):
+    fp = open(svntest.wc.text_base_path(fixed_length_keywords_path), 'r')
+    actual_textbase_kw = fp.readlines()
+    fp.close()
+  else:
+    _, actual_textbase_kw, _ = svntest.main.run_svn(False,
+                                 'cat', '-rHEAD', '--ignore-keywords',
+                                 fixed_length_keywords_path)
+
   check_keywords(actual_textbase_kw, kw_textbase, "text base")
 
   # Check the Id keyword for filename with spaces.
@@ -597,10 +604,11 @@ def eol_change_is_text_mod(sbox):
     if contents != b"1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n":
       raise svntest.Failure
 
-  foo_base_path = svntest.wc.text_base_path(foo_path)
-  base_contents = open(foo_base_path, 'rb').read()
-  if contents != base_contents:
-    raise svntest.Failure
+  if svntest.actions.get_wc_store_pristine(wc_dir):
+    foo_base_path = svntest.wc.text_base_path(foo_path)
+    base_contents = open(foo_base_path, 'rb').read()
+    if contents != base_contents:
+      raise svntest.Failure
 
 #----------------------------------------------------------------------
 # Regression test for issue #1151.  A single file in a directory

Modified: subversion/trunk/subversion/tests/cmdline/update_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/update_tests.py?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/update_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/update_tests.py Tue Dec 13 09:49:29 2022
@@ -1188,10 +1188,13 @@ def another_hudson_problem(sbox):
                      'D    '+G_path+'\n',
                      'Updated to revision 3.\n',
                     ]
+  expected_output = [re.escape(s) for s in expected_output]
+  if not svntest.actions.get_wc_store_pristine(wc_dir):
+    expected_output.append('Fetching text bases [.]*done\n')
 
   # Sigh, I can't get run_and_verify_update to work (but not because
   # of issue 919 as far as I can tell)
-  expected_output = svntest.verify.UnorderedOutput(expected_output)
+  expected_output = svntest.verify.UnorderedRegexListOutput(expected_output)
   svntest.actions.run_and_verify_svn(expected_output, [],
                                      'up', G_path)
 
@@ -3713,65 +3716,74 @@ def update_accept_conflicts(sbox):
   # Setup SVN_EDITOR and SVN_MERGE for --accept={edit,launch}.
   svntest.main.use_editor('append_foo')
 
+  def run_and_verify_update_output(expected_stdout, expected_stderr, *args):
+    expected_exit = 0
+    exit_code, out, err = svntest.main.run_svn(True, *args)
+    out = [line for line in out
+           if not re.match(r'Fetching text bases [.]+done\n', line)]
+    verify.verify_outputs("Unexpected output", out, err,
+                          expected_stdout, expected_stderr)
+    verify.verify_exit_code("Unexpected return code", exit_code, expected_exit)
+
   # iota: no accept option
   # Just leave the conflicts alone, since run_and_verify_svn already uses
   # the --non-interactive option.
-  svntest.actions.run_and_verify_svn(update_output_with_conflicts(
-                                       3, iota_path_backup),
-                                     [],
-                                     'update', iota_path_backup)
+  run_and_verify_update_output(update_output_with_conflicts(
+                                 3, iota_path_backup),
+                               [],
+                               'update', iota_path_backup)
 
   # lambda: --accept=postpone
   # Just leave the conflicts alone.
-  svntest.actions.run_and_verify_svn(update_output_with_conflicts(
-                                       3, lambda_path_backup),
-                                     [],
-                                     'update', '--accept=postpone',
-                                     lambda_path_backup)
+  run_and_verify_update_output(update_output_with_conflicts(
+                                 3, lambda_path_backup),
+                               [],
+                               'update', '--accept=postpone',
+                               lambda_path_backup)
 
   # mu: --accept=base
   # Accept the pre-update base file.
-  svntest.actions.run_and_verify_svn(update_output_with_conflicts_resolved(
-                                       3, mu_path_backup),
-                                     [],
-                                     'update', '--accept=base',
-                                     mu_path_backup)
+  run_and_verify_update_output(update_output_with_conflicts_resolved(
+                                 3, mu_path_backup),
+                               [],
+                               'update', '--accept=base',
+                               mu_path_backup)
 
   # alpha: --accept=mine
   # Accept the user's working file.
-  svntest.actions.run_and_verify_svn(update_output_with_conflicts_resolved(
-                                       3, alpha_path_backup),
-                                     [],
-                                     'update', '--accept=mine-full',
-                                     alpha_path_backup)
+  run_and_verify_update_output(update_output_with_conflicts_resolved(
+                                 3, alpha_path_backup),
+                               [],
+                               'update', '--accept=mine-full',
+                               alpha_path_backup)
 
   # beta: --accept=theirs
   # Accept their file.
-  svntest.actions.run_and_verify_svn(update_output_with_conflicts_resolved(
-                                       3, beta_path_backup),
-                                     [],
-                                     'update', '--accept=theirs-full',
-                                     beta_path_backup)
+  run_and_verify_update_output(update_output_with_conflicts_resolved(
+                                 3, beta_path_backup),
+                               [],
+                               'update', '--accept=theirs-full',
+                               beta_path_backup)
 
   # pi: --accept=edit
   # Run editor and accept the edited file. The merge tool will leave
   # conflicts in place, so expect a message on stderr, but expect
   # svn to exit with an exit code of 0.
-  svntest.actions.run_and_verify_svn2(update_output_with_conflicts_resolved(
-                                        3, p_i_path_backup),
-                                      "system(.*) returned.*", 0,
-                                      'update', '--accept=edit',
-                                      '--force-interactive',
-                                      p_i_path_backup)
+  run_and_verify_update_output(update_output_with_conflicts_resolved(
+                                 3, p_i_path_backup),
+                               "system(.*) returned.*",
+                               'update', '--accept=edit',
+                               '--force-interactive',
+                               p_i_path_backup)
 
   # rho: --accept=launch
   # Run the external merge tool, it should leave conflict markers in place.
-  svntest.actions.run_and_verify_svn(update_output_with_conflicts(
-                                       3, rho_path_backup),
-                                     [],
-                                     'update', '--accept=launch',
-                                     '--force-interactive',
-                                     rho_path_backup)
+  run_and_verify_update_output(update_output_with_conflicts(
+                                 3, rho_path_backup),
+                               [],
+                               'update', '--accept=launch',
+                               '--force-interactive',
+                               rho_path_backup)
 
   # Set the expected disk contents for the test
   expected_disk = svntest.main.greek_state.copy()
@@ -5175,14 +5187,27 @@ def skip_access_denied(sbox):
   expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
   expected_status.tweak('iota', status='M ', wc_rev=2)
 
-  # And now check that update skips the path
-  # *and* status shows the path as modified.
-  svntest.actions.run_and_verify_update(wc_dir,
-                                        expected_output,
-                                        None,
-                                        expected_status,
-                                        [], False,
-                                        wc_dir, '-r', '1')
+  if svntest.actions.get_wc_store_pristine(wc_dir):
+    # And now check that update skips the path *and* status shows
+    # the path as modified.
+    svntest.actions.run_and_verify_update(wc_dir,
+                                          expected_output,
+                                          None,
+                                          expected_status,
+                                          [], False,
+                                          wc_dir, '-r', '1')
+  else:
+    # For a working copy that doesn't store local pristine contents, don't
+    # skip access violation errors when determining if a file was modified.
+    # Because if we did that (and treated such files as modified, see above),
+    # we'd also find ourselves uncontrollably fetching and removing pristines
+    # based on transient errors -- which probably is an undesired property.
+    # So we currently expect to receive an error:
+    expected_err = ".*svn: E155039: Couldn't open a working copy file*"
+    svntest.actions.run_and_verify_update(wc_dir,
+                                          None, None, None,
+                                          expected_err, False,
+                                          wc_dir, '-r', '1')
 
   f.close()
 

Modified: subversion/trunk/subversion/tests/cmdline/upgrade_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/upgrade_tests.py?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/upgrade_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/upgrade_tests.py Tue Dec 13 09:49:29 2022
@@ -116,14 +116,14 @@ def check_formats(sbox, expected_formats
     raise svntest.Failure("found format '%s'; expected '%s'; in wc '%s'" %
                           (formats, expected_formats, sbox.wc_dir))
 
-
 def check_pristine(sbox, files):
   for file in files:
     file_path = sbox.ospath(file)
-    file_text = open(file_path, 'r').read()
-    file_pristine = open(svntest.wc.text_base_path(file_path), 'r').read()
-    if (file_text != file_pristine):
-      raise svntest.Failure("pristine mismatch for '%s'" % (file))
+    if svntest.actions.get_wc_store_pristine(file_path):
+      file_text = open(file_path, 'r').read()
+      file_pristine = open(svntest.wc.text_base_path(file_path), 'r').read()
+      if (file_text != file_pristine):
+        raise svntest.Failure("pristine mismatch for '%s'" % (file))
 
 def check_dav_cache(dir_path, wc_id, expected_dav_caches):
   dot_svn = svntest.main.get_admin_name()
@@ -140,9 +140,8 @@ def check_dav_cache(dir_path, wc_id, exp
   minor = sqlite_ver[1]
   patch = sqlite_ver[2]
 
-  if major < 3 or (major == 3 and minor < 6) \
-     or (major == 3 and minor == 6 and patch < 18):
-       return # We need a newer SQLite
+  if major < 3 or (major == 3 and minor < 9):
+    return # We need a newer SQLite
 
   for local_relpath, expected_dav_cache in expected_dav_caches.items():
     # NODES conversion is complete enough that we can use it if it exists

Modified: subversion/trunk/subversion/tests/libsvn_client/client-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_client/client-test.c?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_client/client-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_client/client-test.c Tue Dec 13 09:49:29 2022
@@ -392,7 +392,9 @@ test_patch(const svn_test_opts_t *opts,
   SVN_ERR(svn_client_checkout4(NULL, repos_url, wc_path,
                                &peg_rev, &rev, svn_depth_infinity,
                                TRUE, FALSE,
-                               opts->wc_format_version, ctx, pool));
+                               opts->wc_format_version,
+                               opts->store_pristine,
+                               ctx, pool));
 
   /* Create the patch file. */
   patch_file_path = svn_dirent_join_many(
@@ -466,13 +468,17 @@ test_wc_add_scenarios(const svn_test_opt
   /* Checkout greek tree as wc_path */
   SVN_ERR(svn_client_checkout4(NULL, repos_url, wc_path, &peg_rev, &rev,
                                svn_depth_infinity, FALSE, FALSE,
-                               opts->wc_format_version, ctx, pool));
+                               opts->wc_format_version,
+                               opts->store_pristine,
+                               ctx, pool));
 
   /* Now checkout again as wc_path/NEW */
   new_dir_path = svn_dirent_join(wc_path, "NEW", pool);
   SVN_ERR(svn_client_checkout4(NULL, repos_url, new_dir_path, &peg_rev, &rev,
                                svn_depth_infinity, FALSE, FALSE,
-                               opts->wc_format_version, ctx, pool));
+                               opts->wc_format_version,
+                               opts->store_pristine,
+                               ctx, pool));
 
   ex_dir_path = svn_dirent_join(wc_path, "NEW_add", pool);
   ex2_dir_path = svn_dirent_join(wc_path, "NEW_add2", pool);
@@ -632,7 +638,9 @@ test_16k_add(const svn_test_opts_t *opts
   SVN_ERR(svn_client_checkout4(NULL, repos_url, wc_path,
                                &peg_rev, &rev, svn_depth_infinity,
                                TRUE, FALSE,
-                               opts->wc_format_version, ctx, pool));
+                               opts->wc_format_version,
+                               opts->store_pristine,
+                               ctx, pool));
 
   for (i = 0; i < 16384; i++)
     {
@@ -763,7 +771,9 @@ test_foreign_repos_copy(const svn_test_o
   SVN_ERR(svn_client_checkout4(NULL, repos_url, wc_path, &peg_rev, &rev,
                                svn_depth_infinity,
                                FALSE, FALSE,
-                               opts->wc_format_version, ctx, pool));
+                               opts->wc_format_version,
+                               opts->store_pristine,
+                               ctx, pool));
 
   SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
                                             repos2_url, NULL, &peg_rev, &rev,
@@ -832,7 +842,9 @@ test_suggest_mergesources(const svn_test
                                wc_path,
                                &head_rev, &head_rev, svn_depth_empty,
                                FALSE, FALSE,
-                               opts->wc_format_version, ctx, pool));
+                               opts->wc_format_version,
+                               opts->store_pristine,
+                               ctx, pool));
 
   SVN_ERR(svn_client_suggest_merge_sources(&results,
                                            wc_path,
@@ -979,7 +991,9 @@ test_remote_only_status(const svn_test_o
                                apr_pstrcat(pool, repos_url, "/A", SVN_VA_NULL),
                                wc_path, &rev, &rev, svn_depth_immediates,
                                FALSE, FALSE,
-                               opts->wc_format_version, ctx, pool));
+                               opts->wc_format_version,
+                               opts->store_pristine,
+                               ctx, pool));
 
   /* Add a local file; this is a double-check to make sure that
      remote-only status ignores local changes. */

Modified: subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c Tue Dec 13 09:49:29 2022
@@ -6117,7 +6117,9 @@ test_file_vs_dir_move_merge_assertion_fa
                                                                  "A1", pool),
                                wc_path, &peg_rev, &opt_rev, svn_depth_infinity,
                                TRUE, FALSE,
-                               opts->wc_format_version, ctx, pool));
+                               opts->wc_format_version,
+                               opts->store_pristine,
+                               ctx, pool));
 
   SVN_ERR(svn_client_merge_peg5(svn_path_url_add_component2(b->repos_url, "A",
                                                             pool),

Modified: subversion/trunk/subversion/tests/libsvn_wc/entries-compat.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_wc/entries-compat.c?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_wc/entries-compat.c (original)
+++ subversion/trunk/subversion/tests/libsvn_wc/entries-compat.c Tue Dec 13 09:49:29 2022
@@ -620,7 +620,7 @@ test_access_baton_like_locking(const svn
                                svn_path_url_add_component2(url, "sub-wc", pool),
                                repos_root_url, repos_uuid,
                                0, svn_depth_infinity,
-                               pool));
+                               opts->store_pristine, pool));
 
     SVN_ERR(svn_wc__db_is_switched(&is_root, NULL, NULL, wc_ctx->db, subdir,
                                    pool));

Modified: subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c Tue Dec 13 09:49:29 2022
@@ -2063,6 +2063,30 @@ typedef struct actual_row_t {
   const char *changelist;
 } actual_row_t;
 
+/* Return STMT_FOR_F31 or STMT_FOR_F32 according to the format (31 or 32)
+ * of the WC in sandbox B. On error, return -1 to trigger a SQLite API error.
+ */
+static int
+stmt_for_f31_or_f32(svn_test__sandbox_t *b,
+                    int stmt_for_f31,
+                    int stmt_for_f32)
+{
+  svn_error_t *err;
+  svn_wc__db_wcroot_t *wcroot;
+  const char *local_relpath;
+
+  err = svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
+                                              b->wc_ctx->db, b->wc_abspath,
+                                              b->pool, b->pool);
+  if (err)
+    {
+      svn_error_clear(err);
+      return -1;
+    }
+
+  return (wcroot->format >= 32 ? stmt_for_f32 : stmt_for_f31);
+}
+
 static svn_error_t *
 insert_actual(svn_test__sandbox_t *b,
               actual_row_t *actual)
@@ -2092,7 +2116,10 @@ insert_actual(svn_test__sandbox_t *b,
       if (actual->changelist)
         {
           SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
-                                            STMT_ENSURE_EMPTY_PRISTINE));
+                                            stmt_for_f31_or_f32(
+                                              b,
+                                              STMT_ENSURE_EMPTY_PRISTINE_F31,
+                                              STMT_ENSURE_EMPTY_PRISTINE_F32)));
           SVN_ERR(svn_sqlite__step_done(stmt));
           SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_NODES_SET_FILE));
           SVN_ERR(svn_sqlite__bindf(stmt, "s", actual->local_relpath));

Modified: subversion/trunk/subversion/tests/libsvn_wc/pristine-store-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_wc/pristine-store-test.c?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_wc/pristine-store-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_wc/pristine-store-test.c Tue Dec 13 09:49:29 2022
@@ -94,7 +94,7 @@ pristine_write_read(const svn_test_opts_
   SVN_ERR(svn_wc__db_pristine_prepare_install(&pristine_stream,
                                               &install_data,
                                               &data_sha1, &data_md5,
-                                              db, wc_abspath,
+                                              db, wc_abspath, TRUE,
                                               pool, pool));
 
   sz = strlen(data);
@@ -104,10 +104,12 @@ pristine_write_read(const svn_test_opts_
   /* Ensure it's not already in the store. */
   {
     svn_boolean_t present;
+    svn_boolean_t hydrated;
 
-    SVN_ERR(svn_wc__db_pristine_check(&present, db, wc_abspath, data_sha1,
-                                      pool));
+    SVN_ERR(svn_wc__db_pristine_check(&present, &hydrated, db, wc_abspath,
+                                      data_sha1, pool));
     SVN_TEST_ASSERT(! present);
+    SVN_TEST_ASSERT(! hydrated);
   }
 
   /* Install the new pristine file, referenced by its checksum. */
@@ -117,10 +119,12 @@ pristine_write_read(const svn_test_opts_
   /* Ensure it is now found in the store. */
   {
     svn_boolean_t present;
+    svn_boolean_t hydrated;
 
-    SVN_ERR(svn_wc__db_pristine_check(&present, db, wc_abspath, data_sha1,
-                                      pool));
+    SVN_ERR(svn_wc__db_pristine_check(&present, &hydrated, db, wc_abspath,
+                                      data_sha1, pool));
     SVN_TEST_ASSERT(present);
+    SVN_TEST_ASSERT(hydrated);
   }
 
   /* Look up its MD-5 from its SHA-1, and check it's the same MD-5. */
@@ -161,10 +165,12 @@ pristine_write_read(const svn_test_opts_
   /* Ensure it's no longer found in the store. */
   {
     svn_boolean_t present;
+    svn_boolean_t hydrated;
 
-    SVN_ERR(svn_wc__db_pristine_check(&present, db, wc_abspath, data_sha1,
-                                      pool));
+    SVN_ERR(svn_wc__db_pristine_check(&present, &hydrated, db, wc_abspath,
+                                      data_sha1, pool));
     SVN_TEST_ASSERT(! present);
+    SVN_TEST_ASSERT(! hydrated);
   }
 
   return SVN_NO_ERROR;
@@ -191,7 +197,7 @@ pristine_delete_while_open(const svn_tes
   SVN_ERR(svn_wc__db_pristine_prepare_install(&pristine_stream,
                                               &install_data,
                                               &data_sha1, &data_md5,
-                                              db, wc_abspath,
+                                              db, wc_abspath, TRUE,
                                               pool, pool));
 
   sz = strlen(data);
@@ -221,10 +227,12 @@ pristine_delete_while_open(const svn_tes
    * an orphan, depending on the implementation.) */
   {
     svn_boolean_t present;
+    svn_boolean_t hydrated;
 
-    SVN_ERR(svn_wc__db_pristine_check(&present, db, wc_abspath, data_sha1,
-                                      pool));
+    SVN_ERR(svn_wc__db_pristine_check(&present, &hydrated, db, wc_abspath,
+                                      data_sha1, pool));
     SVN_TEST_ASSERT(! present);
+    SVN_TEST_ASSERT(! hydrated);
   }
 
   /* Close the read stream */
@@ -264,7 +272,7 @@ reject_mismatching_text(const svn_test_o
     SVN_ERR(svn_wc__db_pristine_prepare_install(&pristine_stream,
                                                 &install_data,
                                                 &data_sha1, &data_md5,
-                                                db, wc_abspath,
+                                                db, wc_abspath, TRUE,
                                                 pool, pool));
 
     sz = strlen(data);
@@ -286,7 +294,7 @@ reject_mismatching_text(const svn_test_o
     SVN_ERR(svn_wc__db_pristine_prepare_install(&pristine_stream,
                                                 &install_data,
                                                 &data_sha1, &data_md5,
-                                                db, wc_abspath,
+                                                db, wc_abspath, TRUE,
                                                 pool, pool));
 
     sz = strlen(data2);
@@ -306,6 +314,233 @@ reject_mismatching_text(const svn_test_o
 #endif
 }
 
+static svn_error_t *
+pristine_install_dehydrated(const svn_test_opts_t *opts,
+                            apr_pool_t *pool)
+{
+  svn_wc__db_t *db;
+  const char *wc_abspath;
+
+  svn_wc__db_install_data_t *install_data;
+  svn_stream_t *pristine_stream;
+  apr_size_t sz;
+
+  const char data[] = "Blah";
+  svn_checksum_t *data_sha1, *data_md5;
+
+  svn_boolean_t store_pristine;
+
+  SVN_ERR(create_repos_and_wc(&wc_abspath, &db,
+                              "pristine_install_dehydrated", opts, pool));
+
+  SVN_ERR(svn_wc__db_get_settings(NULL, &store_pristine, db, wc_abspath, pool));
+  if (store_pristine)
+    return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL,
+                            "Test assumes a working copy without pristine");
+
+  /* Write DATA into a new temporary pristine file, set PRISTINE_TMP_ABSPATH
+   * to its path and set DATA_SHA1 and DATA_MD5 to its checksums. */
+  SVN_ERR(svn_wc__db_pristine_prepare_install(&pristine_stream,
+                                              &install_data,
+                                              &data_sha1, &data_md5,
+                                              db, wc_abspath, FALSE,
+                                              pool, pool));
+
+  sz = strlen(data);
+  SVN_ERR(svn_stream_write(pristine_stream, data, &sz));
+  SVN_ERR(svn_stream_close(pristine_stream));
+
+  /* Ensure it's not already in the store. */
+  {
+    svn_boolean_t present;
+    svn_boolean_t hydrated;
+
+    SVN_ERR(svn_wc__db_pristine_check(&present, &hydrated, db, wc_abspath,
+                                      data_sha1, pool));
+    SVN_TEST_ASSERT(! present);
+    SVN_TEST_ASSERT(! hydrated);
+  }
+
+  /* Install the new pristine file, referenced by its checksum. */
+  SVN_ERR(svn_wc__db_pristine_install(install_data,
+                                      data_sha1, data_md5, pool));
+
+  /* Ensure it is now found in the store. */
+  {
+    svn_boolean_t present;
+    svn_boolean_t hydrated;
+
+    SVN_ERR(svn_wc__db_pristine_check(&present, &hydrated, db, wc_abspath,
+                                      data_sha1, pool));
+    SVN_TEST_ASSERT(present);
+    SVN_TEST_ASSERT(! hydrated);
+  }
+
+  /* Look up its MD-5 from its SHA-1, and check it's the same MD-5. */
+  {
+    const svn_checksum_t *looked_up_md5;
+
+    SVN_ERR(svn_wc__db_pristine_get_md5(&looked_up_md5, db, wc_abspath,
+                                        data_sha1, pool, pool));
+    SVN_TEST_ASSERT(looked_up_md5->kind == svn_checksum_md5);
+    SVN_TEST_ASSERT(svn_checksum_match(data_md5, looked_up_md5));
+  }
+
+  /* Check the saved pristine size and try to read the pristine text back. */
+  {
+    svn_stream_t *actual_contents;
+    svn_filesize_t actual_size;
+
+    SVN_ERR(svn_wc__db_pristine_read(&actual_contents, &actual_size,
+                                     db, wc_abspath, data_sha1, pool, pool));
+    SVN_TEST_ASSERT(actual_contents == NULL);
+    SVN_TEST_INT_ASSERT(actual_size, sz);
+  }
+
+  /* Trivially test the "remove if unreferenced" API: it's not referenced
+     so we should be able to remove it. */
+  {
+    svn_error_t *err;
+    svn_stream_t *data_read_back;
+
+    SVN_ERR(svn_wc__db_pristine_remove(db, wc_abspath, data_sha1, pool));
+    err = svn_wc__db_pristine_read(&data_read_back, NULL, db, wc_abspath,
+                                   data_sha1, pool, pool);
+    SVN_TEST_ASSERT_ERROR(err, SVN_ERR_WC_PATH_NOT_FOUND);
+  }
+
+  /* Ensure it's no longer found in the store. */
+  {
+    svn_boolean_t present;
+    svn_boolean_t hydrated;
+
+    SVN_ERR(svn_wc__db_pristine_check(&present, &hydrated, db, wc_abspath,
+                                      data_sha1, pool));
+    SVN_TEST_ASSERT(! present);
+    SVN_TEST_ASSERT(! hydrated);
+  }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+pristine_dehydrate(const svn_test_opts_t *opts,
+                   apr_pool_t *pool)
+{
+  svn_wc__db_t *db;
+  const char *wc_abspath;
+
+  svn_wc__db_install_data_t *install_data;
+  svn_stream_t *pristine_stream;
+  apr_size_t sz;
+
+  const char data[] = "Blah";
+  svn_string_t *data_string = svn_string_create(data, pool);
+  svn_checksum_t *data_sha1, *data_md5;
+
+  svn_boolean_t store_pristine;
+
+  SVN_ERR(create_repos_and_wc(&wc_abspath, &db,
+                              "pristine_dehydrate", opts, pool));
+
+  SVN_ERR(svn_wc__db_get_settings(NULL, &store_pristine, db, wc_abspath, pool));
+  if (store_pristine)
+    return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL,
+                            "Test assumes a working copy without pristine");
+
+  /* Write DATA into a new temporary pristine file, set PRISTINE_TMP_ABSPATH
+   * to its path and set DATA_SHA1 and DATA_MD5 to its checksums. */
+  SVN_ERR(svn_wc__db_pristine_prepare_install(&pristine_stream,
+                                              &install_data,
+                                              &data_sha1, &data_md5,
+                                              db, wc_abspath, TRUE,
+                                              pool, pool));
+
+  sz = strlen(data);
+  SVN_ERR(svn_stream_write(pristine_stream, data, &sz));
+  SVN_ERR(svn_stream_close(pristine_stream));
+
+  /* Install the new pristine file, referenced by its checksum. */
+  SVN_ERR(svn_wc__db_pristine_install(install_data,
+                                      data_sha1, data_md5, pool));
+
+  /* Check the state of the pristine. */
+  {
+    svn_boolean_t present;
+    svn_boolean_t hydrated;
+
+    SVN_ERR(svn_wc__db_pristine_check(&present, &hydrated, db, wc_abspath,
+                                      data_sha1, pool));
+    SVN_TEST_ASSERT(present);
+    SVN_TEST_ASSERT(hydrated);
+  }
+
+  /* Dehydrate the pristine. */
+  SVN_ERR(svn_wc__db_pristine_dehydrate(db, wc_abspath, data_sha1, pool));
+
+  /* Check the state of the pristine. */
+  {
+    svn_boolean_t present;
+    svn_boolean_t hydrated;
+
+    SVN_ERR(svn_wc__db_pristine_check(&present, &hydrated, db, wc_abspath,
+                                      data_sha1, pool));
+    SVN_TEST_ASSERT(present);
+    SVN_TEST_ASSERT(! hydrated);
+  }
+
+  /* Check the saved pristine size and try to read the pristine text back. */
+  {
+    svn_stream_t *actual_contents;
+    svn_filesize_t actual_size;
+
+    SVN_ERR(svn_wc__db_pristine_read(&actual_contents, &actual_size,
+                                     db, wc_abspath, data_sha1, pool, pool));
+    SVN_TEST_ASSERT(actual_contents == NULL);
+    SVN_TEST_INT_ASSERT(actual_size, sz);
+  }
+
+  /* Rehydrate it by installing the pristine again. */
+  SVN_ERR(svn_wc__db_pristine_prepare_install(&pristine_stream,
+                                              &install_data,
+                                              &data_sha1, &data_md5,
+                                              db, wc_abspath, TRUE,
+                                              pool, pool));
+
+  sz = strlen(data);
+  SVN_ERR(svn_stream_write(pristine_stream, data, &sz));
+  SVN_ERR(svn_stream_close(pristine_stream));
+
+  SVN_ERR(svn_wc__db_pristine_install(install_data,
+                                      data_sha1, data_md5, pool));
+
+  /* Check the state of the pristine. */
+  {
+    svn_boolean_t present;
+    svn_boolean_t hydrated;
+
+    SVN_ERR(svn_wc__db_pristine_check(&present, &hydrated, db, wc_abspath,
+                                      data_sha1, pool));
+    SVN_TEST_ASSERT(present);
+    SVN_TEST_ASSERT(hydrated);
+  }
+
+  /* Read the pristine text back and verify it's the same content. */
+  {
+    svn_stream_t *data_stream = svn_stream_from_string(data_string, pool);
+    svn_stream_t *data_read_back;
+    svn_boolean_t same;
+
+    SVN_ERR(svn_wc__db_pristine_read(&data_read_back, NULL, db, wc_abspath,
+                                     data_sha1, pool, pool));
+    SVN_ERR(svn_stream_contents_same2(&same, data_read_back, data_stream,
+                                      pool));
+    SVN_TEST_ASSERT(same);
+  }
+
+  return SVN_NO_ERROR;
+}
+
 
 static int max_threads = -1;
 
@@ -318,6 +553,10 @@ static struct svn_test_descriptor_t test
                        "pristine_delete_while_open"),
     SVN_TEST_OPTS_PASS(reject_mismatching_text,
                        "reject_mismatching_text"),
+    SVN_TEST_OPTS_PASS(pristine_install_dehydrated,
+                       "pristine_install_dehydrated"),
+    SVN_TEST_OPTS_PASS(pristine_dehydrate,
+                       "pristine_dehydrate"),
     SVN_TEST_NULL
   };
 

Modified: subversion/trunk/subversion/tests/libsvn_wc/utils.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_wc/utils.c?rev=1905955&r1=1905954&r2=1905955&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_wc/utils.c (original)
+++ subversion/trunk/subversion/tests/libsvn_wc/utils.c Tue Dec 13 09:49:29 2022
@@ -108,6 +108,7 @@ create_repos_and_wc(const char **repos_u
                                  FALSE /* ignore_externals */,
                                  FALSE /* allow_unver_obstructions */,
                                  opts->wc_format_version,
+                                 opts->store_pristine,
                                  ctx, subpool));
     svn_pool_destroy(subpool);
   }
@@ -145,10 +146,10 @@ svn_test__create_fake_wc(const char *wc_
   my_statements = apr_palloc(scratch_pool, 7 * sizeof(const char *));
   i = 0;
   my_statements[i++] = statements[STMT_CREATE_SCHEMA];
+  my_statements[i++] = extra_statements;
   if (target_format >= 32)
     my_statements[i++] = statements[STMT_UPGRADE_TO_32];
   my_statements[i++] = statements[STMT_INSTALL_SCHEMA_STATISTICS];
-  my_statements[i++] = extra_statements;
   my_statements[i++] = NULL;
 
   /* Create fake-wc/SUBDIR/.svn/ for placing the metadata. */
@@ -413,28 +414,22 @@ sbox_wc_copy_url(svn_test__sandbox_t *b,
 svn_error_t *
 sbox_wc_revert(svn_test__sandbox_t *b, const char *path, svn_depth_t depth)
 {
-  const char *abspath = sbox_wc_path(b, path);
-  const char *dir_abspath;
-  const char *lock_root_abspath;
+  svn_client_ctx_t *ctx;
+  apr_array_header_t *paths;
 
-  if (strcmp(abspath, b->wc_abspath))
-    dir_abspath = svn_dirent_dirname(abspath, b->pool);
-  else
-    dir_abspath = abspath;
+  SVN_ERR(svn_test__create_client_ctx(&ctx, b, b->pool));
+
+  paths = apr_array_make(b->pool, 1, sizeof(const char *));
+  APR_ARRAY_PUSH(paths, const char *) = sbox_wc_path(b, path);
+
+  SVN_ERR(svn_client_revert4(paths, depth,
+                             NULL /* changelists */,
+                             FALSE /* clear_changelists */,
+                             FALSE /* metadata_only */,
+                             TRUE /*added_keep_local*/,
+                             ctx,
+                             b->pool));
 
-  SVN_ERR(svn_wc__acquire_write_lock(&lock_root_abspath, b->wc_ctx,
-                                     dir_abspath, FALSE /* lock_anchor */,
-                                     b->pool, b->pool));
-  SVN_ERR(svn_wc_revert6(b->wc_ctx, abspath, depth,
-                         FALSE /* use_commit_times */,
-                         NULL /* changelist_filter */,
-                         FALSE /* clear_changelists */,
-                         FALSE /* metadata_only */,
-                         TRUE /*added_keep_local*/,
-                         NULL, NULL, /* cancel baton + func */
-                         NULL, NULL, /* notify baton + func */
-                         b->pool));
-  SVN_ERR(svn_wc__release_write_lock(b->wc_ctx, lock_root_abspath, b->pool));
   return SVN_NO_ERROR;
 }
 
@@ -584,27 +579,14 @@ svn_error_t *
 sbox_wc_resolve(svn_test__sandbox_t *b, const char *path, svn_depth_t depth,
                 svn_wc_conflict_choice_t conflict_choice)
 {
-  const char *lock_abspath;
-  svn_error_t *err;
+  svn_client_ctx_t *ctx;
+
+  SVN_ERR(svn_test__create_client_ctx(&ctx, b, b->pool));
 
-  SVN_ERR(svn_wc__acquire_write_lock_for_resolve(&lock_abspath, b->wc_ctx,
-                                                 sbox_wc_path(b, path),
-                                                 b->pool, b->pool));
-  err = svn_wc__resolve_conflicts(b->wc_ctx, sbox_wc_path(b, path),
-                                  depth,
-                                  TRUE /* resolve_text */,
-                                  "" /* resolve_prop (ALL props) */,
-                                  TRUE /* resolve_tree */,
-                                  conflict_choice,
-                                  NULL, NULL, /* conflict func */
-                                  NULL, NULL, /* cancellation */
-                                  NULL, NULL, /* notification */
-                                  b->pool);
-
-  err = svn_error_compose_create(err, svn_wc__release_write_lock(b->wc_ctx,
-                                                                 lock_abspath,
-                                                                 b->pool));
-  return err;
+  SVN_ERR(svn_client_resolve(sbox_wc_path(b, path), depth, conflict_choice,
+                             ctx, b->pool));
+
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *