1*795d594fSAndroid Build Coastguard Worker#!/usr/bin/python3 2*795d594fSAndroid Build Coastguard Worker# 3*795d594fSAndroid Build Coastguard Worker# Copyright 2017, The Android Open Source Project 4*795d594fSAndroid Build Coastguard Worker# 5*795d594fSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*795d594fSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*795d594fSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*795d594fSAndroid Build Coastguard Worker# 9*795d594fSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*795d594fSAndroid Build Coastguard Worker# 11*795d594fSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*795d594fSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*795d594fSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*795d594fSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*795d594fSAndroid Build Coastguard Worker# limitations under the License. 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker# 18*795d594fSAndroid Build Coastguard Worker# There are many run-tests which generate their sources automatically. 19*795d594fSAndroid Build Coastguard Worker# It is desirable to keep the checked-in source code, as we re-run generators very rarely. 20*795d594fSAndroid Build Coastguard Worker# 21*795d594fSAndroid Build Coastguard Worker# This script will re-run the generators only if their dependent files have changed and then 22*795d594fSAndroid Build Coastguard Worker# complain if the outputs no longer matched what's in the source tree. 23*795d594fSAndroid Build Coastguard Worker# 24*795d594fSAndroid Build Coastguard Worker 25*795d594fSAndroid Build Coastguard Workerimport os 26*795d594fSAndroid Build Coastguard Workerimport pathlib 27*795d594fSAndroid Build Coastguard Workerimport subprocess 28*795d594fSAndroid Build Coastguard Workerimport sys 29*795d594fSAndroid Build Coastguard Workerimport tempfile 30*795d594fSAndroid Build Coastguard Worker 31*795d594fSAndroid Build Coastguard WorkerTHIS_PATH = os.path.dirname(os.path.realpath(__file__)) 32*795d594fSAndroid Build Coastguard Worker 33*795d594fSAndroid Build Coastguard WorkerTOOLS_GEN_SRCS = [ 34*795d594fSAndroid Build Coastguard Worker # tool -> path to a script to generate a file 35*795d594fSAndroid Build Coastguard Worker # reference_files -> list of files that the script can generate 36*795d594fSAndroid Build Coastguard Worker # args -> lambda(path) that generates arguments the 'tool' in order to output to 'path' 37*795d594fSAndroid Build Coastguard Worker # interesting_files -> which files much change in order to re-run the tool. 38*795d594fSAndroid Build Coastguard Worker # interesting_to_reference_files: lambda(x,reference_files) 39*795d594fSAndroid Build Coastguard Worker # given the interesting file 'x' and a list of reference_files, 40*795d594fSAndroid Build Coastguard Worker # return exactly one reference file that corresponds to it. 41*795d594fSAndroid Build Coastguard Worker { 'tool' : 'test/988-method-trace/gen_srcs.py', 42*795d594fSAndroid Build Coastguard Worker 'reference_files' : ['test/988-method-trace/src/art/Test988Intrinsics.java'], 43*795d594fSAndroid Build Coastguard Worker 'args' : lambda output_path: [output_path], 44*795d594fSAndroid Build Coastguard Worker 'interesting_files' : ['compiler/intrinsics_list.h'], 45*795d594fSAndroid Build Coastguard Worker 'interesting_to_reference_file' : lambda interesting, references: references[0], 46*795d594fSAndroid Build Coastguard Worker }, 47*795d594fSAndroid Build Coastguard Worker] 48*795d594fSAndroid Build Coastguard Worker 49*795d594fSAndroid Build Coastguard WorkerDEBUG = False 50*795d594fSAndroid Build Coastguard Worker 51*795d594fSAndroid Build Coastguard Workerdef debug_print(msg): 52*795d594fSAndroid Build Coastguard Worker if DEBUG: 53*795d594fSAndroid Build Coastguard Worker print("[DEBUG]: " + msg, file=sys.stderr) 54*795d594fSAndroid Build Coastguard Worker 55*795d594fSAndroid Build Coastguard Workerdef is_interesting(f, tool_dict): 56*795d594fSAndroid Build Coastguard Worker """ 57*795d594fSAndroid Build Coastguard Worker Returns true if this is a file we want to run this tool before uploading. False otherwise. 58*795d594fSAndroid Build Coastguard Worker """ 59*795d594fSAndroid Build Coastguard Worker path = pathlib.Path(f) 60*795d594fSAndroid Build Coastguard Worker return str(path) in tool_dict['interesting_files'] 61*795d594fSAndroid Build Coastguard Worker 62*795d594fSAndroid Build Coastguard Workerdef get_changed_files(commit): 63*795d594fSAndroid Build Coastguard Worker """ 64*795d594fSAndroid Build Coastguard Worker Gets the files changed in the given commit. 65*795d594fSAndroid Build Coastguard Worker """ 66*795d594fSAndroid Build Coastguard Worker return subprocess.check_output( 67*795d594fSAndroid Build Coastguard Worker ["git", 'diff-tree', '--no-commit-id', '--name-only', '-r', commit], 68*795d594fSAndroid Build Coastguard Worker stderr=subprocess.STDOUT, 69*795d594fSAndroid Build Coastguard Worker universal_newlines=True).split() 70*795d594fSAndroid Build Coastguard Worker 71*795d594fSAndroid Build Coastguard Workerdef command_line_for_tool(tool_dict, output): 72*795d594fSAndroid Build Coastguard Worker """ 73*795d594fSAndroid Build Coastguard Worker Calculate the command line for this tool when ran against the output file 'output'. 74*795d594fSAndroid Build Coastguard Worker """ 75*795d594fSAndroid Build Coastguard Worker proc_args = [tool_dict['tool']] + tool_dict['args'](output) 76*795d594fSAndroid Build Coastguard Worker return proc_args 77*795d594fSAndroid Build Coastguard Worker 78*795d594fSAndroid Build Coastguard Workerdef run_tool(tool_dict, output): 79*795d594fSAndroid Build Coastguard Worker """ 80*795d594fSAndroid Build Coastguard Worker Execute this tool by passing the tool args to the tool. 81*795d594fSAndroid Build Coastguard Worker """ 82*795d594fSAndroid Build Coastguard Worker proc_args = command_line_for_tool(tool_dict, output) 83*795d594fSAndroid Build Coastguard Worker debug_print("PROC_ARGS: %s" %(proc_args)) 84*795d594fSAndroid Build Coastguard Worker succ = subprocess.call(proc_args) 85*795d594fSAndroid Build Coastguard Worker return succ 86*795d594fSAndroid Build Coastguard Worker 87*795d594fSAndroid Build Coastguard Workerdef get_reference_file(changed_file, tool_dict): 88*795d594fSAndroid Build Coastguard Worker """ 89*795d594fSAndroid Build Coastguard Worker Lookup the file that the tool is generating in response to changing an interesting file 90*795d594fSAndroid Build Coastguard Worker """ 91*795d594fSAndroid Build Coastguard Worker return tool_dict['interesting_to_reference_file'](changed_file, tool_dict['reference_files']) 92*795d594fSAndroid Build Coastguard Worker 93*795d594fSAndroid Build Coastguard Workerdef run_diff(changed_file, tool_dict, original_file): 94*795d594fSAndroid Build Coastguard Worker ref_file = get_reference_file(changed_file, tool_dict) 95*795d594fSAndroid Build Coastguard Worker 96*795d594fSAndroid Build Coastguard Worker return subprocess.call(["diff", ref_file, original_file]) != 0 97*795d594fSAndroid Build Coastguard Worker 98*795d594fSAndroid Build Coastguard Workerdef run_gen_srcs(files): 99*795d594fSAndroid Build Coastguard Worker """ 100*795d594fSAndroid Build Coastguard Worker Runs test tools only for interesting files that were changed in this commit. 101*795d594fSAndroid Build Coastguard Worker """ 102*795d594fSAndroid Build Coastguard Worker if len(files) == 0: 103*795d594fSAndroid Build Coastguard Worker return 104*795d594fSAndroid Build Coastguard Worker 105*795d594fSAndroid Build Coastguard Worker success = 0 # exit code 0 = success, >0 error. 106*795d594fSAndroid Build Coastguard Worker had_diffs = False 107*795d594fSAndroid Build Coastguard Worker 108*795d594fSAndroid Build Coastguard Worker for tool_dict in TOOLS_GEN_SRCS: 109*795d594fSAndroid Build Coastguard Worker tool_ran_at_least_once = False 110*795d594fSAndroid Build Coastguard Worker for f in files: 111*795d594fSAndroid Build Coastguard Worker if is_interesting(f, tool_dict): 112*795d594fSAndroid Build Coastguard Worker tmp_file = tempfile.mktemp() 113*795d594fSAndroid Build Coastguard Worker reference_file = get_reference_file(f, tool_dict) 114*795d594fSAndroid Build Coastguard Worker 115*795d594fSAndroid Build Coastguard Worker # Generate the source code with a temporary file as the output. 116*795d594fSAndroid Build Coastguard Worker success = run_tool(tool_dict, tmp_file) 117*795d594fSAndroid Build Coastguard Worker if success != 0: 118*795d594fSAndroid Build Coastguard Worker # Immediately abort if the tool fails with a non-0 exit code, do not go any further. 119*795d594fSAndroid Build Coastguard Worker print("[FATAL] Error when running tool (return code %s)" %(success), file=sys.stderr) 120*795d594fSAndroid Build Coastguard Worker print("$> %s" %(" ".join(command_line_for_tool(tool_dict, tmp_file))), file=sys.stderr) 121*795d594fSAndroid Build Coastguard Worker sys.exit(success) 122*795d594fSAndroid Build Coastguard Worker if run_diff(f, tool_dict, tmp_file): 123*795d594fSAndroid Build Coastguard Worker # If the tool succeeded, but there was a diff, then the generated code has diverged. 124*795d594fSAndroid Build Coastguard Worker # Output the diff information and continue to the next files/tools. 125*795d594fSAndroid Build Coastguard Worker had_diffs = True 126*795d594fSAndroid Build Coastguard Worker print("-----------------------------------------------------------", file=sys.stderr) 127*795d594fSAndroid Build Coastguard Worker print("File '%s' diverged from generated file; please re-run tools:" %(reference_file), file=sys.stderr) 128*795d594fSAndroid Build Coastguard Worker print("$> %s" %(" ".join(command_line_for_tool(tool_dict, reference_file))), file=sys.stderr) 129*795d594fSAndroid Build Coastguard Worker else: 130*795d594fSAndroid Build Coastguard Worker debug_print("File %s is consistent with tool %s" %(reference_file, tool_dict['tool'])) 131*795d594fSAndroid Build Coastguard Worker 132*795d594fSAndroid Build Coastguard Worker tool_ran_at_least_once = True 133*795d594fSAndroid Build Coastguard Worker 134*795d594fSAndroid Build Coastguard Worker if not tool_ran_at_least_once: 135*795d594fSAndroid Build Coastguard Worker debug_print("Interesting files %s unchanged, skipping tool '%s'" %(tool_dict['interesting_files'], tool_dict['tool'])) 136*795d594fSAndroid Build Coastguard Worker 137*795d594fSAndroid Build Coastguard Worker if had_diffs: 138*795d594fSAndroid Build Coastguard Worker success = 1 139*795d594fSAndroid Build Coastguard Worker # Always return non-0 exit code when there were diffs so that the presubmit hooks are FAILED. 140*795d594fSAndroid Build Coastguard Worker 141*795d594fSAndroid Build Coastguard Worker return success 142*795d594fSAndroid Build Coastguard Worker 143*795d594fSAndroid Build Coastguard Worker 144*795d594fSAndroid Build Coastguard Workerdef main(): 145*795d594fSAndroid Build Coastguard Worker if 'PREUPLOAD_COMMIT' in os.environ: 146*795d594fSAndroid Build Coastguard Worker commit = os.environ['PREUPLOAD_COMMIT'] 147*795d594fSAndroid Build Coastguard Worker else: 148*795d594fSAndroid Build Coastguard Worker print("WARNING: Not running as a pre-upload hook. Assuming commit to check = 'HEAD'", file=sys.stderr) 149*795d594fSAndroid Build Coastguard Worker commit = "HEAD" 150*795d594fSAndroid Build Coastguard Worker 151*795d594fSAndroid Build Coastguard Worker os.chdir(os.path.join(THIS_PATH, '..')) # run tool relative to 'art' directory 152*795d594fSAndroid Build Coastguard Worker debug_print("CWD: %s" %(os.getcwd())) 153*795d594fSAndroid Build Coastguard Worker 154*795d594fSAndroid Build Coastguard Worker changed_files = get_changed_files(commit) 155*795d594fSAndroid Build Coastguard Worker debug_print("Changed files: %s" %(changed_files)) 156*795d594fSAndroid Build Coastguard Worker return run_gen_srcs(changed_files) 157*795d594fSAndroid Build Coastguard Worker 158*795d594fSAndroid Build Coastguard Workerif __name__ == '__main__': 159*795d594fSAndroid Build Coastguard Worker sys.exit(main()) 160