// Copyright 2016 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.rules.java; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.Runfiles; import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap; import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMapBuilder; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.packages.BuiltinProvider; import com.google.devtools.build.lib.packages.NativeInfo; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization; import com.google.devtools.build.lib.skylarkbuildapi.FileApi; import com.google.devtools.build.lib.skylarkbuildapi.java.JavaInfoApi; import com.google.devtools.build.lib.skylarkinterface.SkylarkValue; import com.google.devtools.build.lib.syntax.Environment; import com.google.devtools.build.lib.syntax.EvalException; import com.google.devtools.build.lib.syntax.Runtime; import com.google.devtools.build.lib.syntax.SkylarkList; import com.google.devtools.build.lib.syntax.SkylarkList.MutableList; import com.google.devtools.build.lib.syntax.SkylarkNestedSet; import java.util.ArrayList; import java.util.List; import java.util.function.Function; import javax.annotation.Nullable; /** A Skylark declared provider that encapsulates all providers that are needed by Java rules. */ @Immutable @AutoCodec public final class JavaInfo extends NativeInfo implements JavaInfoApi { public static final String SKYLARK_NAME = "JavaInfo"; public static final JavaInfoProvider PROVIDER = new JavaInfoProvider(); @Nullable private static T nullIfNone(Object object, Class type) { return object != Runtime.NONE ? type.cast(object) : null; } @Nullable private static Object nullIfNone(Object object) { return nullIfNone(object, Object.class); } public static final JavaInfo EMPTY = JavaInfo.Builder.create().build(); private static final ImmutableSet> ALLOWED_PROVIDERS = ImmutableSet.of( JavaCompilationArgsProvider.class, JavaSourceJarsProvider.class, JavaRuleOutputJarsProvider.class, JavaRunfilesProvider.class, JavaPluginInfoProvider.class, JavaGenJarsProvider.class, JavaExportsProvider.class, JavaCompilationInfoProvider.class, JavaStrictCompilationArgsProvider.class, JavaSourceInfoProvider.class); private final TransitiveInfoProviderMap providers; /* * Contains the .jar files to be put on the runtime classpath by the configured target. *

