subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cmpil...@apache.org
Subject svn commit: r1425125 - in /subversion/trunk/subversion: include/private/svn_cmdline_private.h libsvn_subr/cmdline.c svn/cl.h svn/conflict-callbacks.c svn/file-merge.c svn/propedit-cmd.c svn/util.c
Date Fri, 21 Dec 2012 20:14:27 GMT
Author: cmpilato
Date: Fri Dec 21 20:14:27 2012
New Revision: 1425125

URL: http://svn.apache.org/viewvc?rev=1425125&view=rev
Log:
Move some fairly useful utility functions from the command-line client
to libsvn_subr, exposing as private svn_cmdline__ APIs.

* subversion/include/private/svn_cmdline_private.h
  (svn_cmdline__edit_file_externally,
   svn_cmdline__edit_string_externally): Rename and move here ...

* subversion/svn/cl.h
  (svn_cl__edit_file_externally, svn_cl__edit_string_externally):
     ... from here.  Callers updated.

* subversion/libsvn_subr/cmdline.c
  (find_editor_binary, svn_cmdline__edit_file_externally,
   svn_cmdline__edit_string_externally): Rename and move here ...

* subversion/svn/util.c
  (find_editor_binary, svn_cl__edit_file_externally,
   svn_cl__edit_string_externally): ... from here.  Callers updated.

* subversion/svn/conflict-callbacks.c,
* subversion/svn/file-merge.c,
* subversion/svn/propedit-cmd.c
  Track function renames.

Modified:
    subversion/trunk/subversion/include/private/svn_cmdline_private.h
    subversion/trunk/subversion/libsvn_subr/cmdline.c
    subversion/trunk/subversion/svn/cl.h
    subversion/trunk/subversion/svn/conflict-callbacks.c
    subversion/trunk/subversion/svn/file-merge.c
    subversion/trunk/subversion/svn/propedit-cmd.c
    subversion/trunk/subversion/svn/util.c

Modified: subversion/trunk/subversion/include/private/svn_cmdline_private.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_cmdline_private.h?rev=1425125&r1=1425124&r2=1425125&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_cmdline_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_cmdline_private.h Fri Dec 21 20:14:27
2012
@@ -28,6 +28,7 @@
 #define SVN_CMDLINE_PRIVATE_H
 
 #include <apr_pools.h>
+#include <apr_hash.h>
 
 #include "svn_string.h"
 #include "svn_error.h"
@@ -143,6 +144,61 @@ svn_cmdline__print_xml_prop_hash(svn_str
                                  svn_boolean_t inherited_props,
                                  apr_pool_t *pool);
 
+
+/* Search for a text editor command in standard environment variables,
+   and invoke it to edit PATH.  Use POOL for all allocations.
+
+   If EDITOR_CMD is not NULL, it is the name of the external editor
+   command to use, overriding anything else that might determine the
+   editor.
+
+   CONFIG is a hash of svn_config_t * items keyed on a configuration
+   category (SVN_CONFIG_CATEGORY_CONFIG et al), and may be NULL.  */
+svn_error_t *
+svn_cmdline__edit_file_externally(const char *path,
+                                  const char *editor_cmd,
+                                  apr_hash_t *config,
+                                  apr_pool_t *pool);
+
+/* Search for a text editor command in standard environment variables,
+   and invoke it to edit CONTENTS (using a temporary file created in
+   directory BASE_DIR).  Return the new contents in *EDITED_CONTENTS,
+   or set *EDITED_CONTENTS to NULL if no edit was performed.
+
+   If EDITOR_CMD is not NULL, it is the name of the external editor
+   command to use, overriding anything else that might determine the
+   editor.
+
+   If TMPFILE_LEFT is NULL, the temporary file will be destroyed.
+   Else, the file will be left on disk, and its path returned in
+   *TMPFILE_LEFT.
+
+   CONFIG is a hash of svn_config_t * items keyed on a configuration
+   category (SVN_CONFIG_CATEGORY_CONFIG et al), and may be NULL.
+
+   If AS_TEXT is TRUE, recode CONTENTS and convert to native eol-style before
+   editing and back again afterwards.  In this case, ENCODING determines the
+   encoding used during editing.  If non-NULL, use the named encoding, else
+   use the system encoding.  If AS_TEXT is FALSE, don't do any translation.
+   In that case, ENCODING is ignored.
+
+   Use POOL for all allocations.  Use PREFIX as the prefix for the
+   temporary file used by the editor.
+
+   If return error, *EDITED_CONTENTS is not touched. */
+svn_error_t *
+svn_cmdline__edit_string_externally(svn_string_t **edited_contents,
+                                    const char **tmpfile_left,
+                                    const char *editor_cmd,
+                                    const char *base_dir,
+                                    const svn_string_t *contents,
+                                    const char *prefix,
+                                    apr_hash_t *config,
+                                    svn_boolean_t as_text,
+                                    const char *encoding,
+                                    apr_pool_t *pool);
+
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/trunk/subversion/libsvn_subr/cmdline.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/cmdline.c?rev=1425125&r1=1425124&r2=1425125&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/cmdline.c (original)
+++ subversion/trunk/subversion/libsvn_subr/cmdline.c Fri Dec 21 20:14:27 2012
@@ -43,6 +43,7 @@
 #include <apr_pools.h>
 
 #include "svn_cmdline.h"
