You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2013/01/06 03:33:39 UTC
svn commit: r1429457 [15/21] - in /subversion/branches/tree-read-api: ./
build/ build/ac-macros/ build/generator/templates/ build/win32/
contrib/server-side/svncutter/ doc/ subversion/bindings/cxxhl/include/
subversion/bindings/cxxhl/include/svncxxhl/ ...
Modified: subversion/branches/tree-read-api/subversion/svn/props.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/svn/props.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/svn/props.c (original)
+++ subversion/branches/tree-read-api/subversion/svn/props.c Sun Jan 6 02:33:34 2013
@@ -83,121 +83,6 @@ svn_cl__revprop_prepare(const svn_opt_re
return SVN_NO_ERROR;
}
-
-svn_error_t *
-svn_cl__print_prop_hash(svn_stream_t *out,
- apr_hash_t *prop_hash,
- svn_boolean_t names_only,
- apr_pool_t *pool)
-{
- apr_array_header_t *sorted_props;
- int i;
-
- sorted_props = svn_sort__hash(prop_hash, svn_sort_compare_items_lexically,
- pool);
- for (i = 0; i < sorted_props->nelts; i++)
- {
- svn_sort__item_t item = APR_ARRAY_IDX(sorted_props, i, svn_sort__item_t);
- const char *pname = item.key;
- svn_string_t *propval = item.value;
- const char *pname_stdout;
-
- if (svn_prop_needs_translation(pname))
- SVN_ERR(svn_subst_detranslate_string(&propval, propval,
- TRUE, pool));
-
- SVN_ERR(svn_cmdline_cstring_from_utf8(&pname_stdout, pname, pool));
-
- if (out)
- {
- pname_stdout = apr_psprintf(pool, " %s\n", pname_stdout);
- SVN_ERR(svn_subst_translate_cstring2(pname_stdout, &pname_stdout,
- APR_EOL_STR, /* 'native' eol */
- FALSE, /* no repair */
- NULL, /* no keywords */
- FALSE, /* no expansion */
- pool));
-
- SVN_ERR(svn_stream_puts(out, pname_stdout));
- }
- else
- {
- /* ### We leave these printfs for now, since if propval wasn't
- translated above, we don't know anything about its encoding.
- In fact, it might be binary data... */
- printf(" %s\n", pname_stdout);
- }
-
- if (!names_only)
- {
- /* Add an extra newline to the value before indenting, so that
- * every line of output has the indentation whether the value
- * already ended in a newline or not. */
- const char *newval = apr_psprintf(pool, "%s\n", propval->data);
- const char *indented_newval = svn_cl__indent_string(newval,
- " ",
- pool);
- if (out)
- {
- SVN_ERR(svn_stream_puts(out, indented_newval));
- }
- else
- {
- printf("%s", indented_newval);
- }
- }
- }
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_cl__print_xml_prop_hash(svn_stringbuf_t **outstr,
- apr_hash_t *prop_hash,
- svn_boolean_t names_only,
- svn_boolean_t inherited_props,
- apr_pool_t *pool)
-{
- apr_array_header_t *sorted_props;
- int i;
-
- if (*outstr == NULL)
- *outstr = svn_stringbuf_create_empty(pool);
-
- sorted_props = svn_sort__hash(prop_hash, svn_sort_compare_items_lexically,
- pool);
- for (i = 0; i < sorted_props->nelts; i++)
- {
- svn_sort__item_t item = APR_ARRAY_IDX(sorted_props, i, svn_sort__item_t);
- const char *pname = item.key;
- svn_string_t *propval = item.value;
-
- if (names_only)
- {
- svn_xml_make_open_tag(
- outstr, pool, svn_xml_self_closing,
- inherited_props ? "inherited_property" : "property",
- "name", pname, NULL);
- }
- else
- {
- const char *pname_out;
-
- if (svn_prop_needs_translation(pname))
- SVN_ERR(svn_subst_detranslate_string(&propval, propval,
- TRUE, pool));
-
- SVN_ERR(svn_cmdline_cstring_from_utf8(&pname_out, pname, pool));
-
- svn_cmdline__print_xml_prop(outstr, pname_out, propval,
- inherited_props, pool);
- }
- }
-
- return SVN_NO_ERROR;
-}
-
-
void
svn_cl__check_boolean_prop_val(const char *propname, const char *propval,
apr_pool_t *pool)
Modified: subversion/branches/tree-read-api/subversion/svn/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/svn/status.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/svn/status.c (original)
+++ subversion/branches/tree-read-api/subversion/svn/status.c Sun Jan 6 02:33:34 2013
@@ -377,7 +377,7 @@ print_status(const char *cwd_abspath, co
SVN_ERR
(svn_cmdline_printf(pool,
- "%c%c%c%c%c%c%c %c %6s %6s %-12s %s%s%s%s\n",
+ "%c%c%c%c%c%c%c %c %8s %8s %-12s %s%s%s%s\n",
generate_status_code(combined_status(status)),
generate_status_code(prop_status),
status->wc_is_locked ? 'L' : ' ',
@@ -396,7 +396,7 @@ print_status(const char *cwd_abspath, co
}
else
SVN_ERR(
- svn_cmdline_printf(pool, "%c%c%c%c%c%c%c %c %6s %s%s%s%s\n",
+ svn_cmdline_printf(pool, "%c%c%c%c%c%c%c %c %8s %s%s%s%s\n",
generate_status_code(combined_status(status)),
generate_status_code(prop_status),
status->wc_is_locked ? 'L' : ' ',
Modified: subversion/branches/tree-read-api/subversion/svn/svn.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/svn/svn.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/svn/svn.c (original)
+++ subversion/branches/tree-read-api/subversion/svn/svn.c Sun Jan 6 02:33:34 2013
@@ -1,5 +1,5 @@
/*
- * main.c: Subversion command line client.
+ * svn.c: Subversion command line client main file.
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
@@ -101,6 +101,7 @@ typedef enum svn_cl__longopt_t {
opt_no_ignore,
opt_no_unlock,
opt_non_interactive,
+ opt_force_interactive,
opt_old_cmd,
opt_record_only,
opt_relocate,
@@ -229,7 +230,13 @@ const apr_getopt_option_t svn_cl__option
" "
"with '--non-interactive')") },
{"non-interactive", opt_non_interactive, 0,
- N_("do no interactive prompting")},
+ N_("do no interactive prompting (default is to prompt\n"
+ " "
+ "only if standard input is a terminal device)")},
+ {"force-interactive", opt_force_interactive, 0,
+ N_("do interactive prompting even if standard input\n"
+ " "
+ "is not a terminal device")},
{"dry-run", opt_dry_run, 0,
N_("try operation but make no changes")},
{"ignore-ancestry", opt_ignore_ancestry, 0,
@@ -401,7 +408,8 @@ const apr_getopt_option_t svn_cl__option
willy-nilly to every invocation of 'svn') . */
const int svn_cl__global_options[] =
{ opt_auth_username, opt_auth_password, opt_no_auth_cache, opt_non_interactive,
- opt_trust_server_cert, opt_config_dir, opt_config_options, 0
+ opt_force_interactive, opt_trust_server_cert, opt_config_dir,
+ opt_config_options, 0
};
/* Options for giving a log message. (Some of these also have other uses.)
@@ -730,7 +738,7 @@ const svn_opt_subcommand_desc2_t svn_cl_
" (the 'automatic' merge)\n"
" 2. merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [TARGET_WCPATH]\n"
" (the 'cherry-pick' merge)\n"
-" 3. merge SOURCE1[@N] SOURCE2[@M] [TARGET_WCPATH]\n"
+" 3. merge SOURCE1[@REV1] SOURCE2[@REV2] [TARGET_WCPATH]\n"
" (the '2-URL' merge)\n"
"\n"
" 1. This form, with one source path and no revision range, is called\n"
@@ -915,26 +923,27 @@ const svn_opt_subcommand_desc2_t svn_cl_
"\n"
" 3. This form is called a '2-URL merge':\n"
"\n"
-" svn merge SOURCE1[@N] SOURCE2[@M] [TARGET_WCPATH]\n"
-"\n"
-" Two source URLs are specified, together with two revisions N and M.\n"
-" The two sources are compared at the specified revisions, and the\n"
-" difference is applied to TARGET_WCPATH, which is a path to a working\n"
-" copy of another branch. The three branches involved can be completely\n"
-" unrelated.\n"
+" svn merge SOURCE1[@REV1] SOURCE2[@REV2] [TARGET_WCPATH]\n"
"\n"
" You should use this merge variant only if the other variants do not\n"
" apply to your situation, as this variant can be quite complex to\n"
" master.\n"
"\n"
+" Two source URLs are specified, identifying two trees on the same\n"
+" branch or on different branches. The trees are compared and the\n"
+" difference from SOURCE1@REV1 to SOURCE2@REV2 is applied to the\n"
+" working copy of the target branch at TARGET_WCPATH. The target\n"
+" branch may be the same as one or both sources, or different again.\n"
+" The three branches involved can be completely unrelated.\n"
+"\n"
" If TARGET_WCPATH is omitted, a default value of '.' is assumed.\n"
" However, in the special case where both sources refer to a file node\n"
-" with the same basename and a similarly named file is also found within\n"
-" '.', the differences will be applied to that local file. The source\n"
-" revisions default to HEAD if omitted.\n"
+" with the same name and a file with the same name is also found within\n"
+" '.', the differences will be applied to that local file. The source\n"
+" revisions REV1 and REV2 default to HEAD if omitted.\n"
"\n"
-" The sources can also be specified as working copy paths, in which case\n"
-" the URLs of the merge sources are derived from the working copies.\n"
+" SOURCE1 and/or SOURCE2 can also be specified as a working copy path,\n"
+" in which case the merge source URL is derived from the working copy.\n"
"\n"
" - 2-URL Merge Example -\n"
"\n"
@@ -1036,7 +1045,7 @@ const svn_opt_subcommand_desc2_t svn_cl_
" repositories.\n"),
{'r', 'c', 'N', opt_depth, 'q', opt_force, opt_dry_run, opt_merge_cmd,
opt_record_only, 'x', opt_ignore_ancestry, opt_accept, opt_reintegrate,
- opt_allow_mixed_revisions} },
+ opt_allow_mixed_revisions, 'v'} },
{ "mergeinfo", svn_cl__mergeinfo, {0}, N_
("Display merge-related information.\n"
@@ -1659,6 +1668,7 @@ sub_main(int argc, const char *argv[], a
svn_config_t *cfg_config;
svn_boolean_t descend = TRUE;
svn_boolean_t interactive_conflicts = FALSE;
+ svn_boolean_t force_interactive = FALSE;
svn_boolean_t use_notifier = TRUE;
apr_hash_t *changelists;
const char *sqlite_exclusive;
@@ -1982,6 +1992,9 @@ sub_main(int argc, const char *argv[], a
case opt_non_interactive:
opt_state.non_interactive = TRUE;
break;
+ case opt_force_interactive:
+ force_interactive = TRUE;
+ break;
case opt_trust_server_cert:
opt_state.trust_server_cert = TRUE;
break;
@@ -2083,6 +2096,12 @@ sub_main(int argc, const char *argv[], a
break;
case opt_changelist:
opt_state.changelist = apr_pstrdup(pool, opt_arg);
+ if (opt_state.changelist[0] == '\0')
+ {
+ err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Changelist names must not be empty"));
+ return svn_cmdline_handle_exit_error(err, pool, "svn: ");
+ }
apr_hash_set(changelists, opt_state.changelist,
APR_HASH_KEY_STRING, (void *)1);
break;
@@ -2191,6 +2210,20 @@ sub_main(int argc, const char *argv[], a
}
}
+ /* The --non-interactive and --force-interactive options are mutually
+ * exclusive. */
+ if (opt_state.non_interactive && force_interactive)
+ {
+ err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--non-interactive and --force-interactive "
+ "are mutually exclusive"));
+ return EXIT_ERROR(err);
+ }
+ else
+ opt_state.non_interactive = !svn_cmdline__be_interactive(
+ opt_state.non_interactive,
+ force_interactive);
+
/* Turn our hash of changelists into an array of unique ones. */
SVN_INT_ERR(svn_hash_keys(&(opt_state.changelists), changelists, pool));
Modified: subversion/branches/tree-read-api/subversion/svn/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/svn/util.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/svn/util.c (original)
+++ subversion/branches/tree-read-api/subversion/svn/util.c Sun Jan 6 02:33:34 2013
@@ -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 */
{
@@ -1264,56 +904,6 @@ svn_cl__time_cstring_to_human_cstring(co
return SVN_NO_ERROR;
}
-
-/* Return a copy, allocated in POOL, of the next line of text from *STR
- * up to and including a CR and/or an LF. Change *STR to point to the
- * remainder of the string after the returned part. If there are no
- * characters to be returned, return NULL; never return an empty string.
- */
-static const char *
-next_line(const char **str, apr_pool_t *pool)
-{
- const char *start = *str;
- const char *p = *str;
-
- /* n.b. Throughout this fn, we never read any character after a '\0'. */
- /* Skip over all non-EOL characters, if any. */
- while (*p != '\r' && *p != '\n' && *p != '\0')
- p++;
- /* Skip over \r\n or \n\r or \r or \n, if any. */
- if (*p == '\r' || *p == '\n')
- {
- char c = *p++;
-
- if ((c == '\r' && *p == '\n') || (c == '\n' && *p == '\r'))
- p++;
- }
-
- /* Now p points after at most one '\n' and/or '\r'. */
- *str = p;
-
- if (p == start)
- return NULL;
-
- return svn_string_ncreate(start, p - start, pool)->data;
-}
-
-const char *
-svn_cl__indent_string(const char *str,
- const char *indent,
- apr_pool_t *pool)
-{
- svn_stringbuf_t *out = svn_stringbuf_create_empty(pool);
- const char *line;
-
- while ((line = next_line(&str, pool)))
- {
- svn_stringbuf_appendcstr(out, indent);
- svn_stringbuf_appendcstr(out, line);
- }
- return out->data;
-}
-
const char *
svn_cl__node_description(const svn_wc_conflict_version_t *node,
const char *wc_repos_root_URL,
Modified: subversion/branches/tree-read-api/subversion/svnadmin/svnadmin.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/svnadmin/svnadmin.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/svnadmin/svnadmin.c (original)
+++ subversion/branches/tree-read-api/subversion/svnadmin/svnadmin.c Sun Jan 6 02:33:34 2013
@@ -1,5 +1,5 @@
/*
- * main.c: Subversion server administration tool.
+ * svnadmin.c: Subversion server administration tool main file.
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
Modified: subversion/branches/tree-read-api/subversion/svndumpfilter/svndumpfilter.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/svndumpfilter/svndumpfilter.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/svndumpfilter/svndumpfilter.c (original)
+++ subversion/branches/tree-read-api/subversion/svndumpfilter/svndumpfilter.c Sun Jan 6 02:33:34 2013
@@ -1,5 +1,5 @@
/*
- * main.c: Subversion dump stream filtering tool.
+ * svndumpfilter.c: Subversion dump stream filtering tool main file.
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
Modified: subversion/branches/tree-read-api/subversion/svnlook/svnlook.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/svnlook/svnlook.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/svnlook/svnlook.c (original)
+++ subversion/branches/tree-read-api/subversion/svnlook/svnlook.c Sun Jan 6 02:33:34 2013
@@ -1,5 +1,5 @@
/*
- * main.c: Subversion server inspection tool.
+ * svnlook.c: Subversion server inspection tool main file.
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
@@ -97,7 +97,8 @@ enum
svnlook__xml_opt,
svnlook__ignore_properties,
svnlook__properties_only,
- svnlook__diff_cmd
+ svnlook__diff_cmd,
+ svnlook__show_inherited_props
};
/*
@@ -150,6 +151,9 @@ static const apr_getopt_option_t options
{"show-ids", svnlook__show_ids, 0,
N_("show node revision ids for each path")},
+ {"show-inherited-props", svnlook__show_inherited_props, 0,
+ N_("show path's inherited properties")},
+
{"transaction", 't', 1,
N_("specify transaction name ARG")},
@@ -265,7 +269,7 @@ static const svn_opt_subcommand_desc2_t
" 2. svnlook propget --revprop REPOS_PATH PROPNAME\n\n"
"Print the raw value of a property on a path in the repository.\n"
"With --revprop, print the raw value of a revision property.\n"),
- {'r', 't', svnlook__revprop_opt} },
+ {'r', 't', 'v', svnlook__revprop_opt, svnlook__show_inherited_props} },
{"proplist", subcommand_plist, {"plist", "pl"},
N_("usage: 1. svnlook proplist REPOS_PATH PATH_IN_REPOS\n"
@@ -275,7 +279,8 @@ static const svn_opt_subcommand_desc2_t
"List the properties of a path in the repository, or\n"
"with the --revprop option, revision properties.\n"
"With -v, show the property values too.\n"),
- {'r', 't', 'v', svnlook__revprop_opt, svnlook__xml_opt} },
+ {'r', 't', 'v', svnlook__revprop_opt, svnlook__xml_opt,
+ svnlook__show_inherited_props} },
{"tree", subcommand_tree, {0},
N_("usage: svnlook tree REPOS_PATH [PATH_IN_REPOS]\n\n"
@@ -323,6 +328,7 @@ struct svnlook_opt_state
svn_boolean_t ignore_properties; /* --ignore_properties */
svn_boolean_t properties_only; /* --properties-only */
const char *diff_cmd; /* --diff-cmd */
+ svn_boolean_t show_inherited_props; /* --show-inherited-props */
};
@@ -1628,13 +1634,23 @@ do_history(svnlook_ctxt_t *c,
/* Print the value of property PROPNAME on PATH in the repository.
- Error with SVN_ERR_FS_NOT_FOUND if PATH does not exist, or with
- SVN_ERR_PROPERTY_NOT_FOUND if no such property on PATH.
+
+ If VERBOSE, print their values too. If SHOW_INHERITED_PROPS, print
+ PATH's inherited props too.
+
+ Error with SVN_ERR_FS_NOT_FOUND if PATH does not exist. If
+ SHOW_INHERITED_PROPS is FALSE,then error with SVN_ERR_PROPERTY_NOT_FOUND
+ if there is no such property on PATH. If SHOW_INHERITED_PROPS is TRUE,
+ then error with SVN_ERR_PROPERTY_NOT_FOUND only if there is no such
+ property on PATH nor inherited by path.
+
If PATH is NULL, operate on a revision property. */
static svn_error_t *
do_pget(svnlook_ctxt_t *c,
const char *propname,
const char *path,
+ svn_boolean_t verbose,
+ svn_boolean_t show_inherited_props,
apr_pool_t *pool)
{
svn_fs_root_t *root;
@@ -1642,17 +1658,30 @@ do_pget(svnlook_ctxt_t *c,
svn_node_kind_t kind;
svn_stream_t *stdout_stream;
apr_size_t len;
+ apr_array_header_t *inherited_props = NULL;
SVN_ERR(get_root(&root, c, pool));
if (path != NULL)
{
+ path = svn_fspath__canonicalize(path, pool);
SVN_ERR(verify_path(&kind, root, path, pool));
SVN_ERR(svn_fs_node_prop(&prop, root, path, propname, pool));
+
+ if (show_inherited_props)
+ {
+ SVN_ERR(svn_repos_fs_get_inherited_props(&inherited_props, root,
+ path, propname, NULL,
+ NULL, pool, pool));
+ }
+ }
+ else /* --revprop */
+ {
+ SVN_ERR(get_property(&prop, c, propname, pool));
}
- else
- SVN_ERR(get_property(&prop, c, propname, pool));
- if (prop == NULL)
+ /* Did we find nothing? */
+ if (prop == NULL
+ && (!show_inherited_props || inherited_props->nelts == 0))
{
const char *err_msg;
if (path == NULL)
@@ -1665,61 +1694,162 @@ do_pget(svnlook_ctxt_t *c,
else
{
if (SVN_IS_VALID_REVNUM(c->rev_id))
- err_msg = apr_psprintf(pool,
- _("Property '%s' not found on path '%s' "
- "in revision %ld"),
- propname, path, c->rev_id);
+ {
+ if (show_inherited_props)
+ err_msg = apr_psprintf(pool,
+ _("Property '%s' not found on path '%s' "
+ "or inherited from a parent "
+ "in revision %ld"),
+ propname, path, c->rev_id);
+ else
+ err_msg = apr_psprintf(pool,
+ _("Property '%s' not found on path '%s' "
+ "in revision %ld"),
+ propname, path, c->rev_id);
+ }
else
- err_msg = apr_psprintf(pool,
- _("Property '%s' not found on path '%s' "
- "in transaction %s"),
- propname, path, c->txn_name);
+ {
+ if (show_inherited_props)
+ err_msg = apr_psprintf(pool,
+ _("Property '%s' not found on path '%s' "
+ "or inherited from a parent "
+ "in transaction %s"),
+ propname, path, c->txn_name);
+ else
+ err_msg = apr_psprintf(pool,
+ _("Property '%s' not found on path '%s' "
+ "in transaction %s"),
+ propname, path, c->txn_name);
+ }
}
return svn_error_create(SVN_ERR_PROPERTY_NOT_FOUND, NULL, err_msg);
}
- /* Else. */
-
SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
- /* Unlike the command line client, we don't translate the property
- value or print a trailing newline here. We just output the raw
- bytes of whatever's in the repository, as svnlook is more likely
- to be used for automated inspections. */
- len = prop->len;
- SVN_ERR(svn_stream_write(stdout_stream, prop->data, &len));
+ if (verbose || show_inherited_props)
+ {
+ if (inherited_props)
+ {
+ int i;
+
+ for (i = 0; i < inherited_props->nelts; i++)
+ {
+ svn_prop_inherited_item_t *elt =
+ APR_ARRAY_IDX(inherited_props, i,
+ svn_prop_inherited_item_t *);
+
+ if (verbose)
+ {
+ SVN_ERR(svn_stream_printf(stdout_stream, pool,
+ _("Inherited properties on '%s',\nfrom '%s':\n"),
+ path, svn_fspath__canonicalize(elt->path_or_url,
+ pool)));
+ SVN_ERR(svn_cmdline__print_prop_hash(stdout_stream,
+ elt->prop_hash,
+ !verbose, pool));
+ }
+ else
+ {
+ svn_string_t *propval =
+ svn__apr_hash_index_val(apr_hash_first(pool,
+ elt->prop_hash));
+
+ SVN_ERR(svn_stream_printf(
+ stdout_stream, pool, "%s - ",
+ svn_fspath__canonicalize(elt->path_or_url, pool)));
+ len = propval->len;
+ SVN_ERR(svn_stream_write(stdout_stream, propval->data, &len));
+ /* If we have more than one property to write, then add a newline*/
+ if (inherited_props->nelts > 1 || prop)
+ {
+ len = strlen(APR_EOL_STR);
+ SVN_ERR(svn_stream_write(stdout_stream, APR_EOL_STR, &len));
+ }
+ }
+ }
+ }
+
+ if (prop)
+ {
+ if (verbose)
+ {
+ apr_hash_t *hash = apr_hash_make(pool);
+
+ apr_hash_set(hash, propname, APR_HASH_KEY_STRING, prop);
+ SVN_ERR(svn_stream_printf(stdout_stream, pool,
+ _("Properties on '%s':\n"), path));
+ SVN_ERR(svn_cmdline__print_prop_hash(stdout_stream, hash,
+ FALSE, pool));
+ }
+ else
+ {
+ SVN_ERR(svn_stream_printf(stdout_stream, pool, "%s - ", path));
+ len = prop->len;
+ SVN_ERR(svn_stream_write(stdout_stream, prop->data, &len));
+ }
+ }
+ }
+ else /* Raw single prop output, i.e. non-verbose output with no
+ inherited props. */
+ {
+ /* Unlike the command line client, we don't translate the property
+ value or print a trailing newline here. We just output the raw
+ bytes of whatever's in the repository, as svnlook is more likely
+ to be used for automated inspections. */
+ len = prop->len;
+ SVN_ERR(svn_stream_write(stdout_stream, prop->data, &len));
+ }
return SVN_NO_ERROR;
}
/* Print the property names of all properties on PATH in the repository.
- If VERBOSE, print their values too.
- If XML, print as XML rather than as plain text.
- Error with SVN_ERR_FS_NOT_FOUND if PATH does not exist, or with
- SVN_ERR_PROPERTY_NOT_FOUND if no such property on PATH.
+
+ If VERBOSE, print their values too. If XML, print as XML rather than as
+ plain text. If SHOW_INHERITED_PROPS, print PATH's inherited props too.
+
+ Error with SVN_ERR_FS_NOT_FOUND if PATH does not exist.
+
If PATH is NULL, operate on a revision properties. */
static svn_error_t *
do_plist(svnlook_ctxt_t *c,
const char *path,
svn_boolean_t verbose,
svn_boolean_t xml,
+ svn_boolean_t show_inherited_props,
apr_pool_t *pool)
{
- svn_stream_t *stdout_stream;
svn_fs_root_t *root;
apr_hash_t *props;
apr_hash_index_t *hi;
svn_node_kind_t kind;
svn_stringbuf_t *sb = NULL;
svn_boolean_t revprop = FALSE;
+ apr_array_header_t *inherited_props = NULL;
- SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
if (path != NULL)
{
+ /* PATH might be the root of the repsository and we accept both
+ "" and "/". But to avoid the somewhat cryptic output like this:
+
+ >svnlook pl repos-path ""
+ Properties on '':
+ svn:auto-props
+ svn:global-ignores
+
+ We canonicalize PATH so that is has a leading slash. */
+ path = svn_fspath__canonicalize(path, pool);
+
SVN_ERR(get_root(&root, c, pool));
SVN_ERR(verify_path(&kind, root, path, pool));
SVN_ERR(svn_fs_node_proplist(&props, root, path, pool));
+
+ if (show_inherited_props)
+ SVN_ERR(svn_repos_fs_get_inherited_props(&inherited_props, root,
+ path, NULL, NULL, NULL,
+ pool, pool));
}
else if (c->is_revision)
{
@@ -1734,18 +1864,55 @@ do_plist(svnlook_ctxt_t *c,
if (xml)
{
- char *revstr = apr_psprintf(pool, "%ld", c->rev_id);
/* <?xml version="1.0" encoding="UTF-8"?> */
svn_xml_make_header2(&sb, "UTF-8", pool);
/* "<properties>" */
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "properties", NULL);
+ }
+ if (inherited_props)
+ {
+ int i;
+
+ for (i = 0; i < inherited_props->nelts; i++)
+ {
+ svn_prop_inherited_item_t *elt =
+ APR_ARRAY_IDX(inherited_props, i, svn_prop_inherited_item_t *);
+
+ /* Canonicalize the inherited parent paths for consistency
+ with PATH. */
+ if (xml)
+ {
+ svn_xml_make_open_tag(
+ &sb, pool, svn_xml_normal, "target", "path",
+ svn_fspath__canonicalize(elt->path_or_url, pool),
+ NULL);
+ SVN_ERR(svn_cmdline__print_xml_prop_hash(&sb, elt->prop_hash,
+ !verbose, TRUE,
+ pool));
+ svn_xml_make_close_tag(&sb, pool, "target");
+ }
+ else
+ {
+ SVN_ERR(svn_cmdline_printf(
+ pool, _("Inherited properties on '%s',\nfrom '%s':\n"),
+ path, svn_fspath__canonicalize(elt->path_or_url, pool)));
+ SVN_ERR(svn_cmdline__print_prop_hash(NULL, elt->prop_hash,
+ !verbose, pool));
+ }
+ }
+ }
+
+ if (xml)
+ {
if (revprop)
{
/* "<revprops ...>" */
if (c->is_revision)
{
+ char *revstr = apr_psprintf(pool, "%ld", c->rev_id);
+
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "revprops",
"rev", revstr, NULL);
}
@@ -1763,6 +1930,9 @@ do_plist(svnlook_ctxt_t *c,
}
}
+ if (!xml && path /* Not a --revprop */)
+ SVN_ERR(svn_cmdline_printf(pool, _("Properties on '%s':\n"), path));
+
for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
{
const char *pname = svn__apr_hash_index_key(hi);
@@ -1786,10 +1956,19 @@ do_plist(svnlook_ctxt_t *c,
else
{
const char *pname_stdout;
+ const char *indented_newval;
SVN_ERR(svn_cmdline_cstring_from_utf8(&pname_stdout, pname,
pool));
- printf(" %s : %s\n", pname_stdout, propval->data);
+ printf(" %s\n", pname_stdout);
+ /* Add an extra newline to the value before indenting, so that
+ every line of output has the indentation whether the value
+ already ended in a newline or not. */
+ indented_newval =
+ svn_cmdline__indent_string(apr_psprintf(pool, "%s\n",
+ propval->data),
+ " ", pool);
+ printf("%s", indented_newval);
}
}
else if (xml)
@@ -2171,7 +2350,9 @@ subcommand_pget(apr_getopt_t *os, void *
SVN_ERR(get_ctxt_baton(&c, opt_state, pool));
SVN_ERR(do_pget(c, opt_state->arg1,
- opt_state->revprop ? NULL : opt_state->arg2, pool));
+ opt_state->revprop ? NULL : opt_state->arg2,
+ opt_state->verbose, opt_state->show_inherited_props,
+ pool));
return SVN_NO_ERROR;
}
@@ -2186,7 +2367,8 @@ subcommand_plist(apr_getopt_t *os, void
SVN_ERR(get_ctxt_baton(&c, opt_state, pool));
SVN_ERR(do_plist(c, opt_state->revprop ? NULL : opt_state->arg1,
- opt_state->verbose, opt_state->xml, pool));
+ opt_state->verbose, opt_state->xml,
+ opt_state->show_inherited_props, pool));
return SVN_NO_ERROR;
}
@@ -2419,6 +2601,10 @@ main(int argc, const char *argv[])
opt_state.diff_cmd = opt_arg;
break;
+ case svnlook__show_inherited_props:
+ opt_state.show_inherited_props = TRUE;
+ break;
+
default:
SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
svn_pool_destroy(pool);
@@ -2434,6 +2620,13 @@ main(int argc, const char *argv[])
_("The '--transaction' (-t) and '--revision' (-r) arguments "
"cannot co-exist")));
+ /* The --show-inherited-props and --revprop options may not co-exist. */
+ if (opt_state.show_inherited_props && opt_state.revprop)
+ SVN_INT_ERR(svn_error_create
+ (SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
+ _("Cannot use the '--show-inherited-props' option with the "
+ "'--revprop' option")));
+
/* If the user asked for help, then the rest of the arguments are
the names of subcommands to get help on (if any), or else they're
just typos/mistakes. Whatever the case, the subcommand to
Modified: subversion/branches/tree-read-api/subversion/svnmucc/svnmucc.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/svnmucc/svnmucc.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/svnmucc/svnmucc.c (original)
+++ subversion/branches/tree-read-api/subversion/svnmucc/svnmucc.c Sun Jan 6 02:33:34 2013
@@ -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,38 +925,43 @@ 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));
- apr_pool_destroy(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));
+ svn_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)))