diff options
author | vladmos <vladmos@google.com> | 2017-04-11 11:14:22 +0000 |
---|---|---|
committer | Jakob Buchgraber <buchgr@google.com> | 2017-04-11 13:50:44 +0200 |
commit | 360fb4d9a1e2c44154b17aeb866e07bac2dd1b5b (patch) | |
tree | 7a61fc7be99320496a50780807945271d4a6c586 /src/main/java/com/google | |
parent | 1dadb878a59b180bf950c72ee3b4bdb8d7ea7d67 (diff) |
Implement default provider
Default providers can now be used not only to return standard providers values
from a rule implementation function, but also to access these values provided
by other rules.
PiperOrigin-RevId: 152797193
Diffstat (limited to 'src/main/java/com/google')
7 files changed, 115 insertions, 44 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/AbstractConfiguredTarget.java b/src/main/java/com/google/devtools/build/lib/analysis/AbstractConfiguredTarget.java index d32b279b49..f5313b8ca0 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/AbstractConfiguredTarget.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/AbstractConfiguredTarget.java @@ -16,7 +16,6 @@ package com.google.devtools.build.lib.analysis; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; -import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.collect.nestedset.NestedSet; @@ -27,10 +26,10 @@ import com.google.devtools.build.lib.packages.ClassObjectConstructor; import com.google.devtools.build.lib.packages.PackageSpecification; import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier; import com.google.devtools.build.lib.packages.Target; +import com.google.devtools.build.lib.rules.SkylarkRuleContext; import com.google.devtools.build.lib.syntax.ClassObject; import com.google.devtools.build.lib.syntax.EvalException; import com.google.devtools.build.lib.syntax.EvalUtils; -import com.google.devtools.build.lib.syntax.SkylarkNestedSet; import javax.annotation.Nullable; /** @@ -108,19 +107,17 @@ public abstract class AbstractConfiguredTarget @Override public Object getValue(String name) { + // Standard fields should be proxied to their default provider object + DefaultProvider defaultProvider = + (DefaultProvider) get(SkylarkRuleContext.getDefaultProvider().getKey()); switch (name) { - case LABEL_FIELD: - return getLabel(); case FILES_FIELD: - // A shortcut for files to build in Skylark. FileConfiguredTarget and RuleConfiguredTarget - // always has FileProvider and Error- and PackageGroupConfiguredTarget-s shouldn't be - // accessible in Skylark. - return SkylarkNestedSet.of( - Artifact.class, getProvider(FileProvider.class).getFilesToBuild()); case DEFAULT_RUNFILES_FIELD: - return RunfilesProvider.DEFAULT_RUNFILES.apply(this); case DATA_RUNFILES_FIELD: - return RunfilesProvider.DATA_RUNFILES.apply(this); + case FilesToRunProvider.SKYLARK_NAME: + return defaultProvider.getValue(name); + case LABEL_FIELD: + return getLabel(); default: return get(name); } @@ -173,6 +170,10 @@ public abstract class AbstractConfiguredTarget @Override public ImmutableCollection<String> getKeys() { return ImmutableList.of( - DATA_RUNFILES_FIELD, DEFAULT_RUNFILES_FIELD, LABEL_FIELD, FILES_FIELD); + DATA_RUNFILES_FIELD, + DEFAULT_RUNFILES_FIELD, + LABEL_FIELD, + FILES_FIELD, + FilesToRunProvider.SKYLARK_NAME); } } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/DefaultProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/DefaultProvider.java new file mode 100644 index 0000000000..c0c2a317a4 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/analysis/DefaultProvider.java @@ -0,0 +1,58 @@ +// 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.analysis; + +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.packages.ClassObjectConstructor; +import com.google.devtools.build.lib.packages.SkylarkClassObject; +import com.google.devtools.build.lib.rules.SkylarkRuleContext; +import com.google.devtools.build.lib.syntax.SkylarkNestedSet; +import java.util.Map; + +/** DefaultProvider is provided by all targets implicitly and contains all standard fields. */ +@Immutable +public final class DefaultProvider extends SkylarkClassObject { + + // Accessors for Skylark + private static final String DATA_RUNFILES_FIELD = "data_runfiles"; + private static final String DEFAULT_RUNFILES_FIELD = "default_runfiles"; + private static final String FILES_FIELD = "files"; + + private DefaultProvider(ClassObjectConstructor constructor, Map<String, Object> values) { + super(constructor, values); + } + + public static DefaultProvider build( + RunfilesProvider runfilesProvider, + FileProvider fileProvider, + FilesToRunProvider filesToRunProvider) { + ImmutableMap.Builder<String, Object> attrBuilder = new ImmutableMap.Builder<>(); + if (runfilesProvider != null) { + attrBuilder.put(DATA_RUNFILES_FIELD, runfilesProvider.getDataRunfiles()); + attrBuilder.put(DEFAULT_RUNFILES_FIELD, runfilesProvider.getDefaultRunfiles()); + } else { + attrBuilder.put(DATA_RUNFILES_FIELD, Runfiles.EMPTY); + attrBuilder.put(DEFAULT_RUNFILES_FIELD, Runfiles.EMPTY); + } + + attrBuilder.put( + FILES_FIELD, SkylarkNestedSet.of(Artifact.class, fileProvider.getFilesToBuild())); + attrBuilder.put(FilesToRunProvider.SKYLARK_NAME, filesToRunProvider); + + ClassObjectConstructor constructor = SkylarkRuleContext.getDefaultProvider(); + return new DefaultProvider(constructor, attrBuilder.build()); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/analysis/FileConfiguredTarget.java b/src/main/java/com/google/devtools/build/lib/analysis/FileConfiguredTarget.java index 0bc9b5342b..0fe798b6d8 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/FileConfiguredTarget.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/FileConfiguredTarget.java @@ -14,6 +14,7 @@ package com.google.devtools.build.lib.analysis; +import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; @@ -21,6 +22,7 @@ import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.lib.packages.ClassObjectConstructor; import com.google.devtools.build.lib.packages.FileTarget; import com.google.devtools.build.lib.packages.SkylarkClassObject; +import com.google.devtools.build.lib.rules.SkylarkRuleContext; import com.google.devtools.build.lib.rules.fileset.FilesetProvider; import com.google.devtools.build.lib.rules.test.InstrumentedFilesProvider; import com.google.devtools.build.lib.util.FileType; @@ -40,12 +42,22 @@ public abstract class FileConfiguredTarget extends AbstractConfiguredTarget super(targetContext); NestedSet<Artifact> filesToBuild = NestedSetBuilder.create(Order.STABLE_ORDER, artifact); this.artifact = artifact; + FileProvider fileProvider = new FileProvider(filesToBuild); + FilesToRunProvider filesToRunProvider = + FilesToRunProvider.fromSingleExecutableArtifact(artifact); + SkylarkClassObject defaultProvider = + DefaultProvider.build(null, fileProvider, filesToRunProvider); + SkylarkProviders skylarkProviders = + new SkylarkProviders( + ImmutableMap.<String, Object>of(), + ImmutableMap.of(SkylarkRuleContext.getDefaultProvider().getKey(), defaultProvider)); TransitiveInfoProviderMap.Builder builder = TransitiveInfoProviderMap.builder() .put(VisibilityProvider.class, this) .put(LicensesProvider.class, this) - .add(new FileProvider(filesToBuild)) - .add(FilesToRunProvider.fromSingleExecutableArtifact(artifact)); + .put(SkylarkProviders.class, skylarkProviders) + .add(fileProvider) + .add(filesToRunProvider); if (this instanceof FilesetProvider) { builder.put(FilesetProvider.class, this); } @@ -86,6 +98,6 @@ public abstract class FileConfiguredTarget extends AbstractConfiguredTarget @Nullable @Override public SkylarkClassObject get(ClassObjectConstructor.Key providerKey) { - return null; + return getProvider(SkylarkProviders.class).getDeclaredProvider(providerKey); } } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupProvider.java index 51954c137c..7ba2eff806 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupProvider.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupProvider.java @@ -53,7 +53,7 @@ import javax.annotation.Nullable; @Immutable public final class OutputGroupProvider implements TransitiveInfoProvider, SkylarkIndexable, Iterable<String> { - public static String SKYLARK_NAME = "output_groups"; + public static final String SKYLARK_NAME = "output_groups"; /** * Prefix for output groups that are not reported to the user on the terminal output of Blaze when diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java index 9bab0463af..077e2ec5e5 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java @@ -92,7 +92,6 @@ public final class RuleConfiguredTargetBuilder { getFilesToRun(runfilesSupport, filesToBuild), runfilesSupport, executable); addProvider(new FileProvider(filesToBuild)); addProvider(filesToRunProvider); - addSkylarkTransitiveInfo(FilesToRunProvider.SKYLARK_NAME, filesToRunProvider); if (runfilesSupport != null) { // If a binary is built, build its runfiles, too @@ -136,6 +135,14 @@ public final class RuleConfiguredTargetBuilder { addSkylarkTransitiveInfo(OutputGroupProvider.SKYLARK_NAME, outputGroupProvider); } + // Populate default provider fields and build it + DefaultProvider defaultProvider = + DefaultProvider.build( + providersBuilder.getProvider(RunfilesProvider.class), + providersBuilder.getProvider(FileProvider.class), + filesToRunProvider); + skylarkDeclaredProviders.put(defaultProvider.getConstructor().getKey(), defaultProvider); + TransitiveInfoProviderMap providers = providersBuilder.build(); addRegisteredProvidersToSkylarkProviders(providers); diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java index c3f6954312..6f0ac7f0a3 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java @@ -13,7 +13,6 @@ // limitations under the License. package com.google.devtools.build.lib.rules; -import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.actions.Artifact; @@ -270,7 +269,7 @@ public final class SkylarkRuleConfiguredTargetBuilder { } if (!isParsed) { - addSimpleProviders(builder, ruleContext, loc, executable, null, null, null, null); + addSimpleProviders(builder, ruleContext, loc, executable, null, null, null); } try { @@ -365,18 +364,19 @@ public final class SkylarkRuleConfiguredTargetBuilder { } } - addSimpleProviders(builder, ruleContext, loc, executable, statelessRunfiles, dataRunfiles, - defaultRunfiles, (isDefaultProvider ? provider : null)); + addSimpleProviders( + builder, ruleContext, loc, executable, statelessRunfiles, dataRunfiles, defaultRunfiles); } - private static void addSimpleProviders(RuleConfiguredTargetBuilder builder, + private static void addSimpleProviders( + RuleConfiguredTargetBuilder builder, RuleContext ruleContext, Location loc, Artifact executable, Runfiles statelessRunfiles, Runfiles dataRunfiles, - Runfiles defaultRunfiles, - SkylarkClassObject defaultProvider) throws EvalException { + Runfiles defaultRunfiles) + throws EvalException { if ((statelessRunfiles != null) && (dataRunfiles != null || defaultRunfiles != null)) { throw new EvalException(loc, "Cannot specify the provider 'runfiles' " @@ -414,19 +414,6 @@ public final class SkylarkRuleConfiguredTargetBuilder { ruleContext.getAnalysisEnvironment().getRegisteredActions()); builder.addSkylarkDeclaredProvider(actions, loc); } - - // Populate default provider fields and build it - ImmutableMap.Builder<String, Object> attrBuilder = new ImmutableMap.Builder<>(); - // TODO: Add actual attributes that users expect to access from default providers - attrBuilder.put("runfiles", runfilesProvider); - SkylarkClassObject statelessDefaultProvider = - new SkylarkClassObject( - SkylarkRuleContext.getDefaultProvider(), - attrBuilder.build()); - - // Add the default provider - builder.addSkylarkDeclaredProvider(statelessDefaultProvider, (defaultProvider == null) ? loc - : Optional.fromNullable(defaultProvider.getCreationLocOrNull()).or(loc)); } private static <T> T cast(String paramName, ClassObject struct, Class<T> expectedGenericType, diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java index 76ac1a99bf..de8d3de361 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java +++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java @@ -594,13 +594,19 @@ public final class SkylarkRuleContext implements SkylarkValue { } }; - @SkylarkCallable(name = "default_provider", structField = true, - doc = "A provider that's provided by every rule, even if it's not returned explicitly. " - + "A <code>default_provider</code> accepts all special parameters that can be returned " - + "from rule implementation function in a struct, which are <code>runfiles</code>, " - + "<code>data_runfiles</code>, <code>default_runfiles</code>, " - + "<code>output_groups</code>, <code>instrumented_files</code>, and all " - + "<a href=\"skylark-provider.html\">providers</a> that are available on built-in rules.") + @SkylarkCallable( + name = "default_provider", + structField = true, + doc = "A provider that's provided by every rule, even if it's not returned explicitly. " + + "A <code>default_provider</code> accepts all special parameters that can be returned " + + "from rule implementation function in a struct, which are <code>runfiles</code>, " + + "<code>data_runfiles</code>, <code>default_runfiles</code>, " + + "<code>output_groups</code>, <code>instrumented_files</code>, and all " + + "<a href=\"skylark-provider.html\">providers</a> that are available on built-in rules. " + + "Each instance of the default provider contains the following standard fields: " + + "<code>data_runfiles</code>, <code>default_runfiles</code>, <code>files</code>, " + + "and <code>files_to_run</code>. The values of these fields are equivalent to the " + + "values of the corresponding fields of the target the default provider belongs to.") public static ClassObjectConstructor getDefaultProvider() { return DEFAULT_PROVIDER; } |