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/09/30 18:26:49 UTC

svn commit: r1842404 [9/11] - in /subversion/branches/better-pristines: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/client-side/svn_load_dirs/ doc/user/ notes/logo/ notes/shelving/ subversion/bindings/javahl/ subversi...

Modified: subversion/branches/better-pristines/subversion/svnrdump/dump_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/svnrdump/dump_editor.c?rev=1842404&r1=1842403&r2=1842404&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/svnrdump/dump_editor.c (original)
+++ subversion/branches/better-pristines/subversion/svnrdump/dump_editor.c Sun Sep 30 18:26:47 2018
@@ -22,951 +22,28 @@
  * ====================================================================
  */
 
-#include "svn_hash.h"
-#include "svn_pools.h"
-#include "svn_repos.h"
-#include "svn_path.h"
+#include "svn_types.h"
 #include "svn_props.h"
-#include "svn_subst.h"
-#include "svn_dirent_uri.h"
+#include "svn_ra.h"
+#include "svn_io.h"
+#include "svn_delta.h"
 
 #include "private/svn_repos_private.h"
-#include "private/svn_subr_private.h"
-#include "private/svn_dep_compat.h"
 #include "private/svn_editor.h"
 
 #include "svnrdump.h"
 #include <assert.h>
 
-#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
-
-
-/* A directory baton used by all directory-related callback functions
- * in the dump editor.  */
-struct dir_baton
-{
-  struct dump_edit_baton *eb;
-
-  /* Pool for per-directory allocations */
-  apr_pool_t *pool;
-
-  /* the path to this directory */
-  const char *repos_relpath; /* a relpath */
-
-  /* Copyfrom info for the node, if any. */
-  const char *copyfrom_path; /* a relpath */
-  svn_revnum_t copyfrom_rev;
-
-  /* Headers accumulated so far for this directory */
-  svn_repos__dumpfile_headers_t *headers;
-
-  /* Properties which were modified during change_dir_prop. */
-  apr_hash_t *props;
-
-  /* Properties which were deleted during change_dir_prop. */
-  apr_hash_t *deleted_props;
-
-  /* Hash of paths that need to be deleted, though some -might- be
-     replaced.  Maps const char * paths to this dir_baton. Note that
-     they're full paths, because that's what the editor driver gives
-     us, although they're all really within this directory. */
-  apr_hash_t *deleted_entries;
-
-  /* Flag to trigger dumping props. */
-  svn_boolean_t dump_props;
-};
-
-/* A file baton used by all file-related callback functions in the dump
- * editor */
-struct file_baton
-{
-  struct dump_edit_baton *eb;
-
-  /* Pool for per-file allocations */
-  apr_pool_t *pool;
-
-  /* the path to this file */
-  const char *repos_relpath; /* a relpath */
-
-  /* Properties which were modified during change_file_prop. */
-  apr_hash_t *props;
-
-  /* Properties which were deleted during change_file_prop. */
-  apr_hash_t *deleted_props;
-
-  /* The checksum of the file the delta is being applied to */
-  const char *base_checksum;
-
-  /* Copy state and source information (if any). */
-  svn_boolean_t is_copy;
-  const char *copyfrom_path;
-  svn_revnum_t copyfrom_rev;
-
-  /* The action associate with this node. */
-  enum svn_node_action action;
-
-  /* Flags to trigger dumping props and text. */
-  svn_boolean_t dump_text;
-  svn_boolean_t dump_props;
-};
 
 /* The baton used by the dump editor. */
 struct dump_edit_baton {
-  /* The output stream we write the dumpfile to */
-  svn_stream_t *stream;
-
   /* A backdoor ra session to fetch additional information during the edit. */
   svn_ra_session_t *ra_session;
 
-  /* The repository relpath of the anchor of the editor when driven
-     via the RA update mechanism; NULL otherwise. (When the editor is
-     driven via the RA "replay" mechanism instead, the editor is
-     always anchored at the repository, we don't need to prepend an
-     anchor path to the dumped node paths, and open_root() doesn't
-     need to manufacture directory additions.)  */
-  const char *update_anchor_relpath;
-
-  /* Pool for per-revision allocations */
-  apr_pool_t *pool;
-
-  /* Temporary file used for textdelta application along with its
-     absolute path; these two variables should be allocated in the
-     per-edit-session pool */
-  const char *delta_abspath;
-  apr_file_t *delta_file;
-
   /* The revision we're currently dumping. */
   svn_revnum_t current_revision;
-
-  /* The baton of the directory node whose block of
-     dump stream data has not been fully completed; NULL if there's no
-     such item. */
-  struct dir_baton *pending_db;
 };
 
