1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
#!/usr/bin/env python
# Generate version information for a program
#
# Copyright (C) 2015 Kevin O'Connor <kevin@koconnor.net>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
import sys, os, subprocess, shlex, time, socket, optparse, logging, traceback
VERSION_FORMAT = """
/* DO NOT EDIT! This is an autogenerated file. See scripts/buildversion.py. */
#define BUILD_VERSION "%s"
#define BUILD_TOOLS "%s"
"""
# Run program and return the specified output
def check_output(prog):
logging.debug("Running %s" % (repr(prog),))
try:
process = subprocess.Popen(shlex.split(prog), stdout=subprocess.PIPE)
output = process.communicate()[0]
retcode = process.poll()
except OSError:
logging.debug("Exception on run: %s" % (traceback.format_exc(),))
return ""
logging.debug("Got (code=%s): %s" % (retcode, repr(output)))
if retcode:
return ""
try:
return output.decode()
except UnicodeError:
logging.debug("Exception on decode: %s" % (traceback.format_exc(),))
return ""
# Obtain version info from "git" program
def git_version():
if not os.path.exists('.git'):
logging.debug("No '.git' file/directory found")
return ""
ver = check_output("git describe --always --tags --long --dirty").strip()
logging.debug("Got git version: %s" % (repr(ver),))
return ver
# Look for version in a ".version" file. Official release tarballs
# have this file (see scripts/tarball.sh).
def file_version():
if not os.path.isfile('.version'):
logging.debug("No '.version' file found")
return ""
try:
f = open('.version', 'r')
ver = f.readline().strip()
f.close()
except OSError:
logging.debug("Exception on read: %s" % (traceback.format_exc(),))
return ""
logging.debug("Got .version: %s" % (repr(ver),))
return ver
# Generate an output file with the version information
def write_version(outfile, version, toolstr):
logging.debug("Write file %s and %s" % (repr(version), repr(toolstr)))
sys.stdout.write("Version: %s\n" % (version,))
f = open(outfile, 'w')
f.write(VERSION_FORMAT % (version, toolstr))
f.close()
# Run "tool --version" for each specified tool and extract versions
def tool_versions(tools):
tools = [t.strip() for t in tools.split(';')]
versions = ['', '']
success = 0
for tool in tools:
# Extract first line from "tool --version" output
verstr = check_output("%s --version" % (tool,)).split('\n')[0]
# Check if this tool looks like a binutils program
isbinutils = 0
if verstr.startswith('GNU '):
isbinutils = 1
verstr = verstr[4:]
# Extract version information and exclude program name
if ' ' not in verstr:
continue
prog, ver = verstr.split(' ', 1)
if not prog or not ver:
continue
# Check for any version conflicts
if versions[isbinutils] and versions[isbinutils] != ver:
logging.debug("Mixed version %s vs %s" % (
repr(versions[isbinutils]), repr(ver)))
versions[isbinutils] = "mixed"
continue
versions[isbinutils] = ver
success += 1
cleanbuild = versions[0] and versions[1] and success == len(tools)
return cleanbuild, "gcc: %s binutils: %s" % (versions[0], versions[1])
def main():
usage = "%prog [options] <outputheader.h>"
opts = optparse.OptionParser(usage)
opts.add_option("-e", "--extra", dest="extra", default="",
help="extra version string to append to version")
opts.add_option("-t", "--tools", dest="tools", default="",
help="list of build programs to extract version from")
opts.add_option("-v", action="store_true", dest="verbose",
help="enable debug messages")
options, args = opts.parse_args()
if len(args) != 1:
opts.error("Incorrect arguments")
outfile = args[0]
if options.verbose:
logging.basicConfig(level=logging.DEBUG)
cleanbuild, toolstr = tool_versions(options.tools)
ver = git_version()
cleanbuild = cleanbuild and 'dirty' not in ver
if not ver:
ver = file_version()
# We expect the "extra version" to contain information on the
# distributor and distribution package version (if
# applicable). It is a "clean" build if this is a build from
# an official release tarball and the above info is present.
cleanbuild = cleanbuild and ver and options.extra != ""
if not ver:
ver = "?"
if not cleanbuild:
btime = time.strftime("%Y%m%d_%H%M%S", time.gmtime(int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))))
ver = "%s-%s" % (ver, btime)
write_version(outfile, ver + options.extra, toolstr)
if __name__ == '__main__':
main()
|