blob: ad74633a1638b94b9b2c9563d9bb9f604821f628 [file] [log] [blame]
// Copyright 2014 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.shell;
import com.google.auto.value.AutoValue;
import com.google.common.flogger.GoogleLogger;
import com.google.common.flogger.LazyArgs;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.io.ByteArrayOutputStream;
import java.time.Duration;
import java.util.Optional;
/**
* Encapsulates the results of a command execution, including exit status and output to stdout and
* stderr.
*/
@AutoValue
public abstract class CommandResult {
private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();
private static final byte[] NO_BYTES = new byte[0];
static final ByteArrayOutputStream EMPTY_OUTPUT =
new ByteArrayOutputStream() {
@Override
public synchronized byte[] toByteArray() {
return NO_BYTES;
}
};
static final ByteArrayOutputStream NO_OUTPUT_COLLECTED =
new ByteArrayOutputStream(){
@Override
public synchronized byte[] toByteArray() {
throw new IllegalStateException("Output was not collected");
}
};
/** Returns the stdout {@link ByteArrayOutputStream}. */
public abstract ByteArrayOutputStream getStdoutStream();
/** Returns the stderr {@link ByteArrayOutputStream}. */
public abstract ByteArrayOutputStream getStderrStream();
/**
* Returns the stdout as a byte array.
*
* @return raw bytes that were written to stdout by the command, or null if caller did chose to
* ignore output
* @throws IllegalStateException if output was not collected
*/
public byte[] getStdout() {
return getStdoutStream().toByteArray();
}
/**
* Returns the stderr as a byte array.
*
* @return raw bytes that were written to stderr by the command, or null if caller did chose to
* ignore output
* @throws IllegalStateException if output was not collected
*/
public byte[] getStderr() {
return getStderrStream().toByteArray();
}
/** Returns the termination status of the subprocess. */
public abstract TerminationStatus getTerminationStatus();
/**
* Returns the wall execution time.
*
* @return the measurement, or empty in case of execution errors or when the measurement is not
* implemented for the current platform
*/
public abstract Optional<Duration> getWallExecutionTime();
/**
* Returns the user execution time.
*
* @return the measurement, or empty in case of execution errors or when the measurement is not
* implemented for the current platform
*/
public abstract Optional<Duration> getUserExecutionTime();
/**
* Returns the system execution time.
*
* @return the measurement, or empty in case of execution errors or when the measurement is not
* implemented for the current platform
*/
public abstract Optional<Duration> getSystemExecutionTime();
void logThis() {
logger.atFiner().log("%s", LazyArgs.lazy(() -> getTerminationStatus()));
if (getStdoutStream() == NO_OUTPUT_COLLECTED) {
return;
}
logger.atFiner().log("Stdout: %s", LazyArgs.lazy(() -> LogUtil.toTruncatedString(getStdout())));
logger.atFiner().log("Stderr: %s", LazyArgs.lazy(() -> LogUtil.toTruncatedString(getStderr())));
}
/** Returns a new {@link CommandResult.Builder}. */
public static Builder builder() {
return new AutoValue_CommandResult.Builder();
}
/** A builder for {@link CommandResult}s. */
@AutoValue.Builder
public abstract static class Builder {
/** Sets the stdout output for the command. */
public abstract Builder setStdoutStream(ByteArrayOutputStream stdout);
/** Sets the stderr output for the command. */
public abstract Builder setStderrStream(ByteArrayOutputStream stderr);
/** Sets the termination status for the command. */
public abstract Builder setTerminationStatus(TerminationStatus terminationStatus);
/** Sets the wall execution time. */
@CanIgnoreReturnValue
public Builder setWallExecutionTime(Duration wallExecutionTime) {
setWallExecutionTime(Optional.of(wallExecutionTime));
return this;
}
/** Sets or clears the wall execution time. */
public abstract Builder setWallExecutionTime(Optional<Duration> wallExecutionTime);
/** Sets the user execution time. */
@CanIgnoreReturnValue
public Builder setUserExecutionTime(Duration userExecutionTime) {
setUserExecutionTime(Optional.of(userExecutionTime));
return this;
}
/** Sets or clears the user execution time. */
public abstract Builder setUserExecutionTime(Optional<Duration> userExecutionTime);
/** Sets the system execution time. */
@CanIgnoreReturnValue
public Builder setSystemExecutionTime(Duration systemExecutionTime) {
setSystemExecutionTime(Optional.of(systemExecutionTime));
return this;
}
/** Sets or clears the system execution time. */
public abstract Builder setSystemExecutionTime(Optional<Duration> systemExecutionTime);
/** Builds a {@link CommandResult} object. */
public abstract CommandResult build();
}
}