aboutsummaryrefslogtreecommitdiffstats
path: root/subversion/svn
diff options
context:
space:
mode:
authorPeter Wemm <peter@FreeBSD.org>2015-10-12 08:54:49 +0000
committerPeter Wemm <peter@FreeBSD.org>2015-10-12 08:54:49 +0000
commitdc5d469d6574e9fb03bdd793658bb371315b306a (patch)
tree013c2e6845398e5a9ca4901dcc077769c7520e1d /subversion/svn
parent58218291fa73a17020ef0447398e9e8a78f9e8c7 (diff)
downloadsrc-dc5d469d6574e9fb03bdd793658bb371315b306a.tar.gz
src-dc5d469d6574e9fb03bdd793658bb371315b306a.zip
Vendor import of subversion-1.9.2vendor/subversion/subversion-1.9.2
Notes
Notes: svn path=/vendor/subversion/dist/; revision=289177 svn path=/vendor/subversion/subversion-1.9.2/; revision=289178; tag=vendor/subversion/subversion-1.9.2
Diffstat (limited to 'subversion/svn')
-rw-r--r--subversion/svn/add-cmd.c2
-rw-r--r--subversion/svn/auth-cmd.c483
-rw-r--r--subversion/svn/blame-cmd.c55
-rw-r--r--subversion/svn/cat-cmd.c7
-rw-r--r--subversion/svn/changelist-cmd.c24
-rw-r--r--subversion/svn/checkout-cmd.c12
-rw-r--r--subversion/svn/cl-conflicts.c84
-rw-r--r--subversion/svn/cl-conflicts.h10
-rw-r--r--subversion/svn/cl-log.h105
-rw-r--r--subversion/svn/cl.h109
-rw-r--r--subversion/svn/cleanup-cmd.c66
-rw-r--r--subversion/svn/client_errors.h97
-rw-r--r--subversion/svn/commit-cmd.c4
-rw-r--r--subversion/svn/conflict-callbacks.c509
-rw-r--r--subversion/svn/copy-cmd.c8
-rw-r--r--subversion/svn/diff-cmd.c29
-rw-r--r--subversion/svn/export-cmd.c10
-rw-r--r--subversion/svn/file-merge.c19
-rw-r--r--subversion/svn/help-cmd.c51
-rw-r--r--subversion/svn/info-cmd.c429
-rw-r--r--subversion/svn/list-cmd.c13
-rw-r--r--subversion/svn/log-cmd.c158
-rw-r--r--subversion/svn/merge-cmd.c4
-rw-r--r--subversion/svn/mergeinfo-cmd.c157
-rw-r--r--subversion/svn/notify.c783
-rw-r--r--subversion/svn/propget-cmd.c69
-rw-r--r--subversion/svn/proplist-cmd.c8
-rw-r--r--subversion/svn/props.c159
-rw-r--r--subversion/svn/resolve-cmd.c2
-rw-r--r--subversion/svn/revert-cmd.c7
-rw-r--r--subversion/svn/similarity.c126
-rw-r--r--subversion/svn/status-cmd.c30
-rw-r--r--subversion/svn/status.c65
-rw-r--r--subversion/svn/svn.c796
-rw-r--r--subversion/svn/util.c62
35 files changed, 3004 insertions, 1548 deletions
diff --git a/subversion/svn/add-cmd.c b/subversion/svn/add-cmd.c
index 44f73c7bc35a..f0791fb0279e 100644
--- a/subversion/svn/add-cmd.c
+++ b/subversion/svn/add-cmd.c
@@ -83,7 +83,7 @@ svn_cl__add(apr_getopt_t *os,
errors, opt_state->quiet,
SVN_ERR_ENTRY_EXISTS,
SVN_ERR_WC_PATH_NOT_FOUND,
- SVN_NO_ERROR));
+ 0));
}
svn_pool_destroy(iterpool);
diff --git a/subversion/svn/auth-cmd.c b/subversion/svn/auth-cmd.c
new file mode 100644
index 000000000000..68ca067e736b
--- /dev/null
+++ b/subversion/svn/auth-cmd.c
@@ -0,0 +1,483 @@
+/*
+ * auth-cmd.c: Subversion auth creds cache administration
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+/*** Includes. ***/
+
+#include <apr_general.h>
+#include <apr_getopt.h>
+#include <apr_fnmatch.h>
+#include <apr_tables.h>
+
+#include "svn_private_config.h"
+
+#include "svn_private_config.h"
+#include "svn_pools.h"
+#include "svn_error.h"
+#include "svn_opt.h"
+#include "svn_dirent_uri.h"
+#include "svn_hash.h"
+#include "svn_utf.h"
+#include "svn_cmdline.h"
+#include "svn_config.h"
+#include "svn_auth.h"
+#include "svn_sorts.h"
+#include "svn_base64.h"
+#include "svn_x509.h"
+#include "svn_time.h"
+
+#include "private/svn_cmdline_private.h"
+#include "private/svn_token.h"
+#include "private/svn_sorts_private.h"
+
+#include "cl.h"
+
+/* The separator between credentials . */
+#define SEP_STRING \
+ "------------------------------------------------------------------------\n"
+
+static svn_error_t *
+show_cert_failures(const char *failure_string,
+ apr_pool_t *scratch_pool)
+{
+ unsigned int failures;
+
+ SVN_ERR(svn_cstring_atoui(&failures, failure_string));
+
+ if (0 == (failures & (SVN_AUTH_SSL_NOTYETVALID | SVN_AUTH_SSL_EXPIRED |
+ SVN_AUTH_SSL_CNMISMATCH | SVN_AUTH_SSL_UNKNOWNCA |
+ SVN_AUTH_SSL_OTHER)))
+ return SVN_NO_ERROR;
+
+ SVN_ERR(svn_cmdline_printf(
+ scratch_pool, _("Automatic certificate validity check failed "
+ "because:\n")));
+
+ if (failures & SVN_AUTH_SSL_NOTYETVALID)
+ SVN_ERR(svn_cmdline_printf(
+ scratch_pool, _(" The certificate is not yet valid.\n")));
+
+ if (failures & SVN_AUTH_SSL_EXPIRED)
+ SVN_ERR(svn_cmdline_printf(
+ scratch_pool, _(" The certificate has expired.\n")));
+
+ if (failures & SVN_AUTH_SSL_CNMISMATCH)
+ SVN_ERR(svn_cmdline_printf(
+ scratch_pool, _(" The certificate's Common Name (hostname) "
+ "does not match the remote hostname.\n")));
+
+ if (failures & SVN_AUTH_SSL_UNKNOWNCA)
+ SVN_ERR(svn_cmdline_printf(
+ scratch_pool, _(" The certificate issuer is unknown.\n")));
+
+ if (failures & SVN_AUTH_SSL_OTHER)
+ SVN_ERR(svn_cmdline_printf(
+ scratch_pool, _(" Unknown verification failure.\n")));
+
+ return SVN_NO_ERROR;
+}
+
+
+/* decodes from format we store certs in for auth creds and
+ * turns parsing errors into warnings if PRINT_WARNING is TRUE
+ * and ignores them otherwise. returns NULL if it couldn't
+ * parse a cert for any reason. */
+static svn_x509_certinfo_t *
+parse_certificate(const svn_string_t *ascii_cert,
+ svn_boolean_t print_warning,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_x509_certinfo_t *certinfo;
+ const svn_string_t *der_cert;
+ svn_error_t *err;
+
+ /* Convert header-less PEM to DER by undoing base64 encoding. */
+ der_cert = svn_base64_decode_string(ascii_cert, scratch_pool);
+
+ err = svn_x509_parse_cert(&certinfo, der_cert->data, der_cert->len,
+ result_pool, scratch_pool);
+ if (err)
+ {
+ /* Just display X.509 parsing errors as warnings and continue */
+ if (print_warning)
+ svn_handle_warning2(stderr, err, "svn: ");
+ svn_error_clear(err);
+ return NULL;
+ }
+
+ return certinfo;
+}
+
+
+struct walk_credentials_baton_t
+{
+ int matches;
+ svn_boolean_t list;
+ svn_boolean_t delete;
+ svn_boolean_t show_passwords;
+ apr_array_header_t *patterns;
+};
+
+static svn_boolean_t
+match_pattern(const char *pattern, const char *value,
+ svn_boolean_t caseblind, apr_pool_t *scratch_pool)
+{
+ const char *p = apr_psprintf(scratch_pool, "*%s*", pattern);
+ int flags = (caseblind ? APR_FNM_CASE_BLIND : 0);
+
+ return (apr_fnmatch(p, value, flags) == APR_SUCCESS);
+}
+
+static svn_boolean_t
+match_certificate(svn_x509_certinfo_t **certinfo,
+ const char *pattern,
+ const svn_string_t *ascii_cert,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const char *value;
+ const svn_checksum_t *checksum;
+ const apr_array_header_t *hostnames;
+ int i;
+
+ *certinfo = parse_certificate(ascii_cert, FALSE, result_pool, scratch_pool);
+ if (*certinfo == NULL)
+ return FALSE;
+
+ value = svn_x509_certinfo_get_subject(*certinfo, scratch_pool);
+ if (match_pattern(pattern, value, FALSE, scratch_pool))
+ return TRUE;
+
+ value = svn_x509_certinfo_get_issuer(*certinfo, scratch_pool);
+ if (match_pattern(pattern, value, FALSE, scratch_pool))
+ return TRUE;
+
+ checksum = svn_x509_certinfo_get_digest(*certinfo);
+ value = svn_checksum_to_cstring_display(checksum, scratch_pool);
+ if (match_pattern(pattern, value, TRUE, scratch_pool))
+ return TRUE;
+
+ hostnames = svn_x509_certinfo_get_hostnames(*certinfo);
+ if (hostnames)
+ {
+ for (i = 0; i < hostnames->nelts; i++)
+ {
+ const char *hostname = APR_ARRAY_IDX(hostnames, i, const char *);
+ if (match_pattern(pattern, hostname, TRUE, scratch_pool))
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+static svn_error_t *
+match_credential(svn_boolean_t *match,
+ svn_x509_certinfo_t **certinfo,
+ const char *cred_kind,
+ const char *realmstring,
+ apr_array_header_t *patterns,
+ apr_array_header_t *cred_items,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ int i;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+ *match = FALSE;
+
+ for (i = 0; i < patterns->nelts; i++)
+ {
+ const char *pattern = APR_ARRAY_IDX(patterns, i, const char *);
+ int j;
+
+ *match = match_pattern(pattern, cred_kind, FALSE, iterpool);
+ if (!*match)
+ *match = match_pattern(pattern, realmstring, FALSE, iterpool);
+ if (!*match)
+ {
+ svn_pool_clear(iterpool);
+ for (j = 0; j < cred_items->nelts; j++)
+ {
+ svn_sort__item_t item;
+ const char *key;
+ svn_string_t *value;
+
+ item = APR_ARRAY_IDX(cred_items, j, svn_sort__item_t);
+ key = item.key;
+ value = item.value;
+ if (strcmp(key, SVN_CONFIG_AUTHN_PASSWORD_KEY) == 0 ||
+ strcmp(key, SVN_CONFIG_AUTHN_PASSPHRASE_KEY) == 0)
+ continue; /* don't match secrets */
+ else if (strcmp(key, SVN_CONFIG_AUTHN_ASCII_CERT_KEY) == 0)
+ *match = match_certificate(certinfo, pattern, value,
+ result_pool, iterpool);
+ else
+ *match = match_pattern(pattern, value->data, FALSE, iterpool);
+
+ if (*match)
+ break;
+ }
+ }
+ if (!*match)
+ break;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+show_cert(svn_x509_certinfo_t *certinfo, const svn_string_t *pem_cert,
+ apr_pool_t *scratch_pool)
+{
+ const apr_array_header_t *hostnames;
+
+ if (certinfo == NULL)
+ certinfo = parse_certificate(pem_cert, TRUE, scratch_pool, scratch_pool);
+ if (certinfo == NULL)
+ return SVN_NO_ERROR;
+
+ SVN_ERR(svn_cmdline_printf(scratch_pool, _("Subject: %s\n"),
+ svn_x509_certinfo_get_subject(certinfo, scratch_pool)));
+ SVN_ERR(svn_cmdline_printf(scratch_pool, _("Valid from: %s\n"),
+ svn_time_to_human_cstring(
+ svn_x509_certinfo_get_valid_from(certinfo),
+ scratch_pool)));
+ SVN_ERR(svn_cmdline_printf(scratch_pool, _("Valid until: %s\n"),
+ svn_time_to_human_cstring(
+ svn_x509_certinfo_get_valid_to(certinfo),
+ scratch_pool)));
+ SVN_ERR(svn_cmdline_printf(scratch_pool, _("Issuer: %s\n"),
+ svn_x509_certinfo_get_issuer(certinfo, scratch_pool)));
+ SVN_ERR(svn_cmdline_printf(scratch_pool, _("Fingerprint: %s\n"),
+ svn_checksum_to_cstring_display(
+ svn_x509_certinfo_get_digest(certinfo),
+ scratch_pool)));
+
+ hostnames = svn_x509_certinfo_get_hostnames(certinfo);
+ if (hostnames && !apr_is_empty_array(hostnames))
+ {
+ int i;
+ svn_stringbuf_t *buf = svn_stringbuf_create_empty(scratch_pool);
+ for (i = 0; i < hostnames->nelts; ++i)
+ {
+ const char *hostname = APR_ARRAY_IDX(hostnames, i, const char*);
+ if (i > 0)
+ svn_stringbuf_appendbytes(buf, ", ", 2);
+ svn_stringbuf_appendbytes(buf, hostname, strlen(hostname));
+ }
+ SVN_ERR(svn_cmdline_printf(scratch_pool, _("Hostnames: %s\n"),
+ buf->data));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+list_credential(const char *cred_kind,
+ const char *realmstring,
+ apr_array_header_t *cred_items,
+ svn_boolean_t show_passwords,
+ svn_x509_certinfo_t *certinfo,
+ apr_pool_t *scratch_pool)
+{
+ int i;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+ SVN_ERR(svn_cmdline_printf(scratch_pool, SEP_STRING));
+ SVN_ERR(svn_cmdline_printf(scratch_pool,
+ _("Credential kind: %s\n"), cred_kind));
+ SVN_ERR(svn_cmdline_printf(scratch_pool,
+ _("Authentication realm: %s\n"), realmstring));
+
+ for (i = 0; i < cred_items->nelts; i++)
+ {
+ svn_sort__item_t item;
+ const char *key;
+ svn_string_t *value;
+
+ svn_pool_clear(iterpool);
+ item = APR_ARRAY_IDX(cred_items, i, svn_sort__item_t);
+ key = item.key;
+ value = item.value;
+ if (strcmp(value->data, realmstring) == 0)
+ continue; /* realm string was already shown above */
+ else if (strcmp(key, SVN_CONFIG_AUTHN_PASSWORD_KEY) == 0)
+ {
+ if (show_passwords)
+ SVN_ERR(svn_cmdline_printf(iterpool,
+ _("Password: %s\n"), value->data));
+ else
+ SVN_ERR(svn_cmdline_printf(iterpool, _("Password: [not shown]\n")));
+ }
+ else if (strcmp(key, SVN_CONFIG_AUTHN_PASSPHRASE_KEY) == 0)
+ {
+ if (show_passwords)
+ SVN_ERR(svn_cmdline_printf(iterpool,
+ _("Passphrase: %s\n"), value->data));
+ else
+ SVN_ERR(svn_cmdline_printf(iterpool,
+ _("Passphrase: [not shown]\n")));
+ }
+ else if (strcmp(key, SVN_CONFIG_AUTHN_PASSTYPE_KEY) == 0)
+ SVN_ERR(svn_cmdline_printf(iterpool, _("Password cache: %s\n"),
+ value->data));
+ else if (strcmp(key, SVN_CONFIG_AUTHN_USERNAME_KEY) == 0)
+ SVN_ERR(svn_cmdline_printf(iterpool, _("Username: %s\n"), value->data));
+ else if (strcmp(key, SVN_CONFIG_AUTHN_ASCII_CERT_KEY) == 0)
+ SVN_ERR(show_cert(certinfo, value, iterpool));
+ else if (strcmp(key, SVN_CONFIG_AUTHN_FAILURES_KEY) == 0)
+ SVN_ERR(show_cert_failures(value->data, iterpool));
+ else
+ SVN_ERR(svn_cmdline_printf(iterpool, "%s: %s\n", key, value->data));
+ }
+ svn_pool_destroy(iterpool);
+
+ SVN_ERR(svn_cmdline_printf(scratch_pool, "\n"));
+ return SVN_NO_ERROR;
+}
+
+/* This implements `svn_config_auth_walk_func_t` */
+static svn_error_t *
+walk_credentials(svn_boolean_t *delete_cred,
+ void *baton,
+ const char *cred_kind,
+ const char *realmstring,
+ apr_hash_t *cred_hash,
+ apr_pool_t *scratch_pool)
+{
+ struct walk_credentials_baton_t *b = baton;
+ apr_array_header_t *sorted_cred_items;
+ svn_x509_certinfo_t *certinfo = NULL;
+
+ *delete_cred = FALSE;
+
+ sorted_cred_items = svn_sort__hash(cred_hash,
+ svn_sort_compare_items_lexically,
+ scratch_pool);
+ if (b->patterns->nelts > 0)
+ {
+ svn_boolean_t match;
+
+ SVN_ERR(match_credential(&match, &certinfo, cred_kind, realmstring,
+ b->patterns, sorted_cred_items,
+ scratch_pool, scratch_pool));
+ if (!match)
+ return SVN_NO_ERROR;
+ }
+
+ b->matches++;
+
+ if (b->list)
+ SVN_ERR(list_credential(cred_kind, realmstring, sorted_cred_items,
+ b->show_passwords, certinfo, scratch_pool));
+ if (b->delete)
+ {
+ *delete_cred = TRUE;
+ SVN_ERR(svn_cmdline_printf(scratch_pool,
+ _("Deleting %s credential for realm '%s'\n"),
+ cred_kind, realmstring));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+/* This implements `svn_opt_subcommand_t'. */
+svn_error_t *
+svn_cl__auth(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+{
+ svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
+ const char *config_path;
+ struct walk_credentials_baton_t b;
+
+ b.matches = 0;
+ b.show_passwords = opt_state->show_passwords;
+ b.list = !opt_state->remove;
+ b.delete = opt_state->remove;
+ b.patterns = apr_array_make(pool, 1, sizeof(const char *));
+ for (; os->ind < os->argc; os->ind++)
+ {
+ /* The apr_getopt targets are still in native encoding. */
+ const char *raw_target = os->argv[os->ind];
+ const char *utf8_target;
+
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_target,
+ raw_target, pool));
+ APR_ARRAY_PUSH(b.patterns, const char *) = utf8_target;
+ }
+
+ SVN_ERR(svn_config_get_user_config_path(&config_path,
+ opt_state->config_dir, NULL,
+ pool));
+
+ if (b.delete && b.patterns->nelts < 1)
+ return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);
+
+ SVN_ERR(svn_config_walk_auth_data(config_path, walk_credentials, &b, pool));
+
+ if (b.list)
+ {
+ if (b.matches == 0)
+ {
+ if (b.patterns->nelts == 0)
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("Credentials cache in '%s' is empty\n"),
+ svn_dirent_local_style(config_path, pool)));
+ else
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, 0,
+ _("Credentials cache in '%s' contains "
+ "no matching credentials"),
+ svn_dirent_local_style(config_path, pool));
+ }
+ else
+ {
+ if (b.patterns->nelts == 0)
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("Credentials cache in '%s' contains %d credentials\n"),
+ svn_dirent_local_style(config_path, pool), b.matches));
+ else
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("Credentials cache in '%s' contains %d matching "
+ "credentials\n"),
+ svn_dirent_local_style(config_path, pool), b.matches));
+ }
+
+ }
+
+ if (b.delete)
+ {
+ if (b.matches == 0)
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, 0,
+ _("Credentials cache in '%s' contains "
+ "no matching credentials"),
+ svn_dirent_local_style(config_path, pool));
+ else
+ SVN_ERR(svn_cmdline_printf(pool, _("Deleted %d matching credentials "
+ "from '%s'\n"), b.matches,
+ svn_dirent_local_style(config_path, pool)));
+ }
+
+ return SVN_NO_ERROR;
+}
diff --git a/subversion/svn/blame-cmd.c b/subversion/svn/blame-cmd.c
index 174a199fe898..3911a64258f8 100644
--- a/subversion/svn/blame-cmd.c
+++ b/subversion/svn/blame-cmd.c
@@ -31,6 +31,7 @@
#include "svn_pools.h"
#include "svn_props.h"
#include "svn_cmdline.h"
+#include "svn_sorts.h"
#include "svn_xml.h"
#include "svn_time.h"
#include "cl.h"
@@ -42,6 +43,8 @@ typedef struct blame_baton_t
svn_cl__opt_state_t *opt_state;
svn_stream_t *out;
svn_stringbuf_t *sbuf;
+
+ int rev_maxlength;
} blame_baton_t;
@@ -63,9 +66,9 @@ blame_receiver_xml(void *baton,
svn_boolean_t local_change,
apr_pool_t *pool)
{
- svn_cl__opt_state_t *opt_state =
- ((blame_baton_t *) baton)->opt_state;
- svn_stringbuf_t *sb = ((blame_baton_t *) baton)->sbuf;
+ blame_baton_t *bb = baton;
+ svn_cl__opt_state_t *opt_state = bb->opt_state;
+ svn_stringbuf_t *sb = bb->sbuf;
/* "<entry ...>" */
/* line_no is 0-based, but the rest of the world is probably Pascal
@@ -74,7 +77,7 @@ blame_receiver_xml(void *baton,
"line-number",
apr_psprintf(pool, "%" APR_INT64_T_FMT,
line_no + 1),
- NULL);
+ SVN_VA_NULL);
if (SVN_IS_VALID_REVNUM(revision))
svn_cl__print_xml_commit(&sb, revision,
@@ -88,7 +91,7 @@ blame_receiver_xml(void *baton,
{
/* "<merged>" */
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "merged",
- "path", merged_path, NULL);
+ "path", merged_path, SVN_VA_NULL);
svn_cl__print_xml_commit(&sb, merged_revision,
svn_prop_get_value(merged_rev_props,
@@ -119,23 +122,13 @@ print_line_info(svn_stream_t *out,
const char *date,
const char *path,
svn_boolean_t verbose,
- svn_revnum_t end_revnum,
+ int rev_maxlength,
apr_pool_t *pool)
{
const char *time_utf8;
const char *time_stdout;
const char *rev_str;
- int rev_maxlength;
- /* The standard column width for the revision number is 6 characters.
- If the revision number can potentially be larger (i.e. if the end_revnum
- is larger than 1000000), we increase the column width as needed. */
- rev_maxlength = 6;
- while (end_revnum >= 1000000)
- {
- rev_maxlength++;
- end_revnum = end_revnum / 10;
- }
rev_str = SVN_IS_VALID_REVNUM(revision)
? apr_psprintf(pool, "%*ld", rev_maxlength, revision)
: apr_psprintf(pool, "%*s", rev_maxlength, "-");
@@ -189,11 +182,26 @@ blame_receiver(void *baton,
svn_boolean_t local_change,
apr_pool_t *pool)
{
- svn_cl__opt_state_t *opt_state =
- ((blame_baton_t *) baton)->opt_state;
- svn_stream_t *out = ((blame_baton_t *)baton)->out;
+ blame_baton_t *bb = baton;
+ svn_cl__opt_state_t *opt_state = bb->opt_state;
+ svn_stream_t *out = bb->out;
svn_boolean_t use_merged = FALSE;
+ if (!bb->rev_maxlength)
+ {
+ svn_revnum_t max_revnum = MAX(start_revnum, end_revnum);
+ /* The standard column width for the revision number is 6 characters.
+ If the revision number can potentially be larger (i.e. if the end_revnum
+ is larger than 1000000), we increase the column width as needed. */
+
+ bb->rev_maxlength = 6;
+ while (max_revnum >= 1000000)
+ {
+ bb->rev_maxlength++;
+ max_revnum = max_revnum / 10;
+ }
+ }
+
if (opt_state->use_merge_history)
{
/* Choose which revision to use. If they aren't equal, prefer the
@@ -216,7 +224,8 @@ blame_receiver(void *baton,
SVN_PROP_REVISION_AUTHOR),
svn_prop_get_value(merged_rev_props,
SVN_PROP_REVISION_DATE),
- merged_path, opt_state->verbose, end_revnum,
+ merged_path, opt_state->verbose,
+ bb->rev_maxlength,
pool));
else
SVN_ERR(print_line_info(out, revision,
@@ -224,7 +233,8 @@ blame_receiver(void *baton,
SVN_PROP_REVISION_AUTHOR),
svn_prop_get_value(rev_props,
SVN_PROP_REVISION_DATE),
- NULL, opt_state->verbose, end_revnum,
+ NULL, opt_state->verbose,
+ bb->rev_maxlength,
pool));
return svn_stream_printf(out, pool, "%s%s", line, APR_EOL_STR);
@@ -286,6 +296,7 @@ svn_cl__blame(apr_getopt_t *os,
bl.sbuf = svn_stringbuf_create_empty(pool);
bl.opt_state = opt_state;
+ bl.rev_maxlength = 0;
subpool = svn_pool_create(pool);
@@ -350,7 +361,7 @@ svn_cl__blame(apr_getopt_t *os,
if (! svn_path_is_url(target))
outpath = svn_dirent_local_style(truepath, subpool);
svn_xml_make_open_tag(&bl.sbuf, pool, svn_xml_normal, "target",
- "path", outpath, NULL);
+ "path", outpath, SVN_VA_NULL);
receiver = blame_receiver_xml;
}
diff --git a/subversion/svn/cat-cmd.c b/subversion/svn/cat-cmd.c
index 551420e7fa5b..eef7696ce2bb 100644
--- a/subversion/svn/cat-cmd.c
+++ b/subversion/svn/cat-cmd.c
@@ -76,15 +76,16 @@ svn_cl__cat(apr_getopt_t *os,
SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target,
subpool));
- SVN_ERR(svn_cl__try(svn_client_cat2(out, truepath, &peg_revision,
+ SVN_ERR(svn_cl__try(svn_client_cat3(NULL, out, truepath, &peg_revision,
&(opt_state->start_revision),
- ctx, subpool),
+ !opt_state->ignore_keywords,
+ ctx, subpool, subpool),
errors, opt_state->quiet,
SVN_ERR_UNVERSIONED_RESOURCE,
SVN_ERR_ENTRY_NOT_FOUND,
SVN_ERR_CLIENT_IS_DIRECTORY,
SVN_ERR_FS_NOT_FOUND,
- SVN_NO_ERROR));
+ 0));
}
svn_pool_destroy(subpool);
diff --git a/subversion/svn/changelist-cmd.c b/subversion/svn/changelist-cmd.c
index 46347b65b0f3..27de62b11f65 100644
--- a/subversion/svn/changelist-cmd.c
+++ b/subversion/svn/changelist-cmd.c
@@ -72,25 +72,7 @@ svn_cl__changelist(apr_getopt_t *os,
SVN_ERR(svn_cl__check_targets_are_local_paths(targets));
if (opt_state->quiet)
- /* FIXME: This is required because svn_client_create_context()
- always initializes ctx->notify_func2 to a wrapper function
- which calls ctx->notify_func() if it isn't NULL. In other
- words, typically, ctx->notify_func2 is never NULL. This isn't
- usually a problem, but the changelist logic generates
- svn_error_t's as part of its notification.
-
- So, svn_wc_set_changelist() checks its notify_func (our
- ctx->notify_func2) for NULL-ness, and seeing non-NULL-ness,
- generates a notificaton object and svn_error_t to describe some
- problem. It passes that off to its notify_func (our
- ctx->notify_func2) which drops the notification on the floor
- (because it wraps a NULL ctx->notify_func). But svn_error_t's
- dropped on the floor cause SEGFAULTs at pool cleanup time --
- they need instead to be cleared.
-
- SOOOooo... we set our ctx->notify_func2 to NULL so the WC code
- doesn't even generate the errors. */
- ctx->notify_func2 = NULL;
+ ctx->notify_func2 = NULL; /* Easy out: avoid unneeded work */
if (depth == svn_depth_unknown)
depth = svn_depth_empty;
@@ -106,7 +88,7 @@ svn_cl__changelist(apr_getopt_t *os,
errors, opt_state->quiet,
SVN_ERR_UNVERSIONED_RESOURCE,
SVN_ERR_WC_PATH_NOT_FOUND,
- SVN_NO_ERROR));
+ 0));
}
else
{
@@ -117,7 +99,7 @@ svn_cl__changelist(apr_getopt_t *os,
errors, opt_state->quiet,
SVN_ERR_UNVERSIONED_RESOURCE,
SVN_ERR_WC_PATH_NOT_FOUND,
- SVN_NO_ERROR));
+ 0));
}
if (errors->nelts > 0)
diff --git a/subversion/svn/checkout-cmd.c b/subversion/svn/checkout-cmd.c
index 6c192a033a07..56fd02b03c1c 100644
--- a/subversion/svn/checkout-cmd.c
+++ b/subversion/svn/checkout-cmd.c
@@ -72,6 +72,7 @@ svn_cl__checkout(apr_getopt_t *os,
svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
apr_pool_t *subpool;
apr_array_header_t *targets;
+ struct svn_cl__check_externals_failed_notify_baton nwb;
const char *last_target, *local_dir;
int i;
@@ -113,6 +114,12 @@ svn_cl__checkout(apr_getopt_t *os,
if (! opt_state->quiet)
SVN_ERR(svn_cl__notifier_mark_checkout(ctx->notify_baton2));
+ nwb.wrapped_func = ctx->notify_func2;
+ nwb.wrapped_baton = ctx->notify_baton2;
+ nwb.had_externals_error = FALSE;
+ ctx->notify_func2 = svn_cl__check_externals_failed_notify_wrapper;
+ ctx->notify_baton2 = &nwb;
+
subpool = svn_pool_create(pool);
for (i = 0; i < targets->nelts; ++i)
{
@@ -169,5 +176,10 @@ svn_cl__checkout(apr_getopt_t *os,
}
svn_pool_destroy(subpool);
+ if (nwb.had_externals_error)
+ return svn_error_create(SVN_ERR_CL_ERROR_PROCESSING_EXTERNALS, NULL,
+ _("Failure occurred processing one or "
+ "more externals definitions"));
+
return SVN_NO_ERROR;
}
diff --git a/subversion/svn/cl-conflicts.c b/subversion/svn/cl-conflicts.c
index 440c9d76fd09..8507e8c3b309 100644
--- a/subversion/svn/cl-conflicts.c
+++ b/subversion/svn/cl-conflicts.c
@@ -69,11 +69,13 @@ static const svn_token_map_t map_conflict_kind_xml[] =
/* Return a localised string representation of the local part of a conflict;
NULL for non-localised odd cases. */
static const char *
-local_reason_str(svn_node_kind_t kind, svn_wc_conflict_reason_t reason)
+local_reason_str(svn_node_kind_t kind, svn_wc_conflict_reason_t reason,
+ svn_wc_operation_t operation)
{
switch (kind)
{
case svn_node_file:
+ case svn_node_symlink:
switch (reason)
{
case svn_wc_conflict_reason_edited:
@@ -83,7 +85,10 @@ local_reason_str(svn_node_kind_t kind, svn_wc_conflict_reason_t reason)
case svn_wc_conflict_reason_deleted:
return _("local file delete");
case svn_wc_conflict_reason_missing:
- return _("local file missing");
+ if (operation == svn_wc_operation_merge)
+ return _("local file missing or deleted or moved away");
+ else
+ return _("local file missing");
case svn_wc_conflict_reason_unversioned:
return _("local file unversioned");
case svn_wc_conflict_reason_added:
@@ -106,7 +111,10 @@ local_reason_str(svn_node_kind_t kind, svn_wc_conflict_reason_t reason)
case svn_wc_conflict_reason_deleted:
return _("local dir delete");
case svn_wc_conflict_reason_missing:
- return _("local dir missing");
+ if (operation == svn_wc_operation_merge)
+ return _("local dir missing or deleted or moved away");
+ else
+ return _("local dir missing");
case svn_wc_conflict_reason_unversioned:
return _("local dir unversioned");
case svn_wc_conflict_reason_added:
@@ -119,9 +127,32 @@ local_reason_str(svn_node_kind_t kind, svn_wc_conflict_reason_t reason)
return _("local dir moved here");
}
break;
- case svn_node_symlink:
case svn_node_none:
case svn_node_unknown:
+ switch (reason)
+ {
+ case svn_wc_conflict_reason_edited:
+ return _("local edit");
+ case svn_wc_conflict_reason_obstructed:
+ return _("local obstruction");
+ case svn_wc_conflict_reason_deleted:
+ return _("local delete");
+ case svn_wc_conflict_reason_missing:
+ if (operation == svn_wc_operation_merge)
+ return _("local missing or deleted or moved away");
+ else
+ return _("local missing");
+ case svn_wc_conflict_reason_unversioned:
+ return _("local unversioned");
+ case svn_wc_conflict_reason_added:
+ return _("local add");
+ case svn_wc_conflict_reason_replaced:
+ return _("local replace");
+ case svn_wc_conflict_reason_moved_away:
+ return _("local moved away");
+ case svn_wc_conflict_reason_moved_here:
+ return _("local moved here");
+ }
break;
}
return NULL;
@@ -135,6 +166,7 @@ incoming_action_str(svn_node_kind_t kind, svn_wc_conflict_action_t action)
switch (kind)
{
case svn_node_file:
+ case svn_node_symlink:
switch (action)
{
case svn_wc_conflict_action_edit:
@@ -142,9 +174,9 @@ incoming_action_str(svn_node_kind_t kind, svn_wc_conflict_action_t action)
case svn_wc_conflict_action_add:
return _("incoming file add");
case svn_wc_conflict_action_delete:
- return _("incoming file delete");
+ return _("incoming file delete or move");
case svn_wc_conflict_action_replace:
- return _("incoming file replace");
+ return _("incoming replace with file");
}
break;
case svn_node_dir:
@@ -155,14 +187,24 @@ incoming_action_str(svn_node_kind_t kind, svn_wc_conflict_action_t action)
case svn_wc_conflict_action_add:
return _("incoming dir add");
case svn_wc_conflict_action_delete:
- return _("incoming dir delete");
+ return _("incoming dir delete or move");
case svn_wc_conflict_action_replace:
- return _("incoming dir replace");
+ return _("incoming replace with dir");
}
break;
- case svn_node_symlink:
case svn_node_none:
case svn_node_unknown:
+ switch (action)
+ {
+ case svn_wc_conflict_action_edit:
+ return _("incoming edit");
+ case svn_wc_conflict_action_add:
+ return _("incoming add");
+ case svn_wc_conflict_action_delete:
+ return _("incoming delete or move");
+ case svn_wc_conflict_action_replace:
+ return _("incoming replace");
+ }
break;
}
return NULL;
@@ -267,7 +309,8 @@ svn_cl__get_human_readable_tree_conflict_description(
incoming_kind = conflict->src_right_version->node_kind;
}
- reason = local_reason_str(conflict->node_kind, conflict->reason);
+ reason = local_reason_str(conflict->node_kind, conflict->reason,
+ conflict->operation);
action = incoming_action_str(incoming_kind, conflict->action);
operation = operation_str(conflict->operation);
SVN_ERR_ASSERT(operation);
@@ -294,6 +337,27 @@ svn_cl__get_human_readable_tree_conflict_description(
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_cl__get_human_readable_action_description(
+ const char **desc,
+ svn_wc_conflict_action_t action,
+ svn_wc_operation_t operation,
+ svn_node_kind_t kind,
+ apr_pool_t *pool)
+{
+ const char *action_s, *operation_s;
+
+ action_s = incoming_action_str(kind, action);
+ operation_s = operation_str(operation);
+
+ SVN_ERR_ASSERT(operation_s);
+
+ *desc = apr_psprintf(pool, _("%s %s"),
+ action_s, operation_s);
+
+ return SVN_NO_ERROR;
+}
+
/* Helper for svn_cl__append_tree_conflict_info_xml().
* Appends the attributes of the given VERSION to ATT_HASH.
diff --git a/subversion/svn/cl-conflicts.h b/subversion/svn/cl-conflicts.h
index 07591a0ef02c..d4880748cd9c 100644
--- a/subversion/svn/cl-conflicts.h
+++ b/subversion/svn/cl-conflicts.h
@@ -63,6 +63,16 @@ svn_cl__get_human_readable_tree_conflict_description(
const svn_wc_conflict_description2_t *conflict,
apr_pool_t *pool);
+/* Like svn_cl__get_human_readable_tree_conflict_description but
+ for other conflict types */
+svn_error_t *
+svn_cl__get_human_readable_action_description(
+ const char **desc,
+ svn_wc_conflict_action_t action,
+ svn_wc_operation_t operation,
+ svn_node_kind_t kind,
+ apr_pool_t *pool);
+
/**
* Append to @a str an XML representation of the conflict data
* for @a conflict, in a format suitable for 'svn info --xml'.
diff --git a/subversion/svn/cl-log.h b/subversion/svn/cl-log.h
new file mode 100644
index 000000000000..5b4c7aa7a68b
--- /dev/null
+++ b/subversion/svn/cl-log.h
@@ -0,0 +1,105 @@
+/*
+ * cl-log.h: Log entry receiver
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+
+
+#ifndef SVN_CL_LOG_H
+#define SVN_CL_LOG_H
+
+/*** Includes. ***/
+#include <apr_pools.h>
+
+#include "svn_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+
+/* The separator between log messages. */
+#define SVN_CL__LOG_SEP_STRING \
+ "------------------------------------------------------------------------\n"
+
+/* Baton for log_entry_receiver() and log_entry_receiver_xml(). */
+typedef struct svn_cl__log_receiver_baton
+{
+ /* Client context. */
+ svn_client_ctx_t *ctx;
+
+ /* The target of the log operation. */
+ const char *target_path_or_url;
+ svn_opt_revision_t target_peg_revision;
+
+ /* Don't print log message body nor its line count. */
+ svn_boolean_t omit_log_message;
+
+ /* Whether to show diffs in the log. (maps to --diff) */
+ svn_boolean_t show_diff;
+
+ /* Depth applied to diff output. */
+ svn_depth_t depth;
+
+ /* Diff arguments received from command line. */
+ const char *diff_extensions;
+
+ /* Stack which keeps track of merge revision nesting, using svn_revnum_t's */
+ apr_array_header_t *merge_stack;
+
+ /* Log message search patterns. Log entries will only be shown if the author,
+ * the log message, or a changed path matches one of these patterns. */
+ apr_array_header_t *search_patterns;
+
+ /* Pool for persistent allocations. */
+ apr_pool_t *pool;
+} svn_cl__log_receiver_baton;
+
+/* Implement `svn_log_entry_receiver_t', printing the logs in
+ * a human-readable and machine-parseable format.
+ *
+ * BATON is of type `struct svn_cl__log_receiver_baton'.
+ *
+ * First, print a header line. Then if CHANGED_PATHS is non-null,
+ * print all affected paths in a list headed "Changed paths:\n",
+ * immediately following the header line. Then print a newline
+ * followed by the message body, unless BATON->omit_log_message is true.
+ */
+svn_error_t *
+svn_cl__log_entry_receiver(void *baton,
+ svn_log_entry_t *log_entry,
+ apr_pool_t *pool);
+
+/* This implements `svn_log_entry_receiver_t', printing the logs in XML.
+ *
+ * BATON is of type `struct svn_cl__log_receiver_baton'.
+ */
+svn_error_t *
+svn_cl__log_entry_receiver_xml(void *baton,
+ svn_log_entry_t *log_entry,
+ apr_pool_t *pool);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SVN_CL_LOG_H */
diff --git a/subversion/svn/cl.h b/subversion/svn/cl.h
index 8a732c7e8a41..42e770e075c5 100644
--- a/subversion/svn/cl.h
+++ b/subversion/svn/cl.h
@@ -158,7 +158,7 @@ typedef struct svn_cl__opt_state_t
/* Was --no-unlock specified? */
svn_boolean_t no_unlock;
- const char *message; /* log message */
+ const char *message; /* log message (not converted to UTF-8) */
svn_boolean_t force; /* be more forceful, as in "svn rm -f ..." */
svn_boolean_t force_log; /* force validity of a suspect log msg file */
svn_boolean_t incremental; /* yield output suitable for concatenation */
@@ -167,20 +167,22 @@ typedef struct svn_cl__opt_state_t
svn_boolean_t version; /* print version information */
svn_boolean_t verbose; /* be verbose */
svn_boolean_t update; /* contact the server for the full story */
- svn_boolean_t strict; /* do strictly what was requested */
- svn_stringbuf_t *filedata; /* contents of file used as option data */
- const char *encoding; /* the locale/encoding of the data*/
+ svn_stringbuf_t *filedata; /* contents of file used as option data
+ (not converted to UTF-8) */
+ const char *encoding; /* the locale/encoding of 'message' and of
+ 'filedata' (not converted to UTF-8) */
svn_boolean_t help; /* print usage message */
- const char *auth_username; /* auth username */ /* UTF-8! */
- const char *auth_password; /* auth password */ /* UTF-8! */
- const char *extensions; /* subprocess extension args */ /* UTF-8! */
- apr_array_header_t *targets; /* target list from file */ /* UTF-8! */
+ const char *auth_username; /* auth username */
+ const char *auth_password; /* auth password */
+ const char *extensions; /* subprocess extension args */
+ apr_array_header_t *targets; /* target list from file */
svn_boolean_t xml; /* output in xml, e.g., "svn log --xml" */
svn_boolean_t no_ignore; /* disregard default ignores & svn:ignore's */
svn_boolean_t no_auth_cache; /* do not cache authentication information */
struct
{
- const char *diff_cmd; /* the external diff command to use */
+ const char *diff_cmd; /* the external diff command to use
+ (not converted to UTF-8) */
svn_boolean_t internal_diff; /* override diff_cmd in config file */
svn_boolean_t no_diff_added; /* do not show diffs for deleted files */
svn_boolean_t no_diff_deleted; /* do not show diffs for deleted files */
@@ -197,8 +199,10 @@ typedef struct svn_cl__opt_state_t
svn_boolean_t stop_on_copy; /* don't cross copies during processing */
svn_boolean_t dry_run; /* try operation but make no changes */
svn_boolean_t revprop; /* operate on a revision property */
- const char *merge_cmd; /* the external merge command to use */
- const char *editor_cmd; /* the external editor command to use */
+ const char *merge_cmd; /* the external merge command to use
+ (not converted to UTF-8) */
+ const char *editor_cmd; /* the external editor command to use
+ (not converted to UTF-8) */
svn_boolean_t record_only; /* whether to record mergeinfo */
const char *old_target; /* diff target */
const char *new_target; /* diff target */
@@ -210,21 +214,24 @@ typedef struct svn_cl__opt_state_t
const char *native_eol; /* override system standard eol marker */
svn_boolean_t remove; /* deassociate a changelist */
apr_array_header_t *changelists; /* changelist filters */
- const char *changelist; /* operate on this changelist
- THIS IS TEMPORARY (LAST OF CHANGELISTS) */
svn_boolean_t keep_changelists;/* don't remove changelists after commit */
svn_boolean_t keep_local; /* delete path only from repository */
svn_boolean_t all_revprops; /* retrieve all revprops */
svn_boolean_t no_revprops; /* retrieve no revprops */
- apr_hash_t *revprop_table; /* table of revision properties to get/set */
+ apr_hash_t *revprop_table; /* table of revision properties to get/set
+ (not converted to UTF-8) */
svn_boolean_t parents; /* create intermediate directories */
svn_boolean_t use_merge_history; /* use/display extra merge information */
svn_cl__accept_t accept_which; /* how to handle conflicts */
svn_cl__show_revs_t show_revs; /* mergeinfo flavor */
svn_depth_t set_depth; /* new sticky ambient depth value */
svn_boolean_t reintegrate; /* use "reintegrate" merge-source heuristic */
- svn_boolean_t trust_server_cert; /* trust server SSL certs that would
- otherwise be rejected as "untrusted" */
+ /* trust server SSL certs that would otherwise be rejected as "untrusted" */
+ svn_boolean_t trust_server_cert_unknown_ca;
+ svn_boolean_t trust_server_cert_cn_mismatch;
+ svn_boolean_t trust_server_cert_expired;
+ svn_boolean_t trust_server_cert_not_yet_valid;
+ svn_boolean_t trust_server_cert_other_failure;
int strip; /* number of leading path components to strip */
svn_boolean_t ignore_keywords; /* do not expand keywords */
svn_boolean_t reverse_diff; /* reverse a diff (e.g. when patching) */
@@ -235,6 +242,13 @@ typedef struct svn_cl__opt_state_t
svn_boolean_t include_externals; /* Recurses (in)to file & dir externals */
svn_boolean_t show_inherited_props; /* get inherited properties */
apr_array_header_t* search_patterns; /* pattern arguments for --search */
+ svn_boolean_t mergeinfo_log; /* show log message in mergeinfo command */
+ svn_boolean_t remove_unversioned;/* remove unversioned items */
+ svn_boolean_t remove_ignored; /* remove ignored items */
+ svn_boolean_t no_newline; /* do not output the trailing newline */
+ svn_boolean_t show_passwords; /* show cached passwords */
+ svn_boolean_t pin_externals; /* pin externals to last-changed revisions */
+ const char *show_item; /* print only the given item */
} svn_cl__opt_state_t;
@@ -248,6 +262,7 @@ typedef struct svn_cl__cmd_baton_t
/* Declare all the command procedures */
svn_opt_subcommand_t
svn_cl__add,
+ svn_cl__auth,
svn_cl__blame,
svn_cl__cat,
svn_cl__changelist,
@@ -310,7 +325,7 @@ extern const apr_getopt_option_t svn_cl__options[];
*
* Typically, error codes like SVN_ERR_UNVERSIONED_RESOURCE,
* SVN_ERR_ENTRY_NOT_FOUND, etc, are supplied in varargs. Don't
- * forget to terminate the argument list with SVN_NO_ERROR.
+ * forget to terminate the argument list with 0 (or APR_SUCCESS).
*/
svn_error_t *
svn_cl__try(svn_error_t *err,
@@ -347,6 +362,14 @@ svn_cl__conflict_stats_resolved(svn_cl__conflict_stats_t *conflict_stats,
const char *path_local,
svn_wc_conflict_kind_t conflict_kind);
+/* Print the conflict stats accumulated in CONFLICT_STATS.
+ *
+ * Return any error encountered during printing.
+ * See also svn_cl__notifier_print_conflict_stats().
+ */
+svn_error_t *
+svn_cl__print_conflict_stats(svn_cl__conflict_stats_t *conflict_stats,
+ apr_pool_t *scratch_pool);
/* Create and return an baton for use with svn_cl__conflict_func_interactive
* in *B, allocated from RESULT_POOL, and initialised with the values
@@ -514,7 +537,8 @@ svn_cl__merge_file_externally(const char *base_path,
/* Like svn_cl__merge_file_externally, but using a built-in merge tool
* with help from an external editor specified by EDITOR_CMD. */
svn_error_t *
-svn_cl__merge_file(const char *base_path,
+svn_cl__merge_file(svn_boolean_t *remains_in_conflict,
+ const char *base_path,
const char *their_path,
const char *my_path,
const char *merged_path,
@@ -522,7 +546,8 @@ svn_cl__merge_file(const char *base_path,
const char *path_prefix,
const char *editor_cmd,
apr_hash_t *config,
- svn_boolean_t *remains_in_conflict,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *scratch_pool);
@@ -571,7 +596,9 @@ svn_cl__check_externals_failed_notify_wrapper(void *baton,
apr_pool_t *pool);
/* Print the conflict stats accumulated in BATON, which is the
- * notifier baton from svn_cl__get_notifier().
+ * notifier baton from svn_cl__get_notifier(). This is just like
+ * calling svn_cl__print_conflict_stats().
+ *
* Return any error encountered during printing.
*/
svn_error_t *
@@ -828,6 +855,48 @@ svn_cl__deprecated_merge_reintegrate(const char *source_path_or_url,
svn_client_ctx_t *ctx,
apr_pool_t *pool);
+
+/* Forward declaration of the similarity check context. */
+typedef struct svn_cl__simcheck_context_t svn_cl__simcheck_context_t;
+
+/* Token definition for the similarity check. */
+typedef struct svn_cl__simcheck_t
+{
+ /* The token we're checking for similarity. */
+ svn_string_t token;
+
+ /* User data associated with this token. */
+ const void *data;
+
+ /*
+ * The following fields are populated by svn_cl__similarity_check.
+ */
+
+ /* Similarity score [0..SVN_STRING__SIM_RANGE_MAX] */
+ apr_size_t score;
+
+ /* Number of characters of difference from the key. */
+ apr_size_t diff;
+
+ /* Similarity check context (private) */
+ svn_cl__simcheck_context_t *context;
+} svn_cl__simcheck_t;
+
+/* Find the entries in TOKENS that are most similar to KEY.
+ * TOKEN_COUNT is the number of entries in the (mutable) TOKENS array.
+ * Use SCRATCH_POOL for temporary allocations.
+ *
+ * On return, the TOKENS array will be sorted according to similarity
+ * to KEY, in descending order. The return value will be zero if the
+ * first token is an exact match; otherwise, it will be one more than
+ * the number of tokens that are at least two-thirds similar to KEY.
+ */
+apr_size_t
+svn_cl__similarity_check(const char *key,
+ svn_cl__simcheck_t **tokens,
+ apr_size_t token_count,
+ apr_pool_t *scratch_pool);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/subversion/svn/cleanup-cmd.c b/subversion/svn/cleanup-cmd.c
index 64fa400d71be..6b0b62efe930 100644
--- a/subversion/svn/cleanup-cmd.c
+++ b/subversion/svn/cleanup-cmd.c
@@ -47,7 +47,7 @@ svn_cl__cleanup(apr_getopt_t *os,
svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
apr_array_header_t *targets;
- apr_pool_t *subpool;
+ apr_pool_t *iterpool;
int i;
SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
@@ -61,30 +61,60 @@ svn_cl__cleanup(apr_getopt_t *os,
SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool));
- subpool = svn_pool_create(pool);
+ iterpool = svn_pool_create(pool);
for (i = 0; i < targets->nelts; i++)
{
const char *target = APR_ARRAY_IDX(targets, i, const char *);
- svn_error_t *err;
+ const char *target_abspath;
- svn_pool_clear(subpool);
+ svn_pool_clear(iterpool);
SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
- err = svn_client_cleanup(target, ctx, subpool);
- if (err && err->apr_err == SVN_ERR_WC_LOCKED)
+
+ SVN_ERR(svn_dirent_get_absolute(&target_abspath, target, iterpool));
+
+ if (opt_state->remove_unversioned || opt_state->remove_ignored)
{
- const char *target_abspath;
- svn_error_t *err2 = svn_dirent_get_absolute(&target_abspath,
- target, subpool);
- if (err2)
- {
- err = svn_error_compose_create(err, err2);
- }
- else
+ svn_error_t *err = svn_client_vacuum(target_abspath,
+ opt_state->remove_unversioned,
+ opt_state->remove_ignored,
+ TRUE /* fix_timestamps */,
+ FALSE /* vacuum_pristines */,
+ opt_state->include_externals,
+ ctx, iterpool);
+
+ if (err && err->apr_err == SVN_ERR_WC_LOCKED)
+ err = svn_error_create(SVN_ERR_WC_LOCKED, err,
+ _("Working copy locked; if no other "
+ "Subversion client is currently "
+ "using the working copy, try running "
+ "'svn cleanup' without the "
+ "--remove-unversioned and "
+ "--remove-ignored options first."));
+ else if (err && err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY)
+ err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, err,
+ _("Cannot remove unversioned or ignored "
+ "items from something that is not a "
+ "working copy"));
+
+ SVN_ERR(err);
+ }
+ else
+ {
+ svn_error_t *err = svn_client_cleanup2(target_abspath,
+ TRUE /* break_locks */,
+ TRUE /* fix_timestamps */,
+ TRUE /* clear_dav_cache */,
+ TRUE /* vacuum_pristines */,
+ opt_state->include_externals,
+ ctx, iterpool);
+
+ if (err && err->apr_err == SVN_ERR_WC_LOCKED)
{
const char *wcroot_abspath;
+ svn_error_t *err2;
err2 = svn_client_get_wc_root(&wcroot_abspath, target_abspath,
- ctx, subpool, subpool);
+ ctx, iterpool, iterpool);
if (err2)
err = svn_error_compose_create(err, err2);
else
@@ -93,12 +123,12 @@ svn_cl__cleanup(apr_getopt_t *os,
"'svn cleanup' on the root of the "
"working copy ('%s') instead."),
svn_dirent_local_style(wcroot_abspath,
- subpool));
+ iterpool));
}
+ SVN_ERR(err);
}
- SVN_ERR(err);
}
- svn_pool_destroy(subpool);
+ svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
diff --git a/subversion/svn/client_errors.h b/subversion/svn/client_errors.h
deleted file mode 100644
index 19f0bdfadc09..000000000000
--- a/subversion/svn/client_errors.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * client_errors.h: error codes this command line client features
- *
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- * ====================================================================
- */
-
-/* ==================================================================== */
-
-
-
-#ifndef SVN_CLIENT_ERRORS_H
-#define SVN_CLIENT_ERRORS_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/*
- * This error defining system is copied from and explained in
- * ../../include/svn_error_codes.h
- */
-
-/* Process this file if we're building an error array, or if we have
- not defined the enumerated constants yet. */
-#if defined(SVN_ERROR_BUILD_ARRAY) || !defined(SVN_CMDLINE_ERROR_ENUM_DEFINED)
-
-#if defined(SVN_ERROR_BUILD_ARRAY)
-
-#error "Need to update err_defn for r1464679 and un-typo 'CDMLINE'"
-
-#define SVN_ERROR_START \
- static const err_defn error_table[] = { \
- { SVN_ERR_CDMLINE__WARNING, "Warning" },
-#define SVN_ERRDEF(n, s) { n, s },
-#define SVN_ERROR_END { 0, NULL } };
-
-#elif !defined(SVN_CMDLINE_ERROR_ENUM_DEFINED)
-
-#define SVN_ERROR_START \
- typedef enum svn_client_errno_t { \
- SVN_ERR_CDMLINE__WARNING = SVN_ERR_LAST + 1,
-#define SVN_ERRDEF(n, s) n,
-#define SVN_ERROR_END SVN_ERR_CMDLINE__ERR_LAST } svn_client_errno_t;
-
-#define SVN_CMDLINE_ERROR_ENUM_DEFINED
-
-#endif
-
-/* Define custom command line client error numbers */
-
-SVN_ERROR_START
-
- /* BEGIN Client errors */
-
-SVN_ERRDEF(SVN_ERR_CMDLINE__TMPFILE_WRITE,
- "Failed writing to temporary file.")
-
- SVN_ERRDEF(SVN_ERR_CMDLINE__TMPFILE_STAT,
- "Failed getting info about temporary file.")
-
- SVN_ERRDEF(SVN_ERR_CMDLINE__TMPFILE_OPEN,
- "Failed opening temporary file.")
-
- /* END Client errors */
-
-
-SVN_ERROR_END
-
-#undef SVN_ERROR_START
-#undef SVN_ERRDEF
-#undef SVN_ERROR_END
-
-#endif /* SVN_ERROR_BUILD_ARRAY || !SVN_CMDLINE_ERROR_ENUM_DEFINED */
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* SVN_CLIENT_ERRORS_H */
diff --git a/subversion/svn/commit-cmd.c b/subversion/svn/commit-cmd.c
index 2d04c6971ca4..45eef3b985a9 100644
--- a/subversion/svn/commit-cmd.c
+++ b/subversion/svn/commit-cmd.c
@@ -137,7 +137,9 @@ svn_cl__commit(apr_getopt_t *os,
if (opt_state->depth == svn_depth_unknown)
opt_state->depth = svn_depth_infinity;
- cfg = svn_hash_gets(ctx->config, SVN_CONFIG_CATEGORY_CONFIG);
+ cfg = ctx->config
+ ? svn_hash_gets(ctx->config, SVN_CONFIG_CATEGORY_CONFIG)
+ : NULL;
if (cfg)
SVN_ERR(svn_config_get_bool(cfg, &no_unlock,
SVN_CONFIG_SECTION_MISCELLANY,
diff --git a/subversion/svn/conflict-callbacks.c b/subversion/svn/conflict-callbacks.c
index 0f12413d241b..356f59d95e05 100644
--- a/subversion/svn/conflict-callbacks.c
+++ b/subversion/svn/conflict-callbacks.c
@@ -44,6 +44,9 @@
#include "svn_private_config.h"
#define ARRAY_LEN(ary) ((sizeof (ary)) / (sizeof ((ary)[0])))
+#define MAX_ARRAY_LEN(aryx, aryz) \
+ (ARRAY_LEN((aryx)) > ARRAY_LEN((aryz)) \
+ ? ARRAY_LEN((aryx)) : ARRAY_LEN((aryz)))
@@ -56,6 +59,7 @@ struct svn_cl__interactive_conflict_baton_t {
const char *path_prefix;
svn_boolean_t quit;
svn_cl__conflict_stats_t *conflict_stats;
+ svn_boolean_t printed_summary;
};
svn_error_t *
@@ -82,6 +86,7 @@ svn_cl__get_conflict_func_interactive_baton(
SVN_ERR(svn_dirent_get_absolute(&(*b)->path_prefix, "", result_pool));
(*b)->quit = FALSE;
(*b)->conflict_stats = conflict_stats;
+ (*b)->printed_summary = FALSE;
return SVN_NO_ERROR;
}
@@ -127,6 +132,8 @@ svn_cl__accept_from_word(const char *word)
static svn_error_t *
show_diff(const svn_wc_conflict_description2_t *desc,
const char *path_prefix,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *pool)
{
const char *path1, *path2;
@@ -184,11 +191,14 @@ show_diff(const svn_wc_conflict_description2_t *desc,
SVN_ERR(svn_stream_for_stdout(&output, pool));
SVN_ERR(svn_diff_file_diff_2(&diff, path1, path2,
options, pool));
- return svn_diff_file_output_unified3(output, diff,
+ return svn_diff_file_output_unified4(output, diff,
path1, path2,
label1, label2,
APR_LOCALE_CHARSET,
- NULL, FALSE,
+ NULL,
+ options->show_c_function,
+ options->context_size,
+ cancel_func, cancel_baton,
pool);
}
@@ -197,6 +207,8 @@ show_diff(const svn_wc_conflict_description2_t *desc,
* and 'my' files of DESC. */
static svn_error_t *
show_conflicts(const svn_wc_conflict_description2_t *desc,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *pool)
{
svn_diff_t *diff;
@@ -213,7 +225,7 @@ show_conflicts(const svn_wc_conflict_description2_t *desc,
options, pool));
/* ### Consider putting the markers/labels from
### svn_wc__merge_internal in the conflict description. */
- return svn_diff_file_output_merge2(output, diff,
+ return svn_diff_file_output_merge3(output, diff,
desc->base_abspath,
desc->my_abspath,
desc->their_abspath,
@@ -222,6 +234,8 @@ show_conflicts(const svn_wc_conflict_description2_t *desc,
_(">>>>>>> THEIRS (select with 'tc')"),
"=======",
svn_diff_conflict_display_only_conflicts,
+ cancel_func,
+ cancel_baton,
pool);
}
@@ -237,6 +251,8 @@ static svn_error_t *
merge_prop_conflict(svn_stream_t *output,
const svn_wc_conflict_description2_t *desc,
const char *merged_abspath,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *pool)
{
const char *base_abspath = desc->base_abspath;
@@ -268,7 +284,7 @@ merge_prop_conflict(svn_stream_t *output,
merged_abspath ? merged_abspath : my_abspath,
their_abspath,
options, pool));
- SVN_ERR(svn_diff_file_output_merge2(output, diff,
+ SVN_ERR(svn_diff_file_output_merge3(output, diff,
base_abspath,
merged_abspath ? merged_abspath
: my_abspath,
@@ -278,6 +294,8 @@ merge_prop_conflict(svn_stream_t *output,
_(">>>>>>> THEIRS"),
"=======",
svn_diff_conflict_display_modified_original_latest,
+ cancel_func,
+ cancel_baton,
pool));
return SVN_NO_ERROR;
@@ -293,12 +311,15 @@ merge_prop_conflict(svn_stream_t *output,
static svn_error_t *
show_prop_conflict(const svn_wc_conflict_description2_t *desc,
const char *merged_abspath,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *pool)
{
svn_stream_t *output;
SVN_ERR(svn_stream_for_stdout(&output, pool));
- SVN_ERR(merge_prop_conflict(output, desc, merged_abspath, pool));
+ SVN_ERR(merge_prop_conflict(output, desc, merged_abspath,
+ cancel_func, cancel_baton, pool));
return SVN_NO_ERROR;
}
@@ -324,22 +345,14 @@ open_editor(svn_boolean_t *performed_edit,
{
err = svn_cmdline__edit_file_externally(merged_file, b->editor_cmd,
b->config, pool);
- if (err && (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR))
+ if (err && (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR ||
+ err->apr_err == SVN_ERR_EXTERNAL_PROGRAM))
{
- svn_error_t *root_err = svn_error_root_cause(err);
+ char buf[1024];
+ const char *message;
- SVN_ERR(svn_cmdline_fprintf(stderr, pool, "%s\n",
- root_err->message ? root_err->message :
- _("No editor found.")));
- svn_error_clear(err);
- }
- else if (err && (err->apr_err == SVN_ERR_EXTERNAL_PROGRAM))
- {
- svn_error_t *root_err = svn_error_root_cause(err);
-
- SVN_ERR(svn_cmdline_fprintf(stderr, pool, "%s\n",
- root_err->message ? root_err->message :
- _("Error running editor.")));
+ message = svn_err_best_message(err, buf, sizeof(buf));
+ SVN_ERR(svn_cmdline_fprintf(stderr, pool, "%s\n", message));
svn_error_clear(err);
}
else if (err)
@@ -375,60 +388,18 @@ edit_prop_conflict(const char **merged_file_path,
result_pool, scratch_pool));
merged_prop = svn_stream_from_aprfile2(file, TRUE /* disown */,
scratch_pool);
- SVN_ERR(merge_prop_conflict(merged_prop, desc, NULL, scratch_pool));
+ SVN_ERR(merge_prop_conflict(merged_prop, desc, NULL,
+ b->pb->cancel_func,
+ b->pb->cancel_baton,
+ scratch_pool));
SVN_ERR(svn_stream_close(merged_prop));
- SVN_ERR(svn_io_file_flush_to_disk(file, scratch_pool));
+ SVN_ERR(svn_io_file_flush(file, scratch_pool));
SVN_ERR(open_editor(&performed_edit, file_path, b, scratch_pool));
*merged_file_path = (performed_edit ? file_path : NULL);
return SVN_NO_ERROR;
}
-/* Run an external merge tool, passing it the 'base', 'their', 'my' and
- * 'merged' files in DESC. The tool to use is determined by B->config and
- * environment variables; see svn_cl__merge_file_externally() for details.
- *
- * If the tool runs, set *PERFORMED_EDIT to true; if a tool is not
- * configured or cannot run, do not touch *PERFORMED_EDIT, report the error
- * on stderr, and return SVN_NO_ERROR; if any other error is encountered,
- * return that error. */
-static svn_error_t *
-launch_resolver(svn_boolean_t *performed_edit,
- const svn_wc_conflict_description2_t *desc,
- svn_cl__interactive_conflict_baton_t *b,
- apr_pool_t *pool)
-{
- svn_error_t *err;
-
- err = svn_cl__merge_file_externally(desc->base_abspath, desc->their_abspath,
- desc->my_abspath, desc->merged_file,
- desc->local_abspath, b->config, NULL,
- pool);
- if (err && err->apr_err == SVN_ERR_CL_NO_EXTERNAL_MERGE_TOOL)
- {
- SVN_ERR(svn_cmdline_fprintf(stderr, pool, "%s\n",
- err->message ? err->message :
- _("No merge tool found, "
- "try '(m) merge' instead.\n")));
- svn_error_clear(err);
- }
- else if (err && err->apr_err == SVN_ERR_EXTERNAL_PROGRAM)
- {
- SVN_ERR(svn_cmdline_fprintf(stderr, pool, "%s\n",
- err->message ? err->message :
- _("Error running merge tool, "
- "try '(m) merge' instead.")));
- svn_error_clear(err);
- }
- else if (err)
- return svn_error_trace(err);
- else if (performed_edit)
- *performed_edit = TRUE;
-
- return SVN_NO_ERROR;
-}
-
-
/* Maximum line length for the prompt string. */
#define MAX_PROMPT_WIDTH 70
@@ -438,7 +409,8 @@ typedef struct resolver_option_t
const char *code; /* one or two characters */
const char *short_desc; /* label in prompt (localized) */
const char *long_desc; /* longer description (localized) */
- svn_wc_conflict_choice_t choice; /* or -1 if not a simple choice */
+ svn_wc_conflict_choice_t choice;
+ /* or ..._undefined if not a simple choice */
} resolver_option_t;
/* Resolver options for a text conflict */
@@ -450,14 +422,15 @@ static const resolver_option_t text_conflict_options[] =
brackets. */
{ "e", N_("edit file"), N_("change merged file in an editor"
" [edit]"),
- -1 },
+ svn_wc_conflict_choose_undefined },
{ "df", N_("show diff"), N_("show all changes made to merged file"),
- -1 },
- { "r", N_("mark resolved"), N_("accept merged version of file"),
+ svn_wc_conflict_choose_undefined },
+ { "r", N_("mark resolved"), N_("accept merged version of file [working]"),
svn_wc_conflict_choose_merged },
{ "", "", "", svn_wc_conflict_choose_unspecified },
{ "dc", N_("display conflict"), N_("show all conflicts "
- "(ignoring merged version)"), -1 },
+ "(ignoring merged version)"),
+ svn_wc_conflict_choose_undefined },
{ "mc", N_("my side of conflict"), N_("accept my version for all conflicts "
"(same) [mine-conflict]"),
svn_wc_conflict_choose_mine_conflict },
@@ -473,16 +446,43 @@ static const resolver_option_t text_conflict_options[] =
"(same) [theirs-full]"),
svn_wc_conflict_choose_theirs_full },
{ "", "", "", svn_wc_conflict_choose_unspecified },
- { "m", N_("merge"), N_("use internal merge tool to resolve "
- "conflict"), -1 },
- { "l", N_("launch tool"), N_("launch external tool to resolve "
- "conflict [launch]"), -1 },
+ { "m", N_("merge"), N_("use merge tool to resolve conflict"),
+ svn_wc_conflict_choose_undefined },
+ { "l", N_("launch tool"), N_("launch external merge tool to resolve "
+ "conflict [launch]"),
+ svn_wc_conflict_choose_undefined },
+ { "i", N_("internal merge tool"), N_("use built-in merge tool to "
+ "resolve conflict"),
+ svn_wc_conflict_choose_undefined },
{ "p", N_("postpone"), N_("mark the conflict to be resolved later"
" [postpone]"),
svn_wc_conflict_choose_postpone },
{ "q", N_("quit resolution"), N_("postpone all remaining conflicts"),
svn_wc_conflict_choose_postpone },
- { "s", N_("show all options"), N_("show this list (also 'h', '?')"), -1 },
+ { "s", N_("show all options"), N_("show this list (also 'h', '?')"),
+ svn_wc_conflict_choose_undefined },
+ { NULL }
+};
+
+/* Resolver options for a binary file conflict. */
+static const resolver_option_t binary_conflict_options[] =
+{
+ /* Translators: keep long_desc below 70 characters (wrap with a left
+ margin of 9 spaces if needed); don't translate the words within square
+ brackets. */
+ { "r", N_("mark resolved"), N_("accept the working copy version of file "
+ " [working]"),
+ svn_wc_conflict_choose_merged },
+ { "tf", N_("their version"), N_("accept the incoming version of file "
+ " [theirs-full]"),
+ svn_wc_conflict_choose_theirs_full },
+ { "p", N_("postpone"), N_("mark the conflict to be resolved later "
+ " [postpone]"),
+ svn_wc_conflict_choose_postpone },
+ { "q", N_("quit resolution"), N_("postpone all remaining conflicts"),
+ svn_wc_conflict_choose_postpone },
+ { "s", N_("show all options"), N_("show this list (also 'h', '?')"),
+ svn_wc_conflict_choose_undefined },
{ NULL }
};
@@ -495,9 +495,11 @@ static const resolver_option_t prop_conflict_options[] =
{ "tf", N_("their version"), N_("accept their version of entire property "
"(same) [theirs-full]"),
svn_wc_conflict_choose_theirs_full },
- { "dc", N_("display conflict"), N_("show conflicts in this property"), -1 },
+ { "dc", N_("display conflict"), N_("show conflicts in this property"),
+ svn_wc_conflict_choose_undefined },
{ "e", N_("edit property"), N_("change merged property value in an editor"
- " [edit]"), -1 },
+ " [edit]"),
+ svn_wc_conflict_choose_undefined },
{ "r", N_("mark resolved"), N_("accept edited version of property"),
svn_wc_conflict_choose_merged },
{ "p", N_("postpone"), N_("mark the conflict to be resolved later"
@@ -505,7 +507,8 @@ static const resolver_option_t prop_conflict_options[] =
svn_wc_conflict_choose_postpone },
{ "q", N_("quit resolution"), N_("postpone all remaining conflicts"),
svn_wc_conflict_choose_postpone },
- { "h", N_("help"), N_("show this help (also '?')"), -1 },
+ { "h", N_("help"), N_("show this help (also '?')"),
+ svn_wc_conflict_choose_undefined },
{ NULL }
};
@@ -518,31 +521,14 @@ static const resolver_option_t tree_conflict_options[] =
svn_wc_conflict_choose_postpone },
{ "q", N_("quit resolution"), N_("postpone all remaining conflicts"),
svn_wc_conflict_choose_postpone },
- { "h", N_("help"), N_("show this help (also '?')"), -1 },
+ { "h", N_("help"), N_("show this help (also '?')"),
+ svn_wc_conflict_choose_undefined },
{ NULL }
};
static const resolver_option_t tree_conflict_options_update_moved_away[] =
{
- { "mc", N_("apply update (recommended)"),
- N_("apply update to the move destination"
- " [mine-conflict]"),
- svn_wc_conflict_choose_mine_conflict },
- { "r", N_("discard update (breaks move)"), N_("discard update, mark "
- "resolved, the move will "
- "will become a copy"),
- svn_wc_conflict_choose_merged },
- { "p", N_("postpone"), N_("resolve the conflict later [postpone]"),
- svn_wc_conflict_choose_postpone },
- { "q", N_("quit resolution"), N_("postpone all remaining conflicts"),
- svn_wc_conflict_choose_postpone },
- { "h", N_("help"), N_("show this help (also '?')"), -1 },
- { NULL }
-};
-
-static const resolver_option_t tree_conflict_options_update_edit_moved_away[] =
-{
- { "mc", N_("apply update to move destination"),
+ { "mc", N_("apply update to move destination (recommended)"),
N_("apply incoming update to move destination"
" [mine-conflict]"),
svn_wc_conflict_choose_mine_conflict },
@@ -550,43 +536,26 @@ static const resolver_option_t tree_conflict_options_update_edit_moved_away[] =
svn_wc_conflict_choose_postpone },
{ "q", N_("quit resolution"), N_("postpone all remaining conflicts"),
svn_wc_conflict_choose_postpone },
- { "h", N_("help"), N_("show this help (also '?')"), -1 },
- { NULL }
-};
-
-static const resolver_option_t tree_conflict_options_update_deleted[] =
-{
- { "mc", N_("keep affected local moves"), N_("keep any local moves affected "
- "by this deletion [mine-conflict]"),
- svn_wc_conflict_choose_mine_conflict },
- { "r", N_("mark resolved (breaks moves)"), N_("mark resolved, any affected "
- "moves will become copies"),
- svn_wc_conflict_choose_merged },
- { "p", N_("postpone"), N_("resolve the conflict later [postpone]"),
- svn_wc_conflict_choose_postpone },
- { "q", N_("quit resolution"), N_("postpone all remaining conflicts"),
- svn_wc_conflict_choose_postpone },
- { "h", N_("help"), N_("show this help (also '?')"), -1 },
+ { "h", N_("help"), N_("show this help (also '?')"),
+ svn_wc_conflict_choose_undefined },
{ NULL }
};
-static const resolver_option_t tree_conflict_options_update_replaced[] =
+static const resolver_option_t tree_conflict_options_update_edit_deleted_dir[] =
{
- { "mc", N_("keep affected local moves"), N_("keep any moves affected by this "
- "replacement [mine-conflict]"),
+ { "mc", N_("prepare for updating moved-away children, if any (recommended)"),
+ N_("allow updating moved-away children "
+ "with 'svn resolve' [mine-conflict]"),
svn_wc_conflict_choose_mine_conflict },
- { "r", N_("mark resolved (breaks moves)"), N_("mark resolved (any affected "
- "moves will become copies)"),
- svn_wc_conflict_choose_merged },
{ "p", N_("postpone"), N_("resolve the conflict later [postpone]"),
svn_wc_conflict_choose_postpone },
{ "q", N_("quit resolution"), N_("postpone all remaining conflicts"),
svn_wc_conflict_choose_postpone },
- { "h", N_("help"), N_("show this help (also '?')"), -1 },
+ { "h", N_("help"), N_("show this help (also '?')"),
+ svn_wc_conflict_choose_undefined },
{ NULL }
};
-
/* Return a pointer to the option description in OPTIONS matching the
* one- or two-character OPTION_CODE. Return NULL if not found. */
static const resolver_option_t *
@@ -637,21 +606,21 @@ prompt_string(const resolver_option_t *options,
}
if (! first)
- result = apr_pstrcat(pool, result, ",", (char *)NULL);
+ result = apr_pstrcat(pool, result, ",", SVN_VA_NULL);
s = apr_psprintf(pool, _(" (%s) %s"),
opt->code, _(opt->short_desc));
slen = svn_utf_cstring_utf8_width(s);
/* Break the line if adding the next option would make it too long */
if (this_line_len + slen > MAX_PROMPT_WIDTH)
{
- result = apr_pstrcat(pool, result, line_sep, (char *)NULL);
+ result = apr_pstrcat(pool, result, line_sep, SVN_VA_NULL);
this_line_len = left_margin;
}
- result = apr_pstrcat(pool, result, s, (char *)NULL);
+ result = apr_pstrcat(pool, result, s, SVN_VA_NULL);
this_line_len += slen;
first = FALSE;
}
- return apr_pstrcat(pool, result, ": ", (char *)NULL);
+ return apr_pstrcat(pool, result, ": ", SVN_VA_NULL);
}
/* Return a help string listing the OPTIONS. */
@@ -674,13 +643,13 @@ help_string(const resolver_option_t *options,
}
else
{
- result = apr_pstrcat(pool, result, "\n", (char *)NULL);
+ result = apr_pstrcat(pool, result, "\n", SVN_VA_NULL);
}
}
result = apr_pstrcat(pool, result,
_("Words in square brackets are the corresponding "
"--accept option arguments.\n"),
- (char *)NULL);
+ SVN_VA_NULL);
return result;
}
@@ -736,31 +705,50 @@ handle_text_conflict(svn_wc_conflict_result_t *result,
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
svn_boolean_t diff_allowed = FALSE;
/* Have they done something that might have affected the merged
- file (so that we need to save a .edited copy)? */
+ file (so that we need to save a .edited copy by setting the
+ result->save_merge flag)? */
svn_boolean_t performed_edit = FALSE;
/* Have they done *something* (edit, look at diff, etc) to
give them a rational basis for choosing (r)esolved? */
svn_boolean_t knows_something = FALSE;
+ const char *local_relpath;
SVN_ERR_ASSERT(desc->kind == svn_wc_conflict_kind_text);
- SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool,
- _("Conflict discovered in file '%s'.\n"),
- svn_cl__local_style_skip_ancestor(
- b->path_prefix, desc->local_abspath,
- scratch_pool)));
+ local_relpath = svn_cl__local_style_skip_ancestor(b->path_prefix,
+ desc->local_abspath,
+ scratch_pool);;
+
+ if (desc->is_binary)
+ SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool,
+ _("Conflict discovered in binary file '%s'.\n"),
+ local_relpath));
+ else
+ SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool,
+ _("Conflict discovered in file '%s'.\n"),
+ local_relpath));
+
+ /* ### TODO This whole feature availability check is grossly outdated.
+ DIFF_ALLOWED needs either to be redefined or to go away.
+ */
/* Diffing can happen between base and merged, to show conflict
markers to the user (this is the typical 3-way merge
scenario), or if no base is available, we can show a diff
between mine and theirs. */
- if ((desc->merged_file && desc->base_abspath)
- || (!desc->base_abspath && desc->my_abspath && desc->their_abspath))
+ if (!desc->is_binary &&
+ ((desc->merged_file && desc->base_abspath)
+ || (!desc->base_abspath && desc->my_abspath && desc->their_abspath)))
diff_allowed = TRUE;
while (TRUE)
{
- const char *options[ARRAY_LEN(text_conflict_options)];
+ const char *options[1 + MAX_ARRAY_LEN(binary_conflict_options,
+ text_conflict_options)];
+
+ const resolver_option_t *conflict_options = desc->is_binary
+ ? binary_conflict_options
+ : text_conflict_options;
const char **next_option = options;
const resolver_option_t *opt;
@@ -769,31 +757,39 @@ handle_text_conflict(svn_wc_conflict_result_t *result,
*next_option++ = "p";
if (diff_allowed)
{
- *next_option++ = "df";
+ /* We need one more path for this feature. */
+ if (desc->my_abspath)
+ *next_option++ = "df";
+
*next_option++ = "e";
- *next_option++ = "m";
+
+ /* We need one more path for this feature. */
+ if (desc->my_abspath)
+ *next_option++ = "m";
if (knows_something)
*next_option++ = "r";
- if (! desc->is_binary)
- {
- *next_option++ = "mc";
- *next_option++ = "tc";
- }
+ *next_option++ = "mc";
+ *next_option++ = "tc";
}
else
{
if (knows_something)
*next_option++ = "r";
- *next_option++ = "mf";
+
+ /* The 'mine-full' option selects the ".mine" file so only offer
+ * it if that file exists. It does not exist for binary files,
+ * for example (questionable historical behaviour since 1.0). */
+ if (desc->my_abspath)
+ *next_option++ = "mf";
+
*next_option++ = "tf";
}
*next_option++ = "s";
*next_option++ = NULL;
- SVN_ERR(prompt_user(&opt, text_conflict_options, options, b->pb,
- iterpool));
+ SVN_ERR(prompt_user(&opt, conflict_options, options, b->pb, iterpool));
if (! opt)
continue;
@@ -807,7 +803,7 @@ handle_text_conflict(svn_wc_conflict_result_t *result,
else if (strcmp(opt->code, "s") == 0)
{
SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, "\n%s\n",
- help_string(text_conflict_options,
+ help_string(conflict_options,
iterpool)));
}
else if (strcmp(opt->code, "dc") == 0)
@@ -828,12 +824,16 @@ handle_text_conflict(svn_wc_conflict_result_t *result,
"files not available.\n\n")));
continue;
}
- SVN_ERR(show_conflicts(desc, iterpool));
+ SVN_ERR(show_conflicts(desc,
+ b->pb->cancel_func,
+ b->pb->cancel_baton,
+ iterpool));
knows_something = TRUE;
}
else if (strcmp(opt->code, "df") == 0)
{
- if (! diff_allowed)
+ /* Re-check preconditions. */
+ if (! diff_allowed || ! desc->my_abspath)
{
SVN_ERR(svn_cmdline_fprintf(stderr, iterpool,
_("Invalid option; there's no "
@@ -841,7 +841,9 @@ handle_text_conflict(svn_wc_conflict_result_t *result,
continue;
}
- SVN_ERR(show_diff(desc, b->path_prefix, iterpool));
+ SVN_ERR(show_diff(desc, b->path_prefix,
+ b->pb->cancel_func, b->pb->cancel_baton,
+ iterpool));
knows_something = TRUE;
}
else if (strcmp(opt->code, "e") == 0 || strcmp(opt->code, ":-E") == 0)
@@ -853,36 +855,68 @@ handle_text_conflict(svn_wc_conflict_result_t *result,
else if (strcmp(opt->code, "m") == 0 || strcmp(opt->code, ":-g") == 0 ||
strcmp(opt->code, "=>-") == 0 || strcmp(opt->code, ":>.") == 0)
{
- if (desc->kind != svn_wc_conflict_kind_text)
+ svn_error_t *err;
+
+ /* Re-check preconditions. */
+ if (! desc->my_abspath)
{
SVN_ERR(svn_cmdline_fprintf(stderr, iterpool,
- _("Invalid option; can only "
- "resolve text conflicts with "
- "the internal merge tool."
- "\n\n")));
+ _("Invalid option; there's no "
+ "base path to merge.\n\n")));
continue;
}
- if (desc->base_abspath && desc->their_abspath &&
- desc->my_abspath && desc->merged_file)
+ err = svn_cl__merge_file_externally(desc->base_abspath,
+ desc->their_abspath,
+ desc->my_abspath,
+ desc->merged_file,
+ desc->local_abspath, b->config,
+ NULL, iterpool);
+ if (err)
{
- svn_boolean_t remains_in_conflict;
-
- SVN_ERR(svn_cl__merge_file(desc->base_abspath,
- desc->their_abspath,
- desc->my_abspath,
- desc->merged_file,
- desc->local_abspath,
- b->path_prefix,
- b->editor_cmd,
- b->config,
- &remains_in_conflict,
- iterpool));
- knows_something = !remains_in_conflict;
+ if (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_MERGE_TOOL)
+ {
+ svn_boolean_t remains_in_conflict = TRUE;
+
+ /* Try the internal merge tool. */
+ svn_error_clear(err);
+ SVN_ERR(svn_cl__merge_file(&remains_in_conflict,
+ desc->base_abspath,
+ desc->their_abspath,
+ desc->my_abspath,
+ desc->merged_file,
+ desc->local_abspath,
+ b->path_prefix,
+ b->editor_cmd,
+ b->config,
+ b->pb->cancel_func,
+ b->pb->cancel_baton,
+ iterpool));
+ knows_something = !remains_in_conflict;
+ }
+ else if (err->apr_err == SVN_ERR_EXTERNAL_PROGRAM)
+ {
+ char buf[1024];
+ const char *message;
+
+ message = svn_err_best_message(err, buf, sizeof(buf));
+ SVN_ERR(svn_cmdline_fprintf(stderr, iterpool,
+ "%s\n", message));
+ svn_error_clear(err);
+ continue;
+ }
+ else
+ return svn_error_trace(err);
}
else
- SVN_ERR(svn_cmdline_fprintf(stderr, iterpool,
- _("Invalid option.\n\n")));
+ {
+ /* The external merge tool's exit code was either 0 or 1.
+ * The tool may leave the file conflicted by exiting with
+ * exit code 1, and we allow the user to mark the conflict
+ * resolved in this case. */
+ performed_edit = TRUE;
+ knows_something = TRUE;
+ }
}
else if (strcmp(opt->code, "l") == 0 || strcmp(opt->code, ":-l") == 0)
{
@@ -893,7 +927,29 @@ handle_text_conflict(svn_wc_conflict_result_t *result,
if (desc->base_abspath && desc->their_abspath &&
desc->my_abspath && desc->merged_file)
{
- SVN_ERR(launch_resolver(&performed_edit, desc, b, iterpool));
+ svn_error_t *err;
+ char buf[1024];
+ const char *message;
+
+ err = svn_cl__merge_file_externally(desc->base_abspath,
+ desc->their_abspath,
+ desc->my_abspath,
+ desc->merged_file,
+ desc->local_abspath,
+ b->config, NULL, iterpool);
+ if (err && (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_MERGE_TOOL ||
+ err->apr_err == SVN_ERR_EXTERNAL_PROGRAM))
+ {
+ message = svn_err_best_message(err, buf, sizeof(buf));
+ SVN_ERR(svn_cmdline_fprintf(stderr, iterpool, "%s\n",
+ message));
+ svn_error_clear(err);
+ }
+ else if (err)
+ return svn_error_trace(err);
+ else
+ performed_edit = TRUE;
+
if (performed_edit)
knows_something = TRUE;
}
@@ -901,7 +957,27 @@ handle_text_conflict(svn_wc_conflict_result_t *result,
SVN_ERR(svn_cmdline_fprintf(stderr, iterpool,
_("Invalid option.\n\n")));
}
- else if (opt->choice != -1)
+ else if (strcmp(opt->code, "i") == 0)
+ {
+ svn_boolean_t remains_in_conflict = TRUE;
+
+ SVN_ERR(svn_cl__merge_file(&remains_in_conflict,
+ desc->base_abspath,
+ desc->their_abspath,
+ desc->my_abspath,
+ desc->merged_file,
+ desc->local_abspath,
+ b->path_prefix,
+ b->editor_cmd,
+ b->config,
+ b->pb->cancel_func,
+ b->pb->cancel_baton,
+ iterpool));
+
+ if (!remains_in_conflict)
+ knows_something = TRUE;
+ }
+ else if (opt->choice != svn_wc_conflict_choose_undefined)
{
if ((opt->choice == svn_wc_conflict_choose_mine_conflict
|| opt->choice == svn_wc_conflict_choose_theirs_conflict)
@@ -1008,7 +1084,9 @@ handle_prop_conflict(svn_wc_conflict_result_t *result,
}
else if (strcmp(opt->code, "dc") == 0)
{
- SVN_ERR(show_prop_conflict(desc, merged_file_path, scratch_pool));
+ SVN_ERR(show_prop_conflict(desc, merged_file_path,
+ b->pb->cancel_func, b->pb->cancel_baton,
+ scratch_pool));
}
else if (strcmp(opt->code, "e") == 0)
{
@@ -1030,7 +1108,7 @@ handle_prop_conflict(svn_wc_conflict_result_t *result,
result->choice = svn_wc_conflict_choose_merged;
break;
}
- else if (opt->choice != -1)
+ else if (opt->choice != svn_wc_conflict_choose_undefined)
{
result->choice = opt->choice;
break;
@@ -1072,25 +1150,23 @@ handle_tree_conflict(svn_wc_conflict_result_t *result,
svn_pool_clear(iterpool);
+ tc_opts = tree_conflict_options;
+
if (desc->operation == svn_wc_operation_update ||
desc->operation == svn_wc_operation_switch)
{
if (desc->reason == svn_wc_conflict_reason_moved_away)
{
- if (desc->action == svn_wc_conflict_action_edit)
- tc_opts = tree_conflict_options_update_edit_moved_away;
- else
- tc_opts = tree_conflict_options_update_moved_away;
+ tc_opts = tree_conflict_options_update_moved_away;
+ }
+ else if (desc->reason == svn_wc_conflict_reason_deleted ||
+ desc->reason == svn_wc_conflict_reason_replaced)
+ {
+ if (desc->action == svn_wc_conflict_action_edit &&
+ desc->node_kind == svn_node_dir)
+ tc_opts = tree_conflict_options_update_edit_deleted_dir;
}
- else if (desc->reason == svn_wc_conflict_reason_deleted)
- tc_opts = tree_conflict_options_update_deleted;
- else if (desc->reason == svn_wc_conflict_reason_replaced)
- tc_opts = tree_conflict_options_update_replaced;
- else
- tc_opts = tree_conflict_options;
}
- else
- tc_opts = tree_conflict_options;
SVN_ERR(prompt_user(&opt, tc_opts, NULL, b->pb, iterpool));
if (! opt)
@@ -1103,7 +1179,7 @@ handle_tree_conflict(svn_wc_conflict_result_t *result,
b->quit = TRUE;
break;
}
- else if (opt->choice != -1)
+ else if (opt->choice != svn_wc_conflict_choose_undefined)
{
result->choice = opt->choice;
break;
@@ -1172,21 +1248,15 @@ conflict_func_interactive(svn_wc_conflict_result_t **result,
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",
- err->message ? err->message :
- _("No editor found;"
- " leaving all conflicts.")));
- svn_error_clear(err);
- b->external_failed = TRUE;
- }
- else if (err && (err->apr_err == SVN_ERR_EXTERNAL_PROGRAM))
+ if (err && (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR ||
+ err->apr_err == SVN_ERR_EXTERNAL_PROGRAM))
{
+ char buf[1024];
+ const char *message;
+
+ message = svn_err_best_message(err, buf, sizeof(buf));
SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, "%s\n",
- err->message ? err->message :
- _("Error running editor;"
- " leaving all conflicts.")));
+ message));
svn_error_clear(err);
b->external_failed = TRUE;
}
@@ -1217,21 +1287,15 @@ conflict_func_interactive(svn_wc_conflict_result_t **result,
b->config,
&remains_in_conflict,
scratch_pool);
- if (err && err->apr_err == SVN_ERR_CL_NO_EXTERNAL_MERGE_TOOL)
- {
- SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, "%s\n",
- err->message ? err->message :
- _("No merge tool found;"
- " leaving all conflicts.")));
- b->external_failed = TRUE;
- return svn_error_trace(err);
- }
- else if (err && err->apr_err == SVN_ERR_EXTERNAL_PROGRAM)
+ if (err && (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_MERGE_TOOL ||
+ err->apr_err == SVN_ERR_EXTERNAL_PROGRAM))
{
+ char buf[1024];
+ const char *message;
+
+ message = svn_err_best_message(err, buf, sizeof(buf));
SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, "%s\n",
- err->message ? err->message :
- _("Error running merge tool;"
- " leaving all conflicts.")));
+ message));
b->external_failed = TRUE;
return svn_error_trace(err);
}
@@ -1248,6 +1312,13 @@ conflict_func_interactive(svn_wc_conflict_result_t **result,
break;
}
+ /* Print a summary of conflicts before starting interactive resolution */
+ if (! b->printed_summary)
+ {
+ SVN_ERR(svn_cl__print_conflict_stats(b->conflict_stats, scratch_pool));
+ b->printed_summary = TRUE;
+ }
+
/* We're in interactive mode and either the user gave no --accept
option or the option did not apply; let's prompt. */
@@ -1293,7 +1364,7 @@ svn_cl__conflict_func_interactive(svn_wc_conflict_result_t **result,
b->path_prefix, desc->local_abspath, scratch_pool);
svn_cl__conflict_stats_resolved(b->conflict_stats, local_path,
- desc->kind);
+ desc->kind);
}
return SVN_NO_ERROR;
}
diff --git a/subversion/svn/copy-cmd.c b/subversion/svn/copy-cmd.c
index e6fbd4b19570..5b50713f99b6 100644
--- a/subversion/svn/copy-cmd.c
+++ b/subversion/svn/copy-cmd.c
@@ -150,8 +150,7 @@ svn_cl__copy(apr_getopt_t *os,
}
else
{
- /* URL -> URL, meaning that no notification is needed. */
- ctx->notify_func2 = NULL;
+ /* URL -> URL */
}
if (! dst_is_url)
@@ -168,8 +167,11 @@ svn_cl__copy(apr_getopt_t *os,
SVN_ERR(svn_cl__make_log_msg_baton(&(ctx->log_msg_baton3), opt_state,
NULL, ctx->config, pool));
- err = svn_client_copy6(sources, dst_path, TRUE,
+ err = svn_client_copy7(sources, dst_path, TRUE,
opt_state->parents, opt_state->ignore_externals,
+ FALSE /* metadata_only */,
+ opt_state->pin_externals,
+ NULL, /* pin all externals */
opt_state->revprop_table,
(opt_state->quiet ? NULL : svn_cl__print_commit_info),
NULL,
diff --git a/subversion/svn/diff-cmd.c b/subversion/svn/diff-cmd.c
index 2cbd202e3e25..7a84736bee91 100644
--- a/subversion/svn/diff-cmd.c
+++ b/subversion/svn/diff-cmd.c
@@ -37,6 +37,7 @@
#include "svn_types.h"
#include "svn_cmdline.h"
#include "svn_xml.h"
+#include "svn_hash.h"
#include "cl.h"
#include "svn_private_config.h"
@@ -117,7 +118,7 @@ summarize_xml(const svn_client_diff_summarize_t *summary,
"kind", svn_cl__node_kind_str_xml(summary->node_kind),
"item", kind_to_word(summary->summarize_kind),
"props", summary->prop_changed ? "modified" : "none",
- NULL);
+ SVN_VA_NULL);
svn_xml_escape_cdata_cstring(&sb, path, pool);
svn_xml_make_close_tag(&sb, pool, "path");
@@ -179,6 +180,7 @@ svn_cl__diff(apr_getopt_t *os,
const char *old_target, *new_target;
apr_pool_t *iterpool;
svn_boolean_t pegged_diff = FALSE;
+ svn_boolean_t ignore_content_type;
svn_boolean_t show_copies_as_adds =
opt_state->diff.patch_compatible || opt_state->diff.show_copies_as_adds;
svn_boolean_t ignore_properties =
@@ -211,7 +213,7 @@ svn_cl__diff(apr_getopt_t *os,
SVN_ERR(svn_cl__xml_print_header("diff", pool));
sb = svn_stringbuf_create_empty(pool);
- svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "paths", NULL);
+ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "paths", SVN_VA_NULL);
SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
}
@@ -337,6 +339,25 @@ svn_cl__diff(apr_getopt_t *os,
}
+ /* Should we ignore the content-type when deciding what to diff? */
+ if (opt_state->force)
+ {
+ ignore_content_type = TRUE;
+ }
+ else if (ctx->config)
+ {
+ SVN_ERR(svn_config_get_bool(svn_hash_gets(ctx->config,
+ SVN_CONFIG_CATEGORY_CONFIG),
+ &ignore_content_type,
+ SVN_CONFIG_SECTION_MISCELLANY,
+ SVN_CONFIG_OPTION_DIFF_IGNORE_CONTENT_TYPE,
+ FALSE));
+ }
+ else
+ {
+ ignore_content_type = FALSE;
+ }
+
svn_opt_push_implicit_dot_target(targets, pool);
iterpool = svn_pool_create(pool);
@@ -399,7 +420,7 @@ svn_cl__diff(apr_getopt_t *os,
opt_state->diff.no_diff_added,
opt_state->diff.no_diff_deleted,
show_copies_as_adds,
- opt_state->force,
+ ignore_content_type,
ignore_properties,
opt_state->diff.properties_only,
opt_state->diff.use_git_diff_format,
@@ -450,7 +471,7 @@ svn_cl__diff(apr_getopt_t *os,
opt_state->diff.no_diff_added,
opt_state->diff.no_diff_deleted,
show_copies_as_adds,
- opt_state->force,
+ ignore_content_type,
ignore_properties,
opt_state->diff.properties_only,
opt_state->diff.use_git_diff_format,
diff --git a/subversion/svn/export-cmd.c b/subversion/svn/export-cmd.c
index 75b6723a3a11..45554fa4c510 100644
--- a/subversion/svn/export-cmd.c
+++ b/subversion/svn/export-cmd.c
@@ -85,7 +85,15 @@ svn_cl__export(apr_getopt_t *os,
if (strcmp("", to) != 0)
/* svn_cl__eat_peg_revisions() but only on one target */
- SVN_ERR(svn_opt__split_arg_at_peg_revision(&to, NULL, to, pool));
+ {
+ const char *peg;
+
+ SVN_ERR(svn_opt__split_arg_at_peg_revision(&to, &peg, to, pool));
+ if (peg[0] && peg[1])
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("'%s': a peg revision is not allowed here"),
+ APR_ARRAY_IDX(targets, 1, const char *));
+ }
}
SVN_ERR(svn_cl__check_target_is_local_path(to));
diff --git a/subversion/svn/file-merge.c b/subversion/svn/file-merge.c
index c64f5772df45..14017db29d48 100644
--- a/subversion/svn/file-merge.c
+++ b/subversion/svn/file-merge.c
@@ -51,6 +51,10 @@
#include <fcntl.h>
#include <stdlib.h>
+#if defined(HAVE_TERMIOS_H)
+#include <termios.h>
+#endif
+
/* Baton for functions in this file which implement svn_diff_output_fns_t. */
struct file_merge_baton {
/* The files being merged. */
@@ -75,12 +79,12 @@ struct file_merge_baton {
/* The client configuration hash. */
apr_hash_t *config;
- /* Wether the merge should be aborted. */
+ /* Whether the merge should be aborted. */
svn_boolean_t abort_merge;
/* Pool for temporary allocations. */
apr_pool_t *scratch_pool;
-} file_merge_baton;
+};
/* Copy LEN lines from SOURCE_FILE to the MERGED_FILE, starting at
* line START. The CURRENT_LINE is the current line in the source file.
@@ -490,7 +494,7 @@ edit_chunk(apr_array_header_t **merged_chunk,
return svn_error_create(SVN_ERR_IO_WRITE_ERROR, NULL,
_("Could not write data to temporary file"));
}
- SVN_ERR(svn_io_file_flush_to_disk(temp_file, scratch_pool));
+ SVN_ERR(svn_io_file_flush(temp_file, scratch_pool));
err = svn_cmdline__edit_file_externally(temp_file_name, editor_cmd,
config, scratch_pool);
@@ -853,7 +857,8 @@ static svn_diff_output_fns_t file_merge_diff_output_fns = {
};
svn_error_t *
-svn_cl__merge_file(const char *base_path,
+svn_cl__merge_file(svn_boolean_t *remains_in_conflict,
+ const char *base_path,
const char *their_path,
const char *my_path,
const char *merged_path,
@@ -861,7 +866,8 @@ svn_cl__merge_file(const char *base_path,
const char *path_prefix,
const char *editor_cmd,
apr_hash_t *config,
- svn_boolean_t *remains_in_conflict,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *scratch_pool)
{
svn_diff_t *diff;
@@ -918,7 +924,8 @@ svn_cl__merge_file(const char *base_path,
fmb.abort_merge = FALSE;
fmb.scratch_pool = scratch_pool;
- SVN_ERR(svn_diff_output(diff, &fmb, &file_merge_diff_output_fns));
+ SVN_ERR(svn_diff_output2(diff, &fmb, &file_merge_diff_output_fns,
+ cancel_func, cancel_baton));
SVN_ERR(svn_io_file_close(original_file, scratch_pool));
SVN_ERR(svn_io_file_close(modified_file, scratch_pool));
diff --git a/subversion/svn/help-cmd.c b/subversion/svn/help-cmd.c
index 93fecc32249b..b095d30fd1c2 100644
--- a/subversion/svn/help-cmd.c
+++ b/subversion/svn/help-cmd.c
@@ -30,8 +30,8 @@
#include "svn_hash.h"
#include "svn_string.h"
#include "svn_config.h"
+#include "svn_dirent_uri.h"
#include "svn_error.h"
-#include "svn_version.h"
#include "cl.h"
#include "svn_private_config.h"
@@ -47,11 +47,11 @@ svn_cl__help(apr_getopt_t *os,
{
svn_cl__opt_state_t *opt_state = NULL;
svn_stringbuf_t *version_footer = NULL;
+ const char *config_path;
- /* xgettext: the %s is for SVN_VER_NUMBER. */
- char help_header_template[] =
+ char help_header[] =
N_("usage: svn <subcommand> [options] [args]\n"
- "Subversion command-line client, version %s.\n"
+ "Subversion command-line client.\n"
"Type 'svn help <subcommand>' for help on a specific subcommand.\n"
"Type 'svn --version' to see the program version and RA modules\n"
" or 'svn --version --quiet' to see just the version number.\n"
@@ -66,9 +66,6 @@ svn_cl__help(apr_getopt_t *os,
N_("Subversion is a tool for version control.\n"
"For additional information, see http://subversion.apache.org/\n");
- char *help_header =
- apr_psprintf(pool, _(help_header_template), SVN_VER_NUMBER);
-
const char *ra_desc_start
= _("The following repository access (RA) modules are available:\n\n");
@@ -138,6 +135,46 @@ svn_cl__help(apr_getopt_t *os,
version_footer = svn_stringbuf_create(ra_desc_start, pool);
SVN_ERR(svn_ra_print_modules(version_footer, pool));
+ /*
+ * Show auth creds storage providers.
+ */
+ SVN_ERR(svn_config_get_user_config_path(&config_path,
+ opt_state ? opt_state->config_dir
+ : NULL,
+ NULL,
+ pool));
+ svn_stringbuf_appendcstr(version_footer,
+ _("\nThe following authentication credential caches are available:\n\n"));
+
+ /*### There is no API to query available providers at run time. */
+#if (defined(WIN32) && !defined(__MINGW32__))
+ version_footer =
+ svn_stringbuf_create(apr_psprintf(pool, _("%s* Wincrypt cache in %s\n"),
+ version_footer->data,
+ svn_dirent_local_style(config_path,
+ pool)),
+ pool);
+#elif !defined(SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE)
+ version_footer =
+ svn_stringbuf_create(apr_psprintf(pool, _("%s* Plaintext cache in %s\n"),
+ version_footer->data,
+ svn_dirent_local_style(config_path,
+ pool)),
+ pool);
+#endif
+#ifdef SVN_HAVE_GNOME_KEYRING
+ svn_stringbuf_appendcstr(version_footer, "* Gnome Keyring\n");
+#endif
+#ifdef SVN_HAVE_GPG_AGENT
+ svn_stringbuf_appendcstr(version_footer, "* GPG-Agent\n");
+#endif
+#ifdef SVN_HAVE_KEYCHAIN_SERVICES
+ svn_stringbuf_appendcstr(version_footer, "* Mac OS X Keychain\n");
+#endif
+#ifdef SVN_HAVE_KWALLET
+ svn_stringbuf_appendcstr(version_footer, "* KWallet (KDE)\n");
+#endif
+
return svn_opt_print_help4(os,
"svn", /* ### erm, derive somehow? */
opt_state ? opt_state->version : FALSE,
diff --git a/subversion/svn/info-cmd.c b/subversion/svn/info-cmd.c
index 56833f6edc67..0040986207c7 100644
--- a/subversion/svn/info-cmd.c
+++ b/subversion/svn/info-cmd.c
@@ -76,6 +76,168 @@ schedule_str(svn_wc_schedule_t schedule)
}
}
+/* Return a relative URL from information in INFO using POOL for
+ temporary allocation. */
+static const char*
+relative_url(const svn_client_info2_t *info, apr_pool_t *pool)
+{
+ return apr_pstrcat(pool, "^/",
+ svn_path_uri_encode(
+ svn_uri_skip_ancestor(info->repos_root_URL,
+ info->URL, pool),
+ pool), SVN_VA_NULL);
+}
+
+
+/* The kinds of items for print_info_item(). */
+typedef enum
+{
+ /* Entry kind */
+ info_item_kind,
+
+ /* Repository location. */
+ info_item_url,
+ info_item_relative_url,
+ info_item_repos_root_url,
+ info_item_repos_uuid,
+
+ /* Working copy revision or repository HEAD revision */
+ info_item_revision,
+
+ /* Commit details. */
+ info_item_last_changed_rev,
+ info_item_last_changed_date,
+ info_item_last_changed_author,
+
+ /* Working copy information */
+ info_item_wc_root
+} info_item_t;
+
+/* Mapping between option keywords and info_item_t. */
+typedef struct info_item_map_t
+{
+ const svn_string_t keyword;
+ const info_item_t print_what;
+} info_item_map_t;
+
+#define MAKE_STRING(x) { x, sizeof(x) - 1 }
+static const info_item_map_t info_item_map[] =
+ {
+ { MAKE_STRING("kind"), info_item_kind },
+ { MAKE_STRING("url"), info_item_url },
+ { MAKE_STRING("relative-url"), info_item_relative_url },
+ { MAKE_STRING("repos-root-url"), info_item_repos_root_url },
+ { MAKE_STRING("repos-uuid"), info_item_repos_uuid },
+ { MAKE_STRING("revision"), info_item_revision },
+ { MAKE_STRING("last-changed-revision"),
+ info_item_last_changed_rev },
+ { MAKE_STRING("last-changed-date"), info_item_last_changed_date },
+ { MAKE_STRING("last-changed-author"), info_item_last_changed_author },
+ { MAKE_STRING("wc-root"), info_item_wc_root }
+ };
+#undef MAKE_STRING
+
+static const apr_size_t info_item_map_len =
+ (sizeof(info_item_map) / sizeof(info_item_map[0]));
+
+
+/* The baton type used by the info receiver functions. */
+typedef struct print_info_baton_t
+{
+ /* The path prefix that output paths should be normalized to. */
+ const char *path_prefix;
+
+ /*
+ * The following fields are used by print_info_item().
+ */
+
+ /* Which item to print. */
+ info_item_t print_what;
+
+ /* Do we expect to show info for multiple targets? */
+ svn_boolean_t multiple_targets;
+
+ /* TRUE iff the current is a local path. */
+ svn_boolean_t target_is_path;
+
+ /* Did we already print a line of output? */
+ svn_boolean_t start_new_line;
+} print_info_baton_t;
+
+
+/* Find the appropriate info_item_t for KEYWORD and initialize
+ * RECEIVER_BATON for print_info_item(). Use SCRATCH_POOL for
+ * temporary allocation.
+ */
+static svn_error_t *
+find_print_what(const char *keyword,
+ print_info_baton_t *receiver_baton,
+ apr_pool_t *scratch_pool)
+{
+ svn_cl__simcheck_t **keywords = apr_palloc(
+ scratch_pool, info_item_map_len * sizeof(svn_cl__simcheck_t*));
+ svn_cl__simcheck_t *kwbuf = apr_palloc(
+ scratch_pool, info_item_map_len * sizeof(svn_cl__simcheck_t));
+ apr_size_t i;
+
+ for (i = 0; i < info_item_map_len; ++i)
+ {
+ keywords[i] = &kwbuf[i];
+ kwbuf[i].token.data = info_item_map[i].keyword.data;
+ kwbuf[i].token.len = info_item_map[i].keyword.len;
+ kwbuf[i].data = &info_item_map[i];
+ }
+
+ switch (svn_cl__similarity_check(keyword, keywords,
+ info_item_map_len, scratch_pool))
+ {
+ const info_item_map_t *kw0;
+ const info_item_map_t *kw1;
+ const info_item_map_t *kw2;
+
+ case 0: /* Exact match. */
+ kw0 = keywords[0]->data;
+ receiver_baton->print_what = kw0->print_what;
+ return SVN_NO_ERROR;
+
+ case 1:
+ /* The best alternative isn't good enough */
+ return svn_error_createf(
+ SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("'%s' is not a valid value for --show-item"),
+ keyword);
+
+ case 2:
+ /* There is only one good candidate */
+ kw0 = keywords[0]->data;
+ return svn_error_createf(
+ SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("'%s' is not a valid value for --show-item;"
+ " did you mean '%s'?"),
+ keyword, kw0->keyword.data);
+
+ case 3:
+ /* Suggest a list of the most likely candidates */
+ kw0 = keywords[0]->data;
+ kw1 = keywords[1]->data;
+ return svn_error_createf(
+ SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("'%s' is not a valid value for --show-item;"
+ " did you mean '%s' or '%s'?"),
+ keyword, kw0->keyword.data, kw1->keyword.data);
+
+ default:
+ /* Never suggest more than three candidates */
+ kw0 = keywords[0]->data;
+ kw1 = keywords[1]->data;
+ kw2 = keywords[2]->data;
+ return svn_error_createf(
+ SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("'%s' is not a valid value for --show-item;"
+ " did you mean '%s', '%s' or '%s'?"),
+ keyword, kw0->keyword.data, kw1->keyword.data, kw2->keyword.data);
+ }
+}
/* A callback of type svn_client_info_receiver2_t.
Prints svn info in xml mode to standard out */
@@ -87,7 +249,7 @@ print_info_xml(void *baton,
{
svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
const char *rev_str;
- const char *path_prefix = baton;
+ print_info_baton_t *const receiver_baton = baton;
if (SVN_IS_VALID_REVNUM(info->rev))
rev_str = apr_psprintf(pool, "%ld", info->rev);
@@ -97,10 +259,10 @@ print_info_xml(void *baton,
/* "<entry ...>" */
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "entry",
"path", svn_cl__local_style_skip_ancestor(
- path_prefix, target, pool),
+ receiver_baton->path_prefix, target, pool),
"kind", svn_cl__node_kind_str_xml(info->kind),
"revision", rev_str,
- NULL);
+ SVN_VA_NULL);
/* "<url> xx </url>" */
svn_cl__xml_tagged_cdata(&sb, pool, "url", info->URL);
@@ -109,19 +271,14 @@ print_info_xml(void *baton,
{
/* "<relative-url> xx </relative-url>" */
svn_cl__xml_tagged_cdata(&sb, pool, "relative-url",
- apr_pstrcat(pool, "^/",
- svn_path_uri_encode(
- svn_uri_skip_ancestor(
- info->repos_root_URL,
- info->URL, pool),
- pool),
- NULL));
+ relative_url(info, pool));
}
if (info->repos_root_URL || info->repos_UUID)
{
/* "<repository>" */
- svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "repository", NULL);
+ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "repository",
+ SVN_VA_NULL);
/* "<root> xx </root>" */
svn_cl__xml_tagged_cdata(&sb, pool, "root", info->repos_root_URL);
@@ -136,7 +293,8 @@ print_info_xml(void *baton,
if (info->wc_info)
{
/* "<wc-info>" */
- svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "wc-info", NULL);
+ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "wc-info",
+ SVN_VA_NULL);
/* "<wcroot-abspath> xx </wcroot-abspath>" */
if (info->wc_info->wcroot_abspath)
@@ -261,11 +419,11 @@ print_info(void *baton,
const svn_client_info2_t *info,
apr_pool_t *pool)
{
- const char *path_prefix = baton;
+ print_info_baton_t *const receiver_baton = baton;
SVN_ERR(svn_cmdline_printf(pool, _("Path: %s\n"),
svn_cl__local_style_skip_ancestor(
- path_prefix, target, pool)));
+ receiver_baton->path_prefix, target, pool)));
/* ### remove this someday: it's only here for cmdline output
compatibility with svn 1.1 and older. */
@@ -283,11 +441,8 @@ print_info(void *baton,
SVN_ERR(svn_cmdline_printf(pool, _("URL: %s\n"), info->URL));
if (info->URL && info->repos_root_URL)
- SVN_ERR(svn_cmdline_printf(pool, _("Relative URL: ^/%s\n"),
- svn_path_uri_encode(
- svn_uri_skip_ancestor(info->repos_root_URL,
- info->URL, pool),
- pool)));
+ SVN_ERR(svn_cmdline_printf(pool, _("Relative URL: %s\n"),
+ relative_url(info, pool)));
if (info->repos_root_URL)
SVN_ERR(svn_cmdline_printf(pool, _("Repository Root: %s\n"),
@@ -387,30 +542,18 @@ print_info(void *baton,
SVN_ERR(svn_cmdline_printf(pool, _("Copied From Rev: %ld\n"),
info->wc_info->copyfrom_rev));
if (info->wc_info->moved_from_abspath)
- {
- const char *relpath;
-
- relpath = svn_dirent_skip_ancestor(info->wc_info->wcroot_abspath,
- info->wc_info->moved_from_abspath);
- if (relpath && relpath[0] != '\0')
- SVN_ERR(svn_cmdline_printf(pool, _("Moved From: %s\n"), relpath));
- else
- SVN_ERR(svn_cmdline_printf(pool, _("Moved From: %s\n"),
- info->wc_info->moved_from_abspath));
- }
+ SVN_ERR(svn_cmdline_printf(pool, _("Moved From: %s\n"),
+ svn_cl__local_style_skip_ancestor(
+ receiver_baton->path_prefix,
+ info->wc_info->moved_from_abspath,
+ pool)));
if (info->wc_info->moved_to_abspath)
- {
- const char *relpath;
-
- relpath = svn_dirent_skip_ancestor(info->wc_info->wcroot_abspath,
- info->wc_info->moved_to_abspath);
- if (relpath && relpath[0] != '\0')
- SVN_ERR(svn_cmdline_printf(pool, _("Moved To: %s\n"), relpath));
- else
- SVN_ERR(svn_cmdline_printf(pool, _("Moved To: %s\n"),
- info->wc_info->moved_to_abspath));
- }
+ SVN_ERR(svn_cmdline_printf(pool, _("Moved To: %s\n"),
+ svn_cl__local_style_skip_ancestor(
+ receiver_baton->path_prefix,
+ info->wc_info->moved_to_abspath,
+ pool)));
}
if (info->last_changed_author)
@@ -439,6 +582,7 @@ print_info(void *baton,
if (info->wc_info->conflicts)
{
svn_boolean_t printed_prop_conflict_file = FALSE;
+ svn_boolean_t printed_tc = FALSE;
int i;
for (i = 0; i < info->wc_info->conflicts->nelts; i++)
@@ -455,21 +599,24 @@ print_info(void *baton,
SVN_ERR(svn_cmdline_printf(pool,
_("Conflict Previous Base File: %s\n"),
svn_cl__local_style_skip_ancestor(
- path_prefix, conflict->base_abspath,
+ receiver_baton->path_prefix,
+ conflict->base_abspath,
pool)));
if (conflict->my_abspath)
SVN_ERR(svn_cmdline_printf(pool,
_("Conflict Previous Working File: %s\n"),
svn_cl__local_style_skip_ancestor(
- path_prefix, conflict->my_abspath,
+ receiver_baton->path_prefix,
+ conflict->my_abspath,
pool)));
if (conflict->their_abspath)
SVN_ERR(svn_cmdline_printf(pool,
_("Conflict Current Base File: %s\n"),
svn_cl__local_style_skip_ancestor(
- path_prefix, conflict->their_abspath,
+ receiver_baton->path_prefix,
+ conflict->their_abspath,
pool)));
break;
@@ -477,12 +624,15 @@ print_info(void *baton,
if (! printed_prop_conflict_file)
SVN_ERR(svn_cmdline_printf(pool,
_("Conflict Properties File: %s\n"),
- svn_dirent_local_style(conflict->their_abspath,
- pool)));
+ svn_cl__local_style_skip_ancestor(
+ receiver_baton->path_prefix,
+ conflict->prop_reject_abspath,
+ pool)));
printed_prop_conflict_file = TRUE;
break;
case svn_wc_conflict_kind_tree:
+ printed_tc = TRUE;
SVN_ERR(
svn_cl__get_human_readable_tree_conflict_description(
&desc, conflict, pool));
@@ -504,6 +654,19 @@ print_info(void *baton,
APR_ARRAY_IDX(info->wc_info->conflicts, 0,
const svn_wc_conflict_description2_t *);
+ if (!printed_tc)
+ {
+ const char *desc;
+
+ SVN_ERR(svn_cl__get_human_readable_action_description(&desc,
+ svn_wc_conflict_action_edit,
+ conflict->operation,
+ conflict->node_kind, pool));
+
+ SVN_ERR(svn_cmdline_printf(pool, "%s: %s\n",
+ _("Conflict Details"), desc));
+ }
+
src_left_version =
svn_cl__node_description(conflict->src_left_version,
info->repos_root_URL, pool);
@@ -570,6 +733,123 @@ print_info(void *baton,
}
+/* Helper for print_info_item(): Print the value TEXT for TARGET_PATH,
+ either of which may be NULL. Use POOL for temporary allocation. */
+static svn_error_t *
+print_info_item_string(const char *text, const char *target_path,
+ apr_pool_t *pool)
+{
+ if (text)
+ {
+ if (target_path)
+ SVN_ERR(svn_cmdline_printf(pool, "%-10s %s", text, target_path));
+ else
+ SVN_ERR(svn_cmdline_fputs(text, stdout, pool));
+ }
+ else if (target_path)
+ SVN_ERR(svn_cmdline_printf(pool, "%-10s %s", "", target_path));
+
+ return SVN_NO_ERROR;
+}
+
+/* Helper for print_info_item(): Print the revision number REV, which
+ may be SVN_INVALID_REVNUM, for TARGET_PATH, which may be NULL. Use
+ POOL for temporary allocation. */
+static svn_error_t *
+print_info_item_revision(svn_revnum_t rev, const char *target_path,
+ apr_pool_t *pool)
+{
+ if (SVN_IS_VALID_REVNUM(rev))
+ {
+ if (target_path)
+ SVN_ERR(svn_cmdline_printf(pool, "%-10ld %s", rev, target_path));
+ else
+ SVN_ERR(svn_cmdline_printf(pool, "%-10ld", rev));
+ }
+ else if (target_path)
+ SVN_ERR(svn_cmdline_printf(pool, "%-10s %s", "", target_path));
+
+ return SVN_NO_ERROR;
+}
+
+/* A callback of type svn_client_info_receiver2_t. */
+static svn_error_t *
+print_info_item(void *baton,
+ const char *target,
+ const svn_client_info2_t *info,
+ apr_pool_t *pool)
+{
+ print_info_baton_t *const receiver_baton = baton;
+ const char *const target_path =
+ (!receiver_baton->multiple_targets ? NULL
+ : (!receiver_baton->target_is_path ? info->URL
+ : svn_cl__local_style_skip_ancestor(
+ receiver_baton->path_prefix, target, pool)));
+
+ if (receiver_baton->start_new_line)
+ SVN_ERR(svn_cmdline_fputs("\n", stdout, pool));
+
+ switch (receiver_baton->print_what)
+ {
+ case info_item_kind:
+ SVN_ERR(print_info_item_string(svn_node_kind_to_word(info->kind),
+ target_path, pool));
+ break;
+
+ case info_item_url:
+ SVN_ERR(print_info_item_string(info->URL, target_path, pool));
+ break;
+
+ case info_item_relative_url:
+ SVN_ERR(print_info_item_string(relative_url(info, pool),
+ target_path, pool));
+ break;
+
+ case info_item_repos_root_url:
+ SVN_ERR(print_info_item_string(info->repos_root_URL, target_path, pool));
+ break;
+
+ case info_item_repos_uuid:
+ SVN_ERR(print_info_item_string(info->repos_UUID, target_path, pool));
+ break;
+
+ case info_item_revision:
+ SVN_ERR(print_info_item_revision(info->rev, target_path, pool));
+ break;
+
+ case info_item_last_changed_rev:
+ SVN_ERR(print_info_item_revision(info->last_changed_rev,
+ target_path, pool));
+ break;
+
+ case info_item_last_changed_date:
+ SVN_ERR(print_info_item_string(
+ (!info->last_changed_date ? NULL
+ : svn_time_to_cstring(info->last_changed_date, pool)),
+ target_path, pool));
+ break;
+
+ case info_item_last_changed_author:
+ SVN_ERR(print_info_item_string(info->last_changed_author,
+ target_path, pool));
+ break;
+
+ case info_item_wc_root:
+ SVN_ERR(print_info_item_string(
+ (info->wc_info && info->wc_info->wcroot_abspath
+ ? info->wc_info->wcroot_abspath : NULL),
+ target_path, pool));
+ break;
+
+ default:
+ SVN_ERR_MALFUNCTION();
+ }
+
+ receiver_baton->start_new_line = TRUE;
+ return SVN_NO_ERROR;
+}
+
+
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__info(apr_getopt_t *os,
@@ -585,7 +865,7 @@ svn_cl__info(apr_getopt_t *os,
svn_boolean_t seen_nonexistent_target = FALSE;
svn_opt_revision_t peg_revision;
svn_client_info_receiver2_t receiver;
- const char *path_prefix;
+ print_info_baton_t receiver_baton = { 0 };
SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
opt_state->targets,
@@ -598,26 +878,59 @@ svn_cl__info(apr_getopt_t *os,
{
receiver = print_info_xml;
+ if (opt_state->show_item)
+ return svn_error_create(
+ SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--show-item is not valid in --xml mode"));
+ if (opt_state->no_newline)
+ return svn_error_create(
+ SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--no-newline is not valid in --xml mode"));
+
/* If output is not incremental, output the XML header and wrap
everything in a top-level element. This makes the output in
its entirety a well-formed XML document. */
if (! opt_state->incremental)
SVN_ERR(svn_cl__xml_print_header("info", pool));
}
+ else if (opt_state->show_item)
+ {
+ receiver = print_info_item;
+
+ if (opt_state->incremental)
+ return svn_error_create(
+ SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--incremental is only valid in --xml mode"));
+
+ receiver_baton.multiple_targets = (opt_state->depth > svn_depth_empty
+ || targets->nelts > 1);
+ if (receiver_baton.multiple_targets && opt_state->no_newline)
+ return svn_error_create(
+ SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--no-newline is only available for single-target,"
+ " non-recursive info operations"));
+
+ SVN_ERR(find_print_what(opt_state->show_item, &receiver_baton, pool));
+ receiver_baton.start_new_line = FALSE;
+ }
else
{
receiver = print_info;
if (opt_state->incremental)
- return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("'incremental' option only valid in XML "
- "mode"));
+ return svn_error_create(
+ SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--incremental is only valid in --xml mode"));
+ if (opt_state->no_newline)
+ return svn_error_create(
+ SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--no-newline' is only valid with --show-item"));
}
if (opt_state->depth == svn_depth_unknown)
opt_state->depth = svn_depth_empty;
- SVN_ERR(svn_dirent_get_absolute(&path_prefix, "", pool));
+ SVN_ERR(svn_dirent_get_absolute(&receiver_baton.path_prefix, "", pool));
for (i = 0; i < targets->nelts; i++)
{
@@ -635,17 +948,22 @@ svn_cl__info(apr_getopt_t *os,
{
if (peg_revision.kind == svn_opt_revision_unspecified)
peg_revision.kind = svn_opt_revision_head;
+ receiver_baton.target_is_path = FALSE;
}
else
{
SVN_ERR(svn_dirent_get_absolute(&truepath, truepath, subpool));
+ receiver_baton.target_is_path = TRUE;
}
- err = svn_client_info3(truepath,
+ err = svn_client_info4(truepath,
&peg_revision, &(opt_state->start_revision),
- opt_state->depth, TRUE, TRUE,
+ opt_state->depth,
+ TRUE /* fetch_excluded */,
+ TRUE /* fetch_actual_only */,
+ opt_state->include_externals,
opt_state->changelists,
- receiver, (void *) path_prefix,
+ receiver, &receiver_baton,
ctx, subpool);
if (err)
@@ -672,6 +990,9 @@ svn_cl__info(apr_getopt_t *os,
if (opt_state->xml && (! opt_state->incremental))
SVN_ERR(svn_cl__xml_print_footer("info", pool));
+ else if (opt_state->show_item && !opt_state->no_newline
+ && receiver_baton.start_new_line)
+ SVN_ERR(svn_cmdline_fputs("\n", stdout, pool));
if (seen_nonexistent_target)
return svn_error_create(
diff --git a/subversion/svn/list-cmd.c b/subversion/svn/list-cmd.c
index 022ad54975d8..5ea140fc93d1 100644
--- a/subversion/svn/list-cmd.c
+++ b/subversion/svn/list-cmd.c
@@ -222,7 +222,7 @@ print_dirent_xml(void *baton,
svn_xml_make_open_tag(&sb, scratch_pool, svn_xml_normal, "external",
"parent_url", external_parent_url,
"target", external_target,
- NULL);
+ SVN_VA_NULL);
pb->last_external_parent_url = external_parent_url;
pb->last_external_target = external_target;
@@ -232,7 +232,7 @@ print_dirent_xml(void *baton,
svn_xml_make_open_tag(&sb, scratch_pool, svn_xml_normal, "entry",
"kind", svn_cl__node_kind_str_xml(dirent->kind),
- NULL);
+ SVN_VA_NULL);
svn_cl__xml_tagged_cdata(&sb, scratch_pool, "name", entryname);
@@ -246,7 +246,7 @@ print_dirent_xml(void *baton,
svn_xml_make_open_tag(&sb, scratch_pool, svn_xml_normal, "commit",
"revision",
apr_psprintf(scratch_pool, "%ld", dirent->created_rev),
- NULL);
+ SVN_VA_NULL);
svn_cl__xml_tagged_cdata(&sb, scratch_pool, "author", dirent->last_author);
if (dirent->time)
svn_cl__xml_tagged_cdata(&sb, scratch_pool, "date",
@@ -255,7 +255,8 @@ print_dirent_xml(void *baton,
if (lock)
{
- svn_xml_make_open_tag(&sb, scratch_pool, svn_xml_normal, "lock", NULL);
+ svn_xml_make_open_tag(&sb, scratch_pool, svn_xml_normal, "lock",
+ SVN_VA_NULL);
svn_cl__xml_tagged_cdata(&sb, scratch_pool, "token", lock->token);
svn_cl__xml_tagged_cdata(&sb, scratch_pool, "owner", lock->owner);
svn_cl__xml_tagged_cdata(&sb, scratch_pool, "comment", lock->comment);
@@ -370,7 +371,7 @@ svn_cl__list(apr_getopt_t *os,
svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "list",
"path", truepath[0] == '\0' ? "." : truepath,
- NULL);
+ SVN_VA_NULL);
SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
}
@@ -430,6 +431,8 @@ svn_cl__list(apr_getopt_t *os,
if (seen_nonexistent_target)
err = svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL,
_("Could not list all targets because some targets don't exist"));
+ else
+ err = NULL;
return svn_error_compose_create(externals_err, err);
}
diff --git a/subversion/svn/log-cmd.c b/subversion/svn/log-cmd.c
index af57cf4de5b3..44f8a4cff292 100644
--- a/subversion/svn/log-cmd.c
+++ b/subversion/svn/log-cmd.c
@@ -37,51 +37,16 @@
#include "svn_pools.h"
#include "private/svn_cmdline_private.h"
+#include "private/svn_sorts_private.h"
#include "cl.h"
+#include "cl-log.h"
#include "svn_private_config.h"
/*** Code. ***/
-/* Baton for log_entry_receiver() and log_entry_receiver_xml(). */
-struct log_receiver_baton
-{
- /* Client context. */
- svn_client_ctx_t *ctx;
-
- /* The target of the log operation. */
- const char *target_path_or_url;
- svn_opt_revision_t target_peg_revision;
-
- /* Don't print log message body nor its line count. */
- svn_boolean_t omit_log_message;
-
- /* Whether to show diffs in the log. (maps to --diff) */
- svn_boolean_t show_diff;
-
- /* Depth applied to diff output. */
- svn_depth_t depth;
-
- /* Diff arguments received from command line. */
- const char *diff_extensions;
-
- /* Stack which keeps track of merge revision nesting, using svn_revnum_t's */
- apr_array_header_t *merge_stack;
-
- /* Log message search patterns. Log entries will only be shown if the author,
- * the log message, or a changed path matches one of these patterns. */
- apr_array_header_t *search_patterns;
-
- /* Pool for persistent allocations. */
- apr_pool_t *pool;
-};
-
-
-/* The separator between log messages. */
-#define SEP_STRING \
- "------------------------------------------------------------------------\n"
/* Display a diff of the subtree TARGET_PATH_OR_URL@TARGET_PEG_REVISION as
@@ -182,14 +147,14 @@ match_search_pattern(const char *search_pattern,
hi;
hi = apr_hash_next(hi))
{
- const char *path = svn__apr_hash_index_key(hi);
+ const char *path = apr_hash_this_key(hi);
svn_log_changed_path2_t *log_item;
if (apr_fnmatch(pattern, path, flags) == APR_SUCCESS)
return TRUE;
/* Match copy-from paths, too. */
- log_item = svn__apr_hash_index_val(hi);
+ log_item = apr_hash_this_val(hi);
if (log_item->copyfrom_path
&& SVN_IS_VALID_REVNUM(log_item->copyfrom_rev)
&& apr_fnmatch(pattern,
@@ -249,7 +214,7 @@ match_search_patterns(apr_array_header_t *search_patterns,
/* Implement `svn_log_entry_receiver_t', printing the logs in
* a human-readable and machine-parseable format.
*
- * BATON is of type `struct log_receiver_baton'.
+ * BATON is of type `svn_cl__log_receiver_baton'.
*
* First, print a header line. Then if CHANGED_PATHS is non-null,
* print all affected paths in a list headed "Changed paths:\n",
@@ -323,12 +288,12 @@ match_search_patterns(apr_array_header_t *search_patterns,
* ------------------------------------------------------------------------
*
*/
-static svn_error_t *
-log_entry_receiver(void *baton,
- svn_log_entry_t *log_entry,
- apr_pool_t *pool)
+svn_error_t *
+svn_cl__log_entry_receiver(void *baton,
+ svn_log_entry_t *log_entry,
+ apr_pool_t *pool)
{
- struct log_receiver_baton *lb = baton;
+ svn_cl__log_receiver_baton *lb = baton;
const char *author;
const char *date;
const char *message;
@@ -343,7 +308,9 @@ log_entry_receiver(void *baton,
if (! SVN_IS_VALID_REVNUM(log_entry->revision))
{
- apr_array_pop(lb->merge_stack);
+ if (lb->merge_stack)
+ apr_array_pop(lb->merge_stack);
+
return SVN_NO_ERROR;
}
@@ -367,13 +334,18 @@ log_entry_receiver(void *baton,
log_entry->changed_paths2, pool))
{
if (log_entry->has_children)
- APR_ARRAY_PUSH(lb->merge_stack, svn_revnum_t) = log_entry->revision;
+ {
+ if (! lb->merge_stack)
+ lb->merge_stack = apr_array_make(lb->pool, 1, sizeof(svn_revnum_t));
+
+ APR_ARRAY_PUSH(lb->merge_stack, svn_revnum_t) = log_entry->revision;
+ }
return SVN_NO_ERROR;
}
SVN_ERR(svn_cmdline_printf(pool,
- SEP_STRING "r%ld | %s | %s",
+ SVN_CL__LOG_SEP_STRING "r%ld | %s | %s",
log_entry->revision, author, date));
if (message != NULL)
@@ -392,6 +364,7 @@ log_entry_receiver(void *baton,
{
apr_array_header_t *sorted_paths;
int i;
+ apr_pool_t *iterpool;
/* Get an array of sorted hash keys. */
sorted_paths = svn_sort__hash(log_entry->changed_paths2,
@@ -399,6 +372,7 @@ log_entry_receiver(void *baton,
SVN_ERR(svn_cmdline_printf(pool,
_("Changed paths:\n")));
+ iterpool = svn_pool_create(pool);
for (i = 0; i < sorted_paths->nelts; i++)
{
svn_sort__item_t *item = &(APR_ARRAY_IDX(sorted_paths, i,
@@ -407,6 +381,8 @@ log_entry_receiver(void *baton,
svn_log_changed_path2_t *log_item = item->value;
const char *copy_data = "";
+ svn_pool_clear(iterpool);
+
if (lb->ctx->cancel_func)
SVN_ERR(lb->ctx->cancel_func(lb->ctx->cancel_baton));
@@ -414,34 +390,39 @@ log_entry_receiver(void *baton,
&& SVN_IS_VALID_REVNUM(log_item->copyfrom_rev))
{
copy_data
- = apr_psprintf(pool,
+ = apr_psprintf(iterpool,
_(" (from %s:%ld)"),
log_item->copyfrom_path,
log_item->copyfrom_rev);
}
- SVN_ERR(svn_cmdline_printf(pool, " %c %s%s\n",
+ SVN_ERR(svn_cmdline_printf(iterpool, " %c %s%s\n",
log_item->action, path,
copy_data));
}
+ svn_pool_destroy(iterpool);
}
- if (lb->merge_stack->nelts > 0)
+ if (lb->merge_stack && lb->merge_stack->nelts > 0)
{
int i;
+ apr_pool_t *iterpool;
/* Print the result of merge line */
if (log_entry->subtractive_merge)
SVN_ERR(svn_cmdline_printf(pool, _("Reverse merged via:")));
else
SVN_ERR(svn_cmdline_printf(pool, _("Merged via:")));
+ iterpool = svn_pool_create(pool);
for (i = 0; i < lb->merge_stack->nelts; i++)
{
svn_revnum_t rev = APR_ARRAY_IDX(lb->merge_stack, i, svn_revnum_t);
- SVN_ERR(svn_cmdline_printf(pool, " r%ld%c", rev,
+ svn_pool_clear(iterpool);
+ SVN_ERR(svn_cmdline_printf(iterpool, " r%ld%c", rev,
i == lb->merge_stack->nelts - 1 ?
'\n' : ','));
}
+ svn_pool_destroy(iterpool);
}
if (message != NULL)
@@ -473,7 +454,12 @@ log_entry_receiver(void *baton,
}
if (log_entry->has_children)
- APR_ARRAY_PUSH(lb->merge_stack, svn_revnum_t) = log_entry->revision;
+ {
+ if (! lb->merge_stack)
+ lb->merge_stack = apr_array_make(lb->pool, 1, sizeof(svn_revnum_t));
+
+ APR_ARRAY_PUSH(lb->merge_stack, svn_revnum_t) = log_entry->revision;
+ }
return SVN_NO_ERROR;
}
@@ -481,7 +467,7 @@ log_entry_receiver(void *baton,
/* This implements `svn_log_entry_receiver_t', printing the logs in XML.
*
- * BATON is of type `struct log_receiver_baton'.
+ * BATON is of type `svn_cl__log_receiver_baton'.
*
* Here is an example of the output; note that the "<log>" and
* "</log>" tags are not emitted by this function:
@@ -515,12 +501,12 @@ log_entry_receiver(void *baton,
* </log>
*
*/
-static svn_error_t *
-log_entry_receiver_xml(void *baton,
- svn_log_entry_t *log_entry,
- apr_pool_t *pool)
+svn_error_t *
+svn_cl__log_entry_receiver_xml(void *baton,
+ svn_log_entry_t *log_entry,
+ apr_pool_t *pool)
{
- struct log_receiver_baton *lb = baton;
+ svn_cl__log_receiver_baton *lb = baton;
/* Collate whole log message into sb before printing. */
svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
char *revstr;
@@ -540,7 +526,8 @@ log_entry_receiver_xml(void *baton,
{
svn_xml_make_close_tag(&sb, pool, "logentry");
SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
- apr_array_pop(lb->merge_stack);
+ if (lb->merge_stack)
+ apr_array_pop(lb->merge_stack);
return SVN_NO_ERROR;
}
@@ -551,7 +538,12 @@ log_entry_receiver_xml(void *baton,
log_entry->changed_paths2, pool))
{
if (log_entry->has_children)
- APR_ARRAY_PUSH(lb->merge_stack, svn_revnum_t) = log_entry->revision;
+ {
+ if (! lb->merge_stack)
+ lb->merge_stack = apr_array_make(lb->pool, 1, sizeof(svn_revnum_t));
+
+ APR_ARRAY_PUSH(lb->merge_stack, svn_revnum_t) = log_entry->revision;
+ }
return SVN_NO_ERROR;
}
@@ -565,8 +557,19 @@ log_entry_receiver_xml(void *baton,
revstr = apr_psprintf(pool, "%ld", log_entry->revision);
/* <logentry revision="xxx"> */
- svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "logentry",
- "revision", revstr, NULL);
+ if (lb->merge_stack && lb->merge_stack->nelts > 0)
+ {
+ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "logentry",
+ "revision", revstr, "reverse-merge",
+ log_entry->subtractive_merge ? "true" : "false",
+ SVN_VA_NULL);
+
+ }
+ else
+ {
+ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "logentry",
+ "revision", revstr, SVN_VA_NULL);
+ }
/* <author>xxx</author> */
svn_cl__xml_tagged_cdata(&sb, pool, "author", author);
@@ -587,7 +590,7 @@ log_entry_receiver_xml(void *baton,
/* <paths> */
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "paths",
- NULL);
+ SVN_VA_NULL);
/* Get an array of sorted hash keys. */
sorted_paths = svn_sort__hash(log_entry->changed_paths2,
@@ -619,7 +622,7 @@ log_entry_receiver_xml(void *baton,
log_item->text_modified),
"prop-mods", svn_tristate__to_word(
log_item->props_modified),
- NULL);
+ SVN_VA_NULL);
}
else
{
@@ -632,7 +635,7 @@ log_entry_receiver_xml(void *baton,
log_item->text_modified),
"prop-mods", svn_tristate__to_word(
log_item->props_modified),
- NULL);
+ SVN_VA_NULL);
}
/* xxx</path> */
svn_xml_escape_cdata_cstring(&sb, path, pool);
@@ -652,7 +655,7 @@ log_entry_receiver_xml(void *baton,
svn_compat_log_revprops_clear(log_entry->revprops);
if (log_entry->revprops && apr_hash_count(log_entry->revprops) > 0)
{
- svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "revprops", NULL);
+ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "revprops", SVN_VA_NULL);
SVN_ERR(svn_cmdline__print_xml_prop_hash(&sb, log_entry->revprops,
FALSE, /* name_only */
FALSE, pool));
@@ -660,7 +663,12 @@ log_entry_receiver_xml(void *baton,
}
if (log_entry->has_children)
- APR_ARRAY_PUSH(lb->merge_stack, svn_revnum_t) = log_entry->revision;
+ {
+ if (! lb->merge_stack)
+ lb->merge_stack = apr_array_make(lb->pool, 1, sizeof(svn_revnum_t));
+
+ APR_ARRAY_PUSH(lb->merge_stack, svn_revnum_t) = log_entry->revision;
+ }
else
svn_xml_make_close_tag(&sb, pool, "logentry");
@@ -677,7 +685,7 @@ svn_cl__log(apr_getopt_t *os,
svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
apr_array_header_t *targets;
- struct log_receiver_baton lb;
+ svn_cl__log_receiver_baton lb;
const char *target;
int i;
apr_array_header_t *revprops;
@@ -785,7 +793,7 @@ svn_cl__log(apr_getopt_t *os,
lb.depth = opt_state->depth == svn_depth_unknown ? svn_depth_infinity
: opt_state->depth;
lb.diff_extensions = opt_state->extensions;
- lb.merge_stack = apr_array_make(pool, 0, sizeof(svn_revnum_t));
+ lb.merge_stack = NULL;
lb.search_patterns = opt_state->search_patterns;
lb.pool = pool;
@@ -813,8 +821,8 @@ svn_cl__log(apr_getopt_t *os,
hi != NULL;
hi = apr_hash_next(hi))
{
- const char *property = svn__apr_hash_index_key(hi);
- svn_string_t *value = svn__apr_hash_index_val(hi);
+ const char *property = apr_hash_this_key(hi);
+ svn_string_t *value = apr_hash_this_val(hi);
if (value && value->data[0] != '\0')
return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
@@ -839,7 +847,7 @@ svn_cl__log(apr_getopt_t *os,
opt_state->stop_on_copy,
opt_state->use_merge_history,
revprops,
- log_entry_receiver_xml,
+ svn_cl__log_entry_receiver_xml,
&lb,
ctx,
pool));
@@ -862,13 +870,13 @@ svn_cl__log(apr_getopt_t *os,
opt_state->stop_on_copy,
opt_state->use_merge_history,
revprops,
- log_entry_receiver,
+ svn_cl__log_entry_receiver,
&lb,
ctx,
pool));
if (! opt_state->incremental)
- SVN_ERR(svn_cmdline_printf(pool, SEP_STRING));
+ SVN_ERR(svn_cmdline_printf(pool, SVN_CL__LOG_SEP_STRING));
}
return SVN_NO_ERROR;
diff --git a/subversion/svn/merge-cmd.c b/subversion/svn/merge-cmd.c
index 17507a2cbaee..6feda4cd1bff 100644
--- a/subversion/svn/merge-cmd.c
+++ b/subversion/svn/merge-cmd.c
@@ -37,10 +37,6 @@
#include "svn_private_config.h"
-/* A handy constant */
-static const svn_opt_revision_t unspecified_revision
- = { svn_opt_revision_unspecified, { 0 } };
-
/*** Code. ***/
diff --git a/subversion/svn/mergeinfo-cmd.c b/subversion/svn/mergeinfo-cmd.c
index 41edcdafc730..c3c03058c626 100644
--- a/subversion/svn/mergeinfo-cmd.c
+++ b/subversion/svn/mergeinfo-cmd.c
@@ -27,7 +27,9 @@
/*** Includes. ***/
+#include "svn_compat.h"
#include "svn_pools.h"
+#include "svn_props.h"
#include "svn_client.h"
#include "svn_cmdline.h"
#include "svn_path.h"
@@ -35,6 +37,7 @@
#include "svn_error_codes.h"
#include "svn_types.h"
#include "cl.h"
+#include "cl-log.h"
#include "svn_private_config.h"
@@ -55,6 +58,25 @@ print_log_rev(void *baton,
return SVN_NO_ERROR;
}
+/* Implements a svn_log_entry_receiver_t interface that filters out changed
+ * paths data before calling the svn_cl__log_entry_receiver(). Right now we
+ * always have to pass TRUE for discover_changed_paths for
+ * svn_client_mergeinfo_log2() due to the side effect of that option. The
+ * svn_cl__log_entry_receiver() discovers if it should print the changed paths
+ * implicitly by the path info existing. As a result this filter is needed
+ * to allow expected output without changed paths.
+ */
+static svn_error_t *
+print_log_details(void *baton,
+ svn_log_entry_t *log_entry,
+ apr_pool_t *pool)
+{
+ log_entry->changed_paths = NULL;
+ log_entry->changed_paths2 = NULL;
+
+ return svn_cl__log_entry_receiver(baton, log_entry, pool);
+}
+
/* Draw a diagram (by printing text to the console) summarizing the state
* of merging between two branches, given the merge description
* indicated by YCA, BASE, RIGHT, TARGET, REINTEGRATE_LIKE. */
@@ -218,7 +240,8 @@ mergeinfo_summary(
target_is_wc = (! svn_path_is_url(target_path_or_url))
&& (target_revision->kind == svn_opt_revision_unspecified
- || target_revision->kind == svn_opt_revision_working);
+ || target_revision->kind == svn_opt_revision_working
+ || target_revision->kind == svn_opt_revision_base);
SVN_ERR(svn_client_get_merging_summary(
&is_reintegration,
&yca_url, &yca_rev,
@@ -238,6 +261,77 @@ mergeinfo_summary(
return SVN_NO_ERROR;
}
+static svn_error_t *
+mergeinfo_log(svn_boolean_t finding_merged,
+ const char *target,
+ const svn_opt_revision_t *tgt_peg_revision,
+ const char *source,
+ const svn_opt_revision_t *src_peg_revision,
+ const svn_opt_revision_t *src_start_revision,
+ const svn_opt_revision_t *src_end_revision,
+ svn_depth_t depth,
+ svn_boolean_t include_log_details,
+ svn_boolean_t quiet,
+ svn_boolean_t verbose,
+ svn_boolean_t incremental,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ apr_array_header_t *revprops;
+ svn_log_entry_receiver_t log_receiver;
+ void *log_receiver_baton;
+
+ if (include_log_details)
+ {
+ svn_cl__log_receiver_baton *baton;
+
+ revprops = apr_array_make(pool, 3, sizeof(const char *));
+ APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_AUTHOR;
+ APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_DATE;
+ if (!quiet)
+ APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_LOG;
+
+ if (verbose)
+ log_receiver = svn_cl__log_entry_receiver;
+ else
+ log_receiver = print_log_details;
+
+ baton = apr_palloc(pool, sizeof(svn_cl__log_receiver_baton));
+ baton->ctx = ctx;
+ baton->target_path_or_url = target;
+ baton->target_peg_revision = *tgt_peg_revision;
+ baton->omit_log_message = quiet;
+ baton->show_diff = FALSE;
+ baton->depth = depth;
+ baton->diff_extensions = NULL;
+ baton->merge_stack = NULL;
+ baton->search_patterns = NULL;
+ baton->pool = pool;
+ log_receiver_baton = baton;
+ }
+ else
+ {
+ /* We need only revisions number, not revision properties. */
+ revprops = apr_array_make(pool, 0, sizeof(const char *));
+ log_receiver = print_log_rev;
+ log_receiver_baton = NULL;
+ }
+
+ SVN_ERR(svn_client_mergeinfo_log2(finding_merged, target,
+ tgt_peg_revision,
+ source, src_peg_revision,
+ src_start_revision,
+ src_end_revision,
+ log_receiver, log_receiver_baton,
+ TRUE, depth, revprops, ctx,
+ pool));
+
+ if (include_log_details && !incremental)
+ SVN_ERR(svn_cmdline_printf(pool, SVN_CL__LOG_SEP_STRING));
+
+ return SVN_NO_ERROR;
+}
+
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__mergeinfo(apr_getopt_t *os,
@@ -303,36 +397,44 @@ svn_cl__mergeinfo(apr_getopt_t *os,
else
src_end_revision = &(opt_state->end_revision);
- /* Do the real work, depending on the requested data flavor. */
- if (opt_state->show_revs == svn_cl__show_revs_merged)
+ if (!opt_state->mergeinfo_log)
{
- apr_array_header_t *revprops;
+ if (opt_state->quiet)
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--quiet (-q) option valid only with --log "
+ "option"));
- /* We need only revisions number, not revision properties. */
- revprops = apr_array_make(pool, 0, sizeof(const char *));
+ if (opt_state->verbose)
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--verbose (-v) option valid only with "
+ "--log option"));
- SVN_ERR(svn_client_mergeinfo_log2(TRUE, target, &tgt_peg_revision,
- source, &src_peg_revision,
- src_start_revision,
- src_end_revision,
- print_log_rev, NULL,
- TRUE, depth, revprops, ctx,
- pool));
+ if (opt_state->incremental)
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--incremental option valid only with "
+ "--log option"));
+ }
+
+ /* Do the real work, depending on the requested data flavor. */
+ if (opt_state->show_revs == svn_cl__show_revs_merged)
+ {
+ SVN_ERR(mergeinfo_log(TRUE, target, &tgt_peg_revision,
+ source, &src_peg_revision,
+ src_start_revision,
+ src_end_revision,
+ depth, opt_state->mergeinfo_log,
+ opt_state->quiet, opt_state->verbose,
+ opt_state->incremental, ctx, pool));
}
else if (opt_state->show_revs == svn_cl__show_revs_eligible)
{
- apr_array_header_t *revprops;
-
- /* We need only revisions number, not revision properties. */
- revprops = apr_array_make(pool, 0, sizeof(const char *));
-
- SVN_ERR(svn_client_mergeinfo_log2(FALSE, target, &tgt_peg_revision,
- source, &src_peg_revision,
- src_start_revision,
- src_end_revision,
- print_log_rev, NULL,
- TRUE, depth, revprops, ctx,
- pool));
+ SVN_ERR(mergeinfo_log(FALSE, target, &tgt_peg_revision,
+ source, &src_peg_revision,
+ src_start_revision,
+ src_end_revision,
+ depth, opt_state->mergeinfo_log,
+ opt_state->quiet, opt_state->verbose,
+ opt_state->incremental, ctx, pool));
}
else
{
@@ -345,6 +447,11 @@ svn_cl__mergeinfo(apr_getopt_t *os,
return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("Depth specification options valid only "
"with --show-revs option"));
+ if (opt_state->mergeinfo_log)
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--log option valid only with "
+ "--show-revs option"));
+
SVN_ERR(mergeinfo_summary(source, &src_peg_revision,
target, &tgt_peg_revision,
diff --git a/subversion/svn/notify.c b/subversion/svn/notify.c
index 6498fb17839c..c530694c7adf 100644
--- a/subversion/svn/notify.c
+++ b/subversion/svn/notify.c
@@ -52,7 +52,7 @@ struct notify_baton
svn_boolean_t is_export;
svn_boolean_t is_wc_to_repos_copy;
svn_boolean_t sent_first_txdelta;
- svn_boolean_t in_external;
+ int in_external;
svn_boolean_t had_print_error; /* Used to not keep printing error messages
when we've already had one print error. */
@@ -129,7 +129,7 @@ svn_cl__conflict_stats_resolved(svn_cl__conflict_stats_t *conflict_stats,
static const char *
remaining_str(apr_pool_t *pool, int n_remaining)
{
- return apr_psprintf(pool, Q_("%d remaining",
+ return apr_psprintf(pool, Q_("%d remaining",
"%d remaining",
n_remaining),
n_remaining);
@@ -145,20 +145,20 @@ resolved_str(apr_pool_t *pool, int n_resolved)
}
svn_error_t *
-svn_cl__notifier_print_conflict_stats(void *baton, apr_pool_t *scratch_pool)
+svn_cl__print_conflict_stats(svn_cl__conflict_stats_t *conflict_stats,
+ apr_pool_t *scratch_pool)
{
- struct notify_baton *nb = baton;
- int n_text = apr_hash_count(nb->conflict_stats->text_conflicts);
- int n_prop = apr_hash_count(nb->conflict_stats->prop_conflicts);
- int n_tree = apr_hash_count(nb->conflict_stats->tree_conflicts);
- int n_text_r = nb->conflict_stats->text_conflicts_resolved;
- int n_prop_r = nb->conflict_stats->prop_conflicts_resolved;
- int n_tree_r = nb->conflict_stats->tree_conflicts_resolved;
+ int n_text = apr_hash_count(conflict_stats->text_conflicts);
+ int n_prop = apr_hash_count(conflict_stats->prop_conflicts);
+ int n_tree = apr_hash_count(conflict_stats->tree_conflicts);
+ int n_text_r = conflict_stats->text_conflicts_resolved;
+ int n_prop_r = conflict_stats->prop_conflicts_resolved;
+ int n_tree_r = conflict_stats->tree_conflicts_resolved;
if (n_text > 0 || n_text_r > 0
|| n_prop > 0 || n_prop_r > 0
|| n_tree > 0 || n_tree_r > 0
- || nb->conflict_stats->skipped_paths > 0)
+ || conflict_stats->skipped_paths > 0)
SVN_ERR(svn_cmdline_printf(scratch_pool,
_("Summary of conflicts:\n")));
@@ -195,32 +195,43 @@ svn_cl__notifier_print_conflict_stats(void *baton, apr_pool_t *scratch_pool)
remaining_str(scratch_pool, n_tree),
resolved_str(scratch_pool, n_tree_r)));
}
- if (nb->conflict_stats->skipped_paths > 0)
+ if (conflict_stats->skipped_paths > 0)
SVN_ERR(svn_cmdline_printf(scratch_pool,
_(" Skipped paths: %d\n"),
- nb->conflict_stats->skipped_paths));
+ conflict_stats->skipped_paths));
return SVN_NO_ERROR;
}
-/* This implements `svn_wc_notify_func2_t'.
- * NOTE: This function can't fail, so we just ignore any print errors. */
-static void
-notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
+svn_error_t *
+svn_cl__notifier_print_conflict_stats(void *baton, apr_pool_t *scratch_pool)
{
struct notify_baton *nb = baton;
+
+ SVN_ERR(svn_cl__print_conflict_stats(nb->conflict_stats, scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+/* The body for notify() function with standard error handling semantic.
+ * Handling of errors implemented at caller side. */
+static svn_error_t *
+notify_body(struct notify_baton *nb,
+ const svn_wc_notify_t *n,
+ apr_pool_t *pool)
+{
char statchar_buf[5] = " ";
const char *path_local;
- svn_error_t *err;
if (n->url)
path_local = n->url;
else
{
+ /* Skip the path prefix in N, if supplied, or else the path prefix
+ in NB (which was set to the current working directory). */
if (n->path_prefix)
path_local = svn_cl__local_style_skip_ancestor(n->path_prefix, n->path,
pool);
- else /* skip nb->path_prefix, if it's non-null */
+ else
path_local = svn_cl__local_style_skip_ancestor(nb->path_prefix, n->path,
pool);
}
@@ -231,90 +242,78 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
nb->conflict_stats->skipped_paths++;
if (n->content_state == svn_wc_notify_state_missing)
{
- if ((err = svn_cmdline_printf
- (pool, _("Skipped missing target: '%s'\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("Skipped missing target: '%s'\n"),
+ path_local));
}
else if (n->content_state == svn_wc_notify_state_source_missing)
{
- if ((err = svn_cmdline_printf
- (pool, _("Skipped target: '%s' -- copy-source is missing\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(
+ pool,
+ _("Skipped target: '%s' -- copy-source is missing\n"),
+ path_local));
}
else
{
- if ((err = svn_cmdline_printf
- (pool, _("Skipped '%s'\n"), path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, _("Skipped '%s'\n"), path_local));
}
break;
case svn_wc_notify_update_skip_obstruction:
nb->conflict_stats->skipped_paths++;
- if ((err = svn_cmdline_printf(
- pool, _("Skipped '%s' -- An obstructing working copy was found\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(
+ pool,
+ _("Skipped '%s' -- An obstructing working copy was found\n"),
+ path_local));
break;
case svn_wc_notify_update_skip_working_only:
nb->conflict_stats->skipped_paths++;
- if ((err = svn_cmdline_printf(
- pool, _("Skipped '%s' -- Has no versioned parent\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(
+ pool, _("Skipped '%s' -- Has no versioned parent\n"),
+ path_local));
break;
case svn_wc_notify_update_skip_access_denied:
nb->conflict_stats->skipped_paths++;
- if ((err = svn_cmdline_printf(
- pool, _("Skipped '%s' -- Access denied\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(
+ pool, _("Skipped '%s' -- Access denied\n"),
+ path_local));
break;
case svn_wc_notify_skip_conflicted:
nb->conflict_stats->skipped_paths++;
- if ((err = svn_cmdline_printf(
- pool, _("Skipped '%s' -- Node remains in conflict\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(
+ pool, _("Skipped '%s' -- Node remains in conflict\n"),
+ path_local));
break;
case svn_wc_notify_update_delete:
case svn_wc_notify_exclude:
nb->received_some_change = TRUE;
- if ((err = svn_cmdline_printf(pool, "D %s\n", path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, "D %s\n", path_local));
break;
case svn_wc_notify_update_broken_lock:
- if ((err = svn_cmdline_printf(pool, "B %s\n", path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, "B %s\n", path_local));
break;
case svn_wc_notify_update_external_removed:
nb->received_some_change = TRUE;
if (n->err && n->err->message)
{
- if ((err = svn_cmdline_printf(pool, "Removed external '%s': %s\n",
- path_local, n->err->message)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, _("Removed external '%s': %s\n"),
+ path_local, n->err->message));
}
else
{
- if ((err = svn_cmdline_printf(pool, "Removed external '%s'\n",
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, _("Removed external '%s'\n"),
+ path_local));
}
break;
case svn_wc_notify_left_local_modifications:
- if ((err = svn_cmdline_printf(pool, "Left local modifications as '%s'\n",
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, _("Left local modifications as '%s'\n"),
+ path_local));
break;
case svn_wc_notify_update_replace:
nb->received_some_change = TRUE;
- if ((err = svn_cmdline_printf(pool, "R %s\n", path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, "R %s\n", path_local));
break;
case svn_wc_notify_update_add:
@@ -322,13 +321,11 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
if (n->content_state == svn_wc_notify_state_conflicted)
{
store_path(nb, nb->conflict_stats->text_conflicts, path_local);
- if ((err = svn_cmdline_printf(pool, "C %s\n", path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, "C %s\n", path_local));
}
else
{
- if ((err = svn_cmdline_printf(pool, "A %s\n", path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, "A %s\n", path_local));
}
break;
@@ -350,34 +347,29 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
else if (n->prop_state == svn_wc_notify_state_merged)
statchar_buf[1] = 'G';
- if ((err = svn_cmdline_printf(pool, "%s %s\n", statchar_buf, path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, "%s %s\n", statchar_buf, path_local));
break;
case svn_wc_notify_restore:
- if ((err = svn_cmdline_printf(pool, _("Restored '%s'\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, _("Restored '%s'\n"),
+ path_local));
break;
case svn_wc_notify_revert:
- if ((err = svn_cmdline_printf(pool, _("Reverted '%s'\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, _("Reverted '%s'\n"),
+ path_local));
break;
case svn_wc_notify_failed_revert:
- if (( err = svn_cmdline_printf(pool, _("Failed to revert '%s' -- "
- "try updating instead.\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, _("Failed to revert '%s' -- "
+ "try updating instead.\n"),
+ path_local));
break;
case svn_wc_notify_resolved:
- if ((err = svn_cmdline_printf(pool,
- _("Resolved conflicted state of '%s'\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("Resolved conflicted state of '%s'\n"),
+ path_local));
break;
case svn_wc_notify_add:
@@ -386,23 +378,20 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
is a binary addition. */
if (n->mime_type && (svn_mime_type_is_binary(n->mime_type)))
{
- if ((err = svn_cmdline_printf(pool, "A (bin) %s\n",
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, "A (bin) %s\n",
+ path_local));
}
else
{
- if ((err = svn_cmdline_printf(pool, "A %s\n",
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, "A %s\n",
+ path_local));
}
break;
case svn_wc_notify_delete:
nb->received_some_change = TRUE;
- if ((err = svn_cmdline_printf(pool, "D %s\n",
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, "D %s\n",
+ path_local));
break;
case svn_wc_notify_patch:
@@ -431,9 +420,8 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
if (statchar_buf[0] != ' ' || statchar_buf[1] != ' ')
{
- if ((err = svn_cmdline_printf(pool, "%s %s\n",
- statchar_buf, path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, "%s %s\n",
+ statchar_buf, path_local));
}
}
break;
@@ -473,37 +461,34 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
s = _("> applied hunk ## -%lu,%lu +%lu,%lu ## "
"with offset %s");
- err = svn_cmdline_printf(pool,
- apr_pstrcat(pool, s,
- "%"APR_UINT64_T_FMT
- " and fuzz %lu (%s)\n",
- (char *)NULL),
- n->hunk_original_start,
- n->hunk_original_length,
- n->hunk_modified_start,
- n->hunk_modified_length,
- minus, off, n->hunk_fuzz,
- n->prop_name);
+ SVN_ERR(svn_cmdline_printf(pool,
+ apr_pstrcat(pool, s,
+ "%"APR_UINT64_T_FMT
+ " and fuzz %lu (%s)\n",
+ SVN_VA_NULL),
+ n->hunk_original_start,
+ n->hunk_original_length,
+ n->hunk_modified_start,
+ n->hunk_modified_length,
+ minus, off, n->hunk_fuzz,
+ n->prop_name));
}
else
{
s = _("> applied hunk @@ -%lu,%lu +%lu,%lu @@ "
"with offset %s");
- err = svn_cmdline_printf(pool,
- apr_pstrcat(pool, s,
- "%"APR_UINT64_T_FMT
- " and fuzz %lu\n",
- (char *)NULL),
- n->hunk_original_start,
- n->hunk_original_length,
- n->hunk_modified_start,
- n->hunk_modified_length,
- minus, off, n->hunk_fuzz);
+ SVN_ERR(svn_cmdline_printf(pool,
+ apr_pstrcat(pool, s,
+ "%"APR_UINT64_T_FMT
+ " and fuzz %lu\n",
+ SVN_VA_NULL),
+ n->hunk_original_start,
+ n->hunk_original_length,
+ n->hunk_modified_start,
+ n->hunk_modified_length,
+ minus, off, n->hunk_fuzz));
}
-
- if (err)
- goto print_error;
}
else
{
@@ -512,39 +497,36 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
{
s = _("> applied hunk ## -%lu,%lu +%lu,%lu ## "
"with offset %s");
- err = svn_cmdline_printf(pool,
- apr_pstrcat(pool, s,
- "%"APR_UINT64_T_FMT" (%s)\n",
- (char *)NULL),
- n->hunk_original_start,
- n->hunk_original_length,
- n->hunk_modified_start,
- n->hunk_modified_length,
- minus, off, n->prop_name);
+ SVN_ERR(svn_cmdline_printf(pool,
+ apr_pstrcat(pool, s,
+ "%"APR_UINT64_T_FMT" (%s)\n",
+ SVN_VA_NULL),
+ n->hunk_original_start,
+ n->hunk_original_length,
+ n->hunk_modified_start,
+ n->hunk_modified_length,
+ minus, off, n->prop_name));
}
else
{
s = _("> applied hunk @@ -%lu,%lu +%lu,%lu @@ "
"with offset %s");
- err = svn_cmdline_printf(pool,
- apr_pstrcat(pool, s,
- "%"APR_UINT64_T_FMT"\n",
- (char *)NULL),
- n->hunk_original_start,
- n->hunk_original_length,
- n->hunk_modified_start,
- n->hunk_modified_length,
- minus, off);
+ SVN_ERR(svn_cmdline_printf(pool,
+ apr_pstrcat(pool, s,
+ "%"APR_UINT64_T_FMT"\n",
+ SVN_VA_NULL),
+ n->hunk_original_start,
+ n->hunk_original_length,
+ n->hunk_modified_start,
+ n->hunk_modified_length,
+ minus, off));
}
-
- if (err)
- goto print_error;
}
}
else if (n->hunk_fuzz)
{
if (n->prop_name)
- err = svn_cmdline_printf(pool,
+ SVN_ERR(svn_cmdline_printf(pool,
_("> applied hunk ## -%lu,%lu +%lu,%lu ## "
"with fuzz %lu (%s)\n"),
n->hunk_original_start,
@@ -552,18 +534,16 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
n->hunk_modified_start,
n->hunk_modified_length,
n->hunk_fuzz,
- n->prop_name);
+ n->prop_name));
else
- err = svn_cmdline_printf(pool,
+ SVN_ERR(svn_cmdline_printf(pool,
_("> applied hunk @@ -%lu,%lu +%lu,%lu @@ "
"with fuzz %lu\n"),
n->hunk_original_start,
n->hunk_original_length,
n->hunk_modified_start,
n->hunk_modified_length,
- n->hunk_fuzz);
- if (err)
- goto print_error;
+ n->hunk_fuzz));
}
break;
@@ -572,49 +552,45 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
nb->received_some_change = TRUE;
if (n->prop_name)
- err = svn_cmdline_printf(pool,
- _("> rejected hunk "
- "## -%lu,%lu +%lu,%lu ## (%s)\n"),
- n->hunk_original_start,
- n->hunk_original_length,
- n->hunk_modified_start,
- n->hunk_modified_length,
- n->prop_name);
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("> rejected hunk "
+ "## -%lu,%lu +%lu,%lu ## (%s)\n"),
+ n->hunk_original_start,
+ n->hunk_original_length,
+ n->hunk_modified_start,
+ n->hunk_modified_length,
+ n->prop_name));
else
- err = svn_cmdline_printf(pool,
- _("> rejected hunk "
- "@@ -%lu,%lu +%lu,%lu @@\n"),
- n->hunk_original_start,
- n->hunk_original_length,
- n->hunk_modified_start,
- n->hunk_modified_length);
- if (err)
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("> rejected hunk "
+ "@@ -%lu,%lu +%lu,%lu @@\n"),
+ n->hunk_original_start,
+ n->hunk_original_length,
+ n->hunk_modified_start,
+ n->hunk_modified_length));
break;
case svn_wc_notify_patch_hunk_already_applied:
nb->received_some_change = TRUE;
if (n->prop_name)
- err = svn_cmdline_printf(pool,
- _("> hunk "
- "## -%lu,%lu +%lu,%lu ## "
- "already applied (%s)\n"),
- n->hunk_original_start,
- n->hunk_original_length,
- n->hunk_modified_start,
- n->hunk_modified_length,
- n->prop_name);
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("> hunk "
+ "## -%lu,%lu +%lu,%lu ## "
+ "already applied (%s)\n"),
+ n->hunk_original_start,
+ n->hunk_original_length,
+ n->hunk_modified_start,
+ n->hunk_modified_length,
+ n->prop_name));
else
- err = svn_cmdline_printf(pool,
- _("> hunk "
- "@@ -%lu,%lu +%lu,%lu @@ "
- "already applied\n"),
- n->hunk_original_start,
- n->hunk_original_length,
- n->hunk_modified_start,
- n->hunk_modified_length);
- if (err)
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("> hunk "
+ "@@ -%lu,%lu +%lu,%lu @@ "
+ "already applied\n"),
+ n->hunk_original_start,
+ n->hunk_original_length,
+ n->hunk_modified_start,
+ n->hunk_modified_length));
break;
case svn_wc_notify_update_update:
@@ -652,23 +628,21 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
if (statchar_buf[0] != ' ' || statchar_buf[1] != ' '
|| statchar_buf[2] != ' ')
{
- if ((err = svn_cmdline_printf(pool, "%s %s\n",
- statchar_buf, path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, "%s %s\n",
+ statchar_buf, path_local));
}
}
break;
case svn_wc_notify_update_external:
/* Remember that we're now "inside" an externals definition. */
- nb->in_external = TRUE;
+ ++nb->in_external;
/* Currently this is used for checkouts and switches too. If we
want different output, we'll have to add new actions. */
- if ((err = svn_cmdline_printf(pool,
- _("\nFetching external item into '%s':\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("\nFetching external item into '%s':\n"),
+ path_local));
break;
case svn_wc_notify_failed_external:
@@ -679,9 +653,8 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
if (nb->in_external)
{
svn_handle_warning2(stderr, n->err, "svn: ");
- nb->in_external = FALSE;
- if ((err = svn_cmdline_printf(pool, "\n")))
- goto print_error;
+ --nb->in_external;
+ SVN_ERR(svn_cmdline_printf(pool, "\n"));
}
/* Otherwise, we'll just print two warnings. Why? Because
svn_handle_warning2() only shows the single "best message",
@@ -691,7 +664,7 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
else
{
svn_error_t *warn_err =
- svn_error_createf(SVN_ERR_BASE, NULL,
+ svn_error_createf(SVN_ERR_CL_ERROR_PROCESSING_EXTERNALS, NULL,
_("Error handling externals definition for '%s':"),
path_local);
svn_handle_warning2(stderr, warn_err, "svn: ");
@@ -705,9 +678,8 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
nb->is_checkout ||
nb->is_export))
{
- if ((err = svn_cmdline_printf(pool, _("Updating '%s':\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, _("Updating '%s':\n"),
+ path_local));
}
break;
@@ -717,42 +689,38 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
{
if (nb->is_export)
{
- if ((err = svn_cmdline_printf
- (pool, nb->in_external
- ? _("Exported external at revision %ld.\n")
- : _("Exported revision %ld.\n"),
- n->revision)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(
+ pool, nb->in_external
+ ? _("Exported external at revision %ld.\n")
+ : _("Exported revision %ld.\n"),
+ n->revision));
}
else if (nb->is_checkout)
{
- if ((err = svn_cmdline_printf
- (pool, nb->in_external
- ? _("Checked out external at revision %ld.\n")
- : _("Checked out revision %ld.\n"),
- n->revision)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(
+ pool, nb->in_external
+ ? _("Checked out external at revision %ld.\n")
+ : _("Checked out revision %ld.\n"),
+ n->revision));
}
else
{
if (nb->received_some_change)
{
nb->received_some_change = FALSE;
- if ((err = svn_cmdline_printf
- (pool, nb->in_external
- ? _("Updated external to revision %ld.\n")
- : _("Updated to revision %ld.\n"),
- n->revision)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(
+ pool, nb->in_external
+ ? _("Updated external to revision %ld.\n")
+ : _("Updated to revision %ld.\n"),
+ n->revision));
}
else
{
- if ((err = svn_cmdline_printf
- (pool, nb->in_external
- ? _("External at revision %ld.\n")
- : _("At revision %ld.\n"),
- n->revision)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(
+ pool, nb->in_external
+ ? _("External at revision %ld.\n")
+ : _("At revision %ld.\n"),
+ n->revision));
}
}
}
@@ -760,128 +728,119 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
{
if (nb->is_export)
{
- if ((err = svn_cmdline_printf
- (pool, nb->in_external
- ? _("External export complete.\n")
- : _("Export complete.\n"))))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(
+ pool, nb->in_external
+ ? _("External export complete.\n")
+ : _("Export complete.\n")));
}
else if (nb->is_checkout)
{
- if ((err = svn_cmdline_printf
- (pool, nb->in_external
- ? _("External checkout complete.\n")
- : _("Checkout complete.\n"))))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(
+ pool, nb->in_external
+ ? _("External checkout complete.\n")
+ : _("Checkout complete.\n")));
}
else
{
- if ((err = svn_cmdline_printf
- (pool, nb->in_external
- ? _("External update complete.\n")
- : _("Update complete.\n"))))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(
+ pool, nb->in_external
+ ? _("External update complete.\n")
+ : _("Update complete.\n")));
}
}
}
if (nb->in_external)
{
- nb->in_external = FALSE;
- if ((err = svn_cmdline_printf(pool, "\n")))
- goto print_error;
+ --nb->in_external;
+ SVN_ERR(svn_cmdline_printf(pool, "\n"));
}
break;
case svn_wc_notify_status_external:
- if ((err = svn_cmdline_printf
- (pool, _("\nPerforming status on external item at '%s':\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(
+ pool, _("\nPerforming status on external item at '%s':\n"),
+ path_local));
+ break;
+
+ case svn_wc_notify_info_external:
+ SVN_ERR(svn_cmdline_printf(
+ pool, _("\nPerforming info on external item at '%s':\n"),
+ path_local));
break;
case svn_wc_notify_status_completed:
if (SVN_IS_VALID_REVNUM(n->revision))
- if ((err = svn_cmdline_printf(pool,
- _("Status against revision: %6ld\n"),
- n->revision)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("Status against revision: %6ld\n"),
+ n->revision));
break;
case svn_wc_notify_commit_modified:
/* xgettext: Align the %s's on this and the following 4 messages */
- if ((err = svn_cmdline_printf(pool,
- nb->is_wc_to_repos_copy
- ? _("Sending copy of %s\n")
- : _("Sending %s\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ nb->is_wc_to_repos_copy
+ ? _("Sending copy of %s\n")
+ : _("Sending %s\n"),
+ path_local));
break;
case svn_wc_notify_commit_added:
case svn_wc_notify_commit_copied:
if (n->mime_type && svn_mime_type_is_binary(n->mime_type))
{
- if ((err = svn_cmdline_printf(pool,
- nb->is_wc_to_repos_copy
- ? _("Adding copy of (bin) %s\n")
- : _("Adding (bin) %s\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ nb->is_wc_to_repos_copy
+ ? _("Adding copy of (bin) %s\n")
+ : _("Adding (bin) %s\n"),
+ path_local));
}
else
{
- if ((err = svn_cmdline_printf(pool,
- nb->is_wc_to_repos_copy
- ? _("Adding copy of %s\n")
- : _("Adding %s\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ nb->is_wc_to_repos_copy
+ ? _("Adding copy of %s\n")
+ : _("Adding %s\n"),
+ path_local));
}
break;
case svn_wc_notify_commit_deleted:
- if ((err = svn_cmdline_printf(pool,
- nb->is_wc_to_repos_copy
- ? _("Deleting copy of %s\n")
- : _("Deleting %s\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ nb->is_wc_to_repos_copy
+ ? _("Deleting copy of %s\n")
+ : _("Deleting %s\n"),
+ path_local));
break;
case svn_wc_notify_commit_replaced:
case svn_wc_notify_commit_copied_replaced:
- if ((err = svn_cmdline_printf(pool,
- nb->is_wc_to_repos_copy
- ? _("Replacing copy of %s\n")
- : _("Replacing %s\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ nb->is_wc_to_repos_copy
+ ? _("Replacing copy of %s\n")
+ : _("Replacing %s\n"),
+ path_local));
break;
case svn_wc_notify_commit_postfix_txdelta:
if (! nb->sent_first_txdelta)
{
nb->sent_first_txdelta = TRUE;
- if ((err = svn_cmdline_printf(pool,
- _("Transmitting file data "))))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("Transmitting file data ")));
}
- if ((err = svn_cmdline_printf(pool, ".")))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, "."));
break;
case svn_wc_notify_locked:
- if ((err = svn_cmdline_printf(pool, _("'%s' locked by user '%s'.\n"),
- path_local, n->lock->owner)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, _("'%s' locked by user '%s'.\n"),
+ path_local, n->lock->owner));
break;
case svn_wc_notify_unlocked:
- if ((err = svn_cmdline_printf(pool, _("'%s' unlocked.\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, _("'%s' unlocked.\n"),
+ path_local));
break;
case svn_wc_notify_failed_lock:
@@ -890,212 +849,182 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
break;
case svn_wc_notify_changelist_set:
- if ((err = svn_cmdline_printf(pool, "A [%s] %s\n",
- n->changelist_name, path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, "A [%s] %s\n",
+ n->changelist_name, path_local));
break;
case svn_wc_notify_changelist_clear:
case svn_wc_notify_changelist_moved:
- if ((err = svn_cmdline_printf(pool,
- "D [%s] %s\n",
- n->changelist_name, path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ "D [%s] %s\n",
+ n->changelist_name, path_local));
break;
case svn_wc_notify_merge_begin:
if (n->merge_range == NULL)
- err = svn_cmdline_printf(pool,
- _("--- Merging differences between "
- "repository URLs into '%s':\n"),
- path_local);
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("--- Merging differences between "
+ "repository URLs into '%s':\n"),
+ path_local));
else if (n->merge_range->start == n->merge_range->end - 1
|| n->merge_range->start == n->merge_range->end)
- err = svn_cmdline_printf(pool, _("--- Merging r%ld into '%s':\n"),
- n->merge_range->end, path_local);
+ SVN_ERR(svn_cmdline_printf(pool, _("--- Merging r%ld into '%s':\n"),
+ n->merge_range->end, path_local));
else if (n->merge_range->start - 1 == n->merge_range->end)
- err = svn_cmdline_printf(pool,
- _("--- Reverse-merging r%ld into '%s':\n"),
- n->merge_range->start, path_local);
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("--- Reverse-merging r%ld into '%s':\n"),
+ n->merge_range->start, path_local));
else if (n->merge_range->start < n->merge_range->end)
- err = svn_cmdline_printf(pool,
- _("--- Merging r%ld through r%ld into "
- "'%s':\n"),
- n->merge_range->start + 1,
- n->merge_range->end, path_local);
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("--- Merging r%ld through r%ld into "
+ "'%s':\n"),
+ n->merge_range->start + 1,
+ n->merge_range->end, path_local));
else /* n->merge_range->start > n->merge_range->end - 1 */
- err = svn_cmdline_printf(pool,
- _("--- Reverse-merging r%ld through r%ld "
- "into '%s':\n"),
- n->merge_range->start,
- n->merge_range->end + 1, path_local);
- if (err)
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("--- Reverse-merging r%ld through r%ld "
+ "into '%s':\n"),
+ n->merge_range->start,
+ n->merge_range->end + 1, path_local));
break;
case svn_wc_notify_merge_record_info_begin:
if (!n->merge_range)
{
- err = svn_cmdline_printf(pool,
- _("--- Recording mergeinfo for merge "
- "between repository URLs into '%s':\n"),
- path_local);
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("--- Recording mergeinfo for merge "
+ "between repository URLs into '%s':\n"),
+ path_local));
}
else
{
if (n->merge_range->start == n->merge_range->end - 1
|| n->merge_range->start == n->merge_range->end)
- err = svn_cmdline_printf(
+ SVN_ERR(svn_cmdline_printf(
pool,
_("--- Recording mergeinfo for merge of r%ld into '%s':\n"),
- n->merge_range->end, path_local);
+ n->merge_range->end, path_local));
else if (n->merge_range->start - 1 == n->merge_range->end)
- err = svn_cmdline_printf(
+ SVN_ERR(svn_cmdline_printf(
pool,
_("--- Recording mergeinfo for reverse merge of r%ld into '%s':\n"),
- n->merge_range->start, path_local);
+ n->merge_range->start, path_local));
else if (n->merge_range->start < n->merge_range->end)
- err = svn_cmdline_printf(
+ SVN_ERR(svn_cmdline_printf(
pool,
_("--- Recording mergeinfo for merge of r%ld through r%ld into '%s':\n"),
- n->merge_range->start + 1, n->merge_range->end, path_local);
+ n->merge_range->start + 1, n->merge_range->end, path_local));
else /* n->merge_range->start > n->merge_range->end - 1 */
- err = svn_cmdline_printf(
+ SVN_ERR(svn_cmdline_printf(
pool,
_("--- Recording mergeinfo for reverse merge of r%ld through r%ld into '%s':\n"),
- n->merge_range->start, n->merge_range->end + 1, path_local);
+ n->merge_range->start, n->merge_range->end + 1, path_local));
}
-
- if (err)
- goto print_error;
break;
case svn_wc_notify_merge_elide_info:
- if ((err = svn_cmdline_printf(pool,
- _("--- Eliding mergeinfo from '%s':\n"),
- path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("--- Eliding mergeinfo from '%s':\n"),
+ path_local));
break;
case svn_wc_notify_foreign_merge_begin:
if (n->merge_range == NULL)
- err = svn_cmdline_printf(pool,
- _("--- Merging differences between "
- "foreign repository URLs into '%s':\n"),
- path_local);
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("--- Merging differences between "
+ "foreign repository URLs into '%s':\n"),
+ path_local));
else if (n->merge_range->start == n->merge_range->end - 1
|| n->merge_range->start == n->merge_range->end)
- err = svn_cmdline_printf(pool,
- _("--- Merging (from foreign repository) "
- "r%ld into '%s':\n"),
- n->merge_range->end, path_local);
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("--- Merging (from foreign repository) "
+ "r%ld into '%s':\n"),
+ n->merge_range->end, path_local));
else if (n->merge_range->start - 1 == n->merge_range->end)
- err = svn_cmdline_printf(pool,
- _("--- Reverse-merging (from foreign "
- "repository) r%ld into '%s':\n"),
- n->merge_range->start, path_local);
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("--- Reverse-merging (from foreign "
+ "repository) r%ld into '%s':\n"),
+ n->merge_range->start, path_local));
else if (n->merge_range->start < n->merge_range->end)
- err = svn_cmdline_printf(pool,
- _("--- Merging (from foreign repository) "
- "r%ld through r%ld into '%s':\n"),
- n->merge_range->start + 1,
- n->merge_range->end, path_local);
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("--- Merging (from foreign repository) "
+ "r%ld through r%ld into '%s':\n"),
+ n->merge_range->start + 1,
+ n->merge_range->end, path_local));
else /* n->merge_range->start > n->merge_range->end - 1 */
- err = svn_cmdline_printf(pool,
- _("--- Reverse-merging (from foreign "
- "repository) r%ld through r%ld into "
- "'%s':\n"),
- n->merge_range->start,
- n->merge_range->end + 1, path_local);
- if (err)
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("--- Reverse-merging (from foreign "
+ "repository) r%ld through r%ld into "
+ "'%s':\n"),
+ n->merge_range->start,
+ n->merge_range->end + 1, path_local));
break;
case svn_wc_notify_tree_conflict:
store_path(nb, nb->conflict_stats->tree_conflicts, path_local);
- if ((err = svn_cmdline_printf(pool, " C %s\n", path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, " C %s\n", path_local));
break;
case svn_wc_notify_update_shadowed_add:
nb->received_some_change = TRUE;
- if ((err = svn_cmdline_printf(pool, " A %s\n", path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, " A %s\n", path_local));
break;
case svn_wc_notify_update_shadowed_update:
nb->received_some_change = TRUE;
- if ((err = svn_cmdline_printf(pool, " U %s\n", path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, " U %s\n", path_local));
break;
case svn_wc_notify_update_shadowed_delete:
nb->received_some_change = TRUE;
- if ((err = svn_cmdline_printf(pool, " D %s\n", path_local)))
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, " D %s\n", path_local));
break;
case svn_wc_notify_property_modified:
case svn_wc_notify_property_added:
- err = svn_cmdline_printf(pool,
- _("property '%s' set on '%s'\n"),
- n->prop_name, path_local);
- if (err)
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("property '%s' set on '%s'\n"),
+ n->prop_name, path_local));
break;
case svn_wc_notify_property_deleted:
- err = svn_cmdline_printf(pool,
- _("property '%s' deleted from '%s'.\n"),
- n->prop_name, path_local);
- if (err)
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("property '%s' deleted from '%s'.\n"),
+ n->prop_name, path_local));
break;
case svn_wc_notify_property_deleted_nonexistent:
- err = svn_cmdline_printf(pool,
- _("Attempting to delete nonexistent "
- "property '%s' on '%s'\n"), n->prop_name,
- path_local);
- if (err)
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("Attempting to delete nonexistent "
+ "property '%s' on '%s'\n"), n->prop_name,
+ path_local));
break;
case svn_wc_notify_revprop_set:
- err = svn_cmdline_printf(pool,
+ SVN_ERR(svn_cmdline_printf(pool,
_("property '%s' set on repository revision %ld\n"),
- n->prop_name, n->revision);
- if (err)
- goto print_error;
+ n->prop_name, n->revision));
break;
case svn_wc_notify_revprop_deleted:
- err = svn_cmdline_printf(pool,
+ SVN_ERR(svn_cmdline_printf(pool,
_("property '%s' deleted from repository revision %ld\n"),
- n->prop_name, n->revision);
- if (err)
- goto print_error;
+ n->prop_name, n->revision));
break;
case svn_wc_notify_upgraded_path:
- err = svn_cmdline_printf(pool, _("Upgraded '%s'\n"), path_local);
- if (err)
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, _("Upgraded '%s'\n"), path_local));
break;
case svn_wc_notify_url_redirect:
- err = svn_cmdline_printf(pool, _("Redirecting to URL '%s':\n"),
- n->url);
- if (err)
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, _("Redirecting to URL '%s':\n"),
+ n->url));
break;
case svn_wc_notify_path_nonexistent:
- err = svn_cmdline_printf(pool, "%s\n",
- apr_psprintf(pool, _("'%s' is not under version control"),
- path_local));
- if (err)
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool, "%s\n",
+ apr_psprintf(pool, _("'%s' is not under version control"),
+ path_local)));
break;
case svn_wc_notify_conflict_resolver_starting:
@@ -1110,37 +1039,56 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
case svn_wc_notify_foreign_copy_begin:
if (n->merge_range == NULL)
{
- err = svn_cmdline_printf(
+ SVN_ERR(svn_cmdline_printf(
pool,
_("--- Copying from foreign repository URL '%s':\n"),
- n->url);
- if (err)
- goto print_error;
+ n->url));
}
break;
case svn_wc_notify_move_broken:
- err = svn_cmdline_printf(pool,
- _("Breaking move with source path '%s'\n"),
- path_local);
- if (err)
- goto print_error;
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("Breaking move with source path '%s'\n"),
+ path_local));
+ break;
+
+ case svn_wc_notify_cleanup_external:
+ SVN_ERR(svn_cmdline_printf
+ (pool, _("Performing cleanup on external item at '%s'.\n"),
+ path_local));
+ break;
+
+ case svn_wc_notify_commit_finalizing:
+ if (nb->sent_first_txdelta)
+ {
+ SVN_ERR(svn_cmdline_printf(pool, _("done\n")));
+ }
+ SVN_ERR(svn_cmdline_printf(pool, _("Committing transaction...\n")));
break;
default:
break;
}
- if ((err = svn_cmdline_fflush(stdout)))
- goto print_error;
+ SVN_ERR(svn_cmdline_fflush(stdout));
- return;
+ return SVN_NO_ERROR;
+}
+
+/* This implements `svn_wc_notify_func2_t'.
+ * NOTE: This function can't fail, so we just ignore any print errors. */
+static void
+notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
+{
+ struct notify_baton *nb = baton;
+ svn_error_t *err;
+
+ err = notify_body(nb, n, pool);
- print_error:
/* If we had no errors before, print this error to stderr. Else, don't print
anything. The user already knows there were some output errors,
so there is no point in flooding her with an error per notification. */
- if (!nb->had_print_error)
+ if (err && !nb->had_print_error)
{
nb->had_print_error = TRUE;
/* Issue #3014:
@@ -1156,7 +1104,6 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
svn_error_clear(err);
}
-
svn_error_t *
svn_cl__get_notifier(svn_wc_notify_func2_t *notify_func_p,
void **notify_baton_p,
@@ -1170,7 +1117,7 @@ svn_cl__get_notifier(svn_wc_notify_func2_t *notify_func_p,
nb->is_checkout = FALSE;
nb->is_export = FALSE;
nb->is_wc_to_repos_copy = FALSE;
- nb->in_external = FALSE;
+ nb->in_external = 0;
nb->had_print_error = FALSE;
nb->conflict_stats = conflict_stats;
SVN_ERR(svn_dirent_get_absolute(&nb->path_prefix, "", pool));
diff --git a/subversion/svn/propget-cmd.c b/subversion/svn/propget-cmd.c
index e291911845b0..fa04c202ce3d 100644
--- a/subversion/svn/propget-cmd.c
+++ b/subversion/svn/propget-cmd.c
@@ -44,7 +44,8 @@
#include "cl.h"
#include "private/svn_cmdline_private.h"
-
+#include "private/svn_opt_private.h"
+#include "private/svn_sorts_private.h"
#include "svn_private_config.h"
@@ -88,7 +89,7 @@ print_properties_xml(const char *pname,
const char *name_local;
svn_prop_inherited_item_t *iprop =
APR_ARRAY_IDX(inherited_props, i, svn_prop_inherited_item_t *);
- svn_string_t *propval = svn__apr_hash_index_val(
+ svn_string_t *propval = apr_hash_this_val(
apr_hash_first(pool, iprop->prop_hash));
sb = NULL;
@@ -100,7 +101,7 @@ print_properties_xml(const char *pname,
name_local = svn_dirent_local_style(iprop->path_or_url, iterpool);
svn_xml_make_open_tag(&sb, iterpool, svn_xml_normal, "target",
- "path", name_local, NULL);
+ "path", name_local, SVN_VA_NULL);
svn_cmdline__print_xml_prop(&sb, pname, propval, TRUE, iterpool);
svn_xml_make_close_tag(&sb, iterpool, "target");
@@ -123,7 +124,7 @@ print_properties_xml(const char *pname,
svn_pool_clear(iterpool);
svn_xml_make_open_tag(&sb, iterpool, svn_xml_normal, "target",
- "path", filename, NULL);
+ "path", filename, SVN_VA_NULL);
svn_cmdline__print_xml_prop(&sb, pname, propval, FALSE, iterpool);
svn_xml_make_close_tag(&sb, iterpool, "target");
@@ -277,7 +278,7 @@ print_properties(svn_stream_t *out,
{
svn_prop_inherited_item_t *iprop =
APR_ARRAY_IDX(inherited_props, i, svn_prop_inherited_item_t *);
- svn_string_t *propval = svn__apr_hash_index_val(apr_hash_first(pool,
+ svn_string_t *propval = apr_hash_this_val(apr_hash_first(pool,
iprop->prop_hash));
SVN_ERR(print_single_prop(propval, target_abspath_or_url,
iprop->path_or_url,
@@ -319,12 +320,13 @@ svn_cl__propget(apr_getopt_t *os,
const char *pname, *pname_utf8;
apr_array_header_t *args, *targets;
svn_stream_t *out;
+ svn_boolean_t warned = FALSE;
- if (opt_state->verbose && (opt_state->revprop || opt_state->strict
+ if (opt_state->verbose && (opt_state->revprop || opt_state->no_newline
|| opt_state->xml))
return svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
_("--verbose cannot be used with --revprop or "
- "--strict or --xml"));
+ "--no-newline or --xml"));
/* PNAME is first argument (and PNAME_UTF8 will be a UTF-8 version
thereof) */
@@ -365,7 +367,17 @@ svn_cl__propget(apr_getopt_t *os,
URL, &(opt_state->start_revision),
&rev, ctx, pool));
- if (propval != NULL)
+ if (propval == NULL)
+ {
+ return svn_error_createf(SVN_ERR_PROPERTY_NOT_FOUND, NULL,
+ _("Property '%s' not found on "
+ "revision %s"),
+ pname_utf8,
+ svn_opt__revision_to_string(
+ &opt_state->start_revision,
+ pool));
+ }
+ else
{
if (opt_state->xml)
{
@@ -376,7 +388,7 @@ svn_cl__propget(apr_getopt_t *os,
svn_xml_make_open_tag(&sb, pool, svn_xml_normal,
"revprops",
- "rev", revstr, NULL);
+ "rev", revstr, SVN_VA_NULL);
svn_cmdline__print_xml_prop(&sb, pname_utf8, propval, FALSE,
pool);
@@ -399,7 +411,7 @@ svn_cl__propget(apr_getopt_t *os,
SVN_ERR(stream_write(out, printable_val->data,
printable_val->len));
- if (! opt_state->strict)
+ if (! opt_state->no_newline)
SVN_ERR(stream_write(out, APR_EOL_STR, strlen(APR_EOL_STR)));
}
}
@@ -415,15 +427,16 @@ svn_cl__propget(apr_getopt_t *os,
if (opt_state->depth == svn_depth_unknown)
opt_state->depth = svn_depth_empty;
- /* Strict mode only makes sense for a single target. So make
+ /* No-newline mode only makes sense for a single target. So make
sure we have only a single target, and that we're not being
asked to recurse on that target. */
- if (opt_state->strict
- && ((targets->nelts > 1) || (opt_state->depth != svn_depth_empty)))
+ if (opt_state->no_newline
+ && ((targets->nelts > 1) || (opt_state->depth != svn_depth_empty)
+ || (opt_state->show_inherited_props)))
return svn_error_create
(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("Strict output of property values only available for single-"
- "target, non-recursive propget operations"));
+ _("--no-newline is only available for single-target,"
+ " non-recursive propget operations"));
for (i = 0; i < targets->nelts; i++)
{
@@ -459,15 +472,30 @@ svn_cl__propget(apr_getopt_t *os,
/* Any time there is more than one thing to print, or where
the path associated with a printed thing is not obvious,
we'll print filenames. That is, unless we've been told
- not to do so with the --strict option. */
+ not to do so with the --no-newline option. */
print_filenames = ((opt_state->depth > svn_depth_empty
|| targets->nelts > 1
|| apr_hash_count(props) > 1
|| opt_state->verbose
|| opt_state->show_inherited_props)
- && (! opt_state->strict));
- omit_newline = opt_state->strict;
- like_proplist = opt_state->verbose && !opt_state->strict;
+ && (! opt_state->no_newline));
+ omit_newline = opt_state->no_newline;
+ like_proplist = opt_state->verbose && !opt_state->no_newline;
+
+ /* If there are no properties, and exactly one node was queried,
+ then warn. */
+ if (opt_state->depth == svn_depth_empty
+ && !opt_state->show_inherited_props
+ && apr_hash_count(props) == 0)
+ {
+ svn_error_t *err;
+ err = svn_error_createf(SVN_ERR_PROPERTY_NOT_FOUND, NULL,
+ _("Property '%s' not found on '%s'"),
+ pname_utf8, target);
+ svn_handle_warning2(stderr, err, "svn: ");
+ svn_error_clear(err);
+ warned = TRUE;
+ }
if (opt_state->xml)
SVN_ERR(print_properties_xml(
@@ -489,5 +517,8 @@ svn_cl__propget(apr_getopt_t *os,
svn_pool_destroy(subpool);
}
+ if (warned)
+ return svn_error_create(SVN_ERR_BASE, NULL, NULL);
+
return SVN_NO_ERROR;
}
diff --git a/subversion/svn/proplist-cmd.c b/subversion/svn/proplist-cmd.c
index fe23a67f6143..80e0364f3da8 100644
--- a/subversion/svn/proplist-cmd.c
+++ b/subversion/svn/proplist-cmd.c
@@ -83,7 +83,7 @@ proplist_receiver_xml(void *baton,
name_local = svn_dirent_local_style(iprop->path_or_url, iterpool);
svn_xml_make_open_tag(&sb, iterpool, svn_xml_normal, "target",
- "path", name_local, NULL);
+ "path", name_local, SVN_VA_NULL);
SVN_ERR(svn_cmdline__print_xml_prop_hash(&sb, iprop->prop_hash,
(! opt_state->verbose),
TRUE, iterpool));
@@ -105,7 +105,7 @@ proplist_receiver_xml(void *baton,
{
/* "<target ...>" */
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "target",
- "path", name_local, NULL);
+ "path", name_local, SVN_VA_NULL);
SVN_ERR(svn_cmdline__print_xml_prop_hash(&sb, prop_hash,
(! opt_state->verbose),
@@ -230,7 +230,7 @@ svn_cl__proplist(apr_getopt_t *os,
svn_xml_make_open_tag(&sb, scratch_pool, svn_xml_normal,
"revprops",
- "rev", revstr, NULL);
+ "rev", revstr, SVN_VA_NULL);
SVN_ERR(svn_cmdline__print_xml_prop_hash(&sb, proplist,
(! opt_state->verbose),
FALSE, scratch_pool));
@@ -299,7 +299,7 @@ svn_cl__proplist(apr_getopt_t *os,
errors, opt_state->quiet,
SVN_ERR_UNVERSIONED_RESOURCE,
SVN_ERR_ENTRY_NOT_FOUND,
- SVN_NO_ERROR));
+ 0));
}
svn_pool_destroy(iterpool);
diff --git a/subversion/svn/props.c b/subversion/svn/props.c
index 2a41ac81dcac..b4a75f54ff79 100644
--- a/subversion/svn/props.c
+++ b/subversion/svn/props.c
@@ -112,59 +112,6 @@ svn_cl__check_boolean_prop_val(const char *propname, const char *propval,
}
}
-
-/* Context for sorting property names */
-struct simprop_context_t
-{
- svn_string_t name; /* The name of the property we're comparing with */
- svn_membuf_t buffer; /* Buffer for similarity testing */
-};
-
-struct simprop_t
-{
- const char *propname; /* The original svn: property name */
- svn_string_t name; /* The property name without the svn: prefix */
- unsigned int score; /* The similarity score */
- apr_size_t diff; /* Number of chars different from context.name */
- struct simprop_context_t *context; /* Sorting context for qsort() */
-};
-
-/* Similarity test between two property names */
-static APR_INLINE unsigned int
-simprop_key_diff(const svn_string_t *key, const svn_string_t *ctx,
- svn_membuf_t *buffer, apr_size_t *diff)
-{
- apr_size_t lcs;
- const unsigned int score = svn_string__similarity(key, ctx, buffer, &lcs);
- if (key->len > ctx->len)
- *diff = key->len - lcs;
- else
- *diff = ctx->len - lcs;
- return score;
-}
-
-/* Key comparator for qsort for simprop_t */
-static int
-simprop_compare(const void *pkeya, const void *pkeyb)
-{
- struct simprop_t *const keya = *(struct simprop_t *const *)pkeya;
- struct simprop_t *const keyb = *(struct simprop_t *const *)pkeyb;
- struct simprop_context_t *const context = keya->context;
-
- if (keya->score == -1)
- keya->score = simprop_key_diff(&keya->name, &context->name,
- &context->buffer, &keya->diff);
- if (keyb->score == -1)
- keyb->score = simprop_key_diff(&keyb->name, &context->name,
- &context->buffer, &keyb->diff);
-
- return (keya->score < keyb->score ? 1
- : (keya->score > keyb->score ? -1
- : (keya->diff > keyb->diff ? 1
- : (keya->diff < keyb->diff ? -1 : 0))));
-}
-
-
static const char*
force_prop_option_message(svn_cl__prop_use_t prop_use, const char *prop_name,
apr_pool_t *scratch_pool)
@@ -174,18 +121,18 @@ force_prop_option_message(svn_cl__prop_use_t prop_use, const char *prop_name,
case svn_cl__prop_use_set:
return apr_psprintf(
scratch_pool,
- _("(To set the '%s' property, re-run with '--force'.)"),
+ _("Use '--force' to set the '%s' property."),
prop_name);
case svn_cl__prop_use_edit:
return apr_psprintf(
scratch_pool,
- _("(To edit the '%s' property, re-run with '--force'.)"),
+ _("Use '--force' to edit the '%s' property."),
prop_name);
case svn_cl__prop_use_use:
default:
return apr_psprintf(
scratch_pool,
- _("(To use the '%s' property, re-run with '--force'.)"),
+ _("Use '--force' to use the '%s' property'."),
prop_name);
}
}
@@ -199,21 +146,18 @@ wrong_prop_error_message(svn_cl__prop_use_t prop_use, const char *prop_name,
case svn_cl__prop_use_set:
return apr_psprintf(
scratch_pool,
- _("'%s' is not a valid %s property name;"
- " re-run with '--force' to set it"),
+ _("'%s' is not a valid %s property name; use '--force' to set it"),
prop_name, SVN_PROP_PREFIX);
case svn_cl__prop_use_edit:
return apr_psprintf(
scratch_pool,
- _("'%s' is not a valid %s property name;"
- " re-run with '--force' to edit it"),
+ _("'%s' is not a valid %s property name; use '--force' to edit it"),
prop_name, SVN_PROP_PREFIX);
case svn_cl__prop_use_use:
default:
return apr_psprintf(
scratch_pool,
- _("'%s' is not a valid %s property name;"
- " re-run with '--force' to use it"),
+ _("'%s' is not a valid %s property name; use '--force' to use it"),
prop_name, SVN_PROP_PREFIX);
}
}
@@ -239,33 +183,34 @@ svn_cl__check_svn_prop_name(const char *propname,
const char *const *const proplist = (revprop ? revprops : nodeprops);
const apr_size_t numprops = (revprop ? revprops_len : nodeprops_len);
- struct simprop_t **propkeys;
- struct simprop_t *propbuf;
+ svn_cl__simcheck_t **propkeys;
+ svn_cl__simcheck_t *propbuf;
apr_size_t i;
- struct simprop_context_t context;
+ svn_string_t propstring;
svn_string_t prefix;
+ svn_membuf_t buffer;
- context.name.data = propname;
- context.name.len = strlen(propname);
+ propstring.data = propname;
+ propstring.len = strlen(propname);
prefix.data = SVN_PROP_PREFIX;
prefix.len = strlen(SVN_PROP_PREFIX);
- svn_membuf__create(&context.buffer, 0, scratch_pool);
+ svn_membuf__create(&buffer, 0, scratch_pool);
/* First, check if the name is even close to being in the svn: namespace.
It must contain a colon in the right place, and we only allow
one-char typos or a single transposition. */
- if (context.name.len < prefix.len
- || context.name.data[prefix.len - 1] != prefix.data[prefix.len - 1])
+ if (propstring.len < prefix.len
+ || propstring.data[prefix.len - 1] != prefix.data[prefix.len - 1])
return SVN_NO_ERROR; /* Wrong prefix, ignore */
else
{
apr_size_t lcs;
- const apr_size_t name_len = context.name.len;
- context.name.len = prefix.len; /* Only check up to the prefix length */
- svn_string__similarity(&context.name, &prefix, &context.buffer, &lcs);
- context.name.len = name_len; /* Restore the original propname length */
+ const apr_size_t name_len = propstring.len;
+ propstring.len = prefix.len; /* Only check up to the prefix length */
+ svn_string__similarity(&propstring, &prefix, &buffer, &lcs);
+ propstring.len = name_len; /* Restore the original propname length */
if (lcs < prefix.len - 1)
return SVN_NO_ERROR; /* Wrong prefix, ignore */
@@ -276,11 +221,11 @@ svn_cl__check_svn_prop_name(const char *propname,
for (i = 0; i < numprops; ++i)
{
if (0 == strcmp(proplist[i] + prefix.len, propname + prefix.len))
- return svn_error_createf(
+ return svn_error_quick_wrap(svn_error_createf(
SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
_("'%s' is not a valid %s property name;"
- " did you mean '%s'?\n%s"),
- propname, SVN_PROP_PREFIX, proplist[i],
+ " did you mean '%s'?"),
+ propname, SVN_PROP_PREFIX, proplist[i]),
force_prop_option_message(prop_use, propname, scratch_pool));
}
return SVN_NO_ERROR;
@@ -292,65 +237,59 @@ svn_cl__check_svn_prop_name(const char *propname,
we already know that it's the same and looking at it would only
skew the results. */
propkeys = apr_palloc(scratch_pool,
- numprops * sizeof(struct simprop_t*));
+ numprops * sizeof(svn_cl__simcheck_t*));
propbuf = apr_palloc(scratch_pool,
- numprops * sizeof(struct simprop_t));
- context.name.data += prefix.len;
- context.name.len -= prefix.len;
+ numprops * sizeof(svn_cl__simcheck_t));
+ propstring.data += prefix.len;
+ propstring.len -= prefix.len;
for (i = 0; i < numprops; ++i)
{
propkeys[i] = &propbuf[i];
- propbuf[i].propname = proplist[i];
- propbuf[i].name.data = proplist[i] + prefix.len;
- propbuf[i].name.len = strlen(propbuf[i].name.data);
- propbuf[i].score = (unsigned int)-1;
- propbuf[i].context = &context;
+ propbuf[i].token.data = proplist[i] + prefix.len;
+ propbuf[i].token.len = strlen(propbuf[i].token.data);
+ propbuf[i].data = proplist[i];
}
- qsort(propkeys, numprops, sizeof(*propkeys), simprop_compare);
-
- if (0 == propkeys[0]->diff)
- return SVN_NO_ERROR; /* We found an exact match. */
-
- /* See if we can suggest a sane alternative spelling */
- for (i = 0; i < numprops; ++i)
- if (propkeys[i]->score < 666) /* 2/3 similarity required */
- break;
-
- switch (i)
+ switch (svn_cl__similarity_check(
+ propstring.data, propkeys, numprops, scratch_pool))
{
case 0:
+ return SVN_NO_ERROR; /* We found an exact match. */
+
+ case 1:
/* The best alternative isn't good enough */
return svn_error_create(
SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
wrong_prop_error_message(prop_use, propname, scratch_pool));
- case 1:
+ case 2:
/* There is only one good candidate */
- return svn_error_createf(
+ return svn_error_quick_wrap(svn_error_createf(
SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
- _("'%s' is not a valid %s property name; did you mean '%s'?\n%s"),
- propname, SVN_PROP_PREFIX, propkeys[0]->propname,
+ _("'%s' is not a valid %s property name; did you mean '%s'?"),
+ propname, SVN_PROP_PREFIX,
+ (const char *)propkeys[0]->data),
force_prop_option_message(prop_use, propname, scratch_pool));
- case 2:
+ case 3:
/* Suggest a list of the most likely candidates */
- return svn_error_createf(
+ return svn_error_quick_wrap(svn_error_createf(
SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
- _("'%s' is not a valid %s property name\n"
- "Did you mean '%s' or '%s'?\n%s"),
+ _("'%s' is not a valid %s property name; "
+ "did you mean '%s' or '%s'?"),
propname, SVN_PROP_PREFIX,
- propkeys[0]->propname, propkeys[1]->propname,
+ (const char *)propkeys[0]->data, (const char *)propkeys[1]->data),
force_prop_option_message(prop_use, propname, scratch_pool));
default:
/* Never suggest more than three candidates */
- return svn_error_createf(
+ return svn_error_quick_wrap(svn_error_createf(
SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
- _("'%s' is not a valid %s property name\n"
- "Did you mean '%s', '%s' or '%s'?\n%s"),
+ _("'%s' is not a valid %s property name; "
+ "did you mean '%s', '%s' or '%s'?"),
propname, SVN_PROP_PREFIX,
- propkeys[0]->propname, propkeys[1]->propname, propkeys[2]->propname,
+ (const char *)propkeys[0]->data,
+ (const char *)propkeys[1]->data, (const char *)propkeys[2]->data),
force_prop_option_message(prop_use, propname, scratch_pool));
}
}
diff --git a/subversion/svn/resolve-cmd.c b/subversion/svn/resolve-cmd.c
index ce4818eade2b..035bf29aff5a 100644
--- a/subversion/svn/resolve-cmd.c
+++ b/subversion/svn/resolve-cmd.c
@@ -123,7 +123,7 @@ svn_cl__resolve(apr_getopt_t *os,
svn_pool_destroy(iterpool);
if (had_error)
- return svn_error_create(SVN_ERR_CL_ERROR_PROCESSING_EXTERNALS, NULL,
+ return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Failure occurred resolving one or more "
"conflicts"));
diff --git a/subversion/svn/revert-cmd.c b/subversion/svn/revert-cmd.c
index d17aeb6f7e18..74d7ff185635 100644
--- a/subversion/svn/revert-cmd.c
+++ b/subversion/svn/revert-cmd.c
@@ -67,8 +67,11 @@ svn_cl__revert(apr_getopt_t *os,
SVN_ERR(svn_cl__check_targets_are_local_paths(targets));
- err = svn_client_revert2(targets, opt_state->depth,
- opt_state->changelists, ctx, scratch_pool);
+ err = svn_client_revert3(targets, opt_state->depth,
+ opt_state->changelists,
+ FALSE /* clear_changelists */,
+ FALSE /* metadata_only */,
+ ctx, scratch_pool);
if (err
&& (err->apr_err == SVN_ERR_WC_INVALID_OPERATION_DEPTH)
&& (! SVN_DEPTH_IS_RECURSIVE(opt_state->depth)))
diff --git a/subversion/svn/similarity.c b/subversion/svn/similarity.c
new file mode 100644
index 000000000000..0bcf0f559bf5
--- /dev/null
+++ b/subversion/svn/similarity.c
@@ -0,0 +1,126 @@
+/*
+ * similarity.c: Utility functions for finding similar strings in lists
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+/* ==================================================================== */
+
+
+
+/*** Includes. ***/
+
+#include <stdlib.h>
+
+#include "svn_string.h"
+#include "cl.h"
+
+#include "private/svn_string_private.h"
+
+#include "svn_private_config.h"
+
+
+/* Context for token similarity checking */
+struct svn_cl__simcheck_context_t
+{
+ svn_string_t key; /* The token we're comparing with */
+ svn_membuf_t buffer; /* Buffer for similarity testing */
+};
+
+
+/* Similarity test between two property names */
+static APR_INLINE apr_size_t
+simcheck_key_diff(const svn_string_t *key, const svn_string_t *ctx,
+ svn_membuf_t *buffer, apr_size_t *diff)
+{
+ apr_size_t lcs;
+ const apr_size_t score = svn_string__similarity(key, ctx, buffer, &lcs);
+ if (key->len > ctx->len)
+ *diff = key->len - lcs;
+ else
+ *diff = ctx->len - lcs;
+ return score;
+}
+
+
+/* Key comparator for qsort for svn_cl__simcheck_t */
+static int
+simcheck_compare(const void *pkeya, const void *pkeyb)
+{
+ svn_cl__simcheck_t *const keya = *(svn_cl__simcheck_t *const *)pkeya;
+ svn_cl__simcheck_t *const keyb = *(svn_cl__simcheck_t *const *)pkeyb;
+ svn_cl__simcheck_context_t *const context = keya->context;
+
+ if (keya->score == -1)
+ keya->score = simcheck_key_diff(&keya->token, &context->key,
+ &context->buffer, &keya->diff);
+ if (keyb->score == -1)
+ keyb->score = simcheck_key_diff(&keyb->token, &context->key,
+ &context->buffer, &keyb->diff);
+
+ return (keya->score < keyb->score ? 1
+ : (keya->score > keyb->score ? -1
+ : (keya->diff > keyb->diff ? 1
+ : (keya->diff < keyb->diff ? -1 : 0))));
+}
+
+apr_size_t
+svn_cl__similarity_check(const char *key,
+ svn_cl__simcheck_t **tokens,
+ apr_size_t token_count,
+ apr_pool_t *scratch_pool)
+{
+ apr_size_t result;
+ apr_size_t i;
+
+ svn_cl__simcheck_context_t context;
+ context.key.data = key;
+ context.key.len = strlen(key);
+ svn_membuf__create(&context.buffer, 0, scratch_pool);
+
+ /* Populate the score, diff and context members. */
+ for (i = 0; i < token_count; ++i)
+ {
+ svn_cl__simcheck_t *const token = tokens[i];
+ token->score = -1;
+ token->diff = 0;
+ token->context = &context;
+ }
+
+ /* Sort the tokens by similarity. */
+ qsort(tokens, token_count, sizeof(*tokens), simcheck_compare);
+
+ /* Remove references to the context, since it points to the stack,
+ and calculate the number of results that are at least two-thirds
+ similar to the key. */
+ for (i = 0, result = 1; i < token_count; ++i)
+ {
+ svn_cl__simcheck_t *const token = tokens[i];
+ token->context = NULL;
+ /* If you update this factor, consider updating
+ * ../libsvn_subr/cmdline.c:most_similar(). */
+ if (token->score >= (2 * SVN_STRING__SIM_RANGE_MAX + 1) / 3)
+ ++result;
+ }
+
+ if (0 == tokens[0]->diff)
+ return 0; /* We found an exact match. */
+ return result;
+}
diff --git a/subversion/svn/status-cmd.c b/subversion/svn/status-cmd.c
index 9840cd2bd5eb..7692eb3a7cc0 100644
--- a/subversion/svn/status-cmd.c
+++ b/subversion/svn/status-cmd.c
@@ -115,7 +115,7 @@ print_start_target_xml(const char *target, apr_pool_t *pool)
svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "target",
- "path", target, NULL);
+ "path", target, SVN_VA_NULL);
return svn_cl__error_checked_fputs(sb->data, stdout);
}
@@ -135,7 +135,7 @@ print_finish_target_xml(svn_revnum_t repos_rev,
const char *repos_rev_str;
repos_rev_str = apr_psprintf(pool, "%ld", repos_rev);
svn_xml_make_open_tag(&sb, pool, svn_xml_self_closing, "against",
- "revision", repos_rev_str, NULL);
+ "revision", repos_rev_str, SVN_VA_NULL);
}
svn_xml_make_close_tag(&sb, pool, "target");
@@ -187,7 +187,7 @@ print_status(void *baton,
* ### _read_info() returns. The svn_wc_status_func4_t callback is
* ### suppposed to handle the gathering of additional information from the
* ### WORKING nodes on its own. Until we've agreed on how the CLI should
- * ### handle the revision information, we use this appproach to stay compat
+ * ### handle the revision information, we use this approach to stay compat
* ### with our testsuite. */
if (status->versioned
&& !SVN_IS_VALID_REVNUM(status->revision)
@@ -288,8 +288,15 @@ svn_cl__status(apr_getopt_t *os,
SVN_ERR(svn_cl__check_targets_are_local_paths(targets));
- /* We want our -u statuses to be against HEAD. */
- rev.kind = svn_opt_revision_head;
+ /* We want our -u statuses to be against HEAD by default. */
+ if (opt_state->start_revision.kind == svn_opt_revision_unspecified)
+ rev.kind = svn_opt_revision_head;
+ else if (! opt_state->update)
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--revision (-r) option valid only with "
+ "--show-updates (-u) option"));
+ else
+ rev = opt_state->start_revision;
sb.had_print_error = FALSE;
@@ -345,10 +352,11 @@ svn_cl__status(apr_getopt_t *os,
/* Retrieve a hash of status structures with the information
requested by the user. */
- SVN_ERR(svn_cl__try(svn_client_status5(&repos_rev, ctx, target, &rev,
+ SVN_ERR(svn_cl__try(svn_client_status6(&repos_rev, ctx, target, &rev,
opt_state->depth,
opt_state->verbose,
opt_state->update,
+ TRUE /* check_working_copy */,
opt_state->no_ignore,
opt_state->ignore_externals,
FALSE /* depth_as_sticky */,
@@ -359,13 +367,13 @@ svn_cl__status(apr_getopt_t *os,
/* not versioned: */
SVN_ERR_WC_NOT_WORKING_COPY,
SVN_ERR_WC_PATH_NOT_FOUND,
- SVN_NO_ERROR));
+ 0));
if (opt_state->xml)
SVN_ERR(print_finish_target_xml(repos_rev, iterpool));
}
- /* If any paths were cached because they were associatied with
+ /* If any paths were cached because they were associated with
changelists, we can now display them as grouped changelists. */
if (apr_hash_count(master_cl_hash) > 0)
{
@@ -378,8 +386,8 @@ svn_cl__status(apr_getopt_t *os,
for (hi = apr_hash_first(scratch_pool, master_cl_hash); hi;
hi = apr_hash_next(hi))
{
- const char *changelist_name = svn__apr_hash_index_key(hi);
- apr_array_header_t *path_array = svn__apr_hash_index_val(hi);
+ const char *changelist_name = apr_hash_this_key(hi);
+ apr_array_header_t *path_array = apr_hash_this_val(hi);
int j;
/* ### TODO: For non-XML output, we shouldn't print the
@@ -390,7 +398,7 @@ svn_cl__status(apr_getopt_t *os,
svn_stringbuf_setempty(buf);
svn_xml_make_open_tag(&buf, scratch_pool, svn_xml_normal,
"changelist", "name", changelist_name,
- NULL);
+ SVN_VA_NULL);
SVN_ERR(svn_cl__error_checked_fputs(buf->data, stdout));
}
else
diff --git a/subversion/svn/status.c b/subversion/svn/status.c
index 9f1ad341bafb..9ab9c5926c55 100644
--- a/subversion/svn/status.c
+++ b/subversion/svn/status.c
@@ -138,37 +138,38 @@ generate_status_desc(enum svn_wc_status_kind status)
/* Make a relative path containing '..' elements as needed.
TARGET_ABSPATH shall be the absolute version of TARGET_PATH.
- TARGET_ABSPATH, TARGET_PATH and PATH shall be canonical.
+ TARGET_ABSPATH, TARGET_PATH and LOCAL_ABSPATH shall be canonical
If above conditions are met, a relative path that leads to PATH
from TARGET_PATH is returned, but there is no error checking involved.
The returned path is allocated from RESULT_POOL, all other
- allocations are made in SCRATCH_POOL. */
+ allocations are made in SCRATCH_POOL.
+
+ Note that it is not possible to just join the resulting path to
+ reconstruct the real path as the "../" paths are relative from
+ a different base than the normal relative paths!
+ */
static const char *
make_relpath(const char *target_abspath,
const char *target_path,
- const char *path,
+ const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const char *la;
const char *parent_dir_els = "";
- const char *abspath, *relative;
- svn_error_t *err = svn_dirent_get_absolute(&abspath, path, scratch_pool);
+ const char *t_relpath;
+ const char *p_relpath;
- if (err)
- {
- /* We probably got passed some invalid path. */
- svn_error_clear(err);
- return apr_pstrdup(result_pool, path);
- }
+#ifdef SVN_DEBUG
+ SVN_ERR_ASSERT_NO_RETURN(svn_dirent_is_absolute(local_abspath));
+#endif
- relative = svn_dirent_skip_ancestor(target_abspath, abspath);
- if (relative)
- {
- return svn_dirent_join(target_path, relative, result_pool);
- }
+ t_relpath = svn_dirent_skip_ancestor(target_abspath, local_abspath);
+
+ if (t_relpath)
+ return svn_dirent_join(target_path, t_relpath, result_pool);
/* An example:
* relative_to_path = /a/b/c
@@ -180,17 +181,16 @@ make_relpath(const char *target_abspath,
* path = C:/wc
* result = C:/wc
*/
-
/* Skip the common ancestor of both paths, here '/a'. */
- la = svn_dirent_get_longest_ancestor(target_abspath, abspath,
+ la = svn_dirent_get_longest_ancestor(target_abspath, local_abspath,
scratch_pool);
if (*la == '\0')
{
/* Nothing in common: E.g. C:/ vs F:/ on Windows */
- return apr_pstrdup(result_pool, path);
+ return apr_pstrdup(result_pool, local_abspath);
}
- relative = svn_dirent_skip_ancestor(la, target_abspath);
- path = svn_dirent_skip_ancestor(la, path);
+ t_relpath = svn_dirent_skip_ancestor(la, target_abspath);
+ p_relpath = svn_dirent_skip_ancestor(la, local_abspath);
/* In above example, we'd now have:
* relative_to_path = b/c
@@ -198,14 +198,14 @@ make_relpath(const char *target_abspath,
/* Count the elements of relative_to_path and prepend as many '..' elements
* to path. */
- while (*relative)
+ while (*t_relpath)
{
- svn_dirent_split(&relative, NULL, relative,
- scratch_pool);
+ t_relpath = svn_dirent_dirname(t_relpath, scratch_pool);
parent_dir_els = svn_dirent_join(parent_dir_els, "..", scratch_pool);
}
- return svn_dirent_join(parent_dir_els, path, result_pool);
+ /* This returns a ../ style path relative from the status target */
+ return svn_dirent_join(parent_dir_els, p_relpath, result_pool);
}
@@ -232,8 +232,6 @@ print_status(const char *target_abspath,
const char *moved_from_line = "";
const char *moved_to_line = "";
- path = make_relpath(target_abspath, target_path, path, pool, pool);
-
/* For historic reasons svn ignores the property status for added nodes, even
if these nodes were copied and have local property changes.
@@ -317,7 +315,7 @@ print_status(const char *target_abspath,
apr_psprintf(pool,
_("swapped places with %s"),
relpath),
- (char *)NULL);
+ SVN_VA_NULL);
}
else if (status->moved_from_abspath || status->moved_to_abspath)
{
@@ -332,7 +330,7 @@ print_status(const char *target_abspath,
moved_from_line = apr_pstrcat(pool, "\n > ",
apr_psprintf(pool, _("moved from %s"),
relpath),
- (char *)NULL);
+ SVN_VA_NULL);
}
if (status->moved_to_abspath)
@@ -344,7 +342,7 @@ print_status(const char *target_abspath,
moved_to_line = apr_pstrcat(pool, "\n > ",
apr_psprintf(pool, _("moved to %s"),
relpath),
- (char *)NULL);
+ SVN_VA_NULL);
}
}
@@ -487,10 +485,9 @@ svn_cl__print_status_xml(const char *target_abspath,
SVN_ERR(svn_wc_conflicted_p3(NULL, NULL, &tree_conflicted,
ctx->wc_ctx, local_abspath, pool));
- path = make_relpath(target_abspath, target_path, path, pool, pool);
-
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "entry",
- "path", svn_dirent_local_style(path, pool), NULL);
+ "path", svn_dirent_local_style(path, pool),
+ SVN_VA_NULL);
att_hash = apr_hash_make(pool);
svn_hash_sets(att_hash, "item",
@@ -560,7 +557,7 @@ svn_cl__print_status_xml(const char *target_abspath,
generate_status_desc(combined_repos_status(status)),
"props",
generate_status_desc(status->repos_prop_status),
- NULL);
+ SVN_VA_NULL);
if (status->repos_lock)
svn_cl__print_xml_lock(&sb, status->repos_lock, pool);
diff --git a/subversion/svn/svn.c b/subversion/svn/svn.c
index c2db8bf68e50..058be707d074 100644
--- a/subversion/svn/svn.c
+++ b/subversion/svn/svn.c
@@ -110,7 +110,7 @@ typedef enum svn_cl__longopt_t {
opt_remove,
opt_revprop,
opt_stop_on_copy,
- opt_strict,
+ opt_strict, /* ### DEPRECATED */
opt_targets,
opt_depth,
opt_set_depth,
@@ -125,6 +125,7 @@ typedef enum svn_cl__longopt_t {
opt_show_revs,
opt_reintegrate,
opt_trust_server_cert,
+ opt_trust_server_cert_failures,
opt_strip,
opt_ignore_keywords,
opt_reverse_diff,
@@ -134,7 +135,14 @@ typedef enum svn_cl__longopt_t {
opt_include_externals,
opt_show_inherited_props,
opt_search,
- opt_search_and
+ opt_search_and,
+ opt_mergeinfo_log,
+ opt_remove_unversioned,
+ opt_remove_ignored,
+ opt_no_newline,
+ opt_show_passwords,
+ opt_pin_externals,
+ opt_show_item,
} svn_cl__longopt_t;
@@ -186,7 +194,10 @@ const apr_getopt_option_t svn_cl__options[] =
{"verbose", 'v', 0, N_("print extra information")},
{"show-updates", 'u', 0, N_("display update information")},
{"username", opt_auth_username, 1, N_("specify a username ARG")},
- {"password", opt_auth_password, 1, N_("specify a password ARG")},
+ {"password", opt_auth_password, 1,
+ N_("specify a password ARG (caution: on many operating\n"
+ " "
+ "systems, other users will be able to see this)")},
{"extensions", 'x', 1,
N_("Specify differencing options for external diff or\n"
" "
@@ -204,6 +215,8 @@ const apr_getopt_option_t svn_cl__options[] =
" "
" --ignore-eol-style: Ignore changes in EOL style\n"
" "
+ " -U ARG, --context ARG: Show ARG lines of context\n"
+ " "
" -p, --show-c-function: Show C function name")},
{"targets", opt_targets, 1,
N_("pass contents of file ARG as additional args")},
@@ -216,7 +229,7 @@ const apr_getopt_option_t svn_cl__options[] =
" "
"'empty', 'files', 'immediates', or 'infinity')")},
{"xml", opt_xml, 0, N_("output in XML")},
- {"strict", opt_strict, 0, N_("use strict semantics")},
+ {"strict", opt_strict, 0, N_("DEPRECATED")},
{"stop-on-copy", opt_stop_on_copy, 0,
N_("do not cross copies while traversing history")},
{"no-ignore", opt_no_ignore, 0,
@@ -226,11 +239,23 @@ const apr_getopt_option_t svn_cl__options[] =
{"no-auth-cache", opt_no_auth_cache, 0,
N_("do not cache authentication tokens")},
{"trust-server-cert", opt_trust_server_cert, 0,
- N_("accept SSL server certificates from unknown\n"
+ N_("deprecated; same as\n"
+ " "
+ "--trust-server-cert-failures=unknown-ca")},
+ {"trust-server-cert-failures", opt_trust_server_cert_failures, 1,
+ N_("with --non-interactive, accept SSL server\n"
+ " "
+ "certificates with failures; ARG is comma-separated\n"
+ " "
+ "list of 'unknown-ca' (Unknown Authority),\n"
" "
- "certificate authorities without prompting (but only\n"
+ "'cn-mismatch' (Hostname mismatch), 'expired'\n"
" "
- "with '--non-interactive')") },
+ "(Expired certificate), 'not-yet-valid' (Not yet\n"
+ " "
+ "valid certificate) and 'other' (all other not\n"
+ " "
+ "separately classified certificate errors).")},
{"non-interactive", opt_non_interactive, 0,
N_("do no interactive prompting (default is to prompt\n"
" "
@@ -369,17 +394,36 @@ const apr_getopt_option_t svn_cl__options[] =
" "
"Please run 'svn update' instead.")},
{"include-externals", opt_include_externals, 0,
- N_("Also commit file and dir externals reached by\n"
+ N_("also operate on externals defined by\n"
" "
- "recursion. This does not include externals with a\n"
- " "
- "fixed revision. (See the svn:externals property)")},
+ "svn:externals properties")},
{"show-inherited-props", opt_show_inherited_props, 0,
- N_("retrieve target's inherited properties")},
+ N_("retrieve properties set on parents of the target")},
{"search", opt_search, 1,
N_("use ARG as search pattern (glob syntax)")},
{"search-and", opt_search_and, 1,
N_("combine ARG with the previous search pattern")},
+ {"log", opt_mergeinfo_log, 0,
+ N_("show revision log message, author and date")},
+ {"remove-unversioned", opt_remove_unversioned, 0,
+ N_("remove unversioned items")},
+ {"remove-ignored", opt_remove_ignored, 0, N_("remove ignored items")},
+ {"no-newline", opt_no_newline, 0, N_("do not output the trailing newline")},
+ {"show-passwords", opt_show_passwords, 0, N_("show cached passwords")},
+ {"pin-externals", opt_pin_externals, 0,
+ N_("pin externals with no explicit revision to their\n"
+ " "
+ "current revision (recommended when tagging)")},
+ {"show-item", opt_show_item, 1,
+ N_("print only the item identified by ARG ('kind',\n"
+ " "
+ "'url', 'relative-url', 'repos-root-url',\n"
+ " "
+ "'repos-uuid', 'revision', 'last-changed-revision',\n"
+ " "
+ "'last-changed-date', 'last-changed-author',\n"
+ " "
+ "'wc-root')")},
/* Long-opt Aliases
*
@@ -412,8 +456,9 @@ const apr_getopt_option_t svn_cl__options[] =
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_force_interactive, opt_trust_server_cert, opt_config_dir,
- opt_config_options, 0
+ opt_force_interactive, opt_trust_server_cert,
+ opt_trust_server_cert_failures,
+ opt_config_dir, opt_config_options, 0
};
/* Options for giving a log message. (Some of these also have other uses.)
@@ -434,13 +479,54 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
opt_no_autoprops, opt_parents },
{{opt_parents, N_("add intermediate parents")}} },
+ { "auth", svn_cl__auth, {0}, N_
+ ("Manage cached authentication credentials.\n"
+ "usage: 1. svn auth [PATTERN ...]\n"
+ "usage: 2. svn auth --remove PATTERN [PATTERN ...]\n"
+ "\n"
+ " With no arguments, list all cached authentication credentials.\n"
+ " Authentication credentials include usernames, passwords,\n"
+ " SSL certificates, and SSL client-certificate passphrases.\n"
+ " If PATTERN is specified, only list credentials with attributes matching one\n"
+ " or more patterns. With the --remove option, remove cached authentication\n"
+ " credentials matching one or more patterns.\n"
+ "\n"
+ " If more than one pattern is specified credentials are considered only they\n"
+ " match all specified patterns. Patterns are matched case-sensitively and may\n"
+ " contain glob wildcards:\n"
+ " ? matches any single character\n"
+ " * matches a sequence of arbitrary characters\n"
+ " [abc] matches any of the characters listed inside the brackets\n"
+ " Note that wildcards will usually need to be quoted or escaped on the\n"
+ " command line because many command shells will interfere by trying to\n"
+ " expand them.\n"),
+ { opt_remove, opt_show_passwords },
+ { {opt_remove, N_("remove matching authentication credentials")} }
+
+ },
+
{ "blame", svn_cl__blame, {"praise", "annotate", "ann"}, N_
- ("Output the content of specified files or\n"
- "URLs with revision and author information in-line.\n"
- "usage: blame TARGET[@REV]...\n"
+ ("Show when each line of a file was last (or\n"
+ "next) changed.\n"
+ "usage: blame [-rM:N] TARGET[@REV]...\n"
+ "\n"
+ " Annotate each line of a file with the revision number and author of the\n"
+ " last change (or optionally the next change) to that line.\n"
+ "\n"
+ " With no revision range (same as -r0:REV), or with '-r M:N' where M < N,\n"
+ " annotate each line that is present in revision N of the file, with\n"
+ " the last revision at or before rN that changed or added the line,\n"
+ " looking back no further than rM.\n"
+ "\n"
+ " With a reverse revision range '-r M:N' where M > N,\n"
+ " annotate each line that is present in revision N of the file, with\n"
+ " the next revision after rN that changed or deleted the line,\n"
+ " looking forward no further than rM.\n"
"\n"
" If specified, REV determines in which revision the target is first\n"
- " looked up.\n"),
+ " looked up.\n"
+ "\n"
+ " Write the annotated result to standard output.\n"),
{'r', 'v', 'g', opt_incremental, opt_xml, 'x', opt_force} },
{ "cat", svn_cl__cat, {0}, N_
@@ -449,7 +535,7 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
"\n"
" If specified, REV determines in which revision the target is first\n"
" looked up.\n"),
- {'r'} },
+ {'r', opt_ignore_keywords} },
{ "changelist", svn_cl__changelist, {"cl"}, N_
("Associate (or dissociate) changelist CLNAME with the named files.\n"
@@ -489,16 +575,25 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
"unfinished operations, etc.\n"
"usage: cleanup [WCPATH...]\n"
"\n"
- " Finish any unfinished business in the working copy at WCPATH, and remove\n"
- " write locks (shown as 'L' by the 'svn status' command) from the working\n"
- " copy. Usually, this is only necessary if a Subversion client has crashed\n"
- " while using the working copy, leaving it in an unusable state.\n"
+ " By default, finish any unfinished business in the working copy at WCPATH,\n"
+ " and remove write locks (shown as 'L' by the 'svn status' command) from\n"
+ " the working copy. Usually, this is only necessary if a Subversion client\n"
+ " has crashed while using the working copy, leaving it in an unusable state.\n"
"\n"
" WARNING: There is no mechanism that will protect write locks still\n"
" being used by other Subversion clients. Running this command\n"
" while another client is using the working copy can corrupt\n"
- " the working copy beyond repair!\n"),
- {opt_merge_cmd} },
+ " the working copy beyond repair!\n"
+ "\n"
+ " If the --remove-unversioned option or the --remove-ignored option\n"
+ " is given, remove any unversioned or ignored items within WCPATH.\n"
+ " To prevent accidental working copy corruption, unversioned or ignored\n"
+ " items can only be removed if the working copy is not already locked\n"
+ " for writing by another Subversion client.\n"
+ " Note that the 'svn status' command shows unversioned items as '?',\n"
+ " and ignored items as 'I' if the --no-ignore option is given to it.\n"),
+ {opt_merge_cmd, opt_remove_unversioned, opt_remove_ignored,
+ opt_include_externals, 'q'} },
{ "commit", svn_cl__commit, {"ci"},
N_("Send changes from your working copy to the repository.\n"
@@ -507,7 +602,11 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
" A log message must be provided, but it can be empty. If it is not\n"
" given by a --message or --file option, an editor will be started.\n"
" If any targets are (or contain) locked items, those will be\n"
- " unlocked after a successful commit.\n"),
+ " unlocked after a successful commit.\n"
+ "\n"
+ " If --include-externals is given, also commit file and directory\n"
+ " externals reached by recursion. Do not commit externals with a\n"
+ " fixed revision.\n"),
{'q', 'N', opt_depth, opt_targets, opt_no_unlock, SVN_CL__LOG_MSG_OPTIONS,
opt_changelist, opt_keep_changelists, opt_include_externals} },
@@ -528,7 +627,8 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
" contact the repository. As such, they may not, by default, be able\n"
" to propagate merge tracking information from the source of the copy\n"
" to the destination.\n"),
- {'r', 'q', opt_ignore_externals, opt_parents, SVN_CL__LOG_MSG_OPTIONS} },
+ {'r', 'q', opt_ignore_externals, opt_parents, SVN_CL__LOG_MSG_OPTIONS,
+ opt_pin_externals} },
{ "delete", svn_cl__delete, {"del", "remove", "rm"}, N_
("Remove files and directories from version control.\n"
@@ -635,8 +735,24 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
"\n"
" Print information about each TARGET (default: '.').\n"
" TARGET may be either a working-copy path or URL. If specified, REV\n"
- " determines in which revision the target is first looked up.\n"),
- {'r', 'R', opt_depth, opt_targets, opt_incremental, opt_xml, opt_changelist}
+ " determines in which revision the target is first looked up.\n"
+ "\n"
+ " With --show-item, print only the value of one item of information\n"
+ " about TARGET. One of the following items can be selected:\n"
+ " kind the kind of TARGET\n"
+ " url the URL of TARGET in the repository\n"
+ " relative-url the repository-relative URL\n"
+ " repos-root-url the repository root URL\n"
+ " repos-uuid the repository UUID\n"
+ " revision the revision of TARGET (defaults to BASE\n"
+ " for working copy paths and HEAD for URLs)\n"
+ " last-changed-revision the most recent revision in which TARGET\n"
+ " was changed\n"
+ " last-changed-date the date of the last-changed revision\n"
+ " last-changed-author the author of the last-changed revision\n"
+ " wc-root the root of TARGET's working copy\n"),
+ {'r', 'R', opt_depth, opt_targets, opt_incremental, opt_xml,
+ opt_changelist, opt_include_externals, opt_show_item, opt_no_newline}
},
{ "list", svn_cl__list, {"ls"}, N_
@@ -659,8 +775,7 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
" Size (in bytes)\n"
" Date and time of the last commit\n"),
{'r', 'v', 'R', opt_depth, opt_incremental, opt_xml,
- opt_include_externals },
- {{opt_include_externals, N_("include externals definitions")}} },
+ opt_include_externals}, },
{ "lock", svn_cl__lock, {0}, N_
("Lock working copy paths or URLs in the repository, so that\n"
@@ -748,12 +863,14 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
" Show the log message for the revision in which /branches/foo\n"
" was created:\n"
" svn log --stop-on-copy --limit 1 -r0:HEAD ^/branches/foo\n"),
- {'r', 'q', 'v', 'g', 'c', opt_targets, opt_stop_on_copy, opt_incremental,
- opt_xml, 'l', opt_with_all_revprops, opt_with_no_revprops, opt_with_revprop,
- opt_depth, opt_diff, opt_diff_cmd, opt_internal_diff, 'x', opt_search,
- opt_search_and, },
+ {'r', 'c', 'q', 'v', 'g', opt_targets, opt_stop_on_copy, opt_incremental,
+ opt_xml, 'l', opt_with_all_revprops, opt_with_no_revprops,
+ opt_with_revprop, opt_depth, opt_diff, opt_diff_cmd,
+ opt_internal_diff, 'x', opt_search, opt_search_and },
{{opt_with_revprop, N_("retrieve revision property ARG")},
- {'c', N_("the change made in revision ARG")}} },
+ {'c', N_("the change made in revision ARG")},
+ {'v', N_("also print all affected paths")},
+ {'q', N_("do not print the log message")}} },
{ "merge", svn_cl__merge, {0}, N_
( /* For this large section, let's keep it unindented for easier
@@ -1088,7 +1205,9 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
" 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, 'v'} },
+ opt_allow_mixed_revisions, 'v'},
+ { { opt_force, N_("force deletions even if deleted contents don't match") } }
+ },
{ "mergeinfo", svn_cl__mergeinfo, {0}, N_
("Display merge-related information.\n"
@@ -1119,7 +1238,8 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
" and the default for TARGET is HEAD for a URL or BASE for a WC path.\n"
"\n"
" The depth can be 'empty' or 'infinity'; the default is 'empty'.\n"),
- {'r', 'R', opt_depth, opt_show_revs} },
+ {'r', 'R', 'q', 'v', opt_depth, opt_show_revs, opt_mergeinfo_log,
+ opt_incremental } },
{ "mkdir", svn_cl__mkdir, {0}, N_
("Create a new directory under version control.\n"
@@ -1215,7 +1335,9 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
"\n"
" 1. Removes versioned props in working copy.\n"
" 2. Removes unversioned remote prop on repos revision.\n"
- " TARGET only determines which repository to access.\n"),
+ " TARGET only determines which repository to access.\n"
+ "\n"
+ " See 'svn help propset' for descriptions of the svn:* special properties.\n"),
{'q', 'R', opt_depth, 'r', opt_revprop, opt_changelist} },
{ "propedit", svn_cl__propedit, {"pedit", "pe"}, N_
@@ -1227,7 +1349,7 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
" 2. Edits unversioned remote prop on repos revision.\n"
" TARGET only determines which repository to access.\n"
"\n"
- " See 'svn help propset' for more on setting properties.\n"),
+ " See 'svn help propset' for descriptions of the svn:* special properties.\n"),
{'r', opt_revprop, SVN_CL__LOG_MSG_OPTIONS, opt_force} },
{ "propget", svn_cl__propget, {"pget", "pg"}, N_
@@ -1246,13 +1368,15 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
" 'empty', the target path is printed on the same line before each value.\n"
"\n"
" By default, an extra newline is printed after the property value so that\n"
- " the output looks pretty. With a single TARGET and depth 'empty', you can\n"
- " use the --strict option to disable this (useful when redirecting a binary\n"
- " property value to a file, for example).\n"),
- {'v', 'R', opt_depth, 'r', opt_revprop, opt_strict, opt_xml,
+ " the output looks pretty. With a single TARGET, depth 'empty' and without\n"
+ " --show-inherited-props, you can use the --no-newline option to disable this\n"
+ " (useful when redirecting a binary property value to a file, for example).\n"
+ "\n"
+ " See 'svn help propset' for descriptions of the svn:* special properties.\n"),
+ {'v', 'R', opt_depth, 'r', opt_revprop, opt_strict, opt_no_newline, opt_xml,
opt_changelist, opt_show_inherited_props },
{{'v', N_("print path, name and value on separate lines")},
- {opt_strict, N_("don't print an extra newline")}} },
+ {opt_strict, N_("(deprecated; use --no-newline)")}} },
{ "proplist", svn_cl__proplist, {"plist", "pl"}, N_
("List all properties on files, dirs, or revisions.\n"
@@ -1265,7 +1389,9 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
" TARGET only determines which repository to access.\n"
"\n"
" With --verbose, the property values are printed as well, like 'svn propget\n"
- " --verbose'. With --quiet, the paths are not printed.\n"),
+ " --verbose'. With --quiet, the paths are not printed.\n"
+ "\n"
+ " See 'svn help propset' for descriptions of the svn:* special properties.\n"),
{'v', 'R', opt_depth, 'r', 'q', opt_revprop, opt_xml, opt_changelist,
opt_show_inherited_props },
{{'v', N_("print path, name and value on separate lines")},
@@ -1350,6 +1476,7 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
" ^/ to the repository root\n"
" / to the server root\n"
" // to the URL scheme\n"
+ " ^/../ to a sibling repository beneath the same SVNParentPath location\n"
" Use of the following format is discouraged but is supported for\n"
" interoperability with Subversion 1.4 and earlier clients:\n"
" LOCALPATH [-r PEG] URL\n"
@@ -1452,9 +1579,9 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
" another Subversion client modifying the working copy\n"
" ' ' not locked for writing\n"
" 'L' locked for writing\n"
- " Fourth column: Scheduled commit will contain addition-with-history\n"
- " ' ' no history scheduled with commit\n"
- " '+' history scheduled with commit\n"
+ " Fourth column: Scheduled commit will create a copy (addition-with-history)\n"
+ " ' ' no history scheduled with commit (item was newly added)\n"
+ " '+' history scheduled with commit (item was copied)\n"
" Fifth column: Whether the item is switched or a file external\n"
" ' ' normal\n"
" 'S' the item has a Switched URL relative to the parent\n"
@@ -1514,8 +1641,8 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
" ! C wc/qaz.c\n"
" > local missing, incoming edit upon update\n"
" D wc/qax.c\n"),
- { 'u', 'v', 'N', opt_depth, 'q', opt_no_ignore, opt_incremental, opt_xml,
- opt_ignore_externals, opt_changelist},
+ { 'u', 'v', 'N', opt_depth, 'r', 'q', opt_no_ignore, opt_incremental,
+ opt_xml, opt_ignore_externals, opt_changelist},
{{'q', N_("don't print unversioned items")}} },
{ "switch", svn_cl__switch, {"sw"}, N_
@@ -1561,7 +1688,9 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
{ 'r', 'N', opt_depth, opt_set_depth, 'q', opt_merge_cmd, opt_relocate,
opt_ignore_externals, opt_ignore_ancestry, opt_force, opt_accept},
{{opt_ignore_ancestry,
- N_("allow switching to a node with no common ancestor")}}
+ N_("allow switching to a node with no common ancestor")},
+ {opt_force,
+ N_("handle unversioned obstructions as changes")}}
},
{ "unlock", svn_cl__unlock, {0}, N_
@@ -1619,7 +1748,9 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
" targets of this operation.\n"),
{'r', 'N', opt_depth, opt_set_depth, 'q', opt_merge_cmd, opt_force,
opt_ignore_externals, opt_changelist, opt_editor_cmd, opt_accept,
- opt_parents} },
+ opt_parents},
+ { {opt_force,
+ N_("handle unversioned obstructions as changes")} } },
{ "upgrade", svn_cl__upgrade, {0}, N_
("Upgrade the metadata storage format for a working copy.\n"
@@ -1667,6 +1798,8 @@ signal_handler(int signum)
svn_error_t *
svn_cl__check_cancel(void *baton)
{
+ /* Cancel baton should be always NULL in command line client. */
+ SVN_ERR_ASSERT(baton == NULL);
if (cancelled)
return svn_error_create(SVN_ERR_CANCELLED, NULL, _("Caught signal"));
else
@@ -1715,23 +1848,13 @@ add_search_pattern_to_latest_group(svn_cl__opt_state_t *opt_state,
/*** Main. ***/
-/* Report and clear the error ERR, and return EXIT_FAILURE. Suppress the
- * error message if it is SVN_ERR_IO_PIPE_WRITE_ERROR. */
-#define EXIT_ERROR(err) \
- svn_cmdline_handle_exit_error(err, NULL, "svn: ")
-
-/* A redefinition of the public SVN_INT_ERR macro, that suppresses the
- * error message if it is SVN_ERR_IO_PIPE_WRITE_ERROR. */
-#undef SVN_INT_ERR
-#define SVN_INT_ERR(expr) \
- do { \
- svn_error_t *svn_err__temp = (expr); \
- if (svn_err__temp) \
- return EXIT_ERROR(svn_err__temp); \
- } while (0)
-
-static int
-sub_main(int argc, const char *argv[], apr_pool_t *pool)
+/*
+ * On success, leave *EXIT_CODE untouched and return SVN_NO_ERROR. On error,
+ * either return an error to be displayed, or set *EXIT_CODE to non-zero and
+ * return SVN_NO_ERROR.
+ */
+static svn_error_t *
+sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
{
svn_error_t *err;
int opt_id;
@@ -1741,7 +1864,7 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
apr_array_header_t *received_opts;
int i;
const svn_opt_subcommand_desc2_t *subcommand = NULL;
- const char *dash_m_arg = NULL, *dash_F_arg = NULL;
+ const char *dash_F_arg = NULL;
svn_cl__cmd_baton_t command_baton;
svn_auth_baton_t *ab;
svn_config_t *cfg_config;
@@ -1758,18 +1881,18 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int));
/* Check library versions */
- SVN_INT_ERR(check_lib_versions());
+ SVN_ERR(check_lib_versions());
#if defined(WIN32) || defined(__CYGWIN__)
/* Set the working copy administrative directory name. */
if (getenv("SVN_ASP_DOT_NET_HACK"))
{
- SVN_INT_ERR(svn_wc_set_adm_dir("_svn", pool));
+ SVN_ERR(svn_wc_set_adm_dir("_svn", pool));
}
#endif
/* Initialize the RA library. */
- SVN_INT_ERR(svn_ra_initialize(pool));
+ SVN_ERR(svn_ra_initialize(pool));
/* Init our changelists hash. */
changelists = apr_hash_make(pool);
@@ -1787,12 +1910,13 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
/* No args? Show usage. */
if (argc <= 1)
{
- SVN_INT_ERR(svn_cl__help(NULL, NULL, pool));
- return EXIT_FAILURE;
+ SVN_ERR(svn_cl__help(NULL, NULL, pool));
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
/* Else, parse options. */
- SVN_INT_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
+ SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
os->interleave = 1;
while (1)
@@ -1807,8 +1931,9 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
break;
else if (apr_err)
{
- SVN_INT_ERR(svn_cl__help(NULL, NULL, pool));
- return EXIT_FAILURE;
+ SVN_ERR(svn_cl__help(NULL, NULL, pool));
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
/* Stash the option code in an array before parsing it. */
@@ -1817,39 +1942,37 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
switch (opt_id) {
case 'l':
{
- err = svn_cstring_atoi(&opt_state.limit, opt_arg);
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ err = svn_cstring_atoi(&opt_state.limit, utf8_opt_arg);
if (err)
{
- err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, err,
- _("Non-numeric limit argument given"));
- return EXIT_ERROR(err);
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, err,
+ _("Non-numeric limit argument given"));
}
if (opt_state.limit <= 0)
{
- err = svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
- _("Argument to --limit must be positive"));
- return EXIT_ERROR(err);
+ return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+ _("Argument to --limit must be positive"));
}
}
break;
case 'm':
- /* Note that there's no way here to detect if the log message
- contains a zero byte -- if it does, then opt_arg will just
- be shorter than the user intended. Oh well. */
+ /* We store the raw message here. We will convert it to UTF-8
+ * later, according to the value of the '--encoding' option. */
opt_state.message = apr_pstrdup(pool, opt_arg);
- dash_m_arg = opt_arg;
break;
case 'c':
{
- apr_array_header_t *change_revs =
- svn_cstring_split(opt_arg, ", \n\r\t\v", TRUE, pool);
+ apr_array_header_t *change_revs;
+
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ change_revs = svn_cstring_split(utf8_opt_arg, ", \n\r\t\v", TRUE,
+ pool);
if (opt_state.old_target)
{
- err = svn_error_create
- (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("Can't specify -c with --old"));
- return EXIT_ERROR(err);
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Can't specify -c with --old"));
}
for (i = 0; i < change_revs->nelts; i++)
@@ -1877,12 +2000,11 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
{
if (changeno < 0 || is_negative)
{
- err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR,
- NULL,
- _("Negative number in range (%s)"
- " not supported with -c"),
- change_str);
- return EXIT_ERROR(err);
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR,
+ NULL,
+ _("Negative number in range (%s)"
+ " not supported with -c"),
+ change_str);
}
s = end + 1;
while (*s == 'r')
@@ -1891,17 +2013,15 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
}
if (end == change_str || *end != '\0')
{
- err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("Non-numeric change argument (%s) "
- "given to -c"), change_str);
- return EXIT_ERROR(err);
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Non-numeric change argument (%s) "
+ "given to -c"), change_str);
}
if (changeno == 0)
{
- err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("There is no change 0"));
- return EXIT_ERROR(err);
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("There is no change 0"));
}
if (is_negative)
@@ -1937,15 +2057,13 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
break;
case 'r':
opt_state.used_revision_arg = TRUE;
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
if (svn_opt_parse_revision_to_range(opt_state.revision_ranges,
- opt_arg, pool) != 0)
+ utf8_opt_arg, pool) != 0)
{
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
- err = svn_error_createf
- (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("Syntax error in revision argument '%s'"),
utf8_opt_arg);
- return EXIT_ERROR(err);
}
break;
case 'v':
@@ -1965,23 +2083,22 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
opt_state.incremental = TRUE;
break;
case 'F':
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
- SVN_INT_ERR(svn_stringbuf_from_file2(&(opt_state.filedata),
- utf8_opt_arg, pool));
+ /* We read the raw file content here. We will convert it to UTF-8
+ * later (if it's a log/lock message or an svn:* prop value),
+ * according to the value of the '--encoding' option. */
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ SVN_ERR(svn_stringbuf_from_file2(&(opt_state.filedata),
+ utf8_opt_arg, pool));
reading_file_from_stdin = (strcmp(utf8_opt_arg, "-") == 0);
- dash_F_arg = opt_arg;
+ dash_F_arg = utf8_opt_arg;
break;
case opt_targets:
{
svn_stringbuf_t *buffer, *buffer_utf8;
- /* We need to convert to UTF-8 now, even before we divide
- the targets into an array, because otherwise we wouldn't
- know what delimiter to use for svn_cstring_split(). */
-
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
- SVN_INT_ERR(svn_stringbuf_from_file2(&buffer, utf8_opt_arg, pool));
- SVN_INT_ERR(svn_utf_stringbuf_to_utf8(&buffer_utf8, buffer, pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ SVN_ERR(svn_stringbuf_from_file2(&buffer, utf8_opt_arg, pool));
+ SVN_ERR(svn_utf_stringbuf_to_utf8(&buffer_utf8, buffer, pool));
opt_state.targets = svn_cstring_split(buffer_utf8->data, "\n\r",
TRUE, pool);
}
@@ -2007,51 +2124,47 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
case opt_depth:
err = svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool);
if (err)
- return EXIT_ERROR
- (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, err,
- _("Error converting depth "
- "from locale to UTF-8")));
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, err,
+ _("Error converting depth "
+ "from locale to UTF-8"));
opt_state.depth = svn_depth_from_word(utf8_opt_arg);
if (opt_state.depth == svn_depth_unknown
|| opt_state.depth == svn_depth_exclude)
{
- return EXIT_ERROR
- (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("'%s' is not a valid depth; try "
- "'empty', 'files', 'immediates', "
- "or 'infinity'"),
- utf8_opt_arg));
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("'%s' is not a valid depth; try "
+ "'empty', 'files', 'immediates', "
+ "or 'infinity'"),
+ utf8_opt_arg);
}
break;
case opt_set_depth:
err = svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool);
if (err)
- return EXIT_ERROR
- (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, err,
- _("Error converting depth "
- "from locale to UTF-8")));
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, err,
+ _("Error converting depth "
+ "from locale to UTF-8"));
opt_state.set_depth = svn_depth_from_word(utf8_opt_arg);
/* svn_depth_exclude is okay for --set-depth. */
if (opt_state.set_depth == svn_depth_unknown)
{
- return EXIT_ERROR
- (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("'%s' is not a valid depth; try "
- "'exclude', 'empty', 'files', "
- "'immediates', or 'infinity'"),
- utf8_opt_arg));
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("'%s' is not a valid depth; try "
+ "'exclude', 'empty', 'files', "
+ "'immediates', or 'infinity'"),
+ utf8_opt_arg);
}
break;
case opt_version:
opt_state.version = TRUE;
break;
case opt_auth_username:
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_username,
- opt_arg, pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_username,
+ opt_arg, pool));
break;
case opt_auth_password:
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_password,
- opt_arg, pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_password,
+ opt_arg, pool));
break;
case opt_encoding:
opt_state.encoding = apr_pstrdup(pool, opt_arg);
@@ -2062,9 +2175,6 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
case opt_stop_on_copy:
opt_state.stop_on_copy = TRUE;
break;
- case opt_strict:
- opt_state.strict = TRUE;
- break;
case opt_no_ignore:
opt_state.no_ignore = TRUE;
break;
@@ -2077,8 +2187,18 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
case opt_force_interactive:
force_interactive = TRUE;
break;
- case opt_trust_server_cert:
- opt_state.trust_server_cert = TRUE;
+ case opt_trust_server_cert: /* backwards compat to 1.8 */
+ opt_state.trust_server_cert_unknown_ca = TRUE;
+ break;
+ case opt_trust_server_cert_failures:
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ SVN_ERR(svn_cmdline__parse_trust_options(
+ &opt_state.trust_server_cert_unknown_ca,
+ &opt_state.trust_server_cert_cn_mismatch,
+ &opt_state.trust_server_cert_expired,
+ &opt_state.trust_server_cert_not_yet_valid,
+ &opt_state.trust_server_cert_other_failure,
+ utf8_opt_arg, pool));
break;
case opt_no_diff_added:
opt_state.diff.no_diff_added = TRUE;
@@ -2105,8 +2225,8 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
opt_state.relocate = TRUE;
break;
case 'x':
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.extensions,
- opt_arg, pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.extensions,
+ opt_arg, pool));
break;
case opt_diff_cmd:
opt_state.diff.diff_cmd = apr_pstrdup(pool, opt_arg);
@@ -2123,22 +2243,19 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
case opt_old_cmd:
if (opt_state.used_change_arg)
{
- err = svn_error_create
- (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("Can't specify -c with --old"));
- return EXIT_ERROR(err);
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Can't specify -c with --old"));
}
- opt_state.old_target = apr_pstrdup(pool, opt_arg);
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ opt_state.old_target = apr_pstrdup(pool, utf8_opt_arg);
break;
case opt_new_cmd:
- opt_state.new_target = apr_pstrdup(pool, opt_arg);
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ opt_state.new_target = apr_pstrdup(pool, utf8_opt_arg);
break;
case opt_config_dir:
- {
- const char *path_utf8;
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&path_utf8, opt_arg, pool));
- opt_state.config_dir = svn_dirent_internal_style(path_utf8, pool);
- }
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ opt_state.config_dir = svn_dirent_internal_style(utf8_opt_arg, pool);
break;
case opt_config_options:
if (!opt_state.config_options)
@@ -2146,9 +2263,9 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
apr_array_make(pool, 1,
sizeof(svn_cmdline__config_argument_t*));
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool));
- SVN_INT_ERR(svn_cmdline__parse_config_option(opt_state.config_options,
- opt_arg, pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ SVN_ERR(svn_cmdline__parse_config_option(opt_state.config_options,
+ utf8_opt_arg, "svn: ", pool));
break;
case opt_autoprops:
opt_state.autoprops = TRUE;
@@ -2157,17 +2274,15 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
opt_state.no_autoprops = TRUE;
break;
case opt_native_eol:
- if ( !strcmp("LF", opt_arg) || !strcmp("CR", opt_arg) ||
- !strcmp("CRLF", opt_arg))
- opt_state.native_eol = apr_pstrdup(pool, opt_arg);
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ if ( !strcmp("LF", utf8_opt_arg) || !strcmp("CR", utf8_opt_arg) ||
+ !strcmp("CRLF", utf8_opt_arg))
+ opt_state.native_eol = utf8_opt_arg;
else
{
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
- err = svn_error_createf
- (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("Syntax error in native-eol argument '%s'"),
utf8_opt_arg);
- return EXIT_ERROR(err);
}
break;
case opt_no_unlock:
@@ -2180,15 +2295,13 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
opt_state.remove = TRUE;
break;
case opt_changelist:
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
- opt_state.changelist = utf8_opt_arg;
- if (opt_state.changelist[0] == '\0')
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ if (utf8_opt_arg[0] == '\0')
{
- err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("Changelist names must not be empty"));
- return EXIT_ERROR(err);
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Changelist names must not be empty"));
}
- svn_hash_sets(changelists, opt_state.changelist, (void *)1);
+ svn_hash_sets(changelists, utf8_opt_arg, (void *)1);
break;
case opt_keep_changelists:
opt_state.keep_changelists = TRUE;
@@ -2205,8 +2318,8 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
opt_state.no_revprops = TRUE;
break;
case opt_with_revprop:
- SVN_INT_ERR(svn_opt_parse_revprop(&opt_state.revprop_table,
- opt_arg, pool));
+ SVN_ERR(svn_opt_parse_revprop(&opt_state.revprop_table,
+ opt_arg, pool));
break;
case opt_parents:
opt_state.parents = TRUE;
@@ -2215,38 +2328,41 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
opt_state.use_merge_history = TRUE;
break;
case opt_accept:
- opt_state.accept_which = svn_cl__accept_from_word(opt_arg);
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ opt_state.accept_which = svn_cl__accept_from_word(utf8_opt_arg);
if (opt_state.accept_which == svn_cl__accept_invalid)
- return EXIT_ERROR
- (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("'%s' is not a valid --accept value"),
- opt_arg));
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("'%s' is not a valid --accept value"),
+ utf8_opt_arg);
break;
case opt_show_revs:
- opt_state.show_revs = svn_cl__show_revs_from_word(opt_arg);
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ opt_state.show_revs = svn_cl__show_revs_from_word(utf8_opt_arg);
if (opt_state.show_revs == svn_cl__show_revs_invalid)
- return EXIT_ERROR
- (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("'%s' is not a valid --show-revs value"),
- opt_arg));
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("'%s' is not a valid --show-revs value"),
+ utf8_opt_arg);
+ break;
+ case opt_mergeinfo_log:
+ opt_state.mergeinfo_log = TRUE;
break;
case opt_reintegrate:
opt_state.reintegrate = TRUE;
break;
case opt_strip:
{
- err = svn_cstring_atoi(&opt_state.strip, opt_arg);
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ err = svn_cstring_atoi(&opt_state.strip, utf8_opt_arg);
if (err)
{
- err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, err,
- _("Invalid strip count '%s'"), opt_arg);
- return EXIT_ERROR(err);
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, err,
+ _("Invalid strip count '%s'"),
+ utf8_opt_arg);
}
if (opt_state.strip < 0)
{
- err = svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
- _("Argument to --strip must be positive"));
- return EXIT_ERROR(err);
+ return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+ _("Argument to --strip must be positive"));
}
}
break;
@@ -2284,10 +2400,32 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
opt_state.diff.properties_only = TRUE;
break;
case opt_search:
- add_search_pattern_group(&opt_state, opt_arg, pool);
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ add_search_pattern_group(&opt_state, utf8_opt_arg, pool);
break;
case opt_search_and:
- add_search_pattern_to_latest_group(&opt_state, opt_arg, pool);
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ add_search_pattern_to_latest_group(&opt_state, utf8_opt_arg, pool);
+ case opt_remove_unversioned:
+ opt_state.remove_unversioned = TRUE;
+ break;
+ case opt_remove_ignored:
+ opt_state.remove_ignored = TRUE;
+ break;
+ case opt_no_newline:
+ case opt_strict: /* ### DEPRECATED */
+ opt_state.no_newline = TRUE;
+ break;
+ case opt_show_passwords:
+ opt_state.show_passwords = TRUE;
+ break;
+ case opt_pin_externals:
+ opt_state.pin_externals = TRUE;
+ break;
+ case opt_show_item:
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ opt_state.show_item = utf8_opt_arg;
+ break;
default:
/* Hmmm. Perhaps this would be a good place to squirrel away
opts that commands like svn diff might need. Hmmm indeed. */
@@ -2299,10 +2437,9 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
* 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);
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--non-interactive and --force-interactive "
+ "are mutually exclusive"));
}
else
opt_state.non_interactive = !svn_cmdline__be_interactive(
@@ -2310,7 +2447,7 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
force_interactive);
/* Turn our hash of changelists into an array of unique ones. */
- SVN_INT_ERR(svn_hash_keys(&(opt_state.changelists), changelists, pool));
+ SVN_ERR(svn_hash_keys(&(opt_state.changelists), changelists, pool));
/* ### This really belongs in libsvn_client. The trouble is,
there's no one place there to run it from, no
@@ -2322,7 +2459,7 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
hand, the alternative is effectively to demand that they call
svn_config_ensure() instead, so maybe we should have a generic
init function anyway. Thoughts? */
- SVN_INT_ERR(svn_config_ensure(opt_state.config_dir, pool));
+ SVN_ERR(svn_config_ensure(opt_state.config_dir, pool));
/* 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
@@ -2356,7 +2493,8 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
(svn_cmdline_fprintf(stderr, pool,
_("Subcommand argument required\n")));
svn_error_clear(svn_cl__help(NULL, NULL, pool));
- return EXIT_FAILURE;
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
}
else
@@ -2367,8 +2505,8 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
if (subcommand == NULL)
{
const char *first_arg_utf8;
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&first_arg_utf8,
- first_arg, pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&first_arg_utf8,
+ first_arg, pool));
svn_error_clear
(svn_cmdline_fprintf(stderr, pool,
_("Unknown subcommand: '%s'\n"),
@@ -2385,7 +2523,8 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
"command.\n")));
}
- return EXIT_FAILURE;
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
}
}
@@ -2418,7 +2557,8 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
(stderr, pool, _("Subcommand '%s' doesn't accept option '%s'\n"
"Type 'svn help %s' for usage.\n"),
subcommand->name, optstr, subcommand->name));
- return EXIT_FAILURE;
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
}
@@ -2428,11 +2568,10 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
{
if (opt_state.revision_ranges->nelts > 1)
{
- err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("Multiple revision arguments "
- "encountered; can't specify -c twice, "
- "or both -c and -r"));
- return EXIT_ERROR(err);
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Multiple revision arguments "
+ "encountered; can't specify -c twice, "
+ "or both -c and -r"));
}
}
@@ -2440,32 +2579,47 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
if ((opt_state.depth != svn_depth_unknown)
&& (opt_state.set_depth != svn_depth_unknown))
{
- err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("--depth and --set-depth are mutually "
- "exclusive"));
- return EXIT_ERROR(err);
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--depth and --set-depth are mutually "
+ "exclusive"));
}
/* Disallow simultaneous use of both --with-all-revprops and
--with-no-revprops. */
if (opt_state.all_revprops && opt_state.no_revprops)
{
- err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("--with-all-revprops and --with-no-revprops "
- "are mutually exclusive"));
- return EXIT_ERROR(err);
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--with-all-revprops and --with-no-revprops "
+ "are mutually exclusive"));
}
/* Disallow simultaneous use of both --with-revprop and
--with-no-revprops. */
if (opt_state.revprop_table && opt_state.no_revprops)
{
- err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("--with-revprop and --with-no-revprops "
- "are mutually exclusive"));
- return EXIT_ERROR(err);
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--with-revprop and --with-no-revprops "
+ "are mutually exclusive"));
}
+#ifdef SVN_CL__OPTION_WITH_REVPROP_CAN_SET_PROPERTIES_IN_SVN_NAMESPACE
+ /* XXX This is incomplete, since we do not yet check for --force, nor
+ do all the commands that accept --with-revprop also accept --force. */
+
+ /* Check the spelling of the revision properties given by --with-revprop. */
+ if (opt_state.revprop_table)
+ {
+ apr_hash_index_t *hi;
+ for (hi = apr_hash_first(pool, opt_state.revprop_table);
+ hi; hi = apr_hash_next(hi))
+ {
+ SVN_ERR(svn_cl__check_svn_prop_name(apr_hash_this_key(hi),
+ TRUE, svn_cl__prop_use_use,
+ pool));
+ }
+ }
+#endif /* SVN_CL__OPTION_WITH_REVPROP_CAN_SET_PROPERTIES_IN_SVN_NAMESPACE */
+
/* Disallow simultaneous use of both -m and -F, when they are
both used to pass a commit message or lock comment. ('propset'
takes the property value, not a commit message, from -F.)
@@ -2473,29 +2627,31 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
if (opt_state.filedata && opt_state.message
&& subcommand->cmd_func != svn_cl__propset)
{
- err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("--message (-m) and --file (-F) "
- "are mutually exclusive"));
- return EXIT_ERROR(err);
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--message (-m) and --file (-F) "
+ "are mutually exclusive"));
}
- /* --trust-server-cert can only be used with --non-interactive */
- if (opt_state.trust_server_cert && !opt_state.non_interactive)
+ /* --trust-* options can only be used with --non-interactive */
+ if (!opt_state.non_interactive)
{
- err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("--trust-server-cert requires "
- "--non-interactive"));
- return EXIT_ERROR(err);
+ if (opt_state.trust_server_cert_unknown_ca
+ || opt_state.trust_server_cert_cn_mismatch
+ || opt_state.trust_server_cert_expired
+ || opt_state.trust_server_cert_not_yet_valid
+ || opt_state.trust_server_cert_other_failure)
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--trust-server-cert-failures requires "
+ "--non-interactive"));
}
/* Disallow simultaneous use of both --diff-cmd and
--internal-diff. */
if (opt_state.diff.diff_cmd && opt_state.diff.internal_diff)
{
- err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("--diff-cmd and --internal-diff "
- "are mutually exclusive"));
- return EXIT_ERROR(err);
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--diff-cmd and --internal-diff "
+ "are mutually exclusive"));
}
/* Ensure that 'revision_ranges' has at least one item, and make
@@ -2521,18 +2677,13 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
if (APR_STATUS_IS_EACCES(err->apr_err)
|| SVN__APR_STATUS_IS_ENOTDIR(err->apr_err))
{
- svn_config_t *empty_cfg;
-
svn_handle_warning2(stderr, err, "svn: ");
svn_error_clear(err);
- cfg_hash = apr_hash_make(pool);
- SVN_INT_ERR(svn_config_create2(&empty_cfg, FALSE, FALSE, pool));
- svn_hash_sets(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG, empty_cfg);
- SVN_INT_ERR(svn_config_create2(&empty_cfg, FALSE, FALSE, pool));
- svn_hash_sets(cfg_hash, SVN_CONFIG_CATEGORY_SERVERS, empty_cfg);
+
+ SVN_ERR(svn_config__get_default_config(&cfg_hash, pool));
}
else
- return EXIT_ERROR(err);
+ return err;
}
/* Relocation is infinite-depth only. */
@@ -2540,18 +2691,16 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
{
if (opt_state.depth != svn_depth_unknown)
{
- err = svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
- _("--relocate and --depth are mutually "
- "exclusive"));
- return EXIT_ERROR(err);
+ return svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
+ _("--relocate and --depth are mutually "
+ "exclusive"));
}
if (! descend)
{
- err = svn_error_create(
+ return svn_error_create(
SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
_("--relocate and --non-recursive (-N) are mutually "
"exclusive"));
- return EXIT_ERROR(err);
}
}
@@ -2565,8 +2714,7 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
{
if (opt_state.end_revision.kind != svn_opt_revision_unspecified)
{
- err = svn_error_create(SVN_ERR_CLIENT_REVISION_RANGE, NULL, NULL);
- return EXIT_ERROR(err);
+ return svn_error_create(SVN_ERR_CLIENT_REVISION_RANGE, NULL, NULL);
}
}
@@ -2593,8 +2741,6 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
}
}
- cfg_config = svn_hash_gets(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG);
-
/* Update the options in the config */
if (opt_state.config_options)
{
@@ -2604,6 +2750,7 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
"svn: ", "--config-option"));
}
+ cfg_config = svn_hash_gets(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG);
#if !defined(SVN_CL_NO_EXCLUSIVE_LOCK)
{
const char *exclusive_clients_option;
@@ -2633,7 +2780,7 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
/* Create a client context object. */
command_baton.opt_state = &opt_state;
- SVN_INT_ERR(svn_client_create_context2(&ctx, cfg_hash, pool));
+ SVN_ERR(svn_client_create_context2(&ctx, cfg_hash, pool));
command_baton.ctx = ctx;
/* If we're running a command that could result in a commit, verify
@@ -2669,19 +2816,18 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
{
if (subcommand->cmd_func != svn_cl__lock)
{
- err = svn_error_create(
+ return svn_error_create(
SVN_ERR_CL_LOG_MESSAGE_IS_VERSIONED_FILE, NULL,
_("Log message file is a versioned file; "
"use '--force-log' to override"));
}
else
{
- err = svn_error_create(
+ return svn_error_create(
SVN_ERR_CL_LOG_MESSAGE_IS_VERSIONED_FILE, NULL,
_("Lock comment file is a versioned file; "
"use '--force-log' to override"));
}
- return EXIT_ERROR(err);
}
}
svn_error_clear(err);
@@ -2689,27 +2835,26 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
/* If the -m argument is a file at all, that's probably not what
the user intended. */
- if (dash_m_arg)
+ if (opt_state.message)
{
apr_finfo_t finfo;
- if (apr_stat(&finfo, dash_m_arg,
+ if (apr_stat(&finfo, opt_state.message /* not converted to UTF-8 */,
APR_FINFO_MIN, pool) == APR_SUCCESS)
{
if (subcommand->cmd_func != svn_cl__lock)
{
- err = svn_error_create
+ return svn_error_create
(SVN_ERR_CL_LOG_MESSAGE_IS_PATHNAME, NULL,
_("The log message is a pathname "
"(was -F intended?); use '--force-log' to override"));
}
else
{
- err = svn_error_create
+ return svn_error_create
(SVN_ERR_CL_LOG_MESSAGE_IS_PATHNAME, NULL,
_("The lock comment is a pathname "
"(was -F intended?); use '--force-log' to override"));
}
- return EXIT_ERROR(err);
}
}
}
@@ -2729,10 +2874,9 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
/* Check for mutually exclusive args --auto-props and --no-auto-props */
if (opt_state.autoprops && opt_state.no_autoprops)
{
- err = svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
- _("--auto-props and --no-auto-props are "
- "mutually exclusive"));
- return EXIT_ERROR(err);
+ return svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
+ _("--auto-props and --no-auto-props are "
+ "mutually exclusive"));
}
/* Update auto-props-enable option, and populate the MIME types map,
@@ -2746,8 +2890,8 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
SVN_CONFIG_OPTION_MIMETYPES_FILE, FALSE);
if (mimetypes_file && *mimetypes_file)
{
- SVN_INT_ERR(svn_io_parse_mimetypes_file(&(ctx->mimetypes_map),
- mimetypes_file, pool));
+ SVN_ERR(svn_io_parse_mimetypes_file(&(ctx->mimetypes_map),
+ mimetypes_file, pool));
}
if (opt_state.autoprops)
@@ -2785,8 +2929,8 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
use_notifier = FALSE;
if (use_notifier)
{
- SVN_INT_ERR(svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2,
- conflict_stats, pool));
+ SVN_ERR(svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2,
+ conflict_stats, pool));
}
/* Set up our cancellation support. */
@@ -2816,35 +2960,41 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
#endif
/* Set up Authentication stuff. */
- SVN_INT_ERR(svn_cmdline_create_auth_baton(&ab,
- opt_state.non_interactive,
- opt_state.auth_username,
- opt_state.auth_password,
- opt_state.config_dir,
- opt_state.no_auth_cache,
- opt_state.trust_server_cert,
- cfg_config,
- ctx->cancel_func,
- ctx->cancel_baton,
- pool));
+ SVN_ERR(svn_cmdline_create_auth_baton2(
+ &ab,
+ opt_state.non_interactive,
+ opt_state.auth_username,
+ opt_state.auth_password,
+ opt_state.config_dir,
+ opt_state.no_auth_cache,
+ opt_state.trust_server_cert_unknown_ca,
+ opt_state.trust_server_cert_cn_mismatch,
+ opt_state.trust_server_cert_expired,
+ opt_state.trust_server_cert_not_yet_valid,
+ opt_state.trust_server_cert_other_failure,
+ cfg_config,
+ ctx->cancel_func,
+ ctx->cancel_baton,
+ pool));
ctx->auth_baton = ab;
if (opt_state.non_interactive)
{
if (opt_state.accept_which == svn_cl__accept_edit)
- return EXIT_ERROR(
- svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ {
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("--accept=%s incompatible with"
" --non-interactive"),
- SVN_CL__ACCEPT_EDIT));
-
+ SVN_CL__ACCEPT_EDIT);
+ }
if (opt_state.accept_which == svn_cl__accept_launch)
- return EXIT_ERROR(
- svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ {
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("--accept=%s incompatible with"
" --non-interactive"),
- SVN_CL__ACCEPT_LAUNCH));
+ SVN_CL__ACCEPT_LAUNCH);
+ }
/* The default action when we're non-interactive is to postpone
* conflict resolution. */
@@ -2855,10 +3005,10 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
/* Check whether interactive conflict resolution is disabled by
* the configuration file. If no --accept option was specified
* we postpone all conflicts in this case. */
- SVN_INT_ERR(svn_config_get_bool(cfg_config, &interactive_conflicts,
- SVN_CONFIG_SECTION_MISCELLANY,
- SVN_CONFIG_OPTION_INTERACTIVE_CONFLICTS,
- TRUE));
+ SVN_ERR(svn_config_get_bool(cfg_config, &interactive_conflicts,
+ SVN_CONFIG_SECTION_MISCELLANY,
+ SVN_CONFIG_OPTION_INTERACTIVE_CONFLICTS,
+ TRUE));
if (!interactive_conflicts)
{
/* Make 'svn resolve' non-interactive. */
@@ -2879,7 +3029,7 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
ctx->conflict_baton = NULL;
ctx->conflict_func2 = svn_cl__conflict_func_interactive;
- SVN_INT_ERR(svn_cl__get_conflict_func_interactive_baton(
+ SVN_ERR(svn_cl__get_conflict_func_interactive_baton(
&b,
opt_state.accept_which,
ctx->config, opt_state.editor_cmd, conflict_stats,
@@ -2896,10 +3046,9 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
if (err->apr_err == SVN_ERR_CL_INSUFFICIENT_ARGS
|| err->apr_err == SVN_ERR_CL_ARG_PARSING_ERROR)
{
- err = svn_error_quick_wrap(
- err, apr_psprintf(pool,
- _("Try 'svn help %s' for more information"),
- subcommand->name));
+ err = svn_error_quick_wrapf(
+ err, _("Try 'svn help %s' for more information"),
+ subcommand->name);
}
if (err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED)
{
@@ -2952,27 +3101,18 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
"Subversion"));
}
- /* Ensure that stdout is flushed, so the user will see any write errors.
- This makes sure that output is not silently lost. */
- err = svn_error_compose_create(err, svn_cmdline_fflush(stdout));
-
- return EXIT_ERROR(err);
+ return err;
}
- else
- {
- /* Ensure that stdout is flushed, so the user will see any write errors.
- This makes sure that output is not silently lost. */
- SVN_INT_ERR(svn_cmdline_fflush(stdout));
- return EXIT_SUCCESS;
- }
+ return SVN_NO_ERROR;
}
int
main(int argc, const char *argv[])
{
apr_pool_t *pool;
- int exit_code;
+ int exit_code = EXIT_SUCCESS;
+ svn_error_t *err;
/* Initialize the app. */
if (svn_cmdline_init("svn", stderr) != EXIT_SUCCESS)
@@ -2983,7 +3123,17 @@ main(int argc, const char *argv[])
*/
pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
- exit_code = sub_main(argc, argv, pool);
+ err = sub_main(&exit_code, argc, argv, pool);
+
+ /* Flush stdout and report if it fails. It would be flushed on exit anyway
+ but this makes sure that output is not silently lost if it fails. */
+ err = svn_error_compose_create(err, svn_cmdline_fflush(stdout));
+
+ if (err)
+ {
+ exit_code = EXIT_FAILURE;
+ svn_cmdline_handle_exit_error(err, NULL, "svn: ");
+ }
svn_pool_destroy(pool);
return exit_code;
diff --git a/subversion/svn/util.c b/subversion/svn/util.c
index 092bc7e3afcf..88ae27b14824 100644
--- a/subversion/svn/util.c
+++ b/subversion/svn/util.c
@@ -75,8 +75,15 @@ svn_cl__print_commit_info(const svn_commit_info_t *commit_info,
void *baton,
apr_pool_t *pool)
{
+ /* Be very careful with returning errors from this callback as those
+ will be returned as errors from editor->close_edit(...), which may
+ cause callers to assume that the commit itself failed.
+
+ See log message of r1659867 and the svn_ra_get_commit_editor3
+ documentation for details on error scenarios. */
+
if (SVN_IS_VALID_REVNUM(commit_info->revision))
- SVN_ERR(svn_cmdline_printf(pool, _("\nCommitted revision %ld%s.\n"),
+ SVN_ERR(svn_cmdline_printf(pool, _("Committed revision %ld%s.\n"),
commit_info->revision,
commit_info->revision == 42 &&
getenv("SVN_I_LOVE_PANGALACTIC_GARGLE_BLASTERS")
@@ -164,9 +171,9 @@ svn_cl__merge_file_externally(const char *base_path,
* is OK to continue with the merge.
* Any other exit code means there was a real problem. */
if (exitcode != 0 && exitcode != 1)
- return svn_error_createf
- (SVN_ERR_EXTERNAL_PROGRAM, NULL,
- _("The external merge tool exited with exit code %d"), exitcode);
+ return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL,
+ _("The external merge tool '%s' exited with exit code %d."),
+ merge_tool, exitcode);
else if (remains_in_conflict)
*remains_in_conflict = exitcode == 1;
}
@@ -197,7 +204,7 @@ svn_cl__make_log_msg_baton(void **baton,
apr_hash_t *config,
apr_pool_t *pool)
{
- struct log_msg_baton *lmb = apr_palloc(pool, sizeof(*lmb));
+ struct log_msg_baton *lmb = apr_pcalloc(pool, sizeof(*lmb));
if (opt_state->filedata)
{
@@ -230,8 +237,10 @@ svn_cl__make_log_msg_baton(void **baton,
SVN_CONFIG_OPTION_LOG_ENCODING,
NULL);
}
+ else
+ lmb->message_encoding = NULL;
- lmb->base_dir = base_dir ? base_dir : "";
+ lmb->base_dir = base_dir;
lmb->tmpfile_left = NULL;
lmb->config = config;
lmb->keep_locks = opt_state->no_unlock;
@@ -343,22 +352,17 @@ svn_cl__get_log_message(const char **log_msg,
*tmp_file = NULL;
if (lmb->message)
{
- svn_stringbuf_t *log_msg_buf = svn_stringbuf_create(lmb->message, pool);
- svn_string_t *log_msg_str = apr_pcalloc(pool, sizeof(*log_msg_str));
-
- /* Trim incoming messages of the EOF marker text and the junk
- that follows it. */
- truncate_buffer_at_prefix(&(log_msg_buf->len), log_msg_buf->data,
- EDITOR_EOF_PREFIX);
+ svn_string_t *log_msg_str = svn_string_create(lmb->message, pool);
- /* Make a string from a stringbuf, sharing the data allocation. */
- log_msg_str->data = log_msg_buf->data;
- log_msg_str->len = log_msg_buf->len;
- SVN_ERR_W(svn_subst_translate_string2(&log_msg_str, FALSE, FALSE,
+ SVN_ERR_W(svn_subst_translate_string2(&log_msg_str, NULL, NULL,
log_msg_str, lmb->message_encoding,
FALSE, pool, pool),
_("Error normalizing log message to internal format"));
+ /* Strip off the EOF marker text and the junk that follows it. */
+ truncate_buffer_at_prefix(&(log_msg_str->len), (char *)log_msg_str->data,
+ EDITOR_EOF_PREFIX);
+
*log_msg = log_msg_str->data;
return SVN_NO_ERROR;
}
@@ -388,14 +392,11 @@ svn_cl__get_log_message(const char **log_msg,
if (! path)
path = item->url;
- else if (! *path)
- path = ".";
-
- if (! svn_path_is_url(path) && lmb->base_dir)
+ else if (lmb->base_dir)
path = svn_dirent_is_child(lmb->base_dir, path, pool);
/* If still no path, then just use current directory. */
- if (! path)
+ if (! path || !*path)
path = ".";
if ((item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
@@ -434,7 +435,8 @@ svn_cl__get_log_message(const char **log_msg,
if (! lmb->non_interactive)
{
err = svn_cmdline__edit_string_externally(&msg_string, &lmb->tmpfile_left,
- lmb->editor_cmd, lmb->base_dir,
+ lmb->editor_cmd,
+ lmb->base_dir ? lmb->base_dir : "",
msg_string, "svn-commit",
lmb->config, TRUE,
lmb->message_encoding,
@@ -466,7 +468,7 @@ svn_cl__get_log_message(const char **log_msg,
if (msg_string)
message = svn_stringbuf_create_from_string(msg_string, pool);
- /* Strip the prefix from the buffer. */
+ /* Strip off the EOF marker text and the junk that follows it. */
if (message)
truncate_buffer_at_prefix(&message->len, message->data,
EDITOR_EOF_PREFIX);
@@ -565,8 +567,8 @@ svn_cl__error_checked_fputs(const char *string, FILE* stream)
if (fputs(string, stream) == EOF)
{
- if (errno)
- return svn_error_wrap_apr(errno, _("Write error"));
+ if (apr_get_os_error()) /* is errno on POSIX */
+ return svn_error_wrap_apr(apr_get_os_error(), _("Write error"));
else
return svn_error_create(SVN_ERR_IO_WRITE_ERROR, NULL, NULL);
}
@@ -631,7 +633,7 @@ svn_cl__xml_tagged_cdata(svn_stringbuf_t **sb,
if (string)
{
svn_xml_make_open_tag(sb, pool, svn_xml_protect_pcdata,
- tagname, NULL);
+ tagname, SVN_VA_NULL);
svn_xml_escape_cdata_cstring(sb, string, pool);
svn_xml_make_close_tag(sb, pool, tagname);
}
@@ -648,7 +650,7 @@ svn_cl__print_xml_commit(svn_stringbuf_t **sb,
/* "<commit ...>" */
svn_xml_make_open_tag(sb, pool, svn_xml_normal, "commit",
"revision",
- apr_psprintf(pool, "%ld", revision), NULL);
+ apr_psprintf(pool, "%ld", revision), SVN_VA_NULL);
/* "<author>xx</author>" */
if (author)
@@ -669,7 +671,7 @@ svn_cl__print_xml_lock(svn_stringbuf_t **sb,
apr_pool_t *pool)
{
/* "<lock>" */
- svn_xml_make_open_tag(sb, pool, svn_xml_normal, "lock", NULL);
+ svn_xml_make_open_tag(sb, pool, svn_xml_normal, "lock", SVN_VA_NULL);
/* "<token>xx</token>" */
svn_cl__xml_tagged_cdata(sb, pool, "token", lock->token);
@@ -704,7 +706,7 @@ svn_cl__xml_print_header(const char *tagname,
svn_xml_make_header2(&sb, "UTF-8", pool);
/* "<TAGNAME>" */
- svn_xml_make_open_tag(&sb, pool, svn_xml_normal, tagname, NULL);
+ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, tagname, SVN_VA_NULL);
return svn_cl__error_checked_fputs(sb->data, stdout);
}