diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-08-05 16:22:51 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-08-05 16:22:51 +0000 |
commit | cf46733632c7279a9fd0fe6ce26f9185a4ae82a9 (patch) | |
tree | da27775a2161723ef342e91af41a8b51fedef405 /tools/client-side | |
parent | bb0ef45f7c46b0ae221b26265ef98a768c33f820 (diff) | |
download | subversion-tarball-master.tar.gz |
subversion-1.9.7HEADsubversion-1.9.7master
Diffstat (limited to 'tools/client-side')
-rw-r--r-- | tools/client-side/bash_completion | 49 | ||||
-rwxr-xr-x | tools/client-side/bash_completion_test | 8 | ||||
-rwxr-xr-x | tools/client-side/showchange.pl | 66 | ||||
-rw-r--r-- | tools/client-side/svn-bench/cl.h | 198 | ||||
-rw-r--r-- | tools/client-side/svn-bench/client_errors.h | 97 | ||||
-rw-r--r-- | tools/client-side/svn-bench/help-cmd.c | 94 | ||||
-rw-r--r-- | tools/client-side/svn-bench/notify.c | 1045 | ||||
-rw-r--r-- | tools/client-side/svn-bench/null-export-cmd.c | 346 | ||||
-rw-r--r-- | tools/client-side/svn-bench/null-list-cmd.c | 169 | ||||
-rw-r--r-- | tools/client-side/svn-bench/null-log-cmd.c | 243 | ||||
-rw-r--r-- | tools/client-side/svn-bench/svn-bench.c | 954 | ||||
-rw-r--r-- | tools/client-side/svn-bench/util.c | 92 | ||||
-rwxr-xr-x | tools/client-side/svn-graph.pl | 17 | ||||
-rwxr-xr-x | tools/client-side/svn-ssl-fingerprints.sh | 2 | ||||
-rwxr-xr-x | tools/client-side/svn-vendor.py | 1065 |
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() |