PageRenderTime 41ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/scripts/update_version_files.py

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