You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2022/01/14 14:01:51 UTC
svn commit: r1897034 [37/37] - in /subversion/branches/multi-wc-format: ./ build/ build/ac-macros/ build/generator/ build/generator/swig/ build/generator/templates/ contrib/client-side/ contrib/client-side/svn_load_dirs/ contrib/hook-scripts/ contrib/s...
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