Short-circuit runfiles tree creation if runfiles are disabled (for example, on Windows by default)

--
MOS_MIGRATED_REVID=129319018
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java b/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java
index 61ac369..fe06afb 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RunfilesSupport.java
@@ -28,7 +28,6 @@
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
 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;
@@ -311,7 +310,6 @@
                 artifactsMiddleman,
                 outputManifest,
                 /*filesetTree=*/ false,
-                config.getShExecutable(),
                 config.getLocalShellEnvironment(),
                 config.runfilesEnabled()));
     return outputManifest;
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/SymlinkTreeAction.java b/src/main/java/com/google/devtools/build/lib/analysis/SymlinkTreeAction.java
index ef2fde9..56b5455 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/SymlinkTreeAction.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/SymlinkTreeAction.java
@@ -25,8 +25,6 @@
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.util.Fingerprint;
 import com.google.devtools.build.lib.util.Preconditions;
-import com.google.devtools.build.lib.vfs.PathFragment;
-
 import javax.annotation.Nullable;
 
 /**
@@ -41,7 +39,6 @@
   private final Artifact inputManifest;
   private final Artifact outputManifest;
   private final boolean filesetTree;
-  private final PathFragment shExecutable;
   private final ImmutableMap<String, String> shellEnviroment;
   private final boolean enableRunfiles;
 
@@ -64,7 +61,6 @@
       @Nullable Artifact artifactMiddleman,
       Artifact outputManifest,
       boolean filesetTree,
-      PathFragment shExecutable,
       ImmutableMap<String, String> shellEnvironment,
       boolean enableRunfiles) {
     super(owner, computeInputs(inputManifest, artifactMiddleman), ImmutableList.of(outputManifest));
@@ -72,7 +68,6 @@
     this.inputManifest = inputManifest;
     this.outputManifest = outputManifest;
     this.filesetTree = filesetTree;
-    this.shExecutable = shExecutable;
     this.shellEnviroment = shellEnvironment;
     this.enableRunfiles = enableRunfiles;
   }
@@ -131,7 +126,6 @@
     actionExecutionContext
         .getExecutor()
         .getContext(SymlinkTreeActionContext.class)
-        .createSymlinks(
-            this, actionExecutionContext, shExecutable, shellEnviroment, enableRunfiles);
+        .createSymlinks(this, actionExecutionContext, shellEnviroment, enableRunfiles);
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/SymlinkTreeActionContext.java b/src/main/java/com/google/devtools/build/lib/analysis/SymlinkTreeActionContext.java
index 11c1417..db5d649 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/SymlinkTreeActionContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/SymlinkTreeActionContext.java
@@ -17,7 +17,6 @@
 import com.google.devtools.build.lib.actions.ActionExecutionContext;
 import com.google.devtools.build.lib.actions.ActionExecutionException;
 import com.google.devtools.build.lib.actions.Executor.ActionContext;
-import com.google.devtools.build.lib.vfs.PathFragment;
 
 /**
  * Action context for symlink tree actions (an action that creates a tree of symlinks).
@@ -30,7 +29,6 @@
   void createSymlinks(
       SymlinkTreeAction action,
       ActionExecutionContext actionExecutionContext,
-      PathFragment shExecutable,
       ImmutableMap<String, String> shellEnvironment,
       boolean enableRunfiles)
       throws ActionExecutionException, InterruptedException;
diff --git a/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeHelper.java b/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeHelper.java
index a98be78..c5a70c6 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeHelper.java
@@ -24,19 +24,16 @@
 import com.google.devtools.build.lib.actions.ResourceManager;
 import com.google.devtools.build.lib.actions.ResourceManager.ResourceHandle;
 import com.google.devtools.build.lib.actions.ResourceSet;
+import com.google.devtools.build.lib.actions.UserExecException;
 import com.google.devtools.build.lib.analysis.config.BinTools;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.shell.CommandException;
 import com.google.devtools.build.lib.util.CommandBuilder;
-import com.google.devtools.build.lib.util.OS;
 import com.google.devtools.build.lib.util.OsUtils;
-import com.google.devtools.build.lib.vfs.FileSystem;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
-import com.google.devtools.build.lib.vfs.UnixFileSystem;
-import com.google.devtools.build.lib.vfs.UnixFileSystem.SymlinkStrategy;
-import com.google.devtools.build.lib.vfs.WindowsFileSystem;
-
+import java.io.IOException;
 import java.util.List;
 
 /**
@@ -55,8 +52,8 @@
    */
   public static final ResourceSet RESOURCE_SET = ResourceSet.createWithRamCpuIo(1000, 0.5, 0.75);
 
-  private final PathFragment inputManifest;
-  private final PathFragment symlinkTreeRoot;
+  private final Path inputManifest;
+  private final Path symlinkTreeRoot;
   private final boolean filesetTree;
 
   /**
@@ -64,18 +61,20 @@
    * SymlinkTreeAction.
    *
    * @param inputManifest exec path to the input runfiles manifest
-   * @param symlinkTreeRoot exec path to the symlink tree location
+   * @param symlinkTreeRoot the root of the symlink tree to be created
    * @param filesetTree true if this is fileset symlink tree,
    *                    false if this is a runfiles symlink tree.
    */
