From fb2fa5c5cea111317af3f7a1017c1c457d674973 Mon Sep 17 00:00:00 2001 From: Jules Villard Date: Tue, 25 Jul 2017 05:01:19 -0700 Subject: [PATCH] [python] return more errors when external commands fail Summary: Better to bail early than have mysterious failures. These used to have the wrong error messages: ``` $ cd examples/android_hello/ $ infer -- ./gradlew rubbish Capturing in gradle mode... Running and capturing gradle compilation... 10:46:56.730 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] 10:46:56.730 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] FAILURE: Build failed with an exception. 10:46:56.730 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] 10:46:56.730 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] * What went wrong: 10:46:56.730 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] Task 'rubbish' not found in root project 'android_hello'. 10:46:56.730 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] 10:46:56.730 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] * Try: 10:46:56.730 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] Run gradlew tasks to get a list of available tasks. Run with --stacktrace option to get the stack trace. Nothing to compile. Try running `./gradlew clean` first. ERROR: (Unix.Exit_or_signal (Exit_non_zero 66)) $ cd - $ infer --flavors --Xbuck --keep-going -- buck build //toto:toto Capturing in buck mode... moving files in buck-out to buck-out/.trash/buck-outwiiL6N Not using buckd because watchman isn't installed. BUILD FAILED: No build file at toto/BUCK when resolving target //toto:toto#infer. Buck failed, but continuing the analysis because --keep-going was passed Not using buckd because watchman isn't installed. No build file at toto/BUCK when resolving target //toto:toto#infer. Traceback (most recent call last): File "/home/jul/infer/infer/bin/../lib/python/infer.py", line 186, in main() File "/home/jul/infer/infer/bin/../lib/python/infer.py", line 168, in main capture_exitcode = imported_module.gen_instance(args, cmd).capture() File "/home/jul/infer/infer/lib/python/inferlib/capture/buck.py", line 89, in capture return self.capture_with_flavors() File "/home/jul/infer/infer/lib/python/inferlib/capture/buck.py", line 242, in capture_with_flavors result_paths = self._get_analysis_result_paths() File "/home/jul/infer/infer/lib/python/inferlib/capture/buck.py", line 148, in _get_analysis_result_paths out = [x.split(None, 1)[1] for x in buck_output.strip().split('\n')] IndexError: list index out of range ERROR: (Unix.Exit_or_signal (Exit_non_zero 1)) $ cd infer/build_systems/ant/ && infer -- ant rubbish Capturing in ant mode... BUILD FAILED Target "rubbish" does not exist in the project "null". at org.apache.tools.ant.Project.tsort(Project.java:1929) at org.apache.tools.ant.Project.topoSort(Project.java:1837) at org.apache.tools.ant.Project.topoSort(Project.java:1800) at org.apache.tools.ant.Project.executeTarget(Project.java:1376) at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41) at org.apache.tools.ant.Project.executeTargets(Project.java:1260) at org.apache.tools.ant.Main.runBuild(Main.java:857) at org.apache.tools.ant.Main.startAnt(Main.java:236) at org.apache.tools.ant.launch.Launcher.run(Launcher.java:287) at org.apache.tools.ant.launch.Launcher.main(Launcher.java:113) Total time: 0 seconds Nothing to compile. Try running `ant clean` first. ERROR: (Unix.Exit_or_signal (Exit_non_zero 66)) ``` Now we fail better, for instance: ``` $ infer --flavors --Xbuck --keep-going -- buck build //toto:toto Capturing in buck mode... moving files in buck-out to buck-out/.trash/buck-outHag8Ji Not using buckd because watchman isn't installed. BUILD FAILED: No build file at toto/BUCK when resolving target //toto:toto#infer. Buck failed, but continuing the analysis because --keep-going was passed Not using buckd because watchman isn't installed. No build file at toto/BUCK when resolving target //toto:toto#infer. ERROR: (Unix.Exit_or_signal (Exit_non_zero 70)) $ cd infer/build_systems/ant/ && infer -- ant rubbish Capturing in ant mode... BUILD FAILED Target "rubbish" does not exist in the project "null". at org.apache.tools.ant.Project.tsort(Project.java:1929) at org.apache.tools.ant.Project.topoSort(Project.java:1837) at org.apache.tools.ant.Project.topoSort(Project.java:1800) at org.apache.tools.ant.Project.executeTarget(Project.java:1376) at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41) at org.apache.tools.ant.Project.executeTargets(Project.java:1260) at org.apache.tools.ant.Main.runBuild(Main.java:857) at org.apache.tools.ant.Main.startAnt(Main.java:236) at org.apache.tools.ant.launch.Launcher.run(Launcher.java:287) at org.apache.tools.ant.launch.Launcher.main(Launcher.java:113) Total time: 0 seconds ERROR: couldn't run compilation command `['ant', '-verbose', u'rubbish']` ERROR: (Unix.Exit_or_signal (Exit_non_zero 1)) ``` Reviewed By: jeremydubreil Differential Revision: D5469607 fbshipit-source-id: a3eb05c --- infer/lib/python/inferlib/capture/ant.py | 8 ++++++-- infer/lib/python/inferlib/capture/buck.py | 5 +++++ infer/lib/python/inferlib/capture/gradle.py | 5 ++++- infer/lib/python/inferlib/capture/util.py | 9 +++++++-- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/infer/lib/python/inferlib/capture/ant.py b/infer/lib/python/inferlib/capture/ant.py index 808691383..3b71265af 100644 --- a/infer/lib/python/inferlib/capture/ant.py +++ b/infer/lib/python/inferlib/capture/ant.py @@ -6,6 +6,7 @@ # of patent rights can be found in the PATENTS file in the same directory. import logging +import os from . import util from inferlib import jwlib @@ -78,6 +79,9 @@ class AntCapture: return calls def capture(self): - cmds = self.get_infer_commands(util.get_build_output(self.build_cmd)) - clean_cmd = '%s clean' % self.build_cmd[0] + (code, verbose_out) = util.get_build_output(self.build_cmd) + if code != os.EX_OK: + return code + clean_cmd = '\'{}\' clean'.format(self.build_cmd[0]) + cmds = self.get_infer_commands(verbose_out) return util.run_compilation_commands(cmds, clean_cmd) diff --git a/infer/lib/python/inferlib/capture/buck.py b/infer/lib/python/inferlib/capture/buck.py index 8e8c41e44..e5a9941d6 100644 --- a/infer/lib/python/inferlib/capture/buck.py +++ b/infer/lib/python/inferlib/capture/buck.py @@ -144,6 +144,8 @@ class BuckAnalyzer: [x for x in buck_results_cmd if x != KEEP_GOING_OPTION] proc = subprocess.Popen(buck_results_cmd, stdout=subprocess.PIPE) (buck_output, _) = proc.communicate() + if proc.returncode != 0: + return None # remove target name prefixes from each line and split them into a list out = [x.split(None, 1)[1] for x in buck_output.strip().split('\n')] return [os.path.dirname(x) @@ -240,6 +242,9 @@ class BuckAnalyzer: if not ret == os.EX_OK and not self.keep_going: return ret result_paths = self._get_analysis_result_paths() + if result_paths is None: + # huho, the Buck command to extract results paths failed + return os.EX_SOFTWARE merged_reports_path = os.path.join( self.args.infer_out, config.JSON_REPORT_FILENAME) merged_deps_path = os.path.join( diff --git a/infer/lib/python/inferlib/capture/gradle.py b/infer/lib/python/inferlib/capture/gradle.py index 0681fff82..5aee3cc59 100644 --- a/infer/lib/python/inferlib/capture/gradle.py +++ b/infer/lib/python/inferlib/capture/gradle.py @@ -83,6 +83,9 @@ class GradleCapture: def capture(self): print('Running and capturing gradle compilation...') - cmds = self.get_infer_commands(util.get_build_output(self.build_cmd)) + (code, verbose_out) = util.get_build_output(self.build_cmd) + if code != os.EX_OK: + return code + cmds = self.get_infer_commands(verbose_out) clean_cmd = '%s clean' % self.build_cmd[0] return util.run_compilation_commands(cmds, clean_cmd) diff --git a/infer/lib/python/inferlib/capture/util.py b/infer/lib/python/inferlib/capture/util.py index 32e950f89..dd807d2cd 100644 --- a/infer/lib/python/inferlib/capture/util.py +++ b/infer/lib/python/inferlib/capture/util.py @@ -25,7 +25,12 @@ def get_build_output(build_cmd): # TODO make it return generator to be able to handle large builds proc = subprocess.Popen(build_cmd, stdout=subprocess.PIPE) (verbose_out_chars, _) = proc.communicate() - return utils.decode(verbose_out_chars).split('\n') + if proc.returncode != 0: + utils.stderr( + 'ERROR: couldn\'t run compilation command `{}`'.format(build_cmd)) + return (proc.returncode, None) + out = utils.decode(verbose_out_chars).split('\n') + return (os.EX_OK, out) def run_compilation_commands(cmds, clean_cmd): @@ -33,7 +38,7 @@ def run_compilation_commands(cmds, clean_cmd): in case there is nothing to compile. """ # TODO call it in parallel - if len(cmds) == 0: + if cmds is None or len(cmds) == 0: utils.stderr('Nothing to compile. Try running `{}` first.' .format(clean_cmd)) return os.EX_NOINPUT