Modified: subversion/branches/svn_mutex/tools/dist/release.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/svn_mutex/tools/dist/release.py?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/tools/dist/release.py (original)
+++ subversion/branches/svn_mutex/tools/dist/release.py Tue Oct 11 19:52:34 2011
@@ -36,13 +36,18 @@
 
 # Stuff we need
 import os
+import re
 import sys
+import glob
 import shutil
 import urllib2
 import hashlib
 import tarfile
 import logging
 import datetime
+import tempfile
+import operator
+import itertools
 import subprocess
 import argparse       # standard in Python 2.7
 
@@ -64,11 +69,87 @@ swig_ver = '2.0.4'
 
 # Some constants
 repos = 'http://svn.apache.org/repos/asf/subversion'
+people_host = 'minotaur.apache.org'
+people_dist_dir = '/www/www.apache.org/dist/subversion'
 
 
 #----------------------------------------------------------------------
 # Utility functions
 
+class Version(object):
+    regex = re.compile('(\d+).(\d+).(\d+)(?:-(?:(rc|alpha|beta)(\d+)))?')
+
+    def __init__(self, ver_str):
+        # Special case the 'trunk-nightly' version
+        if ver_str == 'trunk-nightly':
+            self.major = None
+            self.minor = None
+            self.patch = None
+            self.pre = 'nightly'
+            self.pre_num = None
+            self.base = 'nightly'
+            return
+
+        match = self.regex.search(ver_str)
+
+        if not match:
+            raise RuntimeError("Bad version string '%s'" % ver_str)
+
+        self.major = int(match.group(1))
+        self.minor = int(match.group(2))
+        self.patch = int(match.group(3))
+
+        if match.group(4):
+            self.pre = match.group(4)
+            self.pre_num = int(match.group(5))
+        else:
+            self.pre = None
+            self.pre_num = None
+
+        self.base = '%d.%d.%d' % (self.major, self.minor, self.patch)
+
+    def is_prerelease(self):
+        return self.pre != None
+
+    def __lt__(self, that):
+        if self.major < that.major: return True
+        if self.major > that.major: return False
+
+        if self.minor < that.minor: return True
+        if self.minor > that.minor: return False
+
+        if self.patch < that.patch: return True
+        if self.patch > that.patch: return False
+
+        if not self.pre and not that.pre: return False
+        if not self.pre and that.pre: return False
+        if self.pre and not that.pre: return True
+
+        # We are both pre-releases
+        if self.pre != that.pre:
+            return self.pre < that.pre
+        else:
+            return self.pre_num < that.pre_num
+
+    def __str(self):
+        if self.pre:
+            if self.pre == 'nightly':
+                return 'nightly'
+            else:
+                extra = '-%s%d' % (self.pre, self.pre_num)
+        else:
+            extra = ''
+
+        return self.base + extra
+
+    def __repr__(self):
+
+        return "Version('%s')" % self.__str()
+
+    def __str__(self):
+        return self.__str()
+
+
 def get_prefix(base_dir):
     return os.path.join(base_dir, 'prefix')
 
@@ -108,12 +189,9 @@ def download_file(url, target):
     target_file = open(target, 'w')
     target_file.write(response.read())
 
-def split_version(version):
-    parts = version.split('-')
-    if len(parts) == 1:
-        return (version, None)
-
-    return parts[0], parts[1]
+def assert_people():
+    if os.uname()[1] != people_host:
+        raise RuntimeError('Not running on expected host "%s"' % people_host)
 
 #----------------------------------------------------------------------
 # Cleaning up the environment
@@ -264,15 +342,46 @@ def build_env(args):
 #----------------------------------------------------------------------
 # Create release artifacts
 
