| #!/usr/bin/env python3 |
| # Copyright 2020 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| """Wraps the turbine jar and expands @FileArgs.""" |
| |
| import argparse |
| import functools |
| import logging |
| import os |
| import sys |
| import time |
| import zipfile |
| |
| import compile_java |
| import javac_output_processor |
| from util import build_utils |
| import action_helpers # build_utils adds //build to sys.path. |
| import zip_helpers |
| |
| |
| def ProcessJavacOutput(output, target_name): |
| output_processor = javac_output_processor.JavacOutputProcessor(target_name) |
| lines = output_processor.Process(output.split('\n')) |
| return '\n'.join(lines) |
| |
| |
| def main(argv): |
| build_utils.InitLogging('TURBINE_DEBUG') |
| argv = build_utils.ExpandFileArgs(argv[1:]) |
| parser = argparse.ArgumentParser() |
| action_helpers.add_depfile_arg(parser) |
| parser.add_argument('--target-name', help='Fully qualified GN target name.') |
| parser.add_argument( |
| '--turbine-jar-path', required=True, help='Path to the turbine jar file.') |
| parser.add_argument( |
| '--java-srcjars', |
| action='append', |
| help='List of srcjars to include in compilation.') |
| parser.add_argument('--classpath', action='append', help='Classpath to use.') |
| parser.add_argument( |
| '--processors', |
| action='append', |
| help='GN list of annotation processor main classes.') |
| parser.add_argument( |
| '--processorpath', |
| action='append', |
| help='GN list of jars that comprise the classpath used for Annotation ' |
| 'Processors.') |
| parser.add_argument( |
| '--processor-args', |
| action='append', |
| help='key=value arguments for the annotation processors.') |
| parser.add_argument('--jar-path', help='Jar output path.', required=True) |
| parser.add_argument( |
| '--generated-jar-path', |
| required=True, |
| help='Output path for generated source files.') |
| parser.add_argument('--warnings-as-errors', |
| action='store_true', |
| help='Treat all warnings as errors.') |
| parser.add_argument('--kotlin-jar-path', |
| help='Kotlin jar to be merged into the output jar.') |
| options, unknown_args = parser.parse_known_args(argv) |
| |
| options.classpath = action_helpers.parse_gn_list(options.classpath) |
| options.processorpath = action_helpers.parse_gn_list(options.processorpath) |
| options.processors = action_helpers.parse_gn_list(options.processors) |
| options.java_srcjars = action_helpers.parse_gn_list(options.java_srcjars) |
| |
| files = [] |
| for arg in unknown_args: |
| # Interpret a path prefixed with @ as a file containing a list of sources. |
| if arg.startswith('@'): |
| files.extend(build_utils.ReadSourcesList(arg[1:])) |
| elif arg.startswith('-'): |
| parser.error('Unknown flag: ' + arg) |
| else: |
| files.append(arg) |
| |
| # Turbine does not complain about missing classpath files. Missing files can |
| # result in misleading compile errors though, so do an upfront check. |
| classpath_jars = options.classpath + options.processorpath |
| missing_jars = [p for p in classpath_jars if not os.path.exists(p)] |
| if missing_jars: |
| sys.stderr.write('One or more classpath .jar files does not exist:\n') |
| sys.stderr.write('\n'.join(missing_jars) + '\n') |
| sys.exit(1) |
| |
| # The target's .sources file contains both Java and Kotlin files. We use |
| # compile_kt.py to compile the Kotlin files to .class and header jars. |
| # Turbine is run only on .java files. |
| java_files = [f for f in files if f.endswith('.java')] |
| |
| cmd = build_utils.JavaCmd() + [ |
| '-classpath', options.turbine_jar_path, 'com.google.turbine.main.Main' |
| ] |
| javac_cmd = ['--release', '17'] |
| |
| # Turbine reads lists from command line args by consuming args until one |
| # starts with double dash (--). Thus command line args should be grouped |
| # together and passed in together. |
| if options.processors: |
| cmd += ['--processors'] |
| cmd += options.processors |
| |
| if options.processorpath: |
| cmd += ['--processorpath'] |
| cmd += options.processorpath |
| |
| if options.processor_args: |
| for arg in options.processor_args: |
| javac_cmd.extend(['-A%s' % arg]) |
| |
| if options.classpath: |
| cmd += ['--classpath'] |
| cmd += options.classpath |
| |
| if options.java_srcjars: |
| cmd += ['--source_jars'] |
| cmd += options.java_srcjars |
| |
| if java_files: |
| # Use jar_path to ensure paths are relative (needed for rbe). |
| files_rsp_path = options.jar_path + '.java_files_list.txt' |
| with open(files_rsp_path, 'w') as f: |
| f.write('\n'.join(java_files)) |
| # Pass source paths as response files to avoid extremely long command |
| # lines that are tedius to debug. |
| cmd += ['--sources'] |
| cmd += ['@' + files_rsp_path] |
| |
| cmd += ['--javacopts'] |
| cmd += javac_cmd |
| cmd += ['--'] # Terminate javacopts |
| |
| # Use AtomicOutput so that output timestamps are not updated when outputs |
| # are not changed. |
| with action_helpers.atomic_output(options.jar_path) as output_jar, \ |
| action_helpers.atomic_output(options.generated_jar_path) as gensrc_jar: |
| cmd += ['--output', output_jar.name, '--gensrc_output', gensrc_jar.name] |
| process_javac_output_partial = functools.partial( |
| ProcessJavacOutput, target_name=options.target_name) |
| |
| logging.debug('Command: %s', cmd) |
| start = time.time() |
| try: |
| build_utils.CheckOutput(cmd, |
| print_stdout=True, |
| stdout_filter=process_javac_output_partial, |
| stderr_filter=process_javac_output_partial, |
| fail_on_output=options.warnings_as_errors) |
| except build_utils.CalledProcessError as e: |
| # Do not output stacktrace as it takes up space on gerrit UI, forcing |
| # you to click though to find the actual compilation error. It's never |
| # interesting to see the Python stacktrace for a Java compilation error. |
| sys.stderr.write(e.output) |
| sys.exit(1) |
| end = time.time() - start |
| logging.info('Header compilation took %ss', end) |
| if options.kotlin_jar_path: |
| with zipfile.ZipFile(output_jar.name, 'a') as out_zip: |
| path_transform = lambda p: p if p.endswith('.class') else None |
| zip_helpers.merge_zips(out_zip, [options.kotlin_jar_path], |
| path_transform=path_transform) |
| |
| if options.depfile: |
| # GN already knows of the java files, so avoid listing individual java files |
| # in the depfile. |
| action_helpers.write_depfile(options.depfile, options.jar_path, |
| classpath_jars) |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main(sys.argv)) |