Skip to content

Commit

Permalink
Encode CleanCommand failures with FailureDetails
Browse files Browse the repository at this point in the history
RELNOTES: None.
PiperOrigin-RevId: 312355942
  • Loading branch information
anakanemison authored and copybara-github committed May 19, 2020
1 parent b77bf3c commit 01e0d23
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,7 @@ public void resetEvaluator() {
skyframeExecutor.resetEvaluator();
}

/**
* Removes in-memory caches.
*/
/** Removes in-memory and on-disk action caches. */
public void clearCaches() throws IOException {
if (actionCache != null) {
actionCache.clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package com.google.devtools.build.lib.runtime.commands;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.common.flogger.GoogleLogger;
import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.analysis.NoBuildEvent;
Expand All @@ -25,9 +26,12 @@
import com.google.devtools.build.lib.runtime.BlazeRuntime;
import com.google.devtools.build.lib.runtime.Command;
import com.google.devtools.build.lib.runtime.CommandEnvironment;
import com.google.devtools.build.lib.server.FailureDetails;
import com.google.devtools.build.lib.server.FailureDetails.CleanCommand.Code;
import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.shell.CommandException;
import com.google.devtools.build.lib.util.CommandBuilder;
import com.google.devtools.build.lib.util.ExitCode;
import com.google.devtools.build.lib.util.InterruptedFailureDetails;
import com.google.devtools.build.lib.util.OS;
import com.google.devtools.build.lib.util.ProcessUtils;
import com.google.devtools.build.lib.util.ShellEscaper;
Expand Down Expand Up @@ -160,15 +164,15 @@ public BlazeCommandResult exec(CommandEnvironment env, OptionsParsingResult opti
.getOptions(BuildRequestOptions.class)
.getSymlinkPrefix(env.getRuntime().getProductName());
return actuallyClean(env, env.getOutputBase(), cleanOptions.expunge, async, symlinkPrefix);
} catch (IOException e) {
env.getReporter().handle(Event.error(e.getMessage()));
return BlazeCommandResult.exitCode(ExitCode.LOCAL_ENVIRONMENTAL_ERROR);
} catch (CommandException | ExecException e) {
} catch (CleanException e) {
env.getReporter().handle(Event.error(e.getMessage()));
return BlazeCommandResult.exitCode(ExitCode.RUN_FAILURE);
return BlazeCommandResult.failureDetail(e.getFailureDetail());
} catch (InterruptedException e) {
env.getReporter().handle(Event.error("clean interrupted"));
return BlazeCommandResult.exitCode(ExitCode.INTERRUPTED);
String message = "clean interrupted";
env.getReporter().handle(Event.error(message));
return BlazeCommandResult.detailedExitCode(
InterruptedFailureDetails.detailedExitCode(
message, FailureDetails.Interrupted.Code.CLEAN_COMMAND));
}
}

Expand Down Expand Up @@ -203,25 +207,36 @@ private static void asyncClean(CommandEnvironment env, Path path, String pathIte

private BlazeCommandResult actuallyClean(
CommandEnvironment env, Path outputBase, boolean expunge, boolean async, String symlinkPrefix)
throws IOException, CommandException, ExecException,
InterruptedException {
throws CleanException, InterruptedException {
BlazeRuntime runtime = env.getRuntime();
String workspaceDirectory = env.getWorkspace().getBaseName();
if (env.getOutputService() != null) {
env.getOutputService().clean();
try {
env.getOutputService().clean();
} catch (ExecException e) {
throw new CleanException(Code.OUTPUT_SERVICE_CLEAN_FAILURE, e);
}
}
try {
env.getBlazeWorkspace().clearCaches();
} catch (IOException e) {
throw new CleanException(Code.ACTION_CACHE_CLEAN_FAILURE, e);
}
env.getBlazeWorkspace().clearCaches();
if (expunge && !async) {
logger.atInfo().log("Expunging...");
runtime.prepareForAbruptShutdown();
// Close java.log.
LogManager.getLogManager().reset();
// Close the default stdout/stderr.
if (FileDescriptor.out.valid()) {
new FileOutputStream(FileDescriptor.out).close();
}
if (FileDescriptor.err.valid()) {
new FileOutputStream(FileDescriptor.err).close();
try {
if (FileDescriptor.out.valid()) {
new FileOutputStream(FileDescriptor.out).close();
}
if (FileDescriptor.err.valid()) {
new FileOutputStream(FileDescriptor.err).close();
}
} catch (IOException e) {
throw new CleanException(Code.OUT_ERR_CLOSE_FAILURE, e);
}
// Close the redirected stdout/stderr.
System.out.close();
Expand All @@ -231,22 +246,42 @@ private BlazeCommandResult actuallyClean(
// and links right before we exit. Once the lock file is gone there will
// be a small possibility of a server race if a client is waiting, but
// all significant files will be gone by then.
outputBase.deleteTreesBelow();
outputBase.deleteTree();
try {
outputBase.deleteTreesBelow();
outputBase.deleteTree();
} catch (IOException e) {
throw new CleanException(Code.OUTPUT_BASE_DELETE_FAILURE, e);
}
} else if (expunge && async) {
logger.atInfo().log("Expunging asynchronously...");
runtime.prepareForAbruptShutdown();
asyncClean(env, outputBase, "Output base");
try {
asyncClean(env, outputBase, "Output base");
} catch (IOException e) {
throw new CleanException(Code.OUTPUT_BASE_TEMP_MOVE_FAILURE, e);
} catch (CommandException e) {
throw new CleanException(Code.ASYNC_OUTPUT_BASE_DELETE_FAILURE, e);
}
} else {
logger.atInfo().log("Output cleaning...");
env.getBlazeWorkspace().resetEvaluator();
Path execroot = outputBase.getRelative("execroot");
if (execroot.exists()) {
logger.atFinest().log("Cleaning %s%s", execroot, async ? " asynchronously..." : "");
if (async) {
asyncClean(env, execroot, "Output tree");
try {
asyncClean(env, execroot, "Output tree");
} catch (IOException e) {
throw new CleanException(Code.EXECROOT_TEMP_MOVE_FAILURE, e);
} catch (CommandException e) {
throw new CleanException(Code.ASYNC_EXECROOT_DELETE_FAILURE, e);
}
} else {
execroot.deleteTreesBelow();
try {
execroot.deleteTreesBelow();
} catch (IOException e) {
throw new CleanException(Code.EXECROOT_DELETE_FAILURE, e);
}
}
}
}
Expand All @@ -266,4 +301,20 @@ private BlazeCommandResult actuallyClean(
System.gc();
return BlazeCommandResult.success();
}

private static class CleanException extends Exception {
private final FailureDetails.CleanCommand.Code detailedCode;

private CleanException(FailureDetails.CleanCommand.Code detailedCode, Exception e) {
super(Strings.nullToEmpty(e.getMessage()), e);
this.detailedCode = detailedCode;
}

private FailureDetail getFailureDetail() {
return FailureDetail.newBuilder()
.setMessage(getMessage())
.setCleanCommand(FailureDetails.CleanCommand.newBuilder().setCode(detailedCode))
.build();
}
}
}
19 changes: 19 additions & 0 deletions src/main/protobuf/failure_details.proto
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ message FailureDetail {
TestCommand test_command = 140;
ActionQuery action_query = 141;
TargetPatterns target_patterns = 142;
CleanCommand clean_command = 144;
}

reserved 102; // For internal use
Expand Down Expand Up @@ -145,6 +146,7 @@ message Interrupted {
AFTER_QUERY = 10 [(metadata) = { exit_code: 8 }];
FETCH_COMMAND = 17 [(metadata) = { exit_code: 8 }];
SYNC_COMMAND = 18 [(metadata) = { exit_code: 8 }];
CLEAN_COMMAND = 20 [(metadata) = { exit_code: 8 }];
reserved 1 to 3; // For internal use
reserved 11 to 16; // For internal use
reserved 19; // For internal use
Expand Down Expand Up @@ -616,3 +618,20 @@ message TargetPatterns {

Code code = 1;
}

message CleanCommand {
enum Code {
CLEAN_COMMAND_UNKNOWN = 0 [(metadata) = { exit_code: 37 }];
OUTPUT_SERVICE_CLEAN_FAILURE = 1 [(metadata) = { exit_code: 6 }];
ACTION_CACHE_CLEAN_FAILURE = 2 [(metadata) = { exit_code: 36 }];
OUT_ERR_CLOSE_FAILURE = 3 [(metadata) = { exit_code: 36 }];
OUTPUT_BASE_DELETE_FAILURE = 4 [(metadata) = { exit_code: 36 }];
OUTPUT_BASE_TEMP_MOVE_FAILURE = 5 [(metadata) = { exit_code: 36 }];
ASYNC_OUTPUT_BASE_DELETE_FAILURE = 6 [(metadata) = { exit_code: 6 }];
EXECROOT_DELETE_FAILURE = 7 [(metadata) = { exit_code: 36 }];
EXECROOT_TEMP_MOVE_FAILURE = 8 [(metadata) = { exit_code: 36 }];
ASYNC_EXECROOT_DELETE_FAILURE = 9 [(metadata) = { exit_code: 6 }];
}

Code code = 1;
}

0 comments on commit 01e0d23

Please sign in to comment.