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 [email protected]. 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: [email protected], 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 [email protected]. 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()
