subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stef...@apache.org
Subject svn commit: r1642242 [2/2] - /subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/
Date Thu, 27 Nov 2014 22:16:52 GMT
Added: subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c?rev=1642242&view=auto
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c
(added)
+++ subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c
Thu Nov 27 22:16:52 2014
@@ -0,0 +1,822 @@
+/*
+ * svn-mergeinfo-normalizer.c:  MI normalization tool main file.
+ *
+ * ====================================================================
+ *    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 <string.h>
+#include <assert.h>
+
+#include <apr_strings.h>
+#include <apr_tables.h>
+#include <apr_general.h>
+#include <apr_signal.h>
+
+#include "svn_cmdline.h"
+#include "svn_pools.h"
+#include "svn_wc.h"
+#include "svn_client.h"
+#include "svn_config.h"
+#include "svn_string.h"
+#include "svn_dirent_uri.h"
+#include "svn_path.h"
+#include "svn_delta.h"
+#include "svn_diff.h"
+#include "svn_error.h"
+#include "svn_io.h"
+#include "svn_opt.h"
+#include "svn_utf.h"
+#include "svn_auth.h"
+#include "svn_hash.h"
+#include "svn_version.h"
+#include "mergeinfo-normalizer.h"
+
+#include "private/svn_opt_private.h"
+#include "private/svn_cmdline_private.h"
+#include "private/svn_subr_private.h"
+
+#include "svn_private_config.h"
+
+
+/*** Option Processing ***/
+
+/* Add an identifier here for long options that don't have a short
+   option. Options that have both long and short options should just
+   use the short option letter as identifier.  */
+typedef enum svn_min__longopt_t {
+  opt_auth_password = SVN_OPT_FIRST_LONGOPT_ID,
+  opt_auth_username,
+  opt_config_dir,
+  opt_config_options,
+  opt_dry_run,
+  opt_no_auth_cache,
+  opt_targets,
+  opt_depth,
+  opt_version,
+  opt_non_interactive,
+  opt_force_interactive,
+  opt_trust_server_cert,
+  opt_trust_server_cert_unknown_ca,
+  opt_trust_server_cert_cn_mismatch,
+  opt_trust_server_cert_expired,
+  opt_trust_server_cert_not_yet_valid,
+  opt_trust_server_cert_other_failure,
+  opt_allow_mixed_revisions,
+} svn_cl__longopt_t;
+
+
+/* Option codes and descriptions for the command line client.
+ *
+ * The entire list must be terminated with an entry of nulls.
+ */
+const apr_getopt_option_t svn_min__options[] =
+{
+  {"help",          'h', 0, N_("show help on a subcommand")},
+  {NULL,            '?', 0, N_("show help on a subcommand")},
+  {"quiet",         'q', 0, N_("print nothing, or only summary information")},
+  {"version",       opt_version, 0, N_("show program version information")},
+  {"verbose",       'v', 0, N_("print extra information")},
+  {"username",      opt_auth_username, 1, N_("specify a username 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)")},
+  {"targets",       opt_targets, 1,
+                    N_("pass contents of file ARG as additional args")},
+  {"depth",         opt_depth, 1,
+                    N_("limit operation by depth ARG ('empty', 'files',\n"
+                       "                             "
+                       "'immediates', or 'infinity')")},
+  {"no-auth-cache", opt_no_auth_cache, 0,
+                    N_("do not cache authentication tokens")},
+  {"trust-server-cert", opt_trust_server_cert, 0,
+                    N_("deprecated; same as --trust-unknown-ca")},
+  {"trust-unknown-ca", opt_trust_server_cert_unknown_ca, 0,
+                    N_("with --non-interactive, accept SSL server\n"
+                       "                             "
+                       "certificates from unknown certificate authorities")},
+  {"trust-cn-mismatch", opt_trust_server_cert_cn_mismatch, 0,
+                    N_("with --non-interactive, accept SSL server\n"
+                       "                             "
+                       "certificates even if the server hostname does not\n"
+                       "                             "
+                       "match the certificate's common name attribute")},
+  {"trust-expired", opt_trust_server_cert_expired, 0,
+                    N_("with --non-interactive, accept expired SSL server\n"
+                       "                             "
+                       "certificates")},
+  {"trust-not-yet-valid", opt_trust_server_cert_not_yet_valid, 0,
+                    N_("with --non-interactive, accept SSL server\n"
+                       "                             "
+                       "certificates from the future")},
+  {"trust-other-failure", opt_trust_server_cert_other_failure, 0,
+                    N_("with --non-interactive, accept SSL server\n"
+                       "                             "
+                       "certificates with failures other than the above")},
+  {"non-interactive", opt_non_interactive, 0,
+                    N_("do no interactive prompting (default is to prompt\n"
+                       "                             "
+                       "only if standard input is a terminal device)")},
+  {"force-interactive", opt_force_interactive, 0,
+                    N_("do interactive prompting even if standard input\n"
+                       "                             "
+                       "is not a terminal device")},
+  {"dry-run",       opt_dry_run, 0,
+                    N_("try operation but make no changes")},
+  {"config-dir",    opt_config_dir, 1,
+                    N_("read user configuration files from directory ARG")},
+  {"config-option", opt_config_options, 1,
+                    N_("set user configuration option in the format:\n"
+                       "                             "
+                       "    FILE:SECTION:OPTION=[VALUE]\n"
+                       "                             "
+                       "For example:\n"
+                       "                             "
+                       "    servers:global:http-library=serf")},
+  {"use-merge-history", 'g', 0,
+                    N_("use/display additional information from merge\n"
+                       "                             "
+                       "history")},
+  {"allow-mixed-revisions", opt_allow_mixed_revisions, 0,
+                       N_("Allow operation on mixed-revision working copy.\n"
+                       "                             "
+                       "Use of this option is not recommended!\n"
+                       "                             "
+                       "Please run 'svn update' instead.")},
+
+  {0,               0, 0, 0},
+};
+
+
+
+/*** Command dispatch. ***/
+
+/* Our array of available subcommands.
+ *
+ * The entire list must be terminated with an entry of nulls.
+ *
+ * In most of the help text "PATH" is used where a working copy path is
+ * required, "URL" where a repository URL is required and "TARGET" when
+ * either a path or a url can be used.  Hmm, should this be part of the
+ * help text?
+ */
+
+/* Options that apply to all commands.  (While not every command may
+   currently require authentication or be interactive, allowing every
+   command to take these arguments allows scripts to just pass them
+   willy-nilly to every invocation of 'svn') . */
+const int svn_min__global_options[] =
+{ opt_auth_username, opt_auth_password, opt_no_auth_cache, opt_non_interactive,
+  opt_force_interactive, opt_trust_server_cert,
+  opt_trust_server_cert_unknown_ca, opt_trust_server_cert_cn_mismatch,
+  opt_trust_server_cert_expired, opt_trust_server_cert_not_yet_valid,
+  opt_trust_server_cert_other_failure,
+  opt_config_dir, opt_config_options, 0
+};
+
+/* Options for giving a log message.  (Some of these also have other uses.)
+ */
+#define SVN_CL__LOG_MSG_OPTIONS 'm', 'F', \
+                                opt_force_log, \
+                                opt_editor_cmd, \
+                                opt_encoding, \
+                                opt_with_revprop
+
+const svn_opt_subcommand_desc2_t svn_min__cmd_table[] =
+{
+  { "help", svn_min__help, {"?", "h"}, N_
+    ("Describe the usage of this program or its subcommands.\n"
+     "usage: help [SUBCOMMAND...]\n"),
+    {0} },
+
+  /* This command is also invoked if we see option "--help", "-h" or "-?". */
+
+  { "normalize", svn_min__normalize, { 0 }, N_
+    ("Normalize the mergeinfo throughout the working copy sub-tree.\n"
+     "usage: normalize [WCPATH...]\n"),
+    {opt_targets, opt_depth, opt_dry_run, 'q'} },
+
+  { "clear-obsoletes", svn_min__clear_obsolete, { 0 }, N_
+    ("Remove mergeinfo that refers to branches that no longer exist.\n"
+     "usage: clear-obsoletes [WCPATH...]\n"),
+    {opt_targets, opt_depth, opt_dry_run, 'q'} },
+
+  { "combine-ranges", svn_min__combine_ranges, { 0 }, N_
+    ("Combine revision ranges if all revisions in between are inoperative.\n"
+     "usage: remove-ranges [WCPATH...]\n"),
+    {opt_targets, opt_depth, opt_dry_run, 'q'} },
+
+  { "analyze", svn_min__analyze, { "analyse" }, N_
+    ("Generate a report of which part of the sub-tree mergeinfo\n"
+     "can be removed and which part can't.\n"
+     "usage: remove-ranges [WCPATH...]\n"),
+    {opt_targets, opt_depth, opt_dry_run} },
+
+  { NULL, NULL, {0}, NULL, {0} }
+};
+
+
+/* Version compatibility check */
+static svn_error_t *
+check_lib_versions(void)
+{
+  static const svn_version_checklist_t checklist[] =
+    {
+      { "svn_subr",   svn_subr_version },
+      { "svn_client", svn_client_version },
+      { "svn_wc",     svn_wc_version },
+      { "svn_ra",     svn_ra_version },
+      { "svn_delta",  svn_delta_version },
+      { "svn_diff",   svn_diff_version },
+      { NULL, NULL }
+    };
+  SVN_VERSION_DEFINE(my_version);
+
+  return svn_ver_check_list2(&my_version, checklist, svn_ver_equal);
+}
+
+
+/* A flag to see if we've been cancelled by the client or not. */
+static volatile sig_atomic_t cancelled = FALSE;
+
+/* A signal handler to support cancellation. */
+static void
+signal_handler(int signum)
+{
+  apr_signal(signum, SIG_IGN);
+  cancelled = TRUE;
+}
+
+/* Our cancellation callback. */
+svn_error_t *
+svn_min__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
+    return SVN_NO_ERROR;
+}
+
+
+/*** Main. ***/
+
+/*
+ * 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;
+  apr_getopt_t *os;
+  svn_min__opt_state_t opt_state = { 0 };
+  svn_client_ctx_t *ctx;
+  apr_array_header_t *received_opts;
+  int i;
+  const svn_opt_subcommand_desc2_t *subcommand = NULL;
+  svn_min__cmd_baton_t command_baton;
+  svn_auth_baton_t *ab;
+  svn_config_t *cfg_config;
+  svn_boolean_t interactive_conflicts = FALSE;
+  svn_boolean_t force_interactive = FALSE;
+  apr_hash_t *cfg_hash;
+
+  received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int));
+
+  /* Check library 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_ERR(svn_wc_set_adm_dir("_svn", pool));
+    }
+#endif
+
+  /* Initialize the RA library. */
+  SVN_ERR(svn_ra_initialize(pool));
+
+  /* Begin processing arguments. */
+  opt_state.depth = svn_depth_unknown;
+
+  /* No args?  Show usage. */
+  if (argc <= 1)
+    {
+      SVN_ERR(svn_min__help(NULL, NULL, pool));
+      *exit_code = EXIT_FAILURE;
+      return SVN_NO_ERROR;
+    }
+
+  /* Else, parse options. */
+  SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
+
+  os->interleave = 1;
+  while (1)
+    {
+      const char *opt_arg;
+      const char *utf8_opt_arg;
+
+      /* Parse the next option. */
+      apr_status_t apr_err = apr_getopt_long(os, svn_min__options, &opt_id,
+                                             &opt_arg);
+      if (APR_STATUS_IS_EOF(apr_err))
+        break;
+      else if (apr_err)
+        {
+          SVN_ERR(svn_min__help(NULL, NULL, pool));
+          *exit_code = EXIT_FAILURE;
+          return SVN_NO_ERROR;
+        }
+
+      /* Stash the option code in an array before parsing it. */
+      APR_ARRAY_PUSH(received_opts, int) = opt_id;
+
+      switch (opt_id) {
+      case 'h':
+      case '?':
+        opt_state.help = TRUE;
+        break;
+      case 'q':
+        opt_state.quiet = TRUE;
+        break;
+      case opt_targets:
+        {
+          svn_stringbuf_t *buffer, *buffer_utf8;
+
+          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);
+        }
+        break;
+      case opt_depth:
+        err = svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool);
+        if (err)
+          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 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_version:
+        opt_state.version = TRUE;
+        break;
+      case opt_dry_run:
+        opt_state.dry_run = TRUE;
+        break;
+      case opt_auth_username:
+        SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_username,
+                                        opt_arg, pool));
+        break;
+      case opt_auth_password:
+        SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_password,
+                                        opt_arg, pool));
+        break;
+      case opt_no_auth_cache:
+        opt_state.no_auth_cache = TRUE;
+        break;
+      case opt_non_interactive:
+        opt_state.non_interactive = TRUE;
+        break;
+      case opt_force_interactive:
+        force_interactive = TRUE;
+        break;
+      case opt_trust_server_cert: /* backwards compat to 1.8 */
+      case opt_trust_server_cert_unknown_ca:
+        opt_state.trust_server_cert_unknown_ca = TRUE;
+        break;
+      case opt_trust_server_cert_cn_mismatch:
+        opt_state.trust_server_cert_cn_mismatch = TRUE;
+        break;
+      case opt_trust_server_cert_expired:
+        opt_state.trust_server_cert_expired = TRUE;
+        break;
+      case opt_trust_server_cert_not_yet_valid:
+        opt_state.trust_server_cert_not_yet_valid = TRUE;
+        break;
+      case opt_trust_server_cert_other_failure:
+        opt_state.trust_server_cert_other_failure = TRUE;
+        break;
+      case opt_config_dir:
+        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)
+          opt_state.config_options =
+                   apr_array_make(pool, 1,
+                                  sizeof(svn_cmdline__config_argument_t*));
+
+        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, pool));
+        break;
+      case opt_allow_mixed_revisions:
+        opt_state.allow_mixed_rev = TRUE;
+        break;
+      default:
+        /* Hmmm. Perhaps this would be a good place to squirrel away
+           opts that commands like svn diff might need. Hmmm indeed. */
+        break;
+      }
+    }
+
+  /* The --non-interactive and --force-interactive options are mutually
+   * exclusive. */
+  if (opt_state.non_interactive && force_interactive)
+    {
+      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(
+                                  opt_state.non_interactive,
+                                  force_interactive);
+
+  /* ### This really belongs in libsvn_client.  The trouble is,
+     there's no one place there to run it from, no
+     svn_client_init().  We'd have to add it to all the public
+     functions that a client might call.  It's unmaintainable to do
+     initialization from within libsvn_client itself, but it seems
+     burdensome to demand that all clients call svn_client_init()
+     before calling any other libsvn_client function... On the other
+     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_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
+     just typos/mistakes.  Whatever the case, the subcommand to
+     actually run is svn_cl__help(). */
+  if (opt_state.help)
+    subcommand = svn_opt_get_canonical_subcommand2(svn_min__cmd_table, "help");
+
+  /* If we're not running the `help' subcommand, then look for a
+     subcommand in the first argument. */
+  if (subcommand == NULL)
+    {
+      if (os->ind >= os->argc)
+        {
+          if (opt_state.version)
+            {
+              /* Use the "help" subcommand to handle the "--version" option. */
+              static const svn_opt_subcommand_desc2_t pseudo_cmd =
+                { "--version", svn_min__help, {0}, "",
+                  {opt_version,    /* must accept its own option */
+                   'q',            /* brief output */
+                   'v',            /* verbose output */
+                   opt_config_dir  /* all commands accept this */
+                  } };
+
+              subcommand = &pseudo_cmd;
+            }
+          else
+            {
+              svn_error_clear
+                (svn_cmdline_fprintf(stderr, pool,
+                                     _("Subcommand argument required\n")));
+              svn_error_clear(svn_min__help(NULL, NULL, pool));
+              *exit_code = EXIT_FAILURE;
+              return SVN_NO_ERROR;
+            }
+        }
+      else
+        {
+          const char *first_arg = os->argv[os->ind++];
+          subcommand = svn_opt_get_canonical_subcommand2(svn_min__cmd_table,
+                                                         first_arg);
+          if (subcommand == NULL)
+            {
+              const char *first_arg_utf8;
+              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"),
+                                     first_arg_utf8));
+              svn_error_clear(svn_min__help(NULL, NULL, pool));
+
+              /* Be kind to people who try 'svn undo'. */
+              if (strcmp(first_arg_utf8, "undo") == 0)
+                {
+                  svn_error_clear
+                    (svn_cmdline_fprintf(stderr, pool,
+                                         _("Undo is done using either the "
+                                           "'svn revert' or the 'svn merge' "
+                                           "command.\n")));
+                }
+
+              *exit_code = EXIT_FAILURE;
+              return SVN_NO_ERROR;
+            }
+        }
+    }
+
+  /* Check that the subcommand wasn't passed any inappropriate options. */
+  for (i = 0; i < received_opts->nelts; i++)
+    {
+      opt_id = APR_ARRAY_IDX(received_opts, i, int);
+
+      /* All commands implicitly accept --help, so just skip over this
+         when we see it. Note that we don't want to include this option
+         in their "accepted options" list because it would be awfully
+         redundant to display it in every commands' help text. */
+      if (opt_id == 'h' || opt_id == '?')
+        continue;
+
+      if (! svn_opt_subcommand_takes_option3(subcommand, opt_id,
+                                             svn_min__global_options))
+        {
+          const char *optstr;
+          const apr_getopt_option_t *badopt =
+            svn_opt_get_option_from_code2(opt_id, svn_min__options,
+                                          subcommand, pool);
+          svn_opt_format_option(&optstr, badopt, FALSE, pool);
+          if (subcommand->name[0] == '-')
+            svn_error_clear(svn_min__help(NULL, NULL, pool));
+          else
+            svn_error_clear
+              (svn_cmdline_fprintf
+               (stderr, pool, _("Subcommand '%s' doesn't accept option '%s'\n"
+                                "Type 'svn-mergeinfo-normalizer help %s' for usage.\n"),
+                subcommand->name, optstr, subcommand->name));
+          *exit_code = EXIT_FAILURE;
+          return SVN_NO_ERROR;
+        }
+    }
+
+  /* --trust-* options can only be used with --non-interactive */
+  if (!opt_state.non_interactive)
+    {
+      if (opt_state.trust_server_cert_unknown_ca)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("--trust-unknown-ca requires "
+                                  "--non-interactive"));
+      if (opt_state.trust_server_cert_cn_mismatch)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("--trust-cn-mismatch requires "
+                                  "--non-interactive"));
+      if (opt_state.trust_server_cert_expired)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("--trust-expired requires "
+                                  "--non-interactive"));
+      if (opt_state.trust_server_cert_not_yet_valid)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("--trust-not-yet-valid requires "
+                                  "--non-interactive"));
+      if (opt_state.trust_server_cert_other_failure)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("--trust-other-failure requires "
+                                  "--non-interactive"));
+    }
+
+  err = svn_config_get_config(&cfg_hash, opt_state.config_dir, pool);
+  if (err)
+    {
+      /* Fallback to default config if the config directory isn't readable
+         or is not a directory. */
+      if (APR_STATUS_IS_EACCES(err->apr_err)
+          || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err))
+        {
+          svn_handle_warning2(stderr, err, "svn: ");
+          svn_error_clear(err);
+
+          SVN_ERR(svn_config__get_default_config(&cfg_hash, pool));
+        }
+      else
+        return err;
+    }
+
+  /* Update the options in the config */
+  if (opt_state.config_options)
+    {
+      svn_error_clear(
+          svn_cmdline__apply_config_options(cfg_hash,
+                                            opt_state.config_options,
+                                            "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;
+    apr_array_header_t *exclusive_clients;
+
+    svn_config_get(cfg_config, &exclusive_clients_option,
+                   SVN_CONFIG_SECTION_WORKING_COPY,
+                   SVN_CONFIG_OPTION_SQLITE_EXCLUSIVE_CLIENTS,
+                   NULL);
+    exclusive_clients = svn_cstring_split(exclusive_clients_option,
+                                          " ,", TRUE, pool);
+    for (i = 0; i < exclusive_clients->nelts; ++i)
+      {
+        const char *exclusive_client = APR_ARRAY_IDX(exclusive_clients, i,
+                                                     const char *);
+
+        /* This blocks other clients from accessing the wc.db so it must
+           be explicitly enabled.*/
+        if (!strcmp(exclusive_client, "svn"))
+          svn_config_set(cfg_config,
+                         SVN_CONFIG_SECTION_WORKING_COPY,
+                         SVN_CONFIG_OPTION_SQLITE_EXCLUSIVE,
+                         "true");
+      }
+  }
+#endif
+
+  /* Create a client context object. */
+  command_baton.opt_state = &opt_state;
+  SVN_ERR(svn_client_create_context2(&ctx, cfg_hash, pool));
+  command_baton.ctx = ctx;
+
+  /* Set up our cancellation support. */
+  ctx->cancel_func = svn_min__check_cancel;
+  apr_signal(SIGINT, signal_handler);
+#ifdef SIGBREAK
+  /* SIGBREAK is a Win32 specific signal generated by ctrl-break. */
+  apr_signal(SIGBREAK, signal_handler);
+#endif
+#ifdef SIGHUP
+  apr_signal(SIGHUP, signal_handler);
+#endif
+#ifdef SIGTERM
+  apr_signal(SIGTERM, signal_handler);
+#endif
+
+#ifdef SIGPIPE
+  /* Disable SIGPIPE generation for the platforms that have it. */
+  apr_signal(SIGPIPE, SIG_IGN);
+#endif
+
+#ifdef SIGXFSZ
+  /* Disable SIGXFSZ generation for the platforms that have it, otherwise
+   * working with large files when compiled against an APR that doesn't have
+   * large file support will crash the program, which is uncool. */
+  apr_signal(SIGXFSZ, SIG_IGN);
+#endif
+
+  /* Set up Authentication stuff. */
+  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;
+
+  /* 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_ERR(svn_config_get_bool(cfg_config, &interactive_conflicts,
+                              SVN_CONFIG_SECTION_MISCELLANY,
+                              SVN_CONFIG_OPTION_INTERACTIVE_CONFLICTS,
+                              TRUE));
+
+  SVN_ERR(svn_client_args_to_target_array2(&opt_state.targets,
+                                           os, opt_state.targets,
+                                           ctx, FALSE, pool));
+
+  /* Add "." if user passed 0 arguments. */
+  svn_opt_push_implicit_dot_target(opt_state.targets, pool);
+
+  /* And now we finally run the subcommand. */
+  err = (*subcommand->cmd_func)(os, &command_baton, pool);
+  if (err)
+    {
+      /* For argument-related problems, suggest using the 'help'
+         subcommand. */
+      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));
+        }
+
+        if (err->apr_err == SVN_ERR_AUTHN_FAILED && opt_state.non_interactive)
+        {
+          err = svn_error_quick_wrap(err,
+                                     _("Authentication failed and interactive"
+                                       " prompting is disabled; see the"
+                                       " --force-interactive option"));
+        }
+
+      /* Tell the user about 'svn cleanup' if any error on the stack
+         was about locked working copies. */
+      if (svn_error_find_cause(err, SVN_ERR_WC_LOCKED))
+        {
+          err = svn_error_quick_wrap(
+                  err, _("Run 'svn cleanup' to remove locks "
+                         "(type 'svn help cleanup' for details)"));
+        }
+
+      if (err->apr_err == SVN_ERR_SQLITE_BUSY)
+        {
+          err = svn_error_quick_wrap(err,
+                                     _("Another process is blocking the "
+                                       "working copy database, or the "
+                                       "underlying filesystem does not "
+                                       "support file locking; if the working "
+                                       "copy is on a network filesystem, make "
+                                       "sure file locking has been enabled "
+                                       "on the file server"));
+        }
+
+      if (svn_error_find_cause(err, SVN_ERR_RA_CANNOT_CREATE_TUNNEL) &&
+          (opt_state.auth_username || opt_state.auth_password))
+        {
+          err = svn_error_quick_wrap(
+                  err, _("When using svn+ssh:// URLs, keep in mind that the "
+                         "--username and --password options are ignored "
+                         "because authentication is performed by SSH, not "
+                         "Subversion"));
+        }
+
+      return err;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+int
+main(int argc, const char *argv[])
+{
+  apr_pool_t *pool;
+  int exit_code = EXIT_SUCCESS;
+  svn_error_t *err;
+
+  /* Initialize the app. */
+  if (svn_cmdline_init("svn", stderr) != EXIT_SUCCESS)
+    return EXIT_FAILURE;
+
+  /* Create our top-level pool.  Use a separate mutexless allocator,
+   * given this application is single threaded.
+   */
+  pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
+
+  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;
+}

Propchange: subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/util.c?rev=1642242&view=auto
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/util.c
(added)
+++ subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/util.c
Thu Nov 27 22:16:52 2014
@@ -0,0 +1,78 @@
+/*
+ * util.c: Subversion command line client utility functions. Any
+ * functions that need to be shared across subcommands should be put
+ * in here.
+ *
+ * ====================================================================
+ *    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_errno.h>
+
+#include "svn_error.h"
+#include "svn_path.h"
+
+#include "mergeinfo-normalizer.h"
+
+#include "svn_private_config.h"
+
+
+
+static svn_error_t *
+check_target_is_local_path(const char *target)
+{
+  if (svn_path_is_url(target))
+    return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                             _("'%s' is not a local path"), target);
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_min__add_wc_info(svn_min__cmd_baton_t *baton,
+                     int idx,
+                     apr_pool_t *result_pool,
+                     apr_pool_t *scratch_pool)
+{
+  svn_min__opt_state_t *opt_state = baton->opt_state;
+  const char *target = APR_ARRAY_IDX(opt_state->targets, idx, const char *);
+  const char *truepath;
+  svn_opt_revision_t peg_revision;
+
+  SVN_ERR(check_target_is_local_path(target));
+
+  SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target,
+                             scratch_pool));
+  SVN_ERR(svn_dirent_get_absolute(&baton->local_abspath, truepath,
+                                  result_pool));
+
+  SVN_ERR(svn_client_get_wc_root(&baton->wc_root, baton->local_abspath,
+                                 baton->ctx, result_pool, scratch_pool));
+  SVN_ERR(svn_client_get_repos_root(&baton->repo_root, NULL,
+                                    baton->local_abspath, baton->ctx,
+                                    result_pool, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+

Propchange: subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/util.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/wc_mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/wc_mergeinfo.c?rev=1642242&view=auto
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/wc_mergeinfo.c
(added)
+++ subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/wc_mergeinfo.c
Thu Nov 27 22:16:52 2014
@@ -0,0 +1,345 @@
+/*
+ * wc_mergeinfo.c -- Query and store the mergeinfo.
+ *
+ * ====================================================================
+ *    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 "svn_cmdline.h"
+#include "svn_pools.h"
+#include "svn_client.h"
+#include "svn_string.h"
+#include "svn_sorts.h"
+#include "svn_dirent_uri.h"
+#include "svn_props.h"
+
+#include "mergeinfo-normalizer.h"
+
+#include "private/svn_opt_private.h"
+#include "private/svn_sorts_private.h"
+#include "svn_private_config.h"
+
+
+
+typedef struct mergeinfo_t
+{
+  const char *local_path;
+  struct mergeinfo_t *parent;
+  svn_mergeinfo_t mergeinfo;
+} mergeinfo_t;
+
+static svn_error_t *
+parse_mergeinfo(apr_array_header_t **result_p,
+                apr_hash_t *props,
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
+{
+  apr_array_header_t *result = apr_array_make(result_pool,
+                                              apr_hash_count(props),
+                                              sizeof(mergeinfo_t *));
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  apr_hash_index_t *hi;
+
+  for (hi = apr_hash_first(scratch_pool, props); hi; hi = apr_hash_next(hi))
+    {
+      mergeinfo_t *entry = apr_pcalloc(result_pool, sizeof(*entry));
+      svn_mergeinfo_t mergeinfo;
+      svn_string_t *mi_string = apr_hash_this_val(hi);
+
+      svn_pool_clear(iterpool);
+      SVN_ERR(svn_mergeinfo_parse(&mergeinfo, mi_string->data, scratch_pool));
+
+      entry->local_path = apr_pstrdup(result_pool, apr_hash_this_key(hi));
+      entry->mergeinfo = svn_mergeinfo_dup(mergeinfo, result_pool);
+
+      APR_ARRAY_PUSH(result, mergeinfo_t *) = entry;
+    }
+
+  svn_pool_destroy(iterpool);
+  *result_p = result;
+
+  return SVN_NO_ERROR;
+}
+
+static int
+compare_mergeinfo(const void *lhs,
+                  const void *rhs)
+{
+  const mergeinfo_t *lhs_mi = *(const mergeinfo_t **)lhs;
+  const mergeinfo_t *rhs_mi = *(const mergeinfo_t **)rhs;
+
+  return strcmp(lhs_mi->local_path, rhs_mi->local_path);
+}
+
+static svn_error_t *
+get_url(void *baton,
+        const char *target,
+        const svn_client_info2_t *info,
+        apr_pool_t *pool)
+{
+  svn_stringbuf_t *url = baton;
+  svn_stringbuf_set(url, info->URL);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+link_parents(apr_array_header_t *mergeinfo,
+             svn_min__cmd_baton_t *baton,
+             apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  int i;
+
+  /* We further down assume that there are is least one entry. */
+  if (mergeinfo->nelts == 0)
+    return SVN_NO_ERROR;
+
+  /* sort mergeinfo by path */
+  svn_sort__array(mergeinfo, compare_mergeinfo);
+
+  /* link all mergeinfo to their parent merge info - if that exists */
+  for (i = 1; i < mergeinfo->nelts; ++i)
+    {
+      mergeinfo_t *entry = APR_ARRAY_IDX(mergeinfo, i, mergeinfo_t *);
+      entry->parent = APR_ARRAY_IDX(mergeinfo, i - 1, mergeinfo_t *);
+
+      while (   entry->parent
+             && !svn_dirent_is_ancestor(entry->parent->local_path,
+                                        entry->local_path))
+        entry->parent = entry->parent->parent;
+    }
+
+  /* break links for switched paths */
+  for (i = 1; i < mergeinfo->nelts; ++i)
+    {
+      mergeinfo_t *entry = APR_ARRAY_IDX(mergeinfo, i, mergeinfo_t *);
+      if (entry->parent)
+        {
+          const svn_opt_revision_t rev_working = { svn_opt_revision_working };
+          svn_stringbuf_t *entry_url, *parent_url;
+
+          svn_pool_clear(iterpool);
+          entry_url = svn_stringbuf_create_empty(iterpool);
+          parent_url = svn_stringbuf_create_empty(iterpool);
+
+          SVN_ERR(svn_client_info4(entry->local_path, &rev_working,
+                                   &rev_working, svn_depth_empty, FALSE,
+                                   TRUE, FALSE, NULL, get_url, entry_url,
+                                   baton->ctx, iterpool));
+          SVN_ERR(svn_client_info4(entry->parent->local_path, &rev_working,
+                                   &rev_working, svn_depth_empty, FALSE,
+                                   TRUE, FALSE, NULL, get_url, parent_url,
+                                   baton->ctx, iterpool));
+
+          if (!svn_uri__is_ancestor(parent_url->data, entry_url->data))
+            entry->parent = NULL;
+        }
+    }
+
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_min__read_mergeinfo(apr_array_header_t **result,
+                        svn_min__cmd_baton_t *baton,
+                        apr_pool_t *result_pool,
+                        apr_pool_t *scratch_pool)
+{
+  svn_min__opt_state_t *opt_state = baton->opt_state;
+  svn_client_ctx_t *ctx = baton->ctx;
+
+  apr_pool_t *props_pool = svn_pool_create(scratch_pool);
+  apr_hash_t *props;
+
+  const svn_opt_revision_t rev_working = { svn_opt_revision_working };
+
+  SVN_ERR(svn_client_propget5(&props, NULL, SVN_PROP_MERGEINFO,
+                              baton->local_abspath, &rev_working,
+                              &rev_working, NULL,
+                              opt_state->depth, NULL, ctx,
+                              props_pool, scratch_pool));
+  SVN_ERR(parse_mergeinfo(result, props, result_pool, scratch_pool));
+  SVN_ERR(link_parents(*result, baton, scratch_pool));
+
+  svn_pool_destroy(props_pool);
+
+  return SVN_NO_ERROR;
+}
+
+const char *
+svn_min__common_parent(apr_array_header_t *mergeinfo,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  const char *result = NULL;
+  int i;
+
+  for (i = 0; i < mergeinfo->nelts; ++i)
+    {
+      apr_hash_index_t *hi;
+      mergeinfo_t *entry = APR_ARRAY_IDX(mergeinfo, i, mergeinfo_t *);
+
+      svn_pool_clear(iterpool);
+      for (hi = apr_hash_first(scratch_pool, entry->mergeinfo);
+           hi;
+           hi = apr_hash_next(hi))
+        if (result == NULL)
+          {
+            result = apr_pstrdup(result_pool, apr_hash_this_key(hi));
+          }
+        else
+          {
+            const char * path = apr_hash_this_key(hi);
+            if (!svn_dirent_is_ancestor(result, path))
+              result = svn_dirent_get_longest_ancestor(result, path,
+                                                       result_pool);
+          }
+    }
+
+  svn_pool_destroy(iterpool);
+  return result;
+}
+
+svn_boolean_t
+svn_min__get_mergeinfo_pair(const char **parent_path,
+                            const char **subtree_relpath,
+                            svn_mergeinfo_t *parent_mergeinfo,
+                            svn_mergeinfo_t *subtree_mergeinfo,
+                            apr_array_header_t *mergeinfo,
+                            int idx)
+{
+  mergeinfo_t *entry;
+  if (idx < 0 || mergeinfo->nelts <= idx)
+    return FALSE;
+
+  entry = APR_ARRAY_IDX(mergeinfo, idx, mergeinfo_t *);
+  if (!entry->parent)
+    return FALSE;
+
+  *parent_path = entry->parent->local_path;
+  *subtree_relpath = svn_dirent_skip_ancestor(entry->parent->local_path,
+                                              entry->local_path);
+  *parent_mergeinfo = entry->parent->mergeinfo;
+  *subtree_mergeinfo = entry->mergeinfo;
+
+  return TRUE;
+}
+
+svn_mergeinfo_t
+svn_min__get_mergeinfo(apr_array_header_t *mergeinfo,
+                       int idx)
+{
+  return APR_ARRAY_IDX(mergeinfo, idx, mergeinfo_t *)->mergeinfo;
+}
+
+const char *
+svn_min__get_mergeinfo_path(apr_array_header_t *mergeinfo,
+                            int idx)
+{
+  return APR_ARRAY_IDX(mergeinfo, idx, mergeinfo_t *)->local_path;
+}
+
+svn_error_t *
+svn_min__write_mergeinfo(svn_min__cmd_baton_t *baton,
+                         apr_array_header_t *mergeinfo,
+                         apr_pool_t *scratch_pool)
+{
+  svn_client_ctx_t *ctx = baton->ctx;
+
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  int i;
+
+  for (i = 0; i < mergeinfo->nelts; ++i)
+    {
+      mergeinfo_t *entry = APR_ARRAY_IDX(mergeinfo, i, mergeinfo_t *);
+      svn_string_t *propval = NULL;
+      apr_array_header_t *targets;
+
+      svn_pool_clear(iterpool);
+
+      targets = apr_array_make(iterpool, 1, sizeof(const char *));
+      APR_ARRAY_PUSH(targets, const char *) = entry->local_path;
+
+      if (apr_hash_count(entry->mergeinfo))
+        SVN_ERR(svn_mergeinfo_to_string(&propval, entry->mergeinfo,
+                                        iterpool));
+
+      SVN_ERR(svn_client_propset_local(SVN_PROP_MERGEINFO, propval, targets,
+                                       svn_depth_empty, FALSE, NULL, ctx,
+                                       iterpool));
+    }
+
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_min__print_mergeinfo_stats(apr_array_header_t *wc_mergeinfo,
+                               apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+  int branch_count = 0;
+  int range_count = 0;
+
+  int i;
+  for (i = 0; i < wc_mergeinfo->nelts; ++i)
+    {
+      apr_hash_index_t *hi;
+      svn_mergeinfo_t mergeinfo = svn_min__get_mergeinfo(wc_mergeinfo, i);
+
+      svn_pool_clear(iterpool);
+
+      branch_count += apr_hash_count(mergeinfo);
+
+      for (hi = apr_hash_first(iterpool, mergeinfo);
+           hi;
+           hi = apr_hash_next(hi))
+        {
+          svn_rangelist_t *ranges = apr_hash_this_val(hi);
+          range_count += ranges->nelts;
+        }
+    }
+
+  SVN_ERR(svn_cmdline_printf(scratch_pool,
+                             _("    Found mergeinfo on %d nodes.\n"),
+                             wc_mergeinfo->nelts));
+  SVN_ERR(svn_cmdline_printf(scratch_pool,
+                             _("    Found %d branch entries.\n"),
+                             branch_count));
+  SVN_ERR(svn_cmdline_printf(scratch_pool,
+                             _("    Found %d merged revision ranges.\n\n"),
+                             range_count));
+
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+

Propchange: subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/wc_mergeinfo.c
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message