You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by cm...@apache.org on 2018/11/28 21:25:35 UTC

svn commit: r1847678 [25/25] - in /subversion/branches/swig-py3: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/ contrib/client-side/svn_load_dirs/ contrib/client-side/svnmerge/ contrib/hook-scri...

Modified: subversion/branches/swig-py3/tools/dist/backport/status.py
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/dist/backport/status.py?rev=1847678&r1=1847677&r2=1847678&view=diff
==============================================================================
--- subversion/branches/swig-py3/tools/dist/backport/status.py (original)
+++ subversion/branches/swig-py3/tools/dist/backport/status.py Wed Nov 28 21:25:32 2018
@@ -194,10 +194,10 @@ class StatusFile:
         try:
           entry = StatusEntry(para_text, status_file=self)
           kind = Kind.nomination
-        except ParseException:
+        except ParseException as e:
           kind = Kind.unknown
-          logger.warning("Failed to parse entry {!r} in {!r}".format(
-                          para_text, status_fp))
+          logger.warning("Failed to parse entry {!r} in {!r}: {}".format(
+                          para_text, status_fp, e))
       else:
         kind = Kind.preamble
 
@@ -379,9 +379,11 @@ class StatusEntry:
       raise ParseException("Entry found with neither branch nor revisions")
 
     # Parse the logsummary.
-    while lines and not self._is_subheader(lines[0]):
+    while True:
       self.logsummary.append(lines[0])
       lines = lines[1:]
+      if (not lines) or self._is_subheader(lines[0]):
+        break
 
     # Parse votes.
     if "Votes:" in lines:

Modified: subversion/branches/swig-py3/tools/dist/backport_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/dist/backport_tests.py?rev=1847678&r1=1847677&r2=1847678&view=diff
==============================================================================
--- subversion/branches/swig-py3/tools/dist/backport_tests.py (original)
+++ subversion/branches/swig-py3/tools/dist/backport_tests.py Wed Nov 28 21:25:32 2018
@@ -53,6 +53,12 @@ import sys
 
 @contextlib.contextmanager
 def chdir(dir):
+  """This is a context manager that saves the current working directory's
+  pathname.  Upon entry it chdir's to the argument DIR; upon exit it chdir's
+  back to the saved pathname.
+
+  The current working directory is restored using os.chdir(), not os.fchdir().
+  """
   try:
     saved_dir = os.getcwd()
     os.chdir(dir)
@@ -660,6 +666,21 @@ def backport_unicode_entry(sbox):
   # Run it.
   run_backport(sbox)
 
+#----------------------------------------------------------------------
+@BackportTest('76cee987-25c9-4d6c-ad40-000000000013')
+def backport_logsummary_colon(sbox):
+  "a logsummary that looks like a header"
+
+  # r6: nominate r4
+  approved_entries = [
+    make_entry([4], logsummary="HTTPv2: Add comments."),
+  ]
+  sbox.simple_append(STATUS, serialize_STATUS(approved_entries))
+  sbox.simple_commit(message='Nominate r4')
+
+  # Run it.
+  run_backport(sbox)
+
 
 #----------------------------------------------------------------------
 
@@ -680,6 +701,7 @@ test_list = [ None,
               backport_otherproject_change,
               backport_STATUS_mods,
               backport_unicode_entry,
+              backport_logsummary_colon,
               # When adding a new test, include the test number in the last
               # 6 bytes of the UUID, in decimal.
              ]

Modified: subversion/branches/swig-py3/tools/dist/create-minor-release-branch.py
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/dist/create-minor-release-branch.py?rev=1847678&r1=1847677&r2=1847678&view=diff
==============================================================================
--- subversion/branches/swig-py3/tools/dist/create-minor-release-branch.py (original)
+++ subversion/branches/swig-py3/tools/dist/create-minor-release-branch.py Wed Nov 28 21:25:32 2018
@@ -39,6 +39,9 @@ repos = 'https://svn.apache.org/repos/as
 secure_repos = 'https://svn.apache.org/repos/asf/subversion'
 buildbot_repos = 'https://svn.apache.org/repos/infra/infrastructure/buildbot/aegis/buildmaster'
 
+# Parameters
+dry_run = False
+
 # Local working copies
 base_dir = None  # set by main()
 
@@ -72,15 +75,21 @@ def run(cmd, dry_run=False):
     if not dry_run:
         stdout = subprocess.check_output(cmd)
         print(stdout)
+    else:
+        print('  ## dry-run; not executed')
 
 def run_svn(cmd, dry_run=False):
     run(['svn'] + cmd, dry_run)
 
 def svn_commit(cmd):
-    run_svn(['commit'] + cmd, dry_run=True)
+    run_svn(['commit'] + cmd, dry_run=dry_run)
+
+def svn_copy_branch(src, dst, message):
+    args = ['copy', src, dst, '-m', message]
+    run_svn(args, dry_run=dry_run)
 
-def svn_checkout(*args):
-    args = ['checkout'] + list(args) + ['--revision={2017-12-01}']
+def svn_checkout(url, wc, *args):
+    args = ['checkout', url, wc] + list(args)
     run_svn(args)
 
 #----------------------------------------------------------------------
@@ -100,18 +109,19 @@ def prepend_file(path, text):
     open(path, 'w').write(text + original)
 
 #----------------------------------------------------------------------
-def make_release_branch(ver):
-    run_svn(['copy', get_trunk_url(), get_branch_url(ver),
-             '-m', 'Create the ' + ver.branch + '.x release branch.'],
-             dry_run=True)
+def make_release_branch(ver, revnum):
+    svn_copy_branch(get_trunk_url() + '@' + (str(revnum) if revnum else ''),
+                    get_branch_url(ver),
+                    'Create the ' + ver.branch + '.x release branch.')
 
 #----------------------------------------------------------------------
-def update_minor_ver_in_trunk(ver):
+def update_minor_ver_in_trunk(ver, revnum):
     """Change the minor version in trunk to the next (future) minor version.
     """
     trunk_wc = get_trunk_wc_path()
     trunk_url = get_trunk_url()
-    svn_checkout(trunk_url, trunk_wc)
+    svn_checkout(trunk_url + '@' + (str(revnum) if revnum else ''),
+                 trunk_wc)
 
     prev_ver = Version('1.%d.0' % (ver.minor - 1,))
     next_ver = Version('1.%d.0' % (ver.minor + 1,))
