You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2018/11/01 14:27:24 UTC

svn commit: r1845479 [2/2] - in /subversion/branches/multi-wc-format: ./ build/ac-macros/ notes/ subversion/bindings/javahl/native/ subversion/bindings/swig/include/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/l...

Modified: subversion/branches/multi-wc-format/subversion/svnrdump/load_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/svnrdump/load_editor.c?rev=1845479&r1=1845478&r2=1845479&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/svnrdump/load_editor.c (original)
+++ subversion/branches/multi-wc-format/subversion/svnrdump/load_editor.c Thu Nov  1 14:27:23 2018
@@ -45,15 +45,58 @@
 
 
 /**
+ * A vtable that is driven by get_dumpstream_loader().
+ */
+typedef struct loader_fns_t
+{
+  /* Callback on starting a revision, to obtain an editor for the revision.
+   *
+   * This callback returns in *EDITOR and *EDIT_BATON an editor through which
+   * its caller will drive the changes for revision REVISION.
+   *
+   * This callback should call the editor's SET_TARGET_REVISION method if
+   * required.
+   *
+   * REV_PROPS holds the revision properties.
+   *
+   * POOL (and REV_PROPS) will persist until after the REVFINISH callback
+   * returns.
+   *
+   * Modelled on svn_ra_replay_revstart_callback_t.
+   */
+  svn_error_t *(*revstart)(
+    svn_revnum_t revision,
+    void *baton,
+    const svn_delta_editor_t **editor,
+    void **edit_baton,
+    apr_hash_t *rev_props,
+    apr_pool_t *pool);
+
+  /* Fetch the node props for ORIG_PATH @ ORIG_REV, a node of kind KIND.
+   *
+   * This callback is required if a non-deltas-format dump is parsed;
+   * otherwise it will not be called and may be null. If required and not
+   * provided, the loader will return SVN_ERR_UNSUPPORTED_FEATURE.
+   *
+   * Only regular props are needed. Any special kinds of property such as
+   * entry-props and DAV/WC-props will be ignored.
+   */
+  svn_error_t *(*fetch_props)(
+    apr_hash_t **props,
+    void *baton,
+    const char *orig_path,
+    svn_revnum_t orig_rev,
+    svn_node_kind_t kind,
+    apr_pool_t *result_pool,
+    apr_pool_t *scratch_pool);
+
+} loader_fns_t;
+
+/**
  * General baton used by the parser functions.
  */
 struct parse_baton
 {
-  /* Commit editor and baton used to transfer loaded revisions to
-     the target repository. */
-  const svn_delta_editor_t *commit_editor;
-  void *commit_edit_baton;
-
   /* RA session(s) for committing to the target repository. */
   svn_ra_session_t *session;
   svn_ra_session_t *aux_session;
@@ -87,6 +130,9 @@ struct parse_baton
   /* An hash containing specific revision properties to skip while
      loading. */
   apr_hash_t *skip_revprops;
+
+  const loader_fns_t *callbacks;
+  void *cb_baton;
 };
 
 /**
@@ -144,8 +190,14 @@ struct revision_baton
 {
   svn_revnum_t rev;
   apr_hash_t *revprop_table;
+  svn_revnum_t head_rev_before_commit;
   apr_int32_t rev_offset;
 
+  /* Commit editor and baton used to transfer loaded revisions to
+     the target repository. */
+  const svn_delta_editor_t *commit_editor;
+  void *commit_edit_baton;
+
   const svn_string_t *datestamp;
   const svn_string_t *author;
 
