aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools
diff options
context:
space:
mode:
authorGravatar Vladimir Moskva <vladmos@google.com>2016-11-09 12:54:51 +0000
committerGravatar Klaus Aehlig <aehlig@google.com>2016-11-09 13:45:00 +0000
commiteb0cfc57b58d646ad6a67c655fe0a76b4c22bdbd (patch)
tree2a79fbb7e02ae988431eb36d1aad6627c3158001 /src/main/java/com/google/devtools
parent90b5b19927540fc1e1c9e1a7fbd05c816ae0e4e2 (diff)
Implemented default provider
-- MOS_MIGRATED_REVID=138625702
Diffstat (limited to 'src/main/java/com/google/devtools')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java214
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java8
2 files changed, 142 insertions, 80 deletions
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 814ae564b8..94c507787d 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,6 +13,7 @@
// 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;
@@ -230,93 +231,141 @@ public final class SkylarkRuleConfiguredTargetBuilder {
Map<String, Class<? extends TransitiveInfoProvider>> registeredProviderTypes)
throws EvalException {
Location loc = null;
- Runfiles statelessRunfiles = null;
- Runfiles dataRunfiles = null;
- Runfiles defaultRunfiles = null;
+ Boolean isParsed = false;
if (target instanceof SkylarkClassObject) {
SkylarkClassObject struct = (SkylarkClassObject) target;
loc = struct.getCreationLoc();
- for (String key : struct.getKeys()) {
- if (key.equals("files")) {
- // If we specify files_to_build we don't have the executable in it by default.
- builder.setFilesToBuild(cast("files", struct, SkylarkNestedSet.class, Artifact.class, loc)
- .getSet(Artifact.class));
- } else if (key.equals("runfiles")) {
- statelessRunfiles = cast("runfiles", struct, Runfiles.class, loc);
- } else if (key.equals("data_runfiles")) {
- dataRunfiles = cast("data_runfiles", struct, Runfiles.class, loc);
- } else if (key.equals("default_runfiles")) {
- defaultRunfiles = cast("default_runfiles", struct, Runfiles.class, loc);
- } else if (key.equals("output_groups")) {
- addOutputGroups(struct.getValue(key), loc, builder);
- } else if (key.equals("instrumented_files")) {
- SkylarkClassObject insStruct =
- cast("instrumented_files", struct, SkylarkClassObject.class, loc);
- Location insLoc = insStruct.getCreationLoc();
- FileTypeSet fileTypeSet = FileTypeSet.ANY_FILE;
- if (insStruct.getKeys().contains("extensions")) {
- @SuppressWarnings("unchecked")
- List<String> exts = cast(
- "extensions", insStruct, SkylarkList.class, String.class, insLoc);
- if (exts.isEmpty()) {
- fileTypeSet = FileTypeSet.NO_FILE;
- } else {
- FileType[] fileTypes = new FileType[exts.size()];
- for (int i = 0; i < fileTypes.length; i++) {
- fileTypes[i] = FileType.of(exts.get(i));
- }
- fileTypeSet = FileTypeSet.of(fileTypes);
- }
- }
- List<String> dependencyAttributes = Collections.emptyList();
- if (insStruct.getKeys().contains("dependency_attributes")) {
- dependencyAttributes =
- cast("dependency_attributes", insStruct, SkylarkList.class, String.class, insLoc);
- }
- List<String> sourceAttributes = Collections.emptyList();
- if (insStruct.getKeys().contains("source_attributes")) {
- sourceAttributes =
- cast("source_attributes", insStruct, SkylarkList.class, String.class, insLoc);
- }
- InstrumentationSpec instrumentationSpec =
- new InstrumentationSpec(fileTypeSet)
- .withSourceAttributes(sourceAttributes.toArray(new String[0]))
- .withDependencyAttributes(dependencyAttributes.toArray(new String[0]));
- InstrumentedFilesProvider instrumentedFilesProvider =
- InstrumentedFilesCollector.collect(
- ruleContext,
- instrumentationSpec,
- InstrumentedFilesCollector.NO_METADATA_COLLECTOR,
- Collections.<Artifact>emptySet());
- builder.addProvider(InstrumentedFilesProvider.class, instrumentedFilesProvider);
- } else if (registeredProviderTypes.containsKey(key)) {
- Class<? extends TransitiveInfoProvider> providerType = registeredProviderTypes.get(key);
- TransitiveInfoProvider provider = cast(key, struct, providerType, loc);
- builder.addProvider(providerType, provider);
- } else if (key.equals("providers")) {
- Iterable iterable = cast(key, struct, Iterable.class, loc);
- for (Object o : iterable) {
- SkylarkClassObject declaredProvider = SkylarkType.cast(o, SkylarkClassObject.class, loc,
- "The value of 'providers' should be a sequence of declared providers");
- builder.addSkylarkDeclaredProvider(declaredProvider, loc);
- }
- } else if (!key.equals("executable")) {
- // We handled executable already.
- builder.addSkylarkTransitiveInfo(key, struct.getValue(key), loc);
- }
- }
+ parseProviderKeys(struct, false, ruleContext, loc, executable, registeredProviderTypes,
+ builder);
+ isParsed = true;
} else if (target instanceof Iterable) {
loc = ruleContext.getRule().getRuleClassObject().getConfiguredTargetFunction().getLocation();
for (Object o : (Iterable) target) {
SkylarkClassObject declaredProvider = SkylarkType.cast(o, SkylarkClassObject.class, loc,
"A return value of rule implementation function should be "
+ "a sequence of declared providers");
- Location creationLoc = declaredProvider.getCreationLocOrNull();
- builder.addSkylarkDeclaredProvider(declaredProvider,
- creationLoc != null ? creationLoc : loc);
+ if (declaredProvider.getConstructor().getKey().equals(
+ SkylarkRuleContext.getDefaultProvider().getKey())) {
+ parseProviderKeys(declaredProvider, true, ruleContext, loc, executable,
+ registeredProviderTypes, builder);
+ isParsed = true;
+ } else {
+ Location creationLoc = declaredProvider.getCreationLocOrNull();
+ builder.addSkylarkDeclaredProvider(declaredProvider,
+ creationLoc != null ? creationLoc : loc);
+ }
}
}
+ if (!isParsed) {
+ addSimpleProviders(builder, ruleContext, loc, executable, null, null, null, null);
+ }
+
+ try {
+ return builder.build();
+ } catch (IllegalArgumentException e) {
+ throw new EvalException(loc, e.getMessage());
+ }
+ }
+
+ private static void parseProviderKeys(
+ SkylarkClassObject provider,
+ Boolean isDefaultProvider,
+ RuleContext ruleContext,
+ Location loc,
+ Artifact executable,
+ Map<String, Class<? extends TransitiveInfoProvider>> registeredProviderTypes,
+ RuleConfiguredTargetBuilder builder) throws EvalException {
+ Runfiles statelessRunfiles = null;
+ Runfiles dataRunfiles = null;
+ Runfiles defaultRunfiles = null;
+
+ for (String key : provider.getKeys()) {
+ if (key.equals("files")) {
+ // If we specify files_to_build we don't have the executable in it by default.
+ builder.setFilesToBuild(cast("files", provider, SkylarkNestedSet.class, Artifact.class, loc)
+ .getSet(Artifact.class));
+ } else if (key.equals("runfiles")) {
+ statelessRunfiles = cast("runfiles", provider, Runfiles.class, loc);
+ } else if (key.equals("data_runfiles")) {
+ dataRunfiles = cast("data_runfiles", provider, Runfiles.class, loc);
+ } else if (key.equals("default_runfiles")) {
+ defaultRunfiles = cast("default_runfiles", provider, Runfiles.class, loc);
+ } else if (key.equals("output_groups")) {
+ addOutputGroups(provider.getValue(key), loc, builder);
+ } else if (key.equals("instrumented_files")) {
+ SkylarkClassObject insStruct =
+ cast("instrumented_files", provider, SkylarkClassObject.class, loc);
+ Location insLoc = insStruct.getCreationLoc();
+ FileTypeSet fileTypeSet = FileTypeSet.ANY_FILE;
+ if (insStruct.getKeys().contains("extensions")) {
+ @SuppressWarnings("unchecked")
+ List<String> exts = cast(
+ "extensions", insStruct, SkylarkList.class, String.class, insLoc);
+ if (exts.isEmpty()) {
+ fileTypeSet = FileTypeSet.NO_FILE;
+ } else {
+ FileType[] fileTypes = new FileType[exts.size()];
+ for (int i = 0; i < fileTypes.length; i++) {
+ fileTypes[i] = FileType.of(exts.get(i));
+ }
+ fileTypeSet = FileTypeSet.of(fileTypes);
+ }
+ }
+ List<String> dependencyAttributes = Collections.emptyList();
+ if (insStruct.getKeys().contains("dependency_attributes")) {
+ dependencyAttributes =
+ cast("dependency_attributes", insStruct, SkylarkList.class, String.class, insLoc);
+ }
+ List<String> sourceAttributes = Collections.emptyList();
+ if (insStruct.getKeys().contains("source_attributes")) {
+ sourceAttributes =
+ cast("source_attributes", insStruct, SkylarkList.class, String.class, insLoc);
+ }
+ InstrumentationSpec instrumentationSpec =
+ new InstrumentationSpec(fileTypeSet)
+ .withSourceAttributes(sourceAttributes.toArray(new String[0]))
+ .withDependencyAttributes(dependencyAttributes.toArray(new String[0]));
+ InstrumentedFilesProvider instrumentedFilesProvider =
+ InstrumentedFilesCollector.collect(
+ ruleContext,
+ instrumentationSpec,
+ InstrumentedFilesCollector.NO_METADATA_COLLECTOR,
+ Collections.<Artifact>emptySet());
+ builder.addProvider(InstrumentedFilesProvider.class, instrumentedFilesProvider);
+ } else if (registeredProviderTypes.containsKey(key)) {
+ Class<? extends TransitiveInfoProvider> providerType = registeredProviderTypes.get(key);
+ TransitiveInfoProvider providerField = cast(key, provider, providerType, loc);
+ builder.addProvider(providerType, providerField);
+ } else if (isDefaultProvider) {
+ // Custom keys are not allowed for default providers
+ throw new EvalException(loc, "Invalid key for default provider: " + key);
+ } else if (key.equals("providers")) {
+ Iterable iterable = cast(key, provider, Iterable.class, loc);
+ for (Object o : iterable) {
+ SkylarkClassObject declaredProvider = SkylarkType.cast(o, SkylarkClassObject.class, loc,
+ "The value of 'providers' should be a sequence of declared providers");
+ builder.addSkylarkDeclaredProvider(declaredProvider, loc);
+ }
+ } else if (!key.equals("executable")) {
+ // We handled executable already.
+ builder.addSkylarkTransitiveInfo(key, provider.getValue(key), loc);
+ }
+ }
+
+ addSimpleProviders(builder, ruleContext, loc, executable, statelessRunfiles, dataRunfiles,
+ defaultRunfiles, (isDefaultProvider ? provider : null));
+ }
+
+ private static void addSimpleProviders(RuleConfiguredTargetBuilder builder,
+ RuleContext ruleContext,
+ Location loc,
+ Artifact executable,
+ Runfiles statelessRunfiles,
+ Runfiles dataRunfiles,
+ Runfiles defaultRunfiles,
+ SkylarkClassObject defaultProvider) throws EvalException {
+
if ((statelessRunfiles != null) && (dataRunfiles != null || defaultRunfiles != null)) {
throw new EvalException(loc, "Cannot specify the provider 'runfiles' "
+ "together with 'data_runfiles' or 'default_runfiles'");
@@ -354,11 +403,16 @@ public final class SkylarkRuleConfiguredTargetBuilder {
builder.addSkylarkDeclaredProvider(actions, loc);
}
- try {
- return builder.build();
- } catch (IllegalArgumentException e) {
- throw new EvalException(loc, e.getMessage());
- }
+ // 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 = SkylarkRuleContext.getDefaultProvider().create(
+ attrBuilder.build(), "Default provider has no attribute '%s'");
+
+ // 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 37a77d4be2..ebd4db681c 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
@@ -422,6 +422,14 @@ public final class SkylarkRuleContext {
return ruleContext;
}
+ private static final SkylarkClassObjectConstructor DEFAULT_PROVIDER =
+ SkylarkClassObjectConstructor.createNativeConstructable("default_provider");
+
+ @SkylarkCallable(name = "default_provider", structField = true)
+ public static SkylarkClassObjectConstructor getDefaultProvider() {
+ return DEFAULT_PROVIDER;
+ }
+
@SkylarkCallable(name = "created_actions",
doc = "For rules marked <code>_skylark_testable=True</code>, this returns an "
+ "<a href=\"ActionsSkylarkApiProvider.html\">actions</a> provider representing all "