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 2012/12/24 10:49:04 UTC

svn commit: r1425612 [2/2] - in /subversion/branches/tweak-build-take-two: ./ build/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_fs/ subversion/libsvn_subr/ subversion/libsvn_wc/ subversion/mod_authz_svn/ subversion/mod_dav_...

Modified: subversion/branches/tweak-build-take-two/subversion/svn/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/svn/util.c?rev=1425612&r1=1425611&r2=1425612&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/svn/util.c (original)
+++ subversion/branches/tweak-build-take-two/subversion/svn/util.c Mon Dec 24 09:49:03 2012
@@ -62,6 +62,7 @@
 #include "private/svn_token.h"
 #include "private/svn_opt_private.h"
 #include "private/svn_client_private.h"
+#include "private/svn_cmdline_private.h"
 #include "private/svn_string_private.h"
 
 
@@ -93,125 +94,6 @@ svn_cl__print_commit_info(const svn_comm
 }
 
 
-/* Helper for the next two functions.  Set *EDITOR to some path to an
-   editor binary.  Sources to search include: the EDITOR_CMD argument
-   (if not NULL), $SVN_EDITOR, the runtime CONFIG variable (if CONFIG
-   is not NULL), $VISUAL, $EDITOR.  Return
-   SVN_ERR_CL_NO_EXTERNAL_EDITOR if no binary can be found. */
-static svn_error_t *
-find_editor_binary(const char **editor,
-                   const char *editor_cmd,
-                   apr_hash_t *config)
-{
-  const char *e;
-  struct svn_config_t *cfg;
-
-  /* Use the editor specified on the command line via --editor-cmd, if any. */
-  e = editor_cmd;
-
-  /* Otherwise look for the Subversion-specific environment variable. */
-  if (! e)
-    e = getenv("SVN_EDITOR");
-
-  /* If not found then fall back on the config file. */
-  if (! e)
-    {
-      cfg = config ? apr_hash_get(config, SVN_CONFIG_CATEGORY_CONFIG,
-                                  APR_HASH_KEY_STRING) : NULL;
-      svn_config_get(cfg, &e, SVN_CONFIG_SECTION_HELPERS,
-                     SVN_CONFIG_OPTION_EDITOR_CMD, NULL);
-    }
-
-  /* If not found yet then try general purpose environment variables. */
-  if (! e)
-    e = getenv("VISUAL");
-  if (! e)
-    e = getenv("EDITOR");
-
-#ifdef SVN_CLIENT_EDITOR
-  /* If still not found then fall back on the hard-coded default. */
-  if (! e)
-    e = SVN_CLIENT_EDITOR;
-#endif
-
-  /* Error if there is no editor specified */
-  if (e)
-    {
-      const char *c;
-
-      for (c = e; *c; c++)
-        if (!svn_ctype_isspace(*c))
-          break;
-
-      if (! *c)
-        return svn_error_create
-          (SVN_ERR_CL_NO_EXTERNAL_EDITOR, NULL,
-           _("The EDITOR, SVN_EDITOR or VISUAL environment variable or "
-             "'editor-cmd' run-time configuration option is empty or "
-             "consists solely of whitespace. Expected a shell command."));
-    }
-  else
-    return svn_error_create
-      (SVN_ERR_CL_NO_EXTERNAL_EDITOR, NULL,
-       _("None of the environment variables SVN_EDITOR, VISUAL or EDITOR are "
-         "set, and no 'editor-cmd' run-time configuration option was found"));
-
-  *editor = e;
-  return SVN_NO_ERROR;
-}
-
-
-/* Use the visual editor to edit files. This requires that the file name itself
-   be shell-safe, although the path to reach that file need not be shell-safe.
- */
-svn_error_t *
-svn_cl__edit_file_externally(const char *path,
-                             const char *editor_cmd,
-                             apr_hash_t *config,
-                             apr_pool_t *pool)
-{
-  const char *editor, *cmd, *base_dir, *file_name, *base_dir_apr;
-  char *old_cwd;
-  int sys_err;
-  apr_status_t apr_err;
-
-  svn_dirent_split(&base_dir, &file_name, path, pool);
-
-  SVN_ERR(find_editor_binary(&editor, editor_cmd, config));
-
-  apr_err = apr_filepath_get(&old_cwd, APR_FILEPATH_NATIVE, pool);
-  if (apr_err)
-    return svn_error_wrap_apr(apr_err, _("Can't get working directory"));
-
-  /* APR doesn't like "" directories */
-  if (base_dir[0] == '\0')
-    base_dir_apr = ".";
-  else
-    SVN_ERR(svn_path_cstring_from_utf8(&base_dir_apr, base_dir, pool));
-
-  apr_err = apr_filepath_set(base_dir_apr, pool);
-  if (apr_err)
-    return svn_error_wrap_apr
-      (apr_err, _("Can't change working directory to '%s'"), base_dir);
-
-  cmd = apr_psprintf(pool, "%s %s", editor, file_name);
-  sys_err = system(cmd);
-
-  apr_err = apr_filepath_set(old_cwd, pool);
-  if (apr_err)
-    svn_handle_error2(svn_error_wrap_apr
-                      (apr_err, _("Can't restore working directory")),
-                      stderr, TRUE /* fatal */, "svn: ");
-
-  if (sys_err)
-    /* Extracting any meaning from sys_err is platform specific, so just
-       use the raw value. */
-    return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL,
-                             _("system('%s') returned %d"), cmd, sys_err);
-
-  return SVN_NO_ERROR;
-}
-
 svn_error_t *
 svn_cl__merge_file_externally(const char *base_path,
                               const char *their_path,
@@ -290,248 +172,6 @@ svn_cl__merge_file_externally(const char
   return SVN_NO_ERROR;
 }
 
-svn_error_t *
-svn_cl__edit_string_externally(svn_string_t **edited_contents /* UTF-8! */,
-                               const char **tmpfile_left /* UTF-8! */,
-                               const char *editor_cmd,
-                               const char *base_dir /* UTF-8! */,
-                               const svn_string_t *contents /* UTF-8! */,
-                               const char *filename,
-                               apr_hash_t *config,
-                               svn_boolean_t as_text,
-                               const char *encoding,
-                               apr_pool_t *pool)
-{
-  const char *editor;
-  const char *cmd;
-  apr_file_t *tmp_file;
-  const char *tmpfile_name;
-  const char *tmpfile_native;
-  const char *tmpfile_apr, *base_dir_apr;
-  svn_string_t *translated_contents;
-  apr_status_t apr_err, apr_err2;
-  apr_size_t written;
-  apr_finfo_t finfo_before, finfo_after;
-  svn_error_t *err = SVN_NO_ERROR, *err2;
-  char *old_cwd;
-  int sys_err;
-  svn_boolean_t remove_file = TRUE;
-
-  SVN_ERR(find_editor_binary(&editor, editor_cmd, config));
-
-  /* Convert file contents from UTF-8/LF if desired. */
-  if (as_text)
-    {
-      const char *translated;
-      SVN_ERR(svn_subst_translate_cstring2(contents->data, &translated,
-                                           APR_EOL_STR, FALSE,
-                                           NULL, FALSE, pool));
-      translated_contents = svn_string_create_empty(pool);
-      if (encoding)
-        SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated_contents->data,
-                                              translated, encoding, pool));
-      else
-        SVN_ERR(svn_utf_cstring_from_utf8(&translated_contents->data,
-                                          translated, pool));
-      translated_contents->len = strlen(translated_contents->data);
-    }
-  else
-    translated_contents = svn_string_dup(contents, pool);
-
-  /* Move to BASE_DIR to avoid getting characters that need quoting
-     into tmpfile_name */
-  apr_err = apr_filepath_get(&old_cwd, APR_FILEPATH_NATIVE, pool);
-  if (apr_err)
-    return svn_error_wrap_apr(apr_err, _("Can't get working directory"));
-
-  /* APR doesn't like "" directories */
-  if (base_dir[0] == '\0')
-    base_dir_apr = ".";
-  else
-    SVN_ERR(svn_path_cstring_from_utf8(&base_dir_apr, base_dir, pool));
-  apr_err = apr_filepath_set(base_dir_apr, pool);
-  if (apr_err)
-    {
-      return svn_error_wrap_apr
-        (apr_err, _("Can't change working directory to '%s'"), base_dir);
-    }
-
-  /*** From here on, any problems that occur require us to cd back!! ***/
-
-  /* Ask the working copy for a temporary file named FILENAME-something. */
-  err = svn_io_open_uniquely_named(&tmp_file, &tmpfile_name,
-                                   "" /* dirpath */,
-                                   filename,
-                                   ".tmp",
-                                   svn_io_file_del_none, pool, pool);
-
-  if (err && (APR_STATUS_IS_EACCES(err->apr_err) || err->apr_err == EROFS))
-    {
-      const char *temp_dir_apr;
-
-      svn_error_clear(err);
-
-      SVN_ERR(svn_io_temp_dir(&base_dir, pool));
-
-      SVN_ERR(svn_path_cstring_from_utf8(&temp_dir_apr, base_dir, pool));
-      apr_err = apr_filepath_set(temp_dir_apr, pool);
-      if (apr_err)
-        {
-          return svn_error_wrap_apr
-            (apr_err, _("Can't change working directory to '%s'"), base_dir);
-        }
-
-      err = svn_io_open_uniquely_named(&tmp_file, &tmpfile_name,
-                                       "" /* dirpath */,
-                                       filename,
-                                       ".tmp",
-                                       svn_io_file_del_none, pool, pool);
-    }
-
-  if (err)
-    goto cleanup2;
-
-  /*** From here on, any problems that occur require us to cleanup
-       the file we just created!! ***/
-
-  /* Dump initial CONTENTS to TMP_FILE. */
-  apr_err = apr_file_write_full(tmp_file, translated_contents->data,
-                                translated_contents->len, &written);
-
-  apr_err2 = apr_file_close(tmp_file);
-  if (! apr_err)
-    apr_err = apr_err2;
-
-  /* Make sure the whole CONTENTS were written, else return an error. */
-  if (apr_err)
-    {
-      err = svn_error_wrap_apr(apr_err, _("Can't write to '%s'"),
-                               tmpfile_name);
-      goto cleanup;
-    }
-
-  err = svn_path_cstring_from_utf8(&tmpfile_apr, tmpfile_name, pool);
-  if (err)
-    goto cleanup;
-
-  /* Get information about the temporary file before the user has
-     been allowed to edit its contents. */
-  apr_err = apr_stat(&finfo_before, tmpfile_apr,
-                     APR_FINFO_MTIME, pool);
-  if (apr_err)
-    {
-      err = svn_error_wrap_apr(apr_err, _("Can't stat '%s'"), tmpfile_name);
-      goto cleanup;
-    }
-
-  /* Backdate the file a little bit in case the editor is very fast
-     and doesn't change the size.  (Use two seconds, since some
-     filesystems have coarse granularity.)  It's OK if this call
-     fails, so we don't check its return value.*/
-  apr_file_mtime_set(tmpfile_apr, finfo_before.mtime - 2000, pool);
-
-  /* Stat it again to get the mtime we actually set. */
-  apr_err = apr_stat(&finfo_before, tmpfile_apr,
-                     APR_FINFO_MTIME | APR_FINFO_SIZE, pool);
-  if (apr_err)
-    {
-      err = svn_error_wrap_apr(apr_err, _("Can't stat '%s'"), tmpfile_name);
-      goto cleanup;
-    }
-
-  /* Prepare the editor command line.  */
-  err = svn_utf_cstring_from_utf8(&tmpfile_native, tmpfile_name, pool);
-  if (err)
-    goto cleanup;
-  cmd = apr_psprintf(pool, "%s %s", editor, tmpfile_native);
-
-  /* If the caller wants us to leave the file around, return the path
-     of the file we'll use, and make a note not to destroy it.  */
-  if (tmpfile_left)
-    {
-      *tmpfile_left = svn_dirent_join(base_dir, tmpfile_name, pool);
-      remove_file = FALSE;
-    }
-
-  /* Now, run the editor command line.  */
-  sys_err = system(cmd);
-  if (sys_err != 0)
-    {
-      /* Extracting any meaning from sys_err is platform specific, so just
-         use the raw value. */
-      err =  svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL,
-                               _("system('%s') returned %d"), cmd, sys_err);
-      goto cleanup;
-    }
-
-  /* Get information about the temporary file after the assumed editing. */
-  apr_err = apr_stat(&finfo_after, tmpfile_apr,
-                     APR_FINFO_MTIME | APR_FINFO_SIZE, pool);
-  if (apr_err)
-    {
-      err = svn_error_wrap_apr(apr_err, _("Can't stat '%s'"), tmpfile_name);
-      goto cleanup;
-    }
-
-  /* If the file looks changed... */
-  if ((finfo_before.mtime != finfo_after.mtime) ||
-      (finfo_before.size != finfo_after.size))
-    {
-      svn_stringbuf_t *edited_contents_s;
-      err = svn_stringbuf_from_file2(&edited_contents_s, tmpfile_name, pool);
-      if (err)
-        goto cleanup;
-
-      *edited_contents = svn_stringbuf__morph_into_string(edited_contents_s);
-
-      /* Translate back to UTF8/LF if desired. */
-      if (as_text)
-        {
-          err = svn_subst_translate_string2(edited_contents, FALSE, FALSE,
-                                            *edited_contents, encoding, FALSE,
-                                            pool, pool);
-          if (err)
-            {
-              err = svn_error_quick_wrap
-                (err,
-                 _("Error normalizing edited contents to internal format"));
-              goto cleanup;
-            }
-        }
-    }
-  else
-    {
-      /* No edits seem to have been made */
-      *edited_contents = NULL;
-    }
-
- cleanup:
-  if (remove_file)
-    {
-      /* Remove the file from disk.  */
-      err2 = svn_io_remove_file2(tmpfile_name, FALSE, pool);
-
-      /* Only report remove error if there was no previous error. */
-      if (! err && err2)
-        err = err2;
-      else
-        svn_error_clear(err2);
-    }
-
- cleanup2:
-  /* If we against all probability can't cd back, all further relative
-     file references would be screwed up, so we have to abort. */
-  apr_err = apr_filepath_set(old_cwd, pool);
-  if (apr_err)
-    {
-      svn_handle_error2(svn_error_wrap_apr
-                        (apr_err, _("Can't restore working directory")),
-                        stderr, TRUE /* fatal */, "svn: ");
-    }
-
-  return svn_error_trace(err);
-}
-
 
 /* A svn_client_ctx_t's log_msg_baton3, for use with
    svn_cl__make_log_msg_baton(). */
