diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib')
7 files changed, 108 insertions, 45 deletions
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 e84f9aa187..26e0617454 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,6 +40,7 @@ import com.google.devtools.build.lib.syntax.SkylarkEnvironment; import com.google.devtools.build.lib.syntax.SkylarkModule; 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,6 +77,7 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider { * Builder for {@link ConfiguredRuleClassProvider}. */ public static class Builder implements RuleDefinitionEnvironment { + private final List<PathFragment> defaultWorkspaceFiles = new ArrayList<>(); private final List<ConfigurationFragmentFactory> configurationFragments = new ArrayList<>(); private final List<BuildInfoFactory> buildInfoFactories = new ArrayList<>(); private final List<Class<? extends FragmentOptions>> configurationOptions = new ArrayList<>(); @@ -90,6 +92,10 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider { private PrerequisiteValidator prerequisiteValidator; private ImmutableMap<String, SkylarkType> skylarkAccessibleJavaClasses = ImmutableMap.of(); + public void addWorkspaceFile(PathFragment defaultWorkspace) { + defaultWorkspaceFiles.add(defaultWorkspace); + } + public Builder setPrerequisiteValidator(PrerequisiteValidator prerequisiteValidator) { this.prerequisiteValidator = prerequisiteValidator; return this; @@ -194,6 +200,7 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider { return new ConfiguredRuleClassProvider( ImmutableMap.copyOf(ruleClassMap), ImmutableMap.copyOf(ruleDefinitionMap), + ImmutableList.copyOf(defaultWorkspaceFiles), ImmutableList.copyOf(buildInfoFactories), ImmutableList.copyOf(configurationOptions), ImmutableList.copyOf(configurationFragments), @@ -225,6 +232,12 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider { }); /** + * A list of relative paths to the WORKSPACE files needed to provide external dependencies for + * the rule classes. + */ + private ImmutableList<PathFragment> defaultWorkspaceFiles; + + /** * Maps rule class name to the metaclass instance for that rule. */ private final ImmutableMap<String, RuleClass> ruleClassMap; @@ -260,6 +273,7 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider { public ConfiguredRuleClassProvider( ImmutableMap<String, RuleClass> ruleClassMap, ImmutableMap<String, Class<? extends RuleDefinition>> ruleDefinitionMap, + ImmutableList<PathFragment> defaultWorkspaceFiles, ImmutableList<BuildInfoFactory> buildInfoFactories, ImmutableList<Class<? extends FragmentOptions>> configurationOptions, ImmutableList<ConfigurationFragmentFactory> configurationFragments, @@ -269,6 +283,7 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider { this.ruleClassMap = ruleClassMap; this.ruleDefinitionMap = ruleDefinitionMap; + this.defaultWorkspaceFiles = defaultWorkspaceFiles; this.buildInfoFactories = buildInfoFactories; this.configurationOptions = configurationOptions; this.configurationFragments = configurationFragments; @@ -373,4 +388,9 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider { public Object getNativeModule() { return nativeModule; } + + @Override + public List<PathFragment> getWorkspaceFiles() { + return defaultWorkspaceFiles; + } } 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 663b82ac92..f5d928d011 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 @@ -40,6 +40,7 @@ import com.google.devtools.build.lib.packages.RuleClass.PackageNameConstraint; 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; @@ -52,7 +53,7 @@ public class BazelJavaRuleClasses { PackageNameConstraint.ANY_SEGMENT, "java", "javatests"); public static final ImplicitOutputsFunction JAVA_BINARY_IMPLICIT_OUTPUTS = - fromFunctions(JavaSemantics.JAVA_BINARY_CLASS_JAR, JavaSemantics.JAVA_BINARY_SOURCE_JAR, + fromFunctions(JavaSemantics.JAVA_BINARY_CLASS_JAR, JavaSemantics.JAVA_BINARY_SOURCE_JAR, JavaSemantics.JAVA_BINARY_DEPLOY_JAR, JavaSemantics.JAVA_BINARY_DEPLOY_SOURCE_JAR); static final ImplicitOutputsFunction JAVA_LIBRARY_IMPLICIT_OUTPUTS = @@ -170,4 +171,12 @@ public class BazelJavaRuleClasses { .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/packages/ExternalPackage.java b/src/main/java/com/google/devtools/build/lib/packages/ExternalPackage.java index 9c92b338b2..ac4920ce2e 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/ExternalPackage.java +++ b/src/main/java/com/google/devtools/build/lib/packages/ExternalPackage.java @@ -34,6 +34,7 @@ import java.util.Map.Entry; */ public class ExternalPackage extends Package { + private String workspaceName; private Map<RepositoryName, Rule> repositoryMap; ExternalPackage() { @@ -41,6 +42,13 @@ public class ExternalPackage extends Package { } /** + * Returns the name for this repository. + */ + public String getWorkspaceName() { + return workspaceName; + } + + /** * Returns a description of the repository with the given name, or null if there's no such * repository. */ @@ -79,28 +87,37 @@ public class ExternalPackage extends Package { /** * Given a workspace file path, creates an ExternalPackage. */ - public static class ExternalPackageBuilder - extends AbstractBuilder<ExternalPackage, ExternalPackageBuilder> { + public static class Builder + extends AbstractBuilder<ExternalPackage, Builder> { + private String workspaceName; private Map<Label, Binding> bindMap = Maps.newHashMap(); private Map<RepositoryName, Rule> repositoryMap = Maps.newHashMap(); - public ExternalPackageBuilder(Path workspacePath) { + public Builder(Path workspacePath) { super(new ExternalPackage()); setFilename(workspacePath); setMakeEnv(new MakeEnvironment.Builder()); } @Override - protected ExternalPackageBuilder self() { + protected Builder self() { return this; } @Override public ExternalPackage build() { + pkg.workspaceName = workspaceName; pkg.repositoryMap = ImmutableMap.copyOf(repositoryMap); return super.build(); } + /** + * Sets the name for this repository. + */ + public void setWorkspaceName(String name) { + workspaceName = name; + } + public void addBinding(Label label, Binding binding) { bindMap.put(label, binding); } @@ -178,7 +195,7 @@ public class ExternalPackage extends Package { * Creates an external repository rule. * @throws SyntaxException if the repository name is invalid. */ - public ExternalPackageBuilder createAndAddRepositoryRule(RuleClass ruleClass, + public Builder createAndAddRepositoryRule(RuleClass ruleClass, Map<String, Object> kwargs, FuncallExpression ast) throws InvalidRuleException, NameConflictException, SyntaxException { StoredEventHandler eventHandler = new StoredEventHandler(); 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 90fdfca393..07b1b18dd9 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,7 +17,9 @@ package com.google.devtools.build.lib.packages; 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; /** @@ -46,4 +48,11 @@ public interface RuleClassProvider { * Returns the Skylark module to register the native rules with. */ Object getNativeModule(); + + /** + * 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. + */ + List<PathFragment> getWorkspaceFiles(); } diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleFactory.java b/src/main/java/com/google/devtools/build/lib/packages/RuleFactory.java index c79bbaa395..cffef503fe 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/RuleFactory.java +++ b/src/main/java/com/google/devtools/build/lib/packages/RuleFactory.java @@ -23,7 +23,6 @@ import com.google.devtools.build.lib.packages.PackageFactory.PackageContext; import com.google.devtools.build.lib.syntax.FuncallExpression; import com.google.devtools.build.lib.syntax.Label; import com.google.devtools.build.lib.syntax.Label.SyntaxException; -import com.google.devtools.build.lib.vfs.PathFragment; import java.util.Map; import java.util.Set; @@ -106,7 +105,7 @@ public class RuleFactory { throw new InvalidRuleException("illegal rule name: " + name + ": " + e.getMessage()); } boolean inWorkspaceFile = location.getPath() != null - && location.getPath().endsWith(new PathFragment("WORKSPACE")); + && location.getPath().getBaseName().contains("WORKSPACE"); if (ruleClass.getWorkspaceOnly() && !inWorkspaceFile) { throw new RuleFactory.InvalidRuleException(ruleClass + " must be in the WORKSPACE file " + "(used by " + label + ")"); 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 a30b5c7343..b7d638528d 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 @@ -303,7 +303,7 @@ public abstract class SkyframeExecutor { configurationFactory, clientEnv, configurationPackages)); map.put(SkyFunctions.CONFIGURATION_FRAGMENT, new ConfigurationFragmentFunction( configurationFragments, configurationPackages)); - map.put(SkyFunctions.WORKSPACE_FILE, new WorkspaceFileFunction(pkgFactory)); + map.put(SkyFunctions.WORKSPACE_FILE, new WorkspaceFileFunction(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 f518b8a388..89126cb73d 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 @@ -17,12 +17,14 @@ package com.google.devtools.build.lib.skyframe; import static com.google.devtools.build.lib.syntax.Environment.NONE; import com.google.common.collect.ImmutableList; +import com.google.devtools.build.lib.analysis.BlazeDirectories; import com.google.devtools.build.lib.cmdline.LabelValidator; import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.StoredEventHandler; +import com.google.devtools.build.lib.packages.ExternalPackage; import com.google.devtools.build.lib.packages.ExternalPackage.Binding; -import com.google.devtools.build.lib.packages.ExternalPackage.ExternalPackageBuilder; -import com.google.devtools.build.lib.packages.ExternalPackage.ExternalPackageBuilder.NoSuchBindingException; +import com.google.devtools.build.lib.packages.ExternalPackage.Builder; +import com.google.devtools.build.lib.packages.ExternalPackage.Builder.NoSuchBindingException; 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; @@ -39,6 +41,7 @@ import com.google.devtools.build.lib.syntax.Label.SyntaxException; import com.google.devtools.build.lib.syntax.MixedModeFunction; import com.google.devtools.build.lib.syntax.ParserInputSource; import com.google.devtools.build.lib.vfs.Path; +import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.lib.vfs.RootedPath; import com.google.devtools.build.skyframe.SkyFunction; import com.google.devtools.build.skyframe.SkyFunctionException; @@ -58,22 +61,46 @@ public class WorkspaceFileFunction implements SkyFunction { private static final String BIND = "bind"; private final PackageFactory packageFactory; + private final Path installDir; - WorkspaceFileFunction(PackageFactory packageFactory) { + WorkspaceFileFunction(PackageFactory packageFactory, BlazeDirectories directories) { this.packageFactory = packageFactory; + this.installDir = directories.getEmbeddedBinariesRoot(); } @Override public SkyValue compute(SkyKey skyKey, Environment env) throws WorkspaceFileFunctionException, InterruptedException { RootedPath workspaceRoot = (RootedPath) skyKey.argument(); - // Explicitly make skyframe load this file. if (env.getValue(FileValue.key(workspaceRoot)) == null) { return null; } - Path workspaceFilePath = workspaceRoot.getRoot().getRelative(workspaceRoot.getRelativePath()); - WorkspaceNameHolder holder = new WorkspaceNameHolder(); - ExternalPackageBuilder builder = new ExternalPackageBuilder(workspaceFilePath); + + 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(repoWorkspace, builder); + try { + builder.resolveBindTargets(packageFactory.getRuleClass(BIND)); + } catch (NoSuchBindingException e) { + throw new WorkspaceFileFunctionException(e); + } catch (EvalException e) { + throw new WorkspaceFileFunctionException(e); + } + + ExternalPackage pkg = builder.build(); + return new WorkspaceFileValue(pkg.getWorkspaceName(), pkg); + } + + private void parseWorkspaceFile(Path workspaceFilePath, Builder builder) + throws WorkspaceFileFunctionException, InterruptedException { StoredEventHandler localReporter = new StoredEventHandler(); BuildFileAST buildFileAST; ParserInputSource inputSource = null; @@ -87,13 +114,9 @@ public class WorkspaceFileFunction implements SkyFunction { if (buildFileAST.containsErrors()) { localReporter.handle(Event.error("WORKSPACE file could not be parsed")); } else { - try { - if (!evaluateWorkspaceFile(buildFileAST, holder, builder)) { - localReporter.handle( - Event.error("Error evaluating WORKSPACE file " + workspaceFilePath)); - } - } catch (EvalException e) { - throw new WorkspaceFileFunctionException(e); + if (!evaluateWorkspaceFile(buildFileAST, builder)) { + localReporter.handle( + Event.error("Error evaluating WORKSPACE file " + workspaceFilePath)); } } @@ -101,7 +124,6 @@ public class WorkspaceFileFunction implements SkyFunction { if (localReporter.hasErrors()) { builder.setContainsErrors(); } - return new WorkspaceFileValue(holder.workspaceName, builder.build()); } @Override @@ -109,7 +131,7 @@ public class WorkspaceFileFunction implements SkyFunction { return null; } - private static Function newWorkspaceNameFunction(final WorkspaceNameHolder holder) { + private static Function newWorkspaceNameFunction(final Builder builder) { List<String> params = ImmutableList.of("name"); return new MixedModeFunction("workspace", params, 1, true) { @Override @@ -120,13 +142,13 @@ public class WorkspaceFileFunction implements SkyFunction { if (errorMessage != null) { throw new EvalException(ast.getLocation(), errorMessage); } - holder.workspaceName = name; + builder.setWorkspaceName(name); return NONE; } }; } - private static Function newBindFunction(final ExternalPackageBuilder builder) { + private static Function newBindFunction(final Builder builder) { List<String> params = ImmutableList.of("name", "actual"); return new MixedModeFunction(BIND, params, 2, true) { @Override @@ -154,7 +176,7 @@ public class WorkspaceFileFunction implements SkyFunction { * specified package context. */ private static Function newRuleFunction(final RuleFactory ruleFactory, - final ExternalPackageBuilder builder, final String ruleClassName) { + final Builder builder, final String ruleClassName) { return new AbstractFunction(ruleClassName) { @Override public Object call(List<Object> args, Map<String, Object> kwargs, FuncallExpression ast, @@ -176,9 +198,8 @@ public class WorkspaceFileFunction implements SkyFunction { }; } - public boolean evaluateWorkspaceFile(BuildFileAST buildFileAST, WorkspaceNameHolder holder, - ExternalPackageBuilder builder) - throws InterruptedException, EvalException, WorkspaceFileFunctionException { + public boolean evaluateWorkspaceFile(BuildFileAST buildFileAST, Builder builder) + throws InterruptedException { // Environment is defined in SkyFunction and the syntax package. com.google.devtools.build.lib.syntax.Environment workspaceEnv = new com.google.devtools.build.lib.syntax.Environment(); @@ -190,22 +211,10 @@ public class WorkspaceFileFunction implements SkyFunction { } workspaceEnv.update(BIND, newBindFunction(builder)); - workspaceEnv.update("workspace", newWorkspaceNameFunction(holder)); + workspaceEnv.update("workspace", newWorkspaceNameFunction(builder)); StoredEventHandler eventHandler = new StoredEventHandler(); - if (!buildFileAST.exec(workspaceEnv, eventHandler)) { - return false; - } - try { - builder.resolveBindTargets(packageFactory.getRuleClass(BIND)); - } catch (NoSuchBindingException e) { - throw new WorkspaceFileFunctionException(e); - } - return true; - } - - private static final class WorkspaceNameHolder { - String workspaceName; + return buildFileAST.exec(workspaceEnv, eventHandler); } private static final class WorkspaceFileFunctionException extends SkyFunctionException { |