1 #!/usr/bin/env python 2 3 # Copyright 2016 The Shaderc Authors. All rights reserved. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 # Updates build-version.inc in the current directory, unless the update is 18 # identical to the existing content. 19 # 20 # Args: <shaderc_dir> <spirv-tools_dir> <glslang_dir> 21 # 22 # For each directory, there will be a line in build-version.inc containing that 23 # directory's "git describe" output enclosed in double quotes and appropriately 24 # escaped. 25 26 from __future__ import print_function 27 28 import datetime 29 import os.path 30 import re 31 import subprocess 32 import sys 33 34 OUTFILE = 'build-version.inc' 35 36 37 def command_output(cmd, dir): 38 """Runs a command in a directory and returns its standard output stream. 39 40 Captures the standard error stream. 41 42 Raises a RuntimeError if the command fails to launch or otherwise fails. 43 """ 44 p = subprocess.Popen(cmd, 45 cwd=dir, 46 stdout=subprocess.PIPE, 47 stderr=subprocess.PIPE) 48 (stdout, _) = p.communicate() 49 if p.returncode != 0: 50 raise RuntimeError('Failed to run %s in %s' % (cmd, dir)) 51 return stdout 52 53 54 def deduce_software_version(dir): 55 """Returns a software version number parsed from the CHANGES file 56 in the given dir. 57 58 The CHANGES file describes most recent versions first. 59 """ 60 61 pattern = re.compile('(v\d+\.\d+(-dev)?) \d\d\d\d-\d\d-\d\d$') 62 changes_file = os.path.join(dir, 'CHANGES') 63 with open(changes_file) as f: 64 for line in f.readlines(): 65 match = pattern.match(line) 66 if match: 67 return match.group(1) 68 raise Exception('No version number found in {}'.format(changes_file)) 69 70 71 def describe(dir): 72 """Returns a string describing the current Git HEAD version as descriptively 73 as possible. 74 75 Runs 'git describe', or alternately 'git rev-parse HEAD', in dir. If 76 successful, returns the output; otherwise returns 'unknown hash, <date>'.""" 77 try: 78 # decode() is needed here for Python3 compatibility. In Python2, 79 # str and bytes are the same type, but not in Python3. 80 # Popen.communicate() returns a bytes instance, which needs to be 81 # decoded into text data first in Python3. And this decode() won't 82 # hurt Python2. 83 return command_output(['git', 'describe'], dir).rstrip().decode() 84 except: 85 try: 86 return command_output( 87 ['git', 'rev-parse', 'HEAD'], dir).rstrip().decode() 88 except: 89 return 'unknown hash, ' + datetime.date.today().isoformat() 90 91 92 def get_version_string(project, dir): 93 """Returns a detailed version string for a given project with its directory, 94 which consists of software version string and git description string.""" 95 detailed_version_string_lst = [project] 96 if project != 'glslang': 97 detailed_version_string_lst.append(deduce_software_version(dir)) 98 detailed_version_string_lst.append(describe(dir).replace('"', '\\"')) 99 return ' '.join(detailed_version_string_lst) 100 101 102 def main(): 103 if len(sys.argv) != 4: 104 print( 105 'usage: {0} <shaderc_dir> <spirv-tools_dir> <glslang_dir>'.format( 106 sys.argv[0])) 107 sys.exit(1) 108 109 projects = ['shaderc', 'spirv-tools', 'glslang'] 110 new_content = ''.join([ 111 '"{}\\n"\n'.format(get_version_string(p, d)) 112 for (p, d) in zip(projects, sys.argv[1:]) 113 ]) 114 if os.path.isfile(OUTFILE) and new_content == open(OUTFILE, 'r').read(): 115 sys.exit(0) 116 open(OUTFILE, 'w').write(new_content) 117 118 119 if __name__ == '__main__': 120 main() 121