@@ -732,8 +372,8 @@ svn_cl__get_log_message(const char **log
   while (! message)
     {
       /* We still don't have a valid commit message.  Use $EDITOR to
-         get one.  Note that svn_cl__edit_externally will still return
-         a UTF-8'ized log message. */
+         get one.  Note that svn_cl__edit_string_externally will still
+         return a UTF-8'ized log message. */
       int i;
       svn_stringbuf_t *tmp_message = svn_stringbuf_dup(default_msg, pool);
       svn_error_t *err = SVN_NO_ERROR;
@@ -793,12 +433,12 @@ svn_cl__get_log_message(const char **log
       /* Use the external edit to get a log message. */
       if (! lmb->non_interactive)
         {
-          err = svn_cl__edit_string_externally(&msg_string, &lmb->tmpfile_left,
-                                               lmb->editor_cmd, lmb->base_dir,
-                                               msg_string, "svn-commit",
-                                               lmb->config, TRUE,
-                                               lmb->message_encoding,
-                                               pool);
+          err = svn_cmdline__edit_string_externally(&msg_string, &lmb->tmpfile_left,
+                                                    lmb->editor_cmd, lmb->base_dir,
+                                                    msg_string, "svn-commit",
+                                                    lmb->config, TRUE,
+                                                    lmb->message_encoding,
+                                                    pool);
         }
       else /* non_interactive flag says we can't pop up an editor, so error */
         {

Modified: subversion/branches/tweak-build-take-two/subversion/svnmucc/svnmucc.c
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/svnmucc/svnmucc.c?rev=1425612&r1=1425611&r2=1425612&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/svnmucc/svnmucc.c (original)
+++ subversion/branches/tweak-build-take-two/subversion/svnmucc/svnmucc.c Mon Dec 24 09:49:03 2012
@@ -55,6 +55,9 @@
 
 #include "private/svn_cmdline_private.h"
 #include "private/svn_ra_private.h"
+#include "private/svn_string_private.h"
+
+#include "svn_private_config.h"
 
 static void handle_error(svn_error_t *err, apr_pool_t *pool)
 {
@@ -750,6 +753,29 @@ execute(const apr_array_header_t *action
                                             "svnmucc: ", "--config-option"));
   cfg_config = apr_hash_get(config, SVN_CONFIG_CATEGORY_CONFIG,
                             APR_HASH_KEY_STRING);
+
+  if (! apr_hash_get(revprops, SVN_PROP_REVISION_LOG, APR_HASH_KEY_STRING))
+    {
+      svn_string_t *msg = svn_string_create("", pool);
+
+      /* If we can do so, try to pop up $EDITOR to fetch a log message. */
+      if (non_interactive)
+        {
+          return svn_error_create
+            (SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
+             _("Cannot invoke editor to get log message "
+               "when non-interactive"));
+        }
+      else
+        {
+          SVN_ERR(svn_cmdline__edit_string_externally(
+                      &msg, NULL, NULL, "", msg, "svnmucc-commit", config,
+                      TRUE, NULL, apr_hash_pool_get(revprops)));
+        }
+
+      apr_hash_set(revprops, SVN_PROP_REVISION_LOG, APR_HASH_KEY_STRING, msg);
+    }
+
   SVN_ERR(create_ra_callbacks(&ra_callbacks, username, password, config_dir,
                               cfg_config, non_interactive, no_auth_cache,
                               pool));
@@ -899,37 +925,42 @@ static void
 usage(apr_pool_t *pool, int exit_val)
 {
   FILE *stream = exit_val == EXIT_SUCCESS ? stdout : stderr;
-  static const char *msg =
-    "Multiple URL Command Client (for Subversion)\n"
-    "\nUsage: svnmucc [OPTION]... [ACTION]...\n"
-    "\nActions:\n"
-    "  cp REV URL1 URL2      copy URL1@REV to URL2\n"
-    "  mkdir URL             create new directory URL\n"
-    "  mv URL1 URL2          move URL1 to URL2\n"
-    "  rm URL                delete URL\n"
-    "  put SRC-FILE URL      add or modify file URL with contents copied from\n"
-    "                        SRC-FILE (use \"-\" to read from standard input)\n"
-    "  propset NAME VAL URL  set property NAME on URL to value VAL\n"
-    "  propsetf NAME VAL URL set property NAME on URL to value from file VAL\n"
-    "  propdel NAME URL      delete property NAME from URL\n"
-    "\nOptions:\n"
-    "  -h, --help, -?        display this text\n"
-    "  -m, --message ARG     use ARG as a log message\n"
-    "  -F, --file ARG        read log message from file ARG\n"
-    "  -u, --username ARG    commit the changes as username ARG\n"
-    "  -p, --password ARG    use ARG as the password\n"
-    "  -U, --root-url ARG    interpret all action URLs are relative to ARG\n"
-    "  -r, --revision ARG    use revision ARG as baseline for changes\n"
-    "  --with-revprop A[=B]  set revision property A in new revision to B\n"
-    "                        if specified, else to the empty string\n"
-    "  -n, --non-interactive don't prompt the user about anything\n"
-    "  -X, --extra-args ARG  append arguments from file ARG (one per line;\n"
-    "                        use \"-\" to read from standard input)\n"
-    "  --config-dir ARG      use ARG to override the config directory\n"
-    "  --config-option ARG   use ARG to override a configuration option\n"
-    "  --no-auth-cache       do not cache authentication tokens\n"
-    "  --version             print version information\n";
-  svn_error_clear(svn_cmdline_fputs(msg, stream, pool));
+  svn_error_clear(svn_cmdline_fputs(
+    _("Subversion multiple URL command client\n"
+      "usage: svnmucc [OPTION]... [ACTION]...\n"
+      "\n"
+      "  Perform one or more Subversion repository URL-based ACTIONs, committing\n"
+      "  the result as a (single) new revision.\n"
+      "\n"
+      "Actions:\n"
+      "  cp REV URL1 URL2       : copy URL1@REV to URL2\n"
+      "  mkdir URL              : create new directory URL\n"
+      "  mv URL1 URL2           : move URL1 to URL2\n"
+      "  rm URL                 : delete URL\n"
+      "  put SRC-FILE URL       : add or modify file URL with contents copied from\n"
+      "                           SRC-FILE (use \"-\" to read from standard input)\n"
+      "  propset NAME VAL URL   : set property NAME on URL to value VAL\n"
+      "  propsetf NAME VAL URL  : set property NAME on URL to value from file VAL\n"
+      "  propdel NAME URL       : delete property NAME from URL\n"
+      "\n"
+      "Valid options:\n"
+      "  -h, -? [--help]        : display this text\n"
+      "  -m [--message] ARG     : use ARG as a log message\n"
+      "  -F [--file] ARG        : read log message from file ARG\n"
+      "  -u [--username] ARG    : commit the changes as username ARG\n"
+      "  -p [--password] ARG    : use ARG as the password\n"
+      "  -U [--root-url] ARG    : interpret all action URLs relative to ARG\n"
+      "  -r [--revision] ARG    : use revision ARG as baseline for changes\n"
+      "  --with-revprop ARG     : set revision property in the following format:\n"
+      "                               NAME[=VALUE]\n"
+      "  -n [--non-interactive] : don't prompt the user about anything\n"
+      "  -X [--extra-args] ARG  : append arguments from file ARG (one per line;\n"
+      "                         : use \"-\" to read from standard input)\n"
+      "  --config-dir ARG       : use ARG to override the config directory\n"
+      "  --config-option ARG    : use ARG to override a configuration option\n"
+      "  --no-auth-cache        : do not cache authentication tokens\n"
+      "  --version              : print version information\n"),
+                  stream, pool));
   apr_pool_destroy(pool);
   exit(exit_val);
 }
@@ -959,6 +990,53 @@ display_version(apr_getopt_t *os, apr_po
   return SVN_NO_ERROR;
 }
 
+/* Return an error about the mutual exclusivity of the -m, -F, and
+   --with-revprop=svn:log command-line options. */
+static svn_error_t *
+mutually_exclusive_logs_error(void)
+{
+  return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                          _("--message (-m), --file (-F), and "
+                            "--with-revprop=svn:log are mutually "
+                            "exclusive"));
+}
+
+/* Ensure that the REVPROPS hash contains a command-line-provided log
+   message, if any, and that there was but one source of such a thing
+   provided on that command-line.  */
+static svn_error_t *
+sanitize_log_sources(apr_hash_t *revprops,
+                     const char *message,
+                     svn_stringbuf_t *filedata)
+{
+  apr_pool_t *hash_pool = apr_hash_pool_get(revprops);
+
+  /* If we already have a log message in the revprop hash, then just
+     make sure the user didn't try to also use -m or -F.  Otherwise,
+     we need to consult -m or -F to find a log message, if any. */
+  if (apr_hash_get(revprops, SVN_PROP_REVISION_LOG, APR_HASH_KEY_STRING))
+    {
+      if (filedata || message)
+        return mutually_exclusive_logs_error();
+    }
+  else if (filedata)
+    {
+      if (message)
+        return mutually_exclusive_logs_error();
+
+      SVN_ERR(svn_utf_cstring_to_utf8(&message, filedata->data, hash_pool));
+      apr_hash_set(revprops, SVN_PROP_REVISION_LOG, APR_HASH_KEY_STRING,
+                   svn_stringbuf__morph_into_string(filedata));
+    }
+  else if (message)
+    {
+      apr_hash_set(revprops, SVN_PROP_REVISION_LOG, APR_HASH_KEY_STRING,
+                   svn_string_create(message, hash_pool));
+    }
+  
+  return SVN_NO_ERROR;
+}
+
 int
 main(int argc, const char **argv)
 {
@@ -994,6 +1072,7 @@ main(int argc, const char **argv)
     {NULL, 0, 0, NULL}
   };
   const char *message = NULL;
+  svn_stringbuf_t *filedata = NULL;
   const char *username = NULL, *password = NULL;
   const char *root_url = NULL, *extra_args_file = NULL;
   const char *config_dir = NULL;
@@ -1031,12 +1110,9 @@ main(int argc, const char **argv)
         case 'F':
           {
             const char *arg_utf8;
-            svn_stringbuf_t *contents;
             err = svn_utf_cstring_to_utf8(&arg_utf8, arg, pool);
             if (! err)
-              err = svn_stringbuf_from_file2(&contents, arg, pool);
-            if (! err)
-              err = svn_utf_cstring_to_utf8(&message, contents->data, pool);
+              err = svn_stringbuf_from_file2(&filedata, arg, pool);
             if (err)
               handle_error(err, pool);
           }
@@ -1109,6 +1185,11 @@ main(int argc, const char **argv)
         }
     }
 
+  /* Make sure we have a log message to use. */
+  err = sanitize_log_sources(revprops, message, filedata);
+  if (err)
+    handle_error(err, pool);
+
   /* Copy the rest of our command-line arguments to an array,
      UTF-8-ing them along the way. */
   action_args = apr_array_make(pool, opts->argc, sizeof(const char *));
@@ -1324,21 +1405,6 @@ main(int argc, const char **argv)
   if (! actions->nelts)
     usage(pool, EXIT_FAILURE);
 
-  if (message == NULL)
-    {
-      if (apr_hash_get(revprops, SVN_PROP_REVISION_LOG,
-                       APR_HASH_KEY_STRING) == NULL)
-        /* None of -F, -m, or --with-revprop=svn:log specified; default. */
-        apr_hash_set(revprops, SVN_PROP_REVISION_LOG, APR_HASH_KEY_STRING,
-                     svn_string_create("committed using svnmucc", pool));
-    }
-  else
-    {
-      /* -F or -m specified; use that even if --with-revprop=svn:log. */
-      apr_hash_set(revprops, SVN_PROP_REVISION_LOG, APR_HASH_KEY_STRING,
-                   svn_string_create(message, pool));
-    }
-
   if ((err = execute(actions, anchor, revprops, username, password,
                      config_dir, config_options, non_interactive,
                      no_auth_cache, base_revision, pool)))

Modified: subversion/branches/tweak-build-take-two/subversion/svnrdump/dump_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/svnrdump/dump_editor.c?rev=1425612&r1=1425611&r2=1425612&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/svnrdump/dump_editor.c (original)
+++ subversion/branches/tweak-build-take-two/subversion/svnrdump/dump_editor.c Mon Dec 24 09:49:03 2012
@@ -50,7 +50,8 @@ struct dir_baton
   struct dump_edit_baton *eb;
   struct dir_baton *parent_dir_baton;
 
-  apr_pool_t *pool; /* Directory pool */
+  /* Pool for per-directory allocations */
+  apr_pool_t *pool;
 
   /* is this directory a new addition to this revision? */
   svn_boolean_t added;
@@ -65,11 +66,21 @@ struct dir_baton
   const char *copyfrom_path; /* a relpath */
   svn_revnum_t copyfrom_rev;
 
+  /* 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;
+
+  /* Flags to trigger dumping props and record termination newlines. */
+  svn_boolean_t dump_props;
+  svn_boolean_t dump_newlines;
 };
 
 /* A file baton used by all file-related callback functions in the dump
@@ -79,11 +90,32 @@ struct file_baton
   struct dump_edit_baton *eb;
   struct dir_baton *parent_dir_baton;
 
+  /* 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;
 };
 
 /* A handler baton to be used in window_handler().  */
