Clone the remote execution implementation into a new class

The new RemoteExecutionClient class only performs remote execution, and
nothing else; all higher-level functions, local rety, etc. will live outside
of the client.

In order to add unit tests, I had to add another layer of indirection between
the Grpc{RemoteExecutor,ActionCache} and GRPC, since GRPC generates final,
non-mockable classes. While a testing approach that uses a fake server can
also get some test coverage (as in GrpcActionCacheTest), it doesn't allow us
to test the full range of bad things that can happen at the GRPC layer.

The cloned implementation uses a single GRPC channel, as was recommended to
me by Jakob, who worked on GRPC. A single channel should be sufficiently
scalable, it's thread-safe, and it performs chunking internally. On the
server-side, the requests from a single channel can be dispatched to a thread
pool, so this should not be a blocker for server-side parallelism.

I also changed it to throw an exception whenever anything bad happens - this
makes it much more obvious if there's still bug in this code; the old code
silently swallows many errors, falling back to local execution, which papers
over many issues.

Furthermore, we now return a RemoteExecutionResult to indicate whether the
action ran at all (regardless of exit code), as well as the exit code.

All in all, this implementation is closer to the production code we're using
internally, although quite a few things are still missing.

The cloned implementation is not hooked up to RemoteSpawnStrategy yet. It
also does not support combining remote caching with local execution, but note
that RemoteSpawnStrategy regressed in that respect and currently also does
not support that mode.

PiperOrigin-RevId: 151578409
diff --git a/src/main/java/com/google/devtools/build/lib/exec/SpawnResult.java b/src/main/java/com/google/devtools/build/lib/exec/SpawnResult.java
new file mode 100644
index 0000000..3951e72d
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/exec/SpawnResult.java
@@ -0,0 +1,79 @@
+// Copyright 2017 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.exec;
+
+import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
+
+/**
+ * The result of a spawn execution.
+ */
+public interface SpawnResult {
+  /**
+   * Returns whether the spawn was actually run, regardless of the exit code. Returns false if there
+   * were network errors, missing local files, errors setting up sandboxing, etc.
+   */
+  boolean setupSuccess();
+
+  /**
+   * The exit code of the subprocess.
+   */
+  int exitCode();
+
+  /**
+   * Basic implementation of {@link SpawnResult}.
+   */
+  @Immutable @ThreadSafe
+  public static final class SimpleSpawnResult implements SpawnResult {
+    private final boolean setupSuccess;
+    private final int exitCode;
+
+    SimpleSpawnResult(Builder builder) {
+      this.setupSuccess = builder.setupSuccess;
+      this.exitCode = builder.exitCode;
+    }
+
+    @Override
+    public boolean setupSuccess() {
+      return setupSuccess;
+    }
+
+    @Override
+    public int exitCode() {
+      return exitCode;
+    }
+  }
+
+  /**
+   * Builder class for {@link SpawnResult}.
+   */
+  public static final class Builder {
+    private boolean setupSuccess;
+    private int exitCode;
+
+    public SpawnResult build() {
+      return new SimpleSpawnResult(this);
+    }
+
+    public Builder setSetupSuccess(boolean setupSuccess) {
+      this.setupSuccess = setupSuccess;
+      return this;
+    }
+
+    public Builder setExitCode(int exitCode) {
+      this.exitCode = exitCode;
+      return this;
+    }
+  }
+}