Created
March 15, 2016 10:22
-
-
Save trojanfoe/3e094086830fd426b30c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# | |
# Bump build number if source files have changed, writing the version and build | |
# number to source files as well as updating one or more info.plist files. | |
# | |
# usage: bump_build_number.py version-file version-impl-file version-header-file plist-file [ ... plist-file ] | |
# | |
import sys, os, subprocess, re | |
def read_version(vername): | |
version = None | |
build = None | |
verfile = open(vername, "r") | |
for line in verfile: | |
match = re.match(r"^version\s+(\S+)", line) | |
if match: | |
version = match.group(1).rstrip() | |
match = re.match(r"^build\s+(\S+)", line) | |
if match: | |
build = int(match.group(1).rstrip()) | |
verfile.close() | |
return (version, build) | |
def write_version(vername, version, build): | |
verfile = open(vername, "w") | |
verfile.write("version {0}\n".format(version)) | |
verfile.write("build {0}\n".format(build)) | |
verfile.close() | |
return True | |
def get_process_output(cmdline): | |
if sys.version_info[0] < 3: | |
output = subprocess.Popen(cmdline, stdout=subprocess.PIPE, shell=True).stdout.read().strip() | |
else: | |
output = subprocess.getoutput(cmdline) | |
return output | |
def set_plist_version(plistname, version, build): | |
if not os.path.exists(plistname): | |
sys.stderr.write("{0} does not exist\n".format(plistname)) | |
return False | |
plistbuddy = '/usr/libexec/Plistbuddy' | |
if not os.path.exists(plistbuddy): | |
sys.stderr.write("{0} does not exist\n".format(plistbuddy)) | |
return False | |
cmdline = [plistbuddy, | |
"-c", "Set CFBundleShortVersionString {0}".format(version), | |
"-c", "Set CFBundleVersion {0}".format(build), | |
plistname] | |
if subprocess.call(cmdline): | |
sys.stderr.write("Failed to update {0}\n".format(plistname)) | |
return False | |
print("Updated {0} with v{1} ({2})".format(plistname, version, build)) | |
return True | |
def should_ignore_file(filename, ignorefiles): | |
for ignorefile in ignorefiles: | |
if os.path.isfile(ignorefile) and os.stat(filename) == os.stat(ignorefile): | |
return True | |
return False | |
# | |
# Determine if any files within dirname are newer than vername, ignoring | |
# any files in ignorefiles and including any files with extensions in | |
# includeexts | |
# | |
def should_bump(vername, dirname, ignorefiles, extensions): | |
verstat = os.stat(vername) | |
# Assumes mname is in the top-level source directory: | |
allnames = [] | |
for dirname, dirnames, filenames in os.walk(dirname): | |
for subdirname in dirnames: | |
allnames.append(os.path.join(dirname, subdirname)) | |
for filename in filenames: | |
allnames.append(os.path.join(dirname, filename)) | |
for filename in allnames: | |
if should_ignore_file(filename, ignorefiles): | |
continue | |
extension = os.path.splitext(filename)[1] | |
if not extension: | |
continue | |
if extension not in extensions: | |
continue | |
filestat = os.stat(filename) | |
if filestat.st_mtime > verstat.st_mtime: | |
sys.stderr.write("{0} is newer than {1}\n".format(filename, vername)) | |
return True | |
return False | |
def write_source(implname, hdrname, version, build, commit): | |
implroot, implext = os.path.splitext(implname) | |
implfile = open(implname, "w") | |
if implext == ".c": | |
implfile.write('#include "{0}"\n'.format(os.path.basename(hdrname))) | |
implfile.write('const char *version = "{0}";\n'.format(version)) | |
implfile.write('unsigned buildnum = {0};\n'.format(build)) | |
implfile.write('const char *commit = "{0}";\n'.format(commit)) | |
elif implext == ".m": | |
implfile.write('#import "{0}"\n'.format(os.path.basename(hdrname))) | |
implfile.write('NSString * const version = @"{0}";\n'.format(version)) | |
implfile.write('unsigned buildnum = {0};\n'.format(build)) | |
implfile.write('NSString * const commit = @"{0}";\n'.format(commit)) | |
elif implext == ".cpp" or implext == ".cxx": | |
implfile.write('#include "{0}"\n'.format(os.path.basename(hdrname))) | |
implfile.write('const std::string version = "{0}";\n'.format(version)) | |
implfile.write('unsigned buildnum = {0};\n'.format(build)) | |
implfile.write('const std::string commmit = "{0}";\n'.format(commit)) | |
implfile.close() | |
sys.stdout.write("Written {0}\n".format(implname)) | |
hdrfile = open(hdrname, "w") | |
if implext == ".c": | |
hdrfile.write('#pragma once\n') | |
hdrfile.write('extern const char *version;\n') | |
hdrfile.write('extern unsigned buildnum;\n') | |
hdrfile.write('extern const char *commit;\n'); | |
if implext == ".m": | |
hdrfile.write('#import <Foundation/Foundation.h>\n') | |
hdrfile.write('extern NSString * const version;\n') | |
hdrfile.write('extern unsigned buildnum;\n') | |
hdrfile.write('extern NSString * const commit;\n'); | |
elif implext == ".cpp" or implext == ".cxx": | |
hdrfile.write('#pragma once\n') | |
hdrfile.write('#include <string>\n') | |
hdrfile.write('extern const std::string version;\n') | |
hdrfile.write('extern unsigned buildnum;\n') | |
hdrfile.write('extern const std::string commit;\n'); | |
hdrfile.close() | |
sys.stdout.write("Written {0}\n".format(hdrname)) | |
return True | |
def upver(vername, implname, hdrname): | |
(version, build) = read_version(vername) | |
if version == None or build == None: | |
sys.stderr.write("Failed to read version/build from {0}\n".format(vername)) | |
return False | |
# Bump the version number if any source files or asset files have changed | |
srcdir = os.path.normpath(os.path.join(os.path.dirname(__file__), "..")) | |
implroot, implext = os.path.splitext(implname) | |
hdrroot, hdrext = os.path.splitext(hdrname) | |
bump = should_bump(vername, srcdir, [implname, hdrname], [implext, hdrext]) | |
if bump: | |
build += 1 | |
sys.stdout.write("Incremented to build {0}\n".format(build)) | |
write_version(vername, version, build) | |
sys.stdout.write("Written {0}\n".format(vername)) | |
else: | |
sys.stdout.write("Staying at build {0}\n".format(build)) | |
gitdirty = get_process_output("git ls-files -m") | |
if len(gitdirty) > 0: | |
commit = "0000000000000000000000000000000000000000" | |
sys.stdout.write("Git is dirty, so using dummy commit SHA-1\n") | |
else: | |
commit = get_process_output("git rev-parse HEAD") | |
if not write_source(implname, hdrname, version, build, commit): | |
version = None | |
build = None | |
commit = None | |
return (version, build, commit) | |
if __name__ == "__main__": | |
if len(sys.argv) < 5: | |
sys.stderr.write("Usage: bump_build_number.py infile.ver version-impl-file version-header-file info.plist [... info.plist]\n") | |
sys.exit(1) | |
vername = sys.argv[1] | |
implname = sys.argv[2] | |
hdrname = sys.argv[3] | |
(version, build, commit) = upver(vername, implname, hdrname) | |
if version == None or build == None or commit == None: | |
sys.exit(2) | |
for i in range(4, len(sys.argv)): | |
plistname = sys.argv[i] | |
set_plist_version(plistname, version, build) | |
sys.exit(0) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment