summaryrefslogtreecommitdiff
path: root/tools/client-side
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-08-05 16:22:51 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-08-05 16:22:51 +0000
commitcf46733632c7279a9fd0fe6ce26f9185a4ae82a9 (patch)
treeda27775a2161723ef342e91af41a8b51fedef405 /tools/client-side
parentbb0ef45f7c46b0ae221b26265ef98a768c33f820 (diff)
downloadsubversion-tarball-cf46733632c7279a9fd0fe6ce26f9185a4ae82a9.tar.gz
Diffstat (limited to 'tools/client-side')
-rw-r--r--tools/client-side/bash_completion49
-rwxr-xr-xtools/client-side/bash_completion_test8
-rwxr-xr-xtools/client-side/showchange.pl66
-rw-r--r--tools/client-side/svn-bench/cl.h198
-rw-r--r--tools/client-side/svn-bench/client_errors.h97
-rw-r--r--tools/client-side/svn-bench/help-cmd.c94
-rw-r--r--tools/client-side/svn-bench/notify.c1045
-rw-r--r--tools/client-side/svn-bench/null-export-cmd.c346
-rw-r--r--tools/client-side/svn-bench/null-list-cmd.c169
-rw-r--r--tools/client-side/svn-bench/null-log-cmd.c243
-rw-r--r--tools/client-side/svn-bench/svn-bench.c954
-rw-r--r--tools/client-side/svn-bench/util.c92
-rwxr-xr-xtools/client-side/svn-graph.pl17
-rwxr-xr-xtools/client-side/svn-ssl-fingerprints.sh2
-rwxr-xr-xtools/client-side/svn-vendor.py1065
15 files changed, 1107 insertions, 3338 deletions
diff --git a/tools/client-side/bash_completion b/tools/client-side/bash_completion
index eabc15c..8187fde 100644
--- a/tools/client-side/bash_completion
+++ b/tools/client-side/bash_completion
@@ -162,12 +162,12 @@ _svn()
cur=${COMP_WORDS[COMP_CWORD]}
# Possible expansions, without pure-prefix abbreviations such as "up".
- cmds='add blame annotate praise cat changelist cl checkout co cleanup'
+ cmds='add auth blame annotate praise cat changelist cl checkout co cleanup'
cmds="$cmds commit ci copy cp delete remove rm diff export help import"
cmds="$cmds info list ls lock log merge mergeinfo mkdir move mv rename"
cmds="$cmds patch propdel pdel propedit pedit propget pget proplist"
cmds="$cmds plist propset pset relocate resolve resolved revert status"
- cmds="$cmds switch unlock update upgrade"
+ cmds="$cmds switch unlock update upgrade"
# help options have a strange command status...
local helpOpts='--help -h'
@@ -781,7 +781,8 @@ _svn()
# otherwise build possible options for the command
pOpts="--username --password --no-auth-cache --non-interactive \
- --trust-server-cert --force-interactive"
+ --trust-server-cert-failures \
+ --force-interactive"
mOpts="-m --message -F --file --encoding --force-log --with-revprop"
rOpts="-r --revision"
qOpts="-q --quiet"
@@ -798,12 +799,15 @@ _svn()
cmdOpts="--auto-props --no-auto-props --force --targets \
--no-ignore --parents $nOpts $qOpts $pOpts"
;;
+ auth)
+ cmdOpts="--remove --show-passwords $pOpts"
+ ;;
blame|annotate|ann|praise)
cmdOpts="$rOpts $pOpts -v --verbose --incremental --xml \
-x --extensions --force $gOpts"
;;
cat)
- cmdOpts="$rOpts $pOpts"
+ cmdOpts="$rOpts $pOpts --ignore-keywords"
;;
changelist|cl)
cmdOpts="--targets $pOpts $qOpts $cOpts \
@@ -814,7 +818,8 @@ _svn()
--force"
;;
cleanup)
- cmdOpts="--diff3-cmd $pOpts"
+ cmdOpts="--diff3-cmd $pOpts --include-externals -q --quiet\
+ --remove-ignored --remove-unversioned"
;;
commit|ci)
cmdOpts="$mOpts $qOpts $nOpts --targets --editor-cmd $pOpts \
@@ -823,7 +828,7 @@ _svn()
;;
copy|cp)
cmdOpts="$mOpts $rOpts $qOpts --editor-cmd $pOpts --parents \
- --ignore-externals"
+ --ignore-externals --pin-externals"
;;
delete|del|remove|rm)
cmdOpts="--force $mOpts $qOpts --targets --editor-cmd $pOpts \
@@ -850,7 +855,8 @@ _svn()
;;
info)
cmdOpts="$pOpts $rOpts --targets -R --recursive --depth \
- --incremental --xml $cOpts"
+ --include-externals --incremental --xml \
+ --show-item --no-newline $cOpts"
;;
list|ls)
cmdOpts="$rOpts -v --verbose -R --recursive $pOpts \
@@ -870,11 +876,12 @@ _svn()
merge)
cmdOpts="$rOpts $nOpts $qOpts --force --dry-run --diff3-cmd \
$pOpts --ignore-ancestry -c --change -x --extensions \
- --record-only --accept --reintegrate \
+ --record-only --accept \
--allow-mixed-revisions -v --verbose"
;;
mergeinfo)
- cmdOpts="$rOpts $pOpts --depth --show-revs -R --recursive"
+ cmdOpts="$rOpts $pOpts --depth --show-revs -R --recursive \
+ $qOpts -v --verbose --incremental --log"
;;
mkdir)
cmdOpts="$mOpts $qOpts --editor-cmd $pOpts --parents"
@@ -898,7 +905,7 @@ _svn()
cmdOpts="$cmdOpts --revprop $rOpts"
;;
propget|pget|pg)
- cmdOpts="-v --verbose -R --recursive $rOpts --strict \
+ cmdOpts="-v --verbose -R --recursive $rOpts --no-newline \
$pOpts $cOpts --depth --xml --show-inherited-props"
[[ $isRevProp || ! $prop ]] && cmdOpts="$cmdOpts --revprop"
;;
@@ -930,7 +937,7 @@ _svn()
status|stat|st)
cmdOpts="-u --show-updates -v --verbose $nOpts $qOpts $pOpts \
--no-ignore --ignore-externals --incremental --xml \
- $cOpts"
+ $rOpts $cOpts"
;;
switch|sw)
cmdOpts="--relocate $rOpts $nOpts $qOpts $pOpts --diff3-cmd \
@@ -1030,7 +1037,8 @@ _svnadmin ()
cur=${COMP_WORDS[COMP_CWORD]}
# Possible expansions, without pure-prefix abbreviations such as "h".
- cmds='crashtest create deltify dump freeze help hotcopy list-dblogs \
+ cmds='crashtest create delrevprop deltify dump freeze help hotcopy \
+ info list-dblogs \
list-unused-dblogs load lock lslocks lstxns pack recover rmlocks \
rmtxns setlog setrevprop setuuid unlock upgrade verify --version'
@@ -1093,8 +1101,9 @@ _svnadmin ()
setlog)
cmdOpts="-r --revision --bypass-hooks"
;;
- setrevprop)
- cmdOpts="-r --revision --use-pre-revprop-change-hook \
+ setrevprop|delrevprop)
+ cmdOpts="-r --revision -t --transaction \
+ --use-pre-revprop-change-hook \
--use-post-revprop-change-hook"
;;
verify)
@@ -1126,6 +1135,8 @@ _svnadmin ()
--help) cmdOpts=${cmdOpts/ -h / } ;;
-r) cmdOpts=${cmdOpts/ --revision / } ;;
--revision) cmdOpts=${cmdOpts/ -r / } ;;
+ -t) cmdOpts=${cmdOpts/ --transaction / } ;;
+ --transaction) cmdOpts=${cmdOpts/ -t / } ;;
-F) cmdOpts=${cmdOpts/ --file / } ;;
--file) cmdOpts=${cmdOpts/ -F / } ;;
-M) cmdOpts=${cmdOpts/ --memory-cache-size / } ;;
@@ -1226,8 +1237,8 @@ _svnlook ()
cur=${COMP_WORDS[COMP_CWORD]}
# Possible expansions, without pure-prefix abbreviations such as "h".
- cmds='author cat changed date diff dirs-changed help history info \
- lock log propget proplist tree uuid youngest --version'
+ cmds='author cat changed date diff dirs-changed filesize help history \
+ info lock log propget proplist tree uuid youngest --version'
if [[ $COMP_CWORD -eq 1 ]] ; then
COMPREPLY=( $( compgen -W "$cmds" -- $cur ) )
@@ -1268,6 +1279,9 @@ _svnlook ()
dirs-changed)
cmdOpts="-r --revision -t --transaction"
;;
+ filesize)
+ cmdOpts="-r --revision -t --transaction"
+ ;;
help|h|\?)
cmdOpts="$cmds"
;;
@@ -1380,7 +1394,8 @@ _svnsync ()
copy-revprops|initialize|init|synchronize|sync)
cmdOpts="--non-interactive --no-auth-cache --trust-server-cert \
--source-username --source-password --sync-username \
- --sync-password --config-dir --config-option -q --quiet"
+ --sync-password --config-dir --config-option \
+ -q --quiet -M --memory-cache-size"
;;
help|h|\?)
cmdOpts="$cmds"
diff --git a/tools/client-side/bash_completion_test b/tools/client-side/bash_completion_test
index 49e3532..d2c1785 100755
--- a/tools/client-side/bash_completion_test
+++ b/tools/client-side/bash_completion_test
@@ -114,14 +114,18 @@ get_svn_subcommands() {
# Usage: get_svn_options SUBCMD
get_svn_options() {
{ svn help "$1" |
+ # Remove deprecated options
+ grep -v deprecated |
# Find the relevant lines; remove "arg" and description.
sed -n -e '1,/^Valid options:$/d;/^ -/!d' \
-e 's/\( ARG\)* * : .*//;p' |
# Remove brackets; put each word on its own line.
tr -d '] ' | tr '[' '\n'
# The following options are always accepted but not listed in the help
- echo "-h"
- echo "--help"
+ if [ "$1" != "help" ] ; then
+ echo "-h"
+ echo "--help"
+ fi
} | sort
}
diff --git a/tools/client-side/showchange.pl b/tools/client-side/showchange.pl
deleted file mode 100755
index e4cf7eb..0000000
--- a/tools/client-side/showchange.pl
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/usr/bin/perl -w
-# ====================================================================
-# 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.
-# ====================================================================
-
-use strict;
-
-# ====================================================================
-# Show the log message and diff for a revision.
-#
-# $ showchange.pl REVISION [WC_PATH|URL]
-
-
-if ((scalar(@ARGV) == 0)
- or ($ARGV[0] eq '-?')
- or ($ARGV[0] eq '-h')
- or ($ARGV[0] eq '--help')) {
- print <<EOF;
-Show the log message and diff for a revision.
-usage: $0 REVISION [WC_PATH|URL]
-EOF
- exit 0;
-}
-
-my $revision = shift || die ("Revision argument required.\n");
-if ($revision =~ /r([0-9]+)/) {
- $revision = $1;
-}
-
-my $url = shift || "";
-
-my $svn = "svn";
-
-my $prev_revision = $revision - 1;
-
-if (not $url) {
- # If no URL was provided, use the repository root from the current
- # directory's working copy. We want the root, rather than the URL
- # of the current dir, because when someone's asking for a change
- # by name (that is, by revision number), they generally don't want
- # to have to cd to a particular working copy directory to get it.
- my @info_lines = `${svn} info`;
- foreach my $info_line (@info_lines) {
- if ($info_line =~ s/^Repository Root: (.*)$/$1/e) {
- $url = $info_line;
- }
- }
-}
-
-system ("${svn} log -v --incremental -r${revision} $url");
-system ("${svn} diff -r${prev_revision}:${revision} $url");
diff --git a/tools/client-side/svn-bench/cl.h b/tools/client-side/svn-bench/cl.h
deleted file mode 100644
index 7a1e48d..0000000
--- a/tools/client-side/svn-bench/cl.h
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * cl.h: shared stuff in the command line program
- *
- * ====================================================================
- * 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_H
-#define SVN_CL_H
-
-/*** Includes. ***/
-
-#include <apr_tables.h>
-
-#include "svn_client.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
-/*** Command dispatch. ***/
-
-/* Hold results of option processing that are shared by multiple
- commands. */
-typedef struct svn_cl__opt_state_t
-{
- /* An array of svn_opt_revision_range_t *'s representing revisions
- ranges indicated on the command-line via the -r and -c options.
- For each range in the list, if only one revision was provided
- (-rN), its 'end' member remains 'svn_opt_revision_unspecified'.
- This array always has at least one element, even if that is a
- null range in which both ends are 'svn_opt_revision_unspecified'. */
- apr_array_header_t *revision_ranges;
-
- /* These are simply a copy of the range start and end values present
- in the first item of the revision_ranges list. */
- svn_opt_revision_t start_revision;
- svn_opt_revision_t end_revision;
-
- /* Flag which is only set if the '-c' option was used. */
- svn_boolean_t used_change_arg;
-
- /* Flag which is only set if the '-r' option was used. */
- svn_boolean_t used_revision_arg;
-
- /* Max number of log messages to get back from svn_client_log2. */
- int limit;
-
- /* After option processing is done, reflects the switch actually
- given on the command line, or svn_depth_unknown if none. */
- svn_depth_t depth;
-
- svn_boolean_t quiet; /* sssh...avoid unnecessary output */
- svn_boolean_t non_interactive; /* do no interactive prompting */
- svn_boolean_t version; /* print version information */
- svn_boolean_t verbose; /* be verbose */
- svn_boolean_t strict; /* do strictly what was requested */
- const char *encoding; /* the locale/encoding of the data*/
- 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! */
- svn_boolean_t no_auth_cache; /* do not cache authentication information */
- svn_boolean_t stop_on_copy; /* don't cross copies during processing */
- const char *config_dir; /* over-riding configuration directory */
- apr_array_header_t *config_options; /* over-riding configuration options */
- 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 */
- svn_boolean_t use_merge_history; /* use/display extra merge information */
- svn_boolean_t trust_server_cert; /* trust server SSL certs that would
- otherwise be rejected as "untrusted" */
-} svn_cl__opt_state_t;
-
-
-typedef struct svn_cl__cmd_baton_t
-{
- svn_cl__opt_state_t *opt_state;
- svn_client_ctx_t *ctx;
-} svn_cl__cmd_baton_t;
-
-
-/* Declare all the command procedures */
-svn_opt_subcommand_t
- svn_cl__help,
- svn_cl__null_export,
- svn_cl__null_list,
- svn_cl__null_log;
-
-
-/* See definition in main.c for documentation. */
-extern const svn_opt_subcommand_desc2_t svn_cl__cmd_table[];
-
-/* See definition in main.c for documentation. */
-extern const int svn_cl__global_options[];
-
-/* See definition in main.c for documentation. */
-extern const apr_getopt_option_t svn_cl__options[];
-
-
-/* A helper for the many subcommands that wish to merely warn when
- * invoked on an unversioned, nonexistent, or otherwise innocuously
- * errorful resource. Meant to be wrapped with SVN_ERR().
- *
- * If ERR is null, return SVN_NO_ERROR.
- *
- * Else if ERR->apr_err is one of the error codes supplied in varargs,
- * then handle ERR as a warning (unless QUIET is true), clear ERR, and
- * return SVN_NO_ERROR, and push the value of ERR->apr_err into the
- * ERRORS_SEEN array, if ERRORS_SEEN is not NULL.
- *
- * Else return ERR.
- *
- * 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.
- */
-svn_error_t *
-svn_cl__try(svn_error_t *err,
- apr_array_header_t *errors_seen,
- svn_boolean_t quiet,
- ...);
-
-
-/* Our cancellation callback. */
-svn_error_t *
-svn_cl__check_cancel(void *baton);
-
-
-
-/*** Notification functions to display results on the terminal. */
-
-/* Set *NOTIFY_FUNC_P and *NOTIFY_BATON_P to a notifier/baton for all
- * operations, allocated in POOL.
- */
-svn_error_t *
-svn_cl__get_notifier(svn_wc_notify_func2_t *notify_func_p,
- void **notify_baton_p,
- apr_pool_t *pool);
-
-/* Make the notifier for use with BATON print the appropriate summary
- * line at the end of the output.
- */
-svn_error_t *
-svn_cl__notifier_mark_export(void *baton);
-
-/* Like svn_client_args_to_target_array() but, if the only error is that some
- * arguments are reserved file names, then print warning messages for those
- * targets, store the rest of the targets in TARGETS_P and return success. */
-svn_error_t *
-svn_cl__args_to_target_array_print_reserved(apr_array_header_t **targets_p,
- apr_getopt_t *os,
- const apr_array_header_t *known_targets,
- svn_client_ctx_t *ctx,
- svn_boolean_t keep_dest_origpath_on_truepath_collision,
- apr_pool_t *pool);
-
-/* Return an error if TARGET is a URL; otherwise return SVN_NO_ERROR. */
-svn_error_t *
-svn_cl__check_target_is_local_path(const char *target);
-
-/* Return a copy of PATH, converted to the local path style, skipping
- * PARENT_PATH if it is non-null and is a parent of or equal to PATH.
- *
- * This function assumes PARENT_PATH and PATH are both absolute "dirents"
- * or both relative "dirents". */
-const char *
-svn_cl__local_style_skip_ancestor(const char *parent_path,
- const char *path,
- apr_pool_t *pool);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* SVN_CL_H */
diff --git a/tools/client-side/svn-bench/client_errors.h b/tools/client-side/svn-bench/client_errors.h
deleted file mode 100644
index 19f0bdf..0000000
--- a/tools/client-side/svn-bench/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/tools/client-side/svn-bench/help-cmd.c b/tools/client-side/svn-bench/help-cmd.c
deleted file mode 100644
index a3302ec..0000000
--- a/tools/client-side/svn-bench/help-cmd.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * help-cmd.c -- Provide help
- *
- * ====================================================================
- * 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_string.h"
-#include "svn_error.h"
-#include "svn_version.h"
-#include "cl.h"
-
-#include "svn_private_config.h"
-
-
-/*** Code. ***/
-
-/* This implements the `svn_opt_subcommand_t' interface. */
-svn_error_t *
-svn_cl__help(apr_getopt_t *os,
- void *baton,
- apr_pool_t *pool)
-{
- svn_cl__opt_state_t *opt_state;
-
- /* xgettext: the %s is for SVN_VER_NUMBER. */
- char help_header_template[] =
- N_("usage: svn-bench <subcommand> [options] [args]\n"
- "Subversion command-line client, version %s.\n"
- "Type 'svn-bench help <subcommand>' for help on a specific subcommand.\n"
- "Type 'svn-bench --version' to see the program version and RA modules\n"
- " or 'svn-bench --version --quiet' to see just the version number.\n"
- "\n"
- "Most subcommands take file and/or directory arguments, recursing\n"
- "on the directories. If no arguments are supplied to such a\n"
- "command, it recurses on the current directory (inclusive) by default.\n"
- "\n"
- "Available subcommands:\n");
-
- char help_footer[] =
- 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");
-
- svn_stringbuf_t *version_footer;
-
- if (baton)
- opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
- else
- opt_state = NULL;
-
- version_footer = svn_stringbuf_create(ra_desc_start, pool);
- SVN_ERR(svn_ra_print_modules(version_footer, pool));
-
- return svn_opt_print_help4(os,
- "svn-bench", /* ### erm, derive somehow? */
- opt_state ? opt_state->version : FALSE,
- opt_state ? opt_state->quiet : FALSE,
- opt_state ? opt_state->verbose : FALSE,
- version_footer->data,
- help_header, /* already gettext()'d */
- svn_cl__cmd_table,
- svn_cl__options,
- svn_cl__global_options,
- _(help_footer),
- pool);
-}
diff --git a/tools/client-side/svn-bench/notify.c b/tools/client-side/svn-bench/notify.c
deleted file mode 100644
index 5e19d8a..0000000
--- a/tools/client-side/svn-bench/notify.c
+++ /dev/null
@@ -1,1045 +0,0 @@
-/*
- * notify.c: feedback handlers for cmdline client.
- *
- * ====================================================================
- * 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. ***/
-
-#define APR_WANT_STDIO
-#define APR_WANT_STRFUNC
-#include <apr_want.h>
-
-#include "svn_cmdline.h"
-#include "svn_pools.h"
-#include "svn_dirent_uri.h"
-#include "svn_path.h"
-#include "svn_sorts.h"
-#include "cl.h"
-
-#include "svn_private_config.h"
-
-
-/* Baton for notify and friends. */
-struct notify_baton
-{
- svn_boolean_t received_some_change;
- svn_boolean_t is_checkout;
- svn_boolean_t is_export;
- svn_boolean_t is_wc_to_repos_copy;
- svn_boolean_t sent_first_txdelta;
- svn_boolean_t in_external;
- svn_boolean_t had_print_error; /* Used to not keep printing error messages
- when we've already had one print error. */
-
- /* Conflict stats for update and merge. */
- unsigned int text_conflicts;
- unsigned int prop_conflicts;
- unsigned int tree_conflicts;
- unsigned int skipped_paths;
- apr_hash_t *conflicted_paths;
-
- /* The cwd, for use in decomposing absolute paths. */
- const char *path_prefix;
-};
-
-
-/* Add a conflicted path to the list of conflicted paths stored
- * in the notify baton. */
-static void
-add_conflicted_path(struct notify_baton *nb, const char *path)
-{
- apr_hash_set(nb->conflicted_paths,
- apr_pstrdup(apr_hash_pool_get(nb->conflicted_paths), path),
- APR_HASH_KEY_STRING, "");
-}
-
-/* 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;
- char statchar_buf[5] = " ";
- const char *path_local;
- svn_error_t *err;
-
- if (n->url)
- path_local = n->url;
- else
- {
- 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 */
- path_local = svn_cl__local_style_skip_ancestor(nb->path_prefix, n->path,
- pool);
- }
-
- switch (n->action)
- {
- case svn_wc_notify_skip:
- nb->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;
- }
- 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;
- }
- else
- {
- if ((err = svn_cmdline_printf
- (pool, _("Skipped '%s'\n"), path_local)))
- goto print_error;
- }
- break;
- case svn_wc_notify_update_skip_obstruction:
- nb->skipped_paths++;
- if ((err = svn_cmdline_printf(
- pool, _("Skipped '%s' -- An obstructing working copy was found\n"),
- path_local)))
- goto print_error;
- break;
- case svn_wc_notify_update_skip_working_only:
- nb->skipped_paths++;
- if ((err = svn_cmdline_printf(
- pool, _("Skipped '%s' -- Has no versioned parent\n"),
- path_local)))
- goto print_error;
- break;
- case svn_wc_notify_update_skip_access_denied:
- nb->skipped_paths++;
- if ((err = svn_cmdline_printf(
- pool, _("Skipped '%s' -- Access denied\n"),
- path_local)))
- goto print_error;
- break;
- case svn_wc_notify_skip_conflicted:
- nb->skipped_paths++;
- if ((err = svn_cmdline_printf(
- pool, _("Skipped '%s' -- Node remains in conflict\n"),
- path_local)))
- goto print_error;
- 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;
- break;
- case svn_wc_notify_update_broken_lock:
- if ((err = svn_cmdline_printf(pool, "B %s\n", path_local)))
- goto print_error;
- 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;
- }
- else
- {
- if ((err = svn_cmdline_printf(pool, "Removed external '%s'\n",
- path_local)))
- goto print_error;
- }
- 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;
- 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;
- break;
-
- case svn_wc_notify_update_add:
- nb->received_some_change = TRUE;
- if (n->content_state == svn_wc_notify_state_conflicted)
- {
- nb->text_conflicts++;
- add_conflicted_path(nb, n->path);
- if ((err = svn_cmdline_printf(pool, "C %s\n", path_local)))
- goto print_error;
- }
- else
- {
- if ((err = svn_cmdline_printf(pool, "A %s\n", path_local)))
- goto print_error;
- }
- break;
-
- case svn_wc_notify_exists:
- nb->received_some_change = TRUE;
- if (n->content_state == svn_wc_notify_state_conflicted)
- {
- nb->text_conflicts++;
- add_conflicted_path(nb, n->path);
- statchar_buf[0] = 'C';
- }
- else
- statchar_buf[0] = 'E';
-
- if (n->prop_state == svn_wc_notify_state_conflicted)
- {
- nb->prop_conflicts++;
- add_conflicted_path(nb, n->path);
- statchar_buf[1] = 'C';
- }
- 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;
- break;
-
- case svn_wc_notify_restore:
- if ((err = svn_cmdline_printf(pool, _("Restored '%s'\n"),
- path_local)))
- goto print_error;
- break;
-
- case svn_wc_notify_revert:
- if ((err = svn_cmdline_printf(pool, _("Reverted '%s'\n"),
- path_local)))
- goto print_error;
- 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;
- break;
-
- case svn_wc_notify_resolved:
- if ((err = svn_cmdline_printf(pool,
- _("Resolved conflicted state of '%s'\n"),
- path_local)))
- goto print_error;
- break;
-
- case svn_wc_notify_add:
- /* We *should* only get the MIME_TYPE if PATH is a file. If we
- do get it, and the mime-type is not textual, note that this
- 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;
- }
- else
- {
- if ((err = svn_cmdline_printf(pool, "A %s\n",
- path_local)))
- goto print_error;
- }
- 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;
- break;
-
- case svn_wc_notify_patch:
- {
- nb->received_some_change = TRUE;
- if (n->content_state == svn_wc_notify_state_conflicted)
- {
- nb->text_conflicts++;
- add_conflicted_path(nb, n->path);
- statchar_buf[0] = 'C';
- }
- else if (n->kind == svn_node_file)
- {
- if (n->content_state == svn_wc_notify_state_merged)
- statchar_buf[0] = 'G';
- else if (n->content_state == svn_wc_notify_state_changed)
- statchar_buf[0] = 'U';
- }
-
- if (n->prop_state == svn_wc_notify_state_conflicted)
- {
- nb->prop_conflicts++;
- add_conflicted_path(nb, n->path);
- statchar_buf[1] = 'C';
- }
- else if (n->prop_state == svn_wc_notify_state_changed)
- statchar_buf[1] = 'U';
-
- if (statchar_buf[0] != ' ' || statchar_buf[1] != ' ')
- {
- if ((err = svn_cmdline_printf(pool, "%s %s\n",
- statchar_buf, path_local)))
- goto print_error;
- }
- }
- break;
-
- case svn_wc_notify_patch_applied_hunk:
- nb->received_some_change = TRUE;
- if (n->hunk_original_start != n->hunk_matched_line)
- {
- apr_uint64_t off;
- const char *s;
- const char *minus;
-
- if (n->hunk_matched_line > n->hunk_original_start)
- {
- off = n->hunk_matched_line - n->hunk_original_start;
- minus = "";
- }
- else
- {
- off = n->hunk_original_start - n->hunk_matched_line;
- minus = "-";
- }
-
- /* ### We're creating the localized strings without
- * ### APR_INT64_T_FMT since it isn't translator-friendly */
- if (n->hunk_fuzz)
- {
-
- if (n->prop_name)
- {
- 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);
- }
- 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);
- }
-
- if (err)
- goto print_error;
- }
- else
- {
-
- if (n->prop_name)
- {
- 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);
- }
- 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);
- }
-
- if (err)
- goto print_error;
- }
- }
- else if (n->hunk_fuzz)
- {
- if (n->prop_name)
- err = svn_cmdline_printf(pool,
- _("> applied hunk ## -%lu,%lu +%lu,%lu ## "
- "with fuzz %lu (%s)\n"),
- n->hunk_original_start,
- n->hunk_original_length,
- n->hunk_modified_start,
- n->hunk_modified_length,
- n->hunk_fuzz,
- n->prop_name);
- else
- 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;
-
- }
- break;
-
- case svn_wc_notify_patch_rejected_hunk:
- 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);
- 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;
- 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);
- 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;
- break;
-
- case svn_wc_notify_update_update:
- case svn_wc_notify_merge_record_info:
- {
- if (n->content_state == svn_wc_notify_state_conflicted)
- {
- nb->text_conflicts++;
- add_conflicted_path(nb, n->path);
- statchar_buf[0] = 'C';
- }
- else if (n->kind == svn_node_file)
- {
- if (n->content_state == svn_wc_notify_state_merged)
- statchar_buf[0] = 'G';
- else if (n->content_state == svn_wc_notify_state_changed)
- statchar_buf[0] = 'U';
- }
-
- if (n->prop_state == svn_wc_notify_state_conflicted)
- {
- nb->prop_conflicts++;
- add_conflicted_path(nb, n->path);
- statchar_buf[1] = 'C';
- }
- else if (n->prop_state == svn_wc_notify_state_merged)
- statchar_buf[1] = 'G';
- else if (n->prop_state == svn_wc_notify_state_changed)
- statchar_buf[1] = 'U';
-
- if (n->lock_state == svn_wc_notify_lock_state_unlocked)
- statchar_buf[2] = 'B';
-
- if (statchar_buf[0] != ' ' || statchar_buf[1] != ' ')
- nb->received_some_change = TRUE;
-
- 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;
- }
- }
- break;
-
- case svn_wc_notify_update_external:
- /* Remember that we're now "inside" an externals definition. */
- nb->in_external = TRUE;
-
- /* 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;
- break;
-
- case svn_wc_notify_failed_external:
- /* If we are currently inside the handling of an externals
- definition, then we can simply present n->err as a warning
- and feel confident that after this, we aren't handling that
- externals definition any longer. */
- 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;
- }
- /* Otherwise, we'll just print two warnings. Why? Because
- svn_handle_warning2() only shows the single "best message",
- but we have two pretty important ones: that the external at
- '/some/path' didn't pan out, and then the more specific
- reason why (from n->err). */
- else
- {
- svn_error_t *warn_err =
- svn_error_createf(SVN_ERR_BASE, NULL,
- _("Error handling externals definition for '%s':"),
- path_local);
- svn_handle_warning2(stderr, warn_err, "svn: ");
- svn_error_clear(warn_err);
- svn_handle_warning2(stderr, n->err, "svn: ");
- }
- break;
-
- case svn_wc_notify_update_started:
- if (! (nb->in_external ||
- nb->is_checkout ||
- nb->is_export))
- {
- if ((err = svn_cmdline_printf(pool, _("Updating '%s':\n"),
- path_local)))
- goto print_error;
- }
- break;
-
- case svn_wc_notify_update_completed:
- {
- if (SVN_IS_VALID_REVNUM(n->revision))
- {
- 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;
- }
- 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;
- }
- 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;
- }
- else
- {
- if ((err = svn_cmdline_printf
- (pool, nb->in_external
- ? _("External at revision %ld.\n")
- : _("At revision %ld.\n"),
- n->revision)))
- goto print_error;
- }
- }
- }
- else /* no revision */
- {
- if (nb->is_export)
- {
- if ((err = svn_cmdline_printf
- (pool, nb->in_external
- ? _("External export complete.\n")
- : _("Export complete.\n"))))
- goto print_error;
- }
- else if (nb->is_checkout)
- {
- if ((err = svn_cmdline_printf
- (pool, nb->in_external
- ? _("External checkout complete.\n")
- : _("Checkout complete.\n"))))
- goto print_error;
- }
- else
- {
- if ((err = svn_cmdline_printf
- (pool, nb->in_external
- ? _("External update complete.\n")
- : _("Update complete.\n"))))
- goto print_error;
- }
- }
- }
-
- if (nb->in_external)
- {
- nb->in_external = FALSE;
- if ((err = svn_cmdline_printf(pool, "\n")))
- goto print_error;
- }
- 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;
- 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;
- 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;
- 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;
- }
- 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;
- }
- 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;
- 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;
- 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;
- }
-
- if ((err = svn_cmdline_printf(pool, ".")))
- goto print_error;
- 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;
- break;
-
- case svn_wc_notify_unlocked:
- if ((err = svn_cmdline_printf(pool, _("'%s' unlocked.\n"),
- path_local)))
- goto print_error;
- break;
-
- case svn_wc_notify_failed_lock:
- case svn_wc_notify_failed_unlock:
- svn_handle_warning2(stderr, n->err, "svn: ");
- 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;
- 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;
- 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);
- 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);
- 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);
- 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);
- 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;
- 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);
- }
- else
- {
- if (n->merge_range->start == n->merge_range->end - 1
- || n->merge_range->start == n->merge_range->end)
- err = svn_cmdline_printf(
- pool,
- _("--- Recording mergeinfo for merge of 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,
- _("--- Recording mergeinfo for reverse merge of 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,
- _("--- Recording mergeinfo for merge of 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,
- _("--- 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);
- }
-
- 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;
- 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);
- 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);
- 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);
- 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);
- 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;
- break;
-
- case svn_wc_notify_tree_conflict:
- nb->tree_conflicts++;
- add_conflicted_path(nb, n->path);
- if ((err = svn_cmdline_printf(pool, " C %s\n", path_local)))
- goto print_error;
- 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;
- 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;
- 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;
- 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;
- 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;
- 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;
- break;
-
- case svn_wc_notify_revprop_set:
- err = svn_cmdline_printf(pool,
- _("property '%s' set on repository revision %ld\n"),
- n->prop_name, n->revision);
- if (err)
- goto print_error;
- break;
-
- case svn_wc_notify_revprop_deleted:
- err = svn_cmdline_printf(pool,
- _("property '%s' deleted from repository revision %ld\n"),
- n->prop_name, n->revision);
- if (err)
- goto print_error;
- break;
-
- case svn_wc_notify_upgraded_path:
- err = svn_cmdline_printf(pool, _("Upgraded '%s'\n"), path_local);
- if (err)
- goto print_error;
- break;
-
- case svn_wc_notify_url_redirect:
- err = svn_cmdline_printf(pool, _("Redirecting to URL '%s':\n"),
- n->url);
- if (err)
- goto print_error;
- break;
-
- case svn_wc_notify_path_nonexistent:
- err = svn_cmdline_printf(pool, _("'%s' is not under version control"),
- path_local);
- if (err)
- goto print_error;
- break;
-
- case svn_wc_notify_conflict_resolver_starting:
- /* Once all operations invoke the interactive conflict resolution after
- * they've completed, we can run svn_cl__print_conflict_stats() here. */
- break;
-
- case svn_wc_notify_conflict_resolver_done:
- break;
-
- default:
- break;
- }
-
- if ((err = svn_cmdline_fflush(stdout)))
- goto print_error;
-
- return;
-
- 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)
- {
- nb->had_print_error = TRUE;
- /* Issue #3014:
- * Don't print anything on broken pipes. The pipe was likely
- * closed by the process at the other end. We expect that
- * process to perform error reporting as necessary.
- *
- * ### This assumes that there is only one error in a chain for
- * ### SVN_ERR_IO_PIPE_WRITE_ERROR. See svn_cmdline_fputs(). */
- if (err->apr_err != SVN_ERR_IO_PIPE_WRITE_ERROR)
- svn_handle_error2(err, stderr, FALSE, "svn: ");
- }
- svn_error_clear(err);
-}
-
-
-svn_error_t *
-svn_cl__get_notifier(svn_wc_notify_func2_t *notify_func_p,
- void **notify_baton_p,
- apr_pool_t *pool)
-{
- struct notify_baton *nb = apr_pcalloc(pool, sizeof(*nb));
-
- nb->received_some_change = FALSE;
- nb->sent_first_txdelta = FALSE;
- nb->is_checkout = FALSE;
- nb->is_export = FALSE;
- nb->is_wc_to_repos_copy = FALSE;
- nb->in_external = FALSE;
- nb->had_print_error = FALSE;
- nb->text_conflicts = 0;
- nb->prop_conflicts = 0;
- nb->tree_conflicts = 0;
- nb->skipped_paths = 0;
- nb->conflicted_paths = apr_hash_make(pool);
- SVN_ERR(svn_dirent_get_absolute(&nb->path_prefix, "", pool));
-
- *notify_func_p = notify;
- *notify_baton_p = nb;
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_cl__notifier_mark_export(void *baton)
-{
- struct notify_baton *nb = baton;
-
- nb->is_export = TRUE;
- return SVN_NO_ERROR;
-}
diff --git a/tools/client-side/svn-bench/null-export-cmd.c b/tools/client-side/svn-bench/null-export-cmd.c
deleted file mode 100644
index 8220bfb..0000000
--- a/tools/client-side/svn-bench/null-export-cmd.c
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * export-cmd.c -- Subversion export command
- *
- * ====================================================================
- * 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_client.h"
-#include "svn_error.h"
-#include "svn_dirent_uri.h"
-#include "svn_path.h"
-#include "svn_cmdline.h"
-#include "cl.h"
-
-#include "svn_private_config.h"
-#include "private/svn_string_private.h"
-#include "private/svn_client_private.h"
-
-/*** The export editor code. ***/
-
-/* ---------------------------------------------------------------------- */
-
-/*** A dedicated 'export' editor, which does no .svn/ accounting. ***/
-
-typedef struct edit_baton_t
-{
- apr_int64_t file_count;
- apr_int64_t dir_count;
- apr_int64_t byte_count;
- apr_int64_t prop_count;
- apr_int64_t prop_byte_count;
-} edit_baton_t;
-
-static svn_error_t *
-set_target_revision(void *edit_baton,
- svn_revnum_t target_revision,
- apr_pool_t *pool)
-{
- return SVN_NO_ERROR;
-}
-
-
-/* Just ensure that the main export directory exists. */
-static svn_error_t *
-open_root(void *edit_baton,
- svn_revnum_t base_revision,
- apr_pool_t *pool,
- void **root_baton)
-{
- *root_baton = edit_baton;
- return SVN_NO_ERROR;
-}
-
-
-/* Ensure the directory exists, and send feedback. */
-static svn_error_t *
-add_directory(const char *path,
- void *parent_baton,
- const char *copyfrom_path,
- svn_revnum_t copyfrom_revision,
- apr_pool_t *pool,
- void **baton)
-{
- edit_baton_t *eb = parent_baton;
- eb->dir_count++;
-
- *baton = parent_baton;
- return SVN_NO_ERROR;
-}
-
-
-/* Build a file baton. */
-static svn_error_t *
-add_file(const char *path,
- void *parent_baton,
- const char *copyfrom_path,
- svn_revnum_t copyfrom_revision,
- apr_pool_t *pool,
- void **baton)
-{
- edit_baton_t *eb = parent_baton;
- eb->file_count++;
-
- *baton = parent_baton;
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-window_handler(svn_txdelta_window_t *window, void *baton)
-{
- edit_baton_t *eb = baton;
- if (window != NULL)
- eb->byte_count += window->tview_len;
-
- return SVN_NO_ERROR;
-}
-
-/* Write incoming data into the tmpfile stream */
-
-static svn_error_t *
-apply_textdelta(void *file_baton,
- const char *base_checksum,
- apr_pool_t *pool,
- svn_txdelta_window_handler_t *handler,
- void **handler_baton)
-{
- *handler_baton = file_baton;
- *handler = window_handler;
-
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-change_file_prop(void *file_baton,
- const char *name,
- const svn_string_t *value,
- apr_pool_t *pool)
-{
- edit_baton_t *eb = file_baton;
- eb->prop_count++;
- eb->prop_byte_count += value->len;
-
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-change_dir_prop(void *dir_baton,
- const char *name,
- const svn_string_t *value,
- apr_pool_t *pool)
-{
- edit_baton_t *eb = dir_baton;
- eb->prop_count++;
-
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-close_file(void *file_baton,
- const char *text_checksum,
- apr_pool_t *pool)
-{
- return SVN_NO_ERROR;
-}
-
-
-/*** Public Interfaces ***/
-
-static svn_error_t *
-bench_null_export(svn_revnum_t *result_rev,
- const char *from_path_or_url,
- svn_opt_revision_t *peg_revision,
- svn_opt_revision_t *revision,
- svn_depth_t depth,
- void *baton,
- svn_client_ctx_t *ctx,
- svn_boolean_t quiet,
- apr_pool_t *pool)
-{
- svn_revnum_t edit_revision = SVN_INVALID_REVNUM;
- svn_boolean_t from_is_url = svn_path_is_url(from_path_or_url);
-
- SVN_ERR_ASSERT(peg_revision != NULL);
- SVN_ERR_ASSERT(revision != NULL);
-
- if (peg_revision->kind == svn_opt_revision_unspecified)
- peg_revision->kind = svn_path_is_url(from_path_or_url)
- ? svn_opt_revision_head
- : svn_opt_revision_working;
-
- if (revision->kind == svn_opt_revision_unspecified)
- revision = peg_revision;
-
- if (from_is_url || ! SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind))
- {
- svn_client__pathrev_t *loc;
- svn_ra_session_t *ra_session;
- svn_node_kind_t kind;
-
- /* Get the RA connection. */
- SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
- from_path_or_url, NULL,
- peg_revision,
- revision, ctx, pool));
-
- SVN_ERR(svn_ra_check_path(ra_session, "", loc->rev, &kind, pool));
-
- if (kind == svn_node_file)
- {
- apr_hash_t *props;
-
- /* Since you cannot actually root an editor at a file, we
- * manually drive a few functions of our editor. */
-
- /* Step outside the editor-likeness for a moment, to actually talk
- * to the repository. */
- /* ### note: the stream will not be closed */
- SVN_ERR(svn_ra_get_file(ra_session, "", loc->rev,
- svn_stream_empty(pool),
- NULL, &props, pool));
- }
- else if (kind == svn_node_dir)
- {
- void *edit_baton = NULL;
- const svn_delta_editor_t *export_editor = NULL;
- const svn_ra_reporter3_t *reporter;
- void *report_baton;
-
- svn_delta_editor_t *editor = svn_delta_default_editor(pool);
-
- editor->set_target_revision = set_target_revision;
- editor->open_root = open_root;
- editor->add_directory = add_directory;
- editor->add_file = add_file;
- editor->apply_textdelta = apply_textdelta;
- editor->close_file = close_file;
- editor->change_file_prop = change_file_prop;
- editor->change_dir_prop = change_dir_prop;
-
- /* for ra_svn, we don't need an editior in quiet mode */
- if (!quiet || strncmp(loc->repos_root_url, "svn:", 4))
- SVN_ERR(svn_delta_get_cancellation_editor(ctx->cancel_func,
- ctx->cancel_baton,
- editor,
- baton,
- &export_editor,
- &edit_baton,
- pool));
-
- /* Manufacture a basic 'report' to the update reporter. */
- SVN_ERR(svn_ra_do_update3(ra_session,
- &reporter, &report_baton,
- loc->rev,
- "", /* no sub-target */
- depth,
- FALSE, /* don't want copyfrom-args */
- FALSE, /* don't want ignore_ancestry */
- export_editor, edit_baton,
- pool, pool));
-
- SVN_ERR(reporter->set_path(report_baton, "", loc->rev,
- /* Depth is irrelevant, as we're
- passing start_empty=TRUE anyway. */
- svn_depth_infinity,
- TRUE, /* "help, my dir is empty!" */
- NULL, pool));
-
- SVN_ERR(reporter->finish_report(report_baton, pool));
- }
- else if (kind == svn_node_none)
- {
- return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
- _("URL '%s' doesn't exist"),
- from_path_or_url);
- }
- /* kind == svn_node_unknown not handled */
- }
-
-
- if (result_rev)
- *result_rev = edit_revision;
-
- return SVN_NO_ERROR;
-}
-
-
-/*** Code. ***/
-
-/* This implements the `svn_opt_subcommand_t' interface. */
-svn_error_t *
-svn_cl__null_export(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;
- svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
- const char *from;
- apr_array_header_t *targets;
- svn_error_t *err;
- svn_opt_revision_t peg_revision;
- const char *truefrom;
- edit_baton_t eb = { 0 };
-
- SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
- opt_state->targets,
- ctx, FALSE, pool));
-
- /* We want exactly 1 or 2 targets for this subcommand. */
- if (targets->nelts < 1)
- return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);
- if (targets->nelts > 2)
- return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0, NULL);
-
- /* The first target is the `from' path. */
- from = APR_ARRAY_IDX(targets, 0, const char *);
-
- /* Get the peg revision if present. */
- SVN_ERR(svn_opt_parse_path(&peg_revision, &truefrom, from, pool));
-
- if (opt_state->depth == svn_depth_unknown)
- opt_state->depth = svn_depth_infinity;
-
- /* Do the export. */
- err = bench_null_export(NULL, truefrom, &peg_revision,
- &(opt_state->start_revision),
- opt_state->depth,
- &eb,
- ctx, opt_state->quiet, pool);
-
- if (!opt_state->quiet)
- SVN_ERR(svn_cmdline_printf(pool,
- _("%15s directories\n"
- "%15s files\n"
- "%15s bytes in files\n"
- "%15s properties\n"
- "%15s bytes in properties\n"),
- svn__ui64toa_sep(eb.dir_count, ',', pool),
- svn__ui64toa_sep(eb.file_count, ',', pool),
- svn__ui64toa_sep(eb.byte_count, ',', pool),
- svn__ui64toa_sep(eb.prop_count, ',', pool),
- svn__ui64toa_sep(eb.prop_byte_count, ',', pool)));
-
- return svn_error_trace(err);
-}
diff --git a/tools/client-side/svn-bench/null-list-cmd.c b/tools/client-side/svn-bench/null-list-cmd.c
deleted file mode 100644
index 8aa08cd..0000000
--- a/tools/client-side/svn-bench/null-list-cmd.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * list-cmd.c -- list a URL
- *
- * ====================================================================
- * 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.
- * ====================================================================
- */
-
-#include "svn_cmdline.h"
-#include "svn_client.h"
-#include "svn_error.h"
-#include "svn_pools.h"
-#include "svn_time.h"
-#include "svn_xml.h"
-#include "svn_dirent_uri.h"
-#include "svn_path.h"
-#include "svn_utf.h"
-#include "svn_opt.h"
-
-#include "cl.h"
-
-#include "svn_private_config.h"
-#include "private/svn_string_private.h"
-
-
-
-/* Baton used when printing directory entries. */
-struct print_baton {
- svn_boolean_t verbose;
- apr_int64_t directories;
- apr_int64_t files;
- apr_int64_t locks;
- svn_client_ctx_t *ctx;
-};
-
-/* This implements the svn_client_list_func2_t API, printing a single
- directory entry in text format. */
-static svn_error_t *
-print_dirent(void *baton,
- const char *path,
- const svn_dirent_t *dirent,
- const svn_lock_t *lock,
- const char *abs_path,
- const char *external_parent_url,
- const char *external_target,
- apr_pool_t *pool)
-{
- struct print_baton *pb = baton;
-
- if (pb->ctx->cancel_func)
- SVN_ERR(pb->ctx->cancel_func(pb->ctx->cancel_baton));
-
- if (dirent->kind == svn_node_dir)
- pb->directories++;
- if (dirent->kind == svn_node_file)
- pb->files++;
- if (lock)
- pb->locks++;
-
- return SVN_NO_ERROR;
-}
-
-
-/* This implements the `svn_opt_subcommand_t' interface. */
-svn_error_t *
-svn_cl__null_list(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;
- svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
- apr_array_header_t *targets;
- int i;
- apr_pool_t *subpool = svn_pool_create(pool);
- apr_uint32_t dirent_fields;
- struct print_baton pb = { FALSE };
- svn_boolean_t seen_nonexistent_target = FALSE;
- svn_error_t *err;
-
- SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
- opt_state->targets,
- ctx, FALSE, pool));
-
- /* Add "." if user passed 0 arguments */
- svn_opt_push_implicit_dot_target(targets, pool);
-
- if (opt_state->verbose)
- dirent_fields = SVN_DIRENT_ALL;
- else
- dirent_fields = SVN_DIRENT_KIND; /* the only thing we actually need... */
-
- pb.ctx = ctx;
- pb.verbose = opt_state->verbose;
-
- if (opt_state->depth == svn_depth_unknown)
- opt_state->depth = svn_depth_immediates;
-
- /* For each target, try to list it. */
- for (i = 0; i < targets->nelts; i++)
- {
- const char *target = APR_ARRAY_IDX(targets, i, const char *);
- const char *truepath;
- svn_opt_revision_t peg_revision;
-
- svn_pool_clear(subpool);
-
- SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
-
- /* Get peg revisions. */
- SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target,
- subpool));
-
- err = svn_client_list3(truepath, &peg_revision,
- &(opt_state->start_revision),
- opt_state->depth,
- dirent_fields,
- opt_state->verbose,
- FALSE, /* include externals */
- print_dirent,
- &pb, ctx, subpool);
-
- if (err)
- {
- /* If one of the targets is a non-existent URL or wc-entry,
- don't bail out. Just warn and move on to the next target. */
- if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND ||
- err->apr_err == SVN_ERR_FS_NOT_FOUND)
- svn_handle_warning2(stderr, err, "svn-bench: ");
- else
- return svn_error_trace(err);
-
- svn_error_clear(err);
- err = NULL;
- seen_nonexistent_target = TRUE;
- }
- else if (!opt_state->quiet)
- SVN_ERR(svn_cmdline_printf(pool,
- _("%15s directories\n"
- "%15s files\n"
- "%15s locks\n"),
- svn__ui64toa_sep(pb.directories, ',', pool),
- svn__ui64toa_sep(pb.files, ',', pool),
- svn__ui64toa_sep(pb.locks, ',', pool)));
- }
-
- svn_pool_destroy(subpool);
-
- if (seen_nonexistent_target)
- return svn_error_create(
- SVN_ERR_ILLEGAL_TARGET, NULL,
- _("Could not list all targets because some targets don't exist"));
- else
- return SVN_NO_ERROR;
-}
diff --git a/tools/client-side/svn-bench/null-log-cmd.c b/tools/client-side/svn-bench/null-log-cmd.c
deleted file mode 100644
index b35c8f2..0000000
--- a/tools/client-side/svn-bench/null-log-cmd.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * log-cmd.c -- Display log messages
- *
- * ====================================================================
- * 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.
- * ====================================================================
- */
-
-#define APR_WANT_STRFUNC
-#define APR_WANT_STDIO
-#include <apr_want.h>
-
-#include "svn_cmdline.h"
-#include "svn_compat.h"
-#include "svn_path.h"
-#include "svn_props.h"
-
-#include "cl.h"
-
-#include "svn_private_config.h"
-#include "private/svn_string_private.h"
-
-
-/*** Code. ***/
-
-/* Baton for log_entry_receiver() and log_entry_receiver_xml(). */
-struct log_receiver_baton
-{
- /* Client context. */
- svn_client_ctx_t *ctx;
-
- /* Level of merge revision nesting */
- apr_size_t merge_depth;
-
- /* collect counters? */
- svn_boolean_t quiet;
-
- /* total revision counters */
- apr_int64_t revisions;
- apr_int64_t changes;
- apr_int64_t message_lines;
-
- /* part that came from merges */
- apr_int64_t merges;
- apr_int64_t merged_revs;
- apr_int64_t merged_changes;
- apr_int64_t merged_message_lines;
-};
-
-
-/* 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'.
- */
-static svn_error_t *
-log_entry_receiver(void *baton,
- svn_log_entry_t *log_entry,
- apr_pool_t *pool)
-{
- struct log_receiver_baton *lb = baton;
- const char *author;
- const char *date;
- const char *message;
-
- if (lb->ctx->cancel_func)
- SVN_ERR(lb->ctx->cancel_func(lb->ctx->cancel_baton));
-
- if (! SVN_IS_VALID_REVNUM(log_entry->revision))
- {
- lb->merge_depth--;
- return SVN_NO_ERROR;
- }
-
- /* if we don't want counters, we are done */
- if (lb->quiet)
- return SVN_NO_ERROR;
-
- /* extract the message and do all the other counting */
- svn_compat_log_revprops_out(&author, &date, &message, log_entry->revprops);
- if (log_entry->revision == 0 && message == NULL)
- return SVN_NO_ERROR;
-
- lb->revisions++;
- if (lb->merge_depth)
- lb->merged_revs++;
-
- if (message != NULL)
- {
- int count = svn_cstring_count_newlines(message) + 1;
- lb->message_lines += count;
- if (lb->merge_depth)
- lb->merged_message_lines += count;
- }
-
- if (log_entry->changed_paths2)
- {
- unsigned count = apr_hash_count(log_entry->changed_paths2);
- lb->changes += count;
- if (lb->merge_depth)
- lb->merged_changes += count;
- }
-
- if (log_entry->has_children)
- {
- lb->merge_depth++;
- lb->merges++;
- }
-
- return SVN_NO_ERROR;
-}
-
-/* This implements the `svn_opt_subcommand_t' interface. */
-svn_error_t *
-svn_cl__null_log(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;
- svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
- apr_array_header_t *targets;
- struct log_receiver_baton lb = { 0 };
- const char *target;
- int i;
- apr_array_header_t *revprops;
- svn_opt_revision_t target_peg_revision;
- const char *target_path_or_url;
-
- SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
- opt_state->targets,
- ctx, FALSE, pool));
-
- /* Add "." if user passed 0 arguments */
- svn_opt_push_implicit_dot_target(targets, pool);
-
- /* Determine if they really want a two-revision range. */
- if (opt_state->used_change_arg)
- {
- if (opt_state->used_revision_arg && opt_state->revision_ranges->nelts > 1)
- {
- return svn_error_create
- (SVN_ERR_CLIENT_BAD_REVISION, NULL,
- _("-c and -r are mutually exclusive"));
- }
- for (i = 0; i < opt_state->revision_ranges->nelts; i++)
- {
- svn_opt_revision_range_t *range;
- range = APR_ARRAY_IDX(opt_state->revision_ranges, i,
- svn_opt_revision_range_t *);
- if (range->start.value.number < range->end.value.number)
- range->start.value.number++;
- else
- range->end.value.number++;
- }
- }
-
- /* Parse the first target into path-or-url and peg revision. */
- target = APR_ARRAY_IDX(targets, 0, const char *);
- SVN_ERR(svn_opt_parse_path(&target_peg_revision, &target_path_or_url,
- target, pool));
- if (target_peg_revision.kind == svn_opt_revision_unspecified)
- target_peg_revision.kind = (svn_path_is_url(target)
- ? svn_opt_revision_head
- : svn_opt_revision_working);
- APR_ARRAY_IDX(targets, 0, const char *) = target_path_or_url;
-
- if (svn_path_is_url(target))
- {
- for (i = 1; i < targets->nelts; i++)
- {
- target = APR_ARRAY_IDX(targets, i, const char *);
-
- if (svn_path_is_url(target) || target[0] == '/')
- return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("Only relative paths can be specified"
- " after a URL for 'svn-bench log', "
- "but '%s' is not a relative path"),
- target);
- }
- }
-
- lb.ctx = ctx;
- lb.quiet = opt_state->quiet;
-
- revprops = apr_array_make(pool, 3, sizeof(char *));
- APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_AUTHOR;
- APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_DATE;
- if (!opt_state->quiet)
- APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_LOG;
- SVN_ERR(svn_client_log5(targets,
- &target_peg_revision,
- opt_state->revision_ranges,
- opt_state->limit,
- opt_state->verbose,
- opt_state->stop_on_copy,
- opt_state->use_merge_history,
- revprops,
- log_entry_receiver,
- &lb,
- ctx,
- pool));
-
- if (!opt_state->quiet)
- {
- if (opt_state->use_merge_history)
- SVN_ERR(svn_cmdline_printf(pool,
- _("%15s revisions, %15s merged in %s merges\n"
- "%15s msg lines, %15s in merged revisions\n"
- "%15s changes, %15s in merged revisions\n"),
- svn__ui64toa_sep(lb.revisions, ',', pool),
- svn__ui64toa_sep(lb.merged_revs, ',', pool),
- svn__ui64toa_sep(lb.merges, ',', pool),
- svn__ui64toa_sep(lb.message_lines, ',', pool),
- svn__ui64toa_sep(lb.merged_message_lines, ',', pool),
- svn__ui64toa_sep(lb.changes, ',', pool),
- svn__ui64toa_sep(lb.merged_changes, ',', pool)));
- else
- SVN_ERR(svn_cmdline_printf(pool,
- _("%15s revisions\n"
- "%15s msg lines\n"
- "%15s changes\n"),
- svn__ui64toa_sep(lb.revisions, ',', pool),
- svn__ui64toa_sep(lb.message_lines, ',', pool),
- svn__ui64toa_sep(lb.changes, ',', pool)));
- }
-
- return SVN_NO_ERROR;
-}
diff --git a/tools/client-side/svn-bench/svn-bench.c b/tools/client-side/svn-bench/svn-bench.c
deleted file mode 100644
index bf8964e..0000000
--- a/tools/client-side/svn-bench/svn-bench.c
+++ /dev/null
@@ -1,954 +0,0 @@
-/*
- * main.c: Subversion command line client.
- *
- * ====================================================================
- * 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_signal.h>
-
-#include "svn_cmdline.h"
-#include "svn_dirent_uri.h"
-#include "svn_pools.h"
-#include "svn_utf.h"
-#include "svn_version.h"
-
-#include "cl.h"
-
-#include "private/svn_opt_private.h"
-#include "private/svn_cmdline_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_cl__longopt_t {
- opt_auth_password = SVN_OPT_FIRST_LONGOPT_ID,
- opt_auth_username,
- opt_config_dir,
- opt_config_options,
- opt_depth,
- opt_no_auth_cache,
- opt_non_interactive,
- opt_stop_on_copy,
- opt_strict,
- opt_targets,
- opt_version,
- opt_with_revprop,
- opt_with_all_revprops,
- opt_with_no_revprops,
- opt_trust_server_cert
-} 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_cl__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")},
- {"recursive", 'R', 0, N_("descend recursively, same as --depth=infinity")},
- {"non-recursive", 'N', 0, N_("obsolete; try --depth=files or --depth=immediates")},
- {"change", 'c', 1,
- N_("the change made by revision ARG (like -r ARG-1:ARG)\n"
- " "
- "If ARG is negative this is like -r ARG:ARG-1\n"
- " "
- "If ARG is of the form ARG1-ARG2 then this is like\n"
- " "
- "ARG1:ARG2, where ARG1 is inclusive")},
- {"revision", 'r', 1,
- N_("ARG (some commands also take ARG1:ARG2 range)\n"
- " "
- "A revision argument can be one of:\n"
- " "
- " NUMBER revision number\n"
- " "
- " '{' DATE '}' revision at start of the date\n"
- " "
- " 'HEAD' latest in repository\n"
- " "
- " 'BASE' base rev of item's working copy\n"
- " "
- " 'COMMITTED' last commit at or before BASE\n"
- " "
- " 'PREV' revision just before COMMITTED")},
- {"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")},
- {"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')")},
- {"strict", opt_strict, 0, N_("use strict semantics")},
- {"stop-on-copy", opt_stop_on_copy, 0,
- N_("do not cross copies while traversing history")},
- {"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"
- " "
- "certificate authorities without prompting (but only\n"
- " "
- "with '--non-interactive')") },
- {"non-interactive", opt_non_interactive, 0,
- N_("do no interactive prompting")},
- {"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")},
- {"limit", 'l', 1, N_("maximum number of log entries")},
- {"with-all-revprops", opt_with_all_revprops, 0,
- N_("retrieve all revision properties")},
- {"with-no-revprops", opt_with_no_revprops, 0,
- N_("retrieve no revision properties")},
- {"with-revprop", opt_with_revprop, 1,
- N_("set revision property ARG in new revision\n"
- " "
- "using the name[=value] format")},
- {"use-merge-history", 'g', 0,
- N_("use/display additional information from merge\n"
- " "
- "history")},
-
- /* Long-opt Aliases
- *
- * These have NULL desriptions, but an option code that matches some
- * other option (whose description should probably mention its aliases).
- */
-
- {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_cl__global_options[] =
-{ opt_auth_username, opt_auth_password, opt_no_auth_cache, opt_non_interactive,
- opt_trust_server_cert, opt_config_dir, opt_config_options, 0
-};
-
-const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
-{
- { "help", svn_cl__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 "-?". */
-
- { "null-export", svn_cl__null_export, {0}, N_
- ("Create an unversioned copy of a tree.\n"
- "usage: null-export [-r REV] URL[@PEGREV]\n"
- "\n"
- " Exports a clean directory tree from the repository specified by\n"
- " URL, at revision REV if it is given, otherwise at HEAD.\n"
- "\n"
- " If specified, PEGREV determines in which revision the target is first\n"
- " looked up.\n"),
- {'r', 'q', 'N', opt_depth} },
-
- { "null-list", svn_cl__null_list, {"ls"}, N_
- ("List directory entries in the repository.\n"
- "usage: list [TARGET[@REV]...]\n"
- "\n"
- " List each TARGET file and the contents of each TARGET directory as\n"
- " they exist in the repository. If TARGET is a working copy path, the\n"
- " corresponding repository URL will be used. If specified, REV determines\n"
- " in which revision the target is first looked up.\n"
- "\n"
- " The default TARGET is '.', meaning the repository URL of the current\n"
- " working directory.\n"
- "\n"
- " With --verbose, the following fields will be fetched for each item:\n"
- "\n"
- " Revision number of the last commit\n"
- " Author of the last commit\n"
- " If locked, the letter 'O'. (Use 'svn info URL' to see details)\n"
- " Size (in bytes)\n"
- " Date and time of the last commit\n"),
- {'r', 'v', 'q', 'R', opt_depth} },
-
- { "null-log", svn_cl__null_log, {0}, N_
- ("Fetch the log messages for a set of revision(s) and/or path(s).\n"
- "usage: 1. null-log [PATH][@REV]\n"
- " 2. null-log URL[@REV] [PATH...]\n"
- "\n"
- " 1. Fetch the log messages for the URL corresponding to PATH\n"
- " (default: '.'). If specified, REV is the revision in which the\n"
- " URL is first looked up, and the default revision range is REV:1.\n"
- " If REV is not specified, the default revision range is BASE:1,\n"
- " since the URL might not exist in the HEAD revision.\n"
- "\n"
- " 2. Fetch the log messages for the PATHs (default: '.') under URL.\n"
- " If specified, REV is the revision in which the URL is first\n"
- " looked up, and the default revision range is REV:1; otherwise,\n"
- " the URL is looked up in HEAD, and the default revision range is\n"
- " HEAD:1.\n"
- "\n"
- " Multiple '-c' or '-r' options may be specified (but not a\n"
- " combination of '-c' and '-r' options), and mixing of forward and\n"
- " reverse ranges is allowed.\n"
- "\n"
- " With -v, also print all affected paths with each log message.\n"
- " With -q, don't print the log message body itself (note that this is\n"
- " compatible with -v).\n"
- "\n"
- " Each log message is printed just once, even if more than one of the\n"
- " affected paths for that revision were explicitly requested. Logs\n"
- " follow copy history by default. Use --stop-on-copy to disable this\n"
- " behavior, which can be useful for determining branchpoints.\n"),
- {'r', 'q', 'v', 'g', 'c', opt_targets, opt_stop_on_copy,
- 'l', opt_with_all_revprops, opt_with_no_revprops, opt_with_revprop,
- 'x',},
- {{opt_with_revprop, N_("retrieve revision property ARG")},
- {'c', N_("the change made in revision ARG")}} },
-
- { 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 },
- { NULL, NULL }
- };
- SVN_VERSION_DEFINE(my_version);
-
- return svn_ver_check_list(&my_version, checklist);
-}
-
-
-/* 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_cl__check_cancel(void *baton)
-{
- if (cancelled)
- return svn_error_create(SVN_ERR_CANCELLED, NULL, _("Caught signal"));
- else
- return SVN_NO_ERROR;
-}
-
-
-/*** Main. ***/
-
-/* Report and clear the error ERR, and return EXIT_FAILURE. */
-#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)
-{
- svn_error_t *err;
- int opt_id;
- apr_getopt_t *os;
- svn_cl__opt_state_t opt_state = { 0, { 0 } };
- svn_client_ctx_t *ctx;
- apr_array_header_t *received_opts;
- int i;
- const svn_opt_subcommand_desc2_t *subcommand = NULL;
- svn_cl__cmd_baton_t command_baton;
- svn_auth_baton_t *ab;
- svn_config_t *cfg_config;
- svn_boolean_t descend = TRUE;
- svn_boolean_t use_notifier = TRUE;
-
- received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int));
-
- /* Check library versions */
- SVN_INT_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));
- }
-#endif
-
- /* Initialize the RA library. */
- SVN_INT_ERR(svn_ra_initialize(pool));
-
- /* Begin processing arguments. */
- opt_state.start_revision.kind = svn_opt_revision_unspecified;
- opt_state.end_revision.kind = svn_opt_revision_unspecified;
- opt_state.revision_ranges =
- apr_array_make(pool, 0, sizeof(svn_opt_revision_range_t *));
- opt_state.depth = svn_depth_unknown;
-
- /* No args? Show usage. */
- if (argc <= 1)
- {
- SVN_INT_ERR(svn_cl__help(NULL, NULL, pool));
- return EXIT_FAILURE;
- }
-
- /* Else, parse options. */
- SVN_INT_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_cl__options, &opt_id,
- &opt_arg);
- if (APR_STATUS_IS_EOF(apr_err))
- break;
- else if (apr_err)
- {
- SVN_INT_ERR(svn_cl__help(NULL, NULL, pool));
- return EXIT_FAILURE;
- }
-
- /* Stash the option code in an array before parsing it. */
- APR_ARRAY_PUSH(received_opts, int) = opt_id;
-
- switch (opt_id) {
- case 'l':
- {
- err = svn_cstring_atoi(&opt_state.limit, opt_arg);
- if (err)
- {
- err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, err,
- _("Non-numeric limit argument given"));
- return EXIT_ERROR(err);
- }
- if (opt_state.limit <= 0)
- {
- err = svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
- _("Argument to --limit must be positive"));
- return EXIT_ERROR(err);
- }
- }
- break;
- case 'c':
- {
- apr_array_header_t *change_revs =
- svn_cstring_split(opt_arg, ", \n\r\t\v", TRUE, pool);
-
- for (i = 0; i < change_revs->nelts; i++)
- {
- char *end;
- svn_revnum_t changeno, changeno_end;
- const char *change_str =
- APR_ARRAY_IDX(change_revs, i, const char *);
- const char *s = change_str;
- svn_boolean_t is_negative;
-
- /* Check for a leading minus to allow "-c -r42".
- * The is_negative flag is used to handle "-c -42" and "-c -r42".
- * The "-c r-42" case is handled by strtol() returning a
- * negative number. */
- is_negative = (*s == '-');
- if (is_negative)
- s++;
-
- /* Allow any number of 'r's to prefix a revision number. */
- while (*s == 'r')
- s++;
- changeno = changeno_end = strtol(s, &end, 10);
- if (end != s && *end == '-')
- {
- 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);
- }
- s = end + 1;
- while (*s == 'r')
- s++;
- changeno_end = strtol(s, &end, 10);
- }
- 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);
- }
-
- if (changeno == 0)
- {
- err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("There is no change 0"));
- return EXIT_ERROR(err);
- }
-
- if (is_negative)
- changeno = -changeno;
-
- /* Figure out the range:
- -c N -> -r N-1:N
- -c -N -> -r N:N-1
- -c M-N -> -r M-1:N for M < N
- -c M-N -> -r M:N-1 for M > N
- -c -M-N -> error (too confusing/no valid use case)
- */
- if (changeno > 0)
- {
- if (changeno <= changeno_end)
- changeno--;
- else
- changeno_end--;
- }
- else
- {
- changeno = -changeno;
- changeno_end = changeno - 1;
- }
-
- opt_state.used_change_arg = TRUE;
- APR_ARRAY_PUSH(opt_state.revision_ranges,
- svn_opt_revision_range_t *)
- = svn_opt__revision_range_from_revnums(changeno, changeno_end,
- pool);
- }
- }
- break;
- case 'r':
- opt_state.used_revision_arg = TRUE;
- if (svn_opt_parse_revision_to_range(opt_state.revision_ranges,
- 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,
- _("Syntax error in revision argument '%s'"),
- utf8_opt_arg);
- return EXIT_ERROR(err);
- }
- break;
- case 'v':
- opt_state.verbose = TRUE;
- break;
- case 'h':
- case '?':
- opt_state.help = TRUE;
- break;
- case 'q':
- opt_state.quiet = TRUE;
- 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));
- opt_state.targets = svn_cstring_split(buffer_utf8->data, "\n\r",
- TRUE, pool);
- }
- break;
- case 'N':
- descend = FALSE;
- break;
- 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")));
- 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));
- }
- 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));
- break;
- case opt_auth_password:
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.auth_password,
- opt_arg, pool));
- break;
- case opt_stop_on_copy:
- opt_state.stop_on_copy = TRUE;
- break;
- case opt_strict:
- opt_state.strict = TRUE;
- 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_trust_server_cert:
- opt_state.trust_server_cert = TRUE;
- break;
- case 'x':
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.extensions,
- opt_arg, pool));
- 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);
- }
- 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_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));
- break;
- case opt_with_all_revprops:
- /* If --with-all-revprops is specified along with one or more
- * --with-revprops options, --with-all-revprops takes precedence. */
- opt_state.all_revprops = TRUE;
- break;
- case opt_with_no_revprops:
- opt_state.no_revprops = TRUE;
- break;
- case opt_with_revprop:
- SVN_INT_ERR(svn_opt_parse_revprop(&opt_state.revprop_table,
- opt_arg, pool));
- break;
- case 'g':
- opt_state.use_merge_history = 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;
- }
- }
-
- /* ### 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_INT_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_cl__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_cl__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_INT_ERR(svn_cl__help(NULL, NULL, pool));
- return EXIT_FAILURE;
- }
- }
- else
- {
- const char *first_arg = os->argv[os->ind++];
- subcommand = svn_opt_get_canonical_subcommand2(svn_cl__cmd_table,
- first_arg);
- if (subcommand == NULL)
- {
- const char *first_arg_utf8;
- SVN_INT_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_INT_ERR(svn_cl__help(NULL, NULL, pool));
- return EXIT_FAILURE;
- }
- }
- }
-
- /* 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_cl__global_options))
- {
- const char *optstr;
- const apr_getopt_option_t *badopt =
- svn_opt_get_option_from_code2(opt_id, svn_cl__options,
- subcommand, pool);
- svn_opt_format_option(&optstr, badopt, FALSE, pool);
- if (subcommand->name[0] == '-')
- SVN_INT_ERR(svn_cl__help(NULL, NULL, pool));
- else
- svn_error_clear
- (svn_cmdline_fprintf
- (stderr, pool, _("Subcommand '%s' doesn't accept option '%s'\n"
- "Type 'svn-bench help %s' for usage.\n"),
- subcommand->name, optstr, subcommand->name));
- return EXIT_FAILURE;
- }
- }
-
- /* Only merge and log support multiple revisions/revision ranges. */
- if (subcommand->cmd_func != svn_cl__null_log)
- {
- 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);
- }
- }
-
- /* 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);
- }
-
- /* 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);
- }
-
- /* --trust-server-cert can only be used with --non-interactive */
- if (opt_state.trust_server_cert && !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);
- }
-
- /* Ensure that 'revision_ranges' has at least one item, and make
- 'start_revision' and 'end_revision' match that item. */
- if (opt_state.revision_ranges->nelts == 0)
- {
- svn_opt_revision_range_t *range = apr_palloc(pool, sizeof(*range));
- range->start.kind = svn_opt_revision_unspecified;
- range->end.kind = svn_opt_revision_unspecified;
- APR_ARRAY_PUSH(opt_state.revision_ranges,
- svn_opt_revision_range_t *) = range;
- }
- opt_state.start_revision = APR_ARRAY_IDX(opt_state.revision_ranges, 0,
- svn_opt_revision_range_t *)->start;
- opt_state.end_revision = APR_ARRAY_IDX(opt_state.revision_ranges, 0,
- svn_opt_revision_range_t *)->end;
-
- /* Create a client context object. */
- command_baton.opt_state = &opt_state;
- SVN_INT_ERR(svn_client_create_context2(&ctx, NULL, pool));
- command_baton.ctx = ctx;
-
- /* Only a few commands can accept a revision range; the rest can take at
- most one revision number. */
- if (subcommand->cmd_func != svn_cl__null_log)
- {
- 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);
- }
- }
-
- /* -N has a different meaning depending on the command */
- if (!descend)
- opt_state.depth = svn_depth_files;
-
- err = svn_config_get_config(&(ctx->config),
- 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);
- }
- else
- return EXIT_ERROR(err);
- }
-
- cfg_config = apr_hash_get(ctx->config, SVN_CONFIG_CATEGORY_CONFIG,
- APR_HASH_KEY_STRING);
-
- /* Update the options in the config */
- if (opt_state.config_options)
- {
- svn_error_clear(
- svn_cmdline__apply_config_options(ctx->config,
- opt_state.config_options,
- "svn: ", "--config-option"));
- }
-
- /* Set up the notifier.
-
- In general, we use it any time we aren't in --quiet mode. 'svn
- status' is unique, though, in that we don't want it in --quiet mode
- unless we're also in --verbose mode. When in --xml mode,
- though, we never want it. */
- if (opt_state.quiet)
- use_notifier = FALSE;
- if (use_notifier)
- {
- SVN_INT_ERR(svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2,
- pool));
- }
-
- /* Set up our cancellation support. */
- ctx->cancel_func = svn_cl__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_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));
-
- ctx->auth_baton = ab;
-
- /* The new svn behavior is to postpone everything until after the operation
- completed */
- ctx->conflict_func = NULL;
- ctx->conflict_baton = NULL;
- ctx->conflict_func2 = NULL;
- ctx->conflict_baton2 = NULL;
-
- /* 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-bench help %s' for more information"),
- subcommand->name));
- }
- if (err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED)
- {
- err = svn_error_quick_wrap(err,
- _("Please see the 'svn upgrade' command"));
- }
-
- /* 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)"));
- }
-
- return EXIT_ERROR(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;
- }
-}
-
-int
-main(int argc, const char *argv[])
-{
- apr_pool_t *pool;
- int exit_code;
-
- /* 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));
-
- exit_code = sub_main(argc, argv, pool);
-
- svn_pool_destroy(pool);
- return exit_code;
-}
diff --git a/tools/client-side/svn-bench/util.c b/tools/client-side/svn-bench/util.c
deleted file mode 100644
index 2aedde6..0000000
--- a/tools/client-side/svn-bench/util.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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 <string.h>
-#include <ctype.h>
-#include <assert.h>
-
-#include "svn_private_config.h"
-#include "svn_error.h"
-#include "svn_path.h"
-
-#include "cl.h"
-
-
-
-svn_error_t *
-svn_cl__args_to_target_array_print_reserved(apr_array_header_t **targets,
- apr_getopt_t *os,
- const apr_array_header_t *known_targets,
- svn_client_ctx_t *ctx,
- svn_boolean_t keep_last_origpath_on_truepath_collision,
- apr_pool_t *pool)
-{
- svn_error_t *err = svn_client_args_to_target_array2(targets,
- os,
- known_targets,
- ctx,
- keep_last_origpath_on_truepath_collision,
- pool);
- if (err)
- {
- if (err->apr_err == SVN_ERR_RESERVED_FILENAME_SPECIFIED)
- {
- svn_handle_error2(err, stderr, FALSE, "svn: Skipping argument: ");
- svn_error_clear(err);
- }
- else
- return svn_error_trace(err);
- }
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_cl__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;
-}
-
-const char *
-svn_cl__local_style_skip_ancestor(const char *parent_path,
- const char *path,
- apr_pool_t *pool)
-{
- const char *relpath = NULL;
-
- if (parent_path)
- relpath = svn_dirent_skip_ancestor(parent_path, path);
-
- return svn_dirent_local_style(relpath ? relpath : path, pool);
-}
-
diff --git a/tools/client-side/svn-graph.pl b/tools/client-side/svn-graph.pl
index cd76d04..0675e8a 100755
--- a/tools/client-side/svn-graph.pl
+++ b/tools/client-side/svn-graph.pl
@@ -43,7 +43,6 @@ use Getopt::Std;
$|=1;
require SVN::Core;
-require SVN::Ra;
require SVN::Client;
# The URL of the Subversion repository we wish to graph
@@ -60,17 +59,6 @@ my $startpath;
# Set the variables declared above.
parse_commandline();
-# Point at the root of a repository so we get can look at
-# every revision.
-my $auth = (new SVN::Client())->auth;
-my $ra = SVN::Ra->new(url => $repos_url, auth => $auth);
-
-# Handle identifier for the aboslutely youngest revision.
-if ($youngest eq 'HEAD')
-{
- $youngest = $ra->get_latest_revnum();
-}
-
# The "interesting" nodes are potential sources for copies. This list
# grows as we move through time.
# The "tracking" nodes are the most recent revisions of paths we're
@@ -110,7 +98,7 @@ usage: svn-graph.pl [-r START_REV:END_REV] [-p PATH] REPOS_URL
getopts('r:p:h', \%cmd_opts) or die $usage;
die $usage if scalar(@ARGV) < 1;
- $repos_url = $ARGV[0];
+ $repos_url = SVN::Core::uri_canonicalize($ARGV[0]);
$cmd_opts{'r'} =~ m/(\d+)(:(.+))?/;
if ($3)
@@ -207,6 +195,7 @@ sub process_revision
# Write a descriptor for the graph in GraphViz .dot format to stdout.
sub write_graph_descriptor
{
+ my $client = SVN::Client->new;
# Begin writing the graph descriptor.
print "digraph tree {\n";
print "\tgraph [bgcolor=white];\n";
@@ -215,7 +204,7 @@ sub write_graph_descriptor
print "\n";
# Retrieve the requested history.
- $ra->get_log(['/'], $startrev, $youngest, 0, 1, 0, \&process_revision);
+ $client->log($repos_url, $startrev, $youngest, 1, 0, \&process_revision);
# Now ensure that everything is linked.
foreach my $codeline_change (keys %codeline_changes_forward)
diff --git a/tools/client-side/svn-ssl-fingerprints.sh b/tools/client-side/svn-ssl-fingerprints.sh
index 6fed58b..828ea4a 100755
--- a/tools/client-side/svn-ssl-fingerprints.sh
+++ b/tools/client-side/svn-ssl-fingerprints.sh
@@ -20,7 +20,7 @@
#
#
# $0 --- list the fingerprints of SSL certificates that svn has seen before.
-#
+#
# SYNOPSIS:
# $0
# $0 /path/to/.subversion
diff --git a/tools/client-side/svn-vendor.py b/tools/client-side/svn-vendor.py
new file mode 100755
index 0000000..d0c862c
--- /dev/null
+++ b/tools/client-side/svn-vendor.py
@@ -0,0 +1,1065 @@
+#!/usr/bin/python3
+# vim: set sw=4 expandtab :
+# ====================================================================
+# 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.
+# ====================================================================
+#
+##############################################################################
+# svn-vendor.py
+#
+# Overview
+# --------
+# Replacement for svn_load_dirs.pl (included as a 'contributed utility' in
+# Subversion sources). Main difference is some heuristics in detection of
+# the renames. Note that this script does not attempt to automate remote
+# SVN operations (check-out, check-in and tagging), so it is possible to
+# review the state of sources that are about to be checked in. Another
+# difference is an ability to save the detected renames, review/re-apply
+# them.
+#
+# This script requires Python 3.3.x or higher. Sorry, I was too lazy
+# to write shell quoting routines that are already available in recent
+# Python versions.
+#
+# Using this script
+# -----------------
+# First, it is necessary to check out the working copy from the URL that
+# will host the imported sources. E.g., if the versions of FOO are being
+# imported into svn://example.com/vendor/FOO/current:
+#
+# svn co svn://example.com/vendor/FOO/current wc
+#
+# Then, unpack the sources of the version to be imported:
+#
+# tar xzf foo-1.1.tar.gz
+#
+# Examples below assume the command above created a `foo-1.1' directory.
+# After that, there are three different modes of operation:
+#
+# 1. Fully automatic
+#
+# svn-vendor.py --auto wc foo-1.1
+# svn st wc
+# svn ci wc
+#
+# In this mode, the script fully relies on its heuristics in detection of
+# renames. In many cases, it "just works". There can be spurious moves
+# detected in this mode, though. For example, consider a deleted header
+# that consists of 50 lines of GPL text, 1 line of copyright, and
+# 3 lines of declarations, and a similar unrelated header in the imported
+# sources. From the script's point of view, the files are nearly identical
+# (4 lines removed, 4 lines added, 50 lines unchanged).
+#
+# After the script completes, examine the working copy by doing 'svn diff'
+# and/or 'svn status', paying particular attention to renames. If all the
+# moves are detected correctly, check in the changes in the working copy.
+#
+# 2. Semi-automatic
+#
+# svn-vendor.py --detect moves-foo-1.1.txt wc foo-1.1
+# vi moves-foo-1.1.txt
+# svn-vendor.py --apply moves-foo-1.1.txt wc foo-1.1
+# svn ci wc
+#
+# If the fully automatic mode mis-detected some spurious moves, or did not
+# detect some renames you want to be performed, it is still possible to
+# leverage what the script has detected automatically. First command above
+# does the automatic detection, just as it does in fully automatic mode,
+# but stops short of performing any modification of the working copy.
+# The list of detected copies and renames is saved into a text file,
+# `moves-foo-1.1.txt'.
+#
+# That file can be inspected after the script finishes. Spurious moves can
+# be deleted from the file, and new copies/renames can be added. Then the
+# changes can be applied to the working copy.
+#
+# 3. Manual
+#
+# svn-vendor.py wc foo-1.1
+# (svn-vendor) detect
+# (svn-vendor) move x.c y.c
+# (svn-vendor) move include/1.h include/2.h
+# (svn-vendor) copy include/3.h include/3-copy.h
+# (svn-vendor) lsprep
+# (svn-vendor) save /tmp/renames-to-be-applied.txt
+# (svn-vendor) apply
+#
+# If the automatic detection does not help, it is possible to do the renames
+# manually (similarly to svn_load_dirs.pl). Use the 'help' command to get
+# the list of supported commands and their description. Feel free to play
+# around - since the script does not perform any remote SVN operation,
+# there is no chance to commit the changes accidentally.
+#
+# Notes
+# -----
+# I. The time for rename detection O(Fs*Fd) + O(Ds*Dd), where Fs is
+# the number of files removed from current directory, Fd is number of files
+# added in imported sources, and Ds/Dd is the same for directories. That is,
+# the running time may become an issue if the numbers of added/removed files
+# go into a few thousands (e.g. if updating Linux kernel 2.6.35 to 3.10).
+# As a workaround, import interim releases first so that the number of
+# renames remains sane at each step. That makes reviewing the renames
+# performed by the script much easier.
+#
+# Enjoy!
+#
+##############################################################################
+
+import argparse
+import cmd
+import difflib
+import filecmp
+import os
+import readline
+import shlex
+import shutil
+import subprocess
+import sys
+
+def name_similarity(n1, n2):
+ '''
+ Function to be used as a key for sorting dirs/files by name matching
+ '''
+ sm = difflib.SequenceMatcher(a=n1, b=n2)
+ return 1.0 - sm.ratio()
+
+
+def filename_sort_key(s):
+ '''
+ Function to sort filenames so that parent directory is always followed
+ by its children. Without it, [ "/a", "/a-b", "/a/b", "/a-b/c" ] would
+ not be sorted correctly.
+ '''
+ return s.replace('/', '\001')
+
+
+def descendant_or_self(path, ancestor):
+ '''
+ Check if path is somewhere in hierarchy under ancestor.
+ '''
+ return path == ancestor or path.startswith(ancestor + os.sep)
+
+def path_rebase(path, old_base, new_base):
+ '''
+ Return a path name that has the same relative path to new_base as path
+ had to old_base. Assumes path is a descendant of old_base.
+ '''
+ if path == old_base:
+ return new_base
+ return os.path.normpath(os.path.join(new_base,
+ os.path.relpath(path, old_base)))
+
+
+def for_all_parents(path, func):
+ '''
+ Invoke func for each parent path.
+ '''
+ d = os.path.dirname(path)
+ while d != "":
+ func(d)
+ d = os.path.dirname(d)
+
+class InvalidUsageException(Exception):
+ '''
+ Raised if command line arguments are invalid
+ '''
+ def __init__(self, cmd, msg):
+ Exception.__init__(self, msg)
+ self.cmd = cmd
+
+
+class NotImplementedException(Exception):
+ '''
+ Raised if some code path is not implemented
+ '''
+ pass
+
+
+# Indexes into FSO.state
+S_WC = 0
+S_IM = 1
+
+class FSO(object):
+ '''
+ File system object (file/dir either in imported dir or in WC)
+ '''
+ def __init__(self):
+ self.wc_path = None
+ self.state = [ "-", "-" ] # '-': absent, 'F': file, 'D': dir
+
+ def status(self):
+ return "[%s%s]" % (self.state[S_WC], self.state[S_IM])
+
+ def orig_reference(self, curpath):
+ if self.wc_path and self.wc_path != curpath:
+ return " (original: %s)" % shlex.quote(self.wc_path)
+ return ""
+
+
+class FSOCollection(dict):
+ '''
+ Collection of FSOs
+ '''
+ def print(self):
+ print(" / Status in working copy (-:absent, F:file, D:dir)")
+ print(" |/ Status in imported sources (-:absent, F:file, D:dir)")
+ for k in sorted(self.keys(), key=filename_sort_key):
+ e = self[k]
+ print("%s %s%s" % (e.status(), shlex.quote(k),
+ e.orig_reference(k)))
+
+ def get(self, path):
+ 'Get existing FSO or create a new one'
+ if path in self:
+ return self[path]
+ e = FSO()
+ self[path] = e
+ return e
+
+ def add(self, path, where, kind):
+ 'Adding entries during initial scan'
+ path = os.path.normpath(path)
+ e = self.get(path)
+ e.state[where] = kind
+ if where == S_WC:
+ e.wc_path = path
+
+ def wc_copy(self, src, dst):
+ 'Handle move in a working copy'
+ keys = list(self.keys())
+ for k in keys:
+ if descendant_or_self(k, src):
+ esrc = self[k]
+ if esrc.state[S_WC] == "-":
+ continue
+ kn = path_rebase(k, src, dst)
+ edst = self.get(kn)
+ if edst.state[S_WC] != "-":
+ # Copying into existing destination.
+ # Caller should've checked this.
+ raise NotImplementedException
+ edst.wc_path = esrc.wc_path
+ edst.state[S_WC] = esrc.state[S_WC]
+
+ def wc_remove(self, path):
+ 'Handle removal in a working copy'
+ keys = list(self.keys())
+ for k in keys:
+ if descendant_or_self(k, path):
+ self[k].state[S_WC] = "-"
+
+
+class ConfigOpt(object):
+ 'Helper class - single option (string)'
+ def __init__(self, value, helpmsg):
+ self.value = value
+ self.helpmsg = helpmsg
+
+ def set(self, new_value):
+ self.value = new_value
+
+ def __str__(self):
+ return "<none>" if self.value is None else "`%s'" % self.value
+
+
+class ConfigOptInt(ConfigOpt):
+ 'Helper class - single option (integer)'
+ def set(self, new_value):
+ try:
+ self.value = int(new_value)
+ except ValueError:
+ raise InvalidUsageException(None, "Value must be integer")
+
+ def __str__(self):
+ return "%d" % self.value
+
+
+class Config(dict):
+ '''
+ Store configuration options.
+ '''
+ def add_option(self, name, cfgopt):
+ self[name] = cfgopt
+
+ def set(self, name, value):
+ if name not in self:
+ raise InvalidUsageException(None,
+ "Unknown config variable '%s'" % name)
+ self[name].set(value)
+
+ def get(self, name):
+ if name not in self:
+ raise NotImplementedException()
+ return self[name].value
+
+ def print(self):
+ for k in sorted(self):
+ o = self[k]
+ print("# %s" % o.helpmsg)
+ print("%-20s: %s" % (k, str(o)))
+ print()
+
+
+class SvnVndImport(cmd.Cmd):
+ '''
+ Main driving class.
+ '''
+ intro = "Welcome to SVN vendor import helper. " + \
+ "Type help or ? to list commands.\n"
+ prompt = "(svn-vendor) "
+ prepare_ops = []
+
+ def __init__(self, wcdir, importdir, svninfo):
+ cmd.Cmd.__init__(self)
+ self.wcdir = wcdir
+ self.importdir = importdir
+ self.svninfo = svninfo
+ self.config = Config()
+ self.config.add_option('save-diff-copied',
+ ConfigOpt(None, "Save 'svn diff' output on the " +
+ "moved/copied files and directories to this " +
+ "file as part of 'apply'"))
+ self.config.add_option('dir-similarity',
+ ConfigOptInt(600, "Similarity between dirs to assume " +
+ "a copy/move [0..1000]"))
+ self.config.add_option('file-similarity',
+ ConfigOptInt(600, "Similarity between files to assume a " +
+ "copy/move [0..1000]"))
+ self.config.add_option('file-min-lines',
+ ConfigOptInt(10, "Minimal number of lines in a file for " +
+ "meaningful comparison"))
+ self.config.add_option('verbose',
+ ConfigOptInt(3, "Verbosity of the output [0..5]"))
+ try:
+ self.termwidth = os.get_terminal_size()[0]
+ except OSError:
+ # Not running in a terminal - probably redirected to file
+ self.termwidth = 150 # arbitrary number
+
+ def info(self, level, msg):
+ 'Print message with specified verbosity'
+ if level <= self.config.get('verbose'):
+ print(msg, flush=True)
+
+ def scan(self):
+ self.items = FSOCollection()
+ self.info(1, "Scanning working copy directory...")
+ self.get_lists(self.wcdir, S_WC)
+ self.info(1, "Scanning imported directory...")
+ self.get_lists(self.importdir, S_IM)
+
+ def get_lists(self, top, where):
+ for d, dn, fn in os.walk(top, followlinks=True):
+ dr = os.path.relpath(d, top)
+ # If under .svn directory at the top (SVN 1.7+) or has .svn
+ # in the path (older SVN), ignore
+ if descendant_or_self(dr, '.svn') or \
+ os.path.basename(dr) == '.svn' or \
+ (os.sep + '.svn' + os.sep) in dr:
+ continue
+ if dr != '.':
+ self.items.add(dr, where, "D")
+ for f in fn:
+ fr = os.path.normpath(os.path.join(dr, f))
+ self.items.add(fr, where, "F")
+
+ def onecmd(self, str):
+ 'Override for checking number of arguments'
+ try:
+ return cmd.Cmd.onecmd(self, str)
+ except InvalidUsageException as e:
+ if e.cmd is not None:
+ print("!!! Invalid usage of `%s' command: %s" % (e.cmd, e))
+ print()
+ self.onecmd("help " + e.cmd)
+ else:
+ print("!!! %s" % e)
+
+ def parse_args(self, line, nargs, cmd):
+ 'Parse arguments for a command'
+ args = shlex.split(line)
+ if len(args) != nargs:
+ raise InvalidUsageException(cmd, "expect %d arguments" % nargs)
+ return args
+
+ def run_svn(self, args_fixed, args_split=[]):
+ 'Run SVN command(s), potentially splitting long argument lists'
+ rv = True
+ pos = 0
+ atatime = 100
+ output = ""
+ while pos < len(args_split) or (pos == 0 and len(args_split) == 0):
+ svnargs = ['svn'] + args_fixed + args_split[pos : pos + atatime]
+ pos += atatime
+ self.info(5, "Running: " + " ".join(map(shlex.quote, svnargs)))
+ p = subprocess.Popen(args=svnargs, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, cwd=self.wcdir)
+ so, se = p.communicate()
+ if p.returncode != 0:
+ print("`%s' exited with %d status:" %
+ (" ".join(map(shlex.quote, svnargs)), p.returncode))
+ print(se.decode())
+ rv = False
+ else:
+ output += so.decode()
+ return rv, output
+
+ def copy_or_move(self, op, src, dst):
+ 'Handle copy or move operation'
+ if src not in self.items or self.items[src].state[S_WC] == "-":
+ raise InvalidUsageException(None,
+ "Nothing known about `%s'" % src)
+ if dst in self.items and self.items[dst].state[S_WC] != "-":
+ raise InvalidUsageException(None,
+ "Destination path `%s' already exists" % dst)
+ # Check that we're not creating dst under a file (not a dir)
+ new_dirs = []
+ def check_parent(d):
+ if d not in self.items or self.items[d].state[S_WC] == "-":
+ new_dirs.append(d)
+ elif self.items[d].state[S_WC] == "F":
+ raise InvalidUsageException(None,
+ "Destination path `%s' created under `%s' " +
+ "which is a file" % (dst, d))
+ for_all_parents(dst, check_parent)
+ # All ok, record new directories that may be created
+ for d in new_dirs:
+ self.items.get(d).state[S_WC] = "D"
+ # Record the operation and update the FSO collection
+ self.prepare_ops.append((op, src, dst))
+ self.items.wc_copy(src, dst)
+ if op == "mv":
+ self.items.wc_remove(src)
+
+ def remove(self, path):
+ if path not in self.items or self.items[path].state[S_WC] == "-":
+ raise InvalidUsageException(None,
+ "Nothing known about `%s'" % path)
+ self.prepare_ops.append(("rm", path))
+ self.items.wc_remove(path)
+
+ def similarity_file(self, src, dst, threshold, lst_removal):
+ 'Compare two files, return similarity ratio on 0..1000 scale'
+ if self.items[src].state[S_WC] != "F":
+ return 0
+ # Source is in working copy
+ fn1 = os.path.join(self.wcdir, self.items[src].wc_path)
+ # Destination is in imported dir
+ fn2 = os.path.join(self.importdir, dst)
+ minlines = self.config.get('file-min-lines')
+ try:
+ f1 = open(fn1, 'r')
+ l1 = f1.readlines()
+ f1.close()
+ if len(l1) < minlines:
+ return 0
+ f2 = open(fn2, 'r')
+ l2 = f2.readlines()
+ f2.close()
+ if len(l2) < minlines:
+ return 0
+ sm = difflib.SequenceMatcher(a=l1, b=l2)
+ return int(1000 * sm.quick_ratio())
+ except UnicodeDecodeError:
+ # Oops, file seems to be binary. Fall back to comparing whole
+ # file contents.
+ if filecmp.cmp(fn1, fn2, shallow=False):
+ return 1000
+ return 0
+
+ def _similarity_dir(self, src, dst, get_file_similarity, lst_removal):
+ 'Iterate over FSOs, using callback to compare file entries'
+ common = 0
+ total = 0
+ for xsrc in self.items:
+ if xsrc.startswith(src + os.sep):
+ esrc = self.items[xsrc]
+ if esrc.state[S_WC] == "-":
+ # Source not in WC - ignore for similarity calculation
+ continue
+ skip = False
+ if lst_removal is not None:
+ for i in lst_removal:
+ if descendant_or_self(xsrc, i):
+ skip = True
+ if skip:
+ # Moved to another place, do not consider in score
+ continue
+ total += 1000
+ xdst = path_rebase(xsrc, src, dst)
+ if xdst not in self.items:
+ # Destination not in imported sources - non-similar item
+ continue
+ edst = self.items[xdst]
+ if edst.state[S_IM] == esrc.state[S_WC]:
+ if esrc.state[S_WC] == "D":
+ common += 1000
+ else:
+ common += get_file_similarity(xsrc, xdst)
+ if total == 0:
+ # No files/subdirs in source directory - avoid copying empty dirs
+ return 0
+ return 1000 * common / total
+
+ def similarity_dir(self, src, dst, threshold, lst_removal):
+ '''
+ Compare two dirs recursively, return similarity ratio on
+ 0..1000 scale.
+ '''
+ common = 0
+ total = 0
+ # Quickly estimate upper boundary by comparing file names. Only
+ # concern ourselves with files in source directory. I.e., if
+ # files were added after the move in the destination directory,
+ # it's ok. If most of the files from the source directory were
+ # removed, the directory is not considered similar - instead,
+ # file move detection would move files one by one.
+ upper = self._similarity_dir(src, dst, lambda s, d: 1000, lst_removal)
+ if upper <= threshold:
+ # Even the best estimate is worse than current cut-off
+ return 0
+ # Okay, looks roughly similar. Now redo the above procedure, but also
+ # compare the file content.
+ return self._similarity_dir(src, dst,
+ lambda s, d: self.similarity_file(s, d, 0, lst_removal),
+ lst_removal)
+
+ def similar(self, src, dst, threshold=0, lst_removal=None):
+ 'Compare two FSOs, source in WC and destination in imported dir'
+ if src not in self.items:
+ print("Source `%s' not in the working copy" % src)
+ return
+ xsrc = self.items[src]
+ if xsrc.state[S_WC] == "-":
+ print("Source `%s' not in the working copy" % src)
+ return
+ if dst not in self.items:
+ print("Destination `%s' not in imported sources" % dst)
+ return
+ xdst = self.items[dst]
+ if xdst.state[S_IM] == "-":
+ print("Destination `%s' not in imported sources" % dst)
+ return
+ if xsrc.state[S_WC] != xdst.state[S_IM]:
+ # Different kinds - definitely not the same object
+ return 0
+ if xsrc.state[S_WC] == "D":
+ return self.similarity_dir(src, dst, threshold, lst_removal)
+ else:
+ return self.similarity_file(src, dst, threshold, lst_removal)
+
+ def handle_op(self, op_tuple):
+ 'Handle one SVN operation, recorded as a tuple'
+ def x_mv(src, dst):
+ self.info(2, " Move `%s' to `%s'" % (src, dst))
+ self.copy_or_move("mv", src, dst)
+ def x_cp(src, dst):
+ self.info(2, " Copy `%s' to `%s'" % (src, dst))
+ self.copy_or_move("cp", src, dst)
+ def x_rm(path):
+ self.info(2, " Remove `%s'" % path)
+ self.remove(path)
+ known_ops = {
+ # key: (nargs, handler)
+ 'cp' : (3, x_cp),
+ 'mv' : (3, x_mv),
+ 'rm' : (2, x_rm),
+ }
+ if len(op_tuple) == 0:
+ raise InvalidUsageException
+ op = op_tuple[0]
+ if op not in known_ops:
+ return False
+ nargs, func = known_ops[op]
+ if nargs != len(op_tuple):
+ return False
+ func(*op_tuple[1:])
+ return True
+
+ def detect(self, thresholds):
+ 'Helper for finding copy/move destinations'
+ ilst = []
+ wlst = {}
+ ilst_map = {}
+ for p in self.items:
+ e = self.items[p]
+ if e.state[S_WC] != "-" and e.state[S_IM] == "-":
+ wlst[p] = [] # wlst hash stores copy destinations
+ elif e.state[S_WC] == "-" and e.state[S_IM] != "-":
+ # ilst just lists destination paths as tuples with node kind
+ ilst.append((e.state[S_IM], p))
+ iteration = 0
+ # Do not apply operations immediately - we'll need to post-process
+ # them to account for files/dirs moved inside a moved parent dir.
+ ops = []
+ to_be_removed = []
+ def get_renamed_name(path, rename_ops):
+ '''
+ Check if path was renamed/removed in the recorded operations,
+ return new name.
+ '''
+ for op_tuple in rename_ops:
+ # Since copies do not remove the source file, ignore them.
+ # We push no 'rm' ops in this function
+ if op_tuple[0] == "mv":
+ src = op_tuple[1]
+ dst = op_tuple[2]
+ if descendant_or_self(path, src):
+ path = path_rebase(path, src, dst)
+ return path
+
+ while len(wlst):
+ iteration += 1
+ self.info(2, ("Iteration %d: Possible sources: %d, " +
+ "possible destinations: %d") %
+ (iteration, len(wlst), len(ilst)))
+ ndst = len(ilst)
+ for idx, (nk, dst) in enumerate(sorted(ilst,
+ key=lambda s: filename_sort_key(s[1]))):
+ class SkipDestFile(Exception):
+ pass
+ # Check if moved as a part of a parent directory.
+ def check_moved_parent(xdst):
+ if xdst in ilst_map:
+ src = path_rebase(dst, xdst, ilst_map[xdst])
+ # Did it exist in copied directory?
+ if src in self.items and \
+ self.items[src].state[S_WC] == nk:
+ sim = self.similar(src, dst, thresholds[nk],
+ to_be_removed)
+ if sim > thresholds[nk]:
+ self.info(2, (" [%04d/%04d] Skipping `%s' " +
+ "(copied as part of `%s')") %
+ (idx, ndst, dst, xdst))
+ raise SkipDestFile
+ # Copied, not similar - search for other sources
+ raise StopIteration
+ try:
+ for_all_parents(dst, check_moved_parent)
+ except SkipDestFile:
+ continue
+ except StopIteration:
+ pass
+ self.info(2, (" [%04d/%04d] Looking for possible source " +
+ "for `%s'") % (idx, ndst, dst))
+ bestsrc = None
+ # Won't even consider those lower than threshold
+ bestsim = thresholds[nk]
+ for src in sorted(wlst.keys(),
+ key=lambda x: name_similarity(x, dst)):
+ sim = self.similar(src, dst, bestsim, to_be_removed)
+ if sim > bestsim:
+ self.info(3, " [similarity %4d] %s" % (sim, src))
+ bestsim = sim
+ bestsrc = src
+ if bestsim == 1000:
+ # No chance we're finding anything better
+ break
+ if bestsrc is not None:
+ wlst[bestsrc].append(dst)
+ ilst_map[dst] = bestsrc
+
+ # Discovered all copies/moves, now record them.
+ new_wlst = {}
+ for src in sorted(wlst.keys(), key=filename_sort_key):
+ dlist = wlst[src]
+ if len(dlist) == 0:
+ continue
+ if len(dlist) == 1:
+ ops.append(("mv", src, dlist[0]))
+ to_be_removed.append(src)
+ else:
+ # We don't remove the source here, it will be done when
+ # the changes are applied (it will remove all the WC files
+ # not found in imported sources). Avoiding removal here
+ # simplifies operation sorting below, since we would not
+ # be concerned with source file/dir disappearing before
+ # it is copied to its destination.
+ to_be_removed.append(src)
+ for d in dlist:
+ ops.append(("cp", src, d))
+ # If we copied something - recheck parent source directories.
+ # Since some source file/dir was scheduled to be removed,
+ # this may have increased the similarity to some destination.
+ def recheck_parent(x):
+ if x in wlst and len(wlst) == 0:
+ new_wlst[x] = []
+ for_all_parents(src, recheck_parent)
+
+ # At this point, if we're going to have the next iteration, we
+ # are only concerned about directories (by the way new_wlst is
+ # created above). So, filter out all files from ilst as well.
+ wlst = new_wlst
+ ilst = list(filter(lambda t: t[0] == 'D', ilst))
+
+ # Finished collecting the operations - now can post-process and
+ # apply them. First, sort copies/moves by destination (so that
+ # parent directories are created before files/subdirs are
+ # copied/renamed inside)
+ ops = sorted(ops, key=lambda op: filename_sort_key(op[2]))
+ for i, op_tuple in enumerate(ops):
+ # For each operation, go over its precedents to see if the source
+ # has been renamed. If it is, find out new name.
+ op = op_tuple[0]
+ src = get_renamed_name(op_tuple[1], reversed(ops[:i]))
+ if src != op_tuple[2]:
+ # Unless it became the same file after renames
+ try:
+ # Try to remove the destination, if it existed
+ self.remove(op_tuple[2])
+ except InvalidUsageException:
+ # Okay, it didn't exist
+ pass
+ self.handle_op((op, src, op_tuple[2]))
+
+ def do_detect(self, arg):
+ '''
+ detect : auto-detect possible moves (where source/destination name
+ is unique). If not all moves are applicable, save move list,
+ edit and load.
+ '''
+ self.parse_args(arg, 0, "detect")
+ self.detect({ "D": self.config.get('dir-similarity'),
+ "F": self.config.get('file-similarity')})
+
+ def do_apply(self, arg):
+ '''
+ apply : Perform copies/renames; then copy imported sources into
+ the working copy. Modifies working copy. Exits after
+ completion.
+ '''
+ self.info(1, "Copying imported sources into working copy...")
+ # Perform the recorded copies/moves/removals
+ self.info(2, " Preparatory operations (copies/renames/removals)")
+ to_be_diffed = []
+ for o in self.prepare_ops:
+ op = o[0]
+ if op == "mv":
+ self.run_svn(["mv", "--parents", o[1], o[2]])
+ to_be_diffed.append(o[2])
+ elif op == "cp":
+ self.run_svn(["cp", "--parents", o[1], o[2]])
+ to_be_diffed.append(o[2])
+ elif op == "rm":
+ # --force, as the removed path is likely created as a result
+ # of previous copy/rename
+ self.run_svn(["rm", "--force", o[1]])
+ dirs_added = []
+ dirs_removed = []
+ files_added = []
+ files_removed = []
+ self.info(2, " Creating dirs and copying files...")
+ for i in sorted(self.items.keys()):
+ e = self.items[i]
+ nk_wc = e.state[S_WC]
+ nk_im = e.state[S_IM]
+ flg = None
+ if nk_wc == "-":
+ # Absent in working copy
+ if nk_im == "D":
+ # Directory added
+ os.mkdir(os.path.join(self.wcdir, i))
+ dirs_added.append(i)
+ flg = "(added dir)"
+ elif nk_im == "F":
+ # New file added
+ shutil.copyfile(os.path.join(self.importdir, i),
+ os.path.join(self.wcdir, i))
+ files_added.append(i)
+ flg = "(added file)"
+ else:
+ # Not in imported sources, not in WC (moved
+ # away/removed) - nothing to do
+ pass
+ elif nk_wc == "F":
+ # File in a working copy
+ if nk_im == "D":
+ # File replaced with a directory. See comment above.
+ self.run_svn(["rm", "--force", i])
+ os.mkdir(os.path.join(self.wcdir, i))
+ dirs_added.append(i)
+ flg = "(replaced file with dir)"
+ elif nk_im == "F":
+ # Was a file, is a file - just copy contents
+ shutil.copyfile(os.path.join(self.importdir, i),
+ os.path.join(self.wcdir, i))
+ flg = "(copied)"
+ else:
+ # Was a file, removed
+ files_removed.append(i)
+ flg = "(removed file)"
+ elif nk_wc == "D":
+ # Directory in a working copy
+ if nk_im == "D":
+ # Was a directory, is a directory - nothing to do
+ pass
+ elif nk_im == "F":
+ # Directory replaced with file. Need to remove dir
+ # immediately, as bulk removals/additions assume new files
+ # and dirs already in place.
+ self.run_svn(["rm", "--force", i])
+ shutil.copyfile(os.path.join(self.importdir, i),
+ os.path.join(self.wcdir, i))
+ files_added.append(i)
+ flg = "(replaced dir with file)"
+ else:
+ # Directory removed
+ dirs_removed.append(i)
+ flg = "(removed dir)"
+ if flg is not None:
+ self.info(4, " %s %s %s" % (e.status(), i, flg))
+ # Filter files/directories removed as a part of parent directory
+ files_removed = list(filter(lambda x: os.path.dirname(x) not in
+ dirs_removed, files_removed))
+ dirs_removed = list(filter(lambda x: os.path.dirname(x) not in
+ dirs_removed, dirs_removed))
+ files_added = list(filter(lambda x: os.path.dirname(x) not in
+ dirs_added, files_added))
+ dirs_added = list(filter(lambda x: os.path.dirname(x) not in
+ dirs_added, dirs_added))
+ self.info(2, " Running SVN add/rm commands");
+ if len(dirs_added):
+ self.run_svn(["add"], dirs_added)
+ if len(files_added):
+ self.run_svn(["add"], files_added)
+ if len(dirs_removed):
+ self.run_svn(["rm"], dirs_removed)
+ if len(files_removed):
+ self.run_svn(["rm"], files_removed)
+ # Save the diff for the copied/moved items
+ diff_save = self.config.get('save-diff-copied')
+ if diff_save is not None:
+ self.info(2, " Saving 'svn diff' on copied files/dirs to `%s'" %
+ diff_save)
+ to_be_diffed = list(filter(lambda x: os.path.dirname(x) not in
+ to_be_diffed, to_be_diffed))
+ if len(to_be_diffed):
+ try:
+ rv, out = self.run_svn(["diff"], to_be_diffed)
+ except UnicodeDecodeError:
+ # Some binary files not marked with appropriate MIME type,
+ # or broken text files
+ rv, out = (True, "WARNING: diff contained binary files\n")
+ else:
+ rv, out = (True, "")
+ if rv:
+ f = open(diff_save, "w")
+ f.write(out)
+ f.close()
+ # Exiting, as the resulting working copy can no longer be used
+ # for move analysis
+ self.info(1, "Done. Exiting; please examine the working copy " +
+ "and commit.")
+ return True
+
+ def do_similarity(self, arg):
+ '''
+ similarity SRD DST : estimate whether SRC could be potential source
+ for DST (0=no match, 1000=perfect match)
+ '''
+ src, dst = self.parse_args(arg, 2, "similarity")
+ sim = self.similar(src, dst)
+ if sim is not None:
+ print("Similarity between source `%s' and destination `%s': %4d" %
+ (src, dst, sim))
+
+ def do_set(self, arg):
+ '''
+ set : display current settings
+ set CFG VAL : set a config variable
+ '''
+ if arg.strip() == '':
+ self.config.print()
+ else:
+ cfg, val = self.parse_args(arg, 2, "set")
+ self.config.set(cfg, val)
+
+ def do_move(self, arg):
+ '''
+ move SRC DST : Perform a move from source to destination
+ '''
+ src, dst = self.parse_args(arg, 2, "move")
+ self.copy_or_move("mv", src, dst)
+
+ def do_copy(self, arg):
+ '''
+ copy SRC DST : Perform a copy from source to destination
+ '''
+ src, dst = self.parse_args(arg, 2, "copy")
+ self.copy_or_move("cp", src, dst)
+
+ def do_remove(self, arg):
+ '''
+ remove PATH : Remove a path
+ '''
+ path = self.parse_args(arg, 1, "remove")[0]
+ self.copy_or_move("rm", path)
+
+ def do_lsprep(self, arg):
+ '''
+ lsprep : List the currently recorded moves/copies/removals
+ '''
+ self.parse_args(arg, 0, "lsprep")
+ colsz = int((self.termwidth - 14) / 2)
+ if len(self.prepare_ops):
+ print("Currently recorded preparatory operations:")
+ print()
+ print("%5s %s %-*s %-*s" %
+ ("#", "Op", colsz, "Source", colsz, "Destination"))
+ for id, o in enumerate(self.prepare_ops):
+ if id % 10 == 0:
+ print("%5s %s %*s %*s" %
+ ("-"*5, "--", colsz, "-"*colsz, colsz, "-"*colsz))
+ if len(o) == 3:
+ print("%5d %s %-*s %-*s" %
+ (id, o[0], colsz, o[1], colsz, o[2]))
+ else:
+ print("%5d %s %-*s" % (id, o[0], colsz, o[1]))
+ print()
+ else:
+ print("No copies/moves/removals recorded")
+ print()
+
+ def do_save(self, arg):
+ '''
+ save FILENAME : Save current preparation operations to a file
+ '''
+ fn = self.parse_args(arg, 1, "save")[0]
+ f = open(fn, 'w')
+ longestname = 0
+ for o in self.prepare_ops:
+ if len(o[1]) > longestname:
+ longestname = len(o[1])
+ if len(o) == 3 and len(o[2]) > longestname:
+ longestname = len(o[2])
+ for o in self.prepare_ops:
+ if len(o) == 2:
+ f.write("svn %s %-*s\n" %
+ (o[0], longestname, shlex.quote(o[1])))
+ else:
+ f.write("svn %s %-*s %-*s\n" %
+ (o[0], longestname, shlex.quote(o[1]),
+ longestname, shlex.quote(o[2])))
+ pass
+ f.close()
+
+ def do_load(self, arg):
+ '''
+ load FILENAME : Load/append preparation operations from a file
+ '''
+ fn = self.parse_args(arg, 1, "load")[0]
+ self.info(1, "Performing operations from `%s'" % fn)
+ f = open(fn, 'r')
+ for l in f.readlines():
+ if l[0] == '#':
+ continue
+ args = shlex.split(l)
+ try:
+ if len(args) < 2 or args[0] != 'svn':
+ raise InvalidUsageException(None, "")
+ self.handle_op(args[1:])
+ except InvalidUsageException as e:
+ # Rethrow
+ raise InvalidUsageException(None,
+ "Invalid line in file: %s(%s)" % (l, e))
+ f.close()
+
+ def do_svninfo(self, arg):
+ '''
+ svninfo : Display SVN info on the working copy (debug)
+ '''
+ self.parse_args(arg, 0, "svninfo")
+ print(str(self.svninfo))
+
+ def do_printlst(self, arg):
+ '''
+ printlst WHAT : Print list of files; WHAT is one of {dir,file} (debug)
+ '''
+ self.parse_args(arg, 0, "printlst")
+ self.items.print()
+
+ def do_help(self, arg):
+ '''
+ help [COMMAND] : Print the help message
+ '''
+ cmd.Cmd.do_help(self, arg)
+
+ def do_EOF(self, arg):
+ '''
+ Quit the script
+ '''
+ return True
+
+ def do_quit(self, arg):
+ '''
+ quit : Quit the script
+ '''
+ return True
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(
+ description="Prepare a working copy for SVN vendor import.")
+ parser.add_argument('wcdir',
+ help="Path to working copy (destination of import)")
+ parser.add_argument('importdir',
+ help="Path to imported sources (source of import)")
+ grp = parser.add_mutually_exclusive_group()
+ grp.add_argument('--auto', action='store_true',
+ help="Automatic mode: detect moves, apply them and copy sources")
+ grp.add_argument('--detect', metavar='FILE',
+ help="Semi-automatic mode: detect moves and save them to FILE")
+ grp.add_argument('--apply', metavar='FILE',
+ help="Semi-automatic mode: apply the moves from FILE " +
+ "and copy the sources")
+ parser.add_argument('--save', metavar='FILE',
+ help="Automatic mode: save moves to FILE after detection, " +
+ "then proceed to apply the changes")
+ parser.add_argument('--config', metavar=('OPT','VALUE'), action='append',
+ nargs=2, help="Set configuration option OPT to VALUE")
+ args = parser.parse_args()
+ p = subprocess.Popen(args=['svn', 'info', args.wcdir],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ so, se = p.communicate()
+ if p.returncode != 0:
+ print("%s: does not appear to be SVN working copy." % args.wcdir)
+ print("`svn info' exited with status %d and returned:" % p.returncode)
+ print()
+ print(se.decode())
+ sys.exit(1)
+ imp = SvnVndImport(args.wcdir, args.importdir, so.decode())
+ if args.config:
+ try:
+ for o, v in args.config:
+ imp.config.set(o, v)
+ except InvalidUsageException as e:
+ parser.error(e)
+ imp.scan()
+ if args.auto:
+ imp.onecmd("detect")
+ if args.save:
+ imp.onecmd("save " + shlex.quote(args.save))
+ imp.onecmd("apply")
+ elif args.detect:
+ imp.onecmd("detect")
+ imp.onecmd("save " + shlex.quote(args.detect))
+ elif args.apply:
+ imp.onecmd("load " + shlex.quote(args.apply))
+ imp.onecmd("apply")
+ else:
+ imp.cmdloop()