Home | History | Annotate | Download | only in utils
      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