PageRenderTime 49ms CodeModel.GetById 12ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 0ms

/scripts/update_version_files.py

https://bitbucket.org/lindenlab/viewer-beta/
Python | 343 lines | 302 code | 7 blank | 34 comment | 13 complexity | 9fa3b106048c91df89e511c20162210e MD5 | raw file
  1#!/usr/bin/env python
  2"""\
  3@file   update_version_files.py
  4@brief  Update all of the various files in the repository to a new version number,
  5instead of having to figure it out by hand
  6
  7$LicenseInfo:firstyear=2010&license=viewerlgpl$
  8Second Life Viewer Source Code
  9Copyright (C) 2010-2011, Linden Research, Inc.
 10
 11This library is free software; you can redistribute it and/or
 12modify it under the terms of the GNU Lesser General Public
 13License as published by the Free Software Foundation;
 14version 2.1 of the License only.
 15
 16This library is distributed in the hope that it will be useful,
 17but WITHOUT ANY WARRANTY; without even the implied warranty of
 18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 19Lesser General Public License for more details.
 20
 21You should have received a copy of the GNU Lesser General Public
 22License along with this library; if not, write to the Free Software
 23Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 24
 25Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 26$/LicenseInfo$
 27"""
 28
 29import sys
 30import os.path
 31
 32# Look for indra/lib/python in all possible parent directories ...
 33# This is an improvement over the setup-path.py method used previously:
 34#  * the script may blocated anywhere inside the source tree
 35#  * it doesn't depend on the current directory
 36#  * it doesn't depend on another file being present.
 37
 38def add_indra_lib_path():
 39    root = os.path.realpath(__file__)
 40    # always insert the directory of the script in the search path
 41    dir = os.path.dirname(root)
 42    if dir not in sys.path:
 43        sys.path.insert(0, dir)
 44
 45    # Now go look for indra/lib/python in the parent dies
 46    while root != os.path.sep:
 47        root = os.path.dirname(root)
 48        dir = os.path.join(root, 'indra', 'lib', 'python')
 49        if os.path.isdir(dir):
 50            if dir not in sys.path:
 51                sys.path.insert(0, dir)
 52            break
 53    else:
 54        print >>sys.stderr, "This script is not inside a valid installation."
 55        sys.exit(1)
 56
 57add_indra_lib_path()
 58
 59import getopt, os, re, commands
 60from indra.util import llversion
 61
 62def usage():
 63    print "Usage:"
 64    print sys.argv[0] + """ [options]
 65
 66Options:
 67  --version
 68   Specify the version string to replace current version.
 69  --revision
 70   Specify the revision to replace the last digit of the version.
 71   By default, revision is computed from the version control system.
 72  --skip-on-branch
 73   Specify a regular expression against which the current branch
 74   is matched. If it matches, then leave version strings alone.
 75   Use this to avoid changing version strings on release candidate
 76   builds.
 77  --server
 78   Update llversionserver.h only with new version
 79  --viewer
 80   Update llversionviewer.h only with new version
 81  --channel
 82   Specify the viewer channel string to replace current channel.
 83  --server_channel
 84   Specify the server channel string to replace current channel.
 85  --verbose
 86  --help
 87   Print this message and exit.
 88
 89Common Uses:
 90   # Update server and viewer build numbers to the current hg revision:
 91   update_version_files.py
 92
 93   # Update build numbers unless we are on a release branch:
 94   update_version_files.py --skip-on-branch='^Branch_'
 95
 96   # Update server and viewer version numbers explicitly:
 97   update_version_files.py --version=1.18.1.6     
 98                               
 99   # Update just the viewer version number explicitly:
100   update_version_files.py --viewer --version=1.18.1.6     
101
102   # Update just the server build number to the current hg revision:
103   update_version_files.py --server
104                               
105   # Update the viewer channel
106   update_version_files.py --channel="First Look Puppeteering"
107                               
108   # Update the server channel
109   update_version_files.py --server_channel="Het Grid"
110   
111"""
112def _getstatusoutput(cmd):
113    """Return Win32 (status, output) of executing cmd
114in a shell."""
115    if os.path.sep != "/":
116        # stupid #%#$$ windows
117        cmd = 'cmd.exe /c "'+cmd+'"'
118    pipe = os.popen(cmd, 'r')
119    text = pipe.read()
120    sts = pipe.close()
121    if sts is None: sts = 0
122    if text[-1:] == '\n': text = text[:-1]
123    return sts, text
124
125re_map = {}
126
127#re_map['filename'] = (('pattern', 'replacement'),
128#                      ('pattern', 'replacement')
129re_map['indra/llcommon/llversionviewer.h'] = \
130    (('const S32 LL_VERSION_MAJOR = (\d+);',
131      'const S32 LL_VERSION_MAJOR = %(VER_MAJOR)s;'),
132     ('const S32 LL_VERSION_MINOR = (\d+);',
133      'const S32 LL_VERSION_MINOR = %(VER_MINOR)s;'),
134     ('const S32 LL_VERSION_PATCH = (\d+);',
135      'const S32 LL_VERSION_PATCH = %(VER_PATCH)s;'),
136     ('const S32 LL_VERSION_BUILD = (\d+);',
137      'const S32 LL_VERSION_BUILD = %(VER_BUILD)s;'),
138     ('const char \* const LL_CHANNEL = "(.+)";',
139      'const char * const LL_CHANNEL = "%(VIEWER_CHANNEL)s";'))
140re_map['indra/llcommon/llversionserver.h'] = \
141    (('const S32 LL_VERSION_MAJOR = (\d+);',
142      'const S32 LL_VERSION_MAJOR = %(SERVER_VER_MAJOR)s;'),
143     ('const S32 LL_VERSION_MINOR = (\d+);',
144      'const S32 LL_VERSION_MINOR = %(SERVER_VER_MINOR)s;'),
145     ('const S32 LL_VERSION_PATCH = (\d+);',
146      'const S32 LL_VERSION_PATCH = %(SERVER_VER_PATCH)s;'),
147     ('const S32 LL_VERSION_BUILD = (\d+);',
148      'const S32 LL_VERSION_BUILD = %(SERVER_VER_BUILD)s;'),
149     ('const char \* const LL_CHANNEL = "(.+)";',
150      'const char * const LL_CHANNEL = "%(SERVER_CHANNEL)s";'))
151re_map['indra/newview/res/viewerRes.rc'] = \
152    (('FILEVERSION [0-9,]+',
153      'FILEVERSION %(VER_MAJOR)s,%(VER_MINOR)s,%(VER_PATCH)s,%(VER_BUILD)s'),
154     ('PRODUCTVERSION [0-9,]+',
155      'PRODUCTVERSION %(VER_MAJOR)s,%(VER_MINOR)s,%(VER_PATCH)s,%(VER_BUILD)s'),
156     ('VALUE "FileVersion", "[0-9.]+"',
157      'VALUE "FileVersion", "%(VER_MAJOR)s.%(VER_MINOR)s.%(VER_PATCH)s.%(VER_BUILD)s"'),
158     ('VALUE "ProductVersion", "[0-9.]+"',
159      'VALUE "ProductVersion", "%(VER_MAJOR)s.%(VER_MINOR)s.%(VER_PATCH)s.%(VER_BUILD)s"'))
160
161# Trailing ',' in top level tuple is special form to avoid parsing issues with one element tuple
162re_map['indra/newview/Info-SecondLife.plist'] = \
163    (('<key>CFBundleVersion</key>\n\t<string>[0-9.]+</string>',
164      '<key>CFBundleVersion</key>\n\t<string>%(VER_MAJOR)s.%(VER_MINOR)s.%(VER_PATCH)s.%(VER_BUILD)s</string>'),)
165
166# This will probably only work as long as InfoPlist.strings is NOT UTF16, which is should be...
167re_map['indra/newview/English.lproj/InfoPlist.strings'] = \
168    (('CFBundleShortVersionString = "Second Life version [0-9.]+";',
169      'CFBundleShortVersionString = "Second Life version %(VER_MAJOR)s.%(VER_MINOR)s.%(VER_PATCH)s.%(VER_BUILD)s";'),
170     ('CFBundleGetInfoString = "Second Life version [0-9.]+',
171      'CFBundleGetInfoString = "Second Life version %(VER_MAJOR)s.%(VER_MINOR)s.%(VER_PATCH)s.%(VER_BUILD)s'))
172
173
174version_re = re.compile('(\d+).(\d+).(\d+).(\d+)')
175
176def main():
177    script_path = os.path.dirname(__file__)
178    src_root = script_path + "/../"
179    verbose = False
180
181    opts, args = getopt.getopt(sys.argv[1:],
182                               "",
183                               ['version=',
184                                'revision=',
185                                'channel=',
186                                'server_channel=',
187                                'skip-on-branch=',
188                                'verbose',
189                                'server',
190                                'viewer',
191                                'help'])
192    update_server = False
193    update_viewer = False
194    new_version = None
195    new_revision = None
196    new_viewer_channel = None
197    new_server_channel = None
198    skip_on_branch_re = None
199    for o,a in opts:
200        if o in ('--version'):
201            new_version = a
202        if o in ('--revision'):
203            new_revision = a
204        if o in ('--skip-on-branch'):
205            skip_on_branch_re = re.compile(a)
206        if o in ('--channel'):
207            new_viewer_channel = a
208        if o in ('--server_channel'):
209            new_server_channel = a
210        if o in ('--verbose'):
211            verbose = True
212        if o in ('--server'):
213            update_server = True
214        if o in ('--viewer'):
215            update_viewer = True
216        if o in ('--help'):
217            usage()
218            return 0
219
220    if not(update_server or update_viewer):
221        update_server = True
222        update_viewer = True
223
224    # Get current channel/version from llversion*.h
225    try:
226        viewer_channel = llversion.get_viewer_channel()
227        viewer_version = llversion.get_viewer_version()
228    except IOError:
229        print "Viewer version file not present, skipping..."
230        viewer_channel = None
231        viewer_version = None
232        update_viewer = False
233
234    try:
235        server_channel = llversion.get_server_channel()
236        server_version = llversion.get_server_version()
237    except IOError:
238        print "Server version file not present, skipping..."
239        server_channel = None
240        server_version = None
241        update_server = False
242
243    if verbose:
244        print "Source Path:", src_root
245        if viewer_channel != None:
246            print "Current viewer channel/version: '%(viewer_channel)s' / '%(viewer_version)s'" % locals()
247        if server_channel != None:          
248            print "Current server channel/version: '%(server_channel)s' / '%(server_version)s'" % locals()
249        print
250
251    # Determine new channel(s)
252    if new_viewer_channel != None and len(new_viewer_channel) > 0:
253        viewer_channel = new_viewer_channel
254    if new_server_channel != None and len(new_server_channel) > 0:
255        server_channel = new_server_channel
256
257    # Determine new version(s)
258    if new_version:
259        m = version_re.match(new_version)
260        if not m:
261            print "Invalid version string specified!"
262            return -1
263        if update_viewer:
264            viewer_version = new_version
265        if update_server:
266            server_version = new_version
267    else:
268
269        if llversion.using_hg():
270            if new_revision:
271                revision = new_revision
272            else:
273                revision = llversion.get_hg_changeset()
274            branch = llversion.get_hg_repo()
275        elif new_revision:
276            revision = new_revision
277            branch = "unknown"
278        else:
279            print >>sys.stderr, "ERROR: could not determine revision and branch"
280            return -1
281        
282        if skip_on_branch_re and skip_on_branch_re.match(branch):
283            print "Release Candidate Build, leaving version files untouched."
284            return 0
285        if update_viewer:
286            m = version_re.match(viewer_version)
287            viewer_version = m.group(1)+"."+m.group(2)+"."+m.group(3)+"."+revision
288        if update_server:
289            m = version_re.match(server_version)
290            server_version = m.group(1)+"."+m.group(2)+"."+m.group(3)+"."+revision
291
292    if verbose:
293        if update_viewer:
294            print "Setting viewer channel/version: '%(viewer_channel)s' / '%(viewer_version)s'" % locals()
295        if update_server:
296            print "Setting server channel/version: '%(server_channel)s' / '%(server_version)s'" % locals()
297        print
298
299    # split out version parts
300    if viewer_version != None:
301        m = version_re.match(viewer_version)
302        VER_MAJOR = m.group(1)
303        VER_MINOR = m.group(2)
304        VER_PATCH = m.group(3)
305        VER_BUILD = m.group(4)
306
307    if server_version != None:
308        m = version_re.match(server_version)
309        SERVER_VER_MAJOR = m.group(1)
310        SERVER_VER_MINOR = m.group(2)
311        SERVER_VER_PATCH = m.group(3)
312        SERVER_VER_BUILD = m.group(4)
313
314    # For readability and symmetry with version strings:
315    VIEWER_CHANNEL = viewer_channel
316    SERVER_CHANNEL = server_channel
317
318    # Iterate through all of the files in the map, and apply the
319    # substitution filters
320    for filename in re_map.keys():
321        try:
322            # Read the entire file into a string
323            full_fn = src_root + '/' + filename
324            file = open(full_fn,"r")
325            file_str = file.read()
326            file.close()
327
328            if verbose:
329                print "Processing file:",filename
330            for rule in re_map[filename]:
331                repl = rule[1] % locals()
332                file_str = re.sub(rule[0], repl, file_str)
333
334            file = open(full_fn,"w")
335            file.write(file_str)
336            file.close()
337        except IOError:
338            print "File %(filename)s not present, skipping..." % locals()
339    return 0
340
341if __name__ == '__main__':
342    sys.exit(main())
343