+#include "svn_ctype.h"
 #include "svn_dso.h"
 #include "svn_dirent_uri.h"
 #include "svn_path.h"
@@ -60,6 +61,7 @@
 
 #include "private/svn_cmdline_private.h"
 #include "private/svn_utf_private.h"
+#include "private/svn_string_private.h"
 
 #include "svn_private_config.h"
 
@@ -946,3 +948,363 @@ svn_cmdline__be_interactive(svn_boolean_
 
   return !non_interactive;
 }
+
+
+/* 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;
+}
+
+
+svn_error_t *
+svn_cmdline__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_cmdline__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);
+}

Modified: subversion/trunk/subversion/svn/cl.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/cl.h?rev=1425125&r1=1425124&r2=1425125&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/cl.h (original)
+++ subversion/trunk/subversion/svn/cl.h Fri Dec 21 20:14:27 2012
@@ -493,60 +493,6 @@ svn_cl__revprop_prepare(const svn_opt_re
                         svn_client_ctx_t *ctx,
                         apr_pool_t *pool);
 
-/* Search for a text editor command in standard environment variables,
-   and invoke it to edit CONTENTS (using a temporary file created in
-   directory BASE_DIR).  Return the new contents in *EDITED_CONTENTS,
-   or set *EDITED_CONTENTS to NULL if no edit was performed.
-
-   If EDITOR_CMD is not NULL, it is the name of the external editor
-   command to use, overriding anything else that might determine the
-   editor.
-
-   If TMPFILE_LEFT is NULL, the temporary file will be destroyed.
-   Else, the file will be left on disk, and its path returned in
-   *TMPFILE_LEFT.
-
-   CONFIG is a hash of svn_config_t * items keyed on a configuration
-   category (SVN_CONFIG_CATEGORY_CONFIG et al), and may be NULL.
-
-   If AS_TEXT is TRUE, recode CONTENTS and convert to native eol-style before
-   editing and back again afterwards.  In this case, ENCODING determines the
-   encoding used during editing.  If non-NULL, use the named encoding, else
-   use the system encoding.  If AS_TEXT is FALSE, don't do any translation.
-   In that case, ENCODING is ignored.
-
-   Use POOL for all allocations.  Use PREFIX as the prefix for the
-   temporary file used by the editor.
-
-   If return error, *EDITED_CONTENTS is not touched. */
-svn_error_t *
-svn_cl__edit_string_externally(svn_string_t **edited_contents,
-                               const char **tmpfile_left,
-                               const char *editor_cmd,
-                               const char *base_dir,
-                               const svn_string_t *contents,
-                               const char *prefix,
-                               apr_hash_t *config,
-                               svn_boolean_t as_text,
-                               const char *encoding,
-                               apr_pool_t *pool);
-
-
-/* Search for a text editor command in standard environment variables,
-   and invoke it to edit PATH.  Use POOL for all allocations.
-
-   If EDITOR_CMD is not NULL, it is the name of the external editor
-   command to use, overriding anything else that might determine the
-   editor.
-
-   CONFIG is a hash of svn_config_t * items keyed on a configuration
-   category (SVN_CONFIG_CATEGORY_CONFIG et al), and may be NULL.  */
-svn_error_t *
-svn_cl__edit_file_externally(const char *path,
-                             const char *editor_cmd,
-                             apr_hash_t *config,
-                             apr_pool_t *pool);
-
 /* Search for a merge tool command in environment variables,
    and use it to perform the merge of the four given files.
    WC_PATH is the path of the file that is in conflict, relative

Modified: subversion/trunk/subversion/svn/conflict-callbacks.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/conflict-callbacks.c?rev=1425125&r1=1425124&r2=1425125&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/conflict-callbacks.c (original)
+++ subversion/trunk/subversion/svn/conflict-callbacks.c Fri Dec 21 20:14:27 2012
@@ -38,6 +38,8 @@
 #include "cl.h"
 #include "tree-conflicts.h"
 
+#include "private/svn_cmdline_private.h"
+
 #include "svn_private_config.h"
 
 
@@ -203,8 +205,8 @@ open_editor(svn_boolean_t *performed_edi
 
   if (desc->merged_file)
     {
-      err = svn_cl__edit_file_externally(desc->merged_file, b->editor_cmd,
-                                         b->config, pool);
+      err = svn_cmdline__edit_file_externally(desc->merged_file, b->editor_cmd,
+                                              b->config, pool);
       if (err && (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR))
         {
           svn_error_t *root_err = svn_error_root_cause(err);
@@ -804,9 +806,9 @@ svn_cl__conflict_func_interactive(svn_wc
               return SVN_NO_ERROR;
             }
 
-          err = svn_cl__edit_file_externally(desc->merged_file,
-                                             b->editor_cmd, b->config,
-                                             scratch_pool);
+          err = svn_cmdline__edit_file_externally(desc->merged_file,
+                                                  b->editor_cmd, b->config,
+                                                  scratch_pool);
           if (err && (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR))
             {
               SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, "%s\n",

Modified: subversion/trunk/subversion/svn/file-merge.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/file-merge.c?rev=1425125&r1=1425124&r2=1425125&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/file-merge.c (original)
+++ subversion/trunk/subversion/svn/file-merge.c Fri Dec 21 20:14:27 2012
@@ -37,6 +37,7 @@
 
 #include "svn_private_config.h"
 #include "private/svn_utf_private.h"
+#include "private/svn_cmdline_private.h"
 #include "private/svn_dep_compat.h"
 
 #if APR_HAVE_SYS_IOCTL_H
@@ -491,8 +492,8 @@ edit_chunk(apr_array_header_t **merged_c
     }
   SVN_ERR(svn_io_file_flush_to_disk(temp_file, scratch_pool));
 
-  err = svn_cl__edit_file_externally(temp_file_name, editor_cmd,
-                                     config, scratch_pool);
+  err = svn_cmdline__edit_file_externally(temp_file_name, editor_cmd,
+                                          config, scratch_pool);
   if (err && (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR))
     {
       svn_error_t *root_err = svn_error_root_cause(err);

Modified: subversion/trunk/subversion/svn/propedit-cmd.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/propedit-cmd.c?rev=1425125&r1=1425124&r2=1425125&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/propedit-cmd.c (original)
+++ subversion/trunk/subversion/svn/propedit-cmd.c Fri Dec 21 20:14:27 2012
@@ -39,6 +39,7 @@
 #include "svn_props.h"
 #include "cl.h"
 
+#include "private/svn_cmdline_private.h"
 #include "svn_private_config.h"
 
 
@@ -137,8 +138,8 @@ svn_cl__propedit(apr_getopt_t *os,
       /* Run the editor on a temporary file which contains the
          original property value... */
       SVN_ERR(svn_io_temp_dir(&temp_dir, pool));