@@ -242,14 +252,12 @@ Subversion: start monitoring the %s bran
     svn_commit(commit_paths + ['-m', log_msg])
 
 #----------------------------------------------------------------------
-def steps(args):
-    ver = Version('1.10.0')
-
-    make_release_branch(ver)
-    update_minor_ver_in_trunk(ver)
-    create_status_file_on_branch(ver)
-    update_backport_bot(ver)
-    update_buildbot_config(ver)
+def create_release_branch(args):
+    make_release_branch(args.version, args.revnum)
+    update_minor_ver_in_trunk(args.version, args.revnum)
+    create_status_file_on_branch(args.version)
+    update_backport_bot(args.version)
+    update_buildbot_config(args.version)
 
 
 #----------------------------------------------------------------------
@@ -261,24 +269,37 @@ def main():
     # Setup our main parser
     parser = argparse.ArgumentParser(
                             description='Create an Apache Subversion release branch.')
-    parser.add_argument('--verbose', action='store_true', default=False,
+    subparsers = parser.add_subparsers(title='subcommands')
+
+    # Setup the parser for the create-release-branch subcommand
+    subparser = subparsers.add_parser('create-release-branch',
+                    help='''Create a minor release branch: branch from trunk,
+                            update version numbers on trunk, create status
+                            file on branch, update backport bot,
+                            update buildbot config.''')
+    subparser.set_defaults(func=create_release_branch)
+    subparser.add_argument('version', type=Version,
+                    help='''A version number to indicate the branch, such as
+                            '1.7.0' (the '.0' is required).''')
+    subparser.add_argument('revnum', type=lambda arg: int(arg.lstrip('r')),
+                           nargs='?', default=None,
+                    help='''The trunk revision number to base the branch on.
+                            Default is HEAD.''')
+    subparser.add_argument('--dry-run', action='store_true', default=False,
+                   help='Avoid committing any changes to repositories.')
+    subparser.add_argument('--verbose', action='store_true', default=False,
                    help='Increase output verbosity')
-    parser.add_argument('--base-dir', default=os.getcwd(),
+    subparser.add_argument('--base-dir', default=os.getcwd(),
                    help='''The directory in which to create needed files and
                            folders.  The default is the current working
                            directory.''')
-    subparsers = parser.add_subparsers(title='subcommands')
-
-    # Setup the parser for the build-env subcommand
-    subparser = subparsers.add_parser('steps',
-                    help='''Run the release-branch-creation steps.''')
-    subparser.set_defaults(func=steps)
 
     # Parse the arguments
     args = parser.parse_args()
 
-    global base_dir
+    global base_dir, dry_run
     base_dir = args.base_dir
+    dry_run = args.dry_run
 
     # Set up logging
     logger = logging.getLogger()

Modified: subversion/branches/swig-py3/tools/dist/release.py
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/dist/release.py?rev=1847678&r1=1847677&r2=1847678&view=diff
==============================================================================
--- subversion/branches/swig-py3/tools/dist/release.py (original)
+++ subversion/branches/swig-py3/tools/dist/release.py Wed Nov 28 21:25:32 2018
@@ -51,6 +51,9 @@ import operator
 import itertools
 import subprocess
 import argparse       # standard in Python 2.7
+import io
+
+import backport.status
 
 # Find ezt, using Subversion's copy, if there isn't one on the system.
 try:
@@ -71,16 +74,24 @@ tool_versions = {
             '954bd69b391edc12d6a4a51a2dd1476543da5c6bbf05a95b59dc0dd6fd4c2969'],
             'libtool'  : ['2.4.6',
             'e3bd4d5d3d025a36c21dd6af7ea818a2afcd4dfc1ea5a17b39d7854bcd0c06e3'],
-            'swig'     : ['3.0.10',
-            '2939aae39dec06095462f1b95ce1c958ac80d07b926e48871046d17c0094f44c'],
+            'swig'     : ['3.0.12',
+            '7cf9f447ae7ed1c51722efc45e7f14418d15d7a1e143ac9f09a668999f4fc94d'],
+  },
+  '1.11' : {
+            'autoconf' : ['2.69',
+            '954bd69b391edc12d6a4a51a2dd1476543da5c6bbf05a95b59dc0dd6fd4c2969'],
+            'libtool'  : ['2.4.6',
+            'e3bd4d5d3d025a36c21dd6af7ea818a2afcd4dfc1ea5a17b39d7854bcd0c06e3'],
+            'swig'     : ['3.0.12',
+            '7cf9f447ae7ed1c51722efc45e7f14418d15d7a1e143ac9f09a668999f4fc94d'],
   },
   '1.10' : {
             'autoconf' : ['2.69',
             '954bd69b391edc12d6a4a51a2dd1476543da5c6bbf05a95b59dc0dd6fd4c2969'],
             'libtool'  : ['2.4.6',
             'e3bd4d5d3d025a36c21dd6af7ea818a2afcd4dfc1ea5a17b39d7854bcd0c06e3'],
-            'swig'     : ['3.0.10',
-            '2939aae39dec06095462f1b95ce1c958ac80d07b926e48871046d17c0094f44c'],
+            'swig'     : ['3.0.12',
+            '7cf9f447ae7ed1c51722efc45e7f14418d15d7a1e143ac9f09a668999f4fc94d'],
   },
   '1.9' : {
             'autoconf' : ['2.69',
@@ -102,7 +113,9 @@ tool_versions = {
 
 # The version that is our current recommended release
 # ### TODO: derive this from svn_version.h; see ../../build/getversion.py
-recommended_release = '1.9'
+recommended_release = '1.11'
+# For clean-dist, a whitelist of artifacts to keep, by version.
+supported_release_lines = frozenset({"1.9", "1.10", "1.11", "1.12"})
 
 # Some constants
 repos = 'https://svn.apache.org/repos/asf/subversion'
@@ -712,9 +725,13 @@ def roll_tarballs(args):
         filepath = os.path.join(get_tempdir(args.base_dir), filename)
         shutil.move(filepath, get_deploydir(args.base_dir))
         filepath = os.path.join(get_deploydir(args.base_dir), filename)
-        m = hashlib.sha1()
-        m.update(open(filepath, 'r').read())
-        open(filepath + '.sha1', 'w').write(m.hexdigest())
+        if args.version < Version("1.11.0-alpha1"):
+            # 1.10 and earlier generate *.sha1 files for compatibility reasons.
+            # They are deprecated, however, so we don't publicly link them in
+            # the announcements any more.
+            m = hashlib.sha1()
+            m.update(open(filepath, 'r').read())
+            open(filepath + '.sha1', 'w').write(m.hexdigest())
         m = hashlib.sha512()
         m.update(open(filepath, 'r').read())
         open(filepath + '.sha512', 'w').write(m.hexdigest())
@@ -737,8 +754,12 @@ def sign_candidates(args):
     def sign_file(filename):
         asc_file = open(filename + '.asc', 'a')
         logging.info("Signing %s" % filename)
-        proc = subprocess.check_call(['gpg', '-ba', '-o', '-', filename],
-                                     stdout=asc_file)
+        if args.userid:
+            proc = subprocess.check_call(['gpg', '-ba', '-u', args.userid,
+                                         '-o', '-', filename], stdout=asc_file)
+        else:
+            proc = subprocess.check_call(['gpg', '-ba', '-o', '-', filename],
+                                         stdout=asc_file)
         asc_file.close()
 
     target = get_target(args)
@@ -773,8 +794,9 @@ def post_candidates(args):
 
 #----------------------------------------------------------------------
 # Create tag
+# Bump versions on branch
 
-def create_tag(args):
+def create_tag_only(args):
     'Create tag in the repository'
 
     target = get_target(args)
@@ -805,62 +827,87 @@ def create_tag(args):
             logging.error("Do you need to pass --branch=trunk?")
         raise
 
-    if not args.version.is_prerelease():
-        logging.info('Bumping revisions on the branch')
-        def replace_in_place(fd, startofline, flat, spare):
-            """In file object FD, replace FLAT with SPARE in the first line
-            starting with STARTOFLINE."""
-
-            fd.seek(0, os.SEEK_SET)
-            lines = fd.readlines()
-            for i, line in enumerate(lines):
-                if line.startswith(startofline):
-                    lines[i] = line.replace(flat, spare)
-                    break
-            else:
-                raise RuntimeError('Definition of %r not found' % startofline)
+def bump_versions_on_branch(args):
+    'Bump version numbers on branch'
 
-            fd.seek(0, os.SEEK_SET)
-            fd.writelines(lines)
-            fd.truncate() # for current callers, new value is never shorter.
-
-        new_version = Version('%d.%d.%d' %
-                              (args.version.major, args.version.minor,
-                               args.version.patch + 1))
-
-        def file_object_for(relpath):
-            fd = tempfile.NamedTemporaryFile()
-            url = branch + '/' + relpath
-            fd.url = url
-            subprocess.check_call(['svn', 'cat', '%s@%d' % (url, args.revnum)],
-                                  stdout=fd)
-            return fd
-
-        svn_version_h = file_object_for('subversion/include/svn_version.h')
-        replace_in_place(svn_version_h, '#define SVN_VER_PATCH ',
-                         str(args.version.patch), str(new_version.patch))
-
-        STATUS = file_object_for('STATUS')
-        replace_in_place(STATUS, 'Status of ',
-                         str(args.version), str(new_version))
-
-        svn_version_h.seek(0, os.SEEK_SET)
-        STATUS.seek(0, os.SEEK_SET)
-        subprocess.check_call(['svnmucc', '-r', str(args.revnum),
-                               '-m', 'Post-release housekeeping: '
-                                     'bump the %s branch to %s.'
-                               % (branch.split('/')[-1], str(new_version)),
-                               'put', svn_version_h.name, svn_version_h.url,
-                               'put', STATUS.name, STATUS.url,
-                              ])
-        del svn_version_h
-        del STATUS
+    logging.info('Bumping version numbers on the branch')
+
+    if not args.branch:
+        args.branch = 'branches/%d.%d.x' % (args.version.major, args.version.minor)
+
+    branch = secure_repos + '/' + args.branch.rstrip('/')
+
+    def replace_in_place(fd, startofline, flat, spare):
+        """In file object FD, replace FLAT with SPARE in the first line
+        starting with regex STARTOFLINE."""
+
+        pattern = r'^(%s)%s' % (startofline, re.escape(flat))
+        repl =    r'\g<1>%s' % (spare,)
+        fd.seek(0, os.SEEK_SET)
+        lines = fd.readlines()
+        for i, line in enumerate(lines):
+            replacement = re.sub(pattern, repl, line)
+            if replacement != line:
+                lines[i] = replacement
+                break
+        else:
+            raise RuntimeError("Could not replace r'%s' with r'%s' in '%s'"
+                               % (pattern, repl, fd.url))
+
+        fd.seek(0, os.SEEK_SET)
+        fd.writelines(lines)
+        fd.truncate() # for current callers, new value is never shorter.
+
+    new_version = Version('%d.%d.%d' %
+                          (args.version.major, args.version.minor,
+                           args.version.patch + 1))
+
+    HEAD = subprocess.check_output(['svn', 'info', '--show-item=revision',
+                                    '--', branch]).strip()
+    HEAD = int(HEAD)
+    def file_object_for(relpath):
+        fd = tempfile.NamedTemporaryFile()
+        url = branch + '/' + relpath
+        fd.url = url
+        subprocess.check_call(['svn', 'cat', '%s@%d' % (url, HEAD)],
+                              stdout=fd)
+        return fd
+
+    svn_version_h = file_object_for('subversion/include/svn_version.h')
+    replace_in_place(svn_version_h, '#define SVN_VER_PATCH  *',
+                     str(args.version.patch), str(new_version.patch))
+
+    STATUS = file_object_for('STATUS')
+    replace_in_place(STATUS, 'Status of ',
+                     str(args.version), str(new_version))
+
+    svn_version_h.seek(0, os.SEEK_SET)
+    STATUS.seek(0, os.SEEK_SET)
+    subprocess.check_call(['svnmucc', '-r', str(HEAD),
+                           '-m', 'Post-release housekeeping: '
+                                 'bump the %s branch to %s.'
+                           % (branch.split('/')[-1], str(new_version)),
+                           'put', svn_version_h.name, svn_version_h.url,
+                           'put', STATUS.name, STATUS.url,
+                          ])
+    del svn_version_h
+    del STATUS
+
+def create_tag_and_bump_versions(args):
+    '''Create tag in the repository and, if not a prerelease version,
+       bump version numbers on the branch'''
+
+    create_tag_only(args)
+
+    if not args.version.is_prerelease():
+        bump_versions_on_branch(args)
 
 #----------------------------------------------------------------------
 # Clean dist
 
 def clean_dist(args):
-    'Clean the distribution directory of all but the most recent artifacts.'
+    '''Clean the distribution directory of release artifacts of
+    no-longer-supported minor lines.'''
 
     stdout = subprocess.check_output(['svn', 'list', dist_release_url])
 
@@ -872,15 +919,15 @@ def clean_dist(args):
     filenames = stdout.split('\n')
     filenames = filter(lambda x: x.startswith('subversion-'), filenames)
     versions = set(map(Version, filenames))
-    minor_lines = set(map(minor, versions))
     to_keep = set()
-    # Keep 3 minor lines: 1.10.0-alpha3, 1.9.7, 1.8.19.
     # TODO: When we release 1.A.0 GA we'll have to manually remove 1.(A-2).* artifacts.
-    for recent_line in sorted(minor_lines, reverse=True)[:3]:
-        to_keep.add(max(
+    for line_to_keep in [minor(Version(x + ".0")) for x in supported_release_lines]:
+        candidates = list(
             x for x in versions
-            if minor(x) == recent_line
-        ))
+            if minor(x) == line_to_keep
+        )
+        if candidates:
+            to_keep.add(max(candidates))
     for i in sorted(to_keep):
         logging.info("Saving release '%s'", i)
 
@@ -938,6 +985,7 @@ def write_news(args):
              'version_base' : args.version.base,
              'anchor': args.version.get_download_anchor(),
              'is_recommended': ezt_bool(args.version.is_recommended()),
+             'announcement_url': args.announcement_url,
            }
 
     if args.version.is_prerelease():
@@ -947,38 +995,53 @@ def write_news(args):
 
     template = ezt.Template()
     template.parse(get_tmplfile(template_filename).read())
-    template.generate(sys.stdout, data)
+
+    # Insert the output into an existing file if requested, else print it
+    if args.edit_html_file:
+        tmp_name = args.edit_html_file + '.tmp'
+        with open(args.edit_html_file, 'r') as f, open(tmp_name, 'w') as g:
+            inserted = False
+            for line in f:
+                if not inserted and line.startswith('<div class="h3" id="news-'):
+                    template.generate(g, data)
+                    g.write('\n')
+                    inserted = True
+                g.write(line)
+        os.remove(args.edit_html_file)
+        os.rename(tmp_name, args.edit_html_file)
+    else:
+        template.generate(sys.stdout, data)
 
 
-def get_sha1info(args):
-    'Return a list of sha1 info for the release'
+def get_fileinfo(args):
+    'Return a list of file info (filenames) for the release tarballs'
 
     target = get_target(args)
 
-    sha1s = glob.glob(os.path.join(target, 'subversion*-%s*.sha1' % args.version))
+    files = glob.glob(os.path.join(target, 'subversion*-%s*.asc' % args.version))
+    files.sort()
 
     class info(object):
         pass
 
-    sha1info = []
-    for s in sha1s:
+    fileinfo = []
+    for f in files:
         i = info()
-        # strip ".sha1"
-        i.filename = os.path.basename(s)[:-5]
-        i.sha1 = open(s, 'r').read()
-        sha1info.append(i)
+        # strip ".asc"
+        i.filename = os.path.basename(f)[:-4]
+        fileinfo.append(i)
 
-    return sha1info
+    return fileinfo
 
 
 def write_announcement(args):
     'Write the release announcement.'
-    sha1info = get_sha1info(args)
-    siginfo = "\n".join(get_siginfo(args, True)) + "\n"
+    siginfo = get_siginfo(args, True)
+    if not siginfo:
+      raise RuntimeError("No signatures found for %s at %s" % (args.version, args.target))
 
     data = { 'version'              : str(args.version),
-             'sha1info'             : sha1info,
-             'siginfo'              : siginfo,
+             'siginfo'              : "\n".join(siginfo) + "\n",
              'major-minor'          : args.version.branch,
              'major-minor-patch'    : args.version.base,
              'anchor'               : args.version.get_download_anchor(),
@@ -1007,10 +1070,10 @@ def write_announcement(args):
 
 def write_downloads(args):
     'Output the download section of the website.'
-    sha1info = get_sha1info(args)
+    fileinfo = get_fileinfo(args)
 
     data = { 'version'              : str(args.version),
-             'fileinfo'             : sha1info,
+             'fileinfo'             : fileinfo,
            }
 
     template = ezt.Template(compress_whitespace = False)
@@ -1247,15 +1310,29 @@ def write_changelog(args):
     branch = secure_repos + '/' + args.branch
     previous = secure_repos + '/' + args.previous
     include_unlabeled = args.include_unlabeled
+    separator_line = ('-' * 72) + '\n'
     
     mergeinfo = subprocess.check_output(['svn', 'mergeinfo', '--show-revs',
-                    'eligible', '--log', branch, previous]).splitlines()
+                    'eligible', '--log', branch, previous])
+    log_messages_dict = {
+        # This is a dictionary mapping revision numbers to their respective
+        # log messages.  The expression in the "key:" part of the dict
+        # comprehension extracts the revision number, as integer, from the
+        # 'svn log' output.
+        int(log_message.splitlines()[0].split()[0][1:]): log_message
+        # The [1:-1] ignores the empty first and last element of the split().
+        for log_message in mergeinfo.split(separator_line)[1:-1]
+    }
+    mergeinfo = mergeinfo.splitlines()
     
     separator_pattern = re.compile('^-{72}$')
     revline_pattern = re.compile('^r(\d+) \| [^\|]+ \| [^\|]+ \| \d+ lines?$')
-    changes_prefix_pattern = re.compile('^\[(U|D)?:?([^\]]+)?\](.+)$')
-    changes_suffix_pattern = re.compile('^(.+)\[(U|D)?:?([^\]]+)?\]$')
-    
+    changes_prefix_pattern = re.compile(r'^\[(U|D)?:?([^\]]+)?\](.+)$')
+    changes_suffix_pattern = re.compile(r'^(.+)\[(U|D)?:?([^\]]+)?\]$')
+    # TODO: push this into backport.status as a library function
+    auto_merge_pattern = \
+        re.compile(r'^Merge (r\d+,? |the r\d+ group |the \S+ branch:)')
+
     changes_dict = dict()  # audience -> (section -> (change -> set(revision)))
     revision = -1
     got_firstline = False
@@ -1271,8 +1348,27 @@ def write_changelog(args):
             # If there's an unlabeled summary from a previous section, and
             # include_unlabeled is True, put it into uncategorized_changes.
             if include_unlabeled and unlabeled_summary and not changes_ignore:
-                add_to_changes_dict(changes_dict, None, None,
-                                    unlabeled_summary, revision)
+                if auto_merge_pattern.match(unlabeled_summary):
+                    # 1. Parse revision numbers from the first line
+                    merged_revisions = [
+                        int(x) for x in
+                        re.compile(r'(?<=\br)\d+\b').findall(unlabeled_summary)
+                    ]
+                    # TODO pass each revnum in MERGED_REVISIONS through this
+                    #      logic, in order to extract CHANGES_PREFIX_PATTERN
+                    #      and CHANGES_SUFFIX_PATTERN lines from the trunk log
+                    #      message.
+                    
+                    # 2. Parse the STATUS entry
+                    this_log_message = log_messages_dict[revision]
+                    status_paragraph = this_log_message.split('\n\n')[2]
+                    logsummary = \
+                        backport.status.StatusEntry(status_paragraph).logsummary
+                    add_to_changes_dict(changes_dict, None, None,
+                                        ' '.join(logsummary), revision)
+                else:
+                    add_to_changes_dict(changes_dict, None, None,
+                                        unlabeled_summary, revision)
             revision = -1
             got_firstline = False
             unlabeled_summary = None
@@ -1295,13 +1391,13 @@ def write_changelog(args):
 
         if not got_firstline:
             got_firstline = True
-            if (not re.search('status|changes|post-release housekeeping|follow-up|^\*',
+            if (not re.search(r'status|changes|post-release housekeeping|follow-up|^\*',
                               line, re.IGNORECASE)
                     and not changes_prefix_pattern.match(line)
                     and not changes_suffix_pattern.match(line)):
                 unlabeled_summary = line
 
-        if re.search('\[(c:)?(skip|ignore)\]', line, re.IGNORECASE):
+        if re.search(r'\[(c:)?(skip|ignore)\]', line, re.IGNORECASE):
             changes_ignore = True
             
         prefix_match = changes_prefix_pattern.match(line)
@@ -1398,6 +1494,10 @@ def main():
     subparser.add_argument('--target',
                     help='''The full path to the directory containing
                             release artifacts.''')
+    subparser.add_argument('--userid',
+                    help='''The (optional) USER-ID specifying the key to be
+                            used for signing, such as '110B1C95' (Key-ID). If
+                            omitted, uses the default key.''')
 
     # Setup the parser for the post-candidates subcommand
     subparser = subparsers.add_parser('post-candidates',
@@ -1414,8 +1514,26 @@ def main():
 
     # Setup the parser for the create-tag subcommand
     subparser = subparsers.add_parser('create-tag',
-                    help='''Create the release tag.''')
-    subparser.set_defaults(func=create_tag)
+                    help='''Create the release tag and, if not a prerelease
+                            version, bump version numbers on the branch.''')
+    subparser.set_defaults(func=create_tag_and_bump_versions)
+    subparser.add_argument('version', type=Version,
+                    help='''The release label, such as '1.7.0-alpha1'.''')
+    subparser.add_argument('revnum', type=lambda arg: int(arg.lstrip('r')),
+                    help='''The revision number to base the release on.''')
+    subparser.add_argument('--branch',
+                    help='''The branch to base the release on,
+                            relative to ^/subversion/.''')
+    subparser.add_argument('--username',
+                    help='''Username for ''' + secure_repos + '''.''')
+    subparser.add_argument('--target',
+                    help='''The full path to the directory containing
+                            release artifacts.''')
+
+    # Setup the parser for the bump-versions-on-branch subcommand
+    subparser = subparsers.add_parser('bump-versions-on-branch',
+                    help='''Bump version numbers on branch.''')
+    subparser.set_defaults(func=bump_versions_on_branch)
     subparser.add_argument('version', type=Version,
                     help='''The release label, such as '1.7.0-alpha1'.''')
     subparser.add_argument('revnum', type=lambda arg: int(arg.lstrip('r')),
@@ -1431,8 +1549,7 @@ def main():
 
     # The clean-dist subcommand
     subparser = subparsers.add_parser('clean-dist',
-                    help='''Clean the distribution directory (and mirrors) of
-                            all but the most recent MAJOR.MINOR release.''')
+                    help=clean_dist.__doc__.split('\n\n')[0])
     subparser.set_defaults(func=clean_dist)
     subparser.add_argument('--dist-dir',
                     help='''The directory to clean.''')
@@ -1455,6 +1572,11 @@ def main():
                     help='''Output to stdout template text for use in the news
                             section of the Subversion website.''')
     subparser.set_defaults(func=write_news)
+    subparser.add_argument('--announcement-url',
+                    help='''The URL to the archived announcement email.''')
+    subparser.add_argument('--edit-html-file',
+                    help='''Insert the text into this file
+                            news.html, index.html).''')
     subparser.add_argument('version', type=Version,
                     help='''The release label, such as '1.7.0-alpha1'.''')
 

Modified: subversion/branches/swig-py3/tools/dist/security/parser.py
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/dist/security/parser.py?rev=1847678&r1=1847677&r2=1847678&view=diff
==============================================================================
--- subversion/branches/swig-py3/tools/dist/security/parser.py (original)
+++ subversion/branches/swig-py3/tools/dist/security/parser.py Wed Nov 28 21:25:32 2018
@@ -50,9 +50,16 @@ class Notification(object):
         CULPRIT_SERVER = 'server'
         CULPRIT_CLIENT = 'client'
 
-        __CULPRITS = ((CULPRIT_SERVER, CULPRIT_CLIENT,
-                      (CULPRIT_SERVER, CULPRIT_CLIENT),
-                      (CULPRIT_CLIENT, CULPRIT_SERVER)))
+        # For compatibility, 'client' and 'server' may be specified either with
+        # or without a tuple.
+        __CULPRITS = (
+            CULPRIT_SERVER,
+            CULPRIT_CLIENT,
+            (CULPRIT_SERVER,)
+            (CULPRIT_CLIENT,)
+            (CULPRIT_SERVER, CULPRIT_CLIENT),
+            (CULPRIT_CLIENT, CULPRIT_SERVER),
+        )
 
         def __init__(self, basedir, tracking_id,
                      title, culprit, advisory, patches):

Modified: subversion/branches/swig-py3/tools/dist/templates/download.ezt
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/dist/templates/download.ezt?rev=1847678&r1=1847677&r2=1847678&view=diff
==============================================================================
--- subversion/branches/swig-py3/tools/dist/templates/download.ezt (original)
+++ subversion/branches/swig-py3/tools/dist/templates/download.ezt Wed Nov 28 21:25:32 2018
@@ -2,16 +2,14 @@
 <table class="centered">
 <tr>
   <th>File</th>
-  <th>Checksum (SHA1)</th>
   <th>Checksum (SHA512)</th>
   <th>Signatures</th>
 </tr>
 [for fileinfo]<tr>
   <td><a href="[[]preferred]subversion/[fileinfo.filename]">[fileinfo.filename]</a></td>
-  <td class="checksum">[fileinfo.sha1]</td>
   <!-- The sha512 line does not have a class="checksum" since the link needn't
        be rendered in monospace. -->
-  <td>[<a href="http://www.apache.org/dist/subversion/[fileinfo.filename].sha512">SHA-512</a>]</td>
-  <td>[<a href="http://www.apache.org/dist/subversion/[fileinfo.filename].asc">PGP</a>]</td>
+  <td>[<a href="https://www.apache.org/dist/subversion/[fileinfo.filename].sha512">SHA-512</a>]</td>
+  <td>[<a href="https://www.apache.org/dist/subversion/[fileinfo.filename].asc">PGP</a>]</td>
 </tr>[end]
 </table>

Modified: subversion/branches/swig-py3/tools/dist/templates/rc-news.ezt
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/dist/templates/rc-news.ezt?rev=1847678&r1=1847677&r2=1847678&view=diff
==============================================================================
--- subversion/branches/swig-py3/tools/dist/templates/rc-news.ezt (original)
+++ subversion/branches/swig-py3/tools/dist/templates/rc-news.ezt Wed Nov 28 21:25:32 2018
@@ -8,10 +8,10 @@
    release is not intended for production use, but is provided as a milestone
    to encourage wider testing and feedback from intrepid users and maintainers.
    Please see the
-   <a href="">release
+   <a href="[announcement_url]">release
    announcement</a> for more information about this release, and the
    <a href="/docs/release-notes/[major-minor].html">release notes</a> and 
-   <a href="http://svn.apache.org/repos/asf/subversion/tags/[version]/CHANGES"> 
+   <a href="https://svn.apache.org/repos/asf/subversion/tags/[version]/CHANGES"> 
    change log</a> for information about what will eventually be
    in the [version_base] release.</p> 
  

Modified: subversion/branches/swig-py3/tools/dist/templates/rc-release-ann.ezt
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/dist/templates/rc-release-ann.ezt?rev=1847678&r1=1847677&r2=1847678&view=diff
==============================================================================
--- subversion/branches/swig-py3/tools/dist/templates/rc-release-ann.ezt (original)
+++ subversion/branches/swig-py3/tools/dist/templates/rc-release-ann.ezt Wed Nov 28 21:25:32 2018
@@ -5,12 +5,8 @@ Subject: [[]ANNOUNCE] Apache Subversion
 I'm happy to announce the release of Apache Subversion [version].
 Please choose the mirror closest to you by visiting:
 
-    http://subversion.apache.org/download.cgi#[anchor]
+    https://subversion.apache.org/download.cgi#[anchor]
 
-The SHA1 checksums are:
-
-[for sha1info]    [sha1info.sha1] [sha1info.filename]
-[end]
 SHA-512 checksums are available at:
 
     https://www.apache.org/dist/subversion/subversion-[version].tar.bz2.sha512
@@ -19,9 +15,9 @@ SHA-512 checksums are available at:
 
 PGP Signatures are available at:
 
-    http://www.apache.org/dist/subversion/subversion-[version].tar.bz2.asc
-    http://www.apache.org/dist/subversion/subversion-[version].tar.gz.asc
-    http://www.apache.org/dist/subversion/subversion-[version].zip.asc
+    https://www.apache.org/dist/subversion/subversion-[version].tar.bz2.asc
+    https://www.apache.org/dist/subversion/subversion-[version].tar.gz.asc
+    https://www.apache.org/dist/subversion/subversion-[version].zip.asc
 
 For this release, the following people have provided PGP signatures:
 
@@ -57,13 +53,18 @@ end users please.
 
 Release notes for the [major-minor].x release series may be found at:
 
-    http://subversion.apache.org/docs/release-notes/[major-minor].html
+    https://subversion.apache.org/docs/release-notes/[major-minor].html
 
 You can find the list of changes between [version] and earlier versions at:
 
-    http://svn.apache.org/repos/asf/subversion/tags/[version]/CHANGES
+    https://svn.apache.org/repos/asf/subversion/tags/[version]/CHANGES
 
 Questions, comments, and bug reports to users@subversion.apache.org.
 
 Thanks,
 - The Subversion Team
+
+--
+To unsubscribe, please see:
+
+    https://subversion.apache.org/mailing-lists.html#unsubscribing

Modified: subversion/branches/swig-py3/tools/dist/templates/stable-news.ezt
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/dist/templates/stable-news.ezt?rev=1847678&r1=1847677&r2=1847678&view=diff
==============================================================================
--- subversion/branches/swig-py3/tools/dist/templates/stable-news.ezt (original)
+++ subversion/branches/swig-py3/tools/dist/templates/stable-news.ezt Wed Nov 28 21:25:32 2018
@@ -10,10 +10,10 @@
 [else]   This is the most complete release of the [major-minor].x line to date,
    and we encourage all users to upgrade as soon as reasonable.
 [end]   Please see the
-   <a href=""
+   <a href="[announcement_url]"
    >release announcement</a> and the
-   <a href="http://svn.apache.org/repos/asf/subversion/tags/[version]/CHANGES"
-   >change log</a> for more information about this release.</p> 
+   <a href="/docs/release-notes/[major-minor]"
+   >release notes</a> for more information about this release.</p> 
  
 <p>To get this release from the nearest mirror, please visit our
    <a href="/download.cgi#[anchor]">download page</a>.</p> 

Modified: subversion/branches/swig-py3/tools/dist/templates/stable-release-ann.ezt
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/dist/templates/stable-release-ann.ezt?rev=1847678&r1=1847677&r2=1847678&view=diff
==============================================================================
--- subversion/branches/swig-py3/tools/dist/templates/stable-release-ann.ezt (original)
+++ subversion/branches/swig-py3/tools/dist/templates/stable-release-ann.ezt Wed Nov 28 21:25:32 2018
@@ -7,7 +7,7 @@ To: announce@subversion.apache.org, user
 I'm happy to announce the release of Apache Subversion [version].
 Please choose the mirror closest to you by visiting:
 
-    http://subversion.apache.org/download.cgi#[anchor]
+    https://subversion.apache.org/download.cgi#[anchor]
 [if-any dot-zero]
 This is a stable feature release of the Apache Subversion open source
 version control system.
@@ -18,10 +18,6 @@ open source version control system.
 This is a stable bugfix release of the Apache Subversion open source
 version control system.
 [end][end]
-The SHA1 checksums are:
-
-[for sha1info]    [sha1info.sha1] [sha1info.filename]
-[end]
 SHA-512 checksums are available at:
 
     https://www.apache.org/dist/subversion/subversion-[version].tar.bz2.sha512
@@ -30,22 +26,27 @@ SHA-512 checksums are available at:
 
 PGP Signatures are available at:
 
-    http://www.apache.org/dist/subversion/subversion-[version].tar.bz2.asc
-    http://www.apache.org/dist/subversion/subversion-[version].tar.gz.asc
-    http://www.apache.org/dist/subversion/subversion-[version].zip.asc
+    https://www.apache.org/dist/subversion/subversion-[version].tar.bz2.asc
+    https://www.apache.org/dist/subversion/subversion-[version].tar.gz.asc
+    https://www.apache.org/dist/subversion/subversion-[version].zip.asc
 
 For this release, the following people have provided PGP signatures:
 
 [siginfo]
 Release notes for the [major-minor].x release series may be found at:
 
-    http://subversion.apache.org/docs/release-notes/[major-minor].html
+    https://subversion.apache.org/docs/release-notes/[major-minor].html
 
 You can find the list of changes between [version] and earlier versions at:
 
-    http://svn.apache.org/repos/asf/subversion/tags/[version]/CHANGES
+    https://svn.apache.org/repos/asf/subversion/tags/[version]/CHANGES
 
 Questions, comments, and bug reports to users@subversion.apache.org.
 
 Thanks,
 - The Subversion Team
+
+--
+To unsubscribe, please see:
+
+    https://subversion.apache.org/mailing-lists.html#unsubscribing

Modified: subversion/branches/swig-py3/tools/hook-scripts/mailer/mailer.py
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/hook-scripts/mailer/mailer.py?rev=1847678&r1=1847677&r2=1847678&view=diff
==============================================================================
--- subversion/branches/swig-py3/tools/hook-scripts/mailer/mailer.py (original)
+++ subversion/branches/swig-py3/tools/hook-scripts/mailer/mailer.py Wed Nov 28 21:25:32 2018
@@ -71,16 +71,10 @@ _MIN_SVN_VERSION = [1, 5, 0]
 
 # Import the Subversion Python bindings, making sure they meet our
 # minimum version requirements.
-try:
-  import svn.fs
-  import svn.delta
-  import svn.repos
-  import svn.core
-except ImportError:
-  sys.stderr.write(
-    "You need version %s or better of the Subversion Python bindings.\n" \
-    % ".".join([str(x) for x in _MIN_SVN_VERSION]))
-  sys.exit(1)
+import svn.fs
+import svn.delta
+import svn.repos
+import svn.core
 if _MIN_SVN_VERSION > [svn.core.SVN_VER_MAJOR,
                        svn.core.SVN_VER_MINOR,
                        svn.core.SVN_VER_PATCH]:

Modified: subversion/branches/swig-py3/tools/server-side/svnauthz.c
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/server-side/svnauthz.c?rev=1847678&r1=1847677&r2=1847678&view=diff
==============================================================================
--- subversion/branches/swig-py3/tools/server-side/svnauthz.c (original)
+++ subversion/branches/swig-py3/tools/server-side/svnauthz.c Wed Nov 28 21:25:32 2018
@@ -110,29 +110,34 @@ static svn_opt_subcommand_t
 /* Array of available subcommands.
  * The entire list must be terminated with an entry of nulls.
  */
-static const svn_opt_subcommand_desc2_t cmd_table[] =
+static const svn_opt_subcommand_desc3_t cmd_table[] =
 {
-  {"help", subcommand_help, {"?", "h"},
-   ("usage: svnauthz help [SUBCOMMAND...]\n\n"
-    "Describe the usage of this program or its subcommands.\n"),
+  {"help", subcommand_help, {"?", "h"}, {(
+    "usage: svnauthz help [SUBCOMMAND...]\n"
+    "\n"
+    "Describe the usage of this program or its subcommands.\n"
+    )},
    {0} },
-  {"validate", subcommand_validate, {0} /* no aliases */,
-   ("Checks the syntax of an authz file.\n"
+  {"validate", subcommand_validate, {0} /* no aliases */, {(
+    "Checks the syntax of an authz file.\n"
     "usage: 1. svnauthz validate TARGET\n"
-    "       2. svnauthz validate --transaction TXN REPOS_PATH FILE_PATH\n\n"
+    "       2. svnauthz validate --transaction TXN REPOS_PATH FILE_PATH\n"
+    "\n"
     "  1. Loads and validates the syntax of the authz file at TARGET.\n"
     "     TARGET can be a path to a file or an absolute file:// URL to an authz\n"
-    "     file in a repository, but cannot be a repository relative URL (^/).\n\n"
+    "     file in a repository, but cannot be a repository relative URL (^/).\n"
+    "\n"
     "  2. Loads and validates the syntax of the authz file at FILE_PATH in the\n"
-    "     transaction TXN in the repository at REPOS_PATH.\n\n"
+    "     transaction TXN in the repository at REPOS_PATH.\n"
+    "\n"
     "Returns:\n"
     "    0   when syntax is OK.\n"
     "    1   when syntax is invalid.\n"
     "    2   operational error\n"
-    ),
+    )},
    {'t'} },
-  {"accessof", subcommand_accessof, {0} /* no aliases */,
-   ("Print or test the permissions set by an authz file.\n"
+  {"accessof", subcommand_accessof, {0} /* no aliases */, {(
+    "Print or test the permissions set by an authz file.\n"
     "usage: 1. svnauthz accessof TARGET\n"
     "       2. svnauthz accessof -t TXN REPOS_PATH FILE_PATH\n"
     "\n"
@@ -159,10 +164,10 @@ static const svn_opt_subcommand_desc2_t
     "    1   when syntax is invalid.\n"
     "    2   operational error\n"
     "    3   when '--is' argument doesn't match\n"
-    ),
+    )},
    {'t', svnauthz__username, svnauthz__path, svnauthz__repos, svnauthz__is,
     svnauthz__groups_file, 'R'} },
-  { NULL, NULL, {0}, NULL, {0} }
+  { NULL, NULL, {0}, {NULL}, {0} }
 };
 
 static svn_error_t *
@@ -171,11 +176,14 @@ subcommand_help(apr_getopt_t *os, void *
   struct svnauthz_opt_state *opt_state = baton;
   const char *header =
     ("general usage: svnauthz SUBCOMMAND TARGET [ARGS & OPTIONS ...]\n"
-     "               " SVNAUTHZ_COMPAT_NAME " TARGET\n\n"
+     "               " SVNAUTHZ_COMPAT_NAME " TARGET\n"
+    "\n"
      "If the command name starts with '" SVNAUTHZ_COMPAT_NAME "', runs in\n"
-     "pre-1.8 compatibility mode: run the 'validate' subcommand on TARGET.\n\n"
+     "pre-1.8 compatibility mode: run the 'validate' subcommand on TARGET.\n"
+    "\n"
      "Type 'svnauthz help <subcommand>' for help on a specific subcommand.\n"
-     "Type 'svnauthz --version' to see the program version.\n\n"
+     "Type 'svnauthz --version' to see the program version.\n"
+    "\n"
      "Available subcommands:\n");
 
   const char *fs_desc_start
@@ -186,7 +194,7 @@ subcommand_help(apr_getopt_t *os, void *
   version_footer = svn_stringbuf_create(fs_desc_start, pool);
   SVN_ERR(svn_fs_print_modules(version_footer, pool));
 
-  SVN_ERR(svn_opt_print_help4(os, "svnauthz",
+  SVN_ERR(svn_opt_print_help5(os, "svnauthz",
                               opt_state ? opt_state->version : FALSE,
                               FALSE, /* quiet */
                               FALSE, /* verbose */
@@ -459,7 +467,7 @@ sub_main(int *exit_code, int argc, const
 {
   svn_error_t *err;
 
-  const svn_opt_subcommand_desc2_t *subcommand = NULL;
+  const svn_opt_subcommand_desc3_t *subcommand = NULL;
   struct svnauthz_opt_state opt_state = { 0 };
   apr_getopt_t *os;
   apr_array_header_t *received_opts;
@@ -545,9 +553,9 @@ sub_main(int *exit_code, int argc, const
     {
       /* Pre 1.8 compatibility mode. */
       if (argc == 1) /* No path argument */
-        subcommand = svn_opt_get_canonical_subcommand2(cmd_table, "help");
+        subcommand = svn_opt_get_canonical_subcommand3(cmd_table, "help");
       else
-        subcommand = svn_opt_get_canonical_subcommand2(cmd_table, "validate");
+        subcommand = svn_opt_get_canonical_subcommand3(cmd_table, "validate");
     }
 
   /* If the user asked for help, then the rest of the arguments are
@@ -555,7 +563,7 @@ sub_main(int *exit_code, int argc, const
      just typos/mistakes.  Whatever the case, the subcommand to
      actually run is subcommand_help(). */
   if (opt_state.help)
-    subcommand = svn_opt_get_canonical_subcommand2(cmd_table, "help");
+    subcommand = svn_opt_get_canonical_subcommand3(cmd_table, "help");
 
   if (subcommand == NULL)
     {
@@ -564,8 +572,8 @@ sub_main(int *exit_code, int argc, const
           if (opt_state.version)
             {
               /* Use the "help" subcommand to handle the "--version" option. */
-              static const svn_opt_subcommand_desc2_t pseudo_cmd =
-                { "--version", subcommand_help, {0}, "",
+              static const svn_opt_subcommand_desc3_t pseudo_cmd =
+                { "--version", subcommand_help, {0}, {""},
                   {svnauthz__version /* must accept its own option */ } };
 
               subcommand = &pseudo_cmd;
@@ -585,7 +593,7 @@ sub_main(int *exit_code, int argc, const
 
           SVN_ERR(svn_utf_cstring_to_utf8(&first_arg, os->argv[os->ind++],
                                           pool));
-          subcommand = svn_opt_get_canonical_subcommand2(cmd_table, first_arg);
+          subcommand = svn_opt_get_canonical_subcommand3(cmd_table, first_arg);
           if (subcommand == NULL)
             {
               os->ind++;
@@ -658,11 +666,11 @@ sub_main(int *exit_code, int argc, const
       if (opt_id == 'h' || opt_id == '?')
         continue;
 
-      if (! svn_opt_subcommand_takes_option3(subcommand, opt_id, NULL))
+      if (! svn_opt_subcommand_takes_option4(subcommand, opt_id, NULL))
         {
           const char *optstr;
           const apr_getopt_option_t *badopt =
-            svn_opt_get_option_from_code2(opt_id, options_table, subcommand,
+            svn_opt_get_option_from_code3(opt_id, options_table, subcommand,
                                           pool);
           svn_opt_format_option(&optstr, badopt, FALSE, pool);
           if (subcommand->name[0] == '-')

Modified: subversion/branches/swig-py3/tools/server-side/svnpubsub/svnwcsub.py
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/server-side/svnpubsub/svnwcsub.py?rev=1847678&r1=1847677&r2=1847678&view=diff
==============================================================================
--- subversion/branches/swig-py3/tools/server-side/svnpubsub/svnwcsub.py (original)
+++ subversion/branches/swig-py3/tools/server-side/svnpubsub/svnwcsub.py Wed Nov 28 21:25:32 2018
@@ -32,7 +32,7 @@
 
 # TODO:
 # - bulk update at startup time to avoid backlog warnings
-# - fold BDEC into Daemon
+# - fold BigDoEverythingClasss ("BDEC") into Daemon
 # - fold WorkingCopy._get_match() into __init__
 # - remove wc_ready(). assume all WorkingCopy instances are usable.
 #   place the instances into .watch at creation. the .update_applies()