@@ -112,31 +144,20 @@ struct dump_edit_baton {
   /* Pool for per-revision allocations */
   apr_pool_t *pool;
 
-  /* Properties which were modified during change_file_prop
-   * or change_dir_prop. */
-  apr_hash_t *props;
-
-  /* Properties which were deleted during change_file_prop
-   * or change_dir_prop. */
-  apr_hash_t *deleted_props;
-
-  /* Temporary buffer to write property hashes to in human-readable
-   * form. ### Is this really needed? */
-  svn_stringbuf_t *propstring;
-
   /* 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;
 
-  /* Flags to trigger dumping props and text */
-  svn_boolean_t dump_text;
-  svn_boolean_t dump_props;
-  svn_boolean_t dump_newlines;
-
   /* The revision we're currently dumping. */
   svn_revnum_t current_revision;
+
+  /* The kind (file or directory) and baton of the item whose block of
+     dump stream data has not been fully completed; NULL if there's no
+     such item. */
+  svn_node_kind_t pending_kind;
+  void *pending_baton;
 };
 
 /* Make a directory baton to represent the directory at PATH (relative
@@ -147,21 +168,20 @@ struct dump_edit_baton {
  * information is valid, the directory will be compared against its
  * copy source.
  *
- * PARENT_DIR_BATON is the directory baton of this directory's parent,
- * or NULL if this is the top-level directory of the edit.  ADDED
- * indicates if this directory is newly added in this revision.
- * Perform all allocations in POOL.  */
+ * PB is the directory baton of this directory's parent, or NULL if
+ * this is the top-level directory of the edit.  ADDED indicates if
+ * this directory is newly added in this revision.  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,
-               void *parent_dir_baton,
+               struct dir_baton *pb,
                svn_boolean_t added,
                apr_pool_t *pool)
 {
   struct dump_edit_baton *eb = edit_baton;
-  struct dir_baton *pb = parent_dir_baton;
   struct dir_baton *new_db = apr_pcalloc(pool, sizeof(*new_db));
   const char *repos_relpath;
 
@@ -186,11 +206,38 @@ make_dir_baton(const char *path,
   new_db->copyfrom_rev = copyfrom_rev;
   new_db->added = added;
   new_db->written_out = FALSE;
+  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->parent_dir_baton = pb;
+  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;
+}
+
 /* Return in *HEADER and *CONTENT the headers and content for PROPS. */
 static svn_error_t *
 get_props_content(svn_stringbuf_t **header,
@@ -227,9 +274,13 @@ get_props_content(svn_stringbuf_t **head
   return SVN_NO_ERROR;
 }
 
-/* Extract and dump properties stored in edit baton EB, using POOL for
- * any temporary allocations. If TRIGGER_VAR is not NULL, it is set to FALSE.
- * Unless DUMP_DATA_TOO is set, only property headers are dumped.
+/* Extract and dump properties stored in PROPS and property deletions
+ * stored in DELETED_PROPS. If TRIGGER_VAR is not NULL, it is set to
+ * FALSE.
+ *
+ * If PROPSTRING is non-NULL, set *PROPSTRING to a string containing
+ * the content block of the property changes; otherwise, dump that to
+ * the stream, too.
  */
 static svn_error_t *
 do_dump_props(svn_stringbuf_t **propstring,
@@ -237,7 +288,6 @@ do_dump_props(svn_stringbuf_t **propstri
               apr_hash_t *props,
               apr_hash_t *deleted_props,
               svn_boolean_t *trigger_var,
-              svn_boolean_t dump_data_too,
               apr_pool_t *result_pool,
               apr_pool_t *scratch_pool)
 {
@@ -250,14 +300,14 @@ do_dump_props(svn_stringbuf_t **propstri
 
   SVN_ERR(get_props_content(&header, &content, props, deleted_props,
                             result_pool, scratch_pool));
-
-  /* This is a wacky side-effect of this function. */
-  *propstring = content;
-
   len = header->len;
   SVN_ERR(svn_stream_write(stream, header->data, &len));
 
-  if (dump_data_too)
+  if (propstring)
+    {
+      *propstring = content;
+    }
+  else
     {
       /* Content-length: 14 */
       SVN_ERR(svn_stream_printf(stream, scratch_pool,
@@ -309,7 +359,8 @@ do_dump_newlines(struct dump_edit_baton 
 static svn_error_t *
 dump_node(struct dump_edit_baton *eb,
           const char *repos_relpath,
-          svn_node_kind_t kind,
+          struct dir_baton *db,
+          struct file_baton *fb,
           enum svn_node_action action,
           svn_boolean_t is_copy,
           const char *copyfrom_path,
@@ -320,6 +371,7 @@ dump_node(struct dump_edit_baton *eb,
 
   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)
@@ -332,10 +384,10 @@ dump_node(struct dump_edit_baton *eb,
                             node_relpath));
 
   /* Node-kind: "file" | "dir" */
-  if (kind == svn_node_file)
+  if (fb)
     SVN_ERR(svn_stream_printf(eb->stream, pool,
                               SVN_REPOS_DUMPFILE_NODE_KIND ": file\n"));
-  else if (kind == svn_node_dir)
+  else if (db)
     SVN_ERR(svn_stream_printf(eb->stream, pool,
                               SVN_REPOS_DUMPFILE_NODE_KIND ": dir\n"));
 
@@ -358,9 +410,9 @@ dump_node(struct dump_edit_baton *eb,
         {
           /* Delete the original, and then re-add the replacement as a
              copy using recursive calls into this function. */
-          SVN_ERR(dump_node(eb, repos_relpath, kind, svn_node_action_delete,
+          SVN_ERR(dump_node(eb, repos_relpath, db, fb, svn_node_action_delete,
                             FALSE, NULL, SVN_INVALID_REVNUM, pool));
-          SVN_ERR(dump_node(eb, repos_relpath, kind, svn_node_action_add,
+          SVN_ERR(dump_node(eb, repos_relpath, db, fb, svn_node_action_add,
                             is_copy, copyfrom_path, copyfrom_rev, pool));
         }
       else
@@ -372,7 +424,10 @@ dump_node(struct dump_edit_baton *eb,
 
           /* Wait for a change_*_prop to be called before dumping
              anything */
-          eb->dump_props = TRUE;
+          if (fb)
+            fb->dump_props = TRUE;
+          else if (db)
+            db->dump_props = TRUE;
         }
       break;
 
@@ -410,16 +465,16 @@ dump_node(struct dump_edit_baton *eb,
              set DUMP_NEWLINES here to print the newlines unless
              change_dir_prop() is called next otherwise the `svnadmin load`
              parser will fail.  */
-          if (kind == svn_node_dir)
-            eb->dump_newlines = TRUE;
+          if (db)
+            db->dump_newlines = TRUE;
         }
       else
         {
-          /* eb->dump_props (for files) is handled in close_file()
+          /* 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; eb->dump_props (for directories)
+             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():
 
@@ -431,7 +486,10 @@ dump_node(struct dump_edit_baton *eb,
                - open_file()
 
              change_dir_prop() is a special case. */
-          eb->dump_props = TRUE;
+          if (fb)
+            fb->dump_props = TRUE;
+          else if (db)
+            db->dump_props = TRUE;
         }
 
       break;
@@ -483,21 +541,45 @@ dump_mkdir(struct dump_edit_baton *eb,
 /* Dump pending items from the specified node, to allow starting the dump
    of a child node */
 static svn_error_t *
-dump_pending(struct dir_baton *pb,
+dump_pending(struct dump_edit_baton *eb,
              apr_pool_t *scratch_pool)
 {
-  /* Some pending properties to dump? */
-  SVN_ERR(do_dump_props(&pb->eb->propstring, pb->eb->stream,
-                        pb->eb->props, pb->eb->deleted_props,
-                        &(pb->eb->dump_props), TRUE,
-                        pb->pool, scratch_pool));
+  if (! eb->pending_baton)
+    return SVN_NO_ERROR;
+
+  if (eb->pending_kind == svn_node_dir)
+    {
+      struct dir_baton *db = eb->pending_baton;
+
+      /* Some pending properties to dump? */
+      SVN_ERR(do_dump_props(NULL, eb->stream, db->props, db->deleted_props,
+                            &(db->dump_props), db->pool, scratch_pool));
+      
+      /* Some pending newlines to dump? */
+      SVN_ERR(do_dump_newlines(eb, &(db->dump_newlines), scratch_pool));
+    }
+  else if (eb->pending_kind == svn_node_file)
+    {
+      struct file_baton *fb = eb->pending_baton;
+
+      /* Some pending properties to dump? */
+      SVN_ERR(do_dump_props(NULL, eb->stream, fb->props, fb->deleted_props,
+                            &(fb->dump_props), fb->pool, scratch_pool));
+    }
+  else
+    abort();
 
-  /* Some pending newlines to dump? */
-  SVN_ERR(do_dump_newlines(pb->eb, &(pb->eb->dump_newlines), scratch_pool));
+  /* Anything that was pending is pending no longer. */
+  eb->pending_baton = NULL;
+  eb->pending_kind = svn_node_none;
 
   return SVN_NO_ERROR;
 }
 
+
+
+/*** Editor Function Implementations ***/
+
 static svn_error_t *
 open_root(void *edit_baton,
           svn_revnum_t base_revision,
@@ -510,10 +592,6 @@ open_root(void *edit_baton,
   /* Clear the per-revision pool after each revision */
   svn_pool_clear(eb->pool);
 
-  eb->props = apr_hash_make(eb->pool);
-  eb->deleted_props = apr_hash_make(eb->pool);
-  eb->propstring = svn_stringbuf_create_empty(eb->pool);
-
   LDR_DBG(("open_root %p\n", *root_baton));
 
   if (eb->update_anchor_relpath)
@@ -549,10 +627,15 @@ open_root(void *edit_baton,
                  to letting the typical plumbing handle this task. */
               new_db = make_dir_baton(NULL, NULL, SVN_INVALID_REVNUM,
                                       edit_baton, NULL, TRUE, pool);
-              SVN_ERR(dump_node(eb, new_db->repos_relpath, svn_node_dir,
-                                svn_node_action_add, FALSE, NULL, SVN_INVALID_REVNUM,
-                                pool));
+              SVN_ERR(dump_node(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. */
               new_db->written_out = TRUE;
+              eb->pending_baton = new_db;
+              eb->pending_kind = svn_node_dir;
             }
         }
       svn_pool_destroy(iterpool);
@@ -565,7 +648,6 @@ open_root(void *edit_baton,
     }
 
   *root_baton = new_db;
-    
   return SVN_NO_ERROR;
 }
 
@@ -579,10 +661,12 @@ delete_entry(const char *path,
 
   LDR_DBG(("delete_entry %s\n", path));
 
-  SVN_ERR(dump_pending(pb, pool));
+  SVN_ERR(dump_pending(pb->eb, pool));
 
-  /* Add this path to the deleted_entries of the parent directory
-     baton. */
+  /* 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().  */
   apr_hash_set(pb->deleted_entries, apr_pstrdup(pb->eb->pool, path),
                APR_HASH_KEY_STRING, pb);
 
@@ -604,11 +688,11 @@ add_directory(const char *path,
 
   LDR_DBG(("add_directory %s\n", path));
 
+  SVN_ERR(dump_pending(pb->eb, pool));
+
   new_db = make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb,
                           pb, TRUE, pb->eb->pool);
 
-  SVN_ERR(dump_pending(pb, pool));
-
   /* This might be a replacement -- is the path already deleted? */
   val = apr_hash_get(pb->deleted_entries, path, APR_HASH_KEY_STRING);
 
@@ -616,8 +700,7 @@ add_directory(const char *path,
   is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
 
   /* Dump the node */
-  SVN_ERR(dump_node(pb->eb, new_db->repos_relpath,
-                    svn_node_dir,
+  SVN_ERR(dump_node(pb->eb, new_db->repos_relpath, new_db, NULL,
                     val ? svn_node_action_replace : svn_node_action_add,
                     is_copy,
                     is_copy ? new_db->copyfrom_path : NULL,
@@ -628,7 +711,11 @@ add_directory(const char *path,
     /* Delete the path, it's now been dumped */
     apr_hash_set(pb->deleted_entries, path, APR_HASH_KEY_STRING, NULL);
 
+  /* Remember that we've started, but not yet finished handling this
+     directory. */
   new_db->written_out = TRUE;
+  pb->eb->pending_baton = new_db;
+  pb->eb->pending_kind = svn_node_dir;
 
   *child_baton = new_db;
   return SVN_NO_ERROR;
@@ -648,7 +735,7 @@ open_directory(const char *path,
 
   LDR_DBG(("open_directory %s\n", path));
 
-  SVN_ERR(dump_pending(pb, pool));
+  SVN_ERR(dump_pending(pb->eb, pool));
 
   /* If the parent directory has explicit comparison path and rev,
      record the same for this one. */
@@ -662,6 +749,7 @@ open_directory(const char *path,
 
   new_db = make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb, pb,
                           FALSE, pb->eb->pool);
+
   *child_baton = new_db;
   return SVN_NO_ERROR;
 }
@@ -672,10 +760,33 @@ close_directory(void *dir_baton,
 {
   struct dir_baton *db = dir_baton;
   apr_hash_index_t *hi;
+  svn_boolean_t this_pending;
 
   LDR_DBG(("close_directory %p\n", dir_baton));
 
-  SVN_ERR(dump_pending(db, pool));
+  /* Remember if this directory is the one currently pending. */
+  this_pending = (db->eb->pending_baton == db);
+
+  SVN_ERR(dump_pending(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->eb, db->repos_relpath, db, NULL,
+                        svn_node_action_change, FALSE,
+                        NULL, SVN_INVALID_REVNUM, pool));
+      db->eb->pending_baton = db;
+      db->eb->pending_kind = svn_node_dir;
+      SVN_ERR(dump_pending(db->eb, pool));
+    }
 
   /* Dump the deleted directory entries */
   for (hi = apr_hash_first(pool, db->deleted_entries); hi;
@@ -683,11 +794,13 @@ close_directory(void *dir_baton,
     {
       const char *path = svn__apr_hash_index_key(hi);
 
-      SVN_ERR(dump_node(db->eb, path, svn_node_unknown, svn_node_action_delete,
+      SVN_ERR(dump_node(db->eb, path, NULL, NULL, svn_node_action_delete,
                         FALSE, NULL, SVN_INVALID_REVNUM, pool));
     }
 
+  /* ### should be unnecessary */
   SVN_ERR(svn_hash__clear(db->deleted_entries, pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -700,42 +813,33 @@ add_file(const char *path,
          void **file_baton)
 {
   struct dir_baton *pb = parent_baton;
-  struct file_baton *fb = apr_pcalloc(pool, sizeof(*fb));
+  struct file_baton *fb;
   void *val;
-  svn_boolean_t is_copy;
-
-  fb->eb = pb->eb;
-  fb->parent_dir_baton = pb;
-  fb->repos_relpath = svn_relpath_canonicalize(path, pool);
 
   LDR_DBG(("add_file %s\n", path));
 
-  SVN_ERR(dump_pending(pb, pool));
+  SVN_ERR(dump_pending(pb->eb, pool));
 
+  /* Make the file baton. */
+  fb = make_file_baton(path, pb, pool);
+  
   /* This might be a replacement -- is the path already deleted? */
   val = apr_hash_get(pb->deleted_entries, path, APR_HASH_KEY_STRING);
 
   /* Detect add-with-history. */
-  is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
-
-  /* Dump the node. */
-  SVN_ERR(dump_node(pb->eb, fb->repos_relpath,
-                    svn_node_file,
-                    val ? svn_node_action_replace : svn_node_action_add,
-                    is_copy,
-                    is_copy ? svn_relpath_canonicalize(copyfrom_path, pool)
-                            : NULL,
-                    is_copy ? copyfrom_rev : SVN_INVALID_REVNUM,
-                    pool));
+  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 = val ? svn_node_action_replace : svn_node_action_add;
 
+  /* Delete the path, it's now been dumped. */
   if (val)
-    /* delete the path, it's now been dumped. */
     apr_hash_set(pb->deleted_entries, path, APR_HASH_KEY_STRING, NULL);
 
-  /* Build a nice file baton to pass to change_file_prop and
-     apply_textdelta */
   *file_baton = fb;
-
   return SVN_NO_ERROR;
 }
 
@@ -747,36 +851,26 @@ open_file(const char *path,
           void **file_baton)
 {
   struct dir_baton *pb = parent_baton;
-  struct file_baton *fb = apr_pcalloc(pool, sizeof(*fb));
-  const char *copyfrom_path = NULL;
-  svn_revnum_t copyfrom_rev = SVN_INVALID_REVNUM;
-
-  fb->eb = pb->eb;
-  fb->parent_dir_baton = pb;
-  fb->repos_relpath = svn_relpath_canonicalize(path, pool);
+  struct file_baton *fb;
 
   LDR_DBG(("open_file %s\n", path));
 
-  SVN_ERR(dump_pending(pb, pool));
+  SVN_ERR(dump_pending(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))
     {
-      copyfrom_path = svn_relpath_join(pb->copyfrom_path,
-                                       svn_relpath_basename(path, NULL),
-                                       pb->eb->pool);
-      copyfrom_rev = pb->copyfrom_rev;
+      fb->copyfrom_path = svn_relpath_join(pb->copyfrom_path,
+                                           svn_relpath_basename(path, NULL),
+                                           pb->eb->pool);
+      fb->copyfrom_rev = pb->copyfrom_rev;
     }
 
-  SVN_ERR(dump_node(pb->eb, fb->repos_relpath, svn_node_file,
-                    svn_node_action_change, FALSE, copyfrom_path,
-                    copyfrom_rev, pool));
-
-  /* Build a nice file baton to pass to change_file_prop and
-     apply_textdelta */
   *file_baton = fb;
-
   return SVN_NO_ERROR;
 }
 
@@ -787,37 +881,30 @@ change_dir_prop(void *parent_baton,
                 apr_pool_t *pool)
 {
   struct dir_baton *db = parent_baton;
-
+  svn_boolean_t this_pending;
+  
   LDR_DBG(("change_dir_prop %p\n", parent_baton));
 
+  /* This directory is not pending, but something else is, so handle
+     the "something else".  */
+  this_pending = (db->eb->pending_baton == db);
+  if (! this_pending)
+    SVN_ERR(dump_pending(db->eb, pool));
+
   if (svn_property_kind2(name) != svn_prop_regular_kind)
     return SVN_NO_ERROR;
 
   if (value)
-    apr_hash_set(db->eb->props, apr_pstrdup(db->eb->pool, name),
-                 APR_HASH_KEY_STRING, svn_string_dup(value, db->eb->pool));
+    apr_hash_set(db->props, apr_pstrdup(db->pool, name),
+                 APR_HASH_KEY_STRING, svn_string_dup(value, db->pool));
   else
-    apr_hash_set(db->eb->deleted_props, apr_pstrdup(db->eb->pool, name),
+    apr_hash_set(db->deleted_props, apr_pstrdup(db->pool, name),
                  APR_HASH_KEY_STRING, "");
 
-  if (! db->written_out)
-    {
-      /* If db->written_out is set, it means that the node information
-         corresponding to this directory has already been written: don't
-         do anything; do_dump_props() will take care of dumping the
-         props. If it not, dump the node itself before dumping the
-         props. */
-
-      SVN_ERR(dump_node(db->eb, db->repos_relpath, svn_node_dir,
-                        svn_node_action_change, FALSE, db->copyfrom_path,
-                        db->copyfrom_rev, pool));
-      db->written_out = TRUE;
-    }
-
   /* Make sure we eventually output the props, and disable printing
      a couple of extra newlines */
-  db->eb->dump_newlines = FALSE;
-  db->eb->dump_props = TRUE;
+  db->dump_newlines = FALSE;
+  db->dump_props = TRUE;
 
   return SVN_NO_ERROR;
 }
@@ -829,7 +916,6 @@ change_file_prop(void *file_baton,
                  apr_pool_t *pool)
 {
   struct file_baton *fb = file_baton;
-  struct dump_edit_baton *eb = fb->eb;
 
   LDR_DBG(("change_file_prop %p\n", file_baton));
 
@@ -837,16 +923,16 @@ change_file_prop(void *file_baton,
     return SVN_NO_ERROR;
 
   if (value)
-    apr_hash_set(eb->props, apr_pstrdup(eb->pool, name),
-                 APR_HASH_KEY_STRING, svn_string_dup(value, eb->pool));
+    apr_hash_set(fb->props, apr_pstrdup(fb->pool, name),
+                 APR_HASH_KEY_STRING, svn_string_dup(value, fb->pool));
   else
-    apr_hash_set(eb->deleted_props, apr_pstrdup(eb->pool, name),
+    apr_hash_set(fb->deleted_props, apr_pstrdup(fb->pool, name),
                  APR_HASH_KEY_STRING, "");
 
   /* Dump the property headers and wait; close_file might need
      to write text headers too depending on whether
      apply_textdelta is called */
-  eb->dump_props = TRUE;
+  fb->dump_props = TRUE;
 
   return SVN_NO_ERROR;
 }
@@ -875,15 +961,14 @@ apply_textdelta(void *file_baton, const 
 {
   struct file_baton *fb = file_baton;
   struct dump_edit_baton *eb = fb->eb;
-
-  /* Custom handler_baton allocated in a separate pool */
   struct handler_baton *hb;
   svn_stream_t *delta_filestream;
 
-  hb = apr_pcalloc(eb->pool, sizeof(*hb));
-
   LDR_DBG(("apply_textdelta %p\n", file_baton));
 
+  /* This is custom handler_baton, allocated from a separate pool.  */
+  hb = apr_pcalloc(eb->pool, sizeof(*hb));
+
   /* Use a temporary file to measure the Text-content-length */
   delta_filestream = svn_stream_from_aprfile2(eb->delta_file, TRUE, pool);
 
@@ -892,7 +977,8 @@ apply_textdelta(void *file_baton, const 
                           delta_filestream, 0,
                           SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, pool);
 
-  eb->dump_text = TRUE;
+  /* Record that there's text to be dumped, and its base checksum. */
+  fb->dump_text = TRUE;
   fb->base_checksum = apr_pstrdup(eb->pool, base_checksum);
 
   /* The actual writing takes place when this function has
@@ -912,17 +998,25 @@ close_file(void *file_baton,
   struct file_baton *fb = file_baton;
   struct dump_edit_baton *eb = fb->eb;
   apr_finfo_t *info = apr_pcalloc(pool, sizeof(apr_finfo_t));
-
+  svn_stringbuf_t *propstring;
+  
   LDR_DBG(("close_file %p\n", file_baton));
 
-  /* Some pending properties to dump? Dump just the headers- dump the
-     props only after dumping the text headers too (if present) */
-  SVN_ERR(do_dump_props(&eb->propstring, eb->stream,
-                        eb->props, eb->deleted_props,
-                        &(eb->dump_props), FALSE, pool, pool));
+  SVN_ERR(dump_pending(eb, pool));
+
+  /* Dump the node. */
+  SVN_ERR(dump_node(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). */
+  SVN_ERR(do_dump_props(&propstring, eb->stream, fb->props, fb->deleted_props,
+                        &(fb->dump_props), pool, pool));
 
   /* Dump the text headers */
-  if (eb->dump_text)
+  if (fb->dump_text)
     {
       apr_status_t err;
 
@@ -957,31 +1051,31 @@ close_file(void *file_baton,
 
   /* Content-length: 1549 */
   /* If both text and props are absent, skip this header */
-  if (eb->dump_props)
+  if (fb->dump_props)
     SVN_ERR(svn_stream_printf(eb->stream, pool,
                               SVN_REPOS_DUMPFILE_CONTENT_LENGTH
                               ": %ld\n\n",
-                              (unsigned long)info->size + eb->propstring->len));
-  else if (eb->dump_text)
+                              (unsigned long)info->size + propstring->len));
+  else if (fb->dump_text)
     SVN_ERR(svn_stream_printf(eb->stream, pool,
                               SVN_REPOS_DUMPFILE_CONTENT_LENGTH
                               ": %ld\n\n",
                               (unsigned long)info->size));
 
   /* Dump the props now */
-  if (eb->dump_props)
+  if (fb->dump_props)
     {
-      SVN_ERR(svn_stream_write(eb->stream, eb->propstring->data,
-                               &(eb->propstring->len)));
+      SVN_ERR(svn_stream_write(eb->stream, propstring->data,
+                               &(propstring->len)));
 
       /* Cleanup */
-      eb->dump_props = FALSE;
-      SVN_ERR(svn_hash__clear(eb->props, eb->pool));
-      SVN_ERR(svn_hash__clear(eb->deleted_props, eb->pool));
+      fb->dump_props = FALSE;
+      SVN_ERR(svn_hash__clear(fb->props, fb->pool));
+      SVN_ERR(svn_hash__clear(fb->deleted_props, fb->pool));
     }
 
   /* Dump the text */
-  if (eb->dump_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
@@ -998,7 +1092,6 @@ close_file(void *file_baton,
       /* Cleanup */
       SVN_ERR(svn_stream_close(delta_filestream));
       SVN_ERR(svn_io_file_trunc(eb->delta_file, 0, pool));
-      eb->dump_text = FALSE;
     }
 
   /* Write a couple of blank lines for matching output with `svnadmin
@@ -1143,6 +1236,7 @@ svn_rdump__get_dump_editor(const svn_del
   eb->ra_session = ra_session;
   eb->update_anchor_relpath = update_anchor_relpath;
   eb->current_revision = revision;
+  eb->pending_kind = svn_node_none;
 
   /* Create a special per-revision pool */
   eb->pool = svn_pool_create(pool);

Modified: subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_authz_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_authz_tests.py?rev=1425612&r1=1425611&r2=1425612&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_authz_tests.py (original)
+++ subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_authz_tests.py Mon Dec 24 09:49:03 2012
@@ -256,8 +256,9 @@ def mergeinfo_and_skipped_paths(sbox):
     'C'         : Item(),
     })
   expected_skip = wc.State(A_COPY_2_path, {
-    'B/E'     : Item(),
-    'D/H/psi'   : Item(),
+    'B/E'              : Item(),
+    'D/G/rho'          : Item(),
+    'D/H/psi'          : Item(),
     })
   svntest.actions.run_and_verify_merge(A_COPY_2_path, '4', '8',
                                        sbox.repo_url + '/A', None,

Modified: subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_reintegrate_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_reintegrate_tests.py?rev=1425612&r1=1425611&r2=1425612&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_reintegrate_tests.py (original)
+++ subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_reintegrate_tests.py Mon Dec 24 09:49:03 2012
@@ -825,6 +825,18 @@ def reintegrate_on_shallow_wc(sbox):
                        'Some more work on the A_COPY branch', wc_dir)
   # Reuse the same expectations as the prior merge, except for the mergeinfo
   # on the target root that now includes the latest rev on the branch.
+  expected_mergeinfo_output.add({
+      'D' : Item(status=' U')
+      })
+  expected_A_status.tweak('D', status=' M')
+  expected_A_disk.tweak('D', props={SVN_PROP_MERGEINFO : '/A_COPY/D:2-4*'})
+  # ... a depth-restricted item is skipped ...
+  expected_A_skip.add({
+      'D/H/psi' : Item()
+  })
+  # Currently this fails due to r1424469.  For a full explanation see
+  # http://svn.haxx.se/dev/archive-2012-12/0472.shtml
+  # and http://svn.haxx.se/dev/archive-2012-12/0475.shtml
   expected_A_disk.tweak('', props={SVN_PROP_MERGEINFO : '/A_COPY:2-4'})
   svntest.actions.run_and_verify_merge(A_path, None, None,
                                        sbox.repo_url + '/A_COPY', None,

Modified: subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_tests.py?rev=1425612&r1=1425611&r2=1425612&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_tests.py Mon Dec 24 09:49:03 2012
@@ -7812,10 +7812,14 @@ def merge_to_sparse_directories(sbox):
   # Merge r4:9 into the immediates WC.
   # The root of the immediates WC should get inheritable r4:9 as should
   # the one file present 'mu'.  The three directory children present, 'B',
-  # 'C', and 'D' are checked out at depth empty; the one of these affected
-  # by the merge, 'D', gets non-inheritable mergeinfo for r4:9.
+  # 'C', and 'D' are checked out at depth empty; the two of these affected
+  # by the merge, 'B' and 'D', get non-inheritable mergeinfo for r4:9.
   # The root and 'D' do should also get the changes
   # that affect them directly (the prop adds from r8 and r9).
+  #
+  # Currently this fails due to r1424469.  For a full explanation see
+  # http://svn.haxx.se/dev/archive-2012-12/0472.shtml
+  # and http://svn.haxx.se/dev/archive-2012-12/0475.shtml
   expected_output = wc.State(immediates_dir, {
     'D'   : Item(status=' U'),
     'mu'  : Item(status='U '),
@@ -7823,14 +7827,14 @@ def merge_to_sparse_directories(sbox):
     })
   expected_mergeinfo_output = wc.State(immediates_dir, {
     ''  : Item(status=' U'),
+    'B' : Item(status=' U'),
     'D' : Item(status=' U'),
     })
   expected_elision_output = wc.State(immediates_dir, {
-    'D' : Item(status=' U'),
     })
   expected_status = wc.State(immediates_dir, {
     ''          : Item(status=' M', wc_rev=9),
-    'B'         : Item(status='  ', wc_rev=9),
+    'B'         : Item(status=' M', wc_rev=9),
     'mu'        : Item(status='M ', wc_rev=9),
     'C'         : Item(status='  ', wc_rev=9),
     'D'         : Item(status=' M', wc_rev=9),
@@ -7838,12 +7842,15 @@ def merge_to_sparse_directories(sbox):
   expected_disk = wc.State('', {
     ''          : Item(props={SVN_PROP_MERGEINFO : '/A:5-9',
                               "prop:name" : "propval"}),
-    'B'         : Item(),
+    'B'         : Item(props={SVN_PROP_MERGEINFO : '/A/B:5-9*'}),
     'mu'        : Item("New content"),
     'C'         : Item(),
-    'D'         : Item(props={"prop:name" : "propval"}),
+    'D'         : Item(props={SVN_PROP_MERGEINFO : '/A/D:5-9*',
+                              "prop:name" : "propval"}),
     })
   expected_skip = svntest.wc.State(immediates_dir, {
+    'D/H/omega'         : Item(),
+    'B/E/beta'          : Item(),
     })
   svntest.actions.run_and_verify_merge(immediates_dir, '4', '9',
                                        sbox.repo_url + '/A', None,
@@ -7896,7 +7903,8 @@ def merge_to_sparse_directories(sbox):
                        props={SVN_PROP_MERGEINFO : '/A/mu:5-9'}),
     })
   expected_skip = svntest.wc.State(files_dir, {
-    'D'               : Item(),
+    'D/H/omega'       : Item(),
+    'B/E/beta'        : Item(),
     })
   svntest.actions.run_and_verify_merge(files_dir, '4', '9',
                                        sbox.repo_url + '/A', None,
@@ -7939,7 +7947,8 @@ def merge_to_sparse_directories(sbox):
     })
   expected_skip = svntest.wc.State(empty_dir, {
     'mu'               : Item(),
-    'D'               : Item(),
+    'D/H/omega'        : Item(),
+    'B/E/beta'         : Item(),
     })
   svntest.actions.run_and_verify_merge(empty_dir, '4', '9',
                                        sbox.repo_url + '/A', None,

Modified: subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_tree_conflict_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_tree_conflict_tests.py?rev=1425612&r1=1425611&r2=1425612&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_tree_conflict_tests.py (original)
+++ subversion/branches/tweak-build-take-two/subversion/tests/cmdline/merge_tree_conflict_tests.py Mon Dec 24 09:49:03 2012
@@ -1331,12 +1331,19 @@ def tree_conflicts_merge_edit_onto_missi
 
   expected_skip = svntest.wc.State('', {
     'F/alpha'           : Item(),
-    # BH: After fixing several issues in the obstruction handling
-    #     I get the following Skip notification. Please review!
+    # Obstruction handling improvements in 1.7 and 1.8 added
+    'DF/D1/beta'        : Item(),
+    'DDD/D1/D2/D3/zeta' : Item(),
+    'DDD/D1/D2/D3'      : Item(),
+    'DDF/D1/D2/gamma'   : Item(),
+    'D/D1/delta'        : Item(),
     'D/D1'              : Item(),
+    'DD/D1/D2/epsilon'  : Item(),
+    'DD/D1/D2'          : Item(),
     })
 
-
+  # Currently this test fails because some parts of the merge
+  # start succeeding. 
   svntest.actions.deep_trees_run_tests_scheme_for_merge(sbox,
     [ DeepTreesTestCase(
                "local_tree_missing_incoming_leaf_edit",
@@ -1410,6 +1417,12 @@ def tree_conflicts_merge_del_onto_missin
   expected_skip = svntest.wc.State('', {
     'F/alpha'           : Item(),
     'D/D1'              : Item(),
+    # Obstruction handling improvements in 1.7 and 1.8 added
+    'D/D1'              : Item(),
+    'DD/D1/D2'          : Item(),
+    'DF/D1/beta'        : Item(),
+    'DDD/D1/D2/D3'      : Item(),
+    'DDF/D1/D2/gamma'   : Item(),
     })
 
   svntest.actions.deep_trees_run_tests_scheme_for_merge(sbox,

Modified: subversion/branches/tweak-build-take-two/subversion/tests/cmdline/svnmucc_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/tests/cmdline/svnmucc_tests.py?rev=1425612&r1=1425611&r2=1425612&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/tests/cmdline/svnmucc_tests.py (original)
+++ subversion/branches/tweak-build-take-two/subversion/tests/cmdline/svnmucc_tests.py Mon Dec 24 09:49:03 2012
@@ -45,6 +45,7 @@ def reject_bogus_mergeinfo(sbox):
   # validate the mergeinfo up front then it will only test the client
   svntest.actions.run_and_verify_svnmucc(None, [], expected_error,
                                          'propset', 'svn:mergeinfo', '/B:0',
+                                         '-m', 'log msg',
                                          sbox.repo_url + '/A')
 
 _svnmucc_re = re.compile('^(r[0-9]+) committed by jrandom at (.*)$')
@@ -111,12 +112,14 @@ def basic_svnmucc(sbox):
   test_svnmucc(sbox.repo_url,
                ['A /foo'
                 ], # ---------
+               '-m', 'log msg',
                'mkdir', 'foo')
 
   # revision 3
   test_svnmucc(sbox.repo_url,
                ['A /z.c',
                 ], # ---------
+               '-m', 'log msg',
                'put', empty_file, 'z.c')
 
   # revision 4
@@ -124,6 +127,7 @@ def basic_svnmucc(sbox):
                ['A /foo/z.c (from /z.c:3)',
                 'A /foo/bar (from /foo:3)',
                 ], # ---------
+               '-m', 'log msg',
                'cp', '3', 'z.c', 'foo/z.c',
                'cp', '3', 'foo', 'foo/bar')
 
@@ -134,6 +138,7 @@ def basic_svnmucc(sbox):
                 'D /foo',
                 'A /zig/zag (from /foo:4)',
                 ], # ---------
+               '-m', 'log msg',
                'cp', '4', 'foo', 'zig',
                'rm',             'zig/bar',
                'mv',      'foo', 'zig/zag')
@@ -144,6 +149,7 @@ def basic_svnmucc(sbox):
                 'A /zig/zag/bar/y.c (from /z.c:5)',
                 'A /zig/zag/bar/x.c (from /z.c:3)',
                 ], # ---------
+               '-m', 'log msg',
                'mv',      'z.c', 'zig/zag/bar/y.c',
                'cp', '3', 'z.c', 'zig/zag/bar/x.c')
 
@@ -153,6 +159,7 @@ def basic_svnmucc(sbox):
                 'A /zig/zag/bar/y y.c (from /zig/zag/bar/y.c:6)',
                 'A /zig/zag/bar/y%20y.c (from /zig/zag/bar/y.c:6)',
                 ], # ---------
+               '-m', 'log msg',
                'mv',         'zig/zag/bar/y.c', 'zig/zag/bar/y%20y.c',
                'cp', 'HEAD', 'zig/zag/bar/y.c', 'zig/zag/bar/y%2520y.c')
 
@@ -163,6 +170,7 @@ def basic_svnmucc(sbox):
                 'A /zig/zag/bar/z%20z.c (from /zig/zag/bar/y%20y.c:7)',
                 'A /zig/zag/bar/z z2.c (from /zig/zag/bar/y y.c:7)',
                 ], #---------
+               '-m', 'log msg',
                'mv',         'zig/zag/bar/y%20y.c',   'zig/zag/bar/z z1.c',
                'cp', 'HEAD', 'zig/zag/bar/y%2520y.c', 'zig/zag/bar/z%2520z.c',
                'cp', 'HEAD', 'zig/zag/bar/y y.c',     'zig/zag/bar/z z2.c')
@@ -176,6 +184,7 @@ def basic_svnmucc(sbox):
                 'D /zig/foo/bar/z z2.c',
                 'R /zig/foo/bar/z z1.c (from /zig/zag/bar/x.c:6)',
                 ], #---------
+               '-m', 'log msg',
                'mv',      'zig/zag',         'zig/foo',
                'rm',                         'zig/foo/bar/z z1.c',
                'rm',                         'zig/foo/bar/z%20z2.c',
@@ -186,6 +195,7 @@ def basic_svnmucc(sbox):
   test_svnmucc(sbox.repo_url,
                ['R /zig/foo/bar (from /zig/z.c:9)',
                 ], #---------
+               '-m', 'log msg',
                'rm',                 'zig/foo/bar',
                'cp', '9', 'zig/z.c', 'zig/foo/bar')
 
@@ -194,6 +204,7 @@ def basic_svnmucc(sbox):
                ['R /zig/foo/bar (from /zig/foo/bar:9)',
                 'D /zig/foo/bar/z z1.c',
                 ], #---------
+               '-m', 'log msg',
                'rm',                     'zig/foo/bar',
                'cp', '9', 'zig/foo/bar', 'zig/foo/bar',
                'rm',                     'zig/foo/bar/z%20z1.c')
@@ -202,6 +213,7 @@ def basic_svnmucc(sbox):
   test_svnmucc(sbox.repo_url,
                ['R /zig/foo (from /zig/foo/bar:11)',
                 ], #---------
+               '-m', 'log msg',
                'rm',                        'zig/foo',
                'cp', 'head', 'zig/foo/bar', 'zig/foo')
 
@@ -214,6 +226,7 @@ def basic_svnmucc(sbox):
                 'D /foo/foo/bar',
                 'R /foo/foo/foo/bar (from /foo:4)',
                 ], #---------
+               '-m', 'log msg',
                'rm',             'zig',
                'cp', '4', 'foo', 'foo',
                'cp', '4', 'foo', 'foo/foo',
@@ -228,6 +241,7 @@ def basic_svnmucc(sbox):
                 'A /boozle/buz',
                 'A /boozle/buz/nuz',
                 ], #---------
+               '-m', 'log msg',
                'cp',    '4', 'foo', 'boozle',
                'mkdir',             'boozle/buz',
                'mkdir',             'boozle/buz/nuz')
@@ -238,6 +252,7 @@ def basic_svnmucc(sbox):
                 'A /boozle/guz (from /boozle/buz:14)',
                 'A /boozle/guz/svnmucc-test.py',
                 ], #---------
+               '-m', 'log msg',
                'put',      empty_file,   'boozle/buz/svnmucc-test.py',
                'cp', '14', 'boozle/buz', 'boozle/guz',
                'put',      empty_file,   'boozle/guz/svnmucc-test.py')
@@ -247,20 +262,25 @@ def basic_svnmucc(sbox):
                ['M /boozle/buz/svnmucc-test.py',
                 'R /boozle/guz/svnmucc-test.py',
                 ], #---------
+               '-m', 'log msg',
                'put', empty_file, 'boozle/buz/svnmucc-test.py',
                'rm',              'boozle/guz/svnmucc-test.py',
                'put', empty_file, 'boozle/guz/svnmucc-test.py')
 
   # revision 17
   test_svnmucc(sbox.repo_url,
-               ['R /foo/bar (from /foo/foo:16)'], #---------
+               ['R /foo/bar (from /foo/foo:16)'
+                ], #---------
+               '-m', 'log msg',
                'rm',                            'foo/bar',
                'cp', '16', 'foo/foo',           'foo/bar',
                'propset',  'testprop',  'true', 'foo/bar')
 
   # revision 18
   test_svnmucc(sbox.repo_url,
-               ['M /foo/bar'], #---------
+               ['M /foo/bar'
+                ], #---------
+               '-m', 'log msg',
                'propdel', 'testprop', 'foo/bar')
 
   # revision 19
@@ -268,6 +288,7 @@ def basic_svnmucc(sbox):
                ['M /foo/z.c',
                 'M /foo/foo',
                 ], #---------
+               '-m', 'log msg',
                'propset', 'testprop', 'true', 'foo/z.c',
                'propset', 'testprop', 'true', 'foo/foo')
 
@@ -276,6 +297,7 @@ def basic_svnmucc(sbox):
                ['M /foo/z.c',
                 'M /foo/foo',
                 ], #---------
+               '-m', 'log msg',
                'propsetf', 'testprop', empty_file, 'foo/z.c',
                'propsetf', 'testprop', empty_file, 'foo/foo')
 
@@ -283,6 +305,7 @@ def basic_svnmucc(sbox):
   xtest_svnmucc(sbox.repo_url,
                 ["svnmucc: E200004: 'a' is not a revision"
                  ], #---------
+                '-m', 'log msg',
                 'cp', 'a', 'b')
 
   # Expected cannot be younger error
@@ -290,18 +313,21 @@ def basic_svnmucc(sbox):
                 ['svnmucc: E205000: Copy source revision cannot be younger ' +
                  'than base revision',
                  ], #---------
+                '-m', 'log msg',
                 'cp', '42', 'a', 'b')
 
   # Expected already exists error
   xtest_svnmucc(sbox.repo_url,
                 ["svnmucc: E125002: 'foo' already exists",
                  ], #---------
+                '-m', 'log msg',
                 'cp', '17', 'a', 'foo')
 
   # Expected copy_src already exists error
   xtest_svnmucc(sbox.repo_url,
                 ["svnmucc: E125002: 'a/bar' (from 'foo/bar:17') already exists",
                  ], #---------
+                '-m', 'log msg',
                 'cp', '17', 'foo', 'a',
                 'cp', '17', 'foo/foo', 'a/bar')
 
@@ -309,12 +335,14 @@ def basic_svnmucc(sbox):
   xtest_svnmucc(sbox.repo_url,
                 ["svnmucc: E125002: 'a' not found",
                  ], #---------
+                '-m', 'log msg',
                 'cp', '17', 'a', 'b')
 
 
 def propset_root_internal(sbox, target):
   ## propset on ^/
   svntest.actions.run_and_verify_svnmucc(None, None, [],
+                                         '-m', 'log msg',
                                          'propset', 'foo', 'bar',
                                          target)
   svntest.actions.run_and_verify_svn(None, 'bar', [],
@@ -323,6 +351,7 @@ def propset_root_internal(sbox, target):
 
   ## propdel on ^/
   svntest.actions.run_and_verify_svnmucc(None, None, [],
+                                         '-m', 'log msg',
                                          'propdel', 'foo',
                                          target)
   svntest.actions.run_and_verify_svn(None, [], [],
@@ -338,12 +367,58 @@ def propset_root(sbox):
   propset_root_internal(sbox, sbox.repo_url + '/iota')
 
 
+def too_many_log_messages(sbox):
+  "test log message mutual exclusivity checks"
+
+  sbox.build() # would use read-only=True, but need a place to stuff msg_file
+  msg_file = sbox.ospath('svnmucc_msg')
+  svntest.main.file_append(msg_file, 'some log message')
+  err_msg = ["svnmucc: E205000: --message (-m), --file (-F), and "
+             "--with-revprop=svn:log are mutually exclusive"]
+             
+  xtest_svnmucc(sbox.repo_url, err_msg,
+                '--non-interactive',
+                '-m', 'log msg',
+                '-F', msg_file,
+                'mkdir', 'A/subdir')
+  xtest_svnmucc(sbox.repo_url, err_msg,
+                '--non-interactive',
+                '-m', 'log msg',
+                '--with-revprop', 'svn:log=proppy log message',
+                'mkdir', 'A/subdir')
+  xtest_svnmucc(sbox.repo_url, err_msg,
+                '--non-interactive',
+                '-F', msg_file,
+                '--with-revprop', 'svn:log=proppy log message',
+                'mkdir', 'A/subdir')
+  xtest_svnmucc(sbox.repo_url, err_msg,
+                '--non-interactive',
+                '-m', 'log msg',
+                '-F', msg_file,
+                '--with-revprop', 'svn:log=proppy log message',
+                'mkdir', 'A/subdir')
+  
+@Issues(3418)
+def no_log_msg_non_interactive(sbox):
+  "test non-interactive without a log message"
+  
+  sbox.build(create_wc=False)
+  xtest_svnmucc(sbox.repo_url,
+                ["svnmucc: E205001: Cannot invoke editor to get log message "
+                 "when non-interactive"
+                 ], #---------
+                '--non-interactive',
+                'mkdir', 'A/subdir')
+  
+
 ######################################################################
 
 test_list = [ None,
               reject_bogus_mergeinfo,
               basic_svnmucc,
               propset_root,
+              too_many_log_messages,
+              no_log_msg_non_interactive,
             ]
 
 if __name__ == '__main__':

Modified: subversion/branches/tweak-build-take-two/subversion/tests/cmdline/svntest/main.py
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/tests/cmdline/svntest/main.py?rev=1425612&r1=1425611&r2=1425612&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/tests/cmdline/svntest/main.py (original)
+++ subversion/branches/tweak-build-take-two/subversion/tests/cmdline/svntest/main.py Mon Dec 24 09:49:03 2012
@@ -651,13 +651,6 @@ def _with_auth(args):
   else:
     return args + ('--username', wc_author )
 
-def _with_log_message(args):
-
-  if '-m' in args or '--message' in args or '-F' in args:
-    return args
-  else:
-    return args + ('--message', 'default log message')
-
 # For running subversion and returning the output
 def run_svn(error_expected, *varargs):
   """Run svn with VARARGS; return exit code as int; stdout, stderr as
@@ -705,7 +698,7 @@ def run_svnmucc(*varargs):
   """Run svnmucc with VARARGS, returns exit code as int; stdout, stderr as
   list of lines (including line terminators).  Use binary mode for output."""
   return run_command(svnmucc_binary, 1, 1,
-                     *(_with_auth(_with_config_dir(_with_log_message(varargs)))))
+                     *(_with_auth(_with_config_dir(varargs))))
 
 def run_entriesdump(path):
   """Run the entries-dump helper, returning a dict of Entry objects."""

Modified: subversion/branches/tweak-build-take-two/subversion/tests/cmdline/update_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/tests/cmdline/update_tests.py?rev=1425612&r1=1425611&r2=1425612&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/tests/cmdline/update_tests.py (original)
+++ subversion/branches/tweak-build-take-two/subversion/tests/cmdline/update_tests.py Mon Dec 24 09:49:03 2012
@@ -5653,7 +5653,6 @@ def update_moved_dir_file_add(sbox):
                                         None, None, None,
                                         None, None, 1)
 
-@XFail()
 def update_moved_dir_dir_add(sbox):
   "update locally moved dir with incoming dir"
   sbox.build()
@@ -5672,8 +5671,9 @@ def update_moved_dir_dir_add(sbox):
 
   # the incoming file should auto-merge
   expected_output = svntest.wc.State(wc_dir, {
-    'A/B/E2/foo'      : Item(status='A '),
-    'A/B/E2/foo/bar'  : Item(status='A '),
+      'A/B/E'         : Item(status='  ', treeconflict='C'),
+      'A/B/E/foo'     : Item(status='  ', treeconflict='A'),
+      'A/B/E/foo/bar' : Item(status='  ', treeconflict='A'),
   })
   expected_disk = svntest.main.greek_state.copy()
   expected_disk.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E')
@@ -5681,19 +5681,16 @@ def update_moved_dir_dir_add(sbox):
     'A/B/E2'           : Item(),
     'A/B/E2/alpha'     : Item(contents="This is the file 'alpha'.\n"),
     'A/B/E2/beta'      : Item(contents="This is the file 'beta'.\n"),
-    'A/B/E2/foo'       : Item(),
-    'A/B/E2/foo/bar'   : Item(contents=bar_content),
   })
   expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
   expected_status.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta', status='D ')
+  expected_status.tweak('A/B/E', treeconflict='C')
   expected_status.add({
     'A/B/E/foo'         : Item(status='D ', wc_rev='2'),
     'A/B/E/foo/bar'     : Item(status='D ', wc_rev='2'),
     'A/B/E2'            : Item(status='A ', copied='+', wc_rev='-'),
     'A/B/E2/beta'       : Item(status='  ', copied='+', wc_rev='-'),
     'A/B/E2/alpha'      : Item(status='  ', copied='+', wc_rev='-'),
-    'A/B/E2/foo'        : Item(status='A ', copied='+', wc_rev='-'),
-    'A/B/E2/foo/bar'    : Item(status='A ', copied='+', wc_rev='-'),
   })
   svntest.actions.run_and_verify_update(wc_dir,
                                         expected_output,
@@ -5701,6 +5698,16 @@ def update_moved_dir_dir_add(sbox):
                                         expected_status,
                                         None, None, None,
                                         None, None, 1)
+  svntest.actions.run_and_verify_svn("resolve failed", None, [],
+                                     'resolve',
+                                     '--recursive',
+                                     '--accept=mine-conflict', wc_dir)
+  expected_status.tweak(treeconflict=None)
+  expected_status.add({
+    'A/B/E2/foo'        : Item(status='  ', copied='+', wc_rev='-'),
+    'A/B/E2/foo/bar'    : Item(status='  ', copied='+', wc_rev='-'),
+  })
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
 @XFail()
 @Issue(4037)

Modified: subversion/branches/tweak-build-take-two/subversion/tests/cmdline/upgrade_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/tests/cmdline/upgrade_tests.py?rev=1425612&r1=1425611&r2=1425612&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/tests/cmdline/upgrade_tests.py (original)
+++ subversion/branches/tweak-build-take-two/subversion/tests/cmdline/upgrade_tests.py Mon Dec 24 09:49:03 2012
@@ -1143,18 +1143,21 @@ def upgrade_file_externals(sbox):
 
   expected_output = svntest.verify.RegexOutput('r2 committed.*')
   svntest.actions.run_and_verify_svnmucc(None, expected_output, [],
+                                         '-m', 'r2',
                                          'propset', 'svn:externals',
                                          '^/A/B/E EX\n^/A/mu muX',
                                          sbox.repo_url + '/A/B/F')
 
   expected_output = svntest.verify.RegexOutput('r3 committed.*')
   svntest.actions.run_and_verify_svnmucc(None, expected_output, [],
+                                         '-m', 'r3',
                                          'propset', 'svn:externals',
                                          '^/A/B/F FX\n^/A/B/lambda lambdaX',
                                          sbox.repo_url + '/A/C')
 
   expected_output = svntest.verify.RegexOutput('r4 committed.*')
   svntest.actions.run_and_verify_svnmucc(None, expected_output, [],
+                                         '-m', 'r4',
                                          'propset', 'pname1', 'pvalue1',
                                          sbox.repo_url + '/A/mu',
                                          'propset', 'pname2', 'pvalue2',

Modified: subversion/branches/tweak-build-take-two/subversion/tests/libsvn_repos/repos-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/tweak-build-take-two/subversion/tests/libsvn_repos/repos-test.c?rev=1425612&r1=1425611&r2=1425612&view=diff
==============================================================================
--- subversion/branches/tweak-build-take-two/subversion/tests/libsvn_repos/repos-test.c (original)
+++ subversion/branches/tweak-build-take-two/subversion/tests/libsvn_repos/repos-test.c Mon Dec 24 09:49:03 2012
@@ -1212,7 +1212,7 @@ authz(apr_pool_t *pool)
   svn_error_t *err;
   svn_boolean_t access_granted;
   apr_pool_t *subpool = svn_pool_create(pool);
-  int i;
+
   /* Definition of the paths to test and expected replies for each. */
   struct check_access_tests test_set[] = {
     /* Test that read rules are correctly used. */