1f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III"""Tag the sandbox for release, make source and doc tarballs.
2f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
3f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIRequires Python 2.6
4f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
5f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIExample of invocation (use to test the script):
6f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIpython makerelease.py --platform=msvc6,msvc71,msvc80,msvc90,mingw -ublep 0.6.0 0.7.0-dev
7f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
8f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIWhen testing this script:
9f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIpython makerelease.py --force --retag --platform=msvc6,msvc71,msvc80,mingw -ublep test-0.6.0 test-0.6.1-dev
10f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
11f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIExample of invocation when doing a release:
12f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIpython makerelease.py 0.5.0 0.6.0-dev
13f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III"""
14f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIimport os.path
15f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIimport subprocess
16f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIimport sys
17f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIimport doxybuild
18f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIimport subprocess
19f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIimport xml.etree.ElementTree as ElementTree
20f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIimport shutil
21f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIimport urllib2
22f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIimport tempfile
23f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIimport os
24f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIimport time
25f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIfrom devtools import antglob, fixeol, tarball
26f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIimport amalgamate
27f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
28f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIISVN_ROOT = 'https://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/'
29f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIISVN_TAG_ROOT = SVN_ROOT + 'tags/jsoncpp'
30f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIISCONS_LOCAL_URL = 'http://sourceforge.net/projects/scons/files/scons-local/1.2.0/scons-local-1.2.0.tar.gz/download'
31f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIISOURCEFORGE_PROJECT = 'jsoncpp'
32f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
33f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdef set_version( version ):
34f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    with open('version','wb') as f:
35f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        f.write( version.strip() )
36f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
37f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdef rmdir_if_exist( dir_path ):
38f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    if os.path.isdir( dir_path ):
39f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        shutil.rmtree( dir_path )
40f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
41f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIclass SVNError(Exception):
42f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    pass
43f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
44f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdef svn_command( command, *args ):
45f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    cmd = ['svn', '--non-interactive', command] + list(args)
46f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    print 'Running:', ' '.join( cmd )
47f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    process = subprocess.Popen( cmd,
48f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III                                stdout=subprocess.PIPE,
49f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III                                stderr=subprocess.STDOUT )
50f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    stdout = process.communicate()[0]
51f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    if process.returncode:
52f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        error = SVNError( 'SVN command failed:\n' + stdout )
53f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        error.returncode = process.returncode
54f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        raise error
55f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    return stdout
56f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
57f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdef check_no_pending_commit():
58f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    """Checks that there is no pending commit in the sandbox."""
59f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    stdout = svn_command( 'status', '--xml' )
60f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    etree = ElementTree.fromstring( stdout )
61f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    msg = []
62f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    for entry in etree.getiterator( 'entry' ):
63f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        path = entry.get('path')
64f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        status = entry.find('wc-status').get('item')
65f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        if status != 'unversioned' and path != 'version':
66f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            msg.append( 'File "%s" has pending change (status="%s")' % (path, status) )
67f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    if msg:
68f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        msg.insert(0, 'Pending change to commit found in sandbox. Commit them first!' )
69f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    return '\n'.join( msg )
70f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
71f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdef svn_join_url( base_url, suffix ):
72f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    if not base_url.endswith('/'):
73f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        base_url += '/'
74f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    if suffix.startswith('/'):
75f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        suffix = suffix[1:]
76f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    return base_url + suffix
77f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
78f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdef svn_check_if_tag_exist( tag_url ):
79f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    """Checks if a tag exist.
80f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    Returns: True if the tag exist, False otherwise.
81f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    """
82f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    try:
83f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        list_stdout = svn_command( 'list', tag_url )
84f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    except SVNError, e:
85f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        if e.returncode != 1 or not str(e).find('tag_url'):
86f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            raise e
87f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        # otherwise ignore error, meaning tag does not exist
88f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        return False
89f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    return True
90f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
91f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdef svn_commit( message ):
92f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    """Commit the sandbox, providing the specified comment.
93f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    """
94f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    svn_command( 'ci', '-m', message )
95f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
96f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdef svn_tag_sandbox( tag_url, message ):
97f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    """Makes a tag based on the sandbox revisions.
98f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    """
99f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    svn_command( 'copy', '-m', message, '.', tag_url )
100f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
101f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdef svn_remove_tag( tag_url, message ):
102f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    """Removes an existing tag.
103f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    """
104f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    svn_command( 'delete', '-m', message, tag_url )
105f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
106f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdef svn_export( tag_url, export_dir ):
107f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    """Exports the tag_url revision to export_dir.
108f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III       Target directory, including its parent is created if it does not exist.
109f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III       If the directory export_dir exist, it is deleted before export proceed.
110f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    """
111f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    rmdir_if_exist( export_dir )
112f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    svn_command( 'export', tag_url, export_dir )
113f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
114f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdef fix_sources_eol( dist_dir ):
115f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    """Set file EOL for tarball distribution.
116f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    """
117f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    print 'Preparing exported source file EOL for distribution...'
118f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    prune_dirs = antglob.prune_dirs + 'scons-local* ./build* ./libs ./dist'
119f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    win_sources = antglob.glob( dist_dir,
120f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        includes = '**/*.sln **/*.vcproj',
121f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        prune_dirs = prune_dirs )
122f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    unix_sources = antglob.glob( dist_dir,
123f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        includes = '''**/*.h **/*.cpp **/*.inl **/*.txt **/*.dox **/*.py **/*.html **/*.in
124f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        sconscript *.json *.expected AUTHORS LICENSE''',
125f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        excludes = antglob.default_excludes + 'scons.py sconsign.py scons-*',
126f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        prune_dirs = prune_dirs )
127f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    for path in win_sources:
128f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        fixeol.fix_source_eol( path, is_dry_run = False, verbose = True, eol = '\r\n' )
129f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    for path in unix_sources:
130f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        fixeol.fix_source_eol( path, is_dry_run = False, verbose = True, eol = '\n' )
131f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
132f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdef download( url, target_path ):
133f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    """Download file represented by url to target_path.
134f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    """
135f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    f = urllib2.urlopen( url )
136f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    try:
137f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        data = f.read()
138f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    finally:
139f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        f.close()
140f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    fout = open( target_path, 'wb' )
141f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    try:
142f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        fout.write( data )
143f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    finally:
144f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        fout.close()
145f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
146f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdef check_compile( distcheck_top_dir, platform ):
147f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    cmd = [sys.executable, 'scons.py', 'platform=%s' % platform, 'check']
148f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    print 'Running:', ' '.join( cmd )
149f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    log_path = os.path.join( distcheck_top_dir, 'build-%s.log' % platform )
150f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    flog = open( log_path, 'wb' )
151f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    try:
152f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        process = subprocess.Popen( cmd,
153f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III                                    stdout=flog,
154f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III                                    stderr=subprocess.STDOUT,
155f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III                                    cwd=distcheck_top_dir )
156f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        stdout = process.communicate()[0]
157f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        status = (process.returncode == 0)
158f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    finally:
159f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        flog.close()
160f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    return (status, log_path)
161f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
162f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdef write_tempfile( content, **kwargs ):
163f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    fd, path = tempfile.mkstemp( **kwargs )
164f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    f = os.fdopen( fd, 'wt' )
165f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    try:
166f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        f.write( content )
167f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    finally:
168f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        f.close()
169f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    return path
170f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
171f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIclass SFTPError(Exception):
172f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    pass
173f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
174f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdef run_sftp_batch( userhost, sftp, batch, retry=0 ):
175f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    path = write_tempfile( batch, suffix='.sftp', text=True )
176f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    # psftp -agent -C blep,jsoncpp@web.sourceforge.net -batch -b batch.sftp -bc
177f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    cmd = [sftp, '-agent', '-C', '-batch', '-b', path, '-bc', userhost]
178f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    error = None
179f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    for retry_index in xrange(0, max(1,retry)):
180f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        heading = retry_index == 0 and 'Running:' or 'Retrying:'
181f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        print heading, ' '.join( cmd )
182f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
183f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        stdout = process.communicate()[0]
184f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        if process.returncode != 0:
185f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            error = SFTPError( 'SFTP batch failed:\n' + stdout )
186f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        else:
187f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            break
188f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    if error:
189f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        raise error
190f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    return stdout
191f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
192f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdef sourceforge_web_synchro( sourceforge_project, doc_dir,
193f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III                             user=None, sftp='sftp' ):
194f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    """Notes: does not synchronize sub-directory of doc-dir.
195f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    """
196f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    userhost = '%s,%s@web.sourceforge.net' % (user, sourceforge_project)
197f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    stdout = run_sftp_batch( userhost, sftp, """
198f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIcd htdocs
199f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdir
200f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIexit
201f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III""" )
202f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    existing_paths = set()
203f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    collect = 0
204f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    for line in stdout.split('\n'):
205f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        line = line.strip()
206f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        if not collect and line.endswith('> dir'):
207f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            collect = True
208f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        elif collect and line.endswith('> exit'):
209f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            break
210f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        elif collect == 1:
211f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            collect = 2
212f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        elif collect == 2:
213f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            path = line.strip().split()[-1:]
214f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            if path and path[0] not in ('.', '..'):
215f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III                existing_paths.add( path[0] )
216f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    upload_paths = set( [os.path.basename(p) for p in antglob.glob( doc_dir )] )
217f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    paths_to_remove = existing_paths - upload_paths
218f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    if paths_to_remove:
219f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        print 'Removing the following file from web:'
220f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        print '\n'.join( paths_to_remove )
221f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        stdout = run_sftp_batch( userhost, sftp, """cd htdocs
222f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIrm %s
223f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIexit""" % ' '.join(paths_to_remove) )
224f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    print 'Uploading %d files:' % len(upload_paths)
225f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    batch_size = 10
226f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    upload_paths = list(upload_paths)
227f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    start_time = time.time()
228f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    for index in xrange(0,len(upload_paths),batch_size):
229f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        paths = upload_paths[index:index+batch_size]
230f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        file_per_sec = (time.time() - start_time) / (index+1)
231f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        remaining_files = len(upload_paths) - index
232f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        remaining_sec = file_per_sec * remaining_files
233f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        print '%d/%d, ETA=%.1fs' % (index+1, len(upload_paths), remaining_sec)
234f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        run_sftp_batch( userhost, sftp, """cd htdocs
235f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIlcd %s
236f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIImput %s
237f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIexit""" % (doc_dir, ' '.join(paths) ), retry=3 )
238f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
239f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdef sourceforge_release_tarball( sourceforge_project, paths, user=None, sftp='sftp' ):
240f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    userhost = '%s,%s@frs.sourceforge.net' % (user, sourceforge_project)
241f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    run_sftp_batch( userhost, sftp, """
242f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIImput %s
243f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIexit
244f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III""" % (' '.join(paths),) )
245f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
246f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
247f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIdef main():
248f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    usage = """%prog release_version next_dev_version
249f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIUpdate 'version' file to release_version and commit.
250f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIGenerates the document tarball.
251f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIITags the sandbox revision with release_version.
252f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIUpdate 'version' file to next_dev_version and commit.
253f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
254f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIPerforms an svn export of tag release version, and build a source tarball.
255f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
256f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIMust be started in the project top directory.
257f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
258f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIWarning: --force should only be used when developping/testing the release script.
259f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III"""
260f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    from optparse import OptionParser
261f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    parser = OptionParser(usage=usage)
262f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    parser.allow_interspersed_args = False
263f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    parser.add_option('--dot', dest="dot_path", action='store', default=doxybuild.find_program('dot'),
264f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        help="""Path to GraphViz dot tool. Must be full qualified path. [Default: %default]""")
265f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    parser.add_option('--doxygen', dest="doxygen_path", action='store', default=doxybuild.find_program('doxygen'),
266f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        help="""Path to Doxygen tool. [Default: %default]""")
267f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    parser.add_option('--force', dest="ignore_pending_commit", action='store_true', default=False,
268f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        help="""Ignore pending commit. [Default: %default]""")
269f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    parser.add_option('--retag', dest="retag_release", action='store_true', default=False,
270f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        help="""Overwrite release existing tag if it exist. [Default: %default]""")
271f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    parser.add_option('-p', '--platforms', dest="platforms", action='store', default='',
272f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        help="""Comma separated list of platform passed to scons for build check.""")
273f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    parser.add_option('--no-test', dest="no_test", action='store_true', default=False,
274f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        help="""Skips build check.""")
275f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    parser.add_option('--no-web', dest="no_web", action='store_true', default=False,
276f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        help="""Do not update web site.""")
277f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    parser.add_option('-u', '--upload-user', dest="user", action='store',
278f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III                      help="""Sourceforge user for SFTP documentation upload.""")
279f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    parser.add_option('--sftp', dest='sftp', action='store', default=doxybuild.find_program('psftp', 'sftp'),
280f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III                      help="""Path of the SFTP compatible binary used to upload the documentation.""")
281f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    parser.enable_interspersed_args()
282f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    options, args = parser.parse_args()
283f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
284f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    if len(args) != 2:
285f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        parser.error( 'release_version missing on command-line.' )
286f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    release_version = args[0]
287f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    next_version = args[1]
288f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
289f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    if not options.platforms and not options.no_test:
290f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        parser.error( 'You must specify either --platform or --no-test option.' )
291f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
292f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    if options.ignore_pending_commit:
293f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        msg = ''
294f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    else:
295f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        msg = check_no_pending_commit()
296f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    if not msg:
297f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        print 'Setting version to', release_version
298f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        set_version( release_version )
299f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        svn_commit( 'Release ' + release_version )
300f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        tag_url = svn_join_url( SVN_TAG_ROOT, release_version )
301f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        if svn_check_if_tag_exist( tag_url ):
302f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            if options.retag_release:
303f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III                svn_remove_tag( tag_url, 'Overwriting previous tag' )
304f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            else:
305f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III                print 'Aborting, tag %s already exist. Use --retag to overwrite it!' % tag_url
306f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III                sys.exit( 1 )
307f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        svn_tag_sandbox( tag_url, 'Release ' + release_version )
308f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
309f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        print 'Generated doxygen document...'
310f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III##        doc_dirname = r'jsoncpp-api-html-0.5.0'
311f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III##        doc_tarball_path = r'e:\prg\vc\Lib\jsoncpp-trunk\dist\jsoncpp-api-html-0.5.0.tar.gz'
312f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        doc_tarball_path, doc_dirname = doxybuild.build_doc( options, make_release=True )
313f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        doc_distcheck_dir = 'dist/doccheck'
314f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        tarball.decompress( doc_tarball_path, doc_distcheck_dir )
315f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        doc_distcheck_top_dir = os.path.join( doc_distcheck_dir, doc_dirname )
316f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
317f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        export_dir = 'dist/export'
318f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        svn_export( tag_url, export_dir )
319f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        fix_sources_eol( export_dir )
320f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
321f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        source_dir = 'jsoncpp-src-' + release_version
322f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        source_tarball_path = 'dist/%s.tar.gz' % source_dir
323f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        print 'Generating source tarball to', source_tarball_path
324f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        tarball.make_tarball( source_tarball_path, [export_dir], export_dir, prefix_dir=source_dir )
325f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
326f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        amalgamation_tarball_path = 'dist/%s-amalgamation.tar.gz' % source_dir
327f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        print 'Generating amalgamation source tarball to', amalgamation_tarball_path
328f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        amalgamation_dir = 'dist/amalgamation'
329f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        amalgamate.amalgamate_source( export_dir, '%s/jsoncpp.cpp' % amalgamation_dir, 'json/json.h' )
330f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        amalgamation_source_dir = 'jsoncpp-src-amalgamation' + release_version
331f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        tarball.make_tarball( amalgamation_tarball_path, [amalgamation_dir],
332f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III                              amalgamation_dir, prefix_dir=amalgamation_source_dir )
333f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
334f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        # Decompress source tarball, download and install scons-local
335f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        distcheck_dir = 'dist/distcheck'
336f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        distcheck_top_dir = distcheck_dir + '/' + source_dir
337f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        print 'Decompressing source tarball to', distcheck_dir
338f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        rmdir_if_exist( distcheck_dir )
339f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        tarball.decompress( source_tarball_path, distcheck_dir )
340f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        scons_local_path = 'dist/scons-local.tar.gz'
341f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        print 'Downloading scons-local to', scons_local_path
342f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        download( SCONS_LOCAL_URL, scons_local_path )
343f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        print 'Decompressing scons-local to', distcheck_top_dir
344f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        tarball.decompress( scons_local_path, distcheck_top_dir )
345f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
346f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        # Run compilation
347f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        print 'Compiling decompressed tarball'
348f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        all_build_status = True
349f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        for platform in options.platforms.split(','):
350f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            print 'Testing platform:', platform
351f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            build_status, log_path = check_compile( distcheck_top_dir, platform )
352f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            print 'see build log:', log_path
353f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            print build_status and '=> ok' or '=> FAILED'
354f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            all_build_status = all_build_status and build_status
355f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        if not build_status:
356f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            print 'Testing failed on at least one platform, aborting...'
357f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            svn_remove_tag( tag_url, 'Removing tag due to failed testing' )
358f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            sys.exit(1)
359f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        if options.user:
360f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            if not options.no_web:
361f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III                print 'Uploading documentation using user', options.user
362f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III                sourceforge_web_synchro( SOURCEFORGE_PROJECT, doc_distcheck_top_dir, user=options.user, sftp=options.sftp )
363f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III                print 'Completed documentation upload'
364f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            print 'Uploading source and documentation tarballs for release using user', options.user
365f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            sourceforge_release_tarball( SOURCEFORGE_PROJECT,
366f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III                                         [source_tarball_path, doc_tarball_path],
367f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III                                         user=options.user, sftp=options.sftp )
368f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            print 'Source and doc release tarballs uploaded'
369f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        else:
370f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            print 'No upload user specified. Web site and download tarbal were not uploaded.'
371f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III            print 'Tarball can be found at:', doc_tarball_path
372f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
373f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        # Set next version number and commit
374f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        set_version( next_version )
375f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        svn_commit( 'Released ' + release_version )
376f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    else:
377f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III        sys.stderr.write( msg + '\n' )
378f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III
379f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins IIIif __name__ == '__main__':
380f59fb0e83fd0a4b41700d3f5eebdc8d21b173c2eLeon Scroggins III    main()
381