-/* Make a directory baton to represent the directory at PATH (relative
- * to the EDIT_BATON).
- *
- * COPYFROM_PATH/COPYFROM_REV are the path/revision against which this
- * directory should be compared for changes. If the copyfrom
- * information is valid, the directory will be compared against its
- * copy source.
- *
- * PB is the directory baton of this directory's parent, or NULL if
- * this is the top-level directory of the edit.
- *
- * Perform all allocations in POOL.  */
-static struct dir_baton *
-make_dir_baton(const char *path,
-               const char *copyfrom_path,
-               svn_revnum_t copyfrom_rev,
-               void *edit_baton,
-               struct dir_baton *pb,
-               apr_pool_t *pool)
-{
-  struct dump_edit_baton *eb = edit_baton;
-  struct dir_baton *new_db = apr_pcalloc(pool, sizeof(*new_db));
-  const char *repos_relpath;
-
-  /* Construct the full path of this node. */
-  if (pb)
-    repos_relpath = svn_relpath_canonicalize(path, pool);
-  else
-    repos_relpath = "";
-
-  /* Strip leading slash from copyfrom_path so that the path is
-     canonical and svn_relpath_join can be used */
-  if (copyfrom_path)
-    copyfrom_path = svn_relpath_canonicalize(copyfrom_path, pool);
-
-  new_db->eb = eb;
-  new_db->pool = pool;
-  new_db->repos_relpath = repos_relpath;
-  new_db->copyfrom_path = copyfrom_path
-                            ? svn_relpath_canonicalize(copyfrom_path, pool)
-                            : NULL;
-  new_db->copyfrom_rev = copyfrom_rev;
-  new_db->headers = NULL;
-  new_db->props = apr_hash_make(pool);
-  new_db->deleted_props = apr_hash_make(pool);
-  new_db->deleted_entries = apr_hash_make(pool);
-
-  return new_db;
-}
-
-/* Make a file baton to represent the directory at PATH (relative to
- * PB->eb).  PB is the directory baton of this directory's parent, or
- * NULL if this is the top-level directory of the edit.  Perform all
- * allocations in POOL.  */
-static struct file_baton *
-make_file_baton(const char *path,
-                struct dir_baton *pb,
-                apr_pool_t *pool)
-{
-  struct file_baton *new_fb = apr_pcalloc(pool, sizeof(*new_fb));
-
-  new_fb->eb = pb->eb;
-  new_fb->pool = pool;
-  new_fb->repos_relpath = svn_relpath_canonicalize(path, pool);
-  new_fb->props = apr_hash_make(pool);
-  new_fb->deleted_props = apr_hash_make(pool);
-  new_fb->is_copy = FALSE;
-  new_fb->copyfrom_path = NULL;
-  new_fb->copyfrom_rev = SVN_INVALID_REVNUM;
-  new_fb->action = svn_node_action_change;
-
-  return new_fb;
-}
-
-/* Append to HEADERS the required headers, and set *CONTENT to the property
- * content section, to represent the property delta of PROPS/DELETED_PROPS.
- */
-static svn_error_t *
-get_props_content(svn_repos__dumpfile_headers_t *headers,
-                  svn_stringbuf_t **content,
-                  apr_hash_t *props,
-                  apr_hash_t *deleted_props,
-                  apr_pool_t *result_pool,
-                  apr_pool_t *scratch_pool)
-{
-  svn_stream_t *content_stream;
-  apr_hash_t *normal_props;
-
-  *content = svn_stringbuf_create_empty(result_pool);
-
-  content_stream = svn_stream_from_stringbuf(*content, scratch_pool);
-
-  SVN_ERR(svn_rdump__normalize_props(&normal_props, props, scratch_pool));
-  SVN_ERR(svn_hash_write_incremental(normal_props, deleted_props,
-                                     content_stream, "PROPS-END",
-                                     scratch_pool));
-  SVN_ERR(svn_stream_close(content_stream));
-
-  /* Prop-delta: true */
-  svn_repos__dumpfile_header_push(
-    headers, SVN_REPOS_DUMPFILE_PROP_DELTA, "true");
-
-  return SVN_NO_ERROR;
-}
-
-/* A special case of dump_node(), for a delete record.
- *
- * The only thing special about this version is it only writes one blank
- * line, not two, after the headers. Why? Historical precedent for the
- * case where a delete record is used as part of a (delete + add-with-history)
- * in implementing a replacement.
- */
-static svn_error_t *
-dump_node_delete(svn_stream_t *stream,
-                 const char *node_relpath,
-                 apr_pool_t *pool)
-{
-  svn_repos__dumpfile_headers_t *headers
-    = svn_repos__dumpfile_headers_create(pool);
-
-  assert(svn_relpath_is_canonical(node_relpath));
-
-  /* Node-path: ... */
-  svn_repos__dumpfile_header_push(
-    headers, SVN_REPOS_DUMPFILE_NODE_PATH, node_relpath);
-
-  /* Node-action: delete */
-  svn_repos__dumpfile_header_push(
-    headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete");
-
-  SVN_ERR(svn_repos__dump_node_record(stream, headers,
-                                      NULL, FALSE, 0,  /* props & text */
-                                      FALSE /*content_length_always*/, pool));
-  return SVN_NO_ERROR;
-}
-
-/* Set *HEADERS_P to contain some headers for the node at PATH of type KIND.
- *
- * ACTION describes what is happening to the node (see enum
- * svn_node_action).
- *
- * If the node was itself copied, IS_COPY is TRUE and the
- * path/revision of the copy source are in COPYFROM_PATH/COPYFROM_REV.
- * If IS_COPY is FALSE, yet COPYFROM_PATH/COPYFROM_REV are valid, this
- * node is part of a copied subtree.
- *
- * Iff ACTION is svn_node_action_replace and IS_COPY, then first write a
- * complete deletion record to the dump stream.
- *
- * If ACTION is svn_node_action_delete, then the node record will be
- * complete. (The caller may want to write two blank lines after the
- * header block.)
- */
-static svn_error_t *
-dump_node(svn_repos__dumpfile_headers_t **headers_p,
-          struct dump_edit_baton *eb,
-          const char *repos_relpath,
-          struct dir_baton *db,
-          struct file_baton *fb,
-          enum svn_node_action action,
-          svn_boolean_t is_copy,
-          const char *copyfrom_path,
-          svn_revnum_t copyfrom_rev,
-          apr_pool_t *pool)
-{
-  const char *node_relpath = repos_relpath;
-  svn_repos__dumpfile_headers_t *headers
-    = svn_repos__dumpfile_headers_create(pool);
-
-  assert(svn_relpath_is_canonical(repos_relpath));
-  assert(!copyfrom_path || svn_relpath_is_canonical(copyfrom_path));
-  assert(! (db && fb));
-
-  /* Add the edit root relpath prefix if necessary. */
-  if (eb->update_anchor_relpath)
-    node_relpath = svn_relpath_join(eb->update_anchor_relpath,
-                                    node_relpath, pool);
-
-  /* Node-path: ... */
-  svn_repos__dumpfile_header_push(
-    headers, SVN_REPOS_DUMPFILE_NODE_PATH, node_relpath);
-
-  /* Node-kind: "file" | "dir" */
-  if (fb)
-    svn_repos__dumpfile_header_push(
-      headers, SVN_REPOS_DUMPFILE_NODE_KIND, "file");
-  else if (db)
-    svn_repos__dumpfile_header_push(
-      headers, SVN_REPOS_DUMPFILE_NODE_KIND, "dir");
-
-
-  /* Write the appropriate Node-action header */
-  switch (action)
-    {
-    case svn_node_action_change:
-      /* We are here after a change_file_prop or change_dir_prop. They
-         set up whatever dump_props they needed to- nothing to
-         do here but print node action information.
-
-         Node-action: change.  */
-      svn_repos__dumpfile_header_push(
-        headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "change");
-      break;
-
-    case svn_node_action_delete:
-      /* Node-action: delete */
-      svn_repos__dumpfile_header_push(
-        headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete");
-      break;
-
-    case svn_node_action_replace:
-      if (! is_copy)
-        {
-          /* Node-action: replace */
-          svn_repos__dumpfile_header_push(
-            headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "replace");
-
-          /* Wait for a change_*_prop to be called before dumping
-             anything */
-          if (fb)
-            fb->dump_props = TRUE;
-          else if (db)
-            db->dump_props = TRUE;
-          break;
-        }
-      else
-        {
-          /* More complex case: is_copy is true, and copyfrom_path/
-             copyfrom_rev are present: delete the original, and then re-add
-             it */
-          /* ### Why not write a 'replace' record? Don't know. */
-
-          /* ### Unusually, we end this 'delete' node record with only a single
-                 blank line after the header block -- no extra blank line. */
-          SVN_ERR(dump_node_delete(eb->stream, repos_relpath, pool));
-
-          /* The remaining action is a non-replacing add-with-history */
-          /* action = svn_node_action_add; */
-        }
-      /* FALL THROUGH to 'add' */
-
-    case svn_node_action_add:
-      /* Node-action: add */
-      svn_repos__dumpfile_header_push(
-        headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "add");
-
-      if (is_copy)
-        {
-          /* Node-copyfrom-rev / Node-copyfrom-path */
-          svn_repos__dumpfile_header_pushf(
-            headers, SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV, "%ld", copyfrom_rev);
-          svn_repos__dumpfile_header_push(
-            headers, SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH, copyfrom_path);
-        }
-      else
-        {
-          /* fb->dump_props (for files) is handled in close_file()
-             which is called immediately.
-
-             However, directories are not closed until all the work
-             inside them has been done; db->dump_props (for directories)
-             is handled (via dump_pending()) in all the functions that
-             can possibly be called after add_directory():
-
-               - add_directory()
-               - open_directory()
-               - delete_entry()
-               - close_directory()
-               - add_file()
-               - open_file()
-
-             change_dir_prop() is a special case. */
-          if (fb)
-            fb->dump_props = TRUE;
-          else if (db)
-            db->dump_props = TRUE;
-        }
-
-      break;
-    }
-
-  /* Return the headers so far. We don't necessarily have all the headers
-     yet -- there may be property-related and content length headers to
-     come, if this was not a 'delete' record. */
-  *headers_p = headers;
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-dump_mkdir(struct dump_edit_baton *eb,
-           const char *repos_relpath,
-           apr_pool_t *pool)
-{
-  svn_stringbuf_t *prop_content;
-  svn_repos__dumpfile_headers_t *headers
-    = svn_repos__dumpfile_headers_create(pool);
-
-  /* Node-path: ... */
-  svn_repos__dumpfile_header_push(
-    headers, SVN_REPOS_DUMPFILE_NODE_PATH, repos_relpath);
-
-  /* Node-kind: dir */
-  svn_repos__dumpfile_header_push(
-    headers, SVN_REPOS_DUMPFILE_NODE_KIND, "dir");
-
-  /* Node-action: add */
-  svn_repos__dumpfile_header_push(
-    headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "add");
-
-  /* Dump the (empty) property block. */
-  SVN_ERR(get_props_content(headers, &prop_content,
-                            apr_hash_make(pool), apr_hash_make(pool),
-                            pool, pool));
-  SVN_ERR(svn_repos__dump_node_record(eb->stream, headers, prop_content,
-                                      FALSE, 0, FALSE /*content_length_always*/,
-                                      pool));
-
-  /* Newlines to tie it all off. */
-  SVN_ERR(svn_stream_puts(eb->stream, "\n\n"));
-
-  return SVN_NO_ERROR;
-}
-
-/* Dump pending headers and properties for the directory EB->pending_db (if
- * not null), to allow starting the dump of a child node */
-static svn_error_t *
-dump_pending_dir(struct dump_edit_baton *eb,
-                 apr_pool_t *scratch_pool)
-{
-  struct dir_baton *db = eb->pending_db;
-  svn_stringbuf_t *prop_content = NULL;
-
-  if (! db)
-    return SVN_NO_ERROR;
-
-  /* Some pending properties to dump? */
-  if (db->dump_props)
-    {
-      SVN_ERR(get_props_content(db->headers, &prop_content,
-                                db->props, db->deleted_props,
-                                scratch_pool, scratch_pool));
-    }
-  SVN_ERR(svn_repos__dump_node_record(eb->stream, db->headers, prop_content,
-                                      FALSE, 0, FALSE /*content_length_always*/,
-                                      scratch_pool));
-
-  /* No text is going to be dumped. Write a couple of newlines and
-       wait for the next node/ revision. */
-  SVN_ERR(svn_stream_puts(eb->stream, "\n\n"));
-
-  if (db->dump_props)
-    {
-      /* Cleanup so that data is never dumped twice. */
-      apr_hash_clear(db->props);
-      apr_hash_clear(db->deleted_props);
-      db->dump_props = FALSE;
-    }
-
-  /* Anything that was pending is pending no longer. */
-  eb->pending_db = NULL;
-
-  return SVN_NO_ERROR;
-}
-
-
-
-/*** Editor Function Implementations ***/
-
-static svn_error_t *
-open_root(void *edit_baton,
-          svn_revnum_t base_revision,
-          apr_pool_t *pool,
-          void **root_baton)
-{
-  struct dump_edit_baton *eb = edit_baton;
-  struct dir_baton *new_db = NULL;
-
-  /* Clear the per-revision pool after each revision */
-  svn_pool_clear(eb->pool);
-
-  if (eb->update_anchor_relpath)
-    {
-      int i;
-      const char *parent_path = eb->update_anchor_relpath;
-      apr_array_header_t *dirs_to_add =
-        apr_array_make(pool, 4, sizeof(const char *));
-      apr_pool_t *iterpool = svn_pool_create(pool);
-
-      while (! svn_path_is_empty(parent_path))
-        {
-          APR_ARRAY_PUSH(dirs_to_add, const char *) = parent_path;
-          parent_path = svn_relpath_dirname(parent_path, pool);
-        }
-
-      for (i = dirs_to_add->nelts; i; --i)
-        {
-          const char *dir_to_add =
-            APR_ARRAY_IDX(dirs_to_add, i - 1, const char *);
-
-          svn_pool_clear(iterpool);
-
-          /* For parents of the source directory, we just manufacture
-             the adds ourselves. */
-          if (i > 1)
-            {
-              SVN_ERR(dump_mkdir(eb, dir_to_add, iterpool));
-            }
-          else
-            {
-              /* ... but for the source directory itself, we'll defer
-                 to letting the typical plumbing handle this task. */
-              new_db = make_dir_baton(NULL, NULL, SVN_INVALID_REVNUM,
-                                      edit_baton, NULL, pool);
-              SVN_ERR(dump_node(&new_db->headers,
-                                eb, new_db->repos_relpath, new_db,
-                                NULL, svn_node_action_add, FALSE,
-                                NULL, SVN_INVALID_REVNUM, pool));
-
-              /* Remember that we've started but not yet finished
-                 handling this directory. */
-              eb->pending_db = new_db;
-            }
-        }
-      svn_pool_destroy(iterpool);
-    }
-
-  if (! new_db)
-    {
-      new_db = make_dir_baton(NULL, NULL, SVN_INVALID_REVNUM,
-                              edit_baton, NULL, pool);
-    }
-
-  *root_baton = new_db;
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-delete_entry(const char *path,
-             svn_revnum_t revision,
-             void *parent_baton,
-             apr_pool_t *pool)
-{
-  struct dir_baton *pb = parent_baton;
-
-  SVN_ERR(dump_pending_dir(pb->eb, pool));
-
-  /* We don't dump this deletion immediate.  Rather, we add this path
-     to the deleted_entries of the parent directory baton.  That way,
-     we can tell (later) an addition from a replacement.  All the real
-     deletions get handled in close_directory().  */
-  svn_hash_sets(pb->deleted_entries, apr_pstrdup(pb->pool, path), pb);
-
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-add_directory(const char *path,
-              void *parent_baton,
-              const char *copyfrom_path,
-              svn_revnum_t copyfrom_rev,
-              apr_pool_t *pool,
-              void **child_baton)
-{
-  struct dir_baton *pb = parent_baton;
-  void *was_deleted;
-  struct dir_baton *new_db;
-  svn_boolean_t is_copy;
-
-  SVN_ERR(dump_pending_dir(pb->eb, pool));
-
-  new_db = make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb,
-                          pb, pb->pool);
-
-  /* This might be a replacement -- is the path already deleted? */
-  was_deleted = svn_hash_gets(pb->deleted_entries, path);
-
-  /* Detect an add-with-history */
-  is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
-
-  /* Dump the node */
-  SVN_ERR(dump_node(&new_db->headers,
-                    pb->eb, new_db->repos_relpath, new_db, NULL,
-                    was_deleted ? svn_node_action_replace : svn_node_action_add,
-                    is_copy,
-                    is_copy ? new_db->copyfrom_path : NULL,
-                    is_copy ? copyfrom_rev : SVN_INVALID_REVNUM,
-                    pool));
-
-  if (was_deleted)
-    /* Delete the path, it's now been dumped */
-    svn_hash_sets(pb->deleted_entries, path, NULL);
-
-  /* Remember that we've started, but not yet finished handling this
-     directory. */
-  pb->eb->pending_db = new_db;
-
-  *child_baton = new_db;
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-open_directory(const char *path,
-               void *parent_baton,
-               svn_revnum_t base_revision,
-               apr_pool_t *pool,
-               void **child_baton)
-{
-  struct dir_baton *pb = parent_baton;
-  struct dir_baton *new_db;
-  const char *copyfrom_path = NULL;
-  svn_revnum_t copyfrom_rev = SVN_INVALID_REVNUM;
-
-  SVN_ERR(dump_pending_dir(pb->eb, pool));
-
-  /* If the parent directory has explicit comparison path and rev,
-     record the same for this one. */
-  if (ARE_VALID_COPY_ARGS(pb->copyfrom_path, pb->copyfrom_rev))
-    {
-      copyfrom_path = svn_relpath_join(pb->copyfrom_path,
-                                       svn_relpath_basename(path, NULL),
-                                       pb->pool);
-      copyfrom_rev = pb->copyfrom_rev;
-    }
-
-  new_db = make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb, pb,
-                          pb->pool);
-
-  *child_baton = new_db;
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-close_directory(void *dir_baton,
-                apr_pool_t *pool)
-{
-  struct dir_baton *db = dir_baton;
-  apr_hash_index_t *hi;
-  svn_boolean_t this_pending;
-
-  /* Remember if this directory is the one currently pending. */
-  this_pending = (db->eb->pending_db == db);
-
-  SVN_ERR(dump_pending_dir(db->eb, pool));
-
-  /* If this directory was pending, then dump_pending() should have
-     taken care of all the props and such.  Of course, the only way
-     that would be the case is if this directory was added/replaced.
-
-     Otherwise, if stuff for this directory has already been written
-     out (at some point in the past, prior to our handling other
-     nodes), we might need to generate a second "change" record just
-     to carry the information we've since learned about the
-     directory. */
-  if ((! this_pending) && (db->dump_props))
-    {
-      SVN_ERR(dump_node(&db->headers,
-                        db->eb, db->repos_relpath, db, NULL,
-                        svn_node_action_change, FALSE,
-                        NULL, SVN_INVALID_REVNUM, pool));
-      db->eb->pending_db = db;
-      SVN_ERR(dump_pending_dir(db->eb, pool));
-    }
-
-  /* Dump the deleted directory entries */
-  for (hi = apr_hash_first(pool, db->deleted_entries); hi;
-       hi = apr_hash_next(hi))
-    {
-      const char *path = apr_hash_this_key(hi);
-
-      SVN_ERR(dump_node_delete(db->eb->stream, path, pool));
-      /* This deletion record is complete -- write an extra newline */
-      SVN_ERR(svn_stream_puts(db->eb->stream, "\n"));
-    }
-
-  /* ### should be unnecessary */
-  apr_hash_clear(db->deleted_entries);
-
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-add_file(const char *path,
-         void *parent_baton,
-         const char *copyfrom_path,
-         svn_revnum_t copyfrom_rev,
-         apr_pool_t *pool,
-         void **file_baton)
-{
-  struct dir_baton *pb = parent_baton;
-  struct file_baton *fb;
-  void *was_deleted;
-
-  SVN_ERR(dump_pending_dir(pb->eb, pool));
-
-  /* Make the file baton. */
-  fb = make_file_baton(path, pb, pool);
-
-  /* This might be a replacement -- is the path already deleted? */
-  was_deleted = svn_hash_gets(pb->deleted_entries, path);
-
-  /* Detect add-with-history. */
-  if (ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev))
-    {
-      fb->copyfrom_path = svn_relpath_canonicalize(copyfrom_path, fb->pool);
-      fb->copyfrom_rev = copyfrom_rev;
-      fb->is_copy = TRUE;
-    }
-  fb->action = was_deleted ? svn_node_action_replace : svn_node_action_add;
-
-  /* Delete the path, it's now been dumped. */
-  if (was_deleted)
-    svn_hash_sets(pb->deleted_entries, path, NULL);
-
-  *file_baton = fb;
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-open_file(const char *path,
-          void *parent_baton,
-          svn_revnum_t ancestor_revision,
-          apr_pool_t *pool,
-          void **file_baton)
-{
-  struct dir_baton *pb = parent_baton;
-  struct file_baton *fb;
-
-  SVN_ERR(dump_pending_dir(pb->eb, pool));
-
-  /* Make the file baton. */
-  fb = make_file_baton(path, pb, pool);
-
-  /* If the parent directory has explicit copyfrom path and rev,
-     record the same for this one. */
-  if (ARE_VALID_COPY_ARGS(pb->copyfrom_path, pb->copyfrom_rev))
-    {
-      fb->copyfrom_path = svn_relpath_join(pb->copyfrom_path,
-                                           svn_relpath_basename(path, NULL),
-                                           pb->pool);
-      fb->copyfrom_rev = pb->copyfrom_rev;
-    }
-
-  *file_baton = fb;
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-change_dir_prop(void *parent_baton,
-                const char *name,
-                const svn_string_t *value,
-                apr_pool_t *pool)
-{
-  struct dir_baton *db = parent_baton;
-  svn_boolean_t this_pending;
-
-  /* This directory is not pending, but something else is, so handle
-     the "something else".  */
-  this_pending = (db->eb->pending_db == db);
-  if (! this_pending)
-    SVN_ERR(dump_pending_dir(db->eb, pool));
-
-  if (svn_property_kind2(name) != svn_prop_regular_kind)
-    return SVN_NO_ERROR;
-
-  if (value)
-    svn_hash_sets(db->props,
-                  apr_pstrdup(db->pool, name),
-                  svn_string_dup(value, db->pool));
-  else
-    svn_hash_sets(db->deleted_props, apr_pstrdup(db->pool, name), "");
-
-  /* Make sure we eventually output the props */
-  db->dump_props = TRUE;
-
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-change_file_prop(void *file_baton,
-                 const char *name,
-                 const svn_string_t *value,
-                 apr_pool_t *pool)
-{
-  struct file_baton *fb = file_baton;
-
-  if (svn_property_kind2(name) != svn_prop_regular_kind)
-    return SVN_NO_ERROR;
-
-  if (value)
-    svn_hash_sets(fb->props,
-                  apr_pstrdup(fb->pool, name),
-                  svn_string_dup(value, fb->pool));
-  else
-    svn_hash_sets(fb->deleted_props, apr_pstrdup(fb->pool, name), "");
-
-  /* Dump the property headers and wait; close_file might need
-     to write text headers too depending on whether
-     apply_textdelta is called */
-  fb->dump_props = TRUE;
-
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-apply_textdelta(void *file_baton, const char *base_checksum,
-                apr_pool_t *pool,
-                svn_txdelta_window_handler_t *handler,
-                void **handler_baton)
-{
-  struct file_baton *fb = file_baton;
-  struct dump_edit_baton *eb = fb->eb;
-  svn_stream_t *delta_filestream;
-
-  /* Use a temporary file to measure the Text-content-length */
-  delta_filestream = svn_stream_from_aprfile2(eb->delta_file, TRUE, pool);
-
-  /* Prepare to write the delta to the delta_filestream */
-  svn_txdelta_to_svndiff3(handler, handler_baton,
-                          delta_filestream, 0,
-                          SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, pool);
-
-  /* Record that there's text to be dumped, and its base checksum. */
-  fb->dump_text = TRUE;
-  fb->base_checksum = apr_pstrdup(fb->pool, base_checksum);
-
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-close_file(void *file_baton,
-           const char *text_checksum,
-           apr_pool_t *pool)
-{
-  struct file_baton *fb = file_baton;
-  struct dump_edit_baton *eb = fb->eb;
-  svn_filesize_t text_content_length = 0;
-  svn_stringbuf_t *propstring = NULL;
-  svn_repos__dumpfile_headers_t *headers;
-
-  SVN_ERR(dump_pending_dir(eb, pool));
-
-  /* Start dumping this node, by collecting some basic headers for it. */
-  SVN_ERR(dump_node(&headers, eb, fb->repos_relpath, NULL, fb,
-                    fb->action, fb->is_copy, fb->copyfrom_path,
-                    fb->copyfrom_rev, pool));
-
-  /* Some pending properties to dump?  We'll dump just the headers for
-     now, then dump the actual propchange content only after dumping
-     the text headers too (if present). */
-  if (fb->dump_props)
-    {
-      SVN_ERR(get_props_content(headers, &propstring,
-                                fb->props, fb->deleted_props,
-                                pool, pool));
-    }
-
-  /* Dump the text headers */
-  if (fb->dump_text)
-    {
-      /* Text-delta: true */
-      svn_repos__dumpfile_header_push(
-        headers, SVN_REPOS_DUMPFILE_TEXT_DELTA, "true");
-
-      SVN_ERR(svn_io_file_size_get(&text_content_length, eb->delta_file,
-                                   pool));
-
-      if (fb->base_checksum)
-        /* Text-delta-base-md5: */
-        svn_repos__dumpfile_header_push(
-          headers, SVN_REPOS_DUMPFILE_TEXT_DELTA_BASE_MD5, fb->base_checksum);
-
-      /* Text-content-md5: 82705804337e04dcd0e586bfa2389a7f */
-      svn_repos__dumpfile_header_push(
-        headers, SVN_REPOS_DUMPFILE_TEXT_CONTENT_MD5, text_checksum);
-    }
-
-  /* Dump the headers and props now */
-  SVN_ERR(svn_repos__dump_node_record(eb->stream, headers, propstring,
-                                      fb->dump_text, text_content_length,
-                                      FALSE /*content_length_always*/,
-                                      pool));
-
-  if (fb->dump_props)
-    {
-      /* Cleanup */
-      fb->dump_props = FALSE;
-      apr_hash_clear(fb->props);
-      apr_hash_clear(fb->deleted_props);
-    }
-
-  /* Dump the text */
-  if (fb->dump_text)
-    {
-      /* Seek to the beginning of the delta file, map it to a stream,
-         and copy the stream to eb->stream. Then close the stream and
-         truncate the file so we can reuse it for the next textdelta
-         application. Note that the file isn't created, opened or
-         closed here */
-      svn_stream_t *delta_filestream;
-      apr_off_t offset = 0;
-
-      SVN_ERR(svn_io_file_seek(eb->delta_file, APR_SET, &offset, pool));
-      delta_filestream = svn_stream_from_aprfile2(eb->delta_file, TRUE, pool);
-      SVN_ERR(svn_stream_copy3(delta_filestream, eb->stream, NULL, NULL, pool));
-
-      /* Cleanup */
-      SVN_ERR(svn_stream_close(delta_filestream));
-      SVN_ERR(svn_io_file_trunc(eb->delta_file, 0, pool));
-    }
-
-  /* Write a couple of blank lines for matching output with `svnadmin
-     dump` */
-  SVN_ERR(svn_stream_puts(eb->stream, "\n\n"));
-
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-close_edit(void *edit_baton, apr_pool_t *pool)
-{
-  return SVN_NO_ERROR;
-}
-
 static svn_error_t *
 fetch_base_func(const char **filename,
                 void *baton,
@@ -1085,47 +162,21 @@ svn_rdump__get_dump_editor(const svn_del
                            apr_pool_t *pool)
 {
   struct dump_edit_baton *eb;
-  svn_delta_editor_t *de;
   svn_delta_shim_callbacks_t *shim_callbacks =
                                         svn_delta_shim_callbacks_default(pool);
 
   eb = apr_pcalloc(pool, sizeof(struct dump_edit_baton));
-  eb->stream = stream;
   eb->ra_session = ra_session;
-  eb->update_anchor_relpath = update_anchor_relpath;
   eb->current_revision = revision;
-  eb->pending_db = NULL;
-
-  /* Create a special per-revision pool */
-  eb->pool = svn_pool_create(pool);
 
-  /* Open a unique temporary file for all textdelta applications in
-     this edit session. The file is automatically closed and cleaned
-     up when the edit session is done. */
-  SVN_ERR(svn_io_open_unique_file3(&(eb->delta_file), &(eb->delta_abspath),
-                                   NULL, svn_io_file_del_on_close, pool, pool));
-
-  de = svn_delta_default_editor(pool);
-  de->open_root = open_root;
-  de->delete_entry = delete_entry;
-  de->add_directory = add_directory;
-  de->open_directory = open_directory;
-  de->close_directory = close_directory;
-  de->change_dir_prop = change_dir_prop;
-  de->change_file_prop = change_file_prop;
-  de->apply_textdelta = apply_textdelta;
-  de->add_file = add_file;
-  de->open_file = open_file;
-  de->close_file = close_file;
-  de->close_edit = close_edit;
-
-  /* Set the edit_baton and editor. */
-  *edit_baton = eb;
-  *editor = de;
+  SVN_ERR(svn_repos__get_dump_editor(editor, edit_baton,
+                                     stream, update_anchor_relpath, pool));
 
   /* Wrap this editor in a cancellation editor. */
   SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
-                                            de, eb, editor, edit_baton, pool));
+                                            *editor, *edit_baton,
+                                            editor, edit_baton,
+                                            pool));
 
   shim_callbacks->fetch_base_func = fetch_base_func;
   shim_callbacks->fetch_props_func = fetch_props_func;

Modified: subversion/branches/better-pristines/subversion/tests/cmdline/basic_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/tests/cmdline/basic_tests.py?rev=1842404&r1=1842403&r2=1842404&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/tests/cmdline/basic_tests.py (original)
+++ subversion/branches/better-pristines/subversion/tests/cmdline/basic_tests.py Sun Sep 30 18:26:47 2018
@@ -3024,16 +3024,19 @@ def peg_rev_on_non_existent_wc_path(sbox
   # setup some history
   sbox.simple_move('A', 'A2')
   sbox.simple_move('A2/mu', 'A2/mu2')
-  open(sbox.ospath('A2/mu2'), 'w').write('r2\n')
+  with open(sbox.ospath('A2/mu2'), 'w') as f:
+    f.write('r2\n')
   sbox.simple_commit(message='r2')
   #
   sbox.simple_move('A2/mu2', 'A2/mu3')
   sbox.simple_move('A2', 'A3')
-  open(sbox.ospath('A3/mu3'), 'w').write('r3\n')
+  with open(sbox.ospath('A3/mu3'), 'w') as f:
+    f.write('r3\n')
   sbox.simple_commit(message='r3')
   #
   sbox.simple_move('A3/mu3', 'A3/mu4')
-  open(sbox.ospath('A3/mu4'), 'w').write('r4\n')
+  with open(sbox.ospath('A3/mu4'), 'w') as f:
+    f.write('r4\n')
   sbox.simple_move('A3', 'A4')
   sbox.simple_commit(message='r4')
 
@@ -3121,24 +3124,27 @@ def filtered_ls(sbox):
   sbox.build(read_only=True)
   path = sbox.repo_url + "/A/D"
 
-  # check plain info
-  expected = [ "H/omega\n",
-               "gamma\n" ]
-
-  exit_code, output, error = svntest.actions.run_and_verify_svn(
-    expected, [], 'ls', path, '--depth=infinity', '--search=*a')
-
-  # check case-insensitivity
-  exit_code, output, error = svntest.actions.run_and_verify_svn(
-    expected, [], 'ls', path, '--depth=infinity', '--search=*A')
-
-  expected = [ "H/\n" ]
-  exit_code, output, error = svntest.actions.run_and_verify_svn(
-    expected, [], 'ls', path, '--depth=infinity', '--search=h')
-
-  # we don't match full paths
-  exit_code, output, error = svntest.actions.run_and_verify_svn(
-    [], [], 'ls', path, '--depth=infinity', '--search=*/*')
+  # with and without externals, because without externals on a 1.10+ server
+  # a server-side code path is used
+  for extra_opts in [ [], ['--include-externals'] ]:
+
+    expected = [ "H/omega\n",
+                 "gamma\n" ]
+
+    exit_code, output, error = svntest.actions.run_and_verify_svn(
+      expected, [], 'ls', path, '--depth=infinity', '--search=*a', *extra_opts)
+
+    # check case-insensitivity
+    exit_code, output, error = svntest.actions.run_and_verify_svn(
+      expected, [], 'ls', path, '--depth=infinity', '--search=*A', *extra_opts)
+
+    expected = [ "H/\n" ]
+    exit_code, output, error = svntest.actions.run_and_verify_svn(
+      expected, [], 'ls', path, '--depth=infinity', '--search=h', *extra_opts)
+
+    # we don't match full paths
+    exit_code, output, error = svntest.actions.run_and_verify_svn(
+      [], [], 'ls', path, '--depth=infinity', '--search=*/*', *extra_opts)
 
 @Issue(4700)
 @XFail(svntest.main.is_fs_type_fsx)
@@ -3197,6 +3203,36 @@ def null_prop_update_last_changed_revisi
                                      'info', sbox.path('iota'),
                                      '--show-item', 'last-changed-revision')
 
+@Skip(svntest.main.is_os_windows)
+def filtered_ls_top_level_path(sbox):
+  "filtered 'svn ls' top level path"
+
+  sbox.build(read_only=True, create_wc=False)
+  d_path = sbox.repo_url + "/A/B"
+  f_path = sbox.repo_url + "/A/B/lambda"
+
+  d_expected = svntest.verify.RegexListOutput([
+                 r".* \./",  # expect '*B*' to match its name which is 'B'
+                 r".* E/beta",
+                 r".* lambda" ])
+  f_expected = [ "lambda\n" ]
+
+  # with and without externals, because without externals on a 1.10+ server
+  # a server-side code path is used
+  for extra_opts in [ [], ['--include-externals'] ]:
+
+    exit_code, output, error = svntest.actions.run_and_verify_svn(
+      d_expected, [], 'ls', '-v', d_path, '-R', '--search=*B*', *extra_opts)
+
+    exit_code, output, error = svntest.actions.run_and_verify_svn(
+      f_expected, [], 'ls', f_path, '--search=lambda', *extra_opts)
+
+    # we don't match full paths, even for the top level path
+    exit_code, output, error = svntest.actions.run_and_verify_svn(
+      [], [], 'ls', '-v', d_path, '-R', '--search=*/*', *extra_opts)
+    exit_code, output, error = svntest.actions.run_and_verify_svn(
+      [], [], 'ls', f_path, '--search=*/*', *extra_opts)
+
 
 ########################################################################
 # Run the tests
@@ -3271,6 +3307,7 @@ test_list = [ None,
               filtered_ls,
               null_update_last_changed_revision,
               null_prop_update_last_changed_revision,
+              filtered_ls_top_level_path,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/better-pristines/subversion/tests/cmdline/blame_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/tests/cmdline/blame_tests.py?rev=1842404&r1=1842403&r2=1842404&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/tests/cmdline/blame_tests.py (original)
+++ subversion/branches/better-pristines/subversion/tests/cmdline/blame_tests.py Sun Sep 30 18:26:47 2018
@@ -958,7 +958,8 @@ def blame_youngest_to_oldest(sbox):
   sbox.simple_commit() #r3
 
   # Delete a line.
-  open(iota_moved, 'w').write(line)
+  with open(iota_moved, 'w') as f:
+    f.write(line)
   sbox.simple_commit() #r4
 
   expected_output = [

Modified: subversion/branches/better-pristines/subversion/tests/cmdline/commit_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/tests/cmdline/commit_tests.py?rev=1842404&r1=1842403&r2=1842404&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/tests/cmdline/commit_tests.py (original)
+++ subversion/branches/better-pristines/subversion/tests/cmdline/commit_tests.py Sun Sep 30 18:26:47 2018
@@ -2823,7 +2823,8 @@ def commit_add_subadd(sbox):
 
   # prepare targets file
   targets = "A/D A/D/H A/D/H/chi A/D/H/omega A/D/H/psi".split()
-  open(targets_file, 'w').write("\n".join(targets))
+  with open(targets_file, 'w') as f:
+    f.write("\n".join(targets))
 
   # r2: rm A/D
   sbox.simple_rm('A/D')

Modified: subversion/branches/better-pristines/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/tests/cmdline/diff_tests.py?rev=1842404&r1=1842403&r2=1842404&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/branches/better-pristines/subversion/tests/cmdline/diff_tests.py Sun Sep 30 18:26:47 2018
@@ -36,7 +36,6 @@ from svntest import err, wc
 
 from prop_tests import binary_mime_type_on_text_file_warning
 from svntest.verify import make_diff_header, make_no_diff_deleted_header, \
-                           make_diff_header, make_no_diff_deleted_header, \
                            make_git_diff_header, make_diff_prop_header, \
                            make_diff_prop_val, make_diff_prop_deleted, \
                            make_diff_prop_added, make_diff_prop_modified
@@ -2712,7 +2711,7 @@ def diff_ignore_eolstyle(sbox):
     " Bb\n",
     "-Cc\n",
     "+Cc\n",
-    "\ No newline at end of file\n" ]
+    "\\ No newline at end of file\n" ]
 
   svntest.actions.run_and_verify_svn(expected_output, [],
                                      'diff', '-x', '--ignore-eol-style',
@@ -3855,7 +3854,7 @@ def diff_arbitrary_files_and_dirs(sbox):
   sbox.build()
   wc_dir = sbox.wc_dir
 
-  # diff iota with A/mu
+  # diff files (iota with A/mu)
   expected_output = make_diff_header("iota", "working copy", "working copy",
                                      "iota", "A/mu") + [
                       "@@ -1 +1 @@\n",
@@ -3866,7 +3865,11 @@ def diff_arbitrary_files_and_dirs(sbox):
                                      'diff', '--old', sbox.ospath('iota'),
                                      '--new', sbox.ospath('A/mu'))
 
-  # diff A/B/E with A/D
+  # diff dirs (A/B/E with A/D)
+  # .../gamma is to show as replaced; .../beta is to show as modified
+  sbox.simple_mkdir('A/B/E/gamma')
+  sbox.simple_propset('p', 'v', 'A/B/E/gamma')
+  sbox.simple_add_text("This is a different beta file.\n", 'A/D/beta')
   expected_output = make_diff_header("G/pi", "nonexistent", "working copy",
                                      "B/E", "D") + [
                       "@@ -0,0 +1 @@\n",
@@ -3896,11 +3899,16 @@ def diff_arbitrary_files_and_dirs(sbox):
                       "@@ -1 +0,0 @@\n",
                       "-This is the file 'alpha'.\n"
                     ] + make_diff_header("beta", "working copy",
-                                         "nonexistent", "B/E", "D") + [
-                      "@@ -1 +0,0 @@\n",
-                      "-This is the file 'beta'.\n"
-                    ] + make_diff_header("gamma", "nonexistent",
                                          "working copy", "B/E", "D") + [
+                      "@@ -1 +1 @@\n",
+                      "-This is the file 'beta'.\n",
+                      "+This is a different beta file.\n"
+                    ] + make_diff_header("gamma", "working copy",
+                                           "nonexistent", "B/E", "D") \
+                      + make_diff_prop_header("gamma") \
+                      + make_diff_prop_deleted("p", "v") \
+                      + make_diff_header("gamma", "nonexistent",
+                                       "working copy", "B/E", "D") + [
                       "@@ -0,0 +1 @@\n",
                       "+This is the file 'gamma'.\n"
                     ]
@@ -5160,6 +5168,90 @@ def diff_unversioned_files_git(sbox):
                                      '--old', sbox.ospath('foo'),
                                      '--new', sbox.ospath('A/bar'))
 
+# Summary diff with a repository source side and a local copy target side.
+# This particular combination crashed in 1.10.0 and earlier releases.
+def diff_summary_repo_wc_local_copy(sbox):
+  "diff summary repo wc local copy"
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  sbox.simple_copy('iota', 'iota2')
+  sbox.simple_append('iota2', 'hello\n')
+  expected_diff = svntest.wc.State(wc_dir, {
+    'iota': Item(status='M '),
+    })
+  svntest.actions.run_and_verify_diff_summarize(
+                    expected_diff,
+                    '--old=' + sbox.ospath('iota') + '@HEAD',
+                    '--new=' + sbox.ospath('iota2'))
+
+# Summary diff with a repository source side and a local copy target side.
+# Svn reported the unmodified copy as modified in 1.10.0 and earlier releases.
+@XFail()
+def diff_summary_repo_wc_local_copy_unmodified(sbox):
+  "diff summary repo wc local copy unmodified"
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  sbox.simple_copy('iota', 'iota2')
+  expected_diff = svntest.wc.State(wc_dir, {
+    })
+  svntest.actions.run_and_verify_diff_summarize(
+                    expected_diff,
+                    '--old=' + sbox.ospath('iota') + '@HEAD',
+                    '--new=' + sbox.ospath('iota2'))
+
+# Fails with "Can't open file '.../iota': Too many levels of symbolic links"
+# on Unix.
+@XFail()
+@Skip(svntest.main.is_os_windows)
+def diff_file_replaced_by_symlink(sbox):
+  "diff base vs working: symlink replaces a file"
+  sbox.build(read_only=True)
+  wc_dir = sbox.wc_dir
+
+  iota_path = sbox.ospath('iota')
+  os.remove(iota_path)
+
+  # create a symlink pointing to itself
+  # alternatively it could point to a non-existing path
+  sbox.simple_symlink('iota', 'iota')
+
+  # TODO: add a full expected output
+  expected_output = svntest.verify.AnyOutput
+  svntest.actions.run_and_verify_svn(expected_output, [], 'diff', wc_dir)
+
+# Test 'svn diff --git' with a copy.
+#
+# When this diff is rooted at a path below the repository root directory,
+# it errored out while printing the git diff header, due to confusion of
+# diff-relative and repository-relative copyfrom paths.
+@XFail()
+def diff_git_format_copy(sbox):
+  "diff git format copy"
+  sbox.build(create_wc=False)
+  svntest.actions.run_and_verify_svn(None, [], 'checkout',
+                                     sbox.repo_url + '/A/B',
+                                     sbox.wc_dir)
+  os.chdir(sbox.wc_dir)
+  sbox.wc_dir = ''
+
+  sbox.simple_copy('E/alpha', 'alpha_copied')
+  sbox.simple_append('alpha_copied', "This is a copy of 'alpha'.\n")
+
+  expected_output = \
+    make_git_diff_header('alpha_copied', 'A/B/alpha_copied',
+                         "revision 1", "working copy",
+                         copyfrom_path="A/B/E/alpha",
+                         copyfrom_rev='1', cp=True,
+                         text_changes=True) + [
+    "@@ -1 +1,2 @@\n",
+    " This is the file 'alpha'.\n",
+    "+This is a copy of 'alpha'.\n",
+  ]
+
+  svntest.actions.run_and_verify_svn(expected_output, [], 'diff',
+                                     '--git', '.')
 
 ########################################################################
 #Run the tests
@@ -5257,6 +5349,10 @@ test_list = [ None,
               diff_symlinks,
               diff_peg_resolve,
               diff_unversioned_files_git,
+              diff_summary_repo_wc_local_copy,
+              diff_summary_repo_wc_local_copy_unmodified,
+              diff_file_replaced_by_symlink,
+              diff_git_format_copy,
               ]
 
 if __name__ == '__main__':

Modified: subversion/branches/better-pristines/subversion/tests/cmdline/entries_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/tests/cmdline/entries_tests.py?rev=1842404&r1=1842403&r2=1842404&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/tests/cmdline/entries_tests.py (original)
+++ subversion/branches/better-pristines/subversion/tests/cmdline/entries_tests.py Sun Sep 30 18:26:47 2018
@@ -121,14 +121,17 @@ def basic_entries(sbox):
                                         G_path, iota_path)
 
   # Add a file over the DELETED 'alpha'. It should be schedule-add.
-  open(alpha_path, 'w').write('New alpha contents\n')
+  with open(alpha_path, 'w') as f:
+    f.write('New alpha contents\n')
 
   # Delete 'beta', then add a file over it. Should be schedule-replace.
   svntest.actions.run_and_verify_svn(None, [], 'rm', beta_path)
-  open(beta_path, 'w').write('New beta contents\n')
+  with open(beta_path, 'w') as f:
+    f.write('New beta contents\n')
 
   # Plain old add. Should have revision == 0.
-  open(added_path, 'w').write('Added file contents\n')
+  with open(added_path, 'w') as f:
+    f.write('Added file contents\n')
 
   svntest.actions.run_and_verify_svn(None, [], 'add',
                                      alpha_path, beta_path, added_path)

Modified: subversion/branches/better-pristines/subversion/tests/cmdline/export_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/tests/cmdline/export_tests.py?rev=1842404&r1=1842403&r2=1842404&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/tests/cmdline/export_tests.py (original)
+++ subversion/branches/better-pristines/subversion/tests/cmdline/export_tests.py Sun Sep 30 18:26:47 2018
@@ -610,7 +610,8 @@ def export_file_overwrite_fails(sbox):
   os.mkdir(tmpdir)
 
   # Run it for source local
-  open(os.path.join(tmpdir, 'iota'), 'w').write(not_iota_contents)
+  with open(os.path.join(tmpdir, 'iota'), 'w') as f:
+    f.write(not_iota_contents)
   svntest.actions.run_and_verify_svn([], '.*exist.*',
                                      'export', iota_path, tmpdir)
 
@@ -621,7 +622,8 @@ def export_file_overwrite_fails(sbox):
   svntest.actions.verify_disk(tmpdir, expected_disk)
 
   # Run it for source URL
-  open(os.path.join(tmpdir, 'iota'), 'w').write(not_iota_contents)
+  with open(os.path.join(tmpdir, 'iota'), 'w') as f:
+    f.write(not_iota_contents)
   svntest.actions.run_and_verify_svn([], '.*exist.*',
                                      'export', iota_url, tmpdir)
 
@@ -904,14 +906,16 @@ def export_file_overwrite_with_force(sbo
       })
 
   # Run it for WC export
-  open(os.path.join(tmpdir, 'iota'), 'w').write(not_iota_contents)
+  with open(os.path.join(tmpdir, 'iota'), 'w') as f:
+    f.write(not_iota_contents)
   svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput,
                                      [], 'export', '--force',
                                      iota_path, tmpdir)
   svntest.actions.verify_disk(tmpdir, expected_disk)
 
   # Run it for URL export
-  open(os.path.join(tmpdir, 'iota'), 'w').write(not_iota_contents)
+  with open(os.path.join(tmpdir, 'iota'), 'w') as f:
+    f.write(not_iota_contents)
   svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput,
                                      [], 'export', '--force',
                                      iota_url, tmpdir)

Modified: subversion/branches/better-pristines/subversion/tests/cmdline/externals_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/tests/cmdline/externals_tests.py?rev=1842404&r1=1842403&r2=1842404&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/tests/cmdline/externals_tests.py (original)
+++ subversion/branches/better-pristines/subversion/tests/cmdline/externals_tests.py Sun Sep 30 18:26:47 2018
@@ -1146,7 +1146,7 @@ def external_into_path_with_spaces(sbox)
   repo_url = sbox.repo_url
 
   ext = '^/A/D        "A/copy of D"\n' +\
-        '^/A/D        A/another\ copy\ of\ D'
+        '^/A/D        A/another\\ copy\\ of\\ D'
   change_external(wc_dir, ext)
 
   expected_output = svntest.wc.State(wc_dir, {
@@ -3871,12 +3871,14 @@ def copy_pin_externals_whitespace_dir(sb
   extdef = sbox.get_tempname('extdef')
   info = sbox.get_tempname('info')
 
-  open(extdef, 'w').write(
+  with open(extdef, 'w') as f:
+    f.write(
       '"' + ss_path +'/deps/sqlite"  ext/sqlite\n' +
       '"^/deps/A P R" \'ext/A P R\'\n' +
-      '^/deps/B\ D\ B\' ext/B\ D\ B\'\n' +
+      '^/deps/B\\ D\\ B\' ext/B\\ D\\ B\'\n' +
       repo_url + '/deps/wors%23+t ext/wors#+t')
-  open(info, 'w').write('info\n')
+  with open(info, 'w') as f:
+    f.write('info\n')
 
   svntest.actions.run_and_verify_svnmucc(None, [], '-U', repo_url,
                                          'mkdir', 'trunk',
@@ -4398,6 +4400,55 @@ def invalid_uris_in_repo(sbox):
                                             "-r", revision)
     svntest.main.safe_rmtree(sbox.wc_dir)
 
+# Like issue #3741 'externals not removed when working copy is made shallow'
+# but with --set-depth=exclude instead of --set-depth=empty.
+def update_dir_external_exclude(sbox):
+  "exclude update should remove externals"
+
+  sbox.build()
+
+  # Create an external in r2
+  sbox.simple_propset('svn:externals', '^/A/D/H X', 'A/B/E')
+  sbox.simple_commit()
+
+  # Update to fetch externals
+  expected_output = svntest.wc.State(sbox.wc_dir, {
+    'A/B/E/X/chi'       : Item(status='A '),
+    'A/B/E/X/omega'     : Item(status='A '),
+    'A/B/E/X/psi'       : Item(status='A '),
+  })
+  svntest.actions.run_and_verify_update(sbox.wc_dir,
+                                        expected_output, None, None,
+                                        [], False,
+                                        sbox.ospath('A/B/E'))
+
+  # Now make A/B/E shallow by updating with "--set-depth exclude"
+  expected_output = svntest.wc.State(sbox.wc_dir, {
+    'A/B/E'       : Item(status='D '),
+    'A/B/E/X'     : Item(verb='Removed external'),
+  })
+  svntest.actions.run_and_verify_update(sbox.wc_dir,
+                                        expected_output, None, None,
+                                        [], False,
+                                        '--set-depth=exclude',
+                                        sbox.ospath('A/B/E'))
+
+  # And bring the external back by updating with "--set-depth infinity"
+  expected_output = svntest.wc.State(sbox.wc_dir, {
+    'A/B/E'         : Item(status='A '),
+    'A/B/E/alpha'   : Item(status='A '),
+    'A/B/E/beta'    : Item(status='A '),
+    'A/B/E/X/chi'   : Item(status='A '),
+    'A/B/E/X/omega' : Item(status='A '),
+    'A/B/E/X/psi'   : Item(status='A '),
+  })
+  svntest.actions.run_and_verify_update(sbox.wc_dir,
+                                        expected_output, None, None,
+                                        [], False,
+                                        '--set-depth=infinity',
+                                        sbox.ospath('A/B/E'))
+
+
 ########################################################################
 # Run the tests
 
@@ -4474,6 +4525,7 @@ test_list = [ None,
               file_external_recorded_info,
               external_externally_removed,
               invalid_uris_in_repo,
+              update_dir_external_exclude,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/better-pristines/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout?rev=1842404&r1=1842403&r2=1842404&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout (original)
+++ subversion/branches/better-pristines/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout Sun Sep 30 18:26:47 2018
@@ -47,14 +47,14 @@ Available subcommands:
    unlock
    update (up)
    upgrade
-   x-shelf-diff (shelf-diff)
-   x-shelf-drop (shelf-drop)
-   x-shelf-list (shelf-list, shelves)
-   x-shelf-list-by-paths (shelf-list-by-paths)
-   x-shelf-log (shelf-log)
-   x-shelf-save (shelf-save)
-   x-shelve (shelve)
-   x-unshelve (unshelve)
+   x-shelf-diff
+   x-shelf-drop
+   x-shelf-list (x-shelves)
+   x-shelf-list-by-paths
+   x-shelf-log
+   x-shelf-save
+   x-shelve
+   x-unshelve
 
 Subversion is a tool for version control.
 For additional information, see http://subversion.apache.org/

Modified: subversion/branches/better-pristines/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout?rev=1842404&r1=1842403&r2=1842404&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout (original)
+++ subversion/branches/better-pristines/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout Sun Sep 30 18:26:47 2018
@@ -84,6 +84,10 @@ usage: 1. log [PATH][@REV]
     was created:
       svn log --stop-on-copy --limit 1 -r0:HEAD ^/branches/foo
 
+    Show all log messages for commits between the tags ^/tags/2.0 and
+    ^/tags/3.0; assuming that tag 2.0 was created in revision 100:
+      svn log -rHEAD:100 ^/tags/3.0
+
     If ^/trunk/foo.c was moved to ^/trunk/bar.c' in revision 22, 'svn log -v'
     shows a deletion and a copy in its changed paths list, such as:
        D /trunk/foo.c

Modified: subversion/branches/better-pristines/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout?rev=1842404&r1=1842403&r2=1842404&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout (original)
+++ subversion/branches/better-pristines/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout Sun Sep 30 18:26:47 2018
@@ -47,14 +47,14 @@ Available subcommands:
    unlock
    update (up)
    upgrade
-   x-shelf-diff (shelf-diff)
-   x-shelf-drop (shelf-drop)
-   x-shelf-list (shelf-list, shelves)
-   x-shelf-list-by-paths (shelf-list-by-paths)
-   x-shelf-log (shelf-log)
-   x-shelf-save (shelf-save)
-   x-shelve (shelve)
-   x-unshelve (unshelve)
+   x-shelf-diff
+   x-shelf-drop
+   x-shelf-list (x-shelves)
+   x-shelf-list-by-paths
+   x-shelf-log
+   x-shelf-save
+   x-shelve
+   x-unshelve
 
 Subversion is a tool for version control.
 For additional information, see http://subversion.apache.org/

Modified: subversion/branches/better-pristines/subversion/tests/cmdline/lock_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/tests/cmdline/lock_tests.py?rev=1842404&r1=1842403&r2=1842404&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/tests/cmdline/lock_tests.py (original)
+++ subversion/branches/better-pristines/subversion/tests/cmdline/lock_tests.py Sun Sep 30 18:26:47 2018
@@ -1571,7 +1571,8 @@ def cp_isnt_ro(sbox):
   mu2_path = sbox.ospath('A/mu2')
   mu3_path = sbox.ospath('A/mu3')
   kappa_path = sbox.ospath('kappa')
-  open(kappa_path, 'w').write("This is the file 'kappa'.\n")
+  with open(kappa_path, 'w') as f:
+    f.write("This is the file 'kappa'.\n")
 
   ## added file
   sbox.simple_add('kappa')
@@ -2251,7 +2252,6 @@ def dav_lock_refresh(sbox):
   if r.status != httplib.OK:
     raise svntest.Failure('Lock refresh failed: %d %s' % (r.status, r.reason))
 
-@SkipUnless(svntest.main.is_ra_type_dav)
 def delete_locked_file_with_percent(sbox):
   "lock and delete a file called 'a %( ) .txt'"
 

Modified: subversion/branches/better-pristines/subversion/tests/cmdline/log_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/tests/cmdline/log_tests.py?rev=1842404&r1=1842403&r2=1842404&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/tests/cmdline/log_tests.py (original)
+++ subversion/branches/better-pristines/subversion/tests/cmdline/log_tests.py Sun Sep 30 18:26:47 2018
@@ -2166,13 +2166,13 @@ def log_diff(sbox):
                + [ "@@ -1 +1,2 @@\n",
                    " This is the file 'beta'.\n",
                    "+9\n",
-                   "\ No newline at end of file\n",
+                   "\\ No newline at end of file\n",
                  ]
            ]
   r8diff = [ make_diff_header('A2/D/G/rho', 'nonexistent', 'revision 8')
               + [ "@@ -0,0 +1 @@\n",
                   "+88\n",
-                  "\ No newline at end of file\n",
+                  "\\ No newline at end of file\n",
                 ]
            ]
   log_chain = parse_log_output(output, with_diffs=True)

Modified: subversion/branches/better-pristines/subversion/tests/cmdline/move_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/tests/cmdline/move_tests.py?rev=1842404&r1=1842403&r2=1842404&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/tests/cmdline/move_tests.py (original)
+++ subversion/branches/better-pristines/subversion/tests/cmdline/move_tests.py Sun Sep 30 18:26:47 2018
@@ -1261,7 +1261,7 @@ def nested_replaces(sbox):
     '   D /A/B/C/Y',
   ]))
   expected_output = svntest.verify.UnorderedRegexListOutput(escaped
-                    + [ '^-', '^r2', '^-', '^Changed paths:', ])
+                    + [ '^--*', '^r2.*', '^--*', '^Changed paths:', ])
   svntest.actions.run_and_verify_svn(expected_output, [],
                                      'log', '-qvr2', repo_url)
 

Modified: subversion/branches/better-pristines/subversion/tests/cmdline/patch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/tests/cmdline/patch_tests.py?rev=1842404&r1=1842403&r2=1842404&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/tests/cmdline/patch_tests.py (original)
+++ subversion/branches/better-pristines/subversion/tests/cmdline/patch_tests.py Sun Sep 30 18:26:47 2018
@@ -4246,7 +4246,7 @@ def patch_git_with_index_line(sbox):
     "+++ b/src/tools/ConsoleRunner/hi.txt\n",
     "@@ -0,0 +1 @@\n",
     "+hihihihihihi\n",
-    "\ No newline at end of file\n",
+    "\\ No newline at end of file\n",
   ]
 
   svntest.main.file_write(patch_file_path, ''.join(unidiff_patch))
@@ -4413,7 +4413,7 @@ def patch_replace_dir_with_file_and_vv(s
     "+++ A/D\t(working copy)\n",
     "@@ -0,0 +1 @@\n",
     "+New file\n",
-    "\ No newline at end of file\n",
+    "\\ No newline at end of file\n",
 
   # Add iota as directory
     "Index: iota\n",
@@ -4426,7 +4426,7 @@ def patch_replace_dir_with_file_and_vv(s
     "Added: k\n",
     "## -0,0 +1 ##\n",
     "+v\n",
-    "\ No newline at end of property\n",
+    "\\ No newline at end of property\n",
   ]))
 
   expected_output = wc.State(wc_dir, {
@@ -6541,7 +6541,7 @@ def patch_prop_madness(sbox):
                                        "Property: del_n\n"
                                        "## -1,1 +0,0 ##\n"
                                        "-no-eol\n"
-                                       "\ No newline at end of property\n"
+                                       "\\ No newline at end of property\n"
                                        % (sbox.path('iota'),
                                           sbox.path('iota'))),
   })
@@ -7853,6 +7853,163 @@ def patch_mergeinfo_in_regular_prop_form
                                        [], True, True,
                                        '--strip', strip_count)
 
+@XFail()
+def patch_empty_prop(sbox):
+  "patch empty prop"
+  sbox.build(empty=True)
+  was_cwd = os.getcwd()
+  os.chdir(sbox.wc_dir)
+  sbox.wc_dir = ''
+  wc_dir = ''
+
+  # start with a file with an empty prop
+  sbox.simple_add_text('', 'f')
+  sbox.simple_propset('p', '', 'f')
+  sbox.simple_commit()
+
+  # a patch that modifies the prop to a non-empty value
+  unidiff_patch = [
+    "--- f\n",
+    "+++ f\n",
+    "\n",
+    "Property changes on: f\n",
+    "___________________________________________________________________\n",
+    "Modified: p\n",
+    "## -0,0 +1 ##\n",
+    "+v\n",
+  ]
+
+  trailing_eol = False
+  if trailing_eol:
+    value = "v\n"
+  else:
+    value = "v"
+    unidiff_patch += ['\ No newline at end of property\n']
+
+  patch_file_path = sbox.get_tempname('my.patch')
+  svntest.main.file_write(patch_file_path, ''.join(unidiff_patch), 'wb')
+
+  expected_output = [
+    ' U        %s\n' % sbox.ospath('f'),
+  ]
+
+  expected_disk = svntest.wc.State(wc_dir, {})
+  expected_disk.add({'f': Item(props={'p' : value})})
+  expected_status = svntest.wc.State(wc_dir, {})
+  expected_status.add({'f': Item(status=' M')})
+  expected_skip = wc.State('', { })
+
+  svntest.actions.run_and_verify_patch(wc_dir, patch_file_path,
+                                       expected_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       None, # expected err
+                                       1, # check-props
+                                       False, # dry-run
+                                       )
+
+  svntest.actions.check_prop('p', wc_dir, [value.encode()])
+
+  os.chdir(was_cwd)
+
+# Test that 'patch' can apply a patch that modifies properties on the root
+# of a WC and/or the root of a repository. This test uses the format of
+# diff output produced by 'svn diff --git' in svn <= 1.10.0: paths are given
+# as 'a/' and 'b/' and 'Property changes on: ' (with no following '.').
+#
+# See dev@ email thread 2018-07-09 from Dmitry Pavlenko,
+# '[PATCH] can't "svn patch" working copy root if the patch is in --git format',
+# https://lists.apache.org/thread.html/d1d9811ca36fac8cabb9339634840099e22811beac505be2ea59f19f@%3Cdev.subversion.apache.org%3E
+@XFail()
+def patch_git_wcroot(sbox):
+  "patch working copy root"
+  sbox.build(empty=True)
+  wc_dir = sbox.wc_dir
+
+  git_patch = [ "Index: .\n",
+                "===================================================================\n",
+                "diff --git a/ b/\n",
+                "--- a/	(revision 0)\n",
+                "+++ b/	(working copy)\n",
+                "Property changes on: \n",
+                "___________________________________________________________________\n",
+                "Added: p\n",
+                "## -0,0 +1 ##\n",
+                "+v\n",
+                "\\ No newline at end of property\n",
+  ]
+  value = 'v'
+
+  patch_file_path = sbox.get_tempname('my.patch')
+  svntest.main.file_write(patch_file_path, ''.join(git_patch), 'wb')
+
+  expected_output = wc.State(wc_dir, {
+    '.'                 : Item(status=' U'),
+  })
+  expected_disk = svntest.wc.State('', {})
+  expected_disk.add({'': Item(props={'p' : value })})
+  expected_status = svntest.wc.State(wc_dir, {})
+  expected_status.add({'': Item(status=' M', wc_rev='0')})
+  expected_skip = wc.State('', { })
+
+  svntest.actions.run_and_verify_patch(wc_dir, patch_file_path,
+                                       expected_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       None, # expected err
+                                       True, # check-props
+                                       False, # dry-run
+                                       )
+
+  svntest.actions.check_prop('p', wc_dir, [value.encode()])
+
+# Test that 'patch' can apply a patch that modifies properties on the root
+# of a WC and/or the root of a repository. This test performs a round-trip
+# through 'diff --git' and 'patch' rather than assuming any particular
+# variant of the patch format.
+#
+# See dev@ email thread 2018-07-09 from Dmitry Pavlenko,
+# '[PATCH] can't "svn patch" working copy root if the patch is in --git format',
+# https://lists.apache.org/thread.html/d1d9811ca36fac8cabb9339634840099e22811beac505be2ea59f19f@%3Cdev.subversion.apache.org%3E
+@XFail()
+def patch_git_wcroot2(sbox):
+  "patch working copy root"
+  sbox.build(empty=True)
+  wc_dir = sbox.wc_dir
+
+  value = 'v'
+  sbox.simple_propset('p', value, '')
+  exit_code, git_patch, err_output = svntest.main.run_svn(None, 'diff',
+                                                          '--git', wc_dir)
+
+  patch_file_path = sbox.get_tempname('my.patch')
+  svntest.main.file_write(patch_file_path, ''.join(git_patch), 'wb')
+
+  sbox.simple_revert('')
+
+  expected_output = wc.State(wc_dir, {
+    '.'                 : Item(status=' U'),
+  })
+  expected_disk = svntest.wc.State('', {})
+  expected_disk.add({'': Item(props={'p' : value })})
+  expected_status = svntest.wc.State(wc_dir, {})
+  expected_status.add({'': Item(status=' M', wc_rev='0')})
+  expected_skip = wc.State('', { })
+
+  svntest.actions.run_and_verify_patch(wc_dir, patch_file_path,
+                                       expected_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       None, # expected err
+                                       True, # check-props
+                                       False, # dry-run
+                                       )
+
+  svntest.actions.check_prop('p', wc_dir, [value.encode()])
+
 ########################################################################
 #Run the tests
 
@@ -7937,6 +8094,9 @@ test_list = [ None,
               patch_missed_trail,
               patch_merge,
               patch_mergeinfo_in_regular_prop_format,
+              patch_empty_prop,
+              patch_git_wcroot,
+              patch_git_wcroot2,
             ]
 
 if __name__ == '__main__':

Modified: subversion/branches/better-pristines/subversion/tests/cmdline/prop_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/tests/cmdline/prop_tests.py?rev=1842404&r1=1842403&r2=1842404&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/tests/cmdline/prop_tests.py (original)
+++ subversion/branches/better-pristines/subversion/tests/cmdline/prop_tests.py Sun Sep 30 18:26:47 2018
@@ -1768,7 +1768,7 @@ def rm_of_replaced_file(sbox):
                                                    'proplist', '-v',
                                                    mu_path + '@base')
   expected_output = svntest.verify.UnorderedRegexListOutput([
-      'Properties on',
+      'Properties on.*',
       '  yellow',
       '    submarine',
       '  orange',

Modified: subversion/branches/better-pristines/subversion/tests/cmdline/revert_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/better-pristines/subversion/tests/cmdline/revert_tests.py?rev=1842404&r1=1842403&r2=1842404&view=diff
==============================================================================
--- subversion/branches/better-pristines/subversion/tests/cmdline/revert_tests.py (original)
+++ subversion/branches/better-pristines/subversion/tests/cmdline/revert_tests.py Sun Sep 30 18:26:47 2018
@@ -1550,11 +1550,14 @@ def revert_with_unversioned_targets(sbox
   psi_contents = "modified psi\n"
 
   # touch delta
-  open(delta_path, 'w').write(delta_contents)
+  with open(delta_path, 'w') as f:
+    f.write(delta_contents)
 
   # modify chi psi
-  open(chi_path, 'w').write(chi_contents)
-  open(psi_path, 'w').write(psi_contents)
+  with open(chi_path, 'w') as f:
+    f.write(chi_contents)
+  with open(psi_path, 'w') as f:
+    f.write(psi_contents)
 
   # revert
   expected_output = svntest.verify.UnorderedOutput([