| // 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 java.io.ByteArrayOutputStream; |
| import java.time.Duration; |
| import java.util.Optional; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| /** |
| * Encapsulates the results of a command execution, including exit status and output to stdout and |
| * stderr. |
| */ |
| @AutoValue |
| public abstract class CommandResult { |
| |
| private static final Logger logger = |
| Logger.getLogger("com.google.devtools.build.lib.shell.Command"); |
| |
| 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() { |
| if (!logger.isLoggable(Level.FINER)) { |
| return; |
| } |
| logger.finer(getTerminationStatus().toString()); |
| |
| if (getStdoutStream() == NO_OUTPUT_COLLECTED) { |
| return; |
| } |
| logger.finer("Stdout: " + LogUtil.toTruncatedString(getStdout())); |
| logger.finer("Stderr: " + 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. */ |
| 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. */ |
| 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. */ |
| 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(); |
| } |
| } |