-      SVN_ERR(svn_cl__edit_string_externally
-              (&propval, NULL,
+      SVN_ERR(svn_cmdline__edit_string_externally(
+               &propval, NULL,
                opt_state->editor_cmd, temp_dir,
                propval, "svn-prop",
                ctx->config,
@@ -272,16 +273,16 @@ svn_cl__propedit(apr_getopt_t *os,
 
           /* Run the editor on a temporary file which contains the
              original property value... */
-          SVN_ERR(svn_cl__edit_string_externally(&edited_propval, NULL,
-                                                 opt_state->editor_cmd,
-                                                 base_dir,
-                                                 propval,
-                                                 "svn-prop",
-                                                 ctx->config,
-                                                 svn_prop_needs_translation
-                                                 (pname_utf8),
-                                                 opt_state->encoding,
-                                                 subpool));
+          SVN_ERR(svn_cmdline__edit_string_externally(&edited_propval, NULL,
+                                                      opt_state->editor_cmd,
+                                                      base_dir,
+                                                      propval,
+                                                      "svn-prop",
+                                                      ctx->config,
+                                                      svn_prop_needs_translation
+                                                      (pname_utf8),
+                                                      opt_state->encoding,
+                                                      subpool));
 
           target_local = svn_path_is_url(target) ? target
             : svn_dirent_local_style(target, subpool);

Modified: subversion/trunk/subversion/svn/util.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/util.c?rev=1425125&r1=1425124&r2=1425125&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/util.c (original)
+++ subversion/trunk/subversion/svn/util.c Fri Dec 21 20:14:27 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(). */
@@ -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 */
         {



Mime
View raw message