use of com.google.devtools.build.lib.shell.AbnormalTerminationException in project bazel by bazelbuild.
the class AppleHostInfo method getSdkRoot.
/**
* Returns the absolute root path of the target Apple SDK on the host system for a given
* version of xcode (as defined by the given {@code developerDir}). This may spawn a
* process and use the {@code /usr/bin/xcrun} binary to locate the target SDK. This uses a local
* cache file under {@code bazel-out}, and will only spawn a new {@code xcrun} process in the case
* of a cache miss.
*
* @param execRoot the execution root path, used to locate the cache file
* @param developerDir the value of {@code DEVELOPER_DIR} for the target version of xcode
* @param sdkVersion the sdk version, for example, "9.1"
* @param appleSdkPlatform the sdk platform, for example, "iPhoneOS"
* @param productName the product name
* @throws UserExecException if there is an issue with obtaining the root from the spawned
* process, either because the SDK platform/version pair doesn't exist, or there was an
* unexpected issue finding or running the tool
*/
public static String getSdkRoot(Path execRoot, String developerDir, String sdkVersion, String appleSdkPlatform, String productName) throws UserExecException {
try {
CacheManager cacheManager = new CacheManager(execRoot.getRelative(BlazeDirectories.getRelativeOutputPath(productName)), XCRUN_CACHE_FILENAME);
String sdkString = appleSdkPlatform.toLowerCase() + sdkVersion;
String cacheResult = cacheManager.getValue(developerDir, sdkString);
if (cacheResult != null) {
return cacheResult;
} else {
Map<String, String> env = Strings.isNullOrEmpty(developerDir) ? ImmutableMap.<String, String>of() : ImmutableMap.of("DEVELOPER_DIR", developerDir);
CommandResult xcrunResult = new Command(new String[] { "/usr/bin/xcrun", "--sdk", sdkString, "--show-sdk-path" }, env, null).execute();
// calling xcrun via Command returns a value with a newline on the end.
String sdkRoot = new String(xcrunResult.getStdout(), StandardCharsets.UTF_8).trim();
cacheManager.writeEntry(ImmutableList.of(developerDir, sdkString), sdkRoot);
return sdkRoot;
}
} catch (AbnormalTerminationException e) {
TerminationStatus terminationStatus = e.getResult().getTerminationStatus();
if (terminationStatus.exited()) {
throw new UserExecException(String.format("xcrun failed with code %s.\n" + "This most likely indicates that SDK version [%s] for platform [%s] is " + "unsupported for the target version of xcode.\n" + "%s\n" + "Stderr: %s", terminationStatus.getExitCode(), sdkVersion, appleSdkPlatform, terminationStatus.toString(), new String(e.getResult().getStderr(), StandardCharsets.UTF_8)));
}
String message = String.format("xcrun failed.\n%s\n%s", e.getResult().getTerminationStatus(), new String(e.getResult().getStderr(), StandardCharsets.UTF_8));
throw new UserExecException(message, e);
} catch (CommandException | IOException e) {
throw new UserExecException(e);
}
}
use of com.google.devtools.build.lib.shell.AbnormalTerminationException in project bazel by bazelbuild.
the class AppleHostInfo method getDeveloperDir.
/**
* Returns the absolute root path of the xcode developer directory on the host system for
* the given xcode version. This may spawn a process and use the {@code xcode-locator} binary.
* This uses a local cache file under {@code bazel-out}, and will only spawn a new process in the
* case of a cache miss.
*
* @param execRoot the execution root path, used to locate the cache file
* @param version the xcode version number to look up
* @param productName the product name
* @throws UserExecException if there is an issue with obtaining the path from the spawned
* process, either because there is no installed xcode with the given version, or
* there was an unexpected issue finding or running the tool
*/
public static String getDeveloperDir(Path execRoot, DottedVersion version, String productName) throws UserExecException {
try {
CacheManager cacheManager = new CacheManager(execRoot.getRelative(BlazeDirectories.getRelativeOutputPath(productName)), XCODE_LOCATOR_CACHE_FILENAME);
String cacheResult = cacheManager.getValue(version.toString());
if (cacheResult != null) {
return cacheResult;
} else {
CommandResult xcodeLocatorResult = new Command(new String[] { execRoot.getRelative("_bin/xcode-locator").getPathString(), version.toString() }).execute();
String developerDir = new String(xcodeLocatorResult.getStdout(), StandardCharsets.UTF_8).trim();
cacheManager.writeEntry(ImmutableList.of(version.toString()), developerDir);
return developerDir;
}
} catch (AbnormalTerminationException e) {
TerminationStatus terminationStatus = e.getResult().getTerminationStatus();
String message;
if (e.getResult().getTerminationStatus().exited()) {
message = String.format("xcode-locator failed with code %s.\n" + "This most likely indicates that xcode version %s is not available on the host " + "machine.\n" + "%s\n" + "stderr: %s", terminationStatus.getExitCode(), version, terminationStatus.toString(), new String(e.getResult().getStderr(), StandardCharsets.UTF_8));
} else {
message = String.format("xcode-locator failed. %s\nstderr: %s", e.getResult().getTerminationStatus(), new String(e.getResult().getStderr(), StandardCharsets.UTF_8));
}
throw new UserExecException(message, e);
} catch (CommandException | IOException e) {
throw new UserExecException(e);
}
}
use of com.google.devtools.build.lib.shell.AbnormalTerminationException in project bazel by bazelbuild.
the class RunCommand method exec.
@Override
public ExitCode exec(CommandEnvironment env, OptionsProvider options) {
RunOptions runOptions = options.getOptions(RunOptions.class);
// This list should look like: ["//executable:target", "arg1", "arg2"]
List<String> targetAndArgs = options.getResidue();
// The user must at the least specify an executable target.
if (targetAndArgs.isEmpty()) {
env.getReporter().handle(Event.error("Must specify a target to run"));
return ExitCode.COMMAND_LINE_ERROR;
}
String targetString = targetAndArgs.get(0);
List<String> runTargetArgs = targetAndArgs.subList(1, targetAndArgs.size());
RunUnder runUnder = options.getOptions(BuildConfiguration.Options.class).runUnder;
OutErr outErr = env.getReporter().getOutErr();
List<String> targets = (runUnder != null) && (runUnder.getLabel() != null) ? ImmutableList.of(targetString, runUnder.getLabel().toString()) : ImmutableList.of(targetString);
BuildRequest request = BuildRequest.create(this.getClass().getAnnotation(Command.class).name(), options, env.getRuntime().getStartupOptionsProvider(), targets, outErr, env.getCommandId(), env.getCommandStartTime());
currentRunUnder = runUnder;
BuildResult result;
try {
result = processRequest(env, request);
} finally {
currentRunUnder = null;
}
if (!result.getSuccess()) {
env.getReporter().handle(Event.error("Build failed. Not running target"));
return result.getExitCondition();
}
// Make sure that we have exactly 1 built target (excluding --run_under),
// and that it is executable.
// These checks should only fail if keepGoing is true, because we already did
// validation before the build began. See {@link #validateTargets()}.
Collection<ConfiguredTarget> targetsBuilt = result.getSuccessfulTargets();
ConfiguredTarget targetToRun = null;
ConfiguredTarget runUnderTarget = null;
if (targetsBuilt != null) {
int maxTargets = runUnder != null && runUnder.getLabel() != null ? 2 : 1;
if (targetsBuilt.size() > maxTargets) {
env.getReporter().handle(Event.error(SINGLE_TARGET_MESSAGE));
return ExitCode.COMMAND_LINE_ERROR;
}
for (ConfiguredTarget target : targetsBuilt) {
ExitCode targetValidation = fullyValidateTarget(env, target);
if (!targetValidation.equals(ExitCode.SUCCESS)) {
return targetValidation;
}
if (runUnder != null && target.getLabel().equals(runUnder.getLabel())) {
if (runUnderTarget != null) {
env.getReporter().handle(Event.error(null, "Can't identify the run_under target from multiple options?"));
return ExitCode.COMMAND_LINE_ERROR;
}
runUnderTarget = target;
} else if (targetToRun == null) {
targetToRun = target;
} else {
env.getReporter().handle(Event.error(SINGLE_TARGET_MESSAGE));
return ExitCode.COMMAND_LINE_ERROR;
}
}
}
// Handle target & run_under referring to the same target.
if ((targetToRun == null) && (runUnderTarget != null)) {
targetToRun = runUnderTarget;
}
if (targetToRun == null) {
env.getReporter().handle(Event.error(NO_TARGET_MESSAGE));
return ExitCode.COMMAND_LINE_ERROR;
}
Path executablePath = Preconditions.checkNotNull(targetToRun.getProvider(FilesToRunProvider.class).getExecutable().getPath());
BuildConfiguration configuration = targetToRun.getConfiguration();
if (configuration == null) {
// The target may be an input file, which doesn't have a configuration. In that case, we
// choose any target configuration.
configuration = result.getBuildConfigurationCollection().getTargetConfigurations().get(0);
}
Path workingDir;
try {
workingDir = ensureRunfilesBuilt(env, targetToRun);
} catch (CommandException e) {
env.getReporter().handle(Event.error("Error creating runfiles: " + e.getMessage()));
return ExitCode.LOCAL_ENVIRONMENTAL_ERROR;
}
List<String> args = runTargetArgs;
FilesToRunProvider provider = targetToRun.getProvider(FilesToRunProvider.class);
RunfilesSupport runfilesSupport = provider == null ? null : provider.getRunfilesSupport();
if (runfilesSupport != null && runfilesSupport.getArgs() != null) {
List<String> targetArgs = runfilesSupport.getArgs();
if (!targetArgs.isEmpty()) {
args = Lists.newArrayListWithCapacity(targetArgs.size() + runTargetArgs.size());
args.addAll(targetArgs);
args.addAll(runTargetArgs);
}
}
String productName = env.getRuntime().getProductName();
//
// We now have a unique executable ready to be run.
//
// We build up two different versions of the command to run: one with an absolute path, which
// we'll actually run, and a prettier one with the long absolute path to the executable
// replaced with a shorter relative path that uses the symlinks in the workspace.
PathFragment prettyExecutablePath = OutputDirectoryLinksUtils.getPrettyPath(executablePath, env.getWorkspaceName(), env.getWorkspace(), options.getOptions(BuildRequestOptions.class).getSymlinkPrefix(productName), productName);
List<String> cmdLine = new ArrayList<>();
if (runOptions.scriptPath == null) {
PathFragment processWrapperPath = env.getBlazeWorkspace().getBinTools().getExecPath(PROCESS_WRAPPER);
Preconditions.checkNotNull(processWrapperPath, PROCESS_WRAPPER + " not found in embedded tools");
cmdLine.add(env.getExecRoot().getRelative(processWrapperPath).getPathString());
cmdLine.add("-1");
cmdLine.add("15");
cmdLine.add("-");
cmdLine.add("-");
}
List<String> prettyCmdLine = new ArrayList<>();
// at the start of the command line.
if (runUnder != null) {
String runUnderValue = runUnder.getValue();
if (runUnderTarget != null) {
// --run_under specifies a target. Get the corresponding executable.
// This must be an absolute path, because the run_under target is only
// in the runfiles of test targets.
runUnderValue = runUnderTarget.getProvider(FilesToRunProvider.class).getExecutable().getPath().getPathString();
// If the run_under command contains any options, make sure to add them
// to the command line as well.
List<String> opts = runUnder.getOptions();
if (!opts.isEmpty()) {
runUnderValue += " " + ShellEscaper.escapeJoinAll(opts);
}
}
cmdLine.add(configuration.getShellExecutable().getPathString());
cmdLine.add("-c");
cmdLine.add(runUnderValue + " " + executablePath.getPathString() + " " + ShellEscaper.escapeJoinAll(args));
prettyCmdLine.add(configuration.getShellExecutable().getPathString());
prettyCmdLine.add("-c");
prettyCmdLine.add(runUnderValue + " " + prettyExecutablePath.getPathString() + " " + ShellEscaper.escapeJoinAll(args));
} else {
cmdLine.add(executablePath.getPathString());
cmdLine.addAll(args);
prettyCmdLine.add(prettyExecutablePath.getPathString());
prettyCmdLine.addAll(args);
}
// Add a newline between the blaze output and the binary's output.
outErr.printErrLn("");
if (runOptions.scriptPath != null) {
String unisolatedCommand = CommandFailureUtils.describeCommand(CommandDescriptionForm.COMPLETE_UNISOLATED, cmdLine, null, workingDir.getPathString());
if (writeScript(env, runOptions.scriptPath, unisolatedCommand)) {
return ExitCode.SUCCESS;
} else {
return ExitCode.RUN_FAILURE;
}
}
env.getReporter().handle(Event.info(null, "Running command line: " + ShellEscaper.escapeJoinAll(prettyCmdLine)));
com.google.devtools.build.lib.shell.Command command = new CommandBuilder().addArgs(cmdLine).setEnv(env.getClientEnv()).setWorkingDir(workingDir).build();
try {
// Restore a raw EventHandler if it is registered. This allows for blaze run to produce the
// actual output of the command being run even if --color=no is specified.
env.getReporter().switchToAnsiAllowingHandler();
// The command API is a little strange in that the following statement
// will return normally only if the program exits with exit code 0.
// If it ends with any other code, we have to catch BadExitStatusException.
command.execute(com.google.devtools.build.lib.shell.Command.NO_INPUT, com.google.devtools.build.lib.shell.Command.NO_OBSERVER, outErr.getOutputStream(), outErr.getErrorStream(), true).getTerminationStatus().getExitCode();
return ExitCode.SUCCESS;
} catch (BadExitStatusException e) {
String message = "Non-zero return code '" + e.getResult().getTerminationStatus().getExitCode() + "' from command: " + e.getMessage();
env.getReporter().handle(Event.error(message));
return ExitCode.RUN_FAILURE;
} catch (AbnormalTerminationException e) {
// The process was likely terminated by a signal in this case.
return ExitCode.INTERRUPTED;
} catch (CommandException e) {
env.getReporter().handle(Event.error("Error running program: " + e.getMessage()));
return ExitCode.RUN_FAILURE;
}
}
use of com.google.devtools.build.lib.shell.AbnormalTerminationException in project bazel by bazelbuild.
the class SandboxRunner method run.
/**
* Runs the command specified via {@code arguments} and {@code env} inside the sandbox.
*
* @param arguments - arguments of spawn to run inside the sandbox.
* @param environment - environment variables to pass to the spawn.
* @param outErr - error output to capture sandbox's and command's stderr.
* @param timeout - after how many seconds should the process be killed.
* @param allowNetwork - whether networking should be allowed for the process.
* @param sandboxDebug - whether debugging message should be printed.
* @param useFakeHostname - whether the hostname should be set to 'localhost' inside the sandbox.
*/
void run(List<String> arguments, Map<String, String> environment, OutErr outErr, int timeout, boolean allowNetwork, boolean sandboxDebug, boolean useFakeHostname) throws ExecException {
Command cmd;
try {
cmd = getCommand(arguments, environment, timeout, allowNetwork, useFakeHostname);
} catch (IOException e) {
throw new UserExecException("I/O error during sandboxed execution", e);
}
TerminationStatus status = null;
try {
cmd.execute(/* stdin */
new byte[] {}, getCommandObserver(timeout), outErr.getOutputStream(), outErr.getErrorStream(), /* killSubprocessOnInterrupt */
true);
} catch (CommandException e) {
boolean timedOut = false;
if (e instanceof AbnormalTerminationException) {
status = ((AbnormalTerminationException) e).getResult().getTerminationStatus();
timedOut = !status.exited() && (status.getTerminatingSignal() == getSignalOnTimeout());
}
String statusMessage = status + " [sandboxed]";
if (!verboseFailures) {
// simplest error message
throw new UserExecException(statusMessage, e, timedOut);
}
List<String> commandList;
if (!sandboxDebug) {
commandList = arguments;
} else {
commandList = Arrays.asList(cmd.getCommandLineElements());
}
String commandFailureMessage = CommandFailureUtils.describeCommandFailure(true, commandList, environment, null) + (sandboxDebug ? "" : SANDBOX_DEBUG_SUGGESTION);
throw new UserExecException(commandFailureMessage, e, timedOut);
}
}
use of com.google.devtools.build.lib.shell.AbnormalTerminationException in project bazel by bazelbuild.
the class StandaloneSpawnStrategy method actuallyExec.
/**
* Executes the given {@code spawn}.
*/
private void actuallyExec(Spawn spawn, ActionExecutionContext actionExecutionContext) throws ExecException {
Executor executor = actionExecutionContext.getExecutor();
if (executor.reportsSubcommands()) {
executor.reportSubcommand(spawn);
}
int timeoutSeconds = Spawns.getTimeoutSeconds(spawn);
// We must wrap the subprocess with process-wrapper to kill the process tree.
// All actions therefore depend on the process-wrapper file. Since it's embedded,
// we don't bother with declaring it as an input.
List<String> args = new ArrayList<>();
if (OS.getCurrent() != OS.WINDOWS) {
// TODO(bazel-team): process-wrapper seems to work on Windows, but requires
// additional setup as it is an msys2 binary, so it needs msys2 DLLs on %PATH%.
// Disable it for now to make the setup easier and to avoid further PATH hacks.
// Ideally we should have a native implementation of process-wrapper for Windows.
args.add(processWrapper.getPathString());
args.add(Integer.toString(timeoutSeconds));
args.add("5");
/* kill delay: give some time to print stacktraces and whatnot. */
// TODO(bazel-team): use process-wrapper redirection so we don't have to
// pass test logs through the Java heap.
args.add("-");
/* stdout. */
args.add("-");
/* stderr. */
}
args.addAll(spawn.getArguments());
String cwd = executor.getExecRoot().getPathString();
Command cmd = new Command(args.toArray(new String[] {}), locallyDeterminedEnv(execRoot, productName, spawn.getEnvironment()), new File(cwd), OS.getCurrent() == OS.WINDOWS && timeoutSeconds >= 0 ? timeoutSeconds * 1000 : -1);
FileOutErr outErr = actionExecutionContext.getFileOutErr();
try {
cmd.execute(/* stdin */
new byte[] {}, Command.NO_OBSERVER, outErr.getOutputStream(), outErr.getErrorStream(), /*killSubprocessOnInterrupt*/
true);
} catch (AbnormalTerminationException e) {
TerminationStatus status = e.getResult().getTerminationStatus();
boolean timedOut = !status.exited() && (status.timedout() || status.getTerminatingSignal() == 14);
String message = CommandFailureUtils.describeCommandFailure(verboseFailures, spawn.getArguments(), spawn.getEnvironment(), cwd);
throw new UserExecException(String.format("%s: %s", message, e), timedOut);
} catch (CommandException e) {
String message = CommandFailureUtils.describeCommandFailure(verboseFailures, spawn.getArguments(), spawn.getEnvironment(), cwd);
throw new UserExecException(message, e);
}
}
Aggregations