Java tutorial
// Copyright 2014 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.ideinfo; import static com.google.common.collect.Iterables.transform; import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.HOST; import static com.google.devtools.build.lib.packages.Attribute.attr; import static com.google.devtools.build.lib.packages.BuildType.LABEL; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.io.ByteSource; import com.google.devtools.build.lib.actions.Action; import com.google.devtools.build.lib.actions.ActionOwner; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType; import com.google.devtools.build.lib.actions.Root; import com.google.devtools.build.lib.analysis.AnalysisUtils; import com.google.devtools.build.lib.analysis.ConfiguredAspect; import com.google.devtools.build.lib.analysis.ConfiguredAspect.Builder; import com.google.devtools.build.lib.analysis.ConfiguredAspectFactory; import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.OutputGroupProvider; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; import com.google.devtools.build.lib.analysis.actions.BinaryFileWriteAction; import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; import com.google.devtools.build.lib.analysis.actions.SpawnAction; 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; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.packages.AspectDefinition; import com.google.devtools.build.lib.packages.AspectParameters; import com.google.devtools.build.lib.packages.BuildType; import com.google.devtools.build.lib.packages.NativeAspectClass; import com.google.devtools.build.lib.packages.NonconfigurableAttributeMapper; import com.google.devtools.build.lib.packages.Package; import com.google.devtools.build.lib.packages.TargetUtils; import com.google.devtools.build.lib.rules.android.AndroidIdeInfoProvider; import com.google.devtools.build.lib.rules.android.AndroidIdeInfoProvider.SourceDirectory; import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider; import com.google.devtools.build.lib.rules.cpp.CppCompilationContext; import com.google.devtools.build.lib.rules.cpp.CppConfiguration; import com.google.devtools.build.lib.rules.java.JavaExportsProvider; import com.google.devtools.build.lib.rules.java.JavaGenJarsProvider; import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider; import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider.OutputJar; import com.google.devtools.build.lib.rules.java.JavaSourceInfoProvider; import com.google.devtools.build.lib.rules.java.JavaToolchainProvider; import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.intellij.ideinfo.IntellijIdeInfo.AndroidIdeInfo; import com.google.devtools.intellij.ideinfo.IntellijIdeInfo.ArtifactLocation; import com.google.devtools.intellij.ideinfo.IntellijIdeInfo.CIdeInfo; import com.google.devtools.intellij.ideinfo.IntellijIdeInfo.CToolchainIdeInfo; import com.google.devtools.intellij.ideinfo.IntellijIdeInfo.JavaIdeInfo; import com.google.devtools.intellij.ideinfo.IntellijIdeInfo.JavaToolchainIdeInfo; import com.google.devtools.intellij.ideinfo.IntellijIdeInfo.LibraryArtifact; import com.google.devtools.intellij.ideinfo.IntellijIdeInfo.PyIdeInfo; import com.google.devtools.intellij.ideinfo.IntellijIdeInfo.TargetIdeInfo; import com.google.devtools.intellij.ideinfo.IntellijIdeInfo.TestInfo; import com.google.protobuf.MessageLite; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.List; import javax.annotation.Nullable; /** Generates ide-build information for Android Studio. */ public class AndroidStudioInfoAspect extends NativeAspectClass implements ConfiguredAspectFactory { public static final String NAME = "AndroidStudioInfoAspect"; // Output groups. static final String IDE_INFO = "ide-info"; static final String IDE_INFO_TEXT = "ide-info-text"; static final String IDE_RESOLVE = "ide-resolve"; static final String IDE_COMPILE = "ide-compile"; private final String toolsRepository; private final AndroidStudioInfoSemantics androidStudioInfoSemantics; private final ImmutableList<PrerequisiteAttr> prerequisiteAttrs; public AndroidStudioInfoAspect(String toolsRepository, AndroidStudioInfoSemantics androidStudioInfoSemantics) { this.toolsRepository = toolsRepository; this.androidStudioInfoSemantics = androidStudioInfoSemantics; this.prerequisiteAttrs = buildPrerequisiteAttrs(); } @Override public String getName() { return NAME; } /** Attribute to propagate dependencies along. */ public static class PrerequisiteAttr { public final String name; public final Type<?> type; public PrerequisiteAttr(String name, Type<?> type) { this.name = name; this.type = type; } } private ImmutableList<PrerequisiteAttr> buildPrerequisiteAttrs() { ImmutableList.Builder<PrerequisiteAttr> builder = ImmutableList.builder(); builder.add(new PrerequisiteAttr("deps", BuildType.LABEL_LIST)); builder.add(new PrerequisiteAttr("exports", BuildType.LABEL_LIST)); // From android_test builder.add(new PrerequisiteAttr("binary_under_test", BuildType.LABEL)); // from java_* rules builder.add(new PrerequisiteAttr(":java_toolchain", BuildType.LABEL)); // from cc_* rules builder.add(new PrerequisiteAttr(":cc_toolchain", BuildType.LABEL)); androidStudioInfoSemantics.augmentPrerequisiteAttrs(builder); return builder.build(); } // File suffixes. public static final String ASWB_BUILD_SUFFIX = ".aswb-build"; public static final String ASWB_BUILD_TEXT_SUFFIX = ".aswb-build.txt"; public static final Function<Label, String> LABEL_TO_STRING = new Function<Label, String>() { @Nullable @Override public String apply(Label label) { return label.toString(); } }; @Override public AspectDefinition getDefinition(AspectParameters aspectParameters) { AspectDefinition.Builder builder = new AspectDefinition.Builder(this) .propagateAlongAttribute("runtime_deps").propagateAlongAttribute("resources") .add(attr("$packageParser", LABEL).cfg(HOST).exec() .value(Label.parseAbsoluteUnchecked(toolsRepository + "//tools/android:PackageParser"))) .add(attr("$jarFilter", LABEL).cfg(HOST).exec() .value(Label.parseAbsoluteUnchecked(toolsRepository + "//tools/android:JarFilter"))); for (PrerequisiteAttr prerequisiteAttr : prerequisiteAttrs) { builder.propagateAlongAttribute(prerequisiteAttr.name); } return builder.build(); } @Override public ConfiguredAspect create(ConfiguredTarget base, RuleContext ruleContext, AspectParameters parameters) { ConfiguredAspect.Builder builder = new Builder(this, parameters, ruleContext); AndroidStudioInfoFilesProvider.Builder providerBuilder = new AndroidStudioInfoFilesProvider.Builder(); DependenciesResult dependenciesResult = processDependencies(base, ruleContext, providerBuilder); AndroidStudioInfoFilesProvider provider = createIdeBuildArtifact(base, ruleContext, dependenciesResult, providerBuilder); NestedSetBuilder<Artifact> ideCompileArtifacts = NestedSetBuilder.stableOrder(); // Add artifacts required for compilation OutputGroupProvider outputGroupProvider = base.getProvider(OutputGroupProvider.class); if (outputGroupProvider != null) { ideCompileArtifacts .addTransitive(outputGroupProvider.getOutputGroup(OutputGroupProvider.FILES_TO_COMPILE)); } builder.addOutputGroup(IDE_INFO, provider.getIdeInfoFiles()) .addOutputGroup(IDE_INFO_TEXT, provider.getIdeInfoTextFiles()) .addOutputGroup(IDE_RESOLVE, provider.getIdeResolveFiles()) .addOutputGroup(IDE_COMPILE, ideCompileArtifacts.build()).addProvider(provider); return builder.build(); } private static class DependenciesResult { private DependenciesResult(Iterable<Label> deps, Iterable<Label> runtimeDeps, @Nullable Label resources) { this.deps = deps; this.runtimeDeps = runtimeDeps; this.resources = resources; } final Iterable<Label> deps; final Iterable<Label> runtimeDeps; @Nullable final Label resources; } private DependenciesResult processDependencies(ConfiguredTarget base, RuleContext ruleContext, AndroidStudioInfoFilesProvider.Builder providerBuilder) { // Calculate direct dependencies ImmutableList.Builder<TransitiveInfoCollection> directDepsBuilder = ImmutableList.builder(); for (PrerequisiteAttr prerequisiteAttr : prerequisiteAttrs) { if (ruleContext.attributes().has(prerequisiteAttr.name, prerequisiteAttr.type)) { Mode mode = ruleContext.getAttributeMode(prerequisiteAttr.name); if (mode == Mode.TARGET || mode == Mode.SPLIT) { directDepsBuilder.addAll(ruleContext.getPrerequisites(prerequisiteAttr.name, Mode.TARGET)); } } } List<TransitiveInfoCollection> directDeps = directDepsBuilder.build(); // Add exports from direct dependencies NestedSetBuilder<Label> dependenciesBuilder = NestedSetBuilder.stableOrder(); for (AndroidStudioInfoFilesProvider depProvider : AnalysisUtils.getProviders(directDeps, AndroidStudioInfoFilesProvider.class)) { dependenciesBuilder.addTransitive(depProvider.getExportedDeps()); } for (TransitiveInfoCollection dep : directDeps) { dependenciesBuilder.add(dep.getLabel()); } NestedSet<Label> dependencies = dependenciesBuilder.build(); // Propagate my own exports JavaExportsProvider javaExportsProvider = base.getProvider(JavaExportsProvider.class); if (javaExportsProvider != null) { providerBuilder.exportedDepsBuilder().addTransitive(javaExportsProvider.getTransitiveExports()); } // android_library without sources exports all its deps if (ruleContext.getRule().getRuleClass().equals("android_library")) { JavaSourceInfoProvider sourceInfoProvider = base.getProvider(JavaSourceInfoProvider.class); boolean hasSources = sourceInfoProvider != null && !sourceInfoProvider.getSourceFiles().isEmpty(); if (!hasSources) { for (TransitiveInfoCollection dep : directDeps) { providerBuilder.exportedDepsBuilder().add(dep.getLabel()); } } } // runtime_deps List<? extends TransitiveInfoCollection> runtimeDeps = ImmutableList.of(); NestedSetBuilder<Label> runtimeDepsBuilder = NestedSetBuilder.stableOrder(); if (ruleContext.attributes().has("runtime_deps", BuildType.LABEL_LIST)) { runtimeDeps = ruleContext.getPrerequisites("runtime_deps", Mode.TARGET); for (TransitiveInfoCollection dep : runtimeDeps) { runtimeDepsBuilder.add(dep.getLabel()); } } // resources @Nullable TransitiveInfoCollection resources = ruleContext.attributes().has("resources", BuildType.LABEL) ? ruleContext.getPrerequisite("resources", Mode.TARGET) : null; // Propagate providers from all prerequisites (deps + runtime_deps) ImmutableList.Builder<TransitiveInfoCollection> prerequisitesBuilder = ImmutableList.builder(); prerequisitesBuilder.addAll(directDeps); prerequisitesBuilder.addAll(runtimeDeps); if (resources != null) { prerequisitesBuilder.add(resources); } List<TransitiveInfoCollection> prerequisites = prerequisitesBuilder.build(); for (AndroidStudioInfoFilesProvider depProvider : AnalysisUtils.getProviders(prerequisites, AndroidStudioInfoFilesProvider.class)) { providerBuilder.ideInfoFilesBuilder().addTransitive(depProvider.getIdeInfoFiles()); providerBuilder.ideInfoTextFilesBuilder().addTransitive(depProvider.getIdeInfoTextFiles()); providerBuilder.ideResolveFilesBuilder().addTransitive(depProvider.getIdeResolveFiles()); } return new DependenciesResult(dependencies, runtimeDepsBuilder.build(), resources != null ? resources.getLabel() : null); } private AndroidStudioInfoFilesProvider createIdeBuildArtifact(ConfiguredTarget base, RuleContext ruleContext, DependenciesResult dependenciesResult, AndroidStudioInfoFilesProvider.Builder providerBuilder) { Artifact ideInfoFile = derivedArtifact(base, ruleContext, ASWB_BUILD_SUFFIX); Artifact ideInfoTextFile = derivedArtifact(base, ruleContext, ASWB_BUILD_TEXT_SUFFIX); providerBuilder.ideInfoFilesBuilder().add(ideInfoFile); providerBuilder.ideInfoTextFilesBuilder().add(ideInfoTextFile); NestedSetBuilder<Artifact> ideResolveArtifacts = providerBuilder.ideResolveFilesBuilder(); TargetIdeInfo.Builder outputBuilder = TargetIdeInfo.newBuilder(); outputBuilder.setLabel(base.getLabel().toString()); outputBuilder.setBuildFileArtifactLocation( makeArtifactLocation(ruleContext.getRule().getPackage(), ruleContext.getLabel())); outputBuilder.setKindString(ruleContext.getRule().getRuleClass()); // Java rules JavaRuleOutputJarsProvider outputJarsProvider = base.getProvider(JavaRuleOutputJarsProvider.class); if (outputJarsProvider != null && !androidStudioInfoSemantics.suppressJavaRuleInfo(base)) { JavaIdeInfo javaIdeInfo = makeJavaIdeInfo(base, ruleContext, outputJarsProvider, providerBuilder); outputBuilder.setJavaIdeInfo(javaIdeInfo); } // C rules if (isCppRule(base)) { CppCompilationContext cppCompilationContext = base.getProvider(CppCompilationContext.class); if (cppCompilationContext != null) { CIdeInfo cIdeInfo = makeCIdeInfo(base, ruleContext, cppCompilationContext, ideResolveArtifacts); outputBuilder.setCIdeInfo(cIdeInfo); } } // CCToolchain rule CcToolchainProvider ccToolchainProvider = base.getProvider(CcToolchainProvider.class); if (ccToolchainProvider != null) { CppConfiguration cppConfiguration = ccToolchainProvider.getCppConfiguration(); if (cppConfiguration != null) { CToolchainIdeInfo cToolchainIdeInfo = makeCToolchainIdeInfo(ruleContext, cppConfiguration); if (cToolchainIdeInfo != null) { outputBuilder.setCToolchainIdeInfo(cToolchainIdeInfo); } } } // Android rules AndroidIdeInfoProvider androidIdeInfoProvider = base.getProvider(AndroidIdeInfoProvider.class); if (androidIdeInfoProvider != null) { outputBuilder.setAndroidIdeInfo( makeAndroidIdeInfo(androidIdeInfoProvider, dependenciesResult, ideResolveArtifacts)); } // Python rules if (isPythonRule(base)) { outputBuilder.setPyIdeInfo(makePyIdeInfo(base, ruleContext, ideResolveArtifacts)); } // Test rules if (TargetUtils.isTestRule(base.getTarget())) { TestInfo.Builder builder = TestInfo.newBuilder(); String attr = NonconfigurableAttributeMapper.of(base.getTarget().getAssociatedRule()).get("size", Type.STRING); if (attr != null) { builder.setSize(attr); } outputBuilder.setTestInfo(builder); } // Java toolchain rule JavaToolchainProvider javaToolchainProvider = base.getProvider(JavaToolchainProvider.class); if (javaToolchainProvider != null) { outputBuilder.setJavaToolchainIdeInfo( JavaToolchainIdeInfo.newBuilder().setSourceVersion(javaToolchainProvider.getSourceVersion()) .setTargetVersion(javaToolchainProvider.getTargetVersion())); } androidStudioInfoSemantics.augmentRuleInfo(outputBuilder, base, ruleContext, ideResolveArtifacts); AndroidStudioInfoFilesProvider provider = providerBuilder.build(); outputBuilder.addAllDependencies(transform(dependenciesResult.deps, LABEL_TO_STRING)); outputBuilder.addAllRuntimeDeps(transform(dependenciesResult.runtimeDeps, LABEL_TO_STRING)); outputBuilder.addAllTags(base.getTarget().getAssociatedRule().getRuleTags()); final TargetIdeInfo targetIdeInfo = outputBuilder.build(); ruleContext.registerAction(makeProtoWriteAction(ruleContext.getActionOwner(), targetIdeInfo, ideInfoFile)); ruleContext.registerAction( makeProtoTextWriteAction(ruleContext.getActionOwner(), targetIdeInfo, ideInfoTextFile)); return provider; } private boolean isCppRule(ConfiguredTarget base) { String ruleClass = base.getTarget().getAssociatedRule().getRuleClass(); switch (ruleClass) { case "cc_library": case "cc_binary": case "cc_test": case "cc_inc_library:": return true; default: // Fall through } return androidStudioInfoSemantics.checkForAdditionalCppRules(ruleClass); } private boolean isPythonRule(ConfiguredTarget base) { String ruleClass = base.getTarget().getAssociatedRule().getRuleClass(); switch (ruleClass) { case "py_library": case "py_binary": case "py_test": return true; default: // Fall through } return androidStudioInfoSemantics.checkForAdditionalPythonRules(ruleClass); } private static Action[] makePackageManifestAction(RuleContext ruleContext, Artifact packageManifest, Collection<Artifact> sourceFiles) { return new SpawnAction.Builder().addInputs(sourceFiles).addOutput(packageManifest) .setExecutable(ruleContext.getExecutablePrerequisite("$packageParser", Mode.HOST)) .setCommandLine(CustomCommandLine.builder().addExecPath("--output_manifest", packageManifest) .addJoinStrings("--sources", ":", toSerializedArtifactLocations(sourceFiles)).build()) .useParameterFile(ParameterFileType.SHELL_QUOTED) .setProgressMessage("Parsing java package strings for " + ruleContext.getRule()) .setMnemonic("JavaPackageManifest").build(ruleContext); } private static Iterable<String> toSerializedArtifactLocations(Iterable<Artifact> artifacts) { return Iterables.transform(Iterables.filter(artifacts, Artifact.MIDDLEMAN_FILTER), PACKAGE_PARSER_SERIALIZER); } private static final Function<Artifact, String> PACKAGE_PARSER_SERIALIZER = new Function<Artifact, String>() { @Override public String apply(Artifact artifact) { Root root = artifact.getRoot(); return Joiner.on(",").join(root.getExecPath().toString(), artifact.getRootRelativePath().toString()); } }; private static Action[] makeFilteredJarAction(RuleContext ruleContext, List<Artifact> filterJars, List<Artifact> filterSourceJars, List<Artifact> keepJavaFiles, List<Artifact> keepSourceJars, Artifact filteredJar, Artifact filteredSrcJar) { CustomCommandLine.Builder commandLine = CustomCommandLine.builder() .addJoinExecPaths("--filter_jars", File.pathSeparator, filterJars) .addJoinExecPaths("--filter_source_jars", File.pathSeparator, filterSourceJars) .addExecPath("--filtered_jar", filteredJar).addExecPath("--filtered_source_jar", filteredSrcJar); if (!keepJavaFiles.isEmpty()) { commandLine.addJoinExecPaths("--keep_java_files", File.pathSeparator, keepJavaFiles); } if (!keepSourceJars.isEmpty()) { commandLine.addJoinExecPaths("--keep_source_jars", File.pathSeparator, keepSourceJars); } return new SpawnAction.Builder().addInputs(filterJars).addInputs(filterSourceJars).addInputs(keepJavaFiles) .addInputs(keepSourceJars).addOutput(filteredJar).addOutput(filteredSrcJar) .setExecutable(ruleContext.getExecutablePrerequisite("$jarFilter", Mode.HOST)) .setCommandLine(commandLine.build()).useParameterFile(ParameterFileType.SHELL_QUOTED) .setProgressMessage("Filtering generated code for " + ruleContext.getRule()) .setMnemonic("JarFilter").build(ruleContext); } private static Artifact derivedArtifact(ConfiguredTarget base, RuleContext ruleContext, String suffix) { BuildConfiguration configuration = ruleContext.getConfiguration(); assert configuration != null; Root binDirectory = configuration.getBinDirectory(ruleContext.getRule().getRepository()); PathFragment derivedFilePath = getOutputFilePath(base, ruleContext, suffix); return ruleContext.getAnalysisEnvironment().getDerivedArtifact(derivedFilePath, binDirectory); } private static AndroidIdeInfo makeAndroidIdeInfo(AndroidIdeInfoProvider androidIdeInfoProvider, DependenciesResult dependenciesResult, NestedSetBuilder<Artifact> ideResolveArtifacts) { AndroidIdeInfo.Builder builder = AndroidIdeInfo.newBuilder(); if (androidIdeInfoProvider.getSignedApk() != null) { builder.setApk(makeArtifactLocation(androidIdeInfoProvider.getSignedApk())); } Artifact manifest = androidIdeInfoProvider.getManifest(); if (manifest != null) { builder.setManifest(makeArtifactLocation(manifest)); addResolveArtifact(ideResolveArtifacts, manifest); } for (Artifact artifact : androidIdeInfoProvider.getApksUnderTest()) { builder.addDependencyApk(makeArtifactLocation(artifact)); } for (SourceDirectory resourceDir : androidIdeInfoProvider.getResourceDirs()) { ArtifactLocation artifactLocation = makeArtifactLocation(resourceDir); builder.addResources(artifactLocation); } if (androidIdeInfoProvider.getJavaPackage() != null) { builder.setJavaPackage(androidIdeInfoProvider.getJavaPackage()); } String idlImportRoot = androidIdeInfoProvider.getIdlImportRoot(); if (idlImportRoot != null) { builder.setIdlImportRoot(idlImportRoot); } boolean hasIdlSources = !androidIdeInfoProvider.getIdlSrcs().isEmpty(); builder.setHasIdlSources(hasIdlSources); if (hasIdlSources) { LibraryArtifact idlLibraryArtifact = makeLibraryArtifact(ideResolveArtifacts, androidIdeInfoProvider.getIdlClassJar(), null, androidIdeInfoProvider.getIdlSourceJar()); if (idlLibraryArtifact != null) { builder.setIdlJar(idlLibraryArtifact); } } builder.setGenerateResourceClass(androidIdeInfoProvider.definesAndroidResources()); if (dependenciesResult.resources != null) { builder.setLegacyResources(dependenciesResult.resources.toString()); } OutputJar resourceJar = androidIdeInfoProvider.getResourceJar(); if (resourceJar != null) { LibraryArtifact resourceLibraryArtifact = makeLibraryArtifact(ideResolveArtifacts, resourceJar.getClassJar(), resourceJar.getIJar(), resourceJar.getSrcJar()); if (resourceLibraryArtifact != null) { builder.setResourceJar(resourceLibraryArtifact); } } return builder.build(); } private static BinaryFileWriteAction makeProtoWriteAction(ActionOwner actionOwner, final MessageLite message, Artifact artifact) { return new BinaryFileWriteAction(actionOwner, artifact, new ByteSource() { @Override public InputStream openStream() throws IOException { return message.toByteString().newInput(); } }, /*makeExecutable =*/ false); } private static BinaryFileWriteAction makeProtoTextWriteAction(ActionOwner actionOwner, final MessageLite message, Artifact artifact) { return new BinaryFileWriteAction(actionOwner, artifact, new ByteSource() { @Override public InputStream openStream() throws IOException { return new ByteArrayInputStream(message.toString().getBytes(StandardCharsets.UTF_8)); } }, /*makeExecutable =*/ false); } public static ArtifactLocation makeArtifactLocation(Artifact artifact) { return makeArtifactLocation(artifact.getRoot(), artifact.getRootRelativePath(), isExternal(artifact.getOwner())); } private static ArtifactLocation makeArtifactLocation(Package pkg, Label label) { Root root = Root.asSourceRoot(pkg.getSourceRoot(), pkg.getPackageIdentifier().getRepository().isMain()); PathFragment relativePath = pkg.getBuildFile().getPath().relativeTo(root.getPath()); return makeArtifactLocation(root, relativePath, isExternal(label)); } @VisibleForTesting static ArtifactLocation makeArtifactLocation(Root root, PathFragment relativePath, boolean isExternal) { return ArtifactLocation.newBuilder().setRootExecutionPathFragment(root.getExecPath().toString()) .setRelativePath(relativePath.toString()).setIsSource(root.isSourceRoot()).setIsExternal(isExternal) .build(); } private static ArtifactLocation makeArtifactLocation(SourceDirectory resourceDir) { return ArtifactLocation.newBuilder() .setRootExecutionPathFragment(resourceDir.getRootExecutionPathFragment().toString()) .setRelativePath(resourceDir.getRelativePath().toString()).setIsSource(resourceDir.isSource()) .setIsExternal(false).build(); } /** Returns whether this {@link Label} refers to an external repository. */ private static boolean isExternal(Label label) { return label.getWorkspaceRoot().startsWith("external"); } private JavaIdeInfo makeJavaIdeInfo(ConfiguredTarget base, RuleContext ruleContext, JavaRuleOutputJarsProvider outputJarsProvider, AndroidStudioInfoFilesProvider.Builder providerBuilder) { NestedSetBuilder<Artifact> ideResolveArtifacts = providerBuilder.ideResolveFilesBuilder(); JavaIdeInfo.Builder builder = JavaIdeInfo.newBuilder(); List<Artifact> javaSources = Lists.newArrayList(); List<Artifact> generatedJavaSources = Lists.newArrayList(); List<Artifact> srcjars = Lists.newArrayList(); divideJavaSources(ruleContext, javaSources, generatedJavaSources, srcjars); if (!javaSources.isEmpty()) { Artifact packageManifest = derivedArtifact(base, ruleContext, ".manifest"); providerBuilder.ideInfoFilesBuilder().add(packageManifest); ruleContext.registerAction(makePackageManifestAction(ruleContext, packageManifest, javaSources)); builder.setPackageManifest(makeArtifactLocation(packageManifest)); } // HACK -- android_library rules with the resources attribute do not support srcjar inputs // to the filtered gen jar generation, because we don't want all resource classes in this jar. // This can be removed once android_resources is deleted if (ruleContext.attributes().has("resources", BuildType.LABEL) && ruleContext.getRule().getRuleClass().startsWith("android_")) { srcjars = ImmutableList.of(); } if (!javaSources.isEmpty() && (!generatedJavaSources.isEmpty() || !srcjars.isEmpty())) { Artifact filteredGenJar = derivedArtifact(base, ruleContext, "-filtered-gen.jar"); Artifact filteredGenSrcJar = derivedArtifact(base, ruleContext, "-filtered-gen-src.jar"); List<Artifact> jars = Lists.newArrayList(); List<Artifact> sourceJars = Lists.newArrayList(); for (OutputJar outputJar : outputJarsProvider.getOutputJars()) { Artifact jar = outputJar.getIJar(); if (jar == null) { jar = outputJar.getClassJar(); } if (jar != null) { jars.add(jar); } if (outputJar.getSrcJar() != null) { sourceJars.add(outputJar.getSrcJar()); } } ruleContext.registerAction(makeFilteredJarAction(ruleContext, jars, sourceJars, generatedJavaSources, srcjars, filteredGenJar, filteredGenSrcJar)); ideResolveArtifacts.add(filteredGenJar); ideResolveArtifacts.add(filteredGenSrcJar); builder.setFilteredGenJar( makeLibraryArtifact(ideResolveArtifacts, filteredGenJar, null, filteredGenSrcJar)); } collectJarsFromOutputJarsProvider(builder, ideResolveArtifacts, outputJarsProvider); Artifact jdeps = outputJarsProvider.getJdeps(); if (jdeps != null) { builder.setJdeps(makeArtifactLocation(jdeps)); } JavaGenJarsProvider genJarsProvider = base.getProvider(JavaGenJarsProvider.class); if (genJarsProvider != null) { collectGenJars(builder, ideResolveArtifacts, genJarsProvider); } Collection<Artifact> sourceFiles = getSources(ruleContext); for (Artifact sourceFile : sourceFiles) { builder.addSources(makeArtifactLocation(sourceFile)); } return builder.build(); } private CIdeInfo makeCIdeInfo(ConfiguredTarget base, RuleContext ruleContext, CppCompilationContext cppCompilationContext, NestedSetBuilder<Artifact> ideResolveArtifacts) { CIdeInfo.Builder builder = CIdeInfo.newBuilder(); Collection<Artifact> sourceFiles = getSources(ruleContext); for (Artifact sourceFile : sourceFiles) { builder.addSource(makeArtifactLocation(sourceFile)); } ideResolveArtifacts.addTransitive(cppCompilationContext.getDeclaredIncludeSrcs()); builder.addAllTargetInclude(getIncludes(ruleContext)); builder.addAllTargetDefine(getDefines(ruleContext)); builder.addAllTargetCopt(getCopts(ruleContext)); // Get information about from the transitive closure ImmutableList<PathFragment> transitiveIncludeDirectories = cppCompilationContext.getIncludeDirs(); for (PathFragment pathFragment : transitiveIncludeDirectories) { builder.addTransitiveIncludeDirectory(pathFragment.getSafePathString()); } ImmutableList<PathFragment> transitiveQuoteIncludeDirectories = cppCompilationContext.getQuoteIncludeDirs(); for (PathFragment pathFragment : transitiveQuoteIncludeDirectories) { builder.addTransitiveQuoteIncludeDirectory(pathFragment.getSafePathString()); } ImmutableList<String> transitiveDefines = cppCompilationContext.getDefines(); for (String transitiveDefine : transitiveDefines) { builder.addTransitiveDefine(transitiveDefine); } ImmutableList<PathFragment> transitiveSystemIncludeDirectories = cppCompilationContext .getSystemIncludeDirs(); for (PathFragment pathFragment : transitiveSystemIncludeDirectories) { builder.addTransitiveSystemIncludeDirectory(pathFragment.getSafePathString()); } androidStudioInfoSemantics.augmentCppRuleInfo(builder, base, ruleContext, cppCompilationContext, ideResolveArtifacts); return builder.build(); } private static CToolchainIdeInfo makeCToolchainIdeInfo(RuleContext ruleContext, CppConfiguration cppConfiguration) { CToolchainIdeInfo.Builder builder = CToolchainIdeInfo.newBuilder(); ImmutableSet<String> features = ruleContext.getFeatures(); builder.setTargetName(cppConfiguration.getTargetGnuSystemName()); builder.addAllBaseCompilerOption(cppConfiguration.getCompilerOptions(features)); builder.addAllCOption(cppConfiguration.getCOptions()); builder.addAllCppOption(cppConfiguration.getCxxOptions(features)); builder.addAllLinkOption(cppConfiguration.getLinkOptions()); // This includes options such as system includes from toolchains. builder.addAllUnfilteredCompilerOption(cppConfiguration.getUnfilteredCompilerOptions(features)); builder.setPreprocessorExecutable(cppConfiguration.getCpreprocessorExecutable().getSafePathString()); builder.setCppExecutable(cppConfiguration.getCppExecutable().getSafePathString()); List<PathFragment> builtInIncludeDirectories = cppConfiguration.getBuiltInIncludeDirectories(); for (PathFragment builtInIncludeDirectory : builtInIncludeDirectories) { builder.addBuiltInIncludeDirectory(builtInIncludeDirectory.getSafePathString()); } return builder.build(); } private static PyIdeInfo makePyIdeInfo(ConfiguredTarget base, RuleContext ruleContext, NestedSetBuilder<Artifact> ideResolveArtifacts) { PyIdeInfo.Builder builder = PyIdeInfo.newBuilder(); Collection<Artifact> sourceFiles = getSources(ruleContext); for (Artifact sourceFile : sourceFiles) { builder.addSources(makeArtifactLocation(sourceFile)); } // Ensure we add all generated sources to the ide-resolve output group. // See {@link PyCommon#collectTransitivePythonSources}. OutputGroupProvider outputGroupProvider = base.getProvider(OutputGroupProvider.class); if (outputGroupProvider != null) { ideResolveArtifacts .addTransitive(outputGroupProvider.getOutputGroup(OutputGroupProvider.FILES_TO_COMPILE)); } return builder.build(); } private static void collectJarsFromOutputJarsProvider(JavaIdeInfo.Builder builder, NestedSetBuilder<Artifact> ideResolveArtifacts, JavaRuleOutputJarsProvider outputJarsProvider) { for (OutputJar outputJar : outputJarsProvider.getOutputJars()) { LibraryArtifact libraryArtifact = makeLibraryArtifact(ideResolveArtifacts, outputJar.getClassJar(), outputJar.getIJar(), outputJar.getSrcJar()); if (libraryArtifact != null) { builder.addJars(libraryArtifact); } } } @Nullable private static LibraryArtifact makeLibraryArtifact(NestedSetBuilder<Artifact> ideResolveArtifacts, @Nullable Artifact classJar, @Nullable Artifact iJar, @Nullable Artifact sourceJar) { // We don't want to add anything that doesn't have a class jar if (classJar == null) { return null; } LibraryArtifact.Builder jarsBuilder = LibraryArtifact.newBuilder(); jarsBuilder.setJar(makeArtifactLocation(classJar)); addResolveArtifact(ideResolveArtifacts, classJar); if (iJar != null) { jarsBuilder.setInterfaceJar(makeArtifactLocation(iJar)); addResolveArtifact(ideResolveArtifacts, iJar); } if (sourceJar != null) { jarsBuilder.setSourceJar(makeArtifactLocation(sourceJar)); addResolveArtifact(ideResolveArtifacts, sourceJar); } return jarsBuilder.build(); } private static void collectGenJars(JavaIdeInfo.Builder builder, NestedSetBuilder<Artifact> ideResolveArtifacts, JavaGenJarsProvider genJarsProvider) { LibraryArtifact.Builder genjarsBuilder = LibraryArtifact.newBuilder(); if (genJarsProvider.usesAnnotationProcessing()) { Artifact genClassJar = genJarsProvider.getGenClassJar(); if (genClassJar != null) { genjarsBuilder.setJar(makeArtifactLocation(genClassJar)); addResolveArtifact(ideResolveArtifacts, genClassJar); } Artifact gensrcJar = genJarsProvider.getGenSourceJar(); if (gensrcJar != null) { genjarsBuilder.setSourceJar(makeArtifactLocation(gensrcJar)); addResolveArtifact(ideResolveArtifacts, gensrcJar); } if (genjarsBuilder.hasJar()) { builder.addGeneratedJars(genjarsBuilder.build()); } } } private static void divideJavaSources(RuleContext ruleContext, List<Artifact> javaSources, List<Artifact> generatedSources, List<Artifact> srcjars) { Collection<Artifact> srcs = getSources(ruleContext); for (Artifact src : srcs) { if (src.getRootRelativePathString().endsWith(".java")) { if (src.isSourceArtifact()) { javaSources.add(src); } else { generatedSources.add(src); } } else if (src.getRootRelativePathString().endsWith(".srcjar")) { srcjars.add(src); } } } private static Collection<Artifact> getSources(RuleContext ruleContext) { return getTargetListAttribute(ruleContext, "srcs"); } private static Collection<String> getIncludes(RuleContext ruleContext) { return getStringListAttribute(ruleContext, "includes"); } private static Collection<String> getDefines(RuleContext ruleContext) { return getStringListAttribute(ruleContext, "defines"); } private static Collection<String> getCopts(RuleContext ruleContext) { return getStringListAttribute(ruleContext, "copts"); } private static Collection<Artifact> getTargetListAttribute(RuleContext ruleContext, String attributeName) { return (ruleContext.attributes().has(attributeName, BuildType.LABEL_LIST) && ruleContext.getAttributeMode(attributeName) == Mode.TARGET) ? ruleContext.getPrerequisiteArtifacts(attributeName, Mode.TARGET).list() : ImmutableList.<Artifact>of(); } private static Collection<String> getStringListAttribute(RuleContext ruleContext, String attributeName) { return ruleContext.attributes().has(attributeName, Type.STRING_LIST) ? ruleContext.attributes().get(attributeName, Type.STRING_LIST) : ImmutableList.<String>of(); } private static PathFragment getOutputFilePath(ConfiguredTarget base, RuleContext ruleContext, String suffix) { PathFragment packagePathFragment = ruleContext.getLabel().getPackageIdentifier().getSourceRoot(); String name = base.getLabel().getName(); return new PathFragment(packagePathFragment, new PathFragment(name + suffix)); } private static void addResolveArtifact(NestedSetBuilder<Artifact> ideResolveArtifacts, Artifact artifact) { if (!artifact.isSourceArtifact()) { ideResolveArtifacts.add(artifact); } } }