yum-mirror/glslang
git clone https://git.yummers.dev/yum-mirror/glslang
d81aeef9
main
1#!/usr/bin/env python3 2 3# Copyright (c) 2020 Google Inc. 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 17import datetime 18import errno 19import os 20import os .path 21import re 22import subprocess 23import sys 24import time 25 26usage = """{} emits a string to stdout or file with project version information. 27 28args: <project-dir> [<input-string>] [-i <input-file>] [-o <output-file>] 29 30Either <input-string> or -i <input-file> needs to be provided. 31 32The tool will output the provided string or file content with the following 33tokens substituted: 34 35<major> - The major version point parsed from the CHANGES.md file. 36<minor> - The minor version point parsed from the CHANGES.md file. 37<patch> - The point version point parsed from the CHANGES.md file. 38<flavor> - The optional dash suffix parsed from the CHANGES.md file (excluding 39dash prefix). 40<-flavor> - The optional dash suffix parsed from the CHANGES.md file (including 41dash prefix). 42<date> - The optional date of the release in the form YYYY-MM-DD 43<commit> - The git commit information for the directory taken from 44"git describe" if that succeeds, or "git rev-parse HEAD" 45if that succeeds, or otherwise a message containing the phrase 46"unknown hash". 47 48-o is an optional flag for writing the output string to the given file. If 49ommitted then the string is printed to stdout. 50""" 51 52try : 53utc = datetime .timezone .utc 54except AttributeError : 55# Python 2? In datetime.date.today().year? Yes. 56class UTC (datetime .tzinfo ): 57ZERO = datetime .timedelta (0 ) 58 59def utcoffset (self ,dt ): 60return self .ZERO 61 62def tzname (self ,dt ): 63return "UTC" 64 65def dst (self ,dt ): 66return self .ZERO 67utc = UTC () 68 69 70def mkdir_p (directory ): 71"""Make the directory, and all its ancestors as required. Any of the 72directories are allowed to already exist.""" 73 74if directory == "" : 75# We're being asked to make the current directory. 76return 77 78try : 79os .makedirs (directory ) 80except OSError as e : 81if e .errno == errno .EEXIST and os .path .isdir (directory ): 82pass 83else : 84raise 85 86 87def command_output (cmd ,directory ): 88"""Runs a command in a directory and returns its standard output stream. 89 90Captures the standard error stream. 91 92Raises a RuntimeError if the command fails to launch or otherwise fails. 93""" 94p = subprocess .Popen (cmd , 95cwd = directory , 96stdout = subprocess .PIPE , 97stderr = subprocess .PIPE ) 98 (stdout ,_ )= p .communicate () 99if p .returncode != 0 : 100raise RuntimeError ('Failed to run %s in %s' % (cmd ,directory )) 101return stdout 102 103 104def deduce_software_version (directory ): 105"""Returns a software version number parsed from the CHANGES.md file 106in the given directory. 107 108The CHANGES.md file describes most recent versions first. 109""" 110 111# Match the first well-formed version-and-date line. 112# Allow trailing whitespace in the checked-out source code has 113# unexpected carriage returns on a linefeed-only system such as 114# Linux. 115pattern = re .compile (r'^#* +(\d+)\.(\d+)\.(\d+)(-\w+)? (\d\d\d\d-\d\d-\d\d)? *$' ) 116changes_file = os .path .join (directory ,'CHANGES.md' ) 117with open (changes_file ,mode = 'r' )as f : 118for line in f .readlines (): 119match = pattern .match (line ) 120if match : 121flavor = match .group (4 ) 122if flavor == None : 123flavor = "" 124return { 125"major" :match .group (1 ), 126"minor" :match .group (2 ), 127"patch" :match .group (3 ), 128"flavor" :flavor .lstrip ("-" ), 129"-flavor" :flavor , 130"date" :match .group (5 ), 131 } 132raise Exception ('No version number found in {}' .format (changes_file )) 133 134 135def describe (directory ): 136"""Returns a string describing the current Git HEAD version as descriptively 137as possible. 138 139Runs 'git describe', or alternately 'git rev-parse HEAD', in directory. If 140successful, returns the output; otherwise returns 'unknown hash, <date>'.""" 141try : 142# decode() is needed here for Python3 compatibility. In Python2, 143# str and bytes are the same type, but not in Python3. 144# Popen.communicate() returns a bytes instance, which needs to be 145# decoded into text data first in Python3. And this decode() won't 146# hurt Python2. 147return command_output (['git' ,'describe' ],directory ).rstrip ().decode () 148except : 149try : 150return command_output ( 151 ['git' ,'rev-parse' ,'HEAD' ],directory ).rstrip ().decode () 152except : 153# This is the fallback case where git gives us no information, 154# e.g. because the source tree might not be in a git tree. 155# In this case, usually use a timestamp. However, to ensure 156# reproducible builds, allow the builder to override the wall 157# clock time with environment variable SOURCE_DATE_EPOCH 158# containing a (presumably) fixed timestamp. 159timestamp = int (os .environ .get ('SOURCE_DATE_EPOCH' ,time .time ())) 160formatted = datetime .datetime .fromtimestamp (timestamp ,utc ).isoformat () 161return 'unknown hash, {}' .format (formatted ) 162 163def parse_args (): 164directory = None 165input_string = None 166input_file = None 167output_file = None 168 169if len (sys .argv )< 2 : 170raise Exception ("Invalid number of arguments" ) 171 172directory = sys .argv [1 ] 173i = 2 174 175if not sys .argv [i ].startswith ("-" ): 176input_string = sys .argv [i ] 177i = i + 1 178 179while i < len (sys .argv ): 180opt = sys .argv [i ] 181i = i + 1 182 183if opt == "-i" or opt == "-o" : 184if i == len (sys .argv ): 185raise Exception ("Expected path after {}" .format (opt )) 186val = sys .argv [i ] 187i = i + 1 188if (opt == "-i" ): 189input_file = val 190elif (opt == "-o" ): 191output_file = val 192else : 193raise Exception ("Unknown flag {}" .format (opt )) 194 195return { 196"directory" :directory , 197"input_string" :input_string , 198"input_file" :input_file , 199"output_file" :output_file , 200 } 201 202def main (): 203args = None 204try : 205args = parse_args () 206except Exception as e : 207e ) 208"\nUsage:\n" ) 209usage .format (sys .argv [0 ])) 210sys .exit (1 ) 211 212directory = args ["directory" ] 213template = args ["input_string" ] 214if template == None : 215with open (args ["input_file" ],'r' )as f : 216template = f .read () 217output_file = args ["output_file" ] 218 219software_version = deduce_software_version (directory ) 220commit = describe (directory ) 221output = template \ 222 .replace ("@major@" ,software_version ["major" ]) \ 223 .replace ("@minor@" ,software_version ["minor" ]) \ 224 .replace ("@patch@" ,software_version ["patch" ]) \ 225 .replace ("@flavor@" ,software_version ["flavor" ]) \ 226 .replace ("@-flavor@" ,software_version ["-flavor" ]) \ 227 .replace ("@date@" ,software_version ["date" ]) \ 228 .replace ("@commit@" ,commit ) 229 230if output_file is None : 231output ) 232else : 233mkdir_p (os .path .dirname (output_file )) 234 235if os .path .isfile (output_file ): 236with open (output_file ,'r' )as f : 237if output == f .read (): 238return 239 240with open (output_file ,'w' )as f : 241f .write (output ) 242 243if __name__ == '__main__' : 244main ()