Get jdk.WORKSPACE into the default WORKSPACE file by reading it as a Java resource, then passing it to the parser as a string instead of putting it into embedded_binaries then passing a Path to it to the parser.

This makes the upcoming default WORKSPACE rules for Android much more palatable. In particular, Android rules won't need to be special cased when building the Bazel binary because the contents are self-contained in BazelRuleClassProvider (and the jdk.WORKSPACE file, which is a simple Java resource)

Even better would be not to use a string, but some kind of structured data, but that's probably more effort than it's worth.

--
MOS_MIGRATED_REVID=95983199
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
index 0a5a8d7..3b40300 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
@@ -40,7 +40,6 @@
 import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
 import com.google.devtools.build.lib.syntax.SkylarkType;
 import com.google.devtools.build.lib.syntax.ValidationEnvironment;
-import com.google.devtools.build.lib.vfs.PathFragment;
 import com.google.devtools.common.options.OptionsClassProvider;
 
 import java.lang.reflect.Constructor;
@@ -76,7 +75,7 @@
    * Builder for {@link ConfiguredRuleClassProvider}.
    */
   public static class Builder implements RuleDefinitionEnvironment {
-    private final List<PathFragment> defaultWorkspaceFiles = new ArrayList<>();
+    private final StringBuilder defaultWorkspaceFile = new StringBuilder();
     private final List<ConfigurationFragmentFactory> configurationFragments = new ArrayList<>();
     private final List<BuildInfoFactory> buildInfoFactories = new ArrayList<>();
     private final List<Class<? extends FragmentOptions>> configurationOptions = new ArrayList<>();
@@ -93,8 +92,8 @@
     private PrerequisiteValidator prerequisiteValidator;
     private ImmutableMap<String, SkylarkType> skylarkAccessibleJavaClasses = ImmutableMap.of();
 
-    public void addWorkspaceFile(PathFragment defaultWorkspace) {
-      defaultWorkspaceFiles.add(defaultWorkspace);
+    public void addWorkspaceFile(String contents) {
+      defaultWorkspaceFile.append(contents);
     }
 
     public Builder setPrerequisiteValidator(PrerequisiteValidator prerequisiteValidator) {
@@ -200,7 +199,7 @@
       return new ConfiguredRuleClassProvider(
           ImmutableMap.copyOf(ruleClassMap),
           ImmutableMap.copyOf(ruleDefinitionMap),
-          ImmutableList.copyOf(defaultWorkspaceFiles),
+          defaultWorkspaceFile.toString(),
           ImmutableList.copyOf(buildInfoFactories),
           ImmutableList.copyOf(configurationOptions),
           ImmutableList.copyOf(configurationFragments),
@@ -235,7 +234,7 @@
    * A list of relative paths to the WORKSPACE files needed to provide external dependencies for
    * the rule classes.
    */
-  private ImmutableList<PathFragment> defaultWorkspaceFiles;
+  String defaultWorkspaceFile;
 
   /**
    * Maps rule class name to the metaclass instance for that rule.
@@ -273,7 +272,7 @@
   public ConfiguredRuleClassProvider(
       ImmutableMap<String, RuleClass> ruleClassMap,
       ImmutableMap<String, Class<? extends RuleDefinition>> ruleDefinitionMap,
-      ImmutableList<PathFragment> defaultWorkspaceFiles,
+      String defaultWorkspaceFile,
       ImmutableList<BuildInfoFactory> buildInfoFactories,
       ImmutableList<Class<? extends FragmentOptions>> configurationOptions,
       ImmutableList<ConfigurationFragmentFactory> configurationFragments,
@@ -283,7 +282,7 @@
 
     this.ruleClassMap = ruleClassMap;
     this.ruleDefinitionMap = ruleDefinitionMap;
-    this.defaultWorkspaceFiles = defaultWorkspaceFiles;
+    this.defaultWorkspaceFile = defaultWorkspaceFile;
     this.buildInfoFactories = buildInfoFactories;
     this.configurationOptions = configurationOptions;
     this.configurationFragments = configurationFragments;
@@ -376,7 +375,7 @@
   }
 
   @Override
-  public List<PathFragment> getWorkspaceFiles() {
-    return defaultWorkspaceFiles;
+  public String getDefaultWorkspaceFile() {
+    return defaultWorkspaceFile;
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
index 8b04543..e15ed20 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
@@ -105,6 +105,9 @@
 import com.google.devtools.build.lib.rules.workspace.BindRule;
 import com.google.devtools.build.lib.syntax.Label;
 import com.google.devtools.build.lib.syntax.SkylarkType;
+import com.google.devtools.build.lib.util.ResourceFileLoader;
+
+import java.io.IOException;
 
 /**
  * A rule class provider implementing the rules Bazel knows.
@@ -253,7 +256,13 @@
     builder.addRuleDefinition(new BazelPyBinaryRule());
     builder.addRuleDefinition(new BazelPyTestRule());
 
-    builder.addWorkspaceFile(BazelJavaRuleClasses.getDefaultWorkspace());
+    try {
+      builder.addWorkspaceFile(
+          ResourceFileLoader.loadResource(BazelJavaRuleClasses.class, "jdk.WORKSPACE"));
+    } catch (IOException e) {
+      throw new IllegalStateException(e);
+    }
+
     builder.addRuleDefinition(new BazelJavaRuleClasses.BaseJavaBinaryRule());
     builder.addRuleDefinition(new BazelJavaRuleClasses.IjarBaseRule());
     builder.addRuleDefinition(new BazelJavaRuleClasses.JavaBaseRule());
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
index eac26d8..00fe3c9 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
@@ -39,7 +39,6 @@
 import com.google.devtools.build.lib.packages.TriState;
 import com.google.devtools.build.lib.rules.java.JavaSemantics;
 import com.google.devtools.build.lib.util.FileTypeSet;
-import com.google.devtools.build.lib.vfs.PathFragment;
 
 import java.util.Set;
 
@@ -346,12 +345,4 @@
           .build();
     }
   }
-
-  /**
-   * Returns the relative path to the WORKSPACE file describing the external dependencies necessary
-   * for the Java rules.
-   */
-  public static PathFragment getDefaultWorkspace() {
-    return new PathFragment("jdk.WORKSPACE");
-  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/jdk.WORKSPACE b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/jdk.WORKSPACE
new file mode 100644
index 0000000..5766f2d
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/jdk.WORKSPACE
@@ -0,0 +1,58 @@
+# External dependencies for the java_* rules.
+
+new_local_repository(
+    name = "local-jdk",
+    path = DEFAULT_SERVER_JAVABASE,
+    build_file = __embedded_dir__ + "/jdk.BUILD",
+)
+
+bind(
+    name = "bootclasspath",
+    actual = "@local-jdk//:bootclasspath",
+)
+bind(
+    name = "extdir",
+    actual = "@local-jdk//:extdir",
+)
+bind(
+    name = "langtools",
+    actual = "@local-jdk//:langtools",
+)
+bind(
+    name = "langtools-neverlink",
+    actual = "@local-jdk//:langtools-neverlink",
+)
+bind(
+    name = "jni_header",
+    actual = "@local-jdk//:jni_header",
+)
+
+bind(
+    name = "jni_md_header-darwin",
+    actual = "@local-jdk//:jni_md_header-darwin",
+)
+
+bind(
+    name = "jni_md_header-linux",
+    actual = "@local-jdk//:jni_md_header-linux",
+)
+
+bind(
+    name = "java",
+    actual = "@local-jdk//:java",
+)
+
+bind(
+    name = "jar",
+    actual = "@local-jdk//:jar",
+)
+
+bind(
+    name = "javac",
+    actual = "@local-jdk//:javac",
+)
+
+bind(
+    name = "jdk-default",
+    actual = "@local-jdk//:jdk-default",
+)
diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java
index 1f9f25c..6781d56 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java
@@ -17,9 +17,7 @@
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
 import com.google.devtools.build.lib.syntax.ValidationEnvironment;
-import com.google.devtools.build.lib.vfs.PathFragment;
 
-import java.util.List;
 import java.util.Map;
 
 /**
@@ -45,9 +43,10 @@
   ValidationEnvironment getSkylarkValidationEnvironment();
 
   /**
-   * Returns paths to the WORKSPACE files needed to provide external dependencies for built-in
-   * rules.  The PathFragments are relative to Bazel's install directory. Returns an empty list if
-   * there are none defined.
+   * Returns the default content of the WORKSPACE file.
+   *
+   * <p>Used to provide external dependencies for built-in rules. Rules defined here can be
+   * overwritten in the WORKSPACE file in the actual workspace.
    */
-  List<PathFragment> getWorkspaceFiles();
+  String getDefaultWorkspaceFile();
 }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index a4fde59..5f6963e 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -323,7 +323,9 @@
         configurationFactory, configurationPackages));
     map.put(SkyFunctions.CONFIGURATION_FRAGMENT, new ConfigurationFragmentFunction(
         configurationFragments, configurationPackages));
-    map.put(SkyFunctions.WORKSPACE_FILE, new WorkspaceFileFunction(pkgFactory, directories));
+    map.put(
+        SkyFunctions.WORKSPACE_FILE,
+        new WorkspaceFileFunction(ruleClassProvider, pkgFactory, directories));
     map.put(SkyFunctions.TARGET_COMPLETION, new TargetCompletionFunction(eventBus));
     map.put(SkyFunctions.TEST_COMPLETION, new TestCompletionFunction());
     map.put(SkyFunctions.ARTIFACT, new ArtifactFunction(allowedMissingInputs));
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunction.java
index ea54ef0..cab94da 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunction.java
@@ -27,6 +27,7 @@
 import com.google.devtools.build.lib.packages.Package.NameConflictException;
 import com.google.devtools.build.lib.packages.PackageFactory;
 import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClassProvider;
 import com.google.devtools.build.lib.packages.RuleFactory;
 import com.google.devtools.build.lib.packages.Type.ConversionException;
 import com.google.devtools.build.lib.syntax.BaseFunction;
@@ -49,7 +50,6 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.util.List;
 import java.util.Map;
 
 /**
@@ -61,10 +61,15 @@
 
   private final PackageFactory packageFactory;
   private final Path installDir;
+  private final RuleClassProvider ruleClassProvider;
 
-  WorkspaceFileFunction(PackageFactory packageFactory, BlazeDirectories directories) {
+  WorkspaceFileFunction(
+      RuleClassProvider ruleClassProvider,
+      PackageFactory packageFactory,
+      BlazeDirectories directories) {
     this.packageFactory = packageFactory;
     this.installDir = directories.getEmbeddedBinariesRoot();
+    this.ruleClassProvider = ruleClassProvider;
   }
 
   @Override
@@ -78,18 +83,19 @@
 
     Path repoWorkspace = workspaceRoot.getRoot().getRelative(workspaceRoot.getRelativePath());
     Builder builder = new Builder(repoWorkspace);
-    List<PathFragment> workspaceFiles = packageFactory.getRuleClassProvider().getWorkspaceFiles();
-    for (PathFragment workspaceFile : workspaceFiles) {
-      workspaceRoot = RootedPath.toRootedPath(installDir, workspaceFile);
-      if (env.getValue(FileValue.key(workspaceRoot)) == null) {
-        return null;
-      }
-      parseWorkspaceFile(installDir.getRelative(workspaceFile), builder);
-    }
+    parseWorkspaceFile(
+        ParserInputSource.create(
+            ruleClassProvider.getDefaultWorkspaceFile(), new PathFragment("DEFAULT.WORKSPACE")),
+        builder);
     if (!workspaceFileValue.exists()) {
       return new PackageValue(builder.build());
     }
-    parseWorkspaceFile(repoWorkspace, builder);
+    try {
+      ParserInputSource repoWorkspaceSource = ParserInputSource.create(repoWorkspace);
+      parseWorkspaceFile(repoWorkspaceSource, builder);
+    } catch (IOException e) {
+      throw new WorkspaceFileFunctionException(e, Transience.TRANSIENT);
+    }
     try {
       builder.resolveBindTargets(packageFactory.getRuleClass(BIND));
     } catch (NoSuchBindingException e) {
@@ -102,24 +108,16 @@
     return new PackageValue(builder.build());
   }
 
-  private void parseWorkspaceFile(Path workspaceFilePath, Builder builder)
+  private void parseWorkspaceFile(ParserInputSource source, Builder builder)
       throws WorkspaceFileFunctionException, InterruptedException {
     StoredEventHandler localReporter = new StoredEventHandler();
     BuildFileAST buildFileAST;
-    ParserInputSource inputSource = null;
-
-    try {
-      inputSource = ParserInputSource.create(workspaceFilePath);
-    } catch (IOException e) {
-      throw new WorkspaceFileFunctionException(e, Transience.TRANSIENT);
-    }
-    buildFileAST = BuildFileAST.parseBuildFile(inputSource, localReporter, null, false);
+    buildFileAST = BuildFileAST.parseBuildFile(source, localReporter, null, false);
     if (buildFileAST.containsErrors()) {
       localReporter.handle(Event.error("WORKSPACE file could not be parsed"));
     } else {
       if (!evaluateWorkspaceFile(buildFileAST, builder, localReporter)) {
-        localReporter.handle(
-            Event.error("Error evaluating WORKSPACE file " + workspaceFilePath));
+        localReporter.handle(Event.error("Error evaluating WORKSPACE file " + source.getPath()));
       }
     }