Newer
Older
Merov Linden
committed
#!/usr/bin/env python
"""\
@file update_version_files.py
@brief Update all of the various files in the repository to a new version number,
instead of having to figure it out by hand
$LicenseInfo:firstyear=2010&license=viewerlgpl$
Second Life Viewer Source Code
Copyright (C) 2010-2011, Linden Research, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2.1 of the License only.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
$/LicenseInfo$
"""
Andrew Meadows
committed
# Look for indra/lib/python in all possible parent directories ...
# This is an improvement over the setup-path.py method used previously:
# * the script may blocated anywhere inside the source tree
# * it doesn't depend on the current directory
# * it doesn't depend on another file being present.
def add_indra_lib_path():
root = os.path.realpath(__file__)
# always insert the directory of the script in the search path
dir = os.path.dirname(root)
if dir not in sys.path:
sys.path.insert(0, dir)
# Now go look for indra/lib/python in the parent dies
while root != os.path.sep:
root = os.path.dirname(root)
dir = os.path.join(root, 'indra', 'lib', 'python')
if os.path.isdir(dir):
if dir not in sys.path:
sys.path.insert(0, dir)
break
else:
print >>sys.stderr, "This script is not inside a valid installation."
sys.exit(1)
add_indra_lib_path()
Andrew Meadows
committed
import getopt, os, re, commands
Tess Chu
committed
from indra.util import llversion
def usage():
print "Usage:"
print sys.argv[0] + """ [options]
Options:
--version
Specify the version string to replace current version.
--revision
Specify the revision to replace the last digit of the version.
By default, revision is computed from the version control system.
--skip-on-branch
Specify a regular expression against which the current branch
is matched. If it matches, then leave version strings alone.
Use this to avoid changing version strings on release candidate
builds.
Tess Chu
committed
--server
Update llversionserver.h only with new version
--viewer
Update llversionviewer.h only with new version
--channel
Specify the viewer channel string to replace current channel.
--server_channel
Specify the server channel string to replace current channel.
--verbose
--help
Print this message and exit.
Common Uses:
Merov Linden
committed
# Update server and viewer build numbers to the current hg revision:
Tess Chu
committed
update_version_files.py
# Update build numbers unless we are on a release branch:
update_version_files.py --skip-on-branch='^Branch_'
Tess Chu
committed
# Update server and viewer version numbers explicitly:
update_version_files.py --version=1.18.1.6
# Update just the viewer version number explicitly:
update_version_files.py --viewer --version=1.18.1.6
Merov Linden
committed
# Update just the server build number to the current hg revision:
Tess Chu
committed
update_version_files.py --server
# Update the viewer channel
update_version_files.py --channel="First Look Puppeteering"
# Update the server channel
update_version_files.py --server_channel="Het Grid"
"""
def _getstatusoutput(cmd):
"""Return Win32 (status, output) of executing cmd
in a shell."""
if os.path.sep != "/":
# stupid #%#$$ windows
cmd = 'cmd.exe /c "'+cmd+'"'
pipe = os.popen(cmd, 'r')
text = pipe.read()
sts = pipe.close()
if sts is None: sts = 0
if text[-1:] == '\n': text = text[:-1]
return sts, text
re_map = {}
#re_map['filename'] = (('pattern', 'replacement'),
# ('pattern', 'replacement')
Tess Chu
committed
re_map['indra/llcommon/llversionviewer.h'] = \
(('const S32 LL_VERSION_MAJOR = (\d+);',
'const S32 LL_VERSION_MAJOR = %(VER_MAJOR)s;'),
('const S32 LL_VERSION_MINOR = (\d+);',
'const S32 LL_VERSION_MINOR = %(VER_MINOR)s;'),
('const S32 LL_VERSION_PATCH = (\d+);',
'const S32 LL_VERSION_PATCH = %(VER_PATCH)s;'),
('const S32 LL_VERSION_BUILD = (\d+);',
'const S32 LL_VERSION_BUILD = %(VER_BUILD)s;'),
('const char \* const LL_CHANNEL = "(.+)";',
'const char * const LL_CHANNEL = "%(VIEWER_CHANNEL)s";'))
Tess Chu
committed
re_map['indra/llcommon/llversionserver.h'] = \
(('const S32 LL_VERSION_MAJOR = (\d+);',
'const S32 LL_VERSION_MAJOR = %(SERVER_VER_MAJOR)s;'),
('const S32 LL_VERSION_MINOR = (\d+);',
'const S32 LL_VERSION_MINOR = %(SERVER_VER_MINOR)s;'),
('const S32 LL_VERSION_PATCH = (\d+);',
'const S32 LL_VERSION_PATCH = %(SERVER_VER_PATCH)s;'),
('const S32 LL_VERSION_BUILD = (\d+);',
'const S32 LL_VERSION_BUILD = %(SERVER_VER_BUILD)s;'),
('const char \* const LL_CHANNEL = "(.+)";',
'const char * const LL_CHANNEL = "%(SERVER_CHANNEL)s";'))
Bryan O'Sullivan
committed
re_map['indra/newview/res/viewerRes.rc'] = \
Tess Chu
committed
(('FILEVERSION [0-9,]+',
'FILEVERSION %(VER_MAJOR)s,%(VER_MINOR)s,%(VER_PATCH)s,%(VER_BUILD)s'),
('PRODUCTVERSION [0-9,]+',
'PRODUCTVERSION %(VER_MAJOR)s,%(VER_MINOR)s,%(VER_PATCH)s,%(VER_BUILD)s'),
('VALUE "FileVersion", "[0-9.]+"',
'VALUE "FileVersion", "%(VER_MAJOR)s.%(VER_MINOR)s.%(VER_PATCH)s.%(VER_BUILD)s"'),
('VALUE "ProductVersion", "[0-9.]+"',
'VALUE "ProductVersion", "%(VER_MAJOR)s.%(VER_MINOR)s.%(VER_PATCH)s.%(VER_BUILD)s"'))
# Trailing ',' in top level tuple is special form to avoid parsing issues with one element tuple
re_map['indra/newview/Info-SecondLife.plist'] = \
Tess Chu
committed
(('<key>CFBundleVersion</key>\n\t<string>[0-9.]+</string>',
'<key>CFBundleVersion</key>\n\t<string>%(VER_MAJOR)s.%(VER_MINOR)s.%(VER_PATCH)s.%(VER_BUILD)s</string>'),)
# This will probably only work as long as InfoPlist.strings is NOT UTF16, which is should be...
re_map['indra/newview/English.lproj/InfoPlist.strings'] = \
Tess Chu
committed
(('CFBundleShortVersionString = "Second Life version [0-9.]+";',
'CFBundleShortVersionString = "Second Life version %(VER_MAJOR)s.%(VER_MINOR)s.%(VER_PATCH)s.%(VER_BUILD)s";'),
('CFBundleGetInfoString = "Second Life version [0-9.]+',
'CFBundleGetInfoString = "Second Life version %(VER_MAJOR)s.%(VER_MINOR)s.%(VER_PATCH)s.%(VER_BUILD)s'))
Merov Linden
committed
version_re = re.compile('(\d+).(\d+).(\d+).(\d+)')
Tess Chu
committed
script_path = os.path.dirname(__file__)
src_root = script_path + "/../"
verbose = False
opts, args = getopt.getopt(sys.argv[1:],
"",
'channel=',
'server_channel=',
'skip-on-branch=',
'verbose',
'server',
'viewer',
'help'])
Tess Chu
committed
update_server = False
update_viewer = False
new_version = None
new_revision = None
new_viewer_channel = None
new_server_channel = None
Tess Chu
committed
for o,a in opts:
if o in ('--version'):
new_version = a
if o in ('--revision'):
new_revision = a
if o in ('--skip-on-branch'):
skip_on_branch_re = re.compile(a)
Tess Chu
committed
if o in ('--channel'):
new_viewer_channel = a
Tess Chu
committed
if o in ('--server_channel'):
new_server_channel = a
Tess Chu
committed
if o in ('--verbose'):
verbose = True
if o in ('--server'):
update_server = True
if o in ('--viewer'):
update_viewer = True
if o in ('--help'):
usage()
return 0
if not(update_server or update_viewer):
update_server = True
update_viewer = True
# Get current channel/version from llversion*.h
try:
viewer_channel = llversion.get_viewer_channel()
viewer_version = llversion.get_viewer_version()
except IOError:
print "Viewer version file not present, skipping..."
viewer_channel = None
viewer_version = None
update_viewer = False
try:
server_channel = llversion.get_server_channel()
server_version = llversion.get_server_version()
except IOError:
print "Server version file not present, skipping..."
server_channel = None
server_version = None
update_server = False
Tess Chu
committed
if verbose:
print "Source Path:", src_root
if viewer_channel != None:
print "Current viewer channel/version: '%(viewer_channel)s' / '%(viewer_version)s'" % locals()
if server_channel != None:
print "Current server channel/version: '%(server_channel)s' / '%(server_version)s'" % locals()
print
# Determine new channel(s)
if new_viewer_channel != None and len(new_viewer_channel) > 0:
viewer_channel = new_viewer_channel
if new_server_channel != None and len(new_server_channel) > 0:
server_channel = new_server_channel
# Determine new version(s)
if new_version:
m = version_re.match(new_version)
Tess Chu
committed
if not m:
print "Invalid version string specified!"
return -1
if update_viewer:
viewer_version = new_version
Tess Chu
committed
if update_server:
server_version = new_version
Tess Chu
committed
else:
Merov Linden
committed
if llversion.using_hg():
if new_revision:
revision = new_revision
else:
revision = llversion.get_hg_changeset()
branch = llversion.get_hg_repo()
elif new_revision:
revision = new_revision
branch = "unknown"
else:
print >>sys.stderr, "ERROR: could not determine revision and branch"
Tess Chu
committed
return -1
if skip_on_branch_re and skip_on_branch_re.match(branch):
print "Release Candidate Build, leaving version files untouched."
return 0
Tess Chu
committed
if update_viewer:
m = version_re.match(viewer_version)
viewer_version = m.group(1)+"."+m.group(2)+"."+m.group(3)+"."+revision
if update_server:
m = version_re.match(server_version)
server_version = m.group(1)+"."+m.group(2)+"."+m.group(3)+"."+revision
if verbose:
if update_viewer:
print "Setting viewer channel/version: '%(viewer_channel)s' / '%(viewer_version)s'" % locals()
if update_server:
print "Setting server channel/version: '%(server_channel)s' / '%(server_version)s'" % locals()
Tess Chu
committed
print
# split out version parts
if viewer_version != None:
m = version_re.match(viewer_version)
VER_MAJOR = m.group(1)
VER_MINOR = m.group(2)
VER_PATCH = m.group(3)
VER_BUILD = m.group(4)
if server_version != None:
m = version_re.match(server_version)
SERVER_VER_MAJOR = m.group(1)
SERVER_VER_MINOR = m.group(2)
SERVER_VER_PATCH = m.group(3)
SERVER_VER_BUILD = m.group(4)
# For readability and symmetry with version strings:
VIEWER_CHANNEL = viewer_channel
SERVER_CHANNEL = server_channel
Tess Chu
committed
# Iterate through all of the files in the map, and apply the
# substitution filters
for filename in re_map.keys():
try:
# Read the entire file into a string
full_fn = src_root + '/' + filename
file = open(full_fn,"r")
file_str = file.read()
file.close()
if verbose:
print "Processing file:",filename
for rule in re_map[filename]:
repl = rule[1] % locals()
file_str = re.sub(rule[0], repl, file_str)
file = open(full_fn,"w")
file.write(file_str)
file.close()
except IOError:
print "File %(filename)s not present, skipping..." % locals()
Tess Chu
committed
return 0
Merov Linden
committed
if __name__ == '__main__':
sys.exit(main())