Modified: subversion/branches/addremove/tools/hook-scripts/mailer/mailer.py URL: http://svn.apache.org/viewvc/subversion/branches/addremove/tools/hook-scripts/mailer/mailer.py?rev=1878061&r1=1878060&r2=1878061&view=diff ============================================================================== --- subversion/branches/addremove/tools/hook-scripts/mailer/mailer.py (original) +++ subversion/branches/addremove/tools/hook-scripts/mailer/mailer.py Sat May 23 14:16:56 2020 @@ -71,16 +71,10 @@ _MIN_SVN_VERSION = [1, 5, 0] # Import the Subversion Python bindings, making sure they meet our # minimum version requirements. -try: - import svn.fs - import svn.delta - import svn.repos - import svn.core -except ImportError: - sys.stderr.write( - "You need version %s or better of the Subversion Python bindings.\n" \ - % ".".join([str(x) for x in _MIN_SVN_VERSION])) - sys.exit(1) +import svn.fs +import svn.delta +import svn.repos +import svn.core if _MIN_SVN_VERSION > [svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR, svn.core.SVN_VER_PATCH]: @@ -129,7 +123,7 @@ def main(pool, cmd, config_fname, repos_ else: raise UnknownSubcommand(cmd) - messenger.generate() + return messenger.generate() def remove_leading_slashes(path): @@ -291,15 +285,73 @@ class SMTPOutput(MailedOutput): self.write(self.mail_headers(group, params)) def finish(self): - if self.cfg.is_set('general.smtp_ssl') and self.cfg.general.smtp_ssl == 'yes': - server = smtplib.SMTP_SSL(self.cfg.general.smtp_hostname) + """ + Send email via SMTP or SMTP_SSL, logging in if username is + specified. + + Errors such as invalid recipient, which affect a particular email, + are reported to stderr and raise MessageSendFailure. If the caller + has other emails to send, it may continue doing so. + + Errors caused by bad configuration, such as login failures, for + which too many occurrences could lead to SMTP server lockout, are + reported to stderr and re-raised. These should be considered fatal + (to minimize the chances of said lockout). + """ + + if self.cfg.is_set('general.smtp_port'): + smtp_port = self.cfg.general.smtp_port else: - server = smtplib.SMTP(self.cfg.general.smtp_hostname) - if self.cfg.is_set('general.smtp_username'): - server.login(self.cfg.general.smtp_username, - self.cfg.general.smtp_password) - server.sendmail(self.from_addr, self.to_addrs, self.buffer.getvalue()) - server.quit() + smtp_port = 0 + try: + if self.cfg.is_set('general.smtp_ssl') and self.cfg.general.smtp_ssl == 'yes': + server = smtplib.SMTP_SSL(self.cfg.general.smtp_hostname, smtp_port) + else: + server = smtplib.SMTP(self.cfg.general.smtp_hostname, smtp_port) + except Exception as detail: + sys.stderr.write("mailer.py: Failed to instantiate SMTP object: %s\n" % (detail,)) + # Any error to instantiate is fatal + raise + + try: + if self.cfg.is_set('general.smtp_username'): + try: + server.login(self.cfg.general.smtp_username, + self.cfg.general.smtp_password) + except smtplib.SMTPException as detail: + sys.stderr.write("mailer.py: SMTP login failed with username %s and/or password: %s\n" + % (self.cfg.general.smtp_username, detail,)) + # Any error at login is fatal + raise + + server.sendmail(self.from_addr, self.to_addrs, self.buffer.getvalue()) + + ### TODO: 'raise .. from' is Python 3+. When we convert this + ### script to Python 3, uncomment 'from detail' below + ### (2 instances): + + except smtplib.SMTPRecipientsRefused as detail: + sys.stderr.write("mailer.py: SMTP recipient(s) refused: %s: %s\n" + % (self.to_addrs, detail,)) + raise MessageSendFailure ### from detail + + except smtplib.SMTPSenderRefused as detail: + sys.stderr.write("mailer.py: SMTP sender refused: %s: %s\n" + % (self.from_addr, detail,)) + raise MessageSendFailure ### from detail + + except smtplib.SMTPException as detail: + # All other errors are fatal; this includes: + # SMTPHeloError, SMTPDataError, SMTPNotSupportedError + sys.stderr.write("mailer.py: SMTP error occurred: %s\n" % (detail,)) + raise + + finally: + try: + server.quit() + except smtplib.SMTPException as detail: + sys.stderr.write("mailer.py: Error occurred during SMTP session cleanup: %s\n" + % (detail,)) class StandardOutput(OutputBase): @@ -427,21 +479,26 @@ class Commit(Messenger): ### rather than rebuilding it each time. subpool = svn.core.svn_pool_create(self.pool) + ret = 0 # build a renderer, tied to our output stream renderer = TextCommitRenderer(self.output) for (group, param_tuple), (params, paths) in self.groups.items(): - self.output.start(group, params) - - # generate the content for this group and set of params - generate_content(renderer, self.cfg, self.repos, self.changelist, - group, params, paths, subpool) + try: + self.output.start(group, params) - self.output.finish() + # generate the content for this group and set of params + generate_content(renderer, self.cfg, self.repos, self.changelist, + group, params, paths, subpool) + + self.output.finish() + except MessageSendFailure: + ret = 1 svn.core.svn_pool_clear(subpool) svn.core.svn_pool_destroy(subpool) + return ret class PropChange(Messenger): @@ -462,35 +519,40 @@ class PropChange(Messenger): def generate(self): actions = { 'A': 'added', 'M': 'modified', 'D': 'deleted' } + ret = 0 for (group, param_tuple), params in self.groups.items(): - self.output.start(group, params) - self.output.write('Author: %s\n' - 'Revision: %s\n' - 'Property Name: %s\n' - 'Action: %s\n' - '\n' - % (self.author, self.repos.rev, self.propname, - actions.get(self.action, 'Unknown (\'%s\')' \ - % self.action))) - if self.action == 'A' or self.action not in actions: - self.output.write('Property value:\n') - propvalue = self.repos.get_rev_prop(self.propname) - self.output.write(propvalue) - elif self.action == 'M': - self.output.write('Property diff:\n') - tempfile1 = tempfile.NamedTemporaryFile() - tempfile1.write(sys.stdin.read()) - tempfile1.flush() - tempfile2 = tempfile.NamedTemporaryFile() - tempfile2.write(self.repos.get_rev_prop(self.propname)) - tempfile2.flush() - self.output.run(self.cfg.get_diff_cmd(group, { - 'label_from' : 'old property value', - 'label_to' : 'new property value', - 'from' : tempfile1.name, - 'to' : tempfile2.name, - })) - self.output.finish() + try: + self.output.start(group, params) + self.output.write('Author: %s\n' + 'Revision: %s\n' + 'Property Name: %s\n' + 'Action: %s\n' + '\n' + % (self.author, self.repos.rev, self.propname, + actions.get(self.action, 'Unknown (\'%s\')' \ + % self.action))) + if self.action == 'A' or self.action not in actions: + self.output.write('Property value:\n') + propvalue = self.repos.get_rev_prop(self.propname) + self.output.write(propvalue) + elif self.action == 'M': + self.output.write('Property diff:\n') + tempfile1 = tempfile.NamedTemporaryFile() + tempfile1.write(sys.stdin.read()) + tempfile1.flush() + tempfile2 = tempfile.NamedTemporaryFile() + tempfile2.write(self.repos.get_rev_prop(self.propname)) + tempfile2.flush() + self.output.run(self.cfg.get_diff_cmd(group, { + 'label_from' : 'old property value', + 'label_to' : 'new property value', + 'from' : tempfile1.name, + 'to' : tempfile2.name, + })) + self.output.finish() + except MessageSendFailure: + ret = 1 + return ret def get_commondir(dirlist): @@ -570,21 +632,26 @@ class Lock(Messenger): self.dirlist[0], self.pool) def generate(self): + ret = 0 for (group, param_tuple), (params, paths) in self.groups.items(): - self.output.start(group, params) - - self.output.write('Author: %s\n' - '%s paths:\n' % - (self.author, self.do_lock and 'Locked' or 'Unlocked')) - - self.dirlist.sort() - for dir in self.dirlist: - self.output.write(' %s\n\n' % dir) - - if self.do_lock: - self.output.write('Comment:\n%s\n' % (self.lock.comment or '')) + try: + self.output.start(group, params) - self.output.finish() + self.output.write('Author: %s\n' + '%s paths:\n' % + (self.author, self.do_lock and 'Locked' or 'Unlocked')) + + self.dirlist.sort() + for dir in self.dirlist: + self.output.write(' %s\n\n' % dir) + + if self.do_lock: + self.output.write('Comment:\n%s\n' % (self.lock.comment or '')) + + self.output.finish() + except MessageSendFailure: + ret = 1 + return ret class DiffSelections: @@ -1400,6 +1467,8 @@ class UnknownMappingSpec(Exception): pass class UnknownSubcommand(Exception): pass +class MessageSendFailure(Exception): + pass if __name__ == '__main__': @@ -1461,8 +1530,9 @@ if the property was added, modified or d if not os.path.exists(config_fname): raise MissingConfig(config_fname) - svn.core.run_app(main, cmd, config_fname, repos_dir, - sys.argv[3:3+expected_args]) + ret = svn.core.run_app(main, cmd, config_fname, repos_dir, + sys.argv[3:3+expected_args]) + sys.exit(1 if ret else 0) # ------------------------------------------------------------------------ # TODO
Modified: subversion/branches/addremove/tools/hook-scripts/validate-files.py URL: http://svn.apache.org/viewvc/subversion/branches/addremove/tools/hook-scripts/validate-files.py?rev=1878061&r1=1878060&r2=1878061&view=diff ============================================================================== --- subversion/branches/addremove/tools/hook-scripts/validate-files.py (original) +++ subversion/branches/addremove/tools/hook-scripts/validate-files.py Sat May 23 14:16:56 2020 @@ -19,7 +19,13 @@ """Subversion pre-commit hook script that runs user configured commands to validate files in the commit and reject the commit if the commands exit with a non-zero exit code. The script expects a validate-files.conf -file placed in the conf dir under the repo the commit is for.""" +file placed in the conf dir under the repo the commit is for. + +Note: As changed file paths $FILE are always represented as a Unicode (Py3) + or UTF-8 (Py2) strings, you might need to set apropriate locale and + PYTHONIOENCODING environment variable for this script and + commands to handle non-ascii path and command outputs, especially + you want to use svnlook cat command to inspect file contents.""" import sys import os @@ -30,11 +36,13 @@ import fnmatch try: # Python >= 3.0 import configparser + ConfigParser = configparser.ConfigParser except ImportError: # Python < 3.0 import ConfigParser as configparser + ConfigParser = configparser.SafeConfigParser -class Config(configparser.SafeConfigParser): +class Config(ConfigParser): """Superclass of SafeConfigParser with some customizations for this script""" def optionxform(self, option): @@ -80,18 +88,26 @@ class Commands: line = p.stdout.readline() if not line: break - line = line.decode().strip() + line = line.strip() text_mod = line[0:1] # Only if the contents of the file changed (by addition or update) # directories always end in / in the svnlook changed output - if line[-1] != "/" and (text_mod == "A" or text_mod == "U"): - changed.append(line[4:]) + if line[-1:] != b"/" and (text_mod == b"A" or text_mod == b"U"): + changed_path = line[4:] + if not isinstance(changed_path, str): + # svnlook always uses UTF-8 for internal path + changed_path = changed_path.decode('utf-8') + changed.append(changed_path) # wait on the command to finish so we can get the # returncode/stderr output data = p.communicate() if p.returncode != 0: - sys.stderr.write(data[1].decode()) + err_mesg = data[1] + if sys.stderr.encoding: + err_mesg =err_mesg.decode(sys.stderr.encoding, + 'backslashreplace') + sys.stderr.write(err_mesg) sys.exit(2) return changed @@ -109,7 +125,11 @@ class Commands: cmd_env['FILE'] = fn p = subprocess.Popen(cmd, shell=True, env=cmd_env, stderr=subprocess.PIPE) data = p.communicate() - return (p.returncode, data[1].decode()) + err_mesg = data[1] + if sys.stderr.encoding: + err_mesg = err_mesg.decode(sys.stderr.encoding, + 'backslashreplace') + return (p.returncode, err_mesg) def main(repo, txn): exitcode = 0 Modified: subversion/branches/addremove/tools/server-side/svn-backup-dumps.py URL: http://svn.apache.org/viewvc/subversion/branches/addremove/tools/server-side/svn-backup-dumps.py?rev=1878061&r1=1878060&r2=1878061&view=diff ============================================================================== --- subversion/branches/addremove/tools/server-side/svn-backup-dumps.py (original) +++ subversion/branches/addremove/tools/server-side/svn-backup-dumps.py Sat May 23 14:16:56 2020 @@ -377,38 +377,48 @@ class SvnBackup: return self.exec_cmd_unix(cmd, output, printerr) def exec_cmd_unix(self, cmd, output=None, printerr=False): + if printerr: + if sys.hexversion >= 0x3000000: + sys.stdout.flush() + errout = sys.stdout.buffer + else: + errout = sys.stdout + else: + errout = PIPE try: - proc = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=False) + proc = Popen(cmd, stdout=PIPE, stderr=errout, shell=False) except: return (256, "", "Popen failed (%s ...):\n %s" % (cmd[0], str(sys.exc_info()[1]))) - stdout = proc.stdout - stderr = proc.stderr - self.set_nonblock(stdout) - self.set_nonblock(stderr) - readfds = [ stdout, stderr ] - selres = select.select(readfds, [], []) - bufout = "" - buferr = "" - while len(selres[0]) > 0: - for fd in selres[0]: - buf = fd.read(16384) - if len(buf) == 0: - readfds.remove(fd) - elif fd == stdout: - if output: + if output is None: + bufout, buferr = proc.communicate() + rc = proc.returncode + if buferr is None: + buferr = b"" + else: + stdout = proc.stdout + self.set_nonblock(stdout) + readfds = [ stdout ] + if not printerr: + stderr = proc.stderr + self.set_nonblock(stderr) + readfds.append(stderr) + selres = select.select(readfds, [], []) + bufout = b"" + buferr = b"" + while len(selres[0]) > 0: + for fd in selres[0]: + buf = fd.read(16384) + if len(buf) == 0: + readfds.remove(fd) + elif fd == stdout: output.write(buf) else: - bufout += buf - else: - if printerr: - sys.stdout.write("%s " % buf) - else: buferr += buf - if len(readfds) == 0: - break - selres = select.select(readfds, [], []) - rc = proc.wait() + if len(readfds) == 0: + break + selres = select.select(readfds, [], []) + rc = proc.wait() if printerr: print("") return (rc, bufout, buferr) @@ -420,8 +430,8 @@ class SvnBackup: return (256, "", "Popen failed (%s ...):\n %s" % (cmd[0], str(sys.exc_info()[1]))) stdout = proc.stdout - bufout = "" - buferr = "" + bufout = b"" + buferr = b"" buf = stdout.read(16384) while len(buf) > 0: if output: Modified: subversion/branches/addremove/tools/server-side/svnauthz.c URL: http://svn.apache.org/viewvc/subversion/branches/addremove/tools/server-side/svnauthz.c?rev=1878061&r1=1878060&r2=1878061&view=diff ============================================================================== --- subversion/branches/addremove/tools/server-side/svnauthz.c (original) +++ subversion/branches/addremove/tools/server-side/svnauthz.c Sat May 23 14:16:56 2020 @@ -31,6 +31,7 @@ #include "private/svn_fspath.h" #include "private/svn_cmdline_private.h" +#include "svn_private_config.h" /*** Option Processing. ***/ @@ -99,6 +100,9 @@ struct svnauthz_opt_state /* Libtool command prefix */ #define SVNAUTHZ_LT_PREFIX "lt-" +/* The prefix for handling errors and warnings. */ +#define SVNAUTHZ_ERR_PREFIX "svnauthz: " + /*** Subcommands. */ @@ -110,29 +114,34 @@ static svn_opt_subcommand_t /* Array of available subcommands. * The entire list must be terminated with an entry of nulls. */ -static const svn_opt_subcommand_desc2_t cmd_table[] = +static const svn_opt_subcommand_desc3_t cmd_table[] = { - {"help", subcommand_help, {"?", "h"}, - ("usage: svnauthz help [SUBCOMMAND...]\n\n" - "Describe the usage of this program or its subcommands.\n"), + {"help", subcommand_help, {"?", "h"}, {( + "usage: svnauthz help [SUBCOMMAND...]\n" + "\n" + "Describe the usage of this program or its subcommands.\n" + )}, {0} }, - {"validate", subcommand_validate, {0} /* no aliases */, - ("Checks the syntax of an authz file.\n" + {"validate", subcommand_validate, {0} /* no aliases */, {( + "Checks the syntax of an authz file.\n" "usage: 1. svnauthz validate TARGET\n" - " 2. svnauthz validate --transaction TXN REPOS_PATH FILE_PATH\n\n" + " 2. svnauthz validate --transaction TXN REPOS_PATH FILE_PATH\n" + "\n" " 1. Loads and validates the syntax of the authz file at TARGET.\n" " TARGET can be a path to a file or an absolute file:// URL to an authz\n" - " file in a repository, but cannot be a repository relative URL (^/).\n\n" + " file in a repository, but cannot be a repository relative URL (^/).\n" + "\n" " 2. Loads and validates the syntax of the authz file at FILE_PATH in the\n" - " transaction TXN in the repository at REPOS_PATH.\n\n" + " transaction TXN in the repository at REPOS_PATH.\n" + "\n" "Returns:\n" " 0 when syntax is OK.\n" " 1 when syntax is invalid.\n" " 2 operational error\n" - ), + )}, {'t'} }, - {"accessof", subcommand_accessof, {0} /* no aliases */, - ("Print or test the permissions set by an authz file.\n" + {"accessof", subcommand_accessof, {0} /* no aliases */, {( + "Print or test the permissions set by an authz file.\n" "usage: 1. svnauthz accessof TARGET\n" " 2. svnauthz accessof -t TXN REPOS_PATH FILE_PATH\n" "\n" @@ -159,10 +168,10 @@ static const svn_opt_subcommand_desc2_t " 1 when syntax is invalid.\n" " 2 operational error\n" " 3 when '--is' argument doesn't match\n" - ), + )}, {'t', svnauthz__username, svnauthz__path, svnauthz__repos, svnauthz__is, svnauthz__groups_file, 'R'} }, - { NULL, NULL, {0}, NULL, {0} } + { NULL, NULL, {0}, {NULL}, {0} } }; static svn_error_t * @@ -171,11 +180,14 @@ subcommand_help(apr_getopt_t *os, void * struct svnauthz_opt_state *opt_state = baton; const char *header = ("general usage: svnauthz SUBCOMMAND TARGET [ARGS & OPTIONS ...]\n" - " " SVNAUTHZ_COMPAT_NAME " TARGET\n\n" + " " SVNAUTHZ_COMPAT_NAME " TARGET\n" + "\n" "If the command name starts with '" SVNAUTHZ_COMPAT_NAME "', runs in\n" - "pre-1.8 compatibility mode: run the 'validate' subcommand on TARGET.\n\n" + "pre-1.8 compatibility mode: run the 'validate' subcommand on TARGET.\n" + "\n" "Type 'svnauthz help <subcommand>' for help on a specific subcommand.\n" - "Type 'svnauthz --version' to see the program version.\n\n" + "Type 'svnauthz --version' to see the program version.\n" + "\n" "Available subcommands:\n"); const char *fs_desc_start @@ -186,7 +198,7 @@ subcommand_help(apr_getopt_t *os, void * version_footer = svn_stringbuf_create(fs_desc_start, pool); SVN_ERR(svn_fs_print_modules(version_footer, pool)); - SVN_ERR(svn_opt_print_help4(os, "svnauthz", + SVN_ERR(svn_opt_print_help5(os, "svnauthz", opt_state ? opt_state->version : FALSE, FALSE, /* quiet */ FALSE, /* verbose */ @@ -216,6 +228,18 @@ read_file_contents(svn_stream_t **conten return SVN_NO_ERROR; } +/* Handles warning emitted by the authz parser. */ +static void +handle_parser_warning(void *baton, + const svn_error_t *err, + apr_pool_t *scratch_pool) +{ + svn_handle_warning2(stderr, err, SVNAUTHZ_ERR_PREFIX); + SVN_UNUSED(baton); + SVN_UNUSED(scratch_pool); +} + + /* Loads the authz config into *AUTHZ from the file at AUTHZ_FILE in repository at REPOS_PATH from the transaction TXN_NAME. If GROUPS_FILE is set, the resulting *AUTHZ will be constructed from AUTHZ_FILE with @@ -248,7 +272,8 @@ get_authz_from_txn(svn_authz_t **authz, else groups_contents = NULL; - err = svn_repos_authz_parse(authz, authz_contents, groups_contents, pool); + err = svn_repos_authz_parse2(authz, authz_contents, groups_contents, + handle_parser_warning, NULL, pool, pool); /* Add the filename to the error stack since the parser doesn't have it. */ if (err != SVN_NO_ERROR) @@ -275,9 +300,11 @@ get_authz(svn_authz_t **authz, struct sv opt_state->txn, pool); /* Else */ - return svn_repos_authz_read3(authz, opt_state->authz_file, + return svn_repos_authz_read4(authz, opt_state->authz_file, opt_state->groups_file, - TRUE, NULL, pool, pool); + TRUE, NULL, + handle_parser_warning, NULL, + pool, pool); } static svn_error_t * @@ -387,7 +414,12 @@ subcommand_accessof(apr_getopt_t *os, vo static svn_boolean_t use_compat_mode(const char *cmd, apr_pool_t *pool) { - cmd = svn_dirent_internal_style(cmd, pool); + svn_error_t *err = svn_dirent_internal_style_safe(&cmd, NULL, cmd, pool, pool); + if (err) + { + svn_error_clear(err); + return FALSE; + } cmd = svn_dirent_basename(cmd, NULL); /* Skip over the Libtool command prefix if it exists on the command. */ @@ -429,7 +461,9 @@ canonicalize_access_file(const char **ca access_file); } - *canonicalized_access_file = svn_uri_canonicalize(access_file, pool); + SVN_ERR(svn_uri_canonicalize_safe( + canonicalized_access_file, NULL, + access_file, pool, pool)); } else if (within_txn) { @@ -442,8 +476,9 @@ canonicalize_access_file(const char **ca { /* If it isn't a URL and there's no transaction flag then it's a * dirent to the access file on local disk. */ - *canonicalized_access_file = - svn_dirent_internal_style(access_file, pool); + SVN_ERR(svn_dirent_internal_style_safe( + canonicalized_access_file, NULL, + access_file, pool, pool)); } return SVN_NO_ERROR; @@ -459,7 +494,7 @@ sub_main(int *exit_code, int argc, const { svn_error_t *err; - const svn_opt_subcommand_desc2_t *subcommand = NULL; + const svn_opt_subcommand_desc3_t *subcommand = NULL; struct svnauthz_opt_state opt_state = { 0 }; apr_getopt_t *os; apr_array_header_t *received_opts; @@ -545,9 +580,9 @@ sub_main(int *exit_code, int argc, const { /* Pre 1.8 compatibility mode. */ if (argc == 1) /* No path argument */ - subcommand = svn_opt_get_canonical_subcommand2(cmd_table, "help"); + subcommand = svn_opt_get_canonical_subcommand3(cmd_table, "help"); else - subcommand = svn_opt_get_canonical_subcommand2(cmd_table, "validate"); + subcommand = svn_opt_get_canonical_subcommand3(cmd_table, "validate"); } /* If the user asked for help, then the rest of the arguments are @@ -555,7 +590,7 @@ sub_main(int *exit_code, int argc, const just typos/mistakes. Whatever the case, the subcommand to actually run is subcommand_help(). */ if (opt_state.help) - subcommand = svn_opt_get_canonical_subcommand2(cmd_table, "help"); + subcommand = svn_opt_get_canonical_subcommand3(cmd_table, "help"); if (subcommand == NULL) { @@ -564,8 +599,8 @@ sub_main(int *exit_code, int argc, const if (opt_state.version) { /* Use the "help" subcommand to handle the "--version" option. */ - static const svn_opt_subcommand_desc2_t pseudo_cmd = - { "--version", subcommand_help, {0}, "", + static const svn_opt_subcommand_desc3_t pseudo_cmd = + { "--version", subcommand_help, {0}, {""}, {svnauthz__version /* must accept its own option */ } }; subcommand = &pseudo_cmd; @@ -585,7 +620,7 @@ sub_main(int *exit_code, int argc, const SVN_ERR(svn_utf_cstring_to_utf8(&first_arg, os->argv[os->ind++], pool)); - subcommand = svn_opt_get_canonical_subcommand2(cmd_table, first_arg); + subcommand = svn_opt_get_canonical_subcommand3(cmd_table, first_arg); if (subcommand == NULL) { os->ind++; @@ -618,7 +653,9 @@ sub_main(int *exit_code, int argc, const pool)); os->ind++; - opt_state.repos_path = svn_dirent_internal_style(opt_state.repos_path, pool); + SVN_ERR(svn_dirent_internal_style_safe(&opt_state.repos_path, NULL, + opt_state.repos_path, + pool, pool)); } /* Exactly 1 non-option argument */ @@ -658,11 +695,11 @@ sub_main(int *exit_code, int argc, const if (opt_id == 'h' || opt_id == '?') continue; - if (! svn_opt_subcommand_takes_option3(subcommand, opt_id, NULL)) + if (! svn_opt_subcommand_takes_option4(subcommand, opt_id, NULL)) { const char *optstr; const apr_getopt_option_t *badopt = - svn_opt_get_option_from_code2(opt_id, options_table, subcommand, + svn_opt_get_option_from_code3(opt_id, options_table, subcommand, pool); svn_opt_format_option(&optstr, badopt, FALSE, pool); if (subcommand->name[0] == '-') @@ -737,7 +774,7 @@ main(int argc, const char *argv[]) { if (exit_code == 0) exit_code = EXIT_FAILURE; - svn_cmdline_handle_exit_error(err, NULL, "svnauthz: "); + svn_cmdline_handle_exit_error(err, NULL, SVNAUTHZ_ERR_PREFIX); } svn_pool_destroy(pool); Modified: subversion/branches/addremove/tools/server-side/svnpubsub/svnwcsub.py URL: http://svn.apache.org/viewvc/subversion/branches/addremove/tools/server-side/svnpubsub/svnwcsub.py?rev=1878061&r1=1878060&r2=1878061&view=diff ============================================================================== --- subversion/branches/addremove/tools/server-side/svnpubsub/svnwcsub.py (original) +++ subversion/branches/addremove/tools/server-side/svnpubsub/svnwcsub.py Sat May 23 14:16:56 2020 @@ -32,7 +32,7 @@ # TODO: # - bulk update at startup time to avoid backlog warnings -# - fold BDEC into Daemon +# - fold BigDoEverythingClasss ("BDEC") into Daemon # - fold WorkingCopy._get_match() into __init__ # - remove wc_ready(). assume all WorkingCopy instances are usable. # place the instances into .watch at creation. the .update_applies()