Update from Google.

--
MOE_MIGRATED_REVID=85702957
diff --git a/src/main/java/com/google/devtools/build/lib/actions/BaseSpawn.java b/src/main/java/com/google/devtools/build/lib/actions/BaseSpawn.java
new file mode 100644
index 0000000..dd879c2
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/actions/BaseSpawn.java
@@ -0,0 +1,214 @@
+// Copyright 2014 Google Inc. 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.actions;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.extra.EnvironmentVariable;
+import com.google.devtools.build.lib.actions.extra.SpawnInfo;
+import com.google.devtools.build.lib.util.CommandDescriptionForm;
+import com.google.devtools.build.lib.util.CommandFailureUtils;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.vfs.PathFragment;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+/**
+ * Base implementation of a Spawn.
+ */
+@Immutable
+public class BaseSpawn implements Spawn {
+  private final ImmutableList<String> arguments;
+  private final ImmutableMap<String, String> environment;
+  private final ImmutableMap<String, String> executionInfo;
+  private final ImmutableMap<PathFragment, Artifact> runfilesManifests;
+  private final ActionMetadata action;
+  private final ResourceSet localResources;
+
+  /**
+   * Returns a new Spawn. The caller must not modify the parameters after the call; neither will
+   * this method.
+   */
+  public BaseSpawn(List<String> arguments,
+      Map<String, String> environment,
+      Map<String, String> executionInfo,
+      Map<PathFragment, Artifact> runfilesManifests,
+      ActionMetadata action,
+      ResourceSet localResources) {
+    this.arguments = ImmutableList.copyOf(arguments);
+    this.environment = ImmutableMap.copyOf(environment);
+    this.executionInfo = ImmutableMap.copyOf(executionInfo);
+    this.runfilesManifests = ImmutableMap.copyOf(runfilesManifests);
+    this.action = action;
+    this.localResources = localResources;
+  }
+
+  /**
+   * Returns a new Spawn.
+   */
+  public BaseSpawn(List<String> arguments,
+      Map<String, String> environment,
+      Map<String, String> executionInfo,
+      // TODO(bazel-team): have this always be non-null.
+      @Nullable Artifact runfilesManifest,
+      ActionMetadata action,
+      ResourceSet localResources) {
+    this(arguments, environment, executionInfo,
+        ((runfilesManifest != null)
+            ? ImmutableMap.of(runfilesForFragment(new PathFragment(arguments.get(0))),
+            runfilesManifest)
+            : ImmutableMap.<PathFragment, Artifact>of()),
+        action, localResources);
+  }
+
+  public static PathFragment runfilesForFragment(PathFragment pathFragment) {
+    return pathFragment.getParentDirectory().getChild(pathFragment.getBaseName() + ".runfiles");
+  }
+
+  /**
+   * Returns a new Spawn.
+   */
+  public BaseSpawn(List<String> arguments,
+      Map<String, String> environment,
+      Map<String, String> executionInfo,
+      ActionMetadata action,
+      ResourceSet localResources) {
+    this(arguments, environment, executionInfo,
+        ImmutableMap.<PathFragment, Artifact>of(), action, localResources);
+  }
+
+  @Override
+  public boolean isRemotable() {
+    return !executionInfo.containsKey("local");
+  }
+
+  @Override
+  public final ImmutableMap<String, String> getExecutionInfo() {
+    return executionInfo;
+  }
+
+  @Override
+  public String asShellCommand(Path workingDir) {
+    return asShellCommand(getArguments(), workingDir, getEnvironment());
+  }
+
+  @Override
+  public ImmutableMap<PathFragment, Artifact> getRunfilesManifests() {
+    return runfilesManifests;
+  }
+
+  @Override
+  public ImmutableList<Artifact> getFilesetManifests() {
+    return ImmutableList.<Artifact>of();
+  }
+
+  @Override
+  public SpawnInfo getExtraActionInfo() {
+    SpawnInfo.Builder info = SpawnInfo.newBuilder();
+
+    info.addAllArgument(getArguments());
+    for (Map.Entry<String, String> variable : getEnvironment().entrySet()) {
+      info.addVariable(EnvironmentVariable.newBuilder()
+        .setName(variable.getKey())
+        .setValue(variable.getValue()).build());
+    }
+    for (ActionInput input : getInputFiles()) {
+      // Explicitly ignore middleman artifacts here.
+      if (!(input instanceof Artifact) || !((Artifact) input).isMiddlemanArtifact()) {
+        info.addInputFile(input.getExecPathString());
+      }
+    }
+    info.addAllOutputFile(ActionInputHelper.toExecPaths(getOutputFiles()));
+    return info.build();
+  }
+
+  @Override
+  public ImmutableList<String> getArguments() {
+    // TODO(bazel-team): this method should be final, as the correct value of the args can be
+    // injected in the ctor.
+    return arguments;
+  }
+
+  @Override
+  public ImmutableMap<String, String> getEnvironment() {
+    if (getRunfilesManifests().size() != 1) {
+      return environment;
+    }
+
+    ImmutableMap.Builder<String, String> env = ImmutableMap.builder();
+    env.putAll(environment);
+    for (Map.Entry<PathFragment, Artifact> e : getRunfilesManifests().entrySet()) {
+      // TODO(bazel-team): Unify these into a single env variable.
+      env.put("JAVA_RUNFILES", e.getKey().getPathString() + "/");
+      env.put("PYTHON_RUNFILES", e.getKey().getPathString() + "/");
+    }
+    return env.build();
+  }
+
+  @Override
+  public Iterable<? extends ActionInput> getInputFiles() {
+    return action.getInputs();
+  }
+
+  @Override
+  public Collection<? extends ActionInput> getOutputFiles() {
+    return action.getOutputs();
+  }
+
+  @Override
+  public ActionMetadata getResourceOwner() {
+    return action;
+  }
+
+  @Override
+  public ResourceSet getLocalResources() {
+    return localResources;
+  }
+
+  @Override
+  public ActionOwner getOwner() { return action.getOwner(); }
+
+  @Override
+  public String getMnemonic() { return action.getMnemonic(); }
+
+  /**
+   * Convert a working dir + environment map + arg list into a Bourne shell
+   * command.
+   */
+  public static String asShellCommand(Collection<String> arguments,
+                                      Path workingDirectory,
+                                      Map<String, String> environment) {
+    // We print this command out in such a way that it can safely be
+    // copied+pasted as a Bourne shell command.  This is extremely valuable for
+    // debugging.
+    return CommandFailureUtils.describeCommand(CommandDescriptionForm.COMPLETE,
+        arguments, environment, workingDirectory.getPathString());
+  }
+
+  /**
+   * A local spawn requiring zero resources.
+   */
+  public static class Local extends BaseSpawn {
+    public Local(List<String> arguments, Map<String, String> environment, ActionMetadata action) {
+      super(arguments, environment, ImmutableMap.<String, String>of("local", ""),
+          action, ResourceSet.ZERO);
+    }
+  }
+}