diff options
author | 2015-01-10 13:53:11 +0100 | |
---|---|---|
committer | 2015-01-10 13:53:11 +0100 | |
commit | 02d37b6915e453fbc40afc80830d9a2cbb459d1f (patch) | |
tree | 87d7a4c5a93f9ecca1d955cfdac6fe25399a9b69 /3rdparty/jsoncpp/makerelease.py | |
parent | 950a428641808b5d083dcfddebbed06367f15a15 (diff) |
Added integral version of jsoncpp source (nw)
Diffstat (limited to '3rdparty/jsoncpp/makerelease.py')
-rw-r--r-- | 3rdparty/jsoncpp/makerelease.py | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/3rdparty/jsoncpp/makerelease.py b/3rdparty/jsoncpp/makerelease.py new file mode 100644 index 00000000000..90276d120bb --- /dev/null +++ b/3rdparty/jsoncpp/makerelease.py @@ -0,0 +1,384 @@ +"""Tag the sandbox for release, make source and doc tarballs. + +Requires Python 2.6 + +Example of invocation (use to test the script): +python makerelease.py --platform=msvc6,msvc71,msvc80,msvc90,mingw -ublep 0.6.0 0.7.0-dev + +When testing this script: +python makerelease.py --force --retag --platform=msvc6,msvc71,msvc80,mingw -ublep test-0.6.0 test-0.6.1-dev + +Example of invocation when doing a release: +python makerelease.py 0.5.0 0.6.0-dev + +Note: This was for Subversion. Now that we are in GitHub, we do not +need to build versioned tarballs anymore, so makerelease.py is defunct. +""" +from __future__ import print_function +import os.path +import subprocess +import sys +import doxybuild +import subprocess +import xml.etree.ElementTree as ElementTree +import shutil +import urllib2 +import tempfile +import os +import time +from devtools import antglob, fixeol, tarball +import amalgamate + +SVN_ROOT = 'https://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/' +SVN_TAG_ROOT = SVN_ROOT + 'tags/jsoncpp' +SCONS_LOCAL_URL = 'http://sourceforge.net/projects/scons/files/scons-local/1.2.0/scons-local-1.2.0.tar.gz/download' +SOURCEFORGE_PROJECT = 'jsoncpp' + +def set_version( version ): + with open('version','wb') as f: + f.write( version.strip() ) + +def rmdir_if_exist( dir_path ): + if os.path.isdir( dir_path ): + shutil.rmtree( dir_path ) + +class SVNError(Exception): + pass + +def svn_command( command, *args ): + cmd = ['svn', '--non-interactive', command] + list(args) + print('Running:', ' '.join( cmd )) + process = subprocess.Popen( cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT ) + stdout = process.communicate()[0] + if process.returncode: + error = SVNError( 'SVN command failed:\n' + stdout ) + error.returncode = process.returncode + raise error + return stdout + +def check_no_pending_commit(): + """Checks that there is no pending commit in the sandbox.""" + stdout = svn_command( 'status', '--xml' ) + etree = ElementTree.fromstring( stdout ) + msg = [] + for entry in etree.getiterator( 'entry' ): + path = entry.get('path') + status = entry.find('wc-status').get('item') + if status != 'unversioned' and path != 'version': + msg.append( 'File "%s" has pending change (status="%s")' % (path, status) ) + if msg: + msg.insert(0, 'Pending change to commit found in sandbox. Commit them first!' ) + return '\n'.join( msg ) + +def svn_join_url( base_url, suffix ): + if not base_url.endswith('/'): + base_url += '/' + if suffix.startswith('/'): + suffix = suffix[1:] + return base_url + suffix + +def svn_check_if_tag_exist( tag_url ): + """Checks if a tag exist. + Returns: True if the tag exist, False otherwise. + """ + try: + list_stdout = svn_command( 'list', tag_url ) + except SVNError as e: + if e.returncode != 1 or not str(e).find('tag_url'): + raise e + # otherwise ignore error, meaning tag does not exist + return False + return True + +def svn_commit( message ): + """Commit the sandbox, providing the specified comment. + """ + svn_command( 'ci', '-m', message ) + +def svn_tag_sandbox( tag_url, message ): + """Makes a tag based on the sandbox revisions. + """ + svn_command( 'copy', '-m', message, '.', tag_url ) + +def svn_remove_tag( tag_url, message ): + """Removes an existing tag. + """ + svn_command( 'delete', '-m', message, tag_url ) + +def svn_export( tag_url, export_dir ): + """Exports the tag_url revision to export_dir. + Target directory, including its parent is created if it does not exist. + If the directory export_dir exist, it is deleted before export proceed. + """ + rmdir_if_exist( export_dir ) + svn_command( 'export', tag_url, export_dir ) + +def fix_sources_eol( dist_dir ): + """Set file EOL for tarball distribution. + """ + print('Preparing exported source file EOL for distribution...') + prune_dirs = antglob.prune_dirs + 'scons-local* ./build* ./libs ./dist' + win_sources = antglob.glob( dist_dir, + includes = '**/*.sln **/*.vcproj', + prune_dirs = prune_dirs ) + unix_sources = antglob.glob( dist_dir, + includes = '''**/*.h **/*.cpp **/*.inl **/*.txt **/*.dox **/*.py **/*.html **/*.in + sconscript *.json *.expected AUTHORS LICENSE''', + excludes = antglob.default_excludes + 'scons.py sconsign.py scons-*', + prune_dirs = prune_dirs ) + for path in win_sources: + fixeol.fix_source_eol( path, is_dry_run = False, verbose = True, eol = '\r\n' ) + for path in unix_sources: + fixeol.fix_source_eol( path, is_dry_run = False, verbose = True, eol = '\n' ) + +def download( url, target_path ): + """Download file represented by url to target_path. + """ + f = urllib2.urlopen( url ) + try: + data = f.read() + finally: + f.close() + fout = open( target_path, 'wb' ) + try: + fout.write( data ) + finally: + fout.close() + +def check_compile( distcheck_top_dir, platform ): + cmd = [sys.executable, 'scons.py', 'platform=%s' % platform, 'check'] + print('Running:', ' '.join( cmd )) + log_path = os.path.join( distcheck_top_dir, 'build-%s.log' % platform ) + flog = open( log_path, 'wb' ) + try: + process = subprocess.Popen( cmd, + stdout=flog, + stderr=subprocess.STDOUT, + cwd=distcheck_top_dir ) + stdout = process.communicate()[0] + status = (process.returncode == 0) + finally: + flog.close() + return (status, log_path) + +def write_tempfile( content, **kwargs ): + fd, path = tempfile.mkstemp( **kwargs ) + f = os.fdopen( fd, 'wt' ) + try: + f.write( content ) + finally: + f.close() + return path + +class SFTPError(Exception): + pass + +def run_sftp_batch( userhost, sftp, batch, retry=0 ): + path = write_tempfile( batch, suffix='.sftp', text=True ) + # psftp -agent -C blep,jsoncpp@web.sourceforge.net -batch -b batch.sftp -bc + cmd = [sftp, '-agent', '-C', '-batch', '-b', path, '-bc', userhost] + error = None + for retry_index in range(0, max(1,retry)): + heading = retry_index == 0 and 'Running:' or 'Retrying:' + print(heading, ' '.join( cmd )) + process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT ) + stdout = process.communicate()[0] + if process.returncode != 0: + error = SFTPError( 'SFTP batch failed:\n' + stdout ) + else: + break + if error: + raise error + return stdout + +def sourceforge_web_synchro( sourceforge_project, doc_dir, + user=None, sftp='sftp' ): + """Notes: does not synchronize sub-directory of doc-dir. + """ + userhost = '%s,%s@web.sourceforge.net' % (user, sourceforge_project) + stdout = run_sftp_batch( userhost, sftp, """ +cd htdocs +dir +exit +""" ) + existing_paths = set() + collect = 0 + for line in stdout.split('\n'): + line = line.strip() + if not collect and line.endswith('> dir'): + collect = True + elif collect and line.endswith('> exit'): + break + elif collect == 1: + collect = 2 + elif collect == 2: + path = line.strip().split()[-1:] + if path and path[0] not in ('.', '..'): + existing_paths.add( path[0] ) + upload_paths = set( [os.path.basename(p) for p in antglob.glob( doc_dir )] ) + paths_to_remove = existing_paths - upload_paths + if paths_to_remove: + print('Removing the following file from web:') + print('\n'.join( paths_to_remove )) + stdout = run_sftp_batch( userhost, sftp, """cd htdocs +rm %s +exit""" % ' '.join(paths_to_remove) ) + print('Uploading %d files:' % len(upload_paths)) + batch_size = 10 + upload_paths = list(upload_paths) + start_time = time.time() + for index in range(0,len(upload_paths),batch_size): + paths = upload_paths[index:index+batch_size] + file_per_sec = (time.time() - start_time) / (index+1) + remaining_files = len(upload_paths) - index + remaining_sec = file_per_sec * remaining_files + print('%d/%d, ETA=%.1fs' % (index+1, len(upload_paths), remaining_sec)) + run_sftp_batch( userhost, sftp, """cd htdocs +lcd %s +mput %s +exit""" % (doc_dir, ' '.join(paths) ), retry=3 ) + +def sourceforge_release_tarball( sourceforge_project, paths, user=None, sftp='sftp' ): + userhost = '%s,%s@frs.sourceforge.net' % (user, sourceforge_project) + run_sftp_batch( userhost, sftp, """ +mput %s +exit +""" % (' '.join(paths),) ) + + +def main(): + usage = """%prog release_version next_dev_version +Update 'version' file to release_version and commit. +Generates the document tarball. +Tags the sandbox revision with release_version. +Update 'version' file to next_dev_version and commit. + +Performs an svn export of tag release version, and build a source tarball. + +Must be started in the project top directory. + +Warning: --force should only be used when developping/testing the release script. +""" + from optparse import OptionParser + parser = OptionParser(usage=usage) + parser.allow_interspersed_args = False + parser.add_option('--dot', dest="dot_path", action='store', default=doxybuild.find_program('dot'), + help="""Path to GraphViz dot tool. Must be full qualified path. [Default: %default]""") + parser.add_option('--doxygen', dest="doxygen_path", action='store', default=doxybuild.find_program('doxygen'), + help="""Path to Doxygen tool. [Default: %default]""") + parser.add_option('--force', dest="ignore_pending_commit", action='store_true', default=False, + help="""Ignore pending commit. [Default: %default]""") + parser.add_option('--retag', dest="retag_release", action='store_true', default=False, + help="""Overwrite release existing tag if it exist. [Default: %default]""") + parser.add_option('-p', '--platforms', dest="platforms", action='store', default='', + help="""Comma separated list of platform passed to scons for build check.""") + parser.add_option('--no-test', dest="no_test", action='store_true', default=False, + help="""Skips build check.""") + parser.add_option('--no-web', dest="no_web", action='store_true', default=False, + help="""Do not update web site.""") + parser.add_option('-u', '--upload-user', dest="user", action='store', + help="""Sourceforge user for SFTP documentation upload.""") + parser.add_option('--sftp', dest='sftp', action='store', default=doxybuild.find_program('psftp', 'sftp'), + help="""Path of the SFTP compatible binary used to upload the documentation.""") + parser.enable_interspersed_args() + options, args = parser.parse_args() + + if len(args) != 2: + parser.error( 'release_version missing on command-line.' ) + release_version = args[0] + next_version = args[1] + + if not options.platforms and not options.no_test: + parser.error( 'You must specify either --platform or --no-test option.' ) + + if options.ignore_pending_commit: + msg = '' + else: + msg = check_no_pending_commit() + if not msg: + print('Setting version to', release_version) + set_version( release_version ) + svn_commit( 'Release ' + release_version ) + tag_url = svn_join_url( SVN_TAG_ROOT, release_version ) + if svn_check_if_tag_exist( tag_url ): + if options.retag_release: + svn_remove_tag( tag_url, 'Overwriting previous tag' ) + else: + print('Aborting, tag %s already exist. Use --retag to overwrite it!' % tag_url) + sys.exit( 1 ) + svn_tag_sandbox( tag_url, 'Release ' + release_version ) + + print('Generated doxygen document...') +## doc_dirname = r'jsoncpp-api-html-0.5.0' +## doc_tarball_path = r'e:\prg\vc\Lib\jsoncpp-trunk\dist\jsoncpp-api-html-0.5.0.tar.gz' + doc_tarball_path, doc_dirname = doxybuild.build_doc( options, make_release=True ) + doc_distcheck_dir = 'dist/doccheck' + tarball.decompress( doc_tarball_path, doc_distcheck_dir ) + doc_distcheck_top_dir = os.path.join( doc_distcheck_dir, doc_dirname ) + + export_dir = 'dist/export' + svn_export( tag_url, export_dir ) + fix_sources_eol( export_dir ) + + source_dir = 'jsoncpp-src-' + release_version + source_tarball_path = 'dist/%s.tar.gz' % source_dir + print('Generating source tarball to', source_tarball_path) + tarball.make_tarball( source_tarball_path, [export_dir], export_dir, prefix_dir=source_dir ) + + amalgamation_tarball_path = 'dist/%s-amalgamation.tar.gz' % source_dir + print('Generating amalgamation source tarball to', amalgamation_tarball_path) + amalgamation_dir = 'dist/amalgamation' + amalgamate.amalgamate_source( export_dir, '%s/jsoncpp.cpp' % amalgamation_dir, 'json/json.h' ) + amalgamation_source_dir = 'jsoncpp-src-amalgamation' + release_version + tarball.make_tarball( amalgamation_tarball_path, [amalgamation_dir], + amalgamation_dir, prefix_dir=amalgamation_source_dir ) + + # Decompress source tarball, download and install scons-local + distcheck_dir = 'dist/distcheck' + distcheck_top_dir = distcheck_dir + '/' + source_dir + print('Decompressing source tarball to', distcheck_dir) + rmdir_if_exist( distcheck_dir ) + tarball.decompress( source_tarball_path, distcheck_dir ) + scons_local_path = 'dist/scons-local.tar.gz' + print('Downloading scons-local to', scons_local_path) + download( SCONS_LOCAL_URL, scons_local_path ) + print('Decompressing scons-local to', distcheck_top_dir) + tarball.decompress( scons_local_path, distcheck_top_dir ) + + # Run compilation + print('Compiling decompressed tarball') + all_build_status = True + for platform in options.platforms.split(','): + print('Testing platform:', platform) + build_status, log_path = check_compile( distcheck_top_dir, platform ) + print('see build log:', log_path) + print(build_status and '=> ok' or '=> FAILED') + all_build_status = all_build_status and build_status + if not build_status: + print('Testing failed on at least one platform, aborting...') + svn_remove_tag( tag_url, 'Removing tag due to failed testing' ) + sys.exit(1) + if options.user: + if not options.no_web: + print('Uploading documentation using user', options.user) + sourceforge_web_synchro( SOURCEFORGE_PROJECT, doc_distcheck_top_dir, user=options.user, sftp=options.sftp ) + print('Completed documentation upload') + print('Uploading source and documentation tarballs for release using user', options.user) + sourceforge_release_tarball( SOURCEFORGE_PROJECT, + [source_tarball_path, doc_tarball_path], + user=options.user, sftp=options.sftp ) + print('Source and doc release tarballs uploaded') + else: + print('No upload user specified. Web site and download tarbal were not uploaded.') + print('Tarball can be found at:', doc_tarball_path) + + # Set next version number and commit + set_version( next_version ) + svn_commit( 'Released ' + release_version ) + else: + sys.stderr.write( msg + '\n' ) + +if __name__ == '__main__': + main() |