+def fetch_changes(repos, branch, revision):
+    changes_peg_url = '%s/%s/CHANGES@%d' % (repos, branch, revision)
+    proc = subprocess.Popen(['svn', 'cat', changes_peg_url],
+                            stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    (stdout, stderr) = proc.communicate()
+    proc.wait()
+    return stdout.split('\n')
+
+
+def compare_changes(repos, branch, revision):
+    # Compare trunk's version of CHANGES with that of the branch,
+    # ignoring any lines in trunk's version precede what *should*
+    # match the contents of the branch's version.  (This allows us to
+    # continue adding new stuff at the top of trunk's CHANGES that
+    # might relate to the *next* major release line.)
+    branch_CHANGES = fetch_changes(repos, branch, revision)
+    trunk_CHANGES = fetch_changes(repos, 'trunk', revision)
+    try:
+        first_matching_line = trunk_CHANGES.index(branch_CHANGES[0])
+    except ValueError:
+        raise RuntimeError('CHANGES not synced between trunk and branch')
+
+    trunk_CHANGES = trunk_CHANGES[first_matching_line:]
+    saw_diff = False
+    import difflib
+    for diff_line in difflib.unified_diff(trunk_CHANGES, branch_CHANGES):
+        saw_diff = True
+        logging.debug('%s', diff_line)
+    if saw_diff:
+        raise RuntimeError('CHANGES not synced between trunk and branch')
+
+
 def roll_tarballs(args):
     'Create the release artifacts.'
     extns = ['zip', 'tar.gz', 'tar.bz2']
-    version_base, version_extra = split_version(args.version)
 
     if args.branch:
         branch = args.branch
     else:
-        branch = version_base[:-1] + 'x'
+        branch = 'branches/' + args.version.base[:-1] + 'x'
 
     logging.info('Rolling release %s from branch %s@%d' % (args.version,
                                                            branch, 
args.revnum))
@@ -286,50 +395,38 @@ def roll_tarballs(args):
         if not dep.have_usable():
            raise RuntimeError('Cannot find usable %s' % dep.label)
 
-    # Make sure CHANGES is sync'd
     if branch != 'trunk':
-        trunk_CHANGES = '%s/trunk/CHANGES@%d' % (repos, args.revnum)
-        branch_CHANGES = '%s/branches/%s/CHANGES@%d' % (repos, branch,
-                                                        args.revnum)
-        proc = subprocess.Popen(['svn', 'diff', '--summarize', branch_CHANGES,
-                                   trunk_CHANGES],
-                                  stdout=subprocess.PIPE,
-                                  stderr=subprocess.STDOUT)
-        (stdout, stderr) = proc.communicate()
-        proc.wait()
+        # Make sure CHANGES is sync'd.    
+        compare_changes(repos, branch, args.revnum)
+    
+    # Ensure the output directory doesn't already exist
+    if os.path.exists(get_deploydir(args.base_dir)):
+        raise RuntimeError('output directory \'%s\' already exists'
+                                            % get_deploydir(args.base_dir))
 
-        if stdout:
-            raise RuntimeError('CHANGES not synced between trunk and branch')
-
-    # Create the output directory
-    if not os.path.exists(get_deploydir(args.base_dir)):
-        os.mkdir(get_deploydir(args.base_dir))
+    os.mkdir(get_deploydir(args.base_dir))
 
     # For now, just delegate to dist.sh to create the actual artifacts
     extra_args = ''
-    if version_extra:
-        if version_extra.startswith('alpha'):
-            extra_args = '-alpha %s' % version_extra[5:]
-        elif version_extra.startswith('beta'):
-            extra_args = '-beta %s' % version_extra[4:]
-        elif version_extra.startswith('rc'):
-            extra_args = '-rc %s' % version_extra[2:]
-        elif version_extra.startswith('nightly'):
+    if args.version.is_prerelease():
+        if args.version.pre == 'nightly':
             extra_args = '-nightly'
+        else:
+            extra_args = '-%s %d' % (args.version.pre, args.version.pre_num)
     logging.info('Building UNIX tarballs')
     run_script(args.verbose, '%s/dist.sh -v %s -pr %s -r %d %s'
-                     % (sys.path[0], version_base, branch, args.revnum,
+                     % (sys.path[0], args.version.base, branch, args.revnum,
                         extra_args) )
     logging.info('Buildling Windows tarballs')
     run_script(args.verbose, '%s/dist.sh -v %s -pr %s -r %d -zip %s'
-                     % (sys.path[0], version_base, branch, args.revnum,
+                     % (sys.path[0], args.version.base, branch, args.revnum,
                         extra_args) )
 
     # Move the results to the deploy directory
     logging.info('Moving artifacts and calculating checksums')
     for e in extns:
-        if version_extra and version_extra.startswith('nightly'):
-            filename = 'subversion-trunk.%s' % e
+        if args.version.pre == 'nightly':
+            filename = 'subversion-nightly.%s' % e
         else:
             filename = 'subversion-%s.%s' % (args.version, e)
 
@@ -349,30 +446,24 @@ def roll_tarballs(args):
 
 def post_candidates(args):
     'Post the generated tarballs to web-accessible directory.'
-    version_base, version_extra = split_version(args.version)
-
     if args.target:
         target = args.target
     else:
         target = os.path.join(os.getenv('HOME'), 'public_html', 'svn',
-                              args.version)
-
-    if args.code_name:
-        dirname = args.code_name
-    else:
-        dirname = 'deploy'
+                              str(args.version))
 
-    if not os.path.exists(target):
-        os.makedirs(target)
+    logging.info('Moving tarballs to %s' % target)
+    if os.path.exists(target):
+        shutil.rmtree(target)
+    shutil.copytree(get_deploydir(args.base_dir), target)
 
-    data = { 'version'      : args.version,
+    data = { 'version'      : str(args.version),
              'revnum'       : args.revnum,
-             'dirname'      : dirname,
            }
 
     # Choose the right template text
-    if version_extra:
-        if version_extra.startswith('nightly'):
+    if args.version.is_prerelease():
+        if args.version.pre == 'nightly':
             template_filename = 'nightly-candidates.ezt'
         else:
             template_filename = 'rc-candidates.ezt'
@@ -381,12 +472,66 @@ def post_candidates(args):
 
     template = ezt.Template()
     template.parse(get_tmplfile(template_filename).read())
-    template.generate(open(os.path.join(target, 'index.html'), 'w'), data)
+    template.generate(open(os.path.join(target, 'HEADER.html'), 'w'), data)
+
+    template = ezt.Template()
+    template.parse(get_tmplfile('htaccess.ezt').read())
+    template.generate(open(os.path.join(target, '.htaccess'), 'w'), data)
 
-    logging.info('Moving tarballs to %s' % os.path.join(target, dirname))
-    if os.path.exists(os.path.join(target, dirname)):
-        shutil.rmtree(os.path.join(target, dirname))
-    shutil.copytree(get_deploydir(args.base_dir), os.path.join(target, 
dirname))
+
+#----------------------------------------------------------------------
+# Clean dist
+
+def clean_dist(args):
+    'Clean the distribution directory of all but the most recent artifacts.'
+
+    regex = 
re.compile('subversion-(\d+).(\d+).(\d+)(?:-(?:(rc|alpha|beta)(\d+)))?')
+
+    if not args.dist_dir:
+        assert_people()
+        args.dist_dir = people_dist_dir
+
+    logging.info('Cleaning dist dir \'%s\'' % args.dist_dir)
+
+    filenames = glob.glob(os.path.join(args.dist_dir, 'subversion-*.tar.gz'))
+    versions = []
+    for filename in filenames:
+        versions.append(Version(filename))
+
+    for k, g in itertools.groupby(sorted(versions),
+                                  lambda x: (x.major, x.minor)):
+        releases = list(g)
+        logging.info("Saving release '%s'", releases[-1])
+
+        for r in releases[:-1]:
+            for filename in glob.glob(os.path.join(args.dist_dir,
+                                                   'subversion-%s.*' % r)):
+                logging.info("Removing '%s'" % filename)
+                os.remove(filename)
+
+
+#----------------------------------------------------------------------
+# Move to dist
+
+def move_to_dist(args):
+    'Move candidate artifacts to the distribution directory.'
+
+    if not args.dist_dir:
+        assert_people()
+        args.dist_dir = people_dist_dir
+
+    if args.target:
+        target = args.target
+    else:
+        target = os.path.join(os.getenv('HOME'), 'public_html', 'svn',
+                              str(args.version))
+
+    logging.info('Moving %s to dist dir \'%s\'' % (str(args.version),
+                                                   args.dist_dir) )
+    filenames = glob.glob(os.path.join(target,
+                                       'subversion-%s.*' % str(args.version)))
+    for filename in filenames:
+        shutil.copy(filename, args.dist_dir)
 
 
 #----------------------------------------------------------------------
@@ -394,17 +539,15 @@ def post_candidates(args):
 
 def write_news(args):
     'Write text for the Subversion website.'
-    version_base, version_extra = split_version(args.version)
-
     data = { 'date' : datetime.date.today().strftime('%Y%m%d'),
              'date_pres' : datetime.date.today().strftime('%Y-%m-%d'),
-             'version' : args.version,
-             'version_base' : version_base[0:3],
+             'major-minor' : args.version.base[:3],
+             'version' : str(args.version),
+             'version_base' : args.version.base,
            }
 
-    if version_extra:
-        if version_extra.startswith('alpha'):
-            template_filename = 'rc-news.ezt'
+    if args.version.is_prerelease():
+        template_filename = 'rc-news.ezt'
     else:
         template_filename = 'stable-news.ezt'
 
@@ -413,19 +556,36 @@ def write_news(args):
     template.generate(sys.stdout, data)
 
 
+def get_sha1info(args):
+    'Return a list of sha1 info for the release'
+    sha1s = glob.glob(os.path.join(get_deploydir(args.base_dir), '*.sha1'))
+
+    class info(object):
+        pass
+
+    sha1info = []
+    for s in sha1s:
+        i = info()
+        i.filename = os.path.basename(s)[:-5]
+        i.sha1 = open(s, 'r').read()
+        sha1info.append(i)
+
+    return sha1info
+
+
 def write_announcement(args):
     'Write the release announcement.'
-    version_base, version_extra = split_version(args.version)
+    sha1info = get_sha1info(args)
 
-    data = { 'version'      : args.version,
-             'sha1info'     : 'foo',
-             'siginfo'      : 'bar', 
-             'major-minor'  : 'boo',
+    data = { 'version'              : str(args.version),
+             'sha1info'             : sha1info,
+             'siginfo'              : open('getsigs-output', 'r').read(),
+             'major-minor'          : args.version.base[:3],
+             'major-minor-patch'    : args.version.base,
            }
 
-    if version_extra:
-        if version_extra.startswith('alpha'):
-            template_filename = 'rc-release-ann.ezt'
+    if args.version.is_prerelease():
+        template_filename = 'rc-release-ann.ezt'
     else:
         template_filename = 'stable-release-ann.ezt'
 
@@ -434,6 +594,77 @@ def write_announcement(args):
     template.generate(sys.stdout, data)
 
 
+def write_downloads(args):
+    'Output the download section of the website.'
+    sha1info = get_sha1info(args)
+
+    data = { 'version'              : str(args.version),
+             'fileinfo'             : sha1info,
+           }
+
+    template = ezt.Template(compress_whitespace = False)
+    template.parse(get_tmplfile('download.ezt').read())
+    template.generate(sys.stdout, data)
+
+
+#----------------------------------------------------------------------
+# Validate the signatures for a release
+
+key_start = '-----BEGIN PGP SIGNATURE-----\n'
+fp_pattern = 
re.compile(r'^pub\s+(\w+\/\w+)[^\n]*\n\s+Key\sfingerprint\s=((\s+[0-9A-F]{4}){10})\nuid\s+([^<\(]+)\s')
+
+def check_sigs(args):
+    'Check the signatures for the release.'
+
+    try:
+        import gnupg
+    except ImportError:
+        import _gnupg as gnupg
+    gpg = gnupg.GPG()
+
+    if args.target:
+        target = args.target
+    else:
+        target = os.path.join(os.getenv('HOME'), 'public_html', 'svn',
+                              str(args.version))
+
+    good_sigs = {}
+
+    for filename in glob.glob(os.path.join(target, 'subversion-*.asc')):
+        text = open(filename).read()
+        keys = text.split(key_start)
+
+        for key in keys[1:]:
+            fd, fn = tempfile.mkstemp()
+            os.write(fd, key_start + key)
+            os.close(fd)
+            verified = gpg.verify_file(open(fn, 'rb'), filename[:-4])
+            os.unlink(fn)
+
+            if verified.valid:
+                good_sigs[verified.key_id[-8:]] = True
+            else:
+                sys.stderr.write("BAD SIGNATURE for %s\n" % filename)
+                sys.exit(1)
+
+    for id in good_sigs.keys():
+        gpg = subprocess.Popen(['gpg', '--fingerprint', id],
+                               stdout=subprocess.PIPE, 
stderr=subprocess.STDOUT)
+        rc = gpg.wait()
+        gpg_output = gpg.stdout.read()
+        if rc:
+            print(gpg_output)
+            sys.stderr.write("UNABLE TO GET FINGERPRINT FOR %s" % id)
+            sys.exit(1)
+
+        gpg_output = "\n".join([ l for l in gpg_output.splitlines()
+                                                     if l[0:7] != 'Warning' ])
+
+        fp = fp_pattern.match(gpg_output).groups()
+        print("   %s [%s] with fingerprint:" % (fp[3], fp[0]))
+        print("   %s" % fp[1])
+
+
 #----------------------------------------------------------------------
 # Main entry point for argument parsing and handling
 
@@ -470,7 +701,7 @@ def main():
     subparser = subparsers.add_parser('roll',
                     help='''Create the release artifacts.''')
     subparser.set_defaults(func=roll_tarballs)
-    subparser.add_argument('version',
+    subparser.add_argument('version', type=Version,
                     help='''The release label, such as '1.7.0-alpha1'.''')
     subparser.add_argument('revnum', type=int,
                     help='''The revision number to base the release on.''')
@@ -483,31 +714,71 @@ def main():
                             The default location is somewhere in ~/public_html.
                             ''')
     subparser.set_defaults(func=post_candidates)
-    subparser.add_argument('version',
+    subparser.add_argument('version', type=Version,
                     help='''The release label, such as '1.7.0-alpha1'.''')
     subparser.add_argument('revnum', type=int,
                     help='''The revision number to base the release on.''')
     subparser.add_argument('--target',
                     help='''The full path to the destination.''')
-    subparser.add_argument('--code-name',
-                    help='''A whimsical name for the release, used only for
-                            naming the download directory.''')
+
+    # 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.  If no
+                            dist-dir is given, this command will assume it is
+                            running on people.apache.org.''')
+    subparser.set_defaults(func=clean_dist)
+    subparser.add_argument('--dist-dir',
+                    help='''The directory to clean.''')
+
+    # The move-to-dist subcommand
+    subparser = subparsers.add_parser('move-to-dist',
+                    help='''Move candiates and signatures from the temporary
+                            post location to the permanent distribution
+                            directory.  If no dist-dir is given, this command
+                            will assume it is running on people.apache.org.''')
+    subparser.set_defaults(func=move_to_dist)
+    subparser.add_argument('version', type=Version,
+                    help='''The release label, such as '1.7.0-alpha1'.''')
+    subparser.add_argument('--dist-dir',
+                    help='''The directory to clean.''')
+    subparser.add_argument('--target',
+                    help='''The full path to the destination used in
+                            'post-candiates'..''')
 
     # The write-news subcommand
     subparser = subparsers.add_parser('write-news',
                     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('version',
+    subparser.add_argument('version', type=Version,
                     help='''The release label, such as '1.7.0-alpha1'.''')
 
     subparser = subparsers.add_parser('write-announcement',
                     help='''Output to stdout template text for the emailed
                             release announcement.''')
     subparser.set_defaults(func=write_announcement)
-    subparser.add_argument('version',
+    subparser.add_argument('version', type=Version,
                     help='''The release label, such as '1.7.0-alpha1'.''')
 
+    subparser = subparsers.add_parser('write-downloads',
+                    help='''Output to stdout template text for the download
+                            table for subversion.apache.org''')
+    subparser.set_defaults(func=write_downloads)
+    subparser.add_argument('version', type=Version,
+                    help='''The release label, such as '1.7.0-alpha1'.''')
+
+    # The check sigs subcommand
+    subparser = subparsers.add_parser('check-sigs',
+                    help='''Output to stdout the signatures collected for this
+                            release''')
+    subparser.set_defaults(func=check_sigs)
+    subparser.add_argument('version', type=Version,
+                    help='''The release label, such as '1.7.0-alpha1'.''')
+    subparser.add_argument('--target',
+                    help='''The full path to the destination used in
+                            'post-candiates'..''')
+
     # A meta-target
     subparser = subparsers.add_parser('clean',
                     help='''The same as the '--clean' switch, but as a

Modified: 
subversion/branches/svn_mutex/tools/dist/templates/nightly-candidates.ezt
URL: 
http://svn.apache.org/viewvc/subversion/branches/svn_mutex/tools/dist/templates/nightly-candidates.ezt?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/tools/dist/templates/nightly-candidates.ezt 
(original)
+++ subversion/branches/svn_mutex/tools/dist/templates/nightly-candidates.ezt 
Tue Oct 11 19:52:34 2011
@@ -59,7 +59,4 @@ made available to users who rely on thei
 packages.</p>
 
 <p>If you want to help us test this distribution of Subversion, you
-can find the files <a href="[dirname]/">here</a>.</p>
-
-</body>
-</html>
+can find the files below.</p>

Modified: subversion/branches/svn_mutex/tools/dist/templates/rc-candidates.ezt
URL: 
http://svn.apache.org/viewvc/subversion/branches/svn_mutex/tools/dist/templates/rc-candidates.ezt?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/tools/dist/templates/rc-candidates.ezt 
(original)
+++ subversion/branches/svn_mutex/tools/dist/templates/rc-candidates.ezt Tue 
Oct 11 19:52:34 2011
@@ -57,7 +57,4 @@ clearly denotes that this is not the fin
 purposes.  And please don't do so until it has been publicly announced.</p>
 
 <p>If you want to help us test this distribution of Subversion, you
-can find the files <a href="[dirname]/">here</a>.</p>
-
-</body>
-</html>
+can find the files below.</p>

Modified: subversion/branches/svn_mutex/tools/dist/templates/rc-news.ezt
URL: 
http://svn.apache.org/viewvc/subversion/branches/svn_mutex/tools/dist/templates/rc-news.ezt?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/tools/dist/templates/rc-news.ezt (original)
+++ subversion/branches/svn_mutex/tools/dist/templates/rc-news.ezt Tue Oct 11 
19:52:34 2011
@@ -4,16 +4,16 @@
     title="Link to this section">&para;</a> 
 </h3> 
  
-<p>We are please to announce to release of Apache Subversion [version].  This
+<p>We are pleased to announce to release of Apache Subversion [version].  This
    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
    announcement</a> for more information about this release, and the
-   <a href="/docs/release-notes/[version_base].html">release notes</a> and 
+   <a href="/docs/release-notes/[major-minor].html">release notes</a> and 
    <a 
href="http://svn.apache.org/repos/asf/subversion/tags/[version]/CHANGES";> 
    change log</a> for information about what will eventually be
-   in the [version_base].0 release.</p> 
+   in the [version_base] release.</p> 
  
 <p>To get this release from the nearest mirror, please visit our
    <a href="/download/#pre-releases">download page</a>.</p> 

Modified: 
subversion/branches/svn_mutex/tools/dist/templates/stable-candidates.ezt
URL: 
http://svn.apache.org/viewvc/subversion/branches/svn_mutex/tools/dist/templates/stable-candidates.ezt?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/tools/dist/templates/stable-candidates.ezt 
(original)
+++ subversion/branches/svn_mutex/tools/dist/templates/stable-candidates.ezt 
Tue Oct 11 19:52:34 2011
@@ -91,7 +91,4 @@ reputation as a packager and Subversion'
 but only one will deserve it.</p>
 
 <p>If you want to help us test this distribution of Subversion, you
-can find the files <a href="[dirname]/">here</a>.</p>
-
-</body>
-</html>
+can find the files below.</p>

Modified: 
subversion/branches/svn_mutex/tools/dist/templates/stable-release-ann.ezt
URL: 
http://svn.apache.org/viewvc/subversion/branches/svn_mutex/tools/dist/templates/stable-release-ann.ezt?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/tools/dist/templates/stable-release-ann.ezt 
(original)
+++ subversion/branches/svn_mutex/tools/dist/templates/stable-release-ann.ezt 
Tue Oct 11 19:52:34 2011
@@ -5,8 +5,8 @@ Please choose the mirror closest to you 
 
 The SHA1 checksums are:
 
-[sha1info]
-
+[for sha1info]    [sha1info.sha1] [sha1info.filename]
+[end]
 PGP Signatures are available at:
 
     http://www.apache.org/dist/subversion/subversion-[version].tar.bz2.asc
@@ -16,7 +16,6 @@ PGP Signatures are available at:
 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

Modified: subversion/branches/svn_mutex/tools/examples/get-location-segments.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/svn_mutex/tools/examples/get-location-segments.py?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/tools/examples/get-location-segments.py 
(original)
+++ subversion/branches/svn_mutex/tools/examples/get-location-segments.py Tue 
Oct 11 19:52:34 2011
@@ -21,6 +21,7 @@
 #
 import sys
 import os
+import getpass
 from svn import client, ra, core
 
 def printer(segment, pool):
@@ -71,6 +72,39 @@ def parse_args(args):
   return url, peg_revision, start_revision, end_revision
 
 
+def prompt_func_ssl_unknown_cert(realm, failures, cert_info, may_save, pool):
+  print "The certficate details are as follows:"
+  print "--------------------------------------"
+  print "Issuer     : " + str(cert_info.issuer_dname)
+  print "Hostname   : " + str(cert_info.hostname)
+  print "ValidFrom  : " + str(cert_info.valid_from)
+  print "ValidUpto  : " + str(cert_info.valid_until)
+  print "Fingerprint: " + str(cert_info.fingerprint)
+  print ""
+  ssl_trust = core.svn_auth_cred_ssl_server_trust_t()
+  if may_save:
+    choice = raw_input( "accept (t)temporarily   (p)permanently: ")
+  else:
+    choice = raw_input( "(r)Reject or accept (t)temporarily: ")
+  if choice[0] == "t" or choice[0] == "T":
+    ssl_trust.may_save = False
+    ssl_trust.accepted_failures = failures
+  elif choice[0] == "p" or choice[0] == "P":
+    ssl_trust.may_save = True
+    ssl_trust.accepted_failures = failures
+  else:
+    ssl_trust = None
+  return ssl_trust
+
+def prompt_func_simple_prompt(realm, username, may_save, pool):
+  username = raw_input("username: ")
+  password = getpass.getpass(prompt="password: ")
+  simple_cred = core.svn_auth_cred_simple_t()
+  simple_cred.username = username
+  simple_cred.password = password
+  simple_cred.may_save = False
+  return simple_cred
+
 def main():
   try:
     url, peg_revision, start_revision, end_revision = parse_args(sys.argv[1:])
@@ -93,6 +127,9 @@ ERROR: %s
   ctx = client.ctx_t()
   providers = [
     client.get_simple_provider(),
+    core.svn_auth_get_ssl_server_trust_file_provider(),
+    core.svn_auth_get_simple_prompt_provider(prompt_func_simple_prompt, 2),
+    
core.svn_auth_get_ssl_server_trust_prompt_provider(prompt_func_ssl_unknown_cert),
     client.get_username_provider(),
     client.get_ssl_server_trust_file_provider(),
     client.get_ssl_client_cert_file_provider(),

Modified: subversion/branches/svn_mutex/tools/hook-scripts/svnperms.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/svn_mutex/tools/hook-scripts/svnperms.py?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/tools/hook-scripts/svnperms.py (original)
+++ subversion/branches/svn_mutex/tools/hook-scripts/svnperms.py Tue Oct 11 
19:52:34 2011
@@ -285,7 +285,7 @@ Options:
     -s NAME    Use section NAME as permission section (default is
                repository name, extracted from repository path)
     -R REV     Query revision REV for commit information (for tests)
-    -A AUTHOR  Check commit as if AUTHOR had commited it (for tests)
+    -A AUTHOR  Check commit as if AUTHOR had committed it (for tests)
     -h         Show this message
 """
 

Modified: 
subversion/branches/svn_mutex/tools/server-side/svn-populate-node-origins-index.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/svn_mutex/tools/server-side/svn-populate-node-origins-index.c?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- 
subversion/branches/svn_mutex/tools/server-side/svn-populate-node-origins-index.c
 (original)
+++ 
subversion/branches/svn_mutex/tools/server-side/svn-populate-node-origins-index.c
 Tue Oct 11 19:52:34 2011
@@ -122,7 +122,7 @@ build_index(const char *repos_path, apr_
   apr_pool_t *subpool;
 
   /* Open the repository. */
-  SVN_ERR(svn_repos_open(&repos, repos_path, pool));
+  SVN_ERR(svn_repos_open2(&repos, repos_path, NULL, pool));
 
   /* Get a filesystem object. */
   fs = svn_repos_fs(repos);

Modified: 
subversion/branches/svn_mutex/tools/server-side/svn-rep-sharing-stats.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/svn_mutex/tools/server-side/svn-rep-sharing-stats.c?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/tools/server-side/svn-rep-sharing-stats.c 
(original)
+++ subversion/branches/svn_mutex/tools/server-side/svn-rep-sharing-stats.c Tue 
Oct 11 19:52:34 2011
@@ -390,7 +390,7 @@ static svn_error_t *process(const char *
     both_reps = apr_hash_make(scratch_pool);
 
   /* Open the FS. */
-  SVN_ERR(svn_repos_open(&repos, repos_path, scratch_pool));
+  SVN_ERR(svn_repos_open2(&repos, repos_path, NULL, scratch_pool));
   fs = svn_repos_fs(repos);
 
   SVN_ERR(is_fs_fsfs(fs, scratch_pool));

Modified: subversion/branches/svn_mutex/win-tests.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/svn_mutex/win-tests.py?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/win-tests.py (original)
+++ subversion/branches/svn_mutex/win-tests.py Tue Oct 11 19:52:34 2011
@@ -79,6 +79,7 @@ def _usage_exit():
   print("  --http-library         : dav library to use, neon (default) or 
serf")
   print("  --http-short-circuit   : Use SVNPathAuthz short_circuit on HTTP 
server")
   print("  --disable-http-v2      : Do not advertise support for HTTPv2 on 
server")
+  print("  --disable-bulk-updates : Disable bulk updates on HTTP server")
   print("  --javahl               : Run the javahl tests instead of the normal 
tests")
   print("  --list                 : print test doc strings only")
   print("  --milestone-filter=RE  : RE is a regular expression pattern that 
(when")
@@ -126,7 +127,7 @@ opts, args = my_getopt(sys.argv[1:], 'hr
                         'test=', 'url=', 'svnserve-args=', 'fs-type=', 
'asp.net-hack',
                         'httpd-dir=', 'httpd-port=', 'httpd-daemon',
                         'httpd-server', 'http-library=', 'http-short-circuit',
-                        'disable-http-v2', 'help',
+                        'disable-http-v2', 'disable-bulk-updates', 'help',
                         'fsfs-packing', 'fsfs-sharding=', 'javahl',
                         'list', 'enable-sasl', 'bin=', 'parallel',
                         'config-file=', 'server-minor-version=',
@@ -148,6 +149,7 @@ httpd_service = None
 http_library = 'neon'
 http_short_circuit = False
 advertise_httpv2 = True
+http_bulk_updates = True
 list_tests = None
 milestone_filter = None
 test_javahl = None
@@ -199,8 +201,10 @@ for opt, val in opts:
     http_library = val
   elif opt == '--http-short-circuit':
     http_short_circuit = True
-  elif opt == 'disable-http-v2':
+  elif opt == '--disable-http-v2':
     advertise_httpv2 = False
+  elif opt == '--disable-bulk-updates':
+    http_bulk_updates = False
   elif opt == '--fsfs-sharding':
     fsfs_sharding = int(val)
   elif opt == '--fsfs-packing':
@@ -424,7 +428,7 @@ class Svnserve:
 class Httpd:
   "Run httpd for DAV tests"
   def __init__(self, abs_httpd_dir, abs_objdir, abs_builddir, httpd_port,
-               service, httpv2, short_circuit):
+               service, httpv2, short_circuit, bulk_updates):
     self.name = 'apache.exe'
     self.httpd_port = httpd_port
     self.httpd_dir = abs_httpd_dir
@@ -434,6 +438,11 @@ class Httpd:
     else:
       self.httpv2_option = 'off'
 
+    if bulk_updates:
+      self.bulkupdates_option = 'on'
+    else:
+      self.bulkupdates_option = 'off'
+
     self.service = service
     self.proc_handle = None
     self.path = os.path.join(self.httpd_dir, 'bin', self.name)
@@ -578,6 +587,7 @@ class Httpd:
       '  SVNParentPath   ' + self._quote(path) + '\n' \
       '  SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
       '  SVNPathAuthz ' + self.path_authz_option + '\n' \
+      '  SVNAllowBulkUpdates ' + self.bulkupdates_option + '\n' \
       '  AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
       '  AuthType        Basic\n' \
       '  AuthName        "Subversion Repository"\n' \
@@ -646,6 +656,8 @@ if create_dirs:
     baton = copied_execs
     for dirpath, dirs, files in os.walk('subversion'):
       copy_execs(baton, dirpath, dirs + files)
+    for dirpath, dirs, files in os.walk('tools/client-side/svnmucc'):
+      copy_execs(baton, dirpath, dirs + files)
   except:
     os.chdir(old_cwd)
     raise
@@ -668,7 +680,8 @@ if not list_tests:
 
   if run_httpd:
     daemon = Httpd(abs_httpd_dir, abs_objdir, abs_builddir, httpd_port,
-                   httpd_service, advertise_httpv2, http_short_circuit)
+                   httpd_service, advertise_httpv2, http_short_circuit,
+                   http_bulk_updates)
 
   # Start service daemon, if any
   if daemon:


Reply via email to