@@ -183,204 +235,83 @@ get_revision_mapping(apr_hash_t *rev_map
 
 
 static svn_error_t *
-commit_callback(const svn_commit_info_t *commit_info,
-                void *baton,
-                apr_pool_t *pool)
+magic_header_record(int version,
+            void *parse_baton,
+            apr_pool_t *pool)
 {
-  struct revision_baton *rb = baton;
-  struct parse_baton *pb = rb->pb;
-
-  /* ### Don't print directly; generate a notification. */
-  if (! pb->quiet)
-    SVN_ERR(svn_cmdline_printf(pool, "* Loaded revision %ld.\n",
-                               commit_info->revision));
-
-  /* Add the mapping of the dumpstream revision to the committed revision. */
-  set_revision_mapping(pb->rev_map, rb->rev, commit_info->revision);
-
-  /* If the incoming dump stream has non-contiguous revisions (e.g. from
-     using svndumpfilter --drop-empty-revs without --renumber-revs) then
-     we must account for the missing gaps in PB->REV_MAP.  Otherwise we
-     might not be able to map all mergeinfo source revisions to the correct
-     revisions in the target repos. */
-  if ((pb->last_rev_mapped != SVN_INVALID_REVNUM)
-      && (rb->rev != pb->last_rev_mapped + 1))
-    {
-      svn_revnum_t i;
-
-      for (i = pb->last_rev_mapped + 1; i < rb->rev; i++)
-        {
-          set_revision_mapping(pb->rev_map, i, pb->last_rev_mapped);
-        }
-    }
-
-  /* Update our "last revision mapped". */
-  pb->last_rev_mapped = rb->rev;
-
   return SVN_NO_ERROR;
 }
 
-/* Implements `svn_ra__lock_retry_func_t'. */
-static svn_error_t *
-lock_retry_func(void *baton,
-                const svn_string_t *reposlocktoken,
-                apr_pool_t *pool)
-{
-  return svn_cmdline_printf(pool,
-                            _("Failed to get lock on destination "
-                              "repos, currently held by '%s'\n"),
-                            reposlocktoken->data);
-}
-
-
 static svn_error_t *
-fetch_base_func(const char **filename,
-                void *baton,
-                const char *path,
-                svn_revnum_t base_revision,
-                apr_pool_t *result_pool,
-                apr_pool_t *scratch_pool)
+uuid_record(const char *uuid,
+            void *parse_baton,
+            apr_pool_t *pool)
 {
-  struct revision_baton *rb = baton;
-  svn_stream_t *fstream;
-  svn_error_t *err;
-
-  if (! SVN_IS_VALID_REVNUM(base_revision))
-    base_revision = rb->rev - 1;
-
-  SVN_ERR(svn_stream_open_unique(&fstream, filename, NULL,
-                                 svn_io_file_del_on_pool_cleanup,
-                                 result_pool, scratch_pool));
-
-  err = svn_ra_get_file(rb->pb->aux_session, path, base_revision,
-                        fstream, NULL, NULL, scratch_pool);
-  if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
-    {
-      svn_error_clear(err);
-      SVN_ERR(svn_stream_close(fstream));
-
-      *filename = NULL;
-      return SVN_NO_ERROR;
-    }
-  else if (err)
-    return svn_error_trace(err);
-
-  SVN_ERR(svn_stream_close(fstream));
-
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *
-fetch_props_func(apr_hash_t **props,
-                 void *baton,
-                 const char *path,
-                 svn_revnum_t base_revision,
-                 apr_pool_t *result_pool,
-                 apr_pool_t *scratch_pool)
+/* Push information about another directory onto the linked list RB->db.
+ *
+ * CHILD_BATON is the baton returned by the commit editor. RELPATH is the
+ * repository-relative path of this directory. IS_ADDED is true iff this
+ * directory is being added (with or without history). If added with
+ * history then COPYFROM_PATH/COPYFROM_REV are the copyfrom source, else
+ * are NULL/SVN_INVALID_REVNUM.
+ */
+static void
+push_directory(struct revision_baton *rb,
+               void *child_baton,
+               const char *relpath,
+               svn_boolean_t is_added,
+               const char *copyfrom_path,
+               svn_revnum_t copyfrom_rev)
 {
-  struct revision_baton *rb = baton;
-  svn_node_kind_t node_kind;
-
-  if (! SVN_IS_VALID_REVNUM(base_revision))
-    base_revision = rb->rev - 1;
+  struct directory_baton *child_db = apr_pcalloc(rb->pool, sizeof (*child_db));
 
-  SVN_ERR(svn_ra_check_path(rb->pb->aux_session, path, base_revision,
-                            &node_kind, scratch_pool));
+  SVN_ERR_ASSERT_NO_RETURN(
+    is_added || (copyfrom_path == NULL && copyfrom_rev == SVN_INVALID_REVNUM));
 
-  if (node_kind == svn_node_file)
-    {
-      SVN_ERR(svn_ra_get_file(rb->pb->aux_session, path, base_revision,
-                              NULL, NULL, props, result_pool));
-    }
-  else if (node_kind == svn_node_dir)
+  /* If this node is an existing (not newly added) child of a copied node,
+     calculate where it was copied from. */
+  if (!is_added
+      && ARE_VALID_COPY_ARGS(rb->db->copyfrom_path, rb->db->copyfrom_rev))
     {
-      apr_array_header_t *tmp_props;
+      const char *name = svn_relpath_basename(relpath, NULL);
 
-      SVN_ERR(svn_ra_get_dir2(rb->pb->aux_session, NULL, NULL, props, path,
-                              base_revision, 0 /* Dirent fields */,
-                              result_pool));
-      tmp_props = svn_prop_hash_to_array(*props, result_pool);
-      SVN_ERR(svn_categorize_props(tmp_props, NULL, NULL, &tmp_props,
-                                   result_pool));
-      *props = svn_prop_array_to_hash(tmp_props, result_pool);
-    }
-  else
-    {
-      *props = apr_hash_make(result_pool);
+      copyfrom_path = svn_relpath_join(rb->db->copyfrom_path, name,
+                                       rb->pool);
+      copyfrom_rev = rb->db->copyfrom_rev;
     }
 
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-fetch_kind_func(svn_node_kind_t *kind,
-                void *baton,
-                const char *path,
-                svn_revnum_t base_revision,
-                apr_pool_t *scratch_pool)
-{
-  struct revision_baton *rb = baton;
-
-  if (! SVN_IS_VALID_REVNUM(base_revision))
-    base_revision = rb->rev - 1;
-
-  SVN_ERR(svn_ra_check_path(rb->pb->aux_session, path, base_revision,
-                            kind, scratch_pool));
-
-  return SVN_NO_ERROR;
-}
-
-static svn_delta_shim_callbacks_t *
-get_shim_callbacks(struct revision_baton *rb,
-                   apr_pool_t *pool)
-{
-  svn_delta_shim_callbacks_t *callbacks =
-                        svn_delta_shim_callbacks_default(pool);
-
-  callbacks->fetch_props_func = fetch_props_func;
-  callbacks->fetch_kind_func = fetch_kind_func;
-  callbacks->fetch_base_func = fetch_base_func;
-  callbacks->fetch_baton = rb;
-
-  return callbacks;
+  child_db->baton = child_baton;
+  child_db->relpath = relpath;
+  child_db->copyfrom_path = copyfrom_path;
+  child_db->copyfrom_rev = copyfrom_rev;
+  child_db->parent = rb->db;
+  rb->db = child_db;
 }
 
-/* Acquire a lock (of sorts) on the repository associated with the
- * given RA SESSION. This lock is just a revprop change attempt in a
- * time-delay loop. This function is duplicated by svnsync in
- * svnsync/svnsync.c
- *
- * ### TODO: Make this function more generic and
- * expose it through a header for use by other Subversion
- * applications to avoid duplication.
+/* Called to obtain an editor for the revision described by RB.
  */
 static svn_error_t *
-get_lock(const svn_string_t **lock_string_p,
-         svn_ra_session_t *session,
-         svn_cancel_func_t cancel_func,
-         void *cancel_baton,
-         apr_pool_t *pool)
+revision_start_edit(struct revision_baton *rb,
+                    apr_pool_t *scratch_pool)
 {
-  svn_boolean_t be_atomic;
-
-  SVN_ERR(svn_ra_has_capability(session, &be_atomic,
-                                SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
-                                pool));
-  if (! be_atomic)
-    {
-      /* Pre-1.7 servers can't lock without a race condition.  (Issue #3546) */
-      svn_error_t *err =
-        svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
-                         _("Target server does not support atomic revision "
-                           "property edits; consider upgrading it to 1.7."));
-      svn_handle_warning2(stderr, err, "svnrdump: ");
-      svn_error_clear(err);
-    }
+  struct parse_baton *pb = rb->pb;
+  void *child_baton;
 
-  return svn_ra__get_operational_lock(lock_string_p, NULL, session,
-                                      SVNRDUMP_PROP_LOCK, FALSE,
-                                      10 /* retries */, lock_retry_func, NULL,
-                                      cancel_func, cancel_baton, pool);
+  SVN_ERR(pb->callbacks->revstart(rb->rev,
+                                  pb->cb_baton,
+                                  &rb->commit_editor, &rb->commit_edit_baton,
+                                  rb->revprop_table,
+                                  rb->pool));
+  SVN_ERR(rb->commit_editor->open_root(rb->commit_edit_baton,
+                                       rb->head_rev_before_commit,
+                                       rb->pool, &child_baton));
+  /* child_baton corresponds to the root directory baton here */
+  push_directory(rb, child_baton, "", TRUE /*is_added*/,
+                 NULL, SVN_INVALID_REVNUM);
+  return SVN_NO_ERROR;
 }
 
 static svn_error_t *
@@ -389,13 +320,11 @@ new_revision_record(void **revision_bato
                     void *parse_baton,
                     apr_pool_t *pool)
 {
+  struct parse_baton *pb = parse_baton;
   struct revision_baton *rb;
-  struct parse_baton *pb;
   const char *rev_str;
-  svn_revnum_t head_rev;
 
   rb = apr_pcalloc(pool, sizeof(*rb));
-  pb = parse_baton;
   rb->pool = svn_pool_create(pool);
   rb->pb = pb;
   rb->db = NULL;
@@ -404,13 +333,14 @@ new_revision_record(void **revision_bato
   if (rev_str)
     rb->rev = SVN_STR_TO_REV(rev_str);
 
-  SVN_ERR(svn_ra_get_latest_revnum(pb->session, &head_rev, pool));
+  SVN_ERR(svn_ra_get_latest_revnum(pb->session, &rb->head_rev_before_commit,
+                                   pool));
 
   /* FIXME: This is a lame fallback loading multiple segments of dump in
      several separate operations. It is highly susceptible to race conditions.
      Calculate the revision 'offset' for finding copyfrom sources.
      It might be positive or negative. */
-  rb->rev_offset = (apr_int32_t) ((rb->rev) - (head_rev + 1));
+  rb->rev_offset = (apr_int32_t) ((rb->rev) - (rb->head_rev_before_commit + 1));
 
   /* Stash the oldest (non-zero) dumpstream revision seen. */
   if ((rb->rev > 0) && (!SVN_IS_VALID_REVNUM(pb->oldest_dumpstream_rev)))
@@ -418,8 +348,8 @@ new_revision_record(void **revision_bato
 
   /* Set the commit_editor/ commit_edit_baton to NULL and wait for
      them to be created in new_node_record */
-  rb->pb->commit_editor = NULL;
-  rb->pb->commit_edit_baton = NULL;
+  rb->commit_editor = NULL;
+  rb->commit_edit_baton = NULL;
   rb->revprop_table = apr_hash_make(rb->pool);
 
   *revision_baton = rb;
@@ -427,88 +357,28 @@ new_revision_record(void **revision_bato
 }
 
 static svn_error_t *
-magic_header_record(int version,
-            void *parse_baton,
-            apr_pool_t *pool)
+new_node_record(void **node_baton,
+                apr_hash_t *headers,
+                void *revision_baton,
+                apr_pool_t *pool)
 {
-  return SVN_NO_ERROR;
-}
+  struct revision_baton *rb = revision_baton;
+  const struct svn_delta_editor_t *commit_editor = rb->commit_editor;
+  struct node_baton *nb;
+  apr_hash_index_t *hi;
+  void *child_baton;
+  const char *nb_dirname;
 
-static svn_error_t *
-uuid_record(const char *uuid,
-            void *parse_baton,
-            apr_pool_t *pool)
-{
-  return SVN_NO_ERROR;
-}
-
-/* Push information about another directory onto the linked list RB->db.
- *
- * CHILD_BATON is the baton returned by the commit editor. RELPATH is the
- * repository-relative path of this directory. IS_ADDED is true iff this
- * directory is being added (with or without history). If added with
- * history then COPYFROM_PATH/COPYFROM_REV are the copyfrom source, else
- * are NULL/SVN_INVALID_REVNUM.
- */
-static void
-push_directory(struct revision_baton *rb,
-               void *child_baton,
-               const char *relpath,
-               svn_boolean_t is_added,
-               const char *copyfrom_path,
-               svn_revnum_t copyfrom_rev)
-{
-  struct directory_baton *child_db = apr_pcalloc(rb->pool, sizeof (*child_db));
-
-  SVN_ERR_ASSERT_NO_RETURN(
-    is_added || (copyfrom_path == NULL && copyfrom_rev == SVN_INVALID_REVNUM));
-
-  /* If this node is an existing (not newly added) child of a copied node,
-     calculate where it was copied from. */
-  if (!is_added
-      && ARE_VALID_COPY_ARGS(rb->db->copyfrom_path, rb->db->copyfrom_rev))
-    {
-      const char *name = svn_relpath_basename(relpath, NULL);
-
-      copyfrom_path = svn_relpath_join(rb->db->copyfrom_path, name,
-                                       rb->pool);
-      copyfrom_rev = rb->db->copyfrom_rev;
-    }
-
-  child_db->baton = child_baton;
-  child_db->relpath = relpath;
-  child_db->copyfrom_path = copyfrom_path;
-  child_db->copyfrom_rev = copyfrom_rev;
-  child_db->parent = rb->db;
-  rb->db = child_db;
-}
-
-static svn_error_t *
-new_node_record(void **node_baton,
-                apr_hash_t *headers,
-                void *revision_baton,
-                apr_pool_t *pool)
-{
-  struct revision_baton *rb = revision_baton;
-  const struct svn_delta_editor_t *commit_editor = rb->pb->commit_editor;
-  void *commit_edit_baton = rb->pb->commit_edit_baton;
-  struct node_baton *nb;
-  svn_revnum_t head_rev_before_commit = rb->rev - rb->rev_offset - 1;
-  apr_hash_index_t *hi;
-  void *child_baton;
-  const char *nb_dirname;
-
-  nb = apr_pcalloc(rb->pool, sizeof(*nb));
-  nb->rb = rb;
-  nb->is_added = FALSE;
-  nb->copyfrom_path = NULL;
-  nb->copyfrom_url = NULL;
-  nb->copyfrom_rev = SVN_INVALID_REVNUM;
-  nb->prop_changes = apr_hash_make(rb->pool);
+  nb = apr_pcalloc(rb->pool, sizeof(*nb));
+  nb->rb = rb;
+  nb->is_added = FALSE;
+  nb->copyfrom_path = NULL;
+  nb->copyfrom_url = NULL;
+  nb->copyfrom_rev = SVN_INVALID_REVNUM;
+  nb->prop_changes = apr_hash_make(rb->pool);
 
   /* If the creation of commit_editor is pending, create it now and
      open_root on it; also create a top-level directory baton. */
-
   if (!commit_editor)
     {
       /* The revprop_table should have been filled in with important
@@ -521,23 +391,8 @@ new_node_record(void **node_baton,
       svn_hash_sets(rb->revprop_table, SVN_PROP_REVISION_AUTHOR, NULL);
       svn_hash_sets(rb->revprop_table, SVN_PROP_REVISION_DATE, NULL);
 
-      SVN_ERR(svn_ra__register_editor_shim_callbacks(rb->pb->session,
-                                    get_shim_callbacks(rb, rb->pool)));
-      SVN_ERR(svn_ra_get_commit_editor3(rb->pb->session, &commit_editor,
-                                        &commit_edit_baton, rb->revprop_table,
-                                        commit_callback, revision_baton,
-                                        NULL, FALSE, rb->pool));
-
-      rb->pb->commit_editor = commit_editor;
-      rb->pb->commit_edit_baton = commit_edit_baton;
-
-      SVN_ERR(commit_editor->open_root(commit_edit_baton,
-                                       head_rev_before_commit,
-                                       rb->pool, &child_baton));
-
-      /* child_baton corresponds to the root directory baton here */
-      push_directory(rb, child_baton, "", TRUE /*is_added*/,
-                     NULL, SVN_INVALID_REVNUM);
+      SVN_ERR(revision_start_edit(rb, pool));
+      commit_editor = rb->commit_editor;
     }
 
   for (hi = apr_hash_first(rb->pool, headers); hi; hi = apr_hash_next(hi))
@@ -612,7 +467,7 @@ new_node_record(void **node_baton,
                              rb->pool);
           SVN_ERR(commit_editor->open_directory(relpath_compose,
                                                 rb->db->baton,
-                                                head_rev_before_commit,
+                                                rb->head_rev_before_commit,
                                                 rb->pool, &child_baton));
           push_directory(rb, child_baton, relpath_compose, TRUE /*is_added*/,
                          NULL, SVN_INVALID_REVNUM);
@@ -655,7 +510,7 @@ new_node_record(void **node_baton,
     case svn_node_action_delete:
     case svn_node_action_replace:
       SVN_ERR(commit_editor->delete_entry(nb->path,
-                                          head_rev_before_commit,
+                                          rb->head_rev_before_commit,
                                           rb->db->baton, rb->pool));
       if (nb->action == svn_node_action_delete)
         break;
@@ -693,7 +548,7 @@ new_node_record(void **node_baton,
           break;
         default:
           SVN_ERR(commit_editor->open_directory(nb->path, rb->db->baton,
-                                                head_rev_before_commit,
+                                                rb->head_rev_before_commit,
                                                 rb->pool, &child_baton));
           push_directory(rb, child_baton, nb->path, FALSE /*is_added*/,
                          NULL, SVN_INVALID_REVNUM);
@@ -723,7 +578,7 @@ set_revision_property(void *baton,
         svn_hash_sets(rb->revprop_table,
                       apr_pstrdup(rb->pool, name), value);
     }
-  else if (rb->rev_offset == -1
+  else if (rb->head_rev_before_commit == 0
            && ! svn_hash_gets(rb->pb->skip_revprops, name))
     {
       /* Special case: set revision 0 properties directly (which is
@@ -856,16 +711,14 @@ remove_node_props(void *baton)
     /* Add-without-history; no "old" properties to worry about. */
     return SVN_NO_ERROR;
 
-  if (nb->kind == svn_node_file)
-    {
-      SVN_ERR(svn_ra_get_file(nb->rb->pb->aux_session,
-                              orig_path, orig_rev, NULL, NULL, &props, pool));
-    }
-  else  /* nb->kind == svn_node_dir */
-    {
-      SVN_ERR(svn_ra_get_dir2(nb->rb->pb->aux_session, NULL, NULL, &props,
-                              orig_path, orig_rev, 0, pool));
-    }
+  if (! rb->pb->callbacks->fetch_props)
+    return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+                            _("This dumpstream reader requires a delta "
+                              "format dumpstream"));
+  SVN_ERR(rb->pb->callbacks->fetch_props(&props,
+                                         rb->pb->cb_baton,
+                                         orig_path, orig_rev, nb->kind,
+                                         pool, pool));
 
   for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
     {
@@ -884,7 +737,7 @@ set_fulltext(svn_stream_t **stream,
              void *node_baton)
 {
   struct node_baton *nb = node_baton;
-  const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor;
+  const struct svn_delta_editor_t *commit_editor = nb->rb->commit_editor;
   svn_txdelta_window_handler_t handler;
   void *handler_baton;
   apr_pool_t *pool = nb->rb->pool;
@@ -902,7 +755,7 @@ apply_textdelta(svn_txdelta_window_handl
                 void *node_baton)
 {
   struct node_baton *nb = node_baton;
-  const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor;
+  const struct svn_delta_editor_t *commit_editor = nb->rb->commit_editor;
   apr_pool_t *pool = nb->rb->pool;
 
   SVN_ERR(commit_editor->apply_textdelta(nb->file_baton, nb->base_checksum,
@@ -915,7 +768,7 @@ static svn_error_t *
 close_node(void *baton)
 {
   struct node_baton *nb = baton;
-  const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor;
+  const struct svn_delta_editor_t *commit_editor = nb->rb->commit_editor;
   apr_pool_t *pool = nb->rb->pool;
   apr_hash_index_t *hi;
 
@@ -956,8 +809,8 @@ static svn_error_t *
 close_revision(void *baton)
 {
   struct revision_baton *rb = baton;
-  const svn_delta_editor_t *commit_editor = rb->pb->commit_editor;
-  void *commit_edit_baton = rb->pb->commit_edit_baton;
+  const svn_delta_editor_t *commit_editor = rb->commit_editor;
+  void *commit_edit_baton = rb->commit_edit_baton;
   svn_revnum_t committed_rev = SVN_INVALID_REVNUM;
 
   /* Fake revision 0 */
@@ -982,20 +835,12 @@ close_revision(void *baton)
     }
   else
     {
-      svn_revnum_t head_rev_before_commit = rb->rev - rb->rev_offset - 1;
-      void *child_baton;
-
       /* Legitimate revision with no node information */
-      SVN_ERR(svn_ra_get_commit_editor3(rb->pb->session, &commit_editor,
-                                        &commit_edit_baton, rb->revprop_table,
-                                        commit_callback, baton,
-                                        NULL, FALSE, rb->pool));
+      SVN_ERR(revision_start_edit(rb, rb->pool));
+      commit_editor = rb->commit_editor;
+      commit_edit_baton = rb->commit_edit_baton;
 
-      SVN_ERR(commit_editor->open_root(commit_edit_baton,
-                                       head_rev_before_commit,
-                                       rb->pool, &child_baton));
-
-      SVN_ERR(commit_editor->close_directory(child_baton, rb->pool));
+      SVN_ERR(commit_editor->close_directory(rb->db->baton, rb->pool));
       SVN_ERR(commit_editor->close_edit(commit_edit_baton, rb->pool));
     }
 
@@ -1007,7 +852,7 @@ close_revision(void *baton)
     {
       committed_rev = get_revision_mapping(rb->pb->rev_map, rb->rev);
     }
-  else if (rb->rev_offset == -1)
+  else if (rb->head_rev_before_commit == 0)
     {
       committed_rev = 0;
     }
@@ -1037,27 +882,238 @@ close_revision(void *baton)
   return SVN_NO_ERROR;
 }
 
-svn_error_t *
-svn_rdump__load_dumpstream(svn_stream_t *stream,
-                           svn_ra_session_t *session,
-                           svn_ra_session_t *aux_session,
-                           svn_boolean_t quiet,
-                           apr_hash_t *skip_revprops,
-                           svn_cancel_func_t cancel_func,
-                           void *cancel_baton,
-                           apr_pool_t *pool)
+/*----------------------------------------------------------------------*/
+
+/**
+ * Baton used for commit callback (and Ev2 shims).
+ */
+struct commit_baton_t
+{
+  svn_revnum_t rev;
+  struct parse_baton *pb;
+};
+
+/*
+ * - Notification of the commit.
+ * - Update the revision number mapping to take account of the actual
+ *   committed revision number.
+ */
+static svn_error_t *
+commit_callback(const svn_commit_info_t *commit_info,
+                void *baton,
+                apr_pool_t *pool)
+{
+  struct commit_baton_t *cb = baton;
+  struct parse_baton *pb = cb->pb;
+
+  /* ### Don't print directly; generate a notification. */
+  if (! pb->quiet)
+    SVN_ERR(svn_cmdline_printf(pool, "* Loaded revision %ld.\n",
+                               commit_info->revision));
+
+  /* Add the mapping of the dumpstream revision to the committed revision. */
+  set_revision_mapping(pb->rev_map, cb->rev, commit_info->revision);
+
+  /* If the incoming dump stream has non-contiguous revisions (e.g. from
+     using svndumpfilter --drop-empty-revs without --renumber-revs) then
+     we must account for the missing gaps in PB->REV_MAP.  Otherwise we
+     might not be able to map all mergeinfo source revisions to the correct
+     revisions in the target repos. */
+  if ((pb->last_rev_mapped != SVN_INVALID_REVNUM)
+      && (cb->rev != pb->last_rev_mapped + 1))
+    {
+      svn_revnum_t i;
+
+      for (i = pb->last_rev_mapped + 1; i < cb->rev; i++)
+        {
+          set_revision_mapping(pb->rev_map, i, pb->last_rev_mapped);
+        }
+    }
+
+  /* Update our "last revision mapped". */
+  pb->last_rev_mapped = cb->rev;
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+fetch_base_func(const char **filename,
+                void *baton,
+                const char *path,
+                svn_revnum_t base_revision,
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
+{
+  struct commit_baton_t *cb = baton;
+  svn_stream_t *fstream;
+  svn_error_t *err;
+
+  if (! SVN_IS_VALID_REVNUM(base_revision))
+    base_revision = cb->rev - 1;
+
+  SVN_ERR(svn_stream_open_unique(&fstream, filename, NULL,
+                                 svn_io_file_del_on_pool_cleanup,
+                                 result_pool, scratch_pool));
+
+  err = svn_ra_get_file(cb->pb->aux_session, path, base_revision,
+                        fstream, NULL, NULL, scratch_pool);
+  if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
+    {
+      svn_error_clear(err);
+      SVN_ERR(svn_stream_close(fstream));
+
+      *filename = NULL;
+      return SVN_NO_ERROR;
+    }
+  else if (err)
+    return svn_error_trace(err);
+
+  SVN_ERR(svn_stream_close(fstream));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+fetch_props(apr_hash_t **props,
+            void *baton,
+            const char *path,
+            svn_revnum_t base_revision,
+            svn_node_kind_t node_kind,
+            apr_pool_t *result_pool,
+            apr_pool_t *scratch_pool)
+{
+  struct parse_baton *pb = baton;
+
+  if (node_kind == svn_node_file)
+    {
+      SVN_ERR(svn_ra_get_file(pb->aux_session, path, base_revision,
+                              NULL, NULL, props, result_pool));
+    }
+  else if (node_kind == svn_node_dir)
+    {
+      apr_array_header_t *tmp_props;
+
+      SVN_ERR(svn_ra_get_dir2(pb->aux_session, NULL, NULL, props, path,
+                              base_revision, 0 /* Dirent fields */,
+                              result_pool));
+      tmp_props = svn_prop_hash_to_array(*props, result_pool);
+      SVN_ERR(svn_categorize_props(tmp_props, NULL, NULL, &tmp_props,
+                                   result_pool));
+      *props = svn_prop_array_to_hash(tmp_props, result_pool);
+    }
+  else
+    {
+      *props = apr_hash_make(result_pool);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+fetch_props_func(apr_hash_t **props,
+                 void *baton,
+                 const char *path,
+                 svn_revnum_t base_revision,
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
+{
+  struct commit_baton_t *cb = baton;
+  svn_node_kind_t node_kind;
+
+  if (! SVN_IS_VALID_REVNUM(base_revision))
+    base_revision = cb->rev - 1;
+
+  SVN_ERR(svn_ra_check_path(cb->pb->aux_session, path, base_revision,
+                            &node_kind, scratch_pool));
+  SVN_ERR(fetch_props(props, cb->pb, path, base_revision, node_kind,
+                      result_pool, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+fetch_kind_func(svn_node_kind_t *kind,
+                void *baton,
+                const char *path,
+                svn_revnum_t base_revision,
+                apr_pool_t *scratch_pool)
+{
+  struct commit_baton_t *cb = baton;
+
+  if (! SVN_IS_VALID_REVNUM(base_revision))
+    base_revision = cb->rev - 1;
+
+  SVN_ERR(svn_ra_check_path(cb->pb->aux_session, path, base_revision,
+                            kind, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_delta_shim_callbacks_t *
+get_shim_callbacks(struct commit_baton_t *cb,
+                   apr_pool_t *pool)
+{
+  svn_delta_shim_callbacks_t *callbacks =
+                        svn_delta_shim_callbacks_default(pool);
+
+  callbacks->fetch_props_func = fetch_props_func;
+  callbacks->fetch_kind_func = fetch_kind_func;
+  callbacks->fetch_base_func = fetch_base_func;
+  callbacks->fetch_baton = cb;
+
+  return callbacks;
+}
+
+/*  */
+static svn_error_t *
+revstart(svn_revnum_t revision,
+         void *baton,
+         const svn_delta_editor_t **editor_p,
+         void **edit_baton_p,
+         apr_hash_t *rev_props,
+         apr_pool_t *result_pool)
+{
+  struct parse_baton *pb = baton;
+  struct commit_baton_t *cb = apr_palloc(result_pool, sizeof(*cb));
+
+  cb->rev = revision;
+  cb->pb = pb;
+  SVN_ERR(svn_ra__register_editor_shim_callbacks(pb->session,
+                                                 get_shim_callbacks(cb, result_pool)));
+  SVN_ERR(svn_ra_get_commit_editor3(pb->session,
+                                    editor_p, edit_baton_p,
+                                    rev_props,
+                                    commit_callback, cb,
+                                    NULL, FALSE, result_pool));
+  return SVN_NO_ERROR;
+}
+
+/* Return an implementation of the dumpstream parser API that will drive
+ * commits over the RA layer to the location described by SESSION.
+ *
+ * Use AUX_SESSION (which is opened to the same URL as SESSION)
+ * for any secondary, out-of-band RA communications required. This is
+ * needed when loading a non-deltas dump, and for Ev2.
+ *
+ * Print feedback to the console for each revision, unless QUIET is true.
+ *
+ * Ignore (don't set) any revision property whose name is a key in
+ * SKIP_REVPROPS. The values in the hash are unimportant.
+ */
+static svn_error_t *
+get_dumpstream_loader(svn_repos_parse_fns3_t **parser_p,
+                      void **parse_baton_p,
+                      svn_ra_session_t *session,
+                      svn_ra_session_t *aux_session,
+                      svn_boolean_t quiet,
+                      apr_hash_t *skip_revprops,
+                      apr_pool_t *pool)
 {
   svn_repos_parse_fns3_t *parser;
   struct parse_baton *parse_baton;
-  const svn_string_t *lock_string;
-  svn_boolean_t be_atomic;
-  svn_error_t *err;
   const char *session_url, *root_url, *parent_dir;
+  static const loader_fns_t callbacks = { revstart, fetch_props };
 
-  SVN_ERR(svn_ra_has_capability(session, &be_atomic,
-                                SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
-                                pool));
-  SVN_ERR(get_lock(&lock_string, session, cancel_func, cancel_baton, pool));
   SVN_ERR(svn_ra_get_repos_root2(session, &root_url, pool));
   SVN_ERR(svn_ra_get_session_url(session, &session_url, pool));
   SVN_ERR(svn_ra_get_path_relative_to_root(session, &parent_dir,
@@ -1087,6 +1143,300 @@ svn_rdump__load_dumpstream(svn_stream_t
   parse_baton->last_rev_mapped = SVN_INVALID_REVNUM;
   parse_baton->oldest_dumpstream_rev = SVN_INVALID_REVNUM;
   parse_baton->skip_revprops = skip_revprops;
+  parse_baton->callbacks = &callbacks;
+  parse_baton->cb_baton = parse_baton;
+
+  *parser_p = parser;
+  *parse_baton_p = parse_baton;
+  return SVN_NO_ERROR;
+}
+
+/*----------------------------------------------------------------------*/
+
+/* Dump-stream parser wrapper */
+
+struct filter_parse_baton_t
+{
+  const svn_repos_parse_fns3_t *wrapped_parser;
+  struct parse_baton *wrapped_pb;
+};
+
+struct filter_revision_baton_t
+{
+  struct filter_parse_baton_t *pb;
+  void *wrapped_rb;
+};
+
+struct filter_node_baton_t
+{
+  struct filter_revision_baton_t *rb;
+  void *wrapped_nb;
+};
+
+static svn_error_t *
+filter_magic_header_record(int version,
+                           void *parse_baton,
+                           apr_pool_t *pool)
+{
+  struct filter_parse_baton_t *pb = parse_baton;
+
+  SVN_ERR(pb->wrapped_parser->magic_header_record(version, pb->wrapped_pb,
+                                                  pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_uuid_record(const char *uuid,
+                   void *parse_baton,
+                   apr_pool_t *pool)
+{
+  struct filter_parse_baton_t *pb = parse_baton;
+
+  SVN_ERR(pb->wrapped_parser->uuid_record(uuid, pb->wrapped_pb, pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_new_revision_record(void **revision_baton,
+                           apr_hash_t *headers,
+                           void *parse_baton,
+                           apr_pool_t *pool)
+{
+  struct filter_parse_baton_t *pb = parse_baton;
+  struct filter_revision_baton_t *rb = apr_pcalloc(pool, sizeof (*rb));
+
+  rb->pb = pb;
+  SVN_ERR(pb->wrapped_parser->new_revision_record(&rb->wrapped_rb, headers,
+                                                  pb->wrapped_pb, pool));
+  *revision_baton = rb;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_new_node_record(void **node_baton,
+                       apr_hash_t *headers,
+                       void *revision_baton,
+                       apr_pool_t *pool)
+{
+  struct filter_revision_baton_t *rb = revision_baton;
+  struct filter_parse_baton_t *pb = rb->pb;
+  struct filter_node_baton_t *nb = apr_pcalloc(pool, sizeof (*nb));
+
+  nb->rb = rb;
+  SVN_ERR(pb->wrapped_parser->new_node_record(&nb->wrapped_nb, headers,
+                                              rb->wrapped_rb, pool));
+  *node_baton = nb;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_set_revision_property(void *revision_baton,
+                             const char *name,
+                             const svn_string_t *value)
+{
+  struct filter_revision_baton_t *rb = revision_baton;
+  struct filter_parse_baton_t *pb = rb->pb;
+
+  SVN_ERR(pb->wrapped_parser->set_revision_property(rb->wrapped_rb,
+                                                    name, value));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_set_node_property(void *node_baton,
+                         const char *name,
+                         const svn_string_t *value)
+{
+  struct filter_node_baton_t *nb = node_baton;
+  struct filter_revision_baton_t *rb = nb->rb;
+  struct filter_parse_baton_t *pb = rb->pb;
+
+  SVN_ERR(pb->wrapped_parser->set_node_property(nb->wrapped_nb,
+                                                name, value));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_delete_node_property(void *node_baton,
+                            const char *name)
+{
+  struct filter_node_baton_t *nb = node_baton;
+  struct filter_revision_baton_t *rb = nb->rb;
+  struct filter_parse_baton_t *pb = rb->pb;
+
+  SVN_ERR(pb->wrapped_parser->delete_node_property(nb->wrapped_nb, name));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_remove_node_props(void *node_baton)
+{
+  struct filter_node_baton_t *nb = node_baton;
+  struct filter_revision_baton_t *rb = nb->rb;
+  struct filter_parse_baton_t *pb = rb->pb;
+
+  SVN_ERR(pb->wrapped_parser->remove_node_props(nb->wrapped_nb));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_set_fulltext(svn_stream_t **stream,
+                    void *node_baton)
+{
+  struct filter_node_baton_t *nb = node_baton;
+  struct filter_revision_baton_t *rb = nb->rb;
+  struct filter_parse_baton_t *pb = rb->pb;
+
+  SVN_ERR(pb->wrapped_parser->set_fulltext(stream, nb->wrapped_nb));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_apply_textdelta(svn_txdelta_window_handler_t *handler,
+                       void **handler_baton,
+                       void *node_baton)
+{
+  struct filter_node_baton_t *nb = node_baton;
+  struct filter_revision_baton_t *rb = nb->rb;
+  struct filter_parse_baton_t *pb = rb->pb;
+
+  SVN_ERR(pb->wrapped_parser->apply_textdelta(handler, handler_baton,
+                                              nb->wrapped_nb));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_close_node(void *node_baton)
+{
+  struct filter_node_baton_t *nb = node_baton;
+  struct filter_revision_baton_t *rb = nb->rb;
+  struct filter_parse_baton_t *pb = rb->pb;
+
+  SVN_ERR(pb->wrapped_parser->close_node(nb->wrapped_nb));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_close_revision(void *revision_baton)
+{
+  struct filter_revision_baton_t *rb = revision_baton;
+  struct filter_parse_baton_t *pb = rb->pb;
+
+  SVN_ERR(pb->wrapped_parser->close_revision(rb->wrapped_rb));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+get_dumpstream_filter(svn_repos_parse_fns3_t **parser_p,
+                      void **parse_baton_p,
+                      const svn_repos_parse_fns3_t *wrapped_parser,
+                      void *wrapped_baton,
+                      apr_pool_t *pool)
+{
+  svn_repos_parse_fns3_t *parser;
+  struct filter_parse_baton_t *b;
+
+  parser = apr_pcalloc(pool, sizeof(*parser));
+  parser->magic_header_record = filter_magic_header_record;
+  parser->uuid_record = filter_uuid_record;
+  parser->new_revision_record = filter_new_revision_record;
+  parser->new_node_record = filter_new_node_record;
+  parser->set_revision_property = filter_set_revision_property;
+  parser->set_node_property = filter_set_node_property;
+  parser->delete_node_property = filter_delete_node_property;
+  parser->remove_node_props = filter_remove_node_props;
+  parser->set_fulltext = filter_set_fulltext;
+  parser->apply_textdelta = filter_apply_textdelta;
+  parser->close_node = filter_close_node;
+  parser->close_revision = filter_close_revision;
+
+  b = apr_pcalloc(pool, sizeof(*b));
+  b->wrapped_parser = wrapped_parser;
+  b->wrapped_pb = wrapped_baton;
+
+  *parser_p = parser;
+  *parse_baton_p = b;
+  return SVN_NO_ERROR;
+}
+
+/*----------------------------------------------------------------------*/
+
+/* Implements `svn_ra__lock_retry_func_t'. */
+static svn_error_t *
+lock_retry_func(void *baton,
+                const svn_string_t *reposlocktoken,
+                apr_pool_t *pool)
+{
+  return svn_cmdline_printf(pool,
+                            _("Failed to get lock on destination "
+                              "repos, currently held by '%s'\n"),
+                            reposlocktoken->data);
+}
+
+/* Acquire a lock (of sorts) on the repository associated with the
+ * given RA SESSION. This lock is just a revprop change attempt in a
+ * time-delay loop. This function is duplicated by svnsync in
+ * svnsync/svnsync.c
+ *
+ * ### TODO: Make this function more generic and
+ * expose it through a header for use by other Subversion
+ * applications to avoid duplication.
+ */
+static svn_error_t *
+get_lock(const svn_string_t **lock_string_p,
+         svn_ra_session_t *session,
+         svn_cancel_func_t cancel_func,
+         void *cancel_baton,
+         apr_pool_t *pool)
+{
+  svn_boolean_t be_atomic;
+
+  SVN_ERR(svn_ra_has_capability(session, &be_atomic,
+                                SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+                                pool));
+  if (! be_atomic)
+    {
+      /* Pre-1.7 servers can't lock without a race condition.  (Issue #3546) */
+      svn_error_t *err =
+        svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+                         _("Target server does not support atomic revision "
+                           "property edits; consider upgrading it to 1.7."));
+      svn_handle_warning2(stderr, err, "svnrdump: ");
+      svn_error_clear(err);
+    }
+
+  return svn_ra__get_operational_lock(lock_string_p, NULL, session,
+                                      SVNRDUMP_PROP_LOCK, FALSE,
+                                      10 /* retries */, lock_retry_func, NULL,
+                                      cancel_func, cancel_baton, pool);
+}
+
+svn_error_t *
+svn_rdump__load_dumpstream(svn_stream_t *stream,
+                           svn_ra_session_t *session,
+                           svn_ra_session_t *aux_session,
+                           svn_boolean_t quiet,
+                           apr_hash_t *skip_revprops,
+                           svn_cancel_func_t cancel_func,
+                           void *cancel_baton,
+                           apr_pool_t *pool)
+{
+  svn_repos_parse_fns3_t *parser;
+  void *parse_baton;
+  const svn_string_t *lock_string;
+  svn_error_t *err;
+
+  SVN_ERR(get_lock(&lock_string, session, cancel_func, cancel_baton, pool));
+
+  SVN_ERR(get_dumpstream_loader(&parser, &parse_baton,
+                                session, aux_session,
+                                quiet, skip_revprops,
+                                pool));
+
+  /* Interpose a filtering layer: currently doing nothing */
+  SVN_ERR(get_dumpstream_filter(&parser, &parse_baton,
+                                parser, parse_baton,
+                                pool));
 
   err = svn_repos_parse_dumpstream3(stream, parser, parse_baton, FALSE,
                                     cancel_func, cancel_baton, pool);

Modified: subversion/branches/multi-wc-format/subversion/svnrdump/svnrdump.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/svnrdump/svnrdump.c?rev=1845479&r1=1845478&r2=1845479&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/svnrdump/svnrdump.c (original)
+++ subversion/branches/multi-wc-format/subversion/svnrdump/svnrdump.c Thu Nov  1 14:27:23 2018
@@ -90,13 +90,15 @@ static const svn_opt_subcommand_desc3_t
        "in a 'dumpfile' portable format.  If only LOWER is given, dump that\n"
        "one revision.\n"
     )},
-    { 'r', 'q', opt_incremental, SVN_SVNRDUMP__BASE_OPTIONS } },
+    { 'r', 'q', opt_incremental, 'F', SVN_SVNRDUMP__BASE_OPTIONS },
+    {{'F', N_("write to file ARG instead of stdout")}} },
   { "load", load_cmd, { 0 }, {N_(
        "usage: svnrdump load URL\n"
        "\n"), N_(
        "Load a 'dumpfile' given on stdin to a repository at remote URL.\n"
     )},
-    { 'q', opt_skip_revprop, SVN_SVNRDUMP__BASE_OPTIONS } },
+    { 'q', opt_skip_revprop, 'F', SVN_SVNRDUMP__BASE_OPTIONS },
+    {{'F', N_("read from file ARG instead of stdin")}} },
   { "help", 0, { "?", "h" }, {N_(
        "usage: svnrdump help [SUBCOMMAND...]\n"
        "\n"), N_(
@@ -164,7 +166,8 @@ static const apr_getopt_option_t svnrdum
                        "valid certificate) and 'other' (all other not\n"
                        "                             "
                        "separately classified certificate errors).")},
-    {"dumpfile", 'F', 1, N_("Read or write to a dumpfile instead of stdin/stdout")},
+    {"file",          'F', 1,
+                      N_("read/write file ARG instead of stdin/stdout")},
     {0, 0, 0, 0}
   };
 
@@ -497,12 +500,11 @@ replay_revisions(svn_ra_session_t *sessi
   replay_baton->quiet = quiet;
 
   /* Write the magic header and UUID */
-  SVN_ERR(svn_stream_printf(output_stream, pool,
-                            SVN_REPOS_DUMPFILE_MAGIC_HEADER ": %d\n\n",
-                            SVN_REPOS_DUMPFILE_FORMAT_VERSION));
+  SVN_ERR(svn_repos__dump_magic_header_record(output_stream,
+                                              SVN_REPOS_DUMPFILE_FORMAT_VERSION,
+                                              pool));
   SVN_ERR(svn_ra_get_uuid2(session, &uuid, pool));
-  SVN_ERR(svn_stream_printf(output_stream, pool,
-                            SVN_REPOS_DUMPFILE_UUID ": %s\n\n", uuid));
+  SVN_ERR(svn_repos__dump_uuid_header_record(output_stream, uuid, pool));
 
   /* Fake revision 0 if necessary */
   if (start_revision == 0)
@@ -546,6 +548,7 @@ replay_revisions(svn_ra_session_t *sessi
 #endif
     }
 
+  SVN_ERR(svn_stream_close(output_stream));
   return SVN_NO_ERROR;
 }
 
@@ -578,6 +581,7 @@ load_revisions(svn_ra_session_t *session
                                      quiet, skip_revprops,
                                      check_cancel, NULL, pool));
 
+  SVN_ERR(svn_stream_close(output_stream));
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/multi-wc-format/subversion/svnrdump/svnrdump.h
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/svnrdump/svnrdump.h?rev=1845479&r1=1845478&r2=1845479&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/svnrdump/svnrdump.h (original)
+++ subversion/branches/multi-wc-format/subversion/svnrdump/svnrdump.h Thu Nov  1 14:27:23 2018
@@ -77,12 +77,21 @@ svn_rdump__get_dump_editor_v2(svn_editor
 
 /**
  * Load the dumpstream carried in @a stream to the location described
- * by @a session.  Use @a aux_session (which is opened to the same URL
- * as @a session) for any secondary, out-of-band RA communications
- * required.  If @a quiet is set, suppress notifications.  Use @a pool
- * for all memory allocations.  Use @a cancel_func and @a cancel_baton
- * to check for user cancellation of the operation (for
- * timely-but-safe termination).
+ * by @a session.
+ *
+ * Use @a aux_session (which is opened to the same URL as @a session)
+ * for any secondary, out-of-band RA communications required. This is
+ * needed when loading a non-deltas dump, and for Ev2.
+ *
+ * Print feedback to the console for each revision, unless @a quiet is true.
+ *
+ * Ignore (don't set) any revision property whose name is a key in
+ * @a skip_revprops. The values in the hash are unimportant.
+ *
+ * Use @a cancel_func and @a cancel_baton to check for user cancellation
+ * of the operation (for timely-but-safe termination).
+ *
+ * Use @a pool for all memory allocations.
  */
 svn_error_t *
 svn_rdump__load_dumpstream(svn_stream_t *stream,

Modified: subversion/branches/multi-wc-format/subversion/tests/cmdline/basic_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/tests/cmdline/basic_tests.py?rev=1845479&r1=1845478&r2=1845479&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/tests/cmdline/basic_tests.py (original)
+++ subversion/branches/multi-wc-format/subversion/tests/cmdline/basic_tests.py Thu Nov  1 14:27:23 2018
@@ -3050,6 +3050,42 @@ def peg_rev_on_non_existent_wc_path(sbox
                                      'cat', '-r2', sbox.ospath('mu3') + '@3')
 
 
+def do_move_with_at_signs(sbox, src, dst, dst_cmdline):
+  sbox.build()
+
+  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
+  expected_status.tweak(src, status='D ', moved_to=dst)
+  expected_status.add({dst: Item(status='A ', copied='+',
+                                 moved_from=src, wc_rev='-')})
+
+  sbox.simple_move(src, dst_cmdline)
+  svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status)
+
+@Issue(4530)
+@XFail()
+def move_to_target_with_leading_at_sign(sbox):
+  "rename to dir/@file"
+
+  do_move_with_at_signs(sbox, 'iota', 'A/@upsilon', 'A/@upsilon')
+
+
+@Issue(4530)
+@XFail()
+def move_to_target_with_leading_and_trailing_at_sign(sbox):
+  "rename to dir/@file@"
+
+  do_move_with_at_signs(sbox, 'iota', 'A/@upsilon', 'A/@upsilon@')
+
+
+@Issue(4532)
+def diff_previous_revision_of_r0(sbox):
+  """diff -rPREV on WC at revision 0"""
+
+  sbox.build(empty=True)
+  svntest.actions.run_and_verify_svn(None, 'svn: E195002: ',
+                                     'diff', '-rPREV', sbox.ospath(''))
+
+
 # With 'svn mkdir --parents' the target directory may already exist on disk.
 # In that case it was wrongly performing a recursive 'add' on its contents.
 def mkdir_parents_target_exists_on_disk(sbox):
@@ -3302,6 +3338,9 @@ test_list = [ None,
               rm_missing_with_case_clashing_ondisk_item,
               delete_conflicts_one_of_many,
               peg_rev_on_non_existent_wc_path,
+              move_to_target_with_leading_at_sign,
+              move_to_target_with_leading_and_trailing_at_sign,
+              diff_previous_revision_of_r0,
               mkdir_parents_target_exists_on_disk,
               plaintext_password_storage_disabled,
               filtered_ls,

Modified: subversion/branches/multi-wc-format/subversion/tests/cmdline/copy_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/tests/cmdline/copy_tests.py?rev=1845479&r1=1845478&r2=1845479&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/tests/cmdline/copy_tests.py (original)
+++ subversion/branches/multi-wc-format/subversion/tests/cmdline/copy_tests.py Thu Nov  1 14:27:23 2018
@@ -3504,6 +3504,50 @@ def copy_make_parents_wc_wc(sbox):
                                         expected_output,
                                         expected_status)
 
+
+#----------------------------------------------------------------------
+# Test copying and creating parents in the wc with dst directory being
+# precreated and unversioned
+
+def copy_make_parents_wc_wc_existing_unversioned_dst(sbox):
+  "svn cp --parents WC_PATH WC_PATH (ex. unver. dst)"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  iota_path = sbox.ospath('iota')
+  new_iota_path = sbox.ospath('X/Y/Z/iota')
+  os.makedirs(os.path.dirname(new_iota_path))
+
+  # Copy iota
+  svntest.actions.run_and_verify_svn(None, [],
+                                     'cp', '--parents',
+                                     iota_path, new_iota_path)
+
+  # Create expected output
+  expected_output = svntest.wc.State(wc_dir, {
+    'X'          : Item(verb='Adding'),
+    'X/Y'        : Item(verb='Adding'),
+    'X/Y/Z'      : Item(verb='Adding'),
+    'X/Y/Z/iota' : Item(verb='Adding'),
+    })
+
+  # Create expected status tree
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+
+  # Add the moved files
+  expected_status.add({
+    'X'           : Item(status='  ', wc_rev=2),
+    'X/Y'         : Item(status='  ', wc_rev=2),
+    'X/Y/Z'       : Item(status='  ', wc_rev=2),
+    'X/Y/Z/iota'  : Item(status='  ', wc_rev=2),
+    })
+
+  svntest.actions.run_and_verify_commit(wc_dir,
+                                        expected_output,
+                                        expected_status)
+
+
 #----------------------------------------------------------------------
 # Test copying and creating parents from the repo to the wc
 
@@ -3546,6 +3590,49 @@ def copy_make_parents_repo_wc(sbox):
 
 
 #----------------------------------------------------------------------
+# Test copying and creating parents from the repo to the wc with dst
+# directory being precreated and unversioned
+
+def copy_make_parents_repo_wc_existing_unversioned_dst(sbox):
+  "svn cp --parents URL WC_PATH with (ex. unver. dst)"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  iota_url = sbox.repo_url + '/iota'
+  new_iota_path = sbox.ospath('X/Y/Z/iota')
+  os.makedirs(os.path.dirname(new_iota_path))
+
+  # Copy iota
+  svntest.actions.run_and_verify_svn(None, [],
+                                     'cp', '--parents',
+                                     iota_url, new_iota_path)
+
+  # Create expected output
+  expected_output = svntest.wc.State(wc_dir, {
+    'X'           : Item(verb='Adding'),
+    'X/Y'         : Item(verb='Adding'),
+    'X/Y/Z'       : Item(verb='Adding'),
+    'X/Y/Z/iota'  : Item(verb='Adding'),
+    })
+
+  # Create expected status tree
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+
+  # Add the moved files
+  expected_status.add({
+    'X'           : Item(status='  ', wc_rev=2),
+    'X/Y'         : Item(status='  ', wc_rev=2),
+    'X/Y/Z'       : Item(status='  ', wc_rev=2),
+    'X/Y/Z/iota'  : Item(status='  ', wc_rev=2),
+    })
+
+  svntest.actions.run_and_verify_commit(wc_dir,
+                                        expected_output,
+                                        expected_status)
+
+
+#----------------------------------------------------------------------
 # Test copying and creating parents from the wc to the repo
 
 def copy_make_parents_wc_repo(sbox):
@@ -5904,7 +5991,9 @@ test_list = [ None,
               copy_peg_rev_url,
               old_dir_wc_to_wc,
               copy_make_parents_wc_wc,
+              copy_make_parents_wc_wc_existing_unversioned_dst,
               copy_make_parents_repo_wc,
+              copy_make_parents_repo_wc_existing_unversioned_dst,
               copy_make_parents_wc_repo,
               copy_make_parents_repo_repo,
               URI_encoded_repos_to_wc,

Modified: subversion/branches/multi-wc-format/subversion/tests/cmdline/svnrdump_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/tests/cmdline/svnrdump_tests.py?rev=1845479&r1=1845478&r2=1845479&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/tests/cmdline/svnrdump_tests.py (original)
+++ subversion/branches/multi-wc-format/subversion/tests/cmdline/svnrdump_tests.py Thu Nov  1 14:27:23 2018
@@ -82,6 +82,53 @@ def compare_repos_dumps(sbox, other_dump
   svntest.verify.compare_dump_files(
     None, None, other_dumpfile, sbox_dumpfile)
 
+def run_and_verify_svnrdump_dump(dumpfile,
+                                 expected_stdout,
+                                 expected_stderr,
+                                 expected_exit,
+                                 *varargs):
+  """Run 'svnrdump dump'.
+     Verify the results against EXPECTED_*.
+     DUMPFILE is a filename to write to, or None to return the dump as a
+     list of strings.
+  """
+  if dumpfile:
+    varargs += ('--file=' + dumpfile,)
+    exp_stdout = None
+  else:
+    exp_stdout = expected_stdout
+  output = svntest.actions.run_and_verify_svnrdump(
+                                None,
+                                exp_stdout,
+                                expected_stderr,
+                                expected_exit,
+                                'dump',
+                                *varargs)
+  if not dumpfile:
+    return output
+
+def run_and_verify_svnrdump_load(dumpfile,
+                                 expected_stdout,
+                                 expected_stderr,
+                                 expected_exit,
+                                 *varargs):
+  """Run 'svnrdump load' to load a dumpfile.
+     Verify the results against EXPECTED_*.
+     DUMPFILE is a filename or the dump content as a list of strings.
+  """
+  if isinstance(dumpfile, list):
+    dumpfile_content = dumpfile
+  else:
+    dumpfile_content = None
+    varargs += ('--file=' + dumpfile,)
+  svntest.actions.run_and_verify_svnrdump(
+                                dumpfile_content,
+                                expected_stdout,
+                                expected_stderr,
+                                expected_exit,
+                                'load',
+                                *varargs)
+
 def run_dump_test(sbox, dumpfile_name, expected_dumpfile_name = None,
                   subdir = None, bypass_prop_validation = False,
                   ignore_base_checksums = False, extra_options = []):
@@ -112,10 +159,11 @@ def run_dump_test(sbox, dumpfile_name, e
     repo_url = repo_url + subdir
 
   # Create a dump file using svnrdump
-  opts = extra_options + ['-q', 'dump', repo_url]
+  opts = extra_options + ['-q', repo_url]
   svnrdump_dumpfile = \
-      svntest.actions.run_and_verify_svnrdump(None, svntest.verify.AnyOutput,
-                                              [], 0, *opts)
+      run_and_verify_svnrdump_dump(None,
+                                   svntest.verify.AnyOutput, [], 0,
+                                   *opts)
 
   if expected_dumpfile_name:
     expected_dumpfile = open(os.path.join(svnrdump_tests_dir,
@@ -170,9 +218,9 @@ def run_load_test(sbox, dumpfile_name, e
                                            'setuuid', sbox.repo_dir,
                                            uuid)
 
-  svntest.actions.run_and_verify_svnrdump(original_dumpfile,
-                                          svntest.verify.AnyOutput,
-                                          [], 0, 'load', sbox.repo_url)
+  run_and_verify_svnrdump_load(original_dumpfile,
+                               svntest.verify.AnyOutput,
+                               [], 0, sbox.repo_url)
 
   # Re-dump the rdump-loaded repo using svnadmin dump
   resulted_dumpfile = svntest.actions.run_and_verify_dump(sbox.repo_dir,
@@ -199,9 +247,9 @@ def basic_dump(sbox):
   sbox.build(read_only = True, create_wc = False)
 
   out = \
-      svntest.actions.run_and_verify_svnrdump(None, svntest.verify.AnyOutput,
-                                              [], 0, '-q', 'dump',
-                                              sbox.repo_url)
+      run_and_verify_svnrdump_dump(None,
+                                   svntest.verify.AnyOutput, [], 0,
+                                   '-q', sbox.repo_url)
 
   if not out[0].startswith(b'SVN-fs-dump-format-version:'):
     raise svntest.Failure('No valid output')
@@ -408,17 +456,14 @@ def reflect_dropped_renumbered_revs(sbox
 
   # Load the specified dump file into the sbox repository using
   # svnrdump load
-  dump_file = open(os.path.join(os.path.dirname(sys.argv[0]),
-                                                'svnrdump_tests_data',
-                                                'with_merges.dump'),
-                   'rb')
-  svnrdump_dumpfile = dump_file.readlines()
-  dump_file.close()
+  dump_file = os.path.join(os.path.dirname(sys.argv[0]),
+                           'svnrdump_tests_data',
+                           'with_merges.dump')
 
   # svnrdump load the dump file.
-  svntest.actions.run_and_verify_svnrdump(svnrdump_dumpfile,
-                                          svntest.verify.AnyOutput,
-                                          [], 0, 'load', sbox.repo_url)
+  run_and_verify_svnrdump_load(dump_file,
+                               svntest.verify.AnyOutput, [], 0,
+                               sbox.repo_url)
 
   # Create the 'toplevel' directory in repository and then load the same
   # dumpfile into that subtree.
@@ -426,10 +471,9 @@ def reflect_dropped_renumbered_revs(sbox
                                             'Committed revision 10.\n'],
                                     [], "mkdir", sbox.repo_url + "/toplevel",
                                      "-m", "Create toplevel dir to load into")
-  svntest.actions.run_and_verify_svnrdump(svnrdump_dumpfile,
-                                          svntest.verify.AnyOutput,
-                                          [], 0, 'load',
-                                          sbox.repo_url + "/toplevel")
+  run_and_verify_svnrdump_load(dump_file,
+                               svntest.verify.AnyOutput, [], 0,
+                               sbox.repo_url + "/toplevel")
   # Verify the svn:mergeinfo properties
   url = sbox.repo_url
   expected_output = svntest.verify.UnorderedOutput([
@@ -515,16 +559,13 @@ def dont_drop_valid_mergeinfo_during_inc
   #   Properties on 'branches/B2':
   #     svn:mergeinfo
   #       /trunk:9
-  dump_fp = open(os.path.join(os.path.dirname(sys.argv[0]),
-                              'svnrdump_tests_data',
-                              'mergeinfo_included_full.dump'),
-                 'rb')
-  dumpfile_full = dump_fp.readlines()
-  dump_fp.close()
-
-  svntest.actions.run_and_verify_svnrdump(dumpfile_full,
-                                          svntest.verify.AnyOutput,
-                                          [], 0, 'load', sbox.repo_url)
+  dumpfile_full = os.path.join(os.path.dirname(sys.argv[0]),
+                               'svnrdump_tests_data',
+                               'mergeinfo_included_full.dump')
+
+  run_and_verify_svnrdump_load(dumpfile_full,
+                               svntest.verify.AnyOutput, [], 0,
+                               sbox.repo_url)
 
   # Check that the mergeinfo is as expected.
   url = sbox.repo_url + '/branches/'
@@ -542,33 +583,22 @@ def dont_drop_valid_mergeinfo_during_inc
   #
   # Incrementally dump the repository into three dump files:
   dump_file_r1_10 = sbox.get_tempname("r1-10-dump")
-  output = svntest.actions.run_and_verify_svnrdump(None,
-                                                   svntest.verify.AnyOutput,
-                                                   [], 0, '-q', 'dump', '-r1:10',
-                                                   sbox.repo_url)
-  dump_fp = open(dump_file_r1_10, 'wb')
-  dump_fp.writelines(output)
-  dump_fp.close()
+  run_and_verify_svnrdump_dump(dump_file_r1_10,
+                               svntest.verify.AnyOutput, [], 0,
+                               '-q', '-r1:10',
+                               sbox.repo_url)
 
   dump_file_r11_13 = sbox.get_tempname("r11-13-dump")
-  output = svntest.actions.run_and_verify_svnrdump(None,
-                                                   svntest.verify.AnyOutput,
-                                                   [], 0, '-q', 'dump',
-                                                   '--incremental', '-r11:13',
-                                                   sbox.repo_url)
-  dump_fp = open(dump_file_r11_13, 'wb')
-  dump_fp.writelines(output)
-  dump_fp.close()
+  run_and_verify_svnrdump_dump(dump_file_r11_13,
+                               svntest.verify.AnyOutput, [], 0,
+                               '-q', '--incremental', '-r11:13',
+                               sbox.repo_url)
 
   dump_file_r14_15 = sbox.get_tempname("r14-15-dump")
-  output = svntest.actions.run_and_verify_svnrdump(None,
-                                                   svntest.verify.AnyOutput,
-                                                   [], 0, '-q', 'dump',
-                                                   '--incremental', '-r14:15',
-                                                   sbox.repo_url)
-  dump_fp = open(dump_file_r14_15, 'wb')
-  dump_fp.writelines(output)
-  dump_fp.close()
+  run_and_verify_svnrdump_dump(dump_file_r14_15,
+                               svntest.verify.AnyOutput, [], 0,
+                               '-q', '--incremental', '-r14:15',
+                               sbox.repo_url)
 
   # Blow away the current repos and create an empty one in its place.
   svntest.main.safe_rmtree(sbox.repo_dir, True) # Fix race with bdb in svnserve
@@ -578,21 +608,15 @@ def dont_drop_valid_mergeinfo_during_inc
   svntest.actions.enable_revprop_changes(sbox.repo_dir)
 
   # Load the three incremental dump files in sequence.
-  dump_fp = open(dump_file_r1_10, 'rb')
-  svntest.actions.run_and_verify_svnrdump(dump_fp.readlines(),
-                                          svntest.verify.AnyOutput,
-                                          [], 0, 'load', sbox.repo_url)
-  dump_fp.close()
-  dump_fp = open(dump_file_r11_13, 'rb')
-  svntest.actions.run_and_verify_svnrdump(dump_fp.readlines(),
-                                          svntest.verify.AnyOutput,
-                                          [], 0, 'load', sbox.repo_url)
-  dump_fp.close()
-  dump_fp = open(dump_file_r14_15, 'rb')
-  svntest.actions.run_and_verify_svnrdump(dump_fp.readlines(),
-                                          svntest.verify.AnyOutput,
-                                          [], 0, 'load', sbox.repo_url)
-  dump_fp.close()
+  run_and_verify_svnrdump_load(dump_file_r1_10,
+                               svntest.verify.AnyOutput, [], 0,
+                               sbox.repo_url)
+  run_and_verify_svnrdump_load(dump_file_r11_13,
+                               svntest.verify.AnyOutput, [], 0,
+                               sbox.repo_url)
+  run_and_verify_svnrdump_load(dump_file_r14_15,
+                               svntest.verify.AnyOutput, [], 0,
+                               sbox.repo_url)
 
   # Check the mergeinfo, we use the same expected output as before,
   # as it (duh!) should be exactly the same as when we loaded the
@@ -622,21 +646,17 @@ def dont_drop_valid_mergeinfo_during_inc
   #     Project-Z     (Added r5)
   #     docs/         (Added r6)
   #       README      (Added r6)
-  dump_fp = open(os.path.join(os.path.dirname(sys.argv[0]),
-                              'svnrdump_tests_data',
-                              'skeleton.dump'),
-                 'rb')
-  dumpfile_skeleton = dump_fp.readlines()
-  dump_fp.close()
-  svntest.actions.run_and_verify_svnrdump(dumpfile_skeleton,
-                                          svntest.verify.AnyOutput,
-                                          [], 0, 'load', sbox.repo_url)
+  dumpfile_skeleton = os.path.join(os.path.dirname(sys.argv[0]),
+                                   'svnrdump_tests_data',
+                                   'skeleton.dump')
+  run_and_verify_svnrdump_load(dumpfile_skeleton,
+                               svntest.verify.AnyOutput, [], 0,
+                               sbox.repo_url)
 
   # Load 'svnadmin_tests_data/mergeinfo_included_full.dump' in one shot:
-  svntest.actions.run_and_verify_svnrdump(dumpfile_full,
-                                          svntest.verify.AnyOutput,
-                                          [], 0, 'load',
-                                          sbox.repo_url + '/Projects/Project-X')
+  run_and_verify_svnrdump_load(dumpfile_full,
+                               svntest.verify.AnyOutput, [], 0,
+                               sbox.repo_url + '/Projects/Project-X')
 
   # Check that the mergeinfo is as expected.  This is exactly the
   # same expected mergeinfo we previously checked, except that the
@@ -676,31 +696,22 @@ def dont_drop_valid_mergeinfo_during_inc
   svntest.actions.enable_revprop_changes(sbox.repo_dir)
 
   # Load the skeleton repos into the empty target:
-  svntest.actions.run_and_verify_svnrdump(dumpfile_skeleton,
-                                          svntest.verify.AnyOutput,
-                                          [], 0, 'load', sbox.repo_url)
+  run_and_verify_svnrdump_load(dumpfile_skeleton,
+                               svntest.verify.AnyOutput, [], 0,
+                               sbox.repo_url)
 
   # Load the three incremental dump files in sequence.
   #
   # The first load fails the same as PART 3.
-  dump_fp = open(dump_file_r1_10, 'rb')
-  svntest.actions.run_and_verify_svnrdump(dump_fp.readlines(),
-                                          svntest.verify.AnyOutput,
-                                          [], 0, 'load',
-                                          sbox.repo_url + '/Projects/Project-X')
-  dump_fp.close()
-  dump_fp = open(dump_file_r11_13, 'rb')
-  svntest.actions.run_and_verify_svnrdump(dump_fp.readlines(),
-                                          svntest.verify.AnyOutput,
-                                          [], 0, 'load',
-                                          sbox.repo_url + '/Projects/Project-X')
-  dump_fp.close()
-  dump_fp = open(dump_file_r14_15, 'rb')
-  svntest.actions.run_and_verify_svnrdump(dump_fp.readlines(),
-                                          svntest.verify.AnyOutput,
-                                          [], 0, 'load',
-                                          sbox.repo_url + '/Projects/Project-X')
-  dump_fp.close()
+  run_and_verify_svnrdump_load(dump_file_r1_10,
+                               svntest.verify.AnyOutput, [], 0,
+                               sbox.repo_url + '/Projects/Project-X')
+  run_and_verify_svnrdump_load(dump_file_r11_13,
+                               svntest.verify.AnyOutput, [], 0,
+                               sbox.repo_url + '/Projects/Project-X')
+  run_and_verify_svnrdump_load(dump_file_r14_15,
+                               svntest.verify.AnyOutput, [], 0,
+                               sbox.repo_url + '/Projects/Project-X')
 
   # Check the resulting mergeinfo.  We expect the exact same results
   # as Part 3.
@@ -729,15 +740,12 @@ def svnrdump_load_partial_incremental_du
 
   # Load the specified dump file into the sbox repository using
   # svnrdump load
-  dump_file = open(os.path.join(os.path.dirname(sys.argv[0]),
-                                                'svnrdump_tests_data',
-                                                'partial_incremental.dump'),
-                   'rb')
-  svnrdump_dumpfile = dump_file.readlines()
-  dump_file.close()
-  svntest.actions.run_and_verify_svnrdump(svnrdump_dumpfile,
-                                          svntest.verify.AnyOutput,
-                                          [], 0, 'load', sbox.repo_url)
+  dump_file = os.path.join(os.path.dirname(sys.argv[0]),
+                           'svnrdump_tests_data',
+                           'partial_incremental.dump')
+  run_and_verify_svnrdump_load(dump_file,
+                               svntest.verify.AnyOutput, [], 0,
+                               sbox.repo_url)
 
 
 #----------------------------------------------------------------------
@@ -789,9 +797,9 @@ def load_prop_change_in_non_deltas_dump(
   # Try to load that dump.
   sbox.build(create_wc=False, empty=True)
   svntest.actions.enable_revprop_changes(sbox.repo_dir)
-  svntest.actions.run_and_verify_svnrdump(dump,
-                                          [], [], 0,
-                                          '-q', 'load', sbox.repo_url)
+  run_and_verify_svnrdump_load(dump,
+                               [], [], 0,
+                               '-q', sbox.repo_url)
 
 #----------------------------------------------------------------------
 
@@ -852,9 +860,9 @@ def load_non_deltas_copy_with_props(sbox
   new_repo_dir, new_repo_url = sbox.add_repo_path('new_repo')
   svntest.main.create_repos(new_repo_dir)
   svntest.actions.enable_revprop_changes(new_repo_dir)
-  svntest.actions.run_and_verify_svnrdump(dumpfile,
-                                          svntest.verify.AnyOutput,
-                                          [], 0, 'load', new_repo_url)
+  run_and_verify_svnrdump_load(dumpfile,
+                               svntest.verify.AnyOutput, [], 0,
+                               new_repo_url)
 
   # Check that property 'p' really was deleted on each copied node
   for tgt_path in ['A/mu_COPY', 'A/B_COPY', 'A/B_COPY/E',
@@ -899,9 +907,9 @@ def load_non_deltas_replace_copy_with_pr
   new_repo_dir, new_repo_url = sbox.add_repo_path('new_repo')
   svntest.main.create_repos(new_repo_dir)
   svntest.actions.enable_revprop_changes(new_repo_dir)
-  svntest.actions.run_and_verify_svnrdump(dumpfile,
-                                          svntest.verify.AnyOutput,
-                                          [], 0, 'load', new_repo_url)
+  run_and_verify_svnrdump_load(dumpfile,
+                               svntest.verify.AnyOutput, [], 0,
+                               new_repo_url)
 
   # Check that property 'p' really was deleted on each copied node
   # This used to fail, finding that property 'p' was still present
@@ -928,9 +936,10 @@ def dump_replace_with_copy(sbox):
   sbox.simple_commit()
 
   # Dump with 'svnrdump'
-  dumpfile = svntest.actions.run_and_verify_svnrdump(
-                               None, svntest.verify.AnyOutput, [], 0,
-                               'dump', '--quiet', '--incremental', '-r2',
+  dumpfile = run_and_verify_svnrdump_dump(
+                               None,
+                               svntest.verify.AnyOutput, [], 0,
+                               '--quiet', '--incremental', '-r2',
                                sbox.repo_url)
 
   # Check the 'delete' record headers: expect this parse to fail if headers
@@ -969,9 +978,9 @@ def load_non_deltas_with_props(sbox):
   new_repo_dir, new_repo_url = sbox.add_repo_path('new_repo')
   svntest.main.create_repos(new_repo_dir)
   svntest.actions.enable_revprop_changes(new_repo_dir)
-  svntest.actions.run_and_verify_svnrdump(dumpfile,
-                                          svntest.verify.AnyOutput,
-                                          [], 0, 'load', new_repo_url)
+  run_and_verify_svnrdump_load(dumpfile,
+                               svntest.verify.AnyOutput, [], 0,
+                               new_repo_url)
 
   # Check that property 'q' remains on each modified node
   for tgt_path in ['A/mu', 'A/B']:

Modified: subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/setenv.sh
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/setenv.sh?rev=1845479&r1=1845478&r2=1845479&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/setenv.sh (original)
+++ subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/setenv.sh Thu Nov  1 14:27:23 2018
@@ -24,8 +24,9 @@
 ##     SVNBB_SERF               Serf installation prefix
 ##                              Note: Serf should be built only
 ##                                    with the system APR/-Util.
+##     SVNBB_APR                Path of the default APR
+##     SVNBB_APRUTIL            Path of the default APR-Util
 ##     SVNBB_APR_13_NOTHREAD    Path of APR-1.3 with threading disabled
-##     SVNBB_APR_15             Path of APR-1.5
 ##     SVNBB_APR_20_DEV         Path of APR-2.0
 ##     SVNBB_JUNIT              The path of the junit.jar
 ##     SVNBB_PARALLEL           Optional: parallelization; defaults to 2
@@ -45,7 +46,8 @@ export SVNBB_BDB
 export SVNBB_SWIG
 export SVNBB_SERF
 export SVNBB_APR_13_NOTHREAD
-export SVNBB_APR_15
+export SVNBB_APR
+export SVNBB_APRUTIL
 export SVNBB_APR_20_DEV
 export SVNBB_JUNIT
 export SVNBB_PARALLEL

Modified: subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/svnbuild-bindings.sh
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/svnbuild-bindings.sh?rev=1845479&r1=1845478&r2=1845479&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/svnbuild-bindings.sh (original)
+++ subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/svnbuild-bindings.sh Thu Nov  1 14:27:23 2018
@@ -25,21 +25,17 @@ scripts=$(cd $(dirname "$0") && pwd)
 . ${scripts}/setenv.sh
 
 #
-# Step 4: build swig-py
+# Step 4: build bindings
 #
 
-echo "============ make swig-py"
-cd ${absbld}
-make swig-py
+build_bindings() {
+    echo "============ make $1"
+    cd ${absbld}
+    make $1 2>&1 \
+        | grep -v '^ld: [w]arning:.*Falling back to library file for linking. *$'
+}
 
-echo "============ make swig-pl"
-cd ${absbld}
-make swig-pl
-
-echo "============ make swig-rb"
-cd ${absbld}
-make swig-rb
-
-echo "============ make javahl"
-cd ${absbld}
-make javahl
+build_bindings swig-py
+build_bindings swig-pl
+build_bindings swig-rb
+build_bindings javahl

Modified: subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/svnbuild.sh
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/svnbuild.sh?rev=1845479&r1=1845478&r2=1845479&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/svnbuild.sh (original)
+++ subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/svnbuild.sh Thu Nov  1 14:27:23 2018
@@ -27,11 +27,13 @@ scripts=$(cd $(dirname "$0") && pwd)
 ${scripts}/mkramdisk.sh ${volume_name} ${ramconf}
 
 # These are the default APR and Serf config options
-serfconfig="--with-serf=${SVNBB_SERF} --with-apxs=/usr/sbin/apxs"
+serfconfig=" --with-serf=${SVNBB_SERF} --with-apxs=/usr/local/opt/httpd/bin/apxs"
 
 # An optional parameter tells build scripts which version of APR to use
 if [ ! -z "$1" ]; then
     aprdir=$(eval 'echo $SVNBB_'"$1")
+else
+    aprconfig="--with-apr=${SVNBB_APR} --with-apr-util=${SVNBB_APRUTIL}"
 fi
 if [ ! -z "${aprdir}" -a  -d "${aprdir}" ]; then
     aprconfig="--with-apr=${aprdir} --with-apr-util=${aprdir}"
@@ -91,6 +93,7 @@ ${abssrc}/configure \
     ${aprconfig}${serfconfig} \
     --with-swig="${SVNBB_SWIG}" \
     --with-berkeley-db=db.h:"${SVNBB_BDB}/include":${SVNBB_BDB}/lib:db \
+    --enable-bdb6 \
     --enable-javahl \
     --without-jikes \
     ${lz4config} \
@@ -103,6 +106,14 @@ test -f config.log && mv config.log "${a
 # Step 4: build
 #
 
+# An optional parameter tells build scripts how to parallelize the build
+if [ "$2" = "serial" ]; then
+    parallel=1
+else
+    parallel=${SVNBB_PARALLEL}
+fi
+
 echo "============ make"
 cd ${absbld}
-make -j${SVNBB_PARALLEL}
+make -j${parallel} 2>&1 \
+    | grep -v '^ld: [w]arning:.*Falling back to library file for linking. *$'

Modified: subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/svncheck-bindings.sh
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/svncheck-bindings.sh?rev=1845479&r1=1845478&r2=1845479&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/svncheck-bindings.sh (original)
+++ subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/svncheck-bindings.sh Thu Nov  1 14:27:23 2018
@@ -24,6 +24,8 @@ run_tests() {
 
     echo "============ make check-${check}"
     cd ${absbld}
+    make -s install
+    make -s install-${check}
     make check-${check} ${cleanup} || exit 1
 }
 

Modified: subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/svncheck.sh
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/svncheck.sh?rev=1845479&r1=1845478&r2=1845479&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/svncheck.sh (original)
+++ subversion/branches/multi-wc-format/tools/buildbot/slaves/svn-x64-macosx/svncheck.sh Thu Nov  1 14:27:23 2018
@@ -26,13 +26,18 @@ run_tests() {
     case "${ra}" in
         local) check=check;             skipC=;;
         svn)   check=svnserveautocheck; skipC="SKIP_C_TESTS=1";;
-        dav)   check=davautocheck;      skipC="SKIP_C_TESTS=1";;
+        dav)   check=davautocheck;      skipC="SKIP_C_TESTS=1";
+               if [ "${fs}" == "bdb" ]; then
+                   mpm="APACHE_MPM=prefork"
+               else
+                   mpm="APACHE_MPM=event"
+               fi;;
         *)     exit 1;;
     esac
 
     echo "============ make check ${ra}+${fs}"
     cd ${absbld}
-    make ${check} FS_TYPE=${fs} PARALLEL=${SVNBB_PARALLEL} CLEANUP=1 ${skipC} || ok=false
+    make ${check} FS_TYPE=${fs} PARALLEL=${SVNBB_PARALLEL} CLEANUP=1 ${skipC} ${mpm} || ok=false
 
     # Move any log files to the buildbot work directory
     test -f tests.log && mv tests.log "${abssrc}/.test-logs/tests-${ra}-${fs}.log"

Modified: subversion/branches/multi-wc-format/tools/dev/unix-build/Makefile.svn
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/dev/unix-build/Makefile.svn?rev=1845479&r1=1845478&r2=1845479&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/tools/dev/unix-build/Makefile.svn (original)
+++ subversion/branches/multi-wc-format/tools/dev/unix-build/Makefile.svn Thu Nov  1 14:27:23 2018
@@ -108,7 +108,7 @@ SERF_OLD_VER	= 0.3.1
 CYRUS_SASL_VER	= 2.1.25
 SQLITE_VER	= 3160200
 LIBMAGIC_VER	= 5.30
-RUBY_VER	= 2.4.2
+RUBY_VER	= 2.4.4
 BZ2_VER	= 1.0.6
 PYTHON_VER	= 2.7.13
 JUNIT_VER	= 4.10
@@ -138,7 +138,7 @@ SHA256_${NEON_DIST} = db0bd8cdec329b48f5
 SHA256_${CYRUS_SASL_DIST} = 418c16e6240a4f9b637cbe3d62937b9675627bad27c622191d47de8686fe24fe
 SHA256_${SQLITE_DIST} = 65cc0c3e9366f50c0679c5ccd31432cea894bc4a3e8947dabab88c8693263615
 SHA256_${LIBMAGIC_DIST} = 694c2432e5240187524c9e7cf1ec6acc77b47a0e19554d34c14773e43dbbf214
-SHA256_${RUBY_DIST} = 93b9e75e00b262bc4def6b26b7ae8717efc252c47154abb7392e54357e6c8c9c
+SHA256_${RUBY_DIST} = 254f1c1a79e4cc814d1e7320bc5bdd995dc57e08727d30a767664619a9c8ae5a
 SHA256_${BZ2_DIST} = a2848f34fcd5d6cf47def00461fcb528a0484d8edef8208d6d2e2909dc61d9cd
 SHA256_${PYTHON_DIST} = a4f05a0720ce0fd92626f0278b6b433eee9a6173ddf2bced7957dfb599a5ece1
 SHA256_${JUNIT_DIST} = 36a747ca1e0b86f6ea88055b8723bb87030d627766da6288bf077afdeeb0f75a

Modified: subversion/branches/multi-wc-format/tools/dist/backport.pl
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/dist/backport.pl?rev=1845479&r1=1845478&r2=1845479&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/tools/dist/backport.pl (original)
+++ subversion/branches/multi-wc-format/tools/dist/backport.pl Thu Nov  1 14:27:23 2018
@@ -791,7 +791,7 @@ sub vote {
 
     # Add to state votes that aren't '+0' or 'edit'
     $state->{$_->{digest}}++ for grep
-                                 ($_->{approval} or $_->{vote} =~ /^(-1|-0|[+]1)$/),
+                                 +($_->{approval} or $_->{vote} =~ /^(-1|-0|[+]1)$/),
                                  @votesarray;
   }
 }

Modified: subversion/branches/multi-wc-format/tools/dist/release.py
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/dist/release.py?rev=1845479&r1=1845478&r2=1845479&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/tools/dist/release.py (original)
+++ subversion/branches/multi-wc-format/tools/dist/release.py Thu Nov  1 14:27:23 2018
@@ -1036,10 +1036,12 @@ def get_fileinfo(args):
 
 def write_announcement(args):
     'Write the release announcement.'
-    siginfo = "\n".join(get_siginfo(args, True)) + "\n"
+    siginfo = get_siginfo(args, True)
+    if not siginfo:
+      raise RuntimeError("No signatures found for %s at %s" % (args.version, args.target))
 
     data = { 'version'              : str(args.version),
-             'siginfo'              : siginfo,
+             'siginfo'              : "\n".join(siginfo) + "\n",
              'major-minor'          : args.version.branch,
              'major-minor-patch'    : args.version.base,
              'anchor'               : args.version.get_download_anchor(),
@@ -1325,8 +1327,8 @@ def write_changelog(args):
     
     separator_pattern = re.compile('^-{72}$')
     revline_pattern = re.compile('^r(\d+) \| [^\|]+ \| [^\|]+ \| \d+ lines?$')
-    changes_prefix_pattern = re.compile('^\[(U|D)?:?([^\]]+)?\](.+)$')
-    changes_suffix_pattern = re.compile('^(.+)\[(U|D)?:?([^\]]+)?\]$')
+    changes_prefix_pattern = re.compile(r'^\[(U|D)?:?([^\]]+)?\](.+)$')
+    changes_suffix_pattern = re.compile(r'^(.+)\[(U|D)?:?([^\]]+)?\]$')
     # TODO: push this into backport.status as a library function
     auto_merge_pattern = \
         re.compile(r'^Merge (r\d+,? |the r\d+ group |the \S+ branch:)')
@@ -1389,13 +1391,13 @@ def write_changelog(args):
 
         if not got_firstline:
             got_firstline = True
-            if (not re.search('status|changes|post-release housekeeping|follow-up|^\*',
+            if (not re.search(r'status|changes|post-release housekeeping|follow-up|^\*',
                               line, re.IGNORECASE)
                     and not changes_prefix_pattern.match(line)
                     and not changes_suffix_pattern.match(line)):
                 unlabeled_summary = line
 
-        if re.search('\[(c:)?(skip|ignore)\]', line, re.IGNORECASE):
+        if re.search(r'\[(c:)?(skip|ignore)\]', line, re.IGNORECASE):
             changes_ignore = True
             
         prefix_match = changes_prefix_pattern.match(line)