Port versioning to AMBuild 2 (bug 5997 part 8, r=ds).
authorDavid Anderson <dvander@alliedmods.net>
Mon Dec 30 17:50:59 2013 -0500 (2013-12-30)
changeset 4187e70b65bc70b9
parent 4186 c6a694ae8566
child 4188 89782d5fc91b
Port versioning to AMBuild 2 (bug 5997 part 8, r=ds).
AMBuildScript
plugins/AMBuilder
tools/buildbot/Versioning
tools/buildbot/generate_headers.py
     1.1 --- a/AMBuildScript	Mon Dec 30 17:50:59 2013 -0500
     1.2 +++ b/AMBuildScript	Mon Dec 30 17:50:59 2013 -0500
     1.3 @@ -63,11 +63,26 @@
     1.4      self.sdks = {}
     1.5      self.binaries = []
     1.6      self.extensions = []
     1.7 +    self.generated_headers = None
     1.8      self.mms_root = None
     1.9      self.mysql_root = None
    1.10      self.spcomp = None
    1.11      self.smx_files = {}
    1.12  
    1.13 +  def detectProductVersion(self):
    1.14 +    builder.AddConfigureFile('product.version')
    1.15 +
    1.16 +    # For OS X dylib versioning
    1.17 +    import re
    1.18 +    with open(os.path.join(builder.sourcePath, 'product.version'), 'r') as fp:
    1.19 +      productContents = fp.read()
    1.20 +    m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
    1.21 +    if m == None:
    1.22 +      self.productVersion = '1.0.0'
    1.23 +    else:
    1.24 +      major, minor, release = m.groups()
    1.25 +      self.productVersion = '{0}.{1}.{2}'.format(major, minor, release)
    1.26 +
    1.27    def detectSDKs(self):
    1.28      sdk_list = builder.options.sdks.split(',')
    1.29      use_all = sdk_list[0] == 'all'
    1.30 @@ -229,15 +244,35 @@
    1.31      # Finish up.
    1.32      cfg.defines += [
    1.33        'SOURCEMOD_BUILD',
    1.34 +      'SM_GENERATED_BUILD',
    1.35      ]
    1.36      cfg.includes += [os.path.join(builder.buildPath, 'includes')]
    1.37  
    1.38    def LibraryBuilder(self, compiler, name):
    1.39      binary = compiler.Library(name)
    1.40 +    if builder.target_platform == 'windows':
    1.41 +      binary.sources += ['version.rc']
    1.42 +      binary.compiler.rcdefines += [
    1.43 +        'BINARY_NAME="{0}"'.format(binary.outputFile),
    1.44 +        'SM_GENERATED_BUILD'
    1.45 +      ]
    1.46 +    elif builder.target_platform == 'mac':
    1.47 +      binary.compiler.postlink += [
    1.48 +        '-compatibility_version', '1.0.0',
    1.49 +        '-current_version', self.productVersion
    1.50 +      ]
    1.51 +    binary.compiler.sourcedeps += SM.generated_headers
    1.52      return binary
    1.53  
    1.54    def ProgramBuilder(self, compiler, name):
    1.55      binary = compiler.Program(name)
    1.56 +    if builder.target_platform == 'windows':
    1.57 +      binary.sources += ['version.rc']
    1.58 +      binary.compiler.rcdefines += [
    1.59 +        'BINARY_NAME="{0}"'.format(binary.outputFile),
    1.60 +        'SM_GENERATED_BUILD'
    1.61 +      ]
    1.62 +    binary.compiler.sourcedeps += SM.generated_headers
    1.63      return binary
    1.64  
    1.65    def Library(self, context, name):
    1.66 @@ -389,9 +424,15 @@
    1.67      return binary
    1.68  
    1.69  SM = SMConfig()
    1.70 +SM.detectProductVersion()
    1.71  SM.detectSDKs()
    1.72  SM.configure()
    1.73  
    1.74 +SM.generated_headers = builder.RunScript(
    1.75 +  'tools/buildbot/Versioning',
    1.76 +  { 'SM': SM }
    1.77 +)
    1.78 +
    1.79  builder.RunBuildScripts(
    1.80    [
    1.81      'loader/AMBuilder',
     2.1 --- a/plugins/AMBuilder	Mon Dec 30 17:50:59 2013 -0500
     2.2 +++ b/plugins/AMBuilder	Mon Dec 30 17:50:59 2013 -0500
     2.3 @@ -30,6 +30,8 @@
     2.4  spcomp_argv = [
     2.5    os.path.join(builder.buildPath, SM.spcomp.binary.path),
     2.6    'SM_GENERATED_BUILD=',
     2.7 +  '-i' + os.path.relpath(os.path.join(builder.buildPath, 'includes'),
     2.8 +                         os.path.join(builder.buildPath, builder.buildFolder)),
     2.9    '-i' + os.path.relpath(os.path.join(builder.sourcePath, 'plugins', 'include'),
    2.10                           os.path.join(builder.buildPath, builder.buildFolder)),
    2.11    '-h',
    2.12 @@ -48,7 +50,8 @@
    2.13      inputs = inputs,
    2.14      argv = argv,
    2.15      outputs = outputs,
    2.16 -    dep_type = 'msvc'
    2.17 +    dep_type = 'msvc',
    2.18 +    weak_inputs = SM.generated_headers
    2.19    )
    2.20    SM.smx_files[smx_file] = smx_entry
    2.21  
     3.1 --- a/tools/buildbot/Versioning	Mon Dec 30 17:50:59 2013 -0500
     3.2 +++ b/tools/buildbot/Versioning	Mon Dec 30 17:50:59 2013 -0500
     3.3 @@ -1,89 +1,34 @@
     3.4 -# vim: set ts=2 sw=2 tw=99 noet ft=python: 
     3.5 -import os
     3.6 -import re
     3.7 -import subprocess
     3.8 -from ambuild.cache import Cache
     3.9 -import ambuild.command as command
    3.10 +# vim: set ts=8 sts=2 sw=2 tw=99 et ft=python: 
    3.11 +import os, sys
    3.12  
    3.13 -#Quickly try to ascertain the current repository revision
    3.14 -def GetVersion():
    3.15 -	args = ['hg', 'parent', '-R', AMBuild.sourceFolder]
    3.16 -	p = command.RunDirectCommand(AMBuild, args)
    3.17 -	m = re.match('changeset:\s+(\d+):(.+)', p.stdoutText)
    3.18 -	if m == None:
    3.19 -		raise Exception('Could not determine repository version')
    3.20 -	return m.groups()
    3.21 +builder.SetBuildFolder('/')
    3.22  
    3.23 -def PerformReversioning():
    3.24 -	rev, cset = GetVersion()
    3.25 -	cacheFile = os.path.join(AMBuild.outputFolder, '.ambuild', 'hgcache')
    3.26 -	cache = Cache(cacheFile)
    3.27 -	if os.path.isfile(cacheFile):
    3.28 -		cache.LoadCache()
    3.29 -		if cache.HasVariable('cset') and cache['cset'] == cset:
    3.30 -			return False
    3.31 -	cache.CacheVariable('cset', cset)
    3.32 +includes = builder.AddFolder('includes')
    3.33  
    3.34 -	productFile = open(os.path.join(AMBuild.sourceFolder, 'product.version'), 'r')
    3.35 -	productContents = productFile.read()
    3.36 -	productFile.close()
    3.37 -	m = re.match('(\d+)\.(\d+)\.(\d+)-?(.*)', productContents)
    3.38 -	if m == None:
    3.39 -		raise Exception('Could not detremine product version')
    3.40 -	major, minor, release, tag = m.groups()
    3.41 -	
    3.42 -	fullstring = "{0}.{1}.{2}".format(major, minor, release)
    3.43 -	if tag != "":
    3.44 -		fullstring += "-{0}".format(tag)
    3.45 -		if tag == "dev":
    3.46 -			fullstring += "+{0}".format(rev)
    3.47 -	
    3.48 -	incFolder = os.path.join(AMBuild.outputFolder, 'includes')
    3.49 -	if not os.path.isdir(incFolder):
    3.50 -		os.makedirs(incFolder)
    3.51 -	incFile = open(os.path.join(incFolder, 'sourcemod_version_auto.h'), 'w')
    3.52 -	incFile.write("""
    3.53 -#ifndef _SOURCEMOD_AUTO_VERSION_INFORMATION_H_
    3.54 -#define _SOURCEMOD_AUTO_VERSION_INFORMATION_H_
    3.55 +argv = [
    3.56 +  sys.executable,
    3.57 +  os.path.join(builder.sourcePath, 'tools', 'buildbot', 'generate_headers.py'),
    3.58 +  os.path.join(builder.sourcePath),
    3.59 +  os.path.join(builder.buildPath, 'includes'),
    3.60 +]
    3.61 +outputs = [
    3.62 +  os.path.join(builder.buildFolder, 'includes', 'sourcemod_version_auto.h'),
    3.63 +  os.path.join(builder.buildFolder, 'includes', 'version_auto.inc'),
    3.64 +]
    3.65  
    3.66 -#define SM_BUILD_TAG		\"{0}\"
    3.67 -#define SM_BUILD_REV		\"{1}\"
    3.68 -#define SM_BUILD_CSET		\"{2}\"
    3.69 -#define SM_BUILD_MAJOR		\"{3}\"
    3.70 -#define SM_BUILD_MINOR		\"{4}\"
    3.71 -#define SM_BUILD_RELEASE	\"{5}\"
    3.72 -
    3.73 -#define SM_BUILD_UNIQUEID SM_BUILD_REV \":\" SM_BUILD_CSET
    3.74 +sources = [
    3.75 +  os.path.join(builder.sourcePath, 'product.version'),
    3.76  
    3.77 -#define SM_VERSION_STRING	\"{6}\"
    3.78 -#define SM_VERSION_FILE		{7},{8},{9},0
    3.79 -
    3.80 -#endif /* _SOURCEMOD_AUTO_VERSION_INFORMATION_H_ */
    3.81 -
    3.82 -""".format(tag, rev, cset, major, minor, release, fullstring, major, minor, release))
    3.83 -	incFile.close()
    3.84 -	
    3.85 -	incFile = open(os.path.join(incFolder, 'version_auto.inc'), 'w')
    3.86 -	incFile.write("""
    3.87 -#if defined _auto_version_included
    3.88 - #endinput
    3.89 -#endif
    3.90 -#define _auto_version_included
    3.91 +  # This is a hack, but we need some way to only run this script when HG changes.
    3.92 +  os.path.join(builder.sourcePath, '.hg', 'dirstate'),
    3.93  
    3.94 -#define SOURCEMOD_V_TAG		\"{0}\"
    3.95 -#define SOURCEMOD_V_REV		{1}
    3.96 -#define SOURCEMOD_V_CSET	\"{2}\"
    3.97 -#define SOURCEMOD_V_MAJOR	{3}
    3.98 -#define SOURCEMOD_V_MINOR	{4}
    3.99 -#define SOURCEMOD_V_RELEASE	{5}
   3.100 -
   3.101 -#define SOURCEMOD_VERSION	\"{6}\"
   3.102 +  # The script source is a dependency, of course...
   3.103 +  argv[1]
   3.104 +]
   3.105 +cmd_node, output_nodes = builder.AddCommand(
   3.106 +  inputs=sources,
   3.107 +  argv=argv,
   3.108 +  outputs=outputs
   3.109 +)
   3.110  
   3.111 -""".format(tag, rev, cset, major, minor, release, fullstring))
   3.112 -	incFile.close()
   3.113 -
   3.114 -	cache.WriteCache()
   3.115 -
   3.116 -PerformReversioning()
   3.117 -
   3.118 -
   3.119 +rvalue = output_nodes
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/tools/buildbot/generate_headers.py	Mon Dec 30 17:50:59 2013 -0500
     4.3 @@ -0,0 +1,87 @@
     4.4 +# vim: set ts=8 sts=2 sw=2 tw=99 et:
     4.5 +import re
     4.6 +import os, sys
     4.7 +import subprocess
     4.8 +
     4.9 +argv = sys.argv[1:]
    4.10 +if len(argv) < 2:
    4.11 +  sys.stderr.write('Usage: generate_headers.py <source_path> <output_folder>\n')
    4.12 +  sys.exit(1)
    4.13 +
    4.14 +SourceFolder = os.path.abspath(os.path.normpath(argv[0]))
    4.15 +OutputFolder = os.path.normpath(argv[1])
    4.16 +
    4.17 +def get_hg_version():
    4.18 +  argv = ['hg', 'parent', '-R', SourceFolder]
    4.19 +
    4.20 +  # Python 2.6 doesn't have check_output.
    4.21 +  if hasattr(subprocess, 'check_output'):
    4.22 +    text = subprocess.check_output(argv)
    4.23 +    if str != bytes:
    4.24 +      text = str(text, 'utf-8')
    4.25 +  else:
    4.26 +    p = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    4.27 +    output, ignored = p.communicate()
    4.28 +    rval = p.poll()
    4.29 +    if rval:
    4.30 +      raise subprocess.CalledProcessError(rval, argv)
    4.31 +    text = output.decode('utf8')
    4.32 +
    4.33 +  m = re.match('changeset:\s+(\d+):(.+)', text)
    4.34 +  if m == None:
    4.35 +    raise Exception('Could not determine repository version')
    4.36 +  return m.groups()
    4.37 +
    4.38 +def output_version_headers():
    4.39 +  cset, rev = get_hg_version()
    4.40 +
    4.41 +  with open(os.path.join(SourceFolder, 'product.version')) as fp:
    4.42 +    contents = fp.read()
    4.43 +  m = re.match('(\d+)\.(\d+)\.(\d+)-?(.*)', contents)
    4.44 +  if m == None:
    4.45 +    raise Exception('Could not detremine product version')
    4.46 +  major, minor, release, tag = m.groups()
    4.47 +  fullstring = "{0}.{1}.{2}".format(major, minor, release)
    4.48 +  if tag != "":
    4.49 +    fullstring += "-{0}".format(tag)
    4.50 +    if tag == "dev":
    4.51 +      fullstring += "+{0}".format(rev)
    4.52 +
    4.53 +  with open(os.path.join(OutputFolder, 'sourcemod_version_auto.h'), 'w') as fp:
    4.54 +    fp.write("""
    4.55 +#ifndef _SOURCEMOD_AUTO_VERSION_INFORMATION_H_
    4.56 +#define _SOURCEMOD_AUTO_VERSION_INFORMATION_H_
    4.57 +
    4.58 +#define SM_BUILD_TAG		\"{0}\"
    4.59 +#define SM_BUILD_REV		\"{1}\"
    4.60 +#define SM_BUILD_CSET		\"{2}\"
    4.61 +#define SM_BUILD_MAJOR		\"{3}\"
    4.62 +#define SM_BUILD_MINOR		\"{4}\"
    4.63 +#define SM_BUILD_RELEASE	\"{5}\"
    4.64 +
    4.65 +#define SM_BUILD_UNIQUEID SM_BUILD_REV \":\" SM_BUILD_CSET
    4.66 +
    4.67 +#define SM_VERSION_STRING	\"{6}\"
    4.68 +#define SM_VERSION_FILE		{7},{8},{9},0
    4.69 +
    4.70 +#endif /* _SOURCEMOD_AUTO_VERSION_INFORMATION_H_ */
    4.71 +    """.format(tag, rev, cset, major, minor, release, fullstring, major, minor, release))
    4.72 +
    4.73 +  with open(os.path.join(OutputFolder, 'version_auto.inc'), 'w') as fp:
    4.74 +    fp.write("""
    4.75 +#if defined _auto_version_included
    4.76 + #endinput
    4.77 +#endif
    4.78 +#define _auto_version_included
    4.79 +
    4.80 +#define SOURCEMOD_V_TAG		\"{0}\"
    4.81 +#define SOURCEMOD_V_REV		{1}
    4.82 +#define SOURCEMOD_V_CSET	\"{2}\"
    4.83 +#define SOURCEMOD_V_MAJOR	{3}
    4.84 +#define SOURCEMOD_V_MINOR	{4}
    4.85 +#define SOURCEMOD_V_RELEASE	{5}
    4.86 +
    4.87 +#define SOURCEMOD_VERSION	\"{6}\"
    4.88 +    """.format(tag, rev, cset, major, minor, release, fullstring))
    4.89 +
    4.90 +output_version_headers()