blob: 9dcdcf6aae8a330c35208cd55306ed5468a82b1c [file] [log] [blame]
Baptiste Lepilleur1f4847c2010-02-23 07:57:38 +00001"""Tag the sandbox for release, make source and doc tarballs.
2
3Requires Python 2.6
4
5Example of invocation (use to test the script):
6python makerelease.py --force --retag 0.5.0 0.6.0-dev
7
8Example of invocation when doing a release:
9python makerelease.py 0.5.0 0.6.0-dev
10"""
11import os.path
12import subprocess
13import sys
14import doxybuild
15import subprocess
16import xml.etree.ElementTree as ElementTree
Baptiste Lepilleur7c171ee2010-02-23 08:44:52 +000017import shutil
Baptiste Lepilleure94d2f42010-02-23 21:00:30 +000018from devtools import antglob, fixeol, tarball
Baptiste Lepilleur1f4847c2010-02-23 07:57:38 +000019
20SVN_ROOT = 'https://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/'
21SVN_TAG_ROOT = SVN_ROOT + 'tags/jsoncpp'
22
23def set_version( version ):
24 with open('version','wb') as f:
25 f.write( version.strip() )
26
27class SVNError(Exception):
28 pass
29
30def svn_command( command, *args ):
31 cmd = ['svn', '--non-interactive', command] + list(args)
32 print 'Running:', ' '.join( cmd )
33 process = subprocess.Popen( cmd,
34 stdout=subprocess.PIPE,
35 stderr=subprocess.STDOUT )
36 stdout = process.communicate()[0]
37 if process.returncode:
38 error = SVNError( 'SVN command failed:\n' + stdout )
39 error.returncode = process.returncode
40 raise error
41 return stdout
42
43def check_no_pending_commit():
44 """Checks that there is no pending commit in the sandbox."""
45 stdout = svn_command( 'status', '--xml' )
46 etree = ElementTree.fromstring( stdout )
47 msg = []
48 for entry in etree.getiterator( 'entry' ):
49 path = entry.get('path')
50 status = entry.find('wc-status').get('item')
51 if status != 'unversioned':
52 msg.append( 'File "%s" has pending change (status="%s")' % (path, status) )
53 if msg:
54 msg.insert(0, 'Pending change to commit found in sandbox. Commit them first!' )
55 return '\n'.join( msg )
56
57def svn_join_url( base_url, suffix ):
58 if not base_url.endswith('/'):
59 base_url += '/'
60 if suffix.startswith('/'):
61 suffix = suffix[1:]
62 return base_url + suffix
63
64def svn_check_if_tag_exist( tag_url ):
65 """Checks if a tag exist.
66 Returns: True if the tag exist, False otherwise.
67 """
68 try:
69 list_stdout = svn_command( 'list', tag_url )
70 except SVNError, e:
71 if e.returncode != 1 or not str(e).find('tag_url'):
72 raise e
73 # otherwise ignore error, meaning tag does not exist
74 return False
75 return True
76
77def svn_tag_sandbox( tag_url, message ):
78 """Makes a tag based on the sandbox revisions.
79 """
80 svn_command( 'copy', '-m', message, '.', tag_url )
81
82def svn_remove_tag( tag_url, message ):
83 """Removes an existing tag.
84 """
85 svn_command( 'delete', '-m', message, tag_url )
86
Baptiste Lepilleur7c171ee2010-02-23 08:44:52 +000087def svn_export( tag_url, export_dir ):
88 """Exports the tag_url revision to export_dir.
89 Target directory, including its parent is created if it does not exist.
90 If the directory export_dir exist, it is deleted before export proceed.
91 """
92 if os.path.isdir( export_dir ):
93 shutil.rmtree( export_dir )
94 svn_command( 'export', tag_url, export_dir )
95
Baptiste Lepilleure94d2f42010-02-23 21:00:30 +000096def fix_sources_eol( dist_dir ):
97 """Set file EOL for tarball distribution.
98 """
99 print 'Preparing exported source file EOL for distribution...'
100 prune_dirs = antglob.prune_dirs + 'scons-local* ./build* ./libs ./dist'
101 win_sources = antglob.glob( dist_dir,
102 includes = '**/*.sln **/*.vcproj',
103 prune_dirs = prune_dirs )
104 unix_sources = antglob.glob( dist_dir,
105 includes = '''**/*.h **/*.cpp **/*.inl **/*.txt **/*.dox **/*.py **/*.html **/*.in
106 sconscript *.json *.expected AUTHORS LICENSE''',
107 excludes = antglob.default_excludes + 'scons.py sconsign.py scons-*',
108 prune_dirs = prune_dirs )
109 for path in win_sources:
110 fixeol.fix_source_eol( path, is_dry_run = False, verbose = True, eol = '\r\n' )
111 for path in unix_sources:
112 fixeol.fix_source_eol( path, is_dry_run = False, verbose = True, eol = '\n' )
113
Baptiste Lepilleur1f4847c2010-02-23 07:57:38 +0000114def main():
115 usage = """%prog release_version next_dev_version
116Update 'version' file to release_version and commit.
117Generates the document tarball.
118Tags the sandbox revision with release_version.
119Update 'version' file to next_dev_version and commit.
120
121Performs an svn export of tag release version, and build a source tarball.
122
123Must be started in the project top directory.
124"""
125 from optparse import OptionParser
126 parser = OptionParser(usage=usage)
127 parser.allow_interspersed_args = False
128 parser.add_option('--dot', dest="dot_path", action='store', default=doxybuild.find_program('dot'),
129 help="""Path to GraphViz dot tool. Must be full qualified path. [Default: %default]""")
130 parser.add_option('--doxygen', dest="doxygen_path", action='store', default=doxybuild.find_program('doxygen'),
131 help="""Path to Doxygen tool. [Default: %default]""")
132 parser.add_option('--force', dest="ignore_pending_commit", action='store_true', default=False,
133 help="""Ignore pending commit. [Default: %default]""")
134 parser.add_option('--retag', dest="retag_release", action='store_true', default=False,
135 help="""Overwrite release existing tag if it exist. [Default: %default]""")
136 parser.enable_interspersed_args()
137 options, args = parser.parse_args()
138
139 if len(args) < 1:
140 parser.error( 'release_version missing on command-line.' )
141 release_version = args[0]
142
143 if options.ignore_pending_commit:
144 msg = ''
145 else:
146 msg = check_no_pending_commit()
147 if not msg:
148 print 'Setting version to', release_version
149 set_version( release_version )
150 tag_url = svn_join_url( SVN_TAG_ROOT, release_version )
Baptiste Lepilleure94d2f42010-02-23 21:00:30 +0000151 if svn_check_if_tag_exist( tag_url ):
152 if options.retag_release:
153 svn_remove_tag( tag_url, 'Overwriting previous tag' )
154 else:
155 print 'Aborting, tag %s already exist. Use --retag to overwrite it!' % tag_url
156 sys.exit( 1 )
157 svn_tag_sandbox( tag_url, 'Release ' + release_version )
158
159 print 'Generated doxygen document...'
160 doxybuild.build_doc( options, make_release=True )
161
162 export_dir = 'dist/export'
163 svn_export( tag_url, export_dir )
164 fix_sources_eol( export_dir )
165
166 source_dir = 'jsoncpp-src-' + release_version
167 source_tarball_path = 'dist/%s.tar.gz' % source_dir
168 print 'Generating source tarball to', source_tarball_path
169 tarball.make_tarball( source_tarball_path, [export_dir], export_dir, prefix_dir=source_dir )
Baptiste Lepilleur35bdc072010-02-24 08:05:41 +0000170
171 distcheck_dir = 'dist/distcheck'
172 print 'Decompressing source tarball to', distcheck_dir
173 tarball.decompress( source_tarball_path, distcheck_dir )
Baptiste Lepilleur1f4847c2010-02-23 07:57:38 +0000174 #@todo:
Baptiste Lepilleur1f4847c2010-02-23 07:57:38 +0000175 # ?compile & run & check
176 # ?upload documentation
177 else:
178 sys.stderr.write( msg + '\n' )
179
180if __name__ == '__main__':
181 main()