| // 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 static java.util.Objects.requireNonNull; |
| |
| import com.google.auto.value.AutoBuilder; |
| 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. |
| * |
| * @param stdoutStream Returns the stdout {@link ByteArrayOutputStream}. |
| * @param stderrStream Returns the stderr {@link ByteArrayOutputStream}. |
| * @param terminationStatus Returns the termination status of the subprocess. |
| * @param wallExecutionTime Returns the wall execution time. the measurement, or empty in case of |
| * execution errors or when the measurement is not implemented for the current platform |
| * @param userExecutionTime Returns the user execution time. the measurement, or empty in case of |
| * execution errors or when the measurement is not implemented for the current platform |
| * @param systemExecutionTime Returns the system execution time. the measurement, or empty in case |
| * of execution errors or when the measurement is not implemented for the current platform |
| */ |
| public record CommandResult( |
| ByteArrayOutputStream stdoutStream, |
| ByteArrayOutputStream stderrStream, |
| TerminationStatus terminationStatus, |
| Optional<Duration> wallExecutionTime, |
| Optional<Duration> userExecutionTime, |
| Optional<Duration> systemExecutionTime) { |
| public CommandResult { |
| requireNonNull(stdoutStream, "stdoutStream"); |
| requireNonNull(stderrStream, "stderrStream"); |
| requireNonNull(terminationStatus, "terminationStatus"); |
| requireNonNull(wallExecutionTime, "wallExecutionTime"); |
| requireNonNull(userExecutionTime, "userExecutionTime"); |
| requireNonNull(systemExecutionTime, "systemExecutionTime"); |
| } |
| |
| 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 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 stdoutStream().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 stderrStream().toByteArray(); |
| } |
| |
| void logThis() { |
| logger.atFiner().log("%s", LazyArgs.lazy(() -> terminationStatus())); |
| |
| if (stdoutStream() == 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 AutoBuilder_CommandResult_Builder(); |
| } |
| |
| /** A builder for {@link CommandResult}s. */ |
| @AutoBuilder |
| 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(); |
| } |
| } |