1*b7893ccfSSadaf Ebrahimi#!/usr/bin/env python3 2*b7893ccfSSadaf Ebrahimi# 3*b7893ccfSSadaf Ebrahimi# Copyright (c) 2015-2019 The Khronos Group Inc. 4*b7893ccfSSadaf Ebrahimi# Copyright (c) 2015-2019 Valve Corporation 5*b7893ccfSSadaf Ebrahimi# Copyright (c) 2015-2019 LunarG, Inc. 6*b7893ccfSSadaf Ebrahimi# Copyright (c) 2015-2019 Google Inc. 7*b7893ccfSSadaf Ebrahimi# 8*b7893ccfSSadaf Ebrahimi# Licensed under the Apache License, Version 2.0 (the "License"); 9*b7893ccfSSadaf Ebrahimi# you may not use this file except in compliance with the License. 10*b7893ccfSSadaf Ebrahimi# You may obtain a copy of the License at 11*b7893ccfSSadaf Ebrahimi# 12*b7893ccfSSadaf Ebrahimi# http://www.apache.org/licenses/LICENSE-2.0 13*b7893ccfSSadaf Ebrahimi# 14*b7893ccfSSadaf Ebrahimi# Unless required by applicable law or agreed to in writing, software 15*b7893ccfSSadaf Ebrahimi# distributed under the License is distributed on an "AS IS" BASIS, 16*b7893ccfSSadaf Ebrahimi# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17*b7893ccfSSadaf Ebrahimi# See the License for the specific language governing permissions and 18*b7893ccfSSadaf Ebrahimi# limitations under the License. 19*b7893ccfSSadaf Ebrahimi# 20*b7893ccfSSadaf Ebrahimi# Author: Cort Stratton <[email protected]> 21*b7893ccfSSadaf Ebrahimi# Author: Jean-Francois Roy <[email protected]> 22*b7893ccfSSadaf Ebrahimi 23*b7893ccfSSadaf Ebrahimiimport argparse 24*b7893ccfSSadaf Ebrahimiimport hashlib 25*b7893ccfSSadaf Ebrahimiimport subprocess 26*b7893ccfSSadaf Ebrahimiimport uuid 27*b7893ccfSSadaf Ebrahimiimport json 28*b7893ccfSSadaf Ebrahimi 29*b7893ccfSSadaf Ebrahimidef generate(symbol_name, commit_id, output_header_file): 30*b7893ccfSSadaf Ebrahimi # Write commit ID to output header file 31*b7893ccfSSadaf Ebrahimi with open(output_header_file, "w") as header_file: 32*b7893ccfSSadaf Ebrahimi # File Comment 33*b7893ccfSSadaf Ebrahimi file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n' 34*b7893ccfSSadaf Ebrahimi file_comment += '// See external_revision_generator.py for modifications\n' 35*b7893ccfSSadaf Ebrahimi header_file.write(file_comment) 36*b7893ccfSSadaf Ebrahimi # Copyright Notice 37*b7893ccfSSadaf Ebrahimi copyright = '' 38*b7893ccfSSadaf Ebrahimi copyright += '\n' 39*b7893ccfSSadaf Ebrahimi copyright += '/***************************************************************************\n' 40*b7893ccfSSadaf Ebrahimi copyright += ' *\n' 41*b7893ccfSSadaf Ebrahimi copyright += ' * Copyright (c) 2015-2019 The Khronos Group Inc.\n' 42*b7893ccfSSadaf Ebrahimi copyright += ' * Copyright (c) 2015-2019 Valve Corporation\n' 43*b7893ccfSSadaf Ebrahimi copyright += ' * Copyright (c) 2015-2019 LunarG, Inc.\n' 44*b7893ccfSSadaf Ebrahimi copyright += ' * Copyright (c) 2015-2019 Google Inc.\n' 45*b7893ccfSSadaf Ebrahimi copyright += ' *\n' 46*b7893ccfSSadaf Ebrahimi copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n' 47*b7893ccfSSadaf Ebrahimi copyright += ' * you may not use this file except in compliance with the License.\n' 48*b7893ccfSSadaf Ebrahimi copyright += ' * You may obtain a copy of the License at\n' 49*b7893ccfSSadaf Ebrahimi copyright += ' *\n' 50*b7893ccfSSadaf Ebrahimi copyright += ' * http://www.apache.org/licenses/LICENSE-2.0\n' 51*b7893ccfSSadaf Ebrahimi copyright += ' *\n' 52*b7893ccfSSadaf Ebrahimi copyright += ' * Unless required by applicable law or agreed to in writing, software\n' 53*b7893ccfSSadaf Ebrahimi copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n' 54*b7893ccfSSadaf Ebrahimi copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' 55*b7893ccfSSadaf Ebrahimi copyright += ' * See the License for the specific language governing permissions and\n' 56*b7893ccfSSadaf Ebrahimi copyright += ' * limitations under the License.\n' 57*b7893ccfSSadaf Ebrahimi copyright += ' *\n' 58*b7893ccfSSadaf Ebrahimi copyright += ' * Author: Chris Forbes <[email protected]>\n' 59*b7893ccfSSadaf Ebrahimi copyright += ' * Author: Cort Stratton <[email protected]>\n' 60*b7893ccfSSadaf Ebrahimi copyright += ' *\n' 61*b7893ccfSSadaf Ebrahimi copyright += ' ****************************************************************************/\n' 62*b7893ccfSSadaf Ebrahimi header_file.write(copyright) 63*b7893ccfSSadaf Ebrahimi # Contents 64*b7893ccfSSadaf Ebrahimi contents = '#pragma once\n\n' 65*b7893ccfSSadaf Ebrahimi contents += '#define %s "%s"\n' % (symbol_name, commit_id) 66*b7893ccfSSadaf Ebrahimi header_file.write(contents) 67*b7893ccfSSadaf Ebrahimi 68*b7893ccfSSadaf Ebrahimidef get_commit_id_from_git(git_binary, source_dir): 69*b7893ccfSSadaf Ebrahimi value = subprocess.check_output([git_binary, "rev-parse", "HEAD"], cwd=source_dir).decode('utf-8').strip() 70*b7893ccfSSadaf Ebrahimi return value 71*b7893ccfSSadaf Ebrahimi 72*b7893ccfSSadaf Ebrahimidef is_sha1(str): 73*b7893ccfSSadaf Ebrahimi try: str_as_int = int(str, 16) 74*b7893ccfSSadaf Ebrahimi except ValueError: return False 75*b7893ccfSSadaf Ebrahimi return len(str) == 40 76*b7893ccfSSadaf Ebrahimi 77*b7893ccfSSadaf Ebrahimidef get_commit_id_from_file(rev_file): 78*b7893ccfSSadaf Ebrahimi with open(rev_file, 'r') as rev_stream: 79*b7893ccfSSadaf Ebrahimi rev_contents = rev_stream.read() 80*b7893ccfSSadaf Ebrahimi rev_contents_stripped = rev_contents.strip() 81*b7893ccfSSadaf Ebrahimi if is_sha1(rev_contents_stripped): 82*b7893ccfSSadaf Ebrahimi return rev_contents_stripped; 83*b7893ccfSSadaf Ebrahimi # otherwise, SHA1 the entire (unstripped) file contents 84*b7893ccfSSadaf Ebrahimi sha1 = hashlib.sha1(); 85*b7893ccfSSadaf Ebrahimi sha1.update(rev_contents.encode('utf-8')) 86*b7893ccfSSadaf Ebrahimi return sha1.hexdigest() 87*b7893ccfSSadaf Ebrahimi 88*b7893ccfSSadaf Ebrahimidef get_commit_id_from_uuid(): 89*b7893ccfSSadaf Ebrahimi unique_uuid = str(uuid.uuid4()) 90*b7893ccfSSadaf Ebrahimi sha1 = hashlib.sha1(); 91*b7893ccfSSadaf Ebrahimi sha1.update(unique_uuid.encode()) 92*b7893ccfSSadaf Ebrahimi return sha1.hexdigest() 93*b7893ccfSSadaf Ebrahimi 94*b7893ccfSSadaf Ebrahimidef get_commit_id_from_json(json_file, json_keys): 95*b7893ccfSSadaf Ebrahimi with open(json_file) as json_stream: 96*b7893ccfSSadaf Ebrahimi json_data = json.load(json_stream) 97*b7893ccfSSadaf Ebrahimi for key in json_keys.split(','): 98*b7893ccfSSadaf Ebrahimi if type(json_data) == list: 99*b7893ccfSSadaf Ebrahimi json_data = json_data[int(key)] 100*b7893ccfSSadaf Ebrahimi else: 101*b7893ccfSSadaf Ebrahimi json_data = json_data[key] 102*b7893ccfSSadaf Ebrahimi return json_data 103*b7893ccfSSadaf Ebrahimi 104*b7893ccfSSadaf Ebrahimidef main(): 105*b7893ccfSSadaf Ebrahimi parser = argparse.ArgumentParser() 106*b7893ccfSSadaf Ebrahimi rev_method_group = parser.add_mutually_exclusive_group(required=True) 107*b7893ccfSSadaf Ebrahimi rev_method_group.add_argument("--git_dir", metavar="SOURCE_DIR", help="git working copy directory") 108*b7893ccfSSadaf Ebrahimi rev_method_group.add_argument("--rev_file", metavar="REVISION_FILE", help="source revision file path (must contain a SHA1 hash") 109*b7893ccfSSadaf Ebrahimi rev_method_group.add_argument("--from_uuid", action='store_true', help="base SHA1 on a dynamically generated UUID") 110*b7893ccfSSadaf Ebrahimi rev_method_group.add_argument("--json_file", metavar="JSON_FILE", help="path to json file") 111*b7893ccfSSadaf Ebrahimi parser.add_argument("-s", "--symbol_name", metavar="SYMBOL_NAME", required=True, help="C symbol name") 112*b7893ccfSSadaf Ebrahimi parser.add_argument("-o", "--output_header_file", metavar="OUTPUT_HEADER_FILE", required=True, help="output header file path") 113*b7893ccfSSadaf Ebrahimi parser.add_argument("--json_keys", action='store', metavar="JSON_KEYS", help="comma-separated list of keys specifying SHA1 location in root json object for --json_file option") 114*b7893ccfSSadaf Ebrahimi args = parser.parse_args() 115*b7893ccfSSadaf Ebrahimi 116*b7893ccfSSadaf Ebrahimi if ('json_file' in args) != ('json_keys' in args): 117*b7893ccfSSadaf Ebrahimi parser.error('--json_file and --json_keys must be provided together') 118*b7893ccfSSadaf Ebrahimi 119*b7893ccfSSadaf Ebrahimi # We can either parse the latest Git commit ID out of the specified repository (preferred where possible), 120*b7893ccfSSadaf Ebrahimi # or computing the SHA1 hash of the contents of a file passed on the command line and (where necessary -- 121*b7893ccfSSadaf Ebrahimi # e.g. when building the layers outside of a Git environment). 122*b7893ccfSSadaf Ebrahimi if args.git_dir is not None: 123*b7893ccfSSadaf Ebrahimi # Extract commit ID from the specified source directory 124*b7893ccfSSadaf Ebrahimi try: 125*b7893ccfSSadaf Ebrahimi commit_id = get_commit_id_from_git('git', args.git_dir) 126*b7893ccfSSadaf Ebrahimi except WindowsError: 127*b7893ccfSSadaf Ebrahimi # Call git.bat on Windows for compatibility. 128*b7893ccfSSadaf Ebrahimi commit_id = get_commit_id_from_git('git.bat', args.git_dir) 129*b7893ccfSSadaf Ebrahimi elif args.rev_file is not None: 130*b7893ccfSSadaf Ebrahimi # Read the commit ID from a file. 131*b7893ccfSSadaf Ebrahimi commit_id = get_commit_id_from_file(args.rev_file) 132*b7893ccfSSadaf Ebrahimi elif args.json_file is not None: 133*b7893ccfSSadaf Ebrahimi commit_id = get_commit_id_from_json(args.json_file, args.json_keys) 134*b7893ccfSSadaf Ebrahimi elif args.from_uuid: 135*b7893ccfSSadaf Ebrahimi commit_id = get_commit_id_from_uuid() 136*b7893ccfSSadaf Ebrahimi 137*b7893ccfSSadaf Ebrahimi if not is_sha1(commit_id): 138*b7893ccfSSadaf Ebrahimi raise ValueError("commit ID for " + args.symbol_name + " must be a SHA1 hash.") 139*b7893ccfSSadaf Ebrahimi 140*b7893ccfSSadaf Ebrahimi generate(args.symbol_name, commit_id, args.output_header_file) 141*b7893ccfSSadaf Ebrahimi 142*b7893ccfSSadaf Ebrahimiif __name__ == '__main__': 143*b7893ccfSSadaf Ebrahimi main() 144