-  public SymlinkTreeHelper(PathFragment inputManifest, PathFragment symlinkTreeRoot,
+  public SymlinkTreeHelper(Path inputManifest, Path symlinkTreeRoot,
       boolean filesetTree) {
     this.inputManifest = inputManifest;
     this.symlinkTreeRoot = symlinkTreeRoot;
     this.filesetTree = filesetTree;
   }
 
-  public PathFragment getSymlinkTreeRoot() { return symlinkTreeRoot; }
+  public Path getOutputManifest() {
+    return symlinkTreeRoot;
+  }
 
   /**
    * Creates a symlink tree using a CommandBuilder. This means that the symlink
@@ -90,9 +89,7 @@
    */
   public void createSymlinksUsingCommand(Path execRoot,
       BuildConfiguration config, BinTools binTools) throws CommandException {
-    List<String> argv =
-        getSpawnArgumentList(
-            execRoot, binTools, config.getShExecutable(), config.runfilesEnabled());
+    List<String> argv = getSpawnArgumentList(execRoot, binTools);
 
     CommandBuilder builder = new CommandBuilder();
     builder.addArgs(argv);
@@ -110,47 +107,44 @@
    * preserved.
    * @param action action instance that requested symlink tree creation
    * @param actionExecutionContext Services that are in the scope of the action.
-   * @param shExecutable
    * @param enableRunfiles
    */
   public void createSymlinks(
       AbstractAction action,
       ActionExecutionContext actionExecutionContext,
       BinTools binTools,
-      PathFragment shExecutable,
       ImmutableMap<String, String> shellEnvironment,
       boolean enableRunfiles)
       throws ExecException, InterruptedException {
-    List<String> args =
-        getSpawnArgumentList(
-            actionExecutionContext.getExecutor().getExecRoot(),
-            binTools,
-            shExecutable,
-            enableRunfiles);
-    try (ResourceHandle handle =
-        ResourceManager.instance().acquireResources(action, RESOURCE_SET)) {
-      actionExecutionContext.getExecutor().getSpawnActionContext(action.getMnemonic()).exec(
-          new BaseSpawn.Local(args, shellEnvironment, action),
-          actionExecutionContext);
+    if (enableRunfiles) {
+      List<String> args =
+          getSpawnArgumentList(
+              actionExecutionContext.getExecutor().getExecRoot(), binTools);
+      try (ResourceHandle handle =
+               ResourceManager.instance().acquireResources(action, RESOURCE_SET)) {
+        actionExecutionContext.getExecutor().getSpawnActionContext(action.getMnemonic()).exec(
+            new BaseSpawn.Local(args, shellEnvironment, action),
+            actionExecutionContext);
+      }
+    } else {
+      // Pretend we created the runfiles tree by copying the manifest
+      try {
+        FileSystemUtils.createDirectoryAndParents(symlinkTreeRoot);
+        FileSystemUtils.copyFile(inputManifest, symlinkTreeRoot.getChild("MANIFEST"));
+      } catch (IOException e) {
+        throw new UserExecException(e.getMessage(), e);
+      }
     }
   }
 
   /**
    * Returns the complete argument list build-runfiles has to be called with.
    */
-  private List<String> getSpawnArgumentList(
-      Path execRoot, BinTools binTools, PathFragment shExecutable, boolean enableRunfiles) {
+  private List<String> getSpawnArgumentList(Path execRoot, BinTools binTools) {
     PathFragment path = binTools.getExecPath(BUILD_RUNFILES);
     Preconditions.checkNotNull(path, BUILD_RUNFILES + " not found in embedded tools");
 
     List<String> args = Lists.newArrayList();
-    if (OS.getCurrent() == OS.WINDOWS) {
-      // During bootstrapping, build-runfiles is a shell script, that cannot be directly
-      // executed on Windows, so we shell out.
-      args.add(shExecutable.getPathString());
-      args.add("-c");
-      args.add("$0 $*");
-    }
     args.add(execRoot.getRelative(path).getPathString());
 
     if (filesetTree) {
@@ -158,19 +152,8 @@
       args.add("--use_metadata");
     }
 
-    FileSystem fs = execRoot.getFileSystem();
-    if ((fs instanceof WindowsFileSystem)
-        || (fs instanceof UnixFileSystem
-            && ((UnixFileSystem) fs).getSymlinkStrategy() == SymlinkStrategy.WINDOWS_COMPATIBLE)) {
-      args.add("--windows_compatible");
-    }
-
-    if (!enableRunfiles) {
-      args.add("--manifest_only");
-    }
-
-    args.add(inputManifest.getPathString());
-    args.add(symlinkTreeRoot.getPathString());
+    args.add(inputManifest.relativeTo(execRoot).getPathString());
+    args.add(symlinkTreeRoot.relativeTo(execRoot).getPathString());
 
     return args;
   }
diff --git a/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeStrategy.java b/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeStrategy.java
index dc54714..b79b910 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeStrategy.java
@@ -23,8 +23,6 @@
 import com.google.devtools.build.lib.analysis.SymlinkTreeActionContext;
 import com.google.devtools.build.lib.analysis.config.BinTools;
 import com.google.devtools.build.lib.profiler.AutoProfiler;
-import com.google.devtools.build.lib.vfs.PathFragment;
-
 import java.util.logging.Logger;
 
 /**
@@ -47,7 +45,6 @@
   public void createSymlinks(
       SymlinkTreeAction action,
       ActionExecutionContext actionExecutionContext,
-      PathFragment shExecutable,
       ImmutableMap<String, String> shellEnvironment,
       boolean enableRunfiles)
       throws ActionExecutionException, InterruptedException {
@@ -57,18 +54,18 @@
                 "running " + action.prettyPrint(), LOG, /*minTimeForLoggingInMilliseconds=*/ 100)) {
       try {
         SymlinkTreeHelper helper = new SymlinkTreeHelper(
-            action.getInputManifest().getExecPath(),
-            action.getOutputManifest().getExecPath().getParentDirectory(), action.isFilesetTree());
+            action.getInputManifest().getPath(),
+            action.getOutputManifest().getPath().getParentDirectory(), action.isFilesetTree());
         if (outputService != null && outputService.canCreateSymlinkTree()) {
           outputService.createSymlinkTree(action.getInputManifest().getPath(),
               action.getOutputManifest().getPath(),
-              action.isFilesetTree(), helper.getSymlinkTreeRoot());
+              action.isFilesetTree(),
+              action.getOutputManifest().getExecPath().getParentDirectory());
         } else {
           helper.createSymlinks(
               action,
               actionExecutionContext,
               binTools,
-              shExecutable,
               shellEnvironment,
               enableRunfiles);
         }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/NativeLibs.java b/src/main/java/com/google/devtools/build/lib/rules/android/NativeLibs.java
index fc736ae..46446d2 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/NativeLibs.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/NativeLibs.java
@@ -168,7 +168,6 @@
             nativeLibsMiddleman,
             outputManifest,
             false,
-            ruleContext.getConfiguration().getShExecutable(),
             ruleContext.getConfiguration().getLocalShellEnvironment(),
             ruleContext.getConfiguration().runfilesEnabled()));
     return outputManifest;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java b/src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java
