diff options
author | Yun Peng <pcloudy@google.com> | 2016-03-03 13:14:38 +0000 |
---|---|---|
committer | Kristina Chodorow <kchodorow@google.com> | 2016-03-03 15:28:01 +0000 |
commit | efd7ca1b420e00cf32839c07733e0e4a4d8b1bbb (patch) | |
tree | 04eee06d2b6e277f3d0eaa7f326f1ae843b56746 /src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java | |
parent | f745e99db7632cfb2145b6926f961e85f9084bc5 (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.java | 83 |
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( |