diff --git a/FILES.md b/FILES.md index 488959933..27a4d655b 100644 --- a/FILES.md +++ b/FILES.md @@ -20,5 +20,3 @@ The rest of the commands in infer/bin/ are not meant to be called directly, but *InferAnalyze* : Binary containing the backend of Infer that performs the analysis. *InferPrint* : Binary that prints reports about the analysis such as the specs of methods and a list of bugs found. - -*BuckAnalyze* : Command for running the analysis of Java projects compiled with Buck. diff --git a/infer.install b/infer.install index 2dc9e7d5e..8c5c6f1a4 100644 --- a/infer.install +++ b/infer.install @@ -6,6 +6,5 @@ bin: [ "?infer/bin/InferClang" "infer/bin/InferAnalyze" "infer/bin/InferPrint" - "infer/bin/BuckAnalyze" ] diff --git a/infer/lib/python/BuckAnalyze b/infer/lib/python/inferlib/bucklib.py similarity index 82% rename from infer/lib/python/BuckAnalyze rename to infer/lib/python/inferlib/bucklib.py index cc8268657..d4413478b 100755 --- a/infer/lib/python/BuckAnalyze +++ b/infer/lib/python/inferlib/bucklib.py @@ -118,7 +118,7 @@ def prepare_build(args): return temp_files, infer_script.name -def get_normalized_targets(targets): +def get_normalized_targets(targets, verbose): """ Use buck to convert a list of input targets/aliases into a set of the (transitive) target deps for all inputs""" @@ -133,7 +133,7 @@ def get_normalized_targets(targets): targets = filter( lambda line: len(line) > 0, subprocess.check_output(buck_cmd).decode().strip().split('\n')) - if len(targets) > 0 and args.verbose: + if len(targets) > 0 and verbose: logging.debug('Targets to analyze:') for target in targets: logging.debug(target) @@ -420,67 +420,78 @@ def cleanup(temp_files): logging.error('Could not remove %s' % file) -if __name__ == '__main__': - parser = argparse.ArgumentParser(parents=[analyze.base_parser]) - parser.add_argument('--verbose', action='store_true', - help='Print buck compilation steps') - parser.add_argument('--no-cache', action='store_true', - help='Do not use buck distributed cache') - parser.add_argument('--print-harness', action='store_true', - help='Print generated harness code (Android only)') - parser.add_argument('targets', nargs='*', metavar='target', - help='Build targets to analyze') - args = parser.parse_args() +parser = argparse.ArgumentParser() +parser.add_argument('--build-report', metavar='PATH', type=str) +parser.add_argument('--deep', action='store_true') +parser.add_argument('--keep-going', action='store_true') +parser.add_argument('--load-limit', '-L') +parser.add_argument('--no-cache', action='store_true') +parser.add_argument('--profile', action='store_true') +parser.add_argument('--shallow', action='store_true') +parser.add_argument('--num-threads', '-j', metavar='N') +parser.add_argument('--verbose', '-v', metavar='N', type=int) +parser.add_argument('targets', nargs='*', metavar='target', + help='Build targets to analyze') - utils.configure_logging(args) - timer = utils.Timer(logging.info) - temp_files = [] - try: - start_time = time.time() - logging.info('Starting the analysis') - subprocess.check_call( - [utils.get_cmd_in_bin_dir('InferAnalyze'), '-version']) - - if not os.path.isdir(args.infer_out): - os.mkdir(args.infer_out) - - timer.start('Preparing build...') - temp_files2, infer_script = prepare_build(args) - temp_files += temp_files2 - timer.stop('Build prepared') - - # TODO(t3786463) Start buckd. - - timer.start('Computing library targets') - normalized_targets = get_normalized_targets(args.targets) - timer.stop('%d targets computed', len(normalized_targets)) - - if len(normalized_targets) == 0: - logging.info('Nothing to analyze') - else: - timer.start('Running buck...') - buck_cmd = [ - 'buck', 'build', '--config', 'tools.javac=' + infer_script] - if args.no_cache: - buck_cmd += ['--no-cache'] - if args.verbose: - buck_cmd += ['-v', '2'] - compile_cmd = buck_cmd + normalized_targets - subprocess.check_call(compile_cmd) - timer.stop('Buck finished') - - timer.start('Collecting results...') - collect_results(args, start_time) - timer.stop('Done') - - except KeyboardInterrupt as e: - timer.stop('Exiting') - sys.exit(0) - except Exception as e: - timer.stop('Failed') - logging.error('Caught %s: %s' % (e.__class__.__name__, str(e))) - logging.error(traceback.format_exc()) - sys.exit(1) - finally: - cleanup(temp_files) +class UnsuportedBuckCommand(Exception): + pass + + +def parse_buck_command(args): + build_keyword = 'build' + if build_keyword in args and len(args[args.index(build_keyword):]) > 1: + next_index = args.index(build_keyword) + 1 + buck_args = parser.parse_args(args[next_index:]) + return buck_args + else: + raise UnsuportedBuckCommand(args) + + +class Wrapper: + + def __init__(self, infer_args, buck_cmd): + self.timer = utils.Timer(logging.info) + self.infer_args = infer_args + self.buck_args = parse_buck_command(buck_cmd) + self.timer.start('Computing library targets') + self.targets = get_normalized_targets( + self.buck_args.targets, + self.infer_args.verbose) + self.timer.stop('%d targets computed', len(self.targets)) + + def run(self): + temp_files = [] + try: + start_time = time.time() + logging.info('Starting the analysis') + + if not os.path.isdir(self.infer_args.infer_out): + os.mkdir(self.infer_args.infer_out) + + self.timer.start('Preparing build...') + temp_files2, infer_script = prepare_build(self.infer_args) + temp_files += temp_files2 + self.timer.stop('Build prepared') + + if len(self.targets) == 0: + logging.info('Nothing to analyze') + else: + self.timer.start('Running buck...') + buck_cmd = ['buck', 'build'] + if self.buck_args.verbose is not None: + buck_cmd += ['--verbose', str(self.buck_args.verbose)] + buck_cmd += ['--config', 'tools.javac=' + infer_script] + buck_cmd += self.targets + subprocess.check_call(buck_cmd) + self.timer.stop('Buck finished') + + self.timer.start('Collecting results...') + collect_results(self.infer_args, start_time) + self.timer.stop('Done') + return os.EX_OK + except KeyboardInterrupt as e: + self.timer.stop('Exiting') + sys.exit(0) + finally: + cleanup(temp_files) diff --git a/infer/lib/python/inferlib/capture/buck.py b/infer/lib/python/inferlib/capture/buck.py index e968b966e..e32db3a97 100644 --- a/infer/lib/python/inferlib/capture/buck.py +++ b/infer/lib/python/inferlib/capture/buck.py @@ -13,7 +13,7 @@ import subprocess import traceback import util -from inferlib import config, issues, utils +from inferlib import config, issues, utils, bucklib MODULE_NAME = __name__ MODULE_DESCRIPTION = '''Run analysis of code built with a command like: @@ -153,22 +153,5 @@ class BuckAnalyzer: def capture_without_flavors(self): # BuckAnalyze is a special case, and we run the analysis from here - capture_cmd = [utils.get_cmd_in_bin_dir('BuckAnalyze')] - if self.args.infer_out is not None: - capture_cmd += ['--out', self.args.infer_out] - if self.args.debug: - capture_cmd.append('-g') - if self.args.debug_exceptions: - capture_cmd.append('--debug-exceptions') - if self.args.no_filtering: - capture_cmd.append('--no-filtering') - if self.args.verbose: - capture_cmd.append('--verbose') - if self.args.no_cache: - capture_cmd.append('--no-cache') - if self.args.print_harness: - capture_cmd.append('--print-harness') - capture_cmd += self.cmd[2:] # TODO: make extraction of targets smarter - capture_cmd += ['--analyzer', self.args.analyzer] - subprocess.check_call(capture_cmd) - return os.EX_OK + buck_wrapper = bucklib.Wrapper(self.args, self.cmd) + return buck_wrapper.run()