Move Subprocess.Factory to a top-level class

Also move the implementation of FutureCommandResult to a top-level class.

This is in preparation for significantly simplifying the shell library. The
plan is to remove the Subprocess abstraction, and have lower-level
implementations implement the much simpler FutureCommandResult interface
instead.

PiperOrigin-RevId: 167844736
diff --git a/src/main/java/com/google/devtools/build/lib/shell/Command.java b/src/main/java/com/google/devtools/build/lib/shell/Command.java
index 46eefee..291dd32 100644
--- a/src/main/java/com/google/devtools/build/lib/shell/Command.java
+++ b/src/main/java/com/google/devtools/build/lib/shell/Command.java
@@ -358,7 +358,7 @@
     Preconditions.checkNotNull(stdinInput, "stdinInput");
     logCommand();
 
-    final Subprocess process = startProcess();
+    Subprocess process = startProcess();
 
     outErrConsumers.logConsumptionStrategy();
     outErrConsumers.registerInputs(
@@ -369,22 +369,7 @@
     // enforced.
     processInput(stdinInput, process);
 
-    return new FutureCommandResult() {
-      @Override
-      public CommandResult get() throws AbnormalTerminationException {
-        return waitForProcessToComplete(process, outErrConsumers, killSubprocessOnInterrupt);
-      }
-
-      @Override
-      public boolean isDone() {
-        return process.finished();
-      }
-
-      @Override
-      public void cancel() {
-        process.destroy();
-      }
-    };
+    return new FutureCommandResultImpl(this, process, outErrConsumers, killSubprocessOnInterrupt);
   }
 
   private Subprocess startProcess() throws ExecFailedException {
@@ -425,78 +410,6 @@
     }
   }
 
-  private CommandResult waitForProcessToComplete(
-      Subprocess process, Consumers.OutErrConsumers outErr, boolean killSubprocessOnInterrupt)
-          throws AbnormalTerminationException {
-    logger.finer("Waiting for process...");
-
-    TerminationStatus status = waitForProcess(process, killSubprocessOnInterrupt);
-
-    logger.finer(status.toString());
-
-    try {
-      if (Thread.currentThread().isInterrupted()) {
-        outErr.cancel();
-      } else {
-        outErr.waitForCompletion();
-      }
-    } catch (IOException ioe) {
-      CommandResult noOutputResult =
-        new CommandResult(CommandResult.EMPTY_OUTPUT,
-                          CommandResult.EMPTY_OUTPUT,
-                          status);
-      if (status.success()) {
-        // If command was otherwise successful, throw an exception about this
-        throw new AbnormalTerminationException(this, noOutputResult, ioe);
-      } else {
-        // Otherwise, throw the more important exception -- command
-        // was not successful
-        String message = status
-          + "; also encountered an error while attempting to retrieve output";
-        throw status.exited()
-          ? new BadExitStatusException(this, noOutputResult, message, ioe)
-          : new AbnormalTerminationException(this,
-              noOutputResult, message, ioe);
-      }
-    } finally {
-      process.close();
-    }
-
-    CommandResult result =
-        new CommandResult(outErr.getAccumulatedOut(), outErr.getAccumulatedErr(), status);
-    result.logThis();
-    if (status.success()) {
-      return result;
-    } else if (status.exited()) {
-      throw new BadExitStatusException(this, result, status.toString());
-    } else {
-      throw new AbnormalTerminationException(this, result, status.toString());
-    }
-  }
-
-  private static TerminationStatus waitForProcess(
-      Subprocess process, boolean killSubprocessOnInterrupt) {
-    boolean wasInterrupted = false;
-    try {
-      while (true) {
-        try {
-          process.waitFor();
-          return new TerminationStatus(process.exitValue(), process.timedout());
-        } catch (InterruptedException ie) {
-          wasInterrupted = true;
-          if (killSubprocessOnInterrupt) {
-            process.destroy();
-          }
-        }
-      }
-    } finally {
-      // Read this for detailed explanation: http://www.ibm.com/developerworks/library/j-jtp05236/
-      if (wasInterrupted) {
-        Thread.currentThread().interrupt(); // preserve interrupted status
-      }
-    }
-  }
-
   private void logCommand() {
     if (!logger.isLoggable(Level.FINE)) {
       return;