Unlike {@link JavaCompilationArgs#getRuntimeJars()}, it does not contain transitive runtime * jars, only those produced by the configured target itself. * *

The reason why this field exists is that neverlink libraries do not contain the compiled jar * in {@link JavaCompilationArgs#getRuntimeJars()} and those are sometimes needed, for example, * for Proguarding (the compile time classpath is not enough because that contains only ijars) */ private final ImmutableList directRuntimeJars; /** * Java constraints (e.g. "android") that are present on the target. */ private final ImmutableList javaConstraints; // Whether or not this library should be used only for compilation and not at runtime. private final boolean neverlink; /** Returns the instance for the provided providerClass, or null if not present. */ @Nullable public

P getProvider(Class

providerClass) { return providers.getProvider(providerClass); } public TransitiveInfoProviderMap getProviders() { return providers; } /** * Merges the given providers into one {@link JavaInfo}. All the providers with the same type * in the given list are merged into one provider that is added to the resulting * {@link JavaInfo}. */ public static JavaInfo merge(List providers) { List javaCompilationArgsProviders = JavaInfo.fetchProvidersFromList(providers, JavaCompilationArgsProvider.class); List javaStrictCompilationArgsProviders = JavaInfo.fetchProvidersFromList(providers, JavaStrictCompilationArgsProvider.class); List javaSourceJarsProviders = JavaInfo.fetchProvidersFromList(providers, JavaSourceJarsProvider.class); List javaRunfilesProviders = JavaInfo.fetchProvidersFromList(providers, JavaRunfilesProvider.class); List javaPluginInfoProviders = JavaInfo.fetchProvidersFromList(providers, JavaPluginInfoProvider.class); List javaExportsProviders = JavaInfo.fetchProvidersFromList(providers, JavaExportsProvider.class); List javaRuleOutputJarsProviders = JavaInfo.fetchProvidersFromList(providers, JavaRuleOutputJarsProvider.class); Runfiles mergedRunfiles = Runfiles.EMPTY; for (JavaRunfilesProvider javaRunfilesProvider : javaRunfilesProviders) { Runfiles runfiles = javaRunfilesProvider.getRunfiles(); mergedRunfiles = mergedRunfiles == Runfiles.EMPTY ? runfiles : mergedRunfiles.merge(runfiles); } return JavaInfo.Builder.create() .addProvider( JavaCompilationArgsProvider.class, JavaCompilationArgsProvider.merge(javaCompilationArgsProviders)) .addProvider( JavaStrictCompilationArgsProvider.class, JavaStrictCompilationArgsProvider.merge(javaStrictCompilationArgsProviders)) .addProvider( JavaSourceJarsProvider.class, JavaSourceJarsProvider.merge(javaSourceJarsProviders)) .addProvider(JavaRuleOutputJarsProvider.class, JavaRuleOutputJarsProvider.merge(javaRuleOutputJarsProviders)) .addProvider(JavaRunfilesProvider.class, new JavaRunfilesProvider(mergedRunfiles)) .addProvider( JavaPluginInfoProvider.class, JavaPluginInfoProvider.merge(javaPluginInfoProviders)) .addProvider(JavaExportsProvider.class, JavaExportsProvider.merge(javaExportsProviders)) // TODO(b/65618333): add merge function to JavaGenJarsProvider. See #3769 .build(); } /** * Returns a list of providers of the specified class, fetched from the given list of * {@link JavaInfo}s. * Returns an empty list if no providers can be fetched. * Returns a list of the same size as the given list if the requested providers are of type * JavaCompilationArgsProvider. */ public static List fetchProvidersFromList( Iterable javaProviders, Class providersClass) { List fetchedProviders = new ArrayList<>(); for (JavaInfo javaInfo : javaProviders) { C provider = javaInfo.getProvider(providersClass); if (provider != null) { fetchedProviders.add(provider); } } return fetchedProviders; } /** * Returns a provider of the specified class, fetched from the specified target or, if not found, * from the JavaInfo of the given target. JavaInfo can be found as a declared provider * in SkylarkProviders. * Returns null if no such provider exists. * *

A target can either have both the specified provider and JavaInfo that encapsulates the * same information, or just one of them.

*/ @Nullable public static T getProvider( Class providerClass, TransitiveInfoCollection target) { T provider = target.getProvider(providerClass); if (provider != null) { return provider; } JavaInfo javaInfo = (JavaInfo) target.get(JavaInfo.PROVIDER.getKey()); if (javaInfo == null) { return null; } return javaInfo.getProvider(providerClass); } public static JavaInfo getJavaInfo(TransitiveInfoCollection target) { return (JavaInfo) target.get(JavaInfo.PROVIDER.getKey()); } public static T getProvider( Class providerClass, TransitiveInfoProviderMap providerMap) { T provider = providerMap.getProvider(providerClass); if (provider != null) { return provider; } JavaInfo javaInfo = (JavaInfo) providerMap.getProvider(JavaInfo.PROVIDER.getKey()); if (javaInfo == null) { return null; } return javaInfo.getProvider(providerClass); } public static List getProvidersFromListOfTargets( Class providerClass, Iterable targets) { List providersList = new ArrayList<>(); for (TransitiveInfoCollection target : targets) { T provider = getProvider(providerClass, target); if (provider != null) { providersList.add(provider); } } return providersList; } /** * Returns a list of the given provider class with all the said providers retrieved from the * given {@link JavaInfo}s. */ public static ImmutableList getProvidersFromListOfJavaProviders( Class providerClass, Iterable javaProviders) { ImmutableList.Builder providersList = new ImmutableList.Builder<>(); for (JavaInfo javaInfo : javaProviders) { T provider = javaInfo.getProvider(providerClass); if (provider != null) { providersList.add(provider); } } return providersList.build(); } @VisibleForSerialization @AutoCodec.Instantiator JavaInfo( TransitiveInfoProviderMap providers, ImmutableList directRuntimeJars, boolean neverlink, ImmutableList javaConstraints, Location location) { super(PROVIDER, location); this.directRuntimeJars = directRuntimeJars; this.providers = providers; this.neverlink = neverlink; this.javaConstraints = javaConstraints; } public Boolean isNeverlink() { return neverlink; } @Override public SkylarkNestedSet getTransitiveRuntimeJars() { return SkylarkNestedSet.of(Artifact.class, getTransitiveRuntimeDeps()); } @Override public SkylarkNestedSet getTransitiveCompileTimeJars() { return SkylarkNestedSet.of(Artifact.class, getTransitiveDeps()); } @Override public SkylarkNestedSet getCompileTimeJars() { NestedSet compileTimeJars = getProviderAsNestedSet( JavaCompilationArgsProvider.class, JavaCompilationArgsProvider::getDirectCompileTimeJars); return SkylarkNestedSet.of(Artifact.class, compileTimeJars); } @Override public SkylarkNestedSet getFullCompileTimeJars() { NestedSet fullCompileTimeJars = getProviderAsNestedSet( JavaCompilationArgsProvider.class, JavaCompilationArgsProvider::getDirectFullCompileTimeJars); return SkylarkNestedSet.of(Artifact.class, fullCompileTimeJars); } @Override public SkylarkList getSourceJars() { //TODO(#4221) change return type to NestedSet JavaSourceJarsProvider provider = providers.getProvider(JavaSourceJarsProvider.class); ImmutableList sourceJars = provider == null ? ImmutableList.of() : provider.getSourceJars(); return SkylarkList.createImmutable(sourceJars); } @Override public JavaRuleOutputJarsProvider getOutputJars() { return getProvider(JavaRuleOutputJarsProvider.class); } @Override public JavaGenJarsProvider getGenJarsProvider() { return getProvider(JavaGenJarsProvider.class); } @Override public JavaCompilationInfoProvider getCompilationInfoProvider() { return getProvider(JavaCompilationInfoProvider.class); } @Override public SkylarkList getRuntimeOutputJars() { return SkylarkList.createImmutable(getDirectRuntimeJars()); } public ImmutableList getDirectRuntimeJars() { return directRuntimeJars; } @Override public NestedSet getTransitiveDeps() { return getProviderAsNestedSet( JavaCompilationArgsProvider.class, JavaCompilationArgsProvider::getTransitiveCompileTimeJars); } @Override public NestedSet getTransitiveRuntimeDeps() { return getProviderAsNestedSet( JavaCompilationArgsProvider.class, JavaCompilationArgsProvider::getRuntimeJars); } @Override public NestedSet getTransitiveSourceJars() { return getProviderAsNestedSet( JavaSourceJarsProvider.class, JavaSourceJarsProvider::getTransitiveSourceJars); } @Override public NestedSet