From c2cfe601024d5f6cbdee068d3ffda498510a3b35 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 30 Dec 2013 17:50:59 -0500 Subject: [PATCH] Port versioning to AMBuild 2 (bug 5997 part 8, r=ds). --- AMBuildScript | 41 +++++++++++ plugins/AMBuilder | 5 +- tools/buildbot/Versioning | 109 +++++++---------------------- tools/buildbot/generate_headers.py | 87 +++++++++++++++++++++++ 4 files changed, 159 insertions(+), 83 deletions(-) create mode 100644 tools/buildbot/generate_headers.py diff --git a/AMBuildScript b/AMBuildScript index 74002803..0ac845f6 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -63,11 +63,26 @@ class SMConfig(object): self.sdks = {} self.binaries = [] self.extensions = [] + self.generated_headers = None self.mms_root = None self.mysql_root = None self.spcomp = None self.smx_files = {} + def detectProductVersion(self): + builder.AddConfigureFile('product.version') + + # For OS X dylib versioning + import re + with open(os.path.join(builder.sourcePath, 'product.version'), 'r') as fp: + productContents = fp.read() + m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents) + if m == None: + self.productVersion = '1.0.0' + else: + major, minor, release = m.groups() + self.productVersion = '{0}.{1}.{2}'.format(major, minor, release) + def detectSDKs(self): sdk_list = builder.options.sdks.split(',') use_all = sdk_list[0] == 'all' @@ -229,15 +244,35 @@ class SMConfig(object): # Finish up. cfg.defines += [ 'SOURCEMOD_BUILD', + 'SM_GENERATED_BUILD', ] cfg.includes += [os.path.join(builder.buildPath, 'includes')] def LibraryBuilder(self, compiler, name): binary = compiler.Library(name) + if builder.target_platform == 'windows': + binary.sources += ['version.rc'] + binary.compiler.rcdefines += [ + 'BINARY_NAME="{0}"'.format(binary.outputFile), + 'SM_GENERATED_BUILD' + ] + elif builder.target_platform == 'mac': + binary.compiler.postlink += [ + '-compatibility_version', '1.0.0', + '-current_version', self.productVersion + ] + binary.compiler.sourcedeps += SM.generated_headers return binary def ProgramBuilder(self, compiler, name): binary = compiler.Program(name) + if builder.target_platform == 'windows': + binary.sources += ['version.rc'] + binary.compiler.rcdefines += [ + 'BINARY_NAME="{0}"'.format(binary.outputFile), + 'SM_GENERATED_BUILD' + ] + binary.compiler.sourcedeps += SM.generated_headers return binary def Library(self, context, name): @@ -389,9 +424,15 @@ class SMConfig(object): return binary SM = SMConfig() +SM.detectProductVersion() SM.detectSDKs() SM.configure() +SM.generated_headers = builder.RunScript( + 'tools/buildbot/Versioning', + { 'SM': SM } +) + builder.RunBuildScripts( [ 'loader/AMBuilder', diff --git a/plugins/AMBuilder b/plugins/AMBuilder index 49faf7d1..6eeeee80 100644 --- a/plugins/AMBuilder +++ b/plugins/AMBuilder @@ -30,6 +30,8 @@ files = [ spcomp_argv = [ os.path.join(builder.buildPath, SM.spcomp.binary.path), 'SM_GENERATED_BUILD=', + '-i' + os.path.relpath(os.path.join(builder.buildPath, 'includes'), + os.path.join(builder.buildPath, builder.buildFolder)), '-i' + os.path.relpath(os.path.join(builder.sourcePath, 'plugins', 'include'), os.path.join(builder.buildPath, builder.buildFolder)), '-h', @@ -48,7 +50,8 @@ def build_plugin(script_path, smx_file): inputs = inputs, argv = argv, outputs = outputs, - dep_type = 'msvc' + dep_type = 'msvc', + weak_inputs = SM.generated_headers ) SM.smx_files[smx_file] = smx_entry diff --git a/tools/buildbot/Versioning b/tools/buildbot/Versioning index ec508890..68aab6de 100644 --- a/tools/buildbot/Versioning +++ b/tools/buildbot/Versioning @@ -1,89 +1,34 @@ -# vim: set ts=2 sw=2 tw=99 noet ft=python: -import os -import re -import subprocess -from ambuild.cache import Cache -import ambuild.command as command +# vim: set ts=8 sts=2 sw=2 tw=99 et ft=python: +import os, sys -#Quickly try to ascertain the current repository revision -def GetVersion(): - args = ['hg', 'parent', '-R', AMBuild.sourceFolder] - p = command.RunDirectCommand(AMBuild, args) - m = re.match('changeset:\s+(\d+):(.+)', p.stdoutText) - if m == None: - raise Exception('Could not determine repository version') - return m.groups() +builder.SetBuildFolder('/') -def PerformReversioning(): - rev, cset = GetVersion() - cacheFile = os.path.join(AMBuild.outputFolder, '.ambuild', 'hgcache') - cache = Cache(cacheFile) - if os.path.isfile(cacheFile): - cache.LoadCache() - if cache.HasVariable('cset') and cache['cset'] == cset: - return False - cache.CacheVariable('cset', cset) +includes = builder.AddFolder('includes') - productFile = open(os.path.join(AMBuild.sourceFolder, 'product.version'), 'r') - productContents = productFile.read() - productFile.close() - m = re.match('(\d+)\.(\d+)\.(\d+)-?(.*)', productContents) - if m == None: - raise Exception('Could not detremine product version') - major, minor, release, tag = m.groups() - - fullstring = "{0}.{1}.{2}".format(major, minor, release) - if tag != "": - fullstring += "-{0}".format(tag) - if tag == "dev": - fullstring += "+{0}".format(rev) - - incFolder = os.path.join(AMBuild.outputFolder, 'includes') - if not os.path.isdir(incFolder): - os.makedirs(incFolder) - incFile = open(os.path.join(incFolder, 'sourcemod_version_auto.h'), 'w') - incFile.write(""" -#ifndef _SOURCEMOD_AUTO_VERSION_INFORMATION_H_ -#define _SOURCEMOD_AUTO_VERSION_INFORMATION_H_ +argv = [ + sys.executable, + os.path.join(builder.sourcePath, 'tools', 'buildbot', 'generate_headers.py'), + os.path.join(builder.sourcePath), + os.path.join(builder.buildPath, 'includes'), +] +outputs = [ + os.path.join(builder.buildFolder, 'includes', 'sourcemod_version_auto.h'), + os.path.join(builder.buildFolder, 'includes', 'version_auto.inc'), +] -#define SM_BUILD_TAG \"{0}\" -#define SM_BUILD_REV \"{1}\" -#define SM_BUILD_CSET \"{2}\" -#define SM_BUILD_MAJOR \"{3}\" -#define SM_BUILD_MINOR \"{4}\" -#define SM_BUILD_RELEASE \"{5}\" +sources = [ + os.path.join(builder.sourcePath, 'product.version'), -#define SM_BUILD_UNIQUEID SM_BUILD_REV \":\" SM_BUILD_CSET - -#define SM_VERSION_STRING \"{6}\" -#define SM_VERSION_FILE {7},{8},{9},0 - -#endif /* _SOURCEMOD_AUTO_VERSION_INFORMATION_H_ */ - -""".format(tag, rev, cset, major, minor, release, fullstring, major, minor, release)) - incFile.close() - - incFile = open(os.path.join(incFolder, 'version_auto.inc'), 'w') - incFile.write(""" -#if defined _auto_version_included - #endinput -#endif -#define _auto_version_included - -#define SOURCEMOD_V_TAG \"{0}\" -#define SOURCEMOD_V_REV {1} -#define SOURCEMOD_V_CSET \"{2}\" -#define SOURCEMOD_V_MAJOR {3} -#define SOURCEMOD_V_MINOR {4} -#define SOURCEMOD_V_RELEASE {5} - -#define SOURCEMOD_VERSION \"{6}\" - -""".format(tag, rev, cset, major, minor, release, fullstring)) - incFile.close() - - cache.WriteCache() - -PerformReversioning() + # This is a hack, but we need some way to only run this script when HG changes. + os.path.join(builder.sourcePath, '.hg', 'dirstate'), + # The script source is a dependency, of course... + argv[1] +] +cmd_node, output_nodes = builder.AddCommand( + inputs=sources, + argv=argv, + outputs=outputs +) +rvalue = output_nodes diff --git a/tools/buildbot/generate_headers.py b/tools/buildbot/generate_headers.py new file mode 100644 index 00000000..6644f54c --- /dev/null +++ b/tools/buildbot/generate_headers.py @@ -0,0 +1,87 @@ +# vim: set ts=8 sts=2 sw=2 tw=99 et: +import re +import os, sys +import subprocess + +argv = sys.argv[1:] +if len(argv) < 2: + sys.stderr.write('Usage: generate_headers.py \n') + sys.exit(1) + +SourceFolder = os.path.abspath(os.path.normpath(argv[0])) +OutputFolder = os.path.normpath(argv[1]) + +def get_hg_version(): + argv = ['hg', 'parent', '-R', SourceFolder] + + # Python 2.6 doesn't have check_output. + if hasattr(subprocess, 'check_output'): + text = subprocess.check_output(argv) + if str != bytes: + text = str(text, 'utf-8') + else: + p = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + output, ignored = p.communicate() + rval = p.poll() + if rval: + raise subprocess.CalledProcessError(rval, argv) + text = output.decode('utf8') + + m = re.match('changeset:\s+(\d+):(.+)', text) + if m == None: + raise Exception('Could not determine repository version') + return m.groups() + +def output_version_headers(): + cset, rev = get_hg_version() + + with open(os.path.join(SourceFolder, 'product.version')) as fp: + contents = fp.read() + m = re.match('(\d+)\.(\d+)\.(\d+)-?(.*)', contents) + if m == None: + raise Exception('Could not detremine product version') + major, minor, release, tag = m.groups() + fullstring = "{0}.{1}.{2}".format(major, minor, release) + if tag != "": + fullstring += "-{0}".format(tag) + if tag == "dev": + fullstring += "+{0}".format(rev) + + with open(os.path.join(OutputFolder, 'sourcemod_version_auto.h'), 'w') as fp: + fp.write(""" +#ifndef _SOURCEMOD_AUTO_VERSION_INFORMATION_H_ +#define _SOURCEMOD_AUTO_VERSION_INFORMATION_H_ + +#define SM_BUILD_TAG \"{0}\" +#define SM_BUILD_REV \"{1}\" +#define SM_BUILD_CSET \"{2}\" +#define SM_BUILD_MAJOR \"{3}\" +#define SM_BUILD_MINOR \"{4}\" +#define SM_BUILD_RELEASE \"{5}\" + +#define SM_BUILD_UNIQUEID SM_BUILD_REV \":\" SM_BUILD_CSET + +#define SM_VERSION_STRING \"{6}\" +#define SM_VERSION_FILE {7},{8},{9},0 + +#endif /* _SOURCEMOD_AUTO_VERSION_INFORMATION_H_ */ + """.format(tag, rev, cset, major, minor, release, fullstring, major, minor, release)) + + with open(os.path.join(OutputFolder, 'version_auto.inc'), 'w') as fp: + fp.write(""" +#if defined _auto_version_included + #endinput +#endif +#define _auto_version_included + +#define SOURCEMOD_V_TAG \"{0}\" +#define SOURCEMOD_V_REV {1} +#define SOURCEMOD_V_CSET \"{2}\" +#define SOURCEMOD_V_MAJOR {3} +#define SOURCEMOD_V_MINOR {4} +#define SOURCEMOD_V_RELEASE {5} + +#define SOURCEMOD_VERSION \"{6}\" + """.format(tag, rev, cset, major, minor, release, fullstring)) + +output_version_headers()