diff options
Diffstat (limited to 'subversion/svnsync/svnsync.c')
-rw-r--r-- | subversion/svnsync/svnsync.c | 131 |
1 files changed, 64 insertions, 67 deletions
diff --git a/subversion/svnsync/svnsync.c b/subversion/svnsync/svnsync.c index 6dde1f108866..9f50897273a4 100644 --- a/subversion/svnsync/svnsync.c +++ b/subversion/svnsync/svnsync.c @@ -43,7 +43,6 @@ #include "svn_private_config.h" -#include <apr_signal.h> #include <apr_uuid.h> static svn_opt_subcommand_t initialize_cmd, @@ -71,6 +70,7 @@ enum svnsync__opt { svnsync_opt_trust_server_cert_failures_src, svnsync_opt_trust_server_cert_failures_dst, svnsync_opt_allow_non_empty, + svnsync_opt_skip_unchanged, svnsync_opt_steal_lock }; @@ -148,9 +148,14 @@ static const svn_opt_subcommand_desc2_t svnsync_cmd_table[] = "if untrusted users/administrators may have write access to the\n" "DEST_URL repository.\n" "\n" + "Unless you need to trigger the destination repositoy's revprop\n" + "change hooks for all revision properties, it is recommended to use\n" + "the --skip-unchanged option for best performance.\n" + "\n" "Form 2 is deprecated syntax, equivalent to specifying \"-rREV[:REV2]\".\n"), { SVNSYNC_OPTS_DEFAULT, svnsync_opt_source_prop_encoding, 'q', 'r', - svnsync_opt_disable_locking, svnsync_opt_steal_lock, 'M' } }, + svnsync_opt_disable_locking, svnsync_opt_steal_lock, + svnsync_opt_skip_unchanged, 'M' } }, { "info", info_cmd, { 0 }, N_("usage: svnsync info DEST_URL\n" "\n" @@ -179,6 +184,8 @@ static const apr_getopt_option_t svnsync_options[] = " 'HEAD' latest in repository") }, {"allow-non-empty", svnsync_opt_allow_non_empty, 0, N_("allow a non-empty destination repository") }, + {"skip-unchanged", svnsync_opt_skip_unchanged, 0, + N_("don't copy unchanged revision properties") }, {"non-interactive", svnsync_opt_non_interactive, 0, N_("do no interactive prompting (default is to prompt\n" " " @@ -303,6 +310,7 @@ typedef struct opt_baton_t { svn_boolean_t steal_lock; svn_boolean_t quiet; svn_boolean_t allow_non_empty; + svn_boolean_t skip_unchanged; svn_boolean_t version; svn_boolean_t help; svn_opt_revision_t start_rev; @@ -315,29 +323,8 @@ typedef struct opt_baton_t { /*** Helper functions ***/ -/* Global record of whether the user has requested cancellation. */ -static volatile sig_atomic_t cancelled = FALSE; - - -/* Callback function for apr_signal(). */ -static void -signal_handler(int signum) -{ - apr_signal(signum, SIG_IGN); - cancelled = TRUE; -} - - /* Cancellation callback function. */ -static svn_error_t * -check_cancel(void *baton) -{ - if (cancelled) - return svn_error_create(SVN_ERR_CANCELLED, NULL, _("Caught signal")); - else - return SVN_NO_ERROR; -} - +static svn_cancel_func_t check_cancel = 0; /* Check that the version of libraries in use match what we expect. */ static svn_error_t * @@ -422,6 +409,7 @@ typedef struct subcommand_baton_t { svn_ra_callbacks2_t sync_callbacks; svn_boolean_t quiet; svn_boolean_t allow_non_empty; + svn_boolean_t skip_unchanged; /* Enable optimization for revprop changes. */ const char *to_url; /* initialize, synchronize, and copy-revprops only */ @@ -592,6 +580,10 @@ filter_props(int *filtered_count, apr_hash_t *props, * and set *FILTERED_COUNT to the number of properties thus omitted. * REV_PROPS is a hash mapping (char *)propname to (svn_string_t *)propval. * + * If OLD_REV_PROPS is not NULL, skip all properties that did not change. + * Note that this implies that hook scripts won't be triggered anymore for + * those revprops that did not change. + * * All allocations will be done in a subpool of POOL. */ static svn_error_t * @@ -599,6 +591,7 @@ write_revprops(int *filtered_count, svn_ra_session_t *session, svn_revnum_t rev, apr_hash_t *rev_props, + apr_hash_t *old_rev_props, apr_pool_t *pool) { apr_pool_t *subpool = svn_pool_create(pool); @@ -616,6 +609,17 @@ write_revprops(int *filtered_count, if (strncmp(propname, SVNSYNC_PROP_PREFIX, sizeof(SVNSYNC_PROP_PREFIX) - 1) != 0) { + if (old_rev_props) + { + /* Skip the RA call for any no-op propset. */ + const svn_string_t *old_value = svn_hash_gets(old_rev_props, + propname); + if ((!old_value && !propval) + || (old_value && propval + && svn_string_compare(old_value, propval))) + continue; + } + SVN_ERR(svn_ra_change_rev_prop2(session, rev, propname, NULL, propval, subpool)); } @@ -677,6 +681,10 @@ log_properties_normalized(int normalized_rev_props_count, * If SYNC is TRUE, then properties on the destination revision that * do not exist on the source revision will be removed. * + * If SKIP_UNCHANGED is TRUE, skip any no-op revprop changes. This also + * prevents hook scripts from firing for those unchanged revprops. Has + * no effect if SYNC is FALSE. + * * If QUIET is FALSE, then log_properties_copied() is called to log that * properties were copied for revision REV. * @@ -689,6 +697,7 @@ copy_revprops(svn_ra_session_t *from_session, svn_ra_session_t *to_session, svn_revnum_t rev, svn_boolean_t sync, + svn_boolean_t skip_unchanged, svn_boolean_t quiet, const char *source_prop_encoding, int *normalized_count, @@ -714,7 +723,8 @@ copy_revprops(svn_ra_session_t *from_session, source_prop_encoding, pool)); /* Copy all but the svn:svnsync properties. */ - SVN_ERR(write_revprops(&filtered_count, to_session, rev, rev_props, pool)); + SVN_ERR(write_revprops(&filtered_count, to_session, rev, rev_props, + skip_unchanged ? existing_props : NULL, pool)); /* Delete those properties that were in TARGET but not in SOURCE */ if (sync) @@ -750,6 +760,7 @@ make_subcommand_baton(opt_baton_t *opt_baton, b->sync_callbacks.open_tmp_file = open_tmp_file; b->sync_callbacks.auth_baton = opt_baton->sync_auth_baton; b->quiet = opt_baton->quiet; + b->skip_unchanged = opt_baton->skip_unchanged; b->allow_non_empty = opt_baton->allow_non_empty; b->to_url = to_url; b->source_prop_encoding = opt_baton->source_prop_encoding; @@ -859,9 +870,9 @@ do_initialize(svn_ra_session_t *to_session, LATEST is not 0, this really serves merely aesthetic and informational purposes, keeping the output of this command consistent while allowing folks to see what the latest revision is. */ - SVN_ERR(copy_revprops(from_session, to_session, latest, FALSE, baton->quiet, - baton->source_prop_encoding, &normalized_rev_props_count, - pool)); + SVN_ERR(copy_revprops(from_session, to_session, latest, FALSE, FALSE, + baton->quiet, baton->source_prop_encoding, + &normalized_rev_props_count, pool)); SVN_ERR(log_properties_normalized(normalized_rev_props_count, 0, pool)); @@ -1372,7 +1383,7 @@ replay_rev_finished(svn_revnum_t revision, rb->normalized_rev_props_count += normalized_count; SVN_ERR(write_revprops(&filtered_count, rb->to_session, revision, filtered, - subpool)); + NULL, subpool)); /* Remove all extra properties in TARGET. */ SVN_ERR(remove_props_not_in_source(rb->to_session, revision, @@ -1478,7 +1489,8 @@ do_synchronize(svn_ra_session_t *to_session, if (copying > last_merged) { SVN_ERR(copy_revprops(from_session, to_session, to_latest, TRUE, - baton->quiet, baton->source_prop_encoding, + baton->skip_unchanged, baton->quiet, + baton->source_prop_encoding, &normalized_rev_props_count, pool)); last_merged = copying; last_merged_rev = svn_string_create @@ -1515,7 +1527,7 @@ do_synchronize(svn_ra_session_t *to_session, /* Now check to see if there are any revisions to copy. */ SVN_ERR(svn_ra_get_latest_revnum(from_session, &from_latest, pool)); - if (from_latest < last_merged) + if (from_latest <= last_merged) return SVN_NO_ERROR; /* Ok, so there are new revisions, iterate over them copying them @@ -1649,7 +1661,8 @@ do_copy_revprops(svn_ra_session_t *to_session, { int normalized_count; SVN_ERR(check_cancel(NULL)); - SVN_ERR(copy_revprops(from_session, to_session, i, TRUE, baton->quiet, + SVN_ERR(copy_revprops(from_session, to_session, i, TRUE, + baton->skip_unchanged, baton->quiet, baton->source_prop_encoding, &normalized_count, pool)); normalized_rev_props_count += normalized_count; @@ -1757,12 +1770,12 @@ copy_revprops_cmd(apr_getopt_t *os, void *b, apr_pool_t *pool) the source URL. */ if (os->argc - os->ind == 2) { - const char *arg_str = os->argv[os->argc - 1]; - const char *utf_arg_str; + const char *arg_str; - SVN_ERR(svn_utf_cstring_to_utf8(&utf_arg_str, arg_str, pool)); + SVN_ERR(svn_utf_cstring_to_utf8(&arg_str, os->argv[os->argc - 1], + pool)); - if (! svn_path_is_url(utf_arg_str)) + if (! svn_path_is_url(arg_str)) { /* This is the old "... TO_URL REV[:REV2]" syntax. Revisions come only from this argument. (We effectively @@ -2068,11 +2081,11 @@ sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool) case svnsync_opt_config_dir: { - const char *path_utf8; - opt_err = svn_utf_cstring_to_utf8(&path_utf8, opt_arg, pool); + const char *path; + opt_err = svn_utf_cstring_to_utf8(&path, opt_arg, pool); if (!opt_err) - opt_baton.config_dir = svn_dirent_internal_style(path_utf8, pool); + opt_baton.config_dir = svn_dirent_internal_style(path, pool); } break; case svnsync_opt_config_options: @@ -2108,6 +2121,10 @@ sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool) opt_baton.allow_non_empty = TRUE; break; + case svnsync_opt_skip_unchanged: + opt_baton.skip_unchanged = TRUE; + break; + case 'q': opt_baton.quiet = TRUE; break; @@ -2269,7 +2286,10 @@ sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool) } else { - const char *first_arg = os->argv[os->ind++]; + const char *first_arg; + + SVN_ERR(svn_utf_cstring_to_utf8(&first_arg, os->argv[os->ind++], + pool)); subcommand = svn_opt_get_canonical_subcommand2(svnsync_cmd_table, first_arg); if (subcommand == NULL) @@ -2324,33 +2344,7 @@ sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool) opt_baton.source_prop_encoding = source_prop_encoding; - 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 + check_cancel = svn_cmdline__setup_cancellation_handler(); err = svn_cmdline_create_auth_baton2( &opt_baton.source_auth_baton, @@ -2431,5 +2425,8 @@ main(int argc, const char *argv[]) } svn_pool_destroy(pool); + + svn_cmdline__cancellation_exit(); + return exit_code; } |