index acce97a..f2af631 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java
@@ -75,7 +75,6 @@
               action,
               actionExecutionContext,
               binTools,
-              action.getShExecutable(),
               action.getLocalShellEnvironment(),
               action.isEnableRunfiles());
     } catch (ExecException e) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/TestStrategy.java b/src/main/java/com/google/devtools/build/lib/rules/test/TestStrategy.java
index 68cefe1..1bbd5c7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/TestStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/test/TestStrategy.java
@@ -42,7 +42,6 @@
 import com.google.devtools.common.options.EnumConverter;
 import com.google.devtools.common.options.OptionsClassProvider;
 import com.google.devtools.common.options.OptionsParsingException;
-
 import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
@@ -53,7 +52,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
-
 import javax.annotation.Nullable;
 
 /**
@@ -356,7 +354,6 @@
       TestRunnerAction testAction,
       ActionExecutionContext actionExecutionContext,
       BinTools binTools,
-      PathFragment shExecutable,
       ImmutableMap<String, String> shellEnvironment,
       boolean enableRunfiles)
       throws ExecException, InterruptedException {
@@ -386,7 +383,6 @@
           runfilesDir,
           actionExecutionContext,
           binTools,
-          shExecutable,
           shellEnvironment,
           enableRunfiles);
     }
@@ -405,7 +401,6 @@
       Path runfilesDir,
       ActionExecutionContext actionExecutionContext,
       BinTools binTools,
-      PathFragment shExecutable,
       ImmutableMap<String, String> shellEnvironment,
       boolean enableRunfiles)
       throws ExecException, InterruptedException {
@@ -427,14 +422,13 @@
         "Building runfiles directory for '" + execSettings.getExecutable().prettyPrint() + "'."));
 
     new SymlinkTreeHelper(
-            execSettings.getInputManifest().getExecPath(),
-            runfilesDir.relativeTo(executor.getExecRoot()), /* filesetTree= */
+            execSettings.getInputManifest().getPath(),
+            runfilesDir,
             false)
         .createSymlinks(
             testAction,
             actionExecutionContext,
             binTools,
-            shExecutable,
             shellEnvironment,
             enableRunfiles);
 
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/RunCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/RunCommand.java
index 7cdfc0d..26dda27 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/RunCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/RunCommand.java
@@ -63,7 +63,6 @@
 import com.google.devtools.common.options.OptionsBase;
 import com.google.devtools.common.options.OptionsParser;
 import com.google.devtools.common.options.OptionsProvider;
-
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
@@ -374,8 +373,8 @@
     }
 
     SymlinkTreeHelper helper = new SymlinkTreeHelper(
-        manifest.getExecPath(),
-        runfilesDir,
+        manifest.getPath(),
+        runfilesSupport.getRunfilesDirectory(),
         false);
     helper.createSymlinksUsingCommand(env.getExecRoot(), target.getConfiguration(),
         env.getBlazeWorkspace().getBinTools());