// 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 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 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 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 the user execution time. */ public Builder setUserExecutionTime(Duration userExecutionTime) { setUserExecutionTime(Optional.of(userExecutionTime)); return this; } /** Sets the system execution time. */ public Builder setSystemExecutionTime(Duration systemExecutionTime) { setSystemExecutionTime(Optional.of(systemExecutionTime)); return this; } /** Sets or clears the wall execution time. */ public abstract Builder setWallExecutionTime(Optional wallExecutionTime); /** Sets or clears the user execution time. */ public abstract Builder setUserExecutionTime(Optional userExecutionTime); /** Sets or clears the system execution time. */ public abstract Builder setSystemExecutionTime(Optional systemExecutionTime); /** Builds a {@link CommandResult} object. */ public abstract CommandResult build(); } }