aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java
diff options
context:
space:
mode:
authorGravatar Yun Peng <pcloudy@google.com>2016-03-03 13:14:38 +0000
committerGravatar Kristina Chodorow <kchodorow@google.com>2016-03-03 15:28:01 +0000
commitefd7ca1b420e00cf32839c07733e0e4a4d8b1bbb (patch)
tree04eee06d2b6e277f3d0eaa7f326f1ae843b56746 /src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java
parentf745e99db7632cfb2145b6926f961e85f9084bc5 (diff)
Python provider is now available in Skylark
Using mandatoryProvidersList to validate python rules' dependency. Added a SkylarkProvider named 'py' which is a SkylarkClassObject in Java and a struct in Skylark. Native python rule and Skylark python rule should have this provider so that they can depend on each other. RELNOTES[NEW]: Native python rule can depend on skylark rule as long as skylark rule provides 'py' provider. -- MOS_MIGRATED_REVID=116241504
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java83
1 files changed, 70 insertions, 13 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java b/src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java
index 9b6813fad5..eff1239649 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java
@@ -15,6 +15,7 @@ package com.google.devtools.build.lib.rules.python;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Action;
import com.google.devtools.build.lib.actions.ActionOwner;
@@ -30,6 +31,7 @@ import com.google.devtools.build.lib.analysis.PseudoAction;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.SkylarkProviders;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.analysis.Util;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
@@ -44,6 +46,11 @@ import com.google.devtools.build.lib.rules.cpp.CppFileTypes;
import com.google.devtools.build.lib.rules.test.InstrumentedFilesCollector;
import com.google.devtools.build.lib.rules.test.InstrumentedFilesCollector.LocalMetadataCollector;
import com.google.devtools.build.lib.rules.test.InstrumentedFilesProvider;
+import com.google.devtools.build.lib.syntax.ClassObject.SkylarkClassObject;
+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 com.google.devtools.build.lib.syntax.SkylarkType;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.util.FileType;
import com.google.devtools.build.lib.util.Preconditions;
@@ -61,6 +68,10 @@ import java.util.UUID;
*/
public final class PyCommon {
+ public static final String PYTHON_SKYLARK_PROVIDER_NAME = "py";
+ public static final String TRANSITIVE_PYTHON_SRCS = "transitive_sources";
+ public static final String IS_USING_SHARED_LIBRARY = "uses_shared_libraries";
+
private static final LocalMetadataCollector METADATA_COLLECTOR = new LocalMetadataCollector() {
@Override
public void collectMetadataArtifacts(Iterable<Artifact> artifacts,
@@ -125,13 +136,15 @@ public final class PyCommon {
public void addCommonTransitiveInfoProviders(RuleConfiguredTargetBuilder builder,
PythonSemantics semantics, NestedSet<Artifact> filesToBuild) {
- PythonSourcesProvider sourcesProvider =
- new PythonSourcesProvider(transitivePythonSources, usesSharedLibraries());
+
+ SkylarkClassObject sourcesProvider =
+ new SkylarkClassObject(ImmutableMap.<String, Object>of(
+ TRANSITIVE_PYTHON_SRCS, SkylarkNestedSet.of(Artifact.class, transitivePythonSources),
+ IS_USING_SHARED_LIBRARY, usesSharedLibraries()), "No such attribute '%s'");
builder
.add(InstrumentedFilesProvider.class, InstrumentedFilesCollector.collect(ruleContext,
semantics.getCoverageInstrumentationSpec(), METADATA_COLLECTOR, filesToBuild))
- .add(PythonSourcesProvider.class, sourcesProvider)
- .addSkylarkTransitiveInfo(PythonSourcesProvider.SKYLARK_NAME, sourcesProvider)
+ .addSkylarkTransitiveInfo(PYTHON_SKYLARK_PROVIDER_NAME, sourcesProvider)
// Python targets are not really compilable. The best we can do is make sure that all
// generated source files are ready.
.addOutputGroup(OutputGroupProvider.FILES_TO_COMPILE, transitivePythonSources)
@@ -260,12 +273,44 @@ public final class PyCommon {
return ruleContext.getPrerequisites("deps", Mode.TARGET);
}
+ private NestedSet<Artifact> getTransitivePythonSourcesFromSkylarkProvider(
+ TransitiveInfoCollection dep) {
+ SkylarkClassObject pythonSkylarkProvider = null;
+ SkylarkProviders skylarkProviders = dep.getProvider(SkylarkProviders.class);
+ try {
+ if (skylarkProviders != null) {
+ pythonSkylarkProvider = skylarkProviders.getValue(PYTHON_SKYLARK_PROVIDER_NAME,
+ SkylarkClassObject.class);
+ }
+
+ if (pythonSkylarkProvider != null) {
+ Object sourceFiles = pythonSkylarkProvider.getValue(TRANSITIVE_PYTHON_SRCS);
+ String errorType;
+ if (sourceFiles == null) {
+ errorType = "null";
+ } else {
+ errorType = EvalUtils.getDataTypeNameFromClass(sourceFiles.getClass());
+ }
+ String errorMsg = "Illegal Argument: attribute '%s' in provider '%s' is "
+ + "of unexpected type. Should be a set, but got a '%s'";
+ NestedSet<Artifact> pythonSourceFiles = SkylarkType.cast(
+ sourceFiles, SkylarkNestedSet.class, Artifact.class, null,
+ errorMsg, TRANSITIVE_PYTHON_SRCS, PYTHON_SKYLARK_PROVIDER_NAME, errorType)
+ .getSet(Artifact.class);
+ return pythonSourceFiles;
+ }
+ } catch (EvalException e) {
+ ruleContext.ruleError(e.getMessage());
+ }
+ return null;
+ }
+
private void collectTransitivePythonSourcesFrom(
Iterable<? extends TransitiveInfoCollection> deps, NestedSetBuilder<Artifact> builder) {
for (TransitiveInfoCollection dep : deps) {
- if (dep.getProvider(PythonSourcesProvider.class) != null) {
- PythonSourcesProvider provider = dep.getProvider(PythonSourcesProvider.class);
- builder.addTransitive(provider.getTransitivePythonSources());
+ NestedSet<Artifact> pythonSourceFiles = getTransitivePythonSourcesFromSkylarkProvider(dep);
+ if (pythonSourceFiles != null) {
+ builder.addTransitive(pythonSourceFiles);
} else {
// TODO(bazel-team): We also collect .py source files from deps (e.g. for proto_library
// rules). Rules should implement PythonSourcesProvider instead.
@@ -381,9 +426,14 @@ public final class PyCommon {
}
public boolean usesSharedLibraries() {
- return checkForSharedLibraries(Iterables.concat(
- ruleContext.getPrerequisites("deps", Mode.TARGET),
- ruleContext.getPrerequisites("data", Mode.DATA)));
+ try {
+ return checkForSharedLibraries(Iterables.concat(
+ ruleContext.getPrerequisites("deps", Mode.TARGET),
+ ruleContext.getPrerequisites("data", Mode.DATA)));
+ } catch (EvalException e) {
+ ruleContext.ruleError(e.getMessage());
+ return false;
+ }
}
protected static final ResourceSet PY_COMPILE_RESOURCE_SET =
@@ -453,11 +503,18 @@ public final class PyCommon {
/**
* Returns true if this target has an .so file in its transitive dependency closure.
*/
- public static boolean checkForSharedLibraries(Iterable<TransitiveInfoCollection> deps) {
+ public static boolean checkForSharedLibraries(Iterable<TransitiveInfoCollection> deps)
+ throws EvalException{
for (TransitiveInfoCollection dep : deps) {
- PythonSourcesProvider provider = dep.getProvider(PythonSourcesProvider.class);
+ SkylarkProviders providers = dep.getProvider(SkylarkProviders.class);
+ SkylarkClassObject provider = null;
+ if (providers != null) {
+ provider = providers.getValue(PYTHON_SKYLARK_PROVIDER_NAME,
+ SkylarkClassObject.class);
+ }
if (provider != null) {
- if (provider.usesSharedLibraries()) {
+ Boolean isUsingSharedLibrary = provider.getValue(IS_USING_SHARED_LIBRARY, Boolean.class);
+ if (Boolean.TRUE.equals(isUsingSharedLibrary)) {
return true;
}
} else if (FileType.contains(