Modified: subversion/branches/multi-wc-format/tools/hook-scripts/mailer/mailer.py URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/hook-scripts/mailer/mailer.py?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/tools/hook-scripts/mailer/mailer.py (original) +++ subversion/branches/multi-wc-format/tools/hook-scripts/mailer/mailer.py Fri Jan 14 14:01:45 2022 @@ -46,25 +46,21 @@ import os import sys -try: - # Python >=3.0 +if sys.hexversion >= 0x3000000: + PY3 = True import configparser - from urllib.parse import quote as urllib_parse_quote -except ImportError: - # Python <3.0 + from urllib.parse import quote as _url_quote +else: + PY3 = False import ConfigParser as configparser - from urllib import quote as urllib_parse_quote + from urllib import quote as _url_quote import time import subprocess -if sys.version_info[0] >= 3: - # Python >=3.0 - from io import StringIO -else: - # Python <3.0 - from cStringIO import StringIO +from io import BytesIO import smtplib import re import tempfile +import codecs # Minimal version of Subversion's bindings required _MIN_SVN_VERSION = [1, 5, 0] @@ -83,6 +79,28 @@ if _MIN_SVN_VERSION > [svn.core.SVN_VER_ % ".".join([str(x) for x in _MIN_SVN_VERSION])) sys.exit(1) +# Absorb difference between Python 2 and Python >= 3 +if PY3: + def to_bytes(x): + return x.encode('utf-8') + + def to_str(x): + return x.decode('utf-8') + + # We never use sys.stdin nor sys.stdout TextIOwrapper. + _stdin = sys.stdin.buffer + _stdout = sys.stdout.buffer +else: + # Python 2 + def to_bytes(x): + return x + + def to_str(x): + return x + + _stdin = sys.stdin + _stdout = sys.stdout + SEPARATOR = '=' * 78 @@ -101,7 +119,10 @@ def main(pool, cmd, config_fname, repos_ revision = int(cmd_args[0]) author = cmd_args[1] propname = cmd_args[2] - action = (cmd == 'propchange2' and cmd_args[3] or 'A') + if cmd == 'propchange2' and cmd_args[3]: + action = cmd_args[3] + else: + action = 'A' repos = Repository(repos_dir, revision, pool) # Override the repos revision author with the author of the propchange repos.author = author @@ -123,11 +144,11 @@ def main(pool, cmd, config_fname, repos_ else: raise UnknownSubcommand(cmd) - messenger.generate() + return messenger.generate() def remove_leading_slashes(path): - while path and path[0] == '/': + while path and path[0:1] == b'/': path = path[1:] return path @@ -158,8 +179,16 @@ class OutputBase: except ValueError: truncate_subject = 0 - if truncate_subject and len(subject) > truncate_subject: - subject = subject[:(truncate_subject - 3)] + "..." + # truncate subject as UTF-8 string. + # Note: there still exists an issue on combining characters. + if truncate_subject: + bsubject = to_bytes(subject) + if len(bsubject) > truncate_subject: + idx = truncate_subject - 2 + while b'\x80' <= bsubject[idx-1:idx] <= b'\xbf': + idx -= 1 + subject = to_str(bsubject[:idx-1]) + "..." + return subject def start(self, group, params): @@ -177,11 +206,15 @@ class OutputBase: representation.""" raise NotImplementedError - def write(self, output): + def write_binary(self, output): """Override this method. - Append the literal text string OUTPUT to the output representation.""" + Append the binary data OUTPUT to the output representation.""" raise NotImplementedError + def write(self, output): + """Append the literal text string OUTPUT to the output representation.""" + return self.write_binary(to_bytes(output)) + def run(self, cmd): """Override this method, if the default implementation is not sufficient. Execute CMD, writing the stdout produced to the output representation.""" @@ -192,7 +225,7 @@ class OutputBase: buf = pipe_ob.stdout.read(self._CHUNKSIZE) while buf: - self.write(buf) + self.write_binary(buf) buf = pipe_ob.stdout.read(self._CHUNKSIZE) # wait on the child so we don't end up with a billion zombies @@ -234,7 +267,7 @@ class MailedOutput(OutputBase): # Return the result of splitting HDR into tokens (on space # characters), encoding (per RFC2047) each token as necessary, and # slapping 'em back to together again. - from email.Header import Header + from email.header import Header def _maybe_encode_header(hdr_token): try: @@ -246,7 +279,7 @@ class MailedOutput(OutputBase): return ' '.join(map(_maybe_encode_header, hdr.split())) def mail_headers(self, group, params): - from email import Utils + from email import utils subject = self._rfc2047_encode(self.make_subject(group, params)) from_hdr = self._rfc2047_encode(self.from_addr) @@ -265,7 +298,7 @@ class MailedOutput(OutputBase): 'X-Svn-Commit-Revision: %d\n' \ 'X-Svn-Commit-Repository: %s\n' \ % (from_hdr, to_hdr, subject, - Utils.formatdate(), Utils.make_msgid(), group, + utils.formatdate(), utils.make_msgid(), group, self.repos.author or 'no_author', self.repos.rev, os.path.basename(self.repos.repos_dir)) if self.reply_to: @@ -279,21 +312,79 @@ class SMTPOutput(MailedOutput): def start(self, group, params): MailedOutput.start(self, group, params) - self.buffer = StringIO() - self.write = self.buffer.write + self.buffer = BytesIO() + self.write_binary = self.buffer.write 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): @@ -301,7 +392,7 @@ class StandardOutput(OutputBase): def __init__(self, cfg, repos, prefix_param): OutputBase.__init__(self, cfg, repos, prefix_param) - self.write = sys.stdout.write + self.write_binary = _stdout.write def start(self, group, params): self.write("Group: " + (group or "defaults") + "\n") @@ -310,6 +401,12 @@ class StandardOutput(OutputBase): def finish(self): pass + if (PY3 and (codecs.lookup(sys.stdout.encoding) != codecs.lookup('utf-8'))): + def write(self, output): + """Write text as *default* encoding string""" + return self.write_binary(output.encode(sys.stdout.encoding, + 'backslashreplace')) + class PipeOutput(MailedOutput): "Deliver a mail message to an MTA via a pipe." @@ -330,7 +427,7 @@ class PipeOutput(MailedOutput): # construct the pipe for talking to the mailer self.pipe = subprocess.Popen(cmd, stdin=subprocess.PIPE, close_fds=sys.platform != "win32") - self.write = self.pipe.stdin.write + self.write_binary = self.pipe.stdin.write # start writing out the mail message self.write(self.mail_headers(group, params)) @@ -371,7 +468,7 @@ class Commit(Messenger): self.changelist = sorted(editor.get_changes().items()) - log = repos.get_rev_prop(svn.core.SVN_PROP_REVISION_LOG) or '' + log = to_str(repos.get_rev_prop(svn.core.SVN_PROP_REVISION_LOG) or b'') # collect the set of groups and the unique sets of params for the options self.groups = { } @@ -390,6 +487,7 @@ class Commit(Messenger): # figure out the changed directories dirs = { } for path, change in self.changelist: + path = to_str(path) if change.item_kind == svn.core.svn_node_dir: dirs[path] = None else: @@ -421,21 +519,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) + for (group, param_tuple), (params, paths) in sorted(self.groups.items()): + 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): @@ -456,35 +559,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(_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): @@ -532,7 +640,7 @@ class Lock(Messenger): or 'unlock_subject_prefix')) # read all the locked paths from STDIN and strip off the trailing newlines - self.dirlist = [x.rstrip() for x in sys.stdin.readlines()] + self.dirlist = [to_str(x).rstrip() for x in _stdin.readlines()] # collect the set of groups and the unique sets of params for the options self.groups = { } @@ -561,24 +669,30 @@ class Lock(Messenger): # The lock comment is the same for all paths, so we can just pull # the comment for the first path in the dirlist and cache it. self.lock = svn.fs.svn_fs_get_lock(self.repos.fs_ptr, - self.dirlist[0], self.pool) + to_bytes(self.dirlist[0]), + self.pool) def generate(self): - 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 '')) + ret = 0 + for (group, param_tuple), (params, paths) in sorted(self.groups.items()): + 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: @@ -629,9 +743,9 @@ class DiffURLSelections: # parameters for the configuration module, otherwise we may get # KeyError exceptions. params = self.params.copy() - params['path'] = change.path and urllib_parse_quote(change.path) or None - params['base_path'] = change.base_path and urllib_parse_quote(change.base_path) \ - or None + params['path'] = _url_quote(change.path) if change.path else None + params['base_path'] = (_url_quote(change.base_path) + if change.base_path else None) params['rev'] = repos_rev params['base_rev'] = change.base_rev @@ -685,7 +799,7 @@ def generate_content(renderer, cfg, repo author=repos.author, date=date, rev=repos.rev, - log=repos.get_rev_prop(svn.core.SVN_PROP_REVISION_LOG) or '', + log=to_str(repos.get_rev_prop(svn.core.SVN_PROP_REVISION_LOG) or b''), commit_url=commit_url, added_data=generate_list('A', changelist, paths, True), replaced_data=generate_list('R', changelist, paths, True), @@ -793,7 +907,9 @@ class DiffGenerator: # figure out if/how to generate a diff - base_path = remove_leading_slashes(change.base_path) + base_path_bytes = remove_leading_slashes(change.base_path) + base_path = (to_str(base_path_bytes) + if base_path_bytes is not None else None) if change.action == svn.repos.CHANGE_ACTION_DELETE: # it was delete. kind = 'D' @@ -804,7 +920,7 @@ class DiffGenerator: # show the diff? if self.diffsels.delete: diff = svn.fs.FileDiff(self.repos.get_root(change.base_rev), - base_path, None, None, self.pool) + base_path_bytes, None, None, self.pool) label1 = '%s\t%s\t(r%s)' % (base_path, self.date, change.base_rev) label2 = '/dev/null\t00:00:00 1970\t(deleted)' @@ -825,13 +941,13 @@ class DiffGenerator: # show the diff? if self.diffsels.modify: diff = svn.fs.FileDiff(self.repos.get_root(change.base_rev), - base_path, + base_path_bytes, self.repos.root_this, change.path, self.pool) - label1 = '%s\t%s\t(r%s, copy source)' \ - % (base_path, base_date, change.base_rev) - label2 = '%s\t%s\t(r%s)' \ - % (change.path, self.date, self.repos.rev) + label1 = ('%s\t%s\t(r%s, copy source)' + % (base_path, base_date, change.base_rev)) + label2 = ('%s\t%s\t(r%s)' + % (to_str(change.path), self.date, self.repos.rev)) singular = False else: # this file was copied. @@ -839,11 +955,12 @@ class DiffGenerator: if self.diffsels.copy: diff = svn.fs.FileDiff(None, None, self.repos.root_this, change.path, self.pool) - label1 = '/dev/null\t00:00:00 1970\t' \ - '(empty, because file is newly added)' - label2 = '%s\t%s\t(r%s, copy of r%s, %s)' \ - % (change.path, self.date, self.repos.rev, \ - change.base_rev, base_path) + label1 = ('/dev/null\t00:00:00 1970\t' + '(empty, because file is newly added)') + label2 = ('%s\t%s\t(r%s, copy of r%s, %s)' + % (to_str(change.path), + self.date, self.repos.rev, change.base_rev, + base_path)) singular = False else: # the file was added. @@ -859,7 +976,7 @@ class DiffGenerator: label1 = '/dev/null\t00:00:00 1970\t' \ '(empty, because file is newly added)' label2 = '%s\t%s\t(r%s)' \ - % (change.path, self.date, self.repos.rev) + % (to_str(change.path), self.date, self.repos.rev) singular = True elif not change.text_changed: @@ -881,7 +998,7 @@ class DiffGenerator: label1 = '%s\t%s\t(r%s)' \ % (base_path, base_date, change.base_rev) label2 = '%s\t%s\t(r%s)' \ - % (change.path, self.date, self.repos.rev) + % (to_str(change.path), self.date, self.repos.rev) singular = False if diff: @@ -904,7 +1021,7 @@ class DiffGenerator: # return a data item for this diff return _data( path=change.path, - base_path=base_path, + base_path=base_path_bytes, base_rev=change.base_rev, diff=diff, diff_url=diff_url, @@ -1071,7 +1188,7 @@ class TextCommitRenderer: props = ' (props changed)' else: props = '' - w(' %s%s%s\n' % (d.path, is_dir, props)) + w(' %s%s%s\n' % (to_str(d.path), is_dir, props)) if d.copied: if is_dir: text = '' @@ -1080,7 +1197,7 @@ class TextCommitRenderer: else: text = ' unchanged' w(' - copied%s from r%d, %s%s\n' - % (text, d.base_rev, d.base_path, is_dir)) + % (text, d.base_rev, to_str(d.base_path), is_dir)) def _render_diffs(self, diffs, section_header): """Render diffs. Write the SECTION_HEADER if there are actually @@ -1097,18 +1214,20 @@ class TextCommitRenderer: w(section_header) section_header_printed = True if diff.kind == 'D': - w('\nDeleted: %s\n' % diff.base_path) + w('\nDeleted: %s\n' % to_str(diff.base_path)) elif diff.kind == 'A': - w('\nAdded: %s\n' % diff.path) + w('\nAdded: %s\n' % to_str(diff.path)) elif diff.kind == 'C': w('\nCopied: %s (from r%d, %s)\n' - % (diff.path, diff.base_rev, diff.base_path)) + % (to_str(diff.path), diff.base_rev, + to_str(diff.base_path))) elif diff.kind == 'W': w('\nCopied and modified: %s (from r%d, %s)\n' - % (diff.path, diff.base_rev, diff.base_path)) + % (to_str(diff.path), diff.base_rev, + to_str(diff.base_path))) else: # kind == 'M' - w('\nModified: %s\n' % diff.path) + w('\nModified: %s\n' % to_str(diff.path)) if diff.diff_url: w('URL: %s\n' % diff.diff_url) @@ -1125,8 +1244,9 @@ class TextCommitRenderer: w('Binary file (source and/or target). No diff available.\n') continue + wb = self.output.write_binary for line in diff.content: - w(line.raw) + wb(line.raw) class Repository: @@ -1145,6 +1265,8 @@ class Repository: self.root_this = self.get_root(rev) self.author = self.get_rev_prop(svn.core.SVN_PROP_REVISION_AUTHOR) + if self.author is not None: + self.author = to_str(self.author) def get_rev_prop(self, propname, rev = None): if not rev: @@ -1353,9 +1475,9 @@ class Config: "Return the path's associated groups." groups = [] for group, pattern, exclude_pattern, repos_params, search_logmsg_re in self._group_re: - match = pattern.match(path) + match = pattern.match(to_str(path)) if match: - if exclude_pattern and exclude_pattern.match(path): + if exclude_pattern and exclude_pattern.match(to_str(path)): continue params = repos_params.copy() params.update(match.groupdict()) @@ -1394,6 +1516,8 @@ class UnknownMappingSpec(Exception): pass class UnknownSubcommand(Exception): pass +class MessageSendFailure(Exception): + pass if __name__ == '__main__': @@ -1432,7 +1556,7 @@ if the property was added, modified or d usage() cmd = sys.argv[1] - repos_dir = svn.core.svn_path_canonicalize(sys.argv[2]) + repos_dir = to_str(svn.core.svn_path_canonicalize(to_bytes(sys.argv[2]))) try: expected_args = cmd_list[cmd] except KeyError: @@ -1455,8 +1579,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/multi-wc-format/tools/hook-scripts/mailer/tests/mailer-t1.output URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/hook-scripts/mailer/tests/mailer-t1.output?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/tools/hook-scripts/mailer/tests/mailer-t1.output (original) +++ subversion/branches/multi-wc-format/tools/hook-scripts/mailer/tests/mailer-t1.output Fri Jan 14 14:01:45 2022 @@ -1,4 +1,4 @@ -Group: file +Group: All Subject: r1 - dir1 dir2 Author: mailer test @@ -9,9 +9,43 @@ Log: initial load Added: + dir1/ + dir1/file3 + dir1/file4 + dir2/ + dir2/file5 + dir2/file6 file1 file2 +Added: dir1/file3 +============================================================================== +--- /dev/null 00:00:00 1970 (empty, because file is newly added) ++++ dir1/file3 Sun Sep 9 01:46:40 2001 (r1) +@@ -0,0 +1 @@ ++file3 + +Added: dir1/file4 +============================================================================== +--- /dev/null 00:00:00 1970 (empty, because file is newly added) ++++ dir1/file4 Sun Sep 9 01:46:40 2001 (r1) +@@ -0,0 +1 @@ ++file4 + +Added: dir2/file5 +============================================================================== +--- /dev/null 00:00:00 1970 (empty, because file is newly added) ++++ dir2/file5 Sun Sep 9 01:46:40 2001 (r1) +@@ -0,0 +1 @@ ++file5 + +Added: dir2/file6 +============================================================================== +--- /dev/null 00:00:00 1970 (empty, because file is newly added) ++++ dir2/file6 Sun Sep 9 01:46:40 2001 (r1) +@@ -0,0 +1 @@ ++file6 + Added: file1 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) @@ -25,7 +59,7 @@ Added: file2 +++ file2 Sun Sep 9 01:46:40 2001 (r1) @@ -0,0 +1 @@ +file2 -Group: file plus other areas +Group: file Subject: r1 - dir1 dir2 Author: mailer test @@ -39,15 +73,6 @@ Added: file1 file2 -Changes in other areas also in this revision: -Added: - dir1/ - dir1/file3 - dir1/file4 - dir2/ - dir2/file5 - dir2/file6 - Added: file1 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) @@ -61,37 +86,7 @@ Added: file2 +++ file2 Sun Sep 9 01:46:40 2001 (r1) @@ -0,0 +1 @@ +file2 - -Diffs of changes in other areas also in this revision: - -Added: dir1/file3 -============================================================================== ---- /dev/null 00:00:00 1970 (empty, because file is newly added) -+++ dir1/file3 Sun Sep 9 01:46:40 2001 (r1) -@@ -0,0 +1 @@ -+file3 - -Added: dir1/file4 -============================================================================== ---- /dev/null 00:00:00 1970 (empty, because file is newly added) -+++ dir1/file4 Sun Sep 9 01:46:40 2001 (r1) -@@ -0,0 +1 @@ -+file4 - -Added: dir2/file5 -============================================================================== ---- /dev/null 00:00:00 1970 (empty, because file is newly added) -+++ dir2/file5 Sun Sep 9 01:46:40 2001 (r1) -@@ -0,0 +1 @@ -+file5 - -Added: dir2/file6 -============================================================================== ---- /dev/null 00:00:00 1970 (empty, because file is newly added) -+++ dir2/file6 Sun Sep 9 01:46:40 2001 (r1) -@@ -0,0 +1 @@ -+file6 -Group: All +Group: file plus other areas Subject: r1 - dir1 dir2 Author: mailer test @@ -102,14 +97,33 @@ Log: initial load Added: + file1 + file2 + +Changes in other areas also in this revision: +Added: dir1/ dir1/file3 dir1/file4 dir2/ dir2/file5 dir2/file6 - file1 - file2 + +Added: file1 +============================================================================== +--- /dev/null 00:00:00 1970 (empty, because file is newly added) ++++ file1 Sun Sep 9 01:46:40 2001 (r1) +@@ -0,0 +1 @@ ++file1 + +Added: file2 +============================================================================== +--- /dev/null 00:00:00 1970 (empty, because file is newly added) ++++ file2 Sun Sep 9 01:46:40 2001 (r1) +@@ -0,0 +1 @@ ++file2 + +Diffs of changes in other areas also in this revision: Added: dir1/file3 ============================================================================== @@ -138,21 +152,7 @@ Added: dir2/file6 +++ dir2/file6 Sun Sep 9 01:46:40 2001 (r1) @@ -0,0 +1 @@ +file6 - -Added: file1 -============================================================================== ---- /dev/null 00:00:00 1970 (empty, because file is newly added) -+++ file1 Sun Sep 9 01:46:40 2001 (r1) -@@ -0,0 +1 @@ -+file1 - -Added: file2 -============================================================================== ---- /dev/null 00:00:00 1970 (empty, because file is newly added) -+++ file2 Sun Sep 9 01:46:40 2001 (r1) -@@ -0,0 +1 @@ -+file2 -Group: file +Group: All Subject: r2 - dir1 dir2 Author: mailer test @@ -163,9 +163,19 @@ Log: two file changes. Fixes Blah#123 Modified: + dir1/ (props changed) + dir2/file5 file1 (props changed) file2 (contents, props changed) +Modified: dir2/file5 +============================================================================== +--- dir2/file5 Sun Sep 9 01:46:40 2001 (r1) ++++ dir2/file5 Sun Sep 9 04:33:20 2001 (r2) +@@ -1 +1,2 @@ + file5 ++change C2 + Modified: file2 ============================================================================== --- file2 Sun Sep 9 01:46:40 2001 (r1) @@ -204,7 +214,7 @@ Modified: file2 @@ -1 +1,2 @@ file2 +change C1 -Group: All +Group: file Subject: r2 - dir1 dir2 Author: mailer test @@ -215,19 +225,9 @@ Log: two file changes. Fixes Blah#123 Modified: - dir1/ (props changed) - dir2/file5 file1 (props changed) file2 (contents, props changed) -Modified: dir2/file5 -============================================================================== ---- dir2/file5 Sun Sep 9 01:46:40 2001 (r1) -+++ dir2/file5 Sun Sep 9 04:33:20 2001 (r2) -@@ -1 +1,2 @@ - file5 -+change C2 - Modified: file2 ============================================================================== --- file2 Sun Sep 9 01:46:40 2001 (r1) @@ -286,6 +286,11 @@ Added: - copied unchanged from r2, file1 dir3/ (props changed) - copied from r2, dir1/ +Replaced: + dir3/file3 + - copied unchanged from r1, dir1/file3 + dir3/file4 + - copied unchanged from r1, dir1/file4 Copied: dir2/file7 (from r2, file1) ============================================================================== @@ -293,6 +298,20 @@ Copied: dir2/file7 (from r2, file1) +++ dir2/file7 Sun Sep 9 07:20:00 2001 (r3, copy of r2, file1) @@ -0,0 +1 @@ +file1 + +Copied: dir3/file3 (from r1, dir1/file3) +============================================================================== +--- /dev/null 00:00:00 1970 (empty, because file is newly added) ++++ dir3/file3 Sun Sep 9 07:20:00 2001 (r3, copy of r1, dir1/file3) +@@ -0,0 +1 @@ ++file3 + +Copied: dir3/file4 (from r1, dir1/file4) +============================================================================== +--- /dev/null 00:00:00 1970 (empty, because file is newly added) ++++ dir3/file4 Sun Sep 9 07:20:00 2001 (r3, copy of r1, dir1/file4) +@@ -0,0 +1 @@ ++file4 Group: All Subject: r4 - dir3 @@ -314,7 +333,7 @@ Copied and modified: dir3/file8 (from r2 @@ -1 +1,2 @@ file1 +change C3 -Group: file +Group: All Subject: r5 - dir1 dir3 Author: mailer test @@ -325,8 +344,10 @@ Log: changes and deletes of properties Modified: + dir1/ (props changed) + dir3/ (props changed) file2 (props changed) -Group: file plus other areas +Group: file Subject: r5 - dir1 dir3 Author: mailer test @@ -338,12 +359,7 @@ changes and deletes of properties Modified: file2 (props changed) - -Changes in other areas also in this revision: -Modified: - dir1/ (props changed) - dir3/ (props changed) -Group: All +Group: file plus other areas Subject: r5 - dir1 dir3 Author: mailer test @@ -354,10 +370,13 @@ Log: changes and deletes of properties Modified: + file2 (props changed) + +Changes in other areas also in this revision: +Modified: dir1/ (props changed) dir3/ (props changed) - file2 (props changed) -Group: file +Group: All Subject: r6 - dir1 dir4 Author: mailer test @@ -368,7 +387,18 @@ Log: mixed addition and change. Fixes Blaz#456 Blah#987 Added: + dir4/ file9 +Modified: + dir1/file3 + +Modified: dir1/file3 +============================================================================== +--- dir1/file3 Sun Sep 9 12:53:20 2001 (r5) ++++ dir1/file3 Sun Sep 9 15:40:00 2001 (r6) +@@ -1 +1,2 @@ + file3 ++change C4 Added: file9 ============================================================================== @@ -376,8 +406,8 @@ Added: file9 +++ file9 Sun Sep 9 15:40:00 2001 (r6) @@ -0,0 +1 @@ +file9 -Group: file plus other areas -Subject: r6 - dir1 dir4 +Group: bugtracker +Subject: Fix for Blah#987: r6 - dir1 dir4 Author: mailer test Date: Sun Sep 9 15:40:00 2001 @@ -387,23 +417,11 @@ Log: mixed addition and change. Fixes Blaz#456 Blah#987 Added: - file9 - -Changes in other areas also in this revision: -Added: dir4/ + file9 Modified: dir1/file3 -Added: file9 -============================================================================== ---- /dev/null 00:00:00 1970 (empty, because file is newly added) -+++ file9 Sun Sep 9 15:40:00 2001 (r6) -@@ -0,0 +1 @@ -+file9 - -Diffs of changes in other areas also in this revision: - Modified: dir1/file3 ============================================================================== --- dir1/file3 Sun Sep 9 12:53:20 2001 (r5) @@ -411,6 +429,13 @@ Modified: dir1/file3 @@ -1 +1,2 @@ file3 +change C4 + +Added: file9 +============================================================================== +--- /dev/null 00:00:00 1970 (empty, because file is newly added) ++++ file9 Sun Sep 9 15:40:00 2001 (r6) +@@ -0,0 +1 @@ ++file9 Group: bugtracker Subject: Fix for Blaz#456: r6 - dir1 dir4 @@ -441,8 +466,8 @@ Added: file9 +++ file9 Sun Sep 9 15:40:00 2001 (r6) @@ -0,0 +1 @@ +file9 -Group: bugtracker -Subject: Fix for Blah#987: r6 - dir1 dir4 +Group: file +Subject: r6 - dir1 dir4 Author: mailer test Date: Sun Sep 9 15:40:00 2001 @@ -452,18 +477,7 @@ Log: mixed addition and change. Fixes Blaz#456 Blah#987 Added: - dir4/ file9 -Modified: - dir1/file3 - -Modified: dir1/file3 -============================================================================== ---- dir1/file3 Sun Sep 9 12:53:20 2001 (r5) -+++ dir1/file3 Sun Sep 9 15:40:00 2001 (r6) -@@ -1 +1,2 @@ - file3 -+change C4 Added: file9 ============================================================================== @@ -471,7 +485,7 @@ Added: file9 +++ file9 Sun Sep 9 15:40:00 2001 (r6) @@ -0,0 +1 @@ +file9 -Group: All +Group: file plus other areas Subject: r6 - dir1 dir4 Author: mailer test @@ -482,11 +496,23 @@ Log: mixed addition and change. Fixes Blaz#456 Blah#987 Added: - dir4/ file9 + +Changes in other areas also in this revision: +Added: + dir4/ Modified: dir1/file3 +Added: file9 +============================================================================== +--- /dev/null 00:00:00 1970 (empty, because file is newly added) ++++ file9 Sun Sep 9 15:40:00 2001 (r6) +@@ -0,0 +1 @@ ++file9 + +Diffs of changes in other areas also in this revision: + Modified: dir1/file3 ============================================================================== --- dir1/file3 Sun Sep 9 12:53:20 2001 (r5) @@ -494,13 +520,47 @@ Modified: dir1/file3 @@ -1 +1,2 @@ file3 +change C4 +Group: All +Subject: r7 - dir1 dir2 dir3 dir3/dir5 -Added: file9 +Author: mailer test +Date: Sun Sep 9 18:26:40 2001 +New Revision: 7 + +Log: +adds, deletes, and a change + +Added: + dir1/file10 + dir3/dir5/ +Deleted: + dir2/ + file2 +Modified: + dir3/file3 + +Added: dir1/file10 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) -+++ file9 Sun Sep 9 15:40:00 2001 (r6) ++++ dir1/file10 Sun Sep 9 18:26:40 2001 (r7) @@ -0,0 +1 @@ -+file9 ++file10 + +Modified: dir3/file3 +============================================================================== +--- dir3/file3 Sun Sep 9 15:40:00 2001 (r6) ++++ dir3/file3 Sun Sep 9 18:26:40 2001 (r7) +@@ -1 +1,2 @@ + file3 ++change C5 + +Deleted: file2 +============================================================================== +--- file2 Sun Sep 9 18:26:40 2001 (r6) ++++ /dev/null 00:00:00 1970 (deleted) +@@ -1,2 +0,0 @@ +-file2 +-change C1 Group: file Subject: r7 - dir1 dir2 dir3 dir3/dir5 @@ -568,47 +628,6 @@ Modified: dir3/file3 file3 +change C5 Group: All -Subject: r7 - dir1 dir2 dir3 dir3/dir5 - -Author: mailer test -Date: Sun Sep 9 18:26:40 2001 -New Revision: 7 - -Log: -adds, deletes, and a change - -Added: - dir1/file10 - dir3/dir5/ -Deleted: - dir2/ - file2 -Modified: - dir3/file3 - -Added: dir1/file10 -============================================================================== ---- /dev/null 00:00:00 1970 (empty, because file is newly added) -+++ dir1/file10 Sun Sep 9 18:26:40 2001 (r7) -@@ -0,0 +1 @@ -+file10 - -Modified: dir3/file3 -============================================================================== ---- dir3/file3 Sun Sep 9 15:40:00 2001 (r6) -+++ dir3/file3 Sun Sep 9 18:26:40 2001 (r7) -@@ -1 +1,2 @@ - file3 -+change C5 - -Deleted: file2 -============================================================================== ---- file2 Sun Sep 9 18:26:40 2001 (r6) -+++ /dev/null 00:00:00 1970 (deleted) -@@ -1,2 +0,0 @@ --file2 --change C1 -Group: All Subject: r8 - in dir6: . dir5 Author: mailer test @@ -644,7 +663,7 @@ Modified: dir6/file4 @@ -1 +1,2 @@ file4 +change C6 -Group: file +Group: All Subject: r9 - Author: mailer test @@ -662,7 +681,7 @@ Modified: Added: file11 ============================================================================== Binary file. No diff available. -Group: file plus other areas +Group: file Subject: r9 - Author: mailer test @@ -680,7 +699,7 @@ Modified: Added: file11 ============================================================================== Binary file. No diff available. -Group: All +Group: file plus other areas Subject: r9 - Author: mailer test @@ -698,7 +717,7 @@ Modified: Added: file11 ============================================================================== Binary file. No diff available. -Group: file +Group: All Subject: r10 - Author: mailer test @@ -715,7 +734,7 @@ Modified: Modified: file11 ============================================================================== Binary file (source and/or target). No diff available. -Group: file plus other areas +Group: file Subject: r10 - Author: mailer test @@ -732,7 +751,7 @@ Modified: Modified: file11 ============================================================================== Binary file (source and/or target). No diff available. -Group: All +Group: file plus other areas Subject: r10 - Author: mailer test Modified: subversion/branches/multi-wc-format/tools/hook-scripts/mailer/tests/mailer-tweak.py URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/hook-scripts/mailer/tests/mailer-tweak.py?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/tools/hook-scripts/mailer/tests/mailer-tweak.py (original) +++ subversion/branches/multi-wc-format/tools/hook-scripts/mailer/tests/mailer-tweak.py Fri Jan 14 14:01:45 2022 @@ -50,10 +50,10 @@ def tweak_dates(pool, home='.'): for i in range(fs.youngest_rev(fsob, pool)): # convert secs into microseconds, then a string - date = core.svn_time_to_cstring((DATE_BASE+i*DATE_INCR) * 1000000L, pool) + date = core.svn_time_to_cstring((DATE_BASE+i*DATE_INCR) * 1000000, pool) #print date fs.change_rev_prop(fsob, i+1, core.SVN_PROP_REVISION_DATE, date, pool) - fs.change_rev_prop(fsob, i+1, core.SVN_PROP_REVISION_AUTHOR, 'mailer test', pool) + fs.change_rev_prop(fsob, i+1, core.SVN_PROP_REVISION_AUTHOR, b'mailer test', pool) def main(): if len(sys.argv) != 2: Modified: subversion/branches/multi-wc-format/tools/hook-scripts/svnperms.py URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/hook-scripts/svnperms.py?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/tools/hook-scripts/svnperms.py (original) +++ subversion/branches/multi-wc-format/tools/hook-scripts/svnperms.py Fri Jan 14 14:01:45 2022 @@ -137,7 +137,8 @@ class Permission: try: groupusers.extend(self._group[token[1:]]) except KeyError: - raise Error, "group '%s' not found" % token[1:] + raise Error("group '%s' not found" % \ + token[1:]) else: groupusers.append(token) self._group[option] = groupusers Modified: subversion/branches/multi-wc-format/tools/hook-scripts/validate-files.py URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/hook-scripts/validate-files.py?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/tools/hook-scripts/validate-files.py (original) +++ subversion/branches/multi-wc-format/tools/hook-scripts/validate-files.py Fri Jan 14 14:01:45 2022 @@ -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/multi-wc-format/tools/server-side/svn-backup-dumps.py URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/server-side/svn-backup-dumps.py?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/tools/server-side/svn-backup-dumps.py (original) +++ subversion/branches/multi-wc-format/tools/server-side/svn-backup-dumps.py Fri Jan 14 14:01:45 2022 @@ -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/multi-wc-format/tools/server-side/svnauthz.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/server-side/svnauthz.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/tools/server-side/svnauthz.c (original) +++ subversion/branches/multi-wc-format/tools/server-side/svnauthz.c Fri Jan 14 14:01:45 2022 @@ -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. */ @@ -224,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 @@ -256,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) @@ -283,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 * @@ -395,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. */ @@ -437,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) { @@ -450,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; @@ -626,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 */ @@ -745,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/multi-wc-format/tools/server-side/svnpubsub/daemonize.py URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/server-side/svnpubsub/daemonize.py?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/tools/server-side/svnpubsub/daemonize.py (original) +++ subversion/branches/multi-wc-format/tools/server-side/svnpubsub/daemonize.py Fri Jan 14 14:01:45 2022 @@ -16,8 +16,16 @@ # # --------------------------------------------------------------------------- # -# This software lives at: -# http://gstein.googlecode.com/svn/trunk/python/daemonize.py +# This code is no longer maintained "upstream", so consider this module +# a "friendly fork" and is canonical for Apache Subversion's purposes. +# +# Use of systemd's single-process mechanism and re-launching of a daemon +# can greatly simplify daemon coding/management. A possibly-svn-relevant +# example can be found at: +# https://github.com/apache/infrastructure-svnauthz +# +# Historical locations for this module were found on svn.webdav.org, +# gstein.googlecode.com, and (most recently) gstein.svn.beanstalkapp.com. # import os @@ -56,7 +64,7 @@ class Daemon(object): # duplicate the exit code sys.exit(e.code) except (ChildTerminatedAbnormally, ChildForkFailed, - DaemonTerminatedAbnormally, DaemonForkFailed), e: + DaemonTerminatedAbnormally, DaemonForkFailed) as e: sys.stderr.write('ERROR: %s\n' % e) sys.exit(1) except ChildResumedIncorrectly: Modified: subversion/branches/multi-wc-format/win-tests.py URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/win-tests.py?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/win-tests.py (original) +++ subversion/branches/multi-wc-format/win-tests.py Fri Jan 14 14:01:45 2022 @@ -772,6 +772,9 @@ class Httpd: local_tmp = os.path.join(self.abs_builddir, CMDLINE_TEST_SCRIPT_NATIVE_PATH, 'svn-test-work', 'local_tmp') + repositories = os.path.join(self.abs_builddir, + CMDLINE_TEST_SCRIPT_NATIVE_PATH, + 'svn-test-work', 'repositories') return \ '<Location /authz-test-work/anon>' + '\n' \ ' DAV svn' + '\n' \ @@ -787,6 +790,17 @@ class Httpd: ' </IfModule>' + '\n' \ ' SVNPathAuthz ' + self.path_authz_option + '\n' \ '</Location>' + '\n' \ + '<Location /authz-test-work/in-repos-authz>' + '\n' \ + ' DAV svn' + '\n' \ + ' SVNParentPath ' + repositories + '\n' \ + ' AuthzSVNReposRelativeAccessFile "^/authz"\n' \ + ' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \ + ' AuthType Basic' + '\n' \ + ' AuthName "Subversion Repository"' + '\n' \ + ' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \ + ' Require valid-user' + '\n' \ + ' SVNPathAuthz ' + self.path_authz_option + '\n' \ + '</Location>' + '\n' \ '<Location /authz-test-work/mixed>' + '\n' \ ' DAV svn' + '\n' \ ' SVNParentPath ' + local_tmp + '\n' \ @@ -1263,7 +1277,11 @@ elif test_swig == 'python': or isinstance(i, gen_base.TargetSWIGLib)) and i.lang == 'python': src = os.path.join(abs_objdir, i.filename) - copy_changed_file(src, to_dir=swig_py_libsvn) + basename = os.path.basename(src) + if sys.version_info[:2] >= (3, 5) \ + and basename.endswith('.pyd') and objdir == 'Debug': + basename = basename[:-4] + '_d.pyd' + copy_changed_file(src, os.path.join(swig_py_libsvn, basename)) py_src = os.path.join(abs_srcdir, 'subversion', 'bindings', 'swig', 'python') @@ -1285,7 +1303,8 @@ elif test_swig == 'python': if 'PYTHONPATH' in os.environ: pythonpath += os.pathsep + os.environ['PYTHONPATH'] - python_exe = 'python.exe' + python_exe = sys.executable if objdir != 'Debug' else \ + os.path.join(os.path.dirname(sys.executable), 'python_d.exe') old_cwd = os.getcwd() try: os.environ['PYTHONPATH'] = pythonpath
