aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Dmitry Lomov <dslomov@google.com>2015-09-22 11:58:30 +0000
committerGravatar Laszlo Csomor <laszlocsomor@google.com>2015-09-22 17:07:47 +0000
commit590767e9118a3709e49c44fb77130aa4203d0841 (patch)
treeabddccb9aa2e9b7f89e6eb5205f79c0b7e30bc23 /src
parent6bd4f2da3288a1508bdafe3072a1a2f611eb8316 (diff)
Implement support for android_library and android_binary in AndroidStudioInfoAspect.
-- MOS_MIGRATED_REVID=103635637
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidSemantics.java18
-rw-r--r--src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspect.java125
-rw-r--r--src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoFilesProvider.java12
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java34
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java65
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdeInfoProvider.java338
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java40
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java27
-rw-r--r--src/main/protobuf/android_studio_ide_info.proto20
-rw-r--r--src/test/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspectTest.java103
10 files changed, 711 insertions, 71 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidSemantics.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidSemantics.java
index 366bfcfad1..73b3a5c7be 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidSemantics.java
@@ -21,6 +21,7 @@ import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
import com.google.devtools.build.lib.rules.android.AndroidCommon;
+import com.google.devtools.build.lib.rules.android.AndroidIdeInfoProvider;
import com.google.devtools.build.lib.rules.android.AndroidSemantics;
import com.google.devtools.build.lib.rules.android.ApplicationManifest;
import com.google.devtools.build.lib.rules.android.ResourceApk;
@@ -39,11 +40,18 @@ public class BazelAndroidSemantics implements AndroidSemantics {
}
@Override
- public void addTransitiveInfoProviders(RuleConfiguredTargetBuilder builder,
- RuleContext ruleContext, JavaCommon javaCommon, AndroidCommon androidCommon,
- Artifact jarWithAllClasses, ResourceApk resourceApk, Artifact zipAlignedApk,
- Iterable<Artifact> apksUnderTest) {
- }
+ public void addNonLocalResources(
+ RuleContext ruleContext,
+ ResourceApk resourceApk,
+ AndroidIdeInfoProvider.Builder ideInfoProviderBuilder) {}
+
+ @Override
+ public void addTransitiveInfoProviders(
+ RuleConfiguredTargetBuilder builder,
+ RuleContext ruleContext,
+ JavaCommon javaCommon,
+ AndroidCommon androidCommon,
+ Artifact jarWithAllClasses) {}
@Override
public ApplicationManifest getManifestForRule(RuleContext ruleContext) {
diff --git a/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspect.java b/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspect.java
index 5a32d0a872..ebf01e32ff 100644
--- a/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspect.java
@@ -33,6 +33,7 @@ import com.google.devtools.build.lib.analysis.actions.BinaryFileWriteAction;
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.ideinfo.androidstudio.AndroidStudioIdeInfo.AndroidRuleIdeInfo;
import com.google.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo.AndroidSdkRuleInfo;
import com.google.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo.ArtifactLocation;
import com.google.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo.JavaRuleIdeInfo;
@@ -43,10 +44,14 @@ 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.Rule;
+import com.google.devtools.build.lib.rules.android.AndroidCommon;
+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.android.AndroidSdkProvider;
import com.google.devtools.build.lib.rules.java.JavaExportsProvider;
import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider;
import com.google.devtools.build.lib.rules.java.JavaSourceInfoProvider;
+import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.protobuf.MessageLite;
@@ -81,7 +86,6 @@ public class AndroidStudioInfoAspect implements ConfiguredAspectFactory {
@Override
public AspectDefinition getDefinition() {
return new AspectDefinition.Builder(NAME)
- .requireProvider(JavaSourceInfoProvider.class)
.attributeAspect("deps", AndroidStudioInfoAspect.class)
.build();
}
@@ -94,6 +98,7 @@ public class AndroidStudioInfoAspect implements ConfiguredAspectFactory {
// Collect ide build files and calculate dependencies.
NestedSetBuilder<Label> transitiveDependenciesBuilder = NestedSetBuilder.stableOrder();
NestedSetBuilder<Label> dependenciesBuilder = NestedSetBuilder.stableOrder();
+ NestedSetBuilder<SourceDirectory> transitiveResourcesBuilder = NestedSetBuilder.stableOrder();
NestedSetBuilder<Artifact> ideBuildFilesBuilder = NestedSetBuilder.stableOrder();
@@ -106,6 +111,7 @@ public class AndroidStudioInfoAspect implements ConfiguredAspectFactory {
for (AndroidStudioInfoFilesProvider depProvider : androidStudioInfoFilesProviders) {
ideBuildFilesBuilder.addTransitive(depProvider.getIdeBuildFiles());
transitiveDependenciesBuilder.addTransitive(depProvider.getTransitiveDependencies());
+ transitiveResourcesBuilder.addTransitive(depProvider.getTransitiveResources());
}
List<? extends TransitiveInfoCollection> deps =
ruleContext.getPrerequisites("deps", Mode.TARGET);
@@ -126,12 +132,20 @@ public class AndroidStudioInfoAspect implements ConfiguredAspectFactory {
RuleIdeInfo.Kind ruleKind = getRuleKind(ruleContext.getRule(), base);
+ NestedSet<SourceDirectory> transitiveResources;
if (ruleKind != RuleIdeInfo.Kind.UNRECOGNIZED) {
- Artifact ideBuildFile =
- createIdeBuildArtifact(base, ruleContext, ruleKind,
+ Pair<Artifact, NestedSet<SourceDirectory>> ideBuildFile =
+ createIdeBuildArtifact(
+ base,
+ ruleContext,
+ ruleKind,
directDependencies,
- transitiveDependencies);
- ideBuildFilesBuilder.add(ideBuildFile);
+ transitiveDependencies,
+ transitiveResourcesBuilder);
+ ideBuildFilesBuilder.add(ideBuildFile.first);
+ transitiveResources = ideBuildFile.second;
+ } else {
+ transitiveResources = transitiveResourcesBuilder.build();
}
NestedSet<Artifact> ideBuildFiles = ideBuildFilesBuilder.build();
@@ -139,7 +153,8 @@ public class AndroidStudioInfoAspect implements ConfiguredAspectFactory {
.addOutputGroup(IDE_BUILD, ideBuildFiles)
.addProvider(
AndroidStudioInfoFilesProvider.class,
- new AndroidStudioInfoFilesProvider(ideBuildFiles, transitiveDependencies));
+ new AndroidStudioInfoFilesProvider(
+ ideBuildFiles, transitiveDependencies, transitiveResources));
return builder.build();
}
@@ -160,11 +175,13 @@ public class AndroidStudioInfoAspect implements ConfiguredAspectFactory {
return sdkInfoBuilder.build();
}
- private Artifact createIdeBuildArtifact(
+ private Pair<Artifact, NestedSet<SourceDirectory>> createIdeBuildArtifact(
ConfiguredTarget base,
RuleContext ruleContext,
Kind ruleKind,
- NestedSet<Label> directDependencies, NestedSet<Label> transitiveDependencies) {
+ NestedSet<Label> directDependencies,
+ NestedSet<Label> transitiveDependencies,
+ NestedSetBuilder<SourceDirectory> transitiveResourcesBuilder) {
PathFragment ideBuildFilePath = getOutputFilePath(base, ruleContext);
Root genfilesDirectory = ruleContext.getConfiguration().getGenfilesDirectory();
Artifact ideBuildFile =
@@ -189,22 +206,69 @@ public class AndroidStudioInfoAspect implements ConfiguredAspectFactory {
outputBuilder.addAllDependencies(transform(directDependencies, LABEL_TO_STRING));
outputBuilder.addAllTransitiveDependencies(transform(transitiveDependencies, LABEL_TO_STRING));
+ NestedSet<SourceDirectory> transitiveResources = null;
if (ruleKind == Kind.JAVA_LIBRARY
|| ruleKind == Kind.JAVA_IMPORT
|| ruleKind == Kind.JAVA_TEST
|| ruleKind == Kind.JAVA_BINARY) {
outputBuilder.setJavaRuleIdeInfo(makeJavaRuleIdeInfo(base));
+ } else if (ruleKind == Kind.ANDROID_LIBRARY || ruleKind == Kind.ANDROID_BINARY) {
+ outputBuilder.setJavaRuleIdeInfo(makeJavaRuleIdeInfo(base));
+ Pair<AndroidRuleIdeInfo, NestedSet<SourceDirectory>> androidRuleIdeInfo =
+ makeAndroidRuleIdeInfo(ruleContext, base, transitiveResourcesBuilder);
+ outputBuilder.setAndroidRuleIdeInfo(androidRuleIdeInfo.first);
+ transitiveResources = androidRuleIdeInfo.second;
} else if (ruleKind == Kind.ANDROID_SDK) {
outputBuilder.setAndroidSdkRuleInfo(
makeAndroidSdkRuleInfo(ruleContext, base.getProvider(AndroidSdkProvider.class)));
}
+ if (transitiveResources == null) {
+ transitiveResources = transitiveResourcesBuilder.build();
+ }
final RuleIdeInfo ruleIdeInfo = outputBuilder.build();
ruleContext.registerAction(
makeProtoWriteAction(ruleContext.getActionOwner(), ruleIdeInfo, ideBuildFile));
- return ideBuildFile;
+ return Pair.of(ideBuildFile, transitiveResources);
+ }
+
+ private static Pair<AndroidRuleIdeInfo, NestedSet<SourceDirectory>> makeAndroidRuleIdeInfo(
+ RuleContext ruleContext,
+ ConfiguredTarget base,
+ NestedSetBuilder<SourceDirectory> transitiveResourcesBuilder) {
+ AndroidRuleIdeInfo.Builder builder = AndroidRuleIdeInfo.newBuilder();
+ AndroidIdeInfoProvider provider = base.getProvider(AndroidIdeInfoProvider.class);
+ if (provider.getSignedApk() != null) {
+ builder.setApk(makeArtifactLocation(provider.getSignedApk()));
+ }
+
+ if (provider.getManifest() != null) {
+ builder.setManifest(makeArtifactLocation(provider.getManifest()));
+ }
+
+ if (provider.getGeneratedManifest() != null) {
+ builder.setGeneratedManifest(makeArtifactLocation(provider.getGeneratedManifest()));
+ }
+
+ for (Artifact artifact : provider.getApksUnderTest()) {
+ builder.addDependencyApk(makeArtifactLocation(artifact));
+ }
+ for (SourceDirectory resourceDir : provider.getResourceDirs()) {
+ ArtifactLocation artifactLocation = makeArtifactLocation(resourceDir);
+ builder.addResources(artifactLocation);
+ transitiveResourcesBuilder.add(resourceDir);
+ }
+
+ builder.setJavaPackage(AndroidCommon.getJavaPackage(ruleContext));
+
+ NestedSet<SourceDirectory> transitiveResources = transitiveResourcesBuilder.build();
+ for (SourceDirectory transitiveResource : transitiveResources) {
+ builder.addTransitiveResources(makeArtifactLocation(transitiveResource));
+ }
+
+ return Pair.of(builder.build(), transitiveResources);
}
private static BinaryFileWriteAction makeProtoWriteAction(
@@ -228,6 +292,13 @@ public class AndroidStudioInfoAspect implements ConfiguredAspectFactory {
.build();
}
+ private static ArtifactLocation makeArtifactLocation(SourceDirectory resourceDir) {
+ return ArtifactLocation.newBuilder()
+ .setRootPath(resourceDir.getRootPath().toString())
+ .setRelativePath(resourceDir.getRelativePath().toString())
+ .build();
+ }
+
private static JavaRuleIdeInfo makeJavaRuleIdeInfo(ConfiguredTarget base) {
JavaRuleIdeInfo.Builder builder = JavaRuleIdeInfo.newBuilder();
JavaRuleOutputJarsProvider outputJarsProvider =
@@ -325,21 +396,27 @@ public class AndroidStudioInfoAspect implements ConfiguredAspectFactory {
}
private RuleIdeInfo.Kind getRuleKind(Rule rule, ConfiguredTarget base) {
- RuleIdeInfo.Kind kind;
- String ruleClassName = rule.getRuleClassObject().getName();
- if ("java_library".equals(ruleClassName)) {
- kind = RuleIdeInfo.Kind.JAVA_LIBRARY;
- } else if ("java_import".equals(ruleClassName)) {
- kind = Kind.JAVA_IMPORT;
- } else if ("java_test".equals(ruleClassName)) {
- kind = Kind.JAVA_TEST;
- } else if ("java_binary".equals(ruleClassName)) {
- kind = Kind.JAVA_BINARY;
- } else if (base.getProvider(AndroidSdkProvider.class) != null) {
- kind = RuleIdeInfo.Kind.ANDROID_SDK;
- } else {
- kind = RuleIdeInfo.Kind.UNRECOGNIZED;
+ switch (rule.getRuleClassObject().getName()) {
+ case "java_library":
+ return Kind.JAVA_LIBRARY;
+ case "java_import":
+ return Kind.JAVA_IMPORT;
+ case "java_test":
+ return Kind.JAVA_TEST;
+ case "java_binary":
+ return Kind.JAVA_BINARY;
+ case "android_library":
+ return Kind.ANDROID_LIBRARY;
+ case "android_binary":
+ return Kind.ANDROID_BINARY;
+ default:
+ {
+ if (base.getProvider(AndroidSdkProvider.class) != null) {
+ return RuleIdeInfo.Kind.ANDROID_SDK;
+ } else {
+ return RuleIdeInfo.Kind.UNRECOGNIZED;
+ }
+ }
}
- return kind;
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoFilesProvider.java b/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoFilesProvider.java
index 0cb61a8998..5d935310d1 100644
--- a/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoFilesProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoFilesProvider.java
@@ -19,6 +19,8 @@ import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.rules.android.AndroidIdeInfoProvider;
+import com.google.devtools.build.lib.rules.android.AndroidIdeInfoProvider.SourceDirectory;
/**
* File provider for Android Studio ide build files.
@@ -27,11 +29,15 @@ import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
public final class AndroidStudioInfoFilesProvider implements TransitiveInfoProvider {
private final NestedSet<Artifact> ideBuildFiles;
private final NestedSet<Label> transitiveDependencies;
+ private final NestedSet<AndroidIdeInfoProvider.SourceDirectory> transitiveResources;
public AndroidStudioInfoFilesProvider(
- NestedSet<Artifact> ideBuildFiles, NestedSet<Label> transitiveDependencies) {
+ NestedSet<Artifact> ideBuildFiles,
+ NestedSet<Label> transitiveDependencies,
+ NestedSet<SourceDirectory> transitiveResources) {
this.ideBuildFiles = ideBuildFiles;
this.transitiveDependencies = transitiveDependencies;
+ this.transitiveResources = transitiveResources;
}
public NestedSet<Artifact> getIdeBuildFiles() {
@@ -41,4 +47,8 @@ public final class AndroidStudioInfoFilesProvider implements TransitiveInfoProvi
public NestedSet<Label> getTransitiveDependencies() {
return transitiveDependencies;
}
+
+ public NestedSet<SourceDirectory> getTransitiveResources() {
+ return transitiveResources;
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
index 73e3b12722..81db9ac7cf 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
@@ -57,6 +57,7 @@ import com.google.devtools.build.lib.rules.java.DeployArchiveBuilder;
import com.google.devtools.build.lib.rules.java.JavaCommon;
import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider;
import com.google.devtools.build.lib.rules.java.JavaSemantics;
+import com.google.devtools.build.lib.rules.java.JavaSourceInfoProvider;
import com.google.devtools.build.lib.rules.java.JavaTargetAttributes;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -265,7 +266,9 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
Artifact deployJar = createDeployJar(ruleContext, javaSemantics, androidCommon, resourceClasses,
ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_BINARY_DEPLOY_JAR));
- return createAndroidBinary(ruleContext,
+
+ return createAndroidBinary(
+ ruleContext,
filesBuilder,
deployJar,
javaCommon,
@@ -506,9 +509,10 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
.add(splitDeployMarker)
.build();
- androidCommon.addTransitiveInfoProviders(builder);
- androidSemantics.addTransitiveInfoProviders(builder, ruleContext, javaCommon, androidCommon,
- jarToDex, resourceApk, zipAlignedApk, apksUnderTest);
+ androidCommon.addTransitiveInfoProviders(
+ builder, androidSemantics, resourceApk, zipAlignedApk, apksUnderTest);
+ androidSemantics.addTransitiveInfoProviders(
+ builder, ruleContext, javaCommon, androidCommon, jarToDex);
if (proguardOutput.mapping != null) {
builder.add(ProguardMappingProvider.class,
@@ -517,14 +521,20 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
return builder
.setFilesToBuild(filesToBuild)
- .add(RunfilesProvider.class, RunfilesProvider.simple(
- new Runfiles.Builder(ruleContext.getWorkspaceName())
- .addRunfiles(ruleContext, RunfilesProvider.DEFAULT_RUNFILES)
- .addTransitiveArtifacts(filesToBuild)
- .build()))
- .add(ApkProvider.class,
- new ApkProvider(NestedSetBuilder.create(Order.STABLE_ORDER, zipAlignedApk),
- coverageMetadata))
+ .add(
+ RunfilesProvider.class,
+ RunfilesProvider.simple(
+ new Runfiles.Builder(ruleContext.getWorkspaceName())
+ .addRunfiles(ruleContext, RunfilesProvider.DEFAULT_RUNFILES)
+ .addTransitiveArtifacts(filesToBuild)
+ .build()))
+ .add(
+ JavaSourceInfoProvider.class,
+ JavaSourceInfoProvider.fromJavaTargetAttributes(resourceClasses, javaSemantics))
+ .add(
+ ApkProvider.class,
+ new ApkProvider(
+ NestedSetBuilder.create(Order.STABLE_ORDER, zipAlignedApk), coverageMetadata))
.add(AndroidPreDexJarProvider.class, new AndroidPreDexJarProvider(jarToDex))
.addOutputGroup("mobile_install_full", fullDeployMarker)
.addOutputGroup("mobile_install_incremental", incrementalDeployMarker)
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java
index 86aa0c8072..8a26cbf35f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java
@@ -42,6 +42,7 @@ import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SafeImplicitOutputsFunction;
import com.google.devtools.build.lib.rules.android.AndroidResourcesProvider.ResourceContainer;
+import com.google.devtools.build.lib.rules.android.AndroidResourcesProvider.ResourceType;
import com.google.devtools.build.lib.rules.android.AndroidRuleClasses.MultidexMode;
import com.google.devtools.build.lib.rules.cpp.CcLinkParams;
import com.google.devtools.build.lib.rules.cpp.CcLinkParamsProvider;
@@ -58,10 +59,12 @@ import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider;
import com.google.devtools.build.lib.rules.java.JavaCompilationArtifacts;
import com.google.devtools.build.lib.rules.java.JavaCompilationHelper;
import com.google.devtools.build.lib.rules.java.JavaNativeLibraryProvider;
+import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider;
import com.google.devtools.build.lib.rules.java.JavaRuntimeJarProvider;
import com.google.devtools.build.lib.rules.java.JavaSemantics;
import com.google.devtools.build.lib.rules.java.JavaSourceJarsProvider;
import com.google.devtools.build.lib.rules.java.JavaTargetAttributes;
+import com.google.devtools.build.lib.rules.java.JavaUtil;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -207,6 +210,55 @@ public class AndroidCommon {
ruleContext.registerAction(builder.build(ruleContext));
}
+ public static AndroidIdeInfoProvider createAndroidIdeInfoProvider(
+ RuleContext ruleContext,
+ AndroidSemantics semantics,
+ ResourceApk resourceApk,
+ Artifact zipAlignedApk,
+ Iterable<Artifact> apksUnderTest) {
+ AndroidIdeInfoProvider.Builder ideInfoProviderBuilder =
+ new AndroidIdeInfoProvider.Builder()
+ .addIdlParcelables(getIdlParcelables(ruleContext))
+ .addIdlSrcs(getIdlSrcs(ruleContext))
+ .addAllApksUnderTest(apksUnderTest);
+
+ if (zipAlignedApk != null) {
+ ideInfoProviderBuilder.setApk(zipAlignedApk);
+ }
+
+ // If the rule defines resources, put those in the IDE info. Otherwise, proxy the data coming
+ // from the android_resources rule in its direct dependencies, if such a thing exists.
+ if (LocalResourceContainer.definesAndroidResources(ruleContext.attributes())) {
+ ideInfoProviderBuilder
+ .addResourceSources(resourceApk.getPrimaryResource().getArtifacts(ResourceType.RESOURCES))
+ .addAssetSources(
+ resourceApk.getPrimaryResource().getArtifacts(ResourceType.ASSETS),
+ getAssetDir(ruleContext))
+ // Sets the possibly merged manifest and the raw manifest.
+ .setGeneratedManifest(resourceApk.getPrimaryResource().getManifest())
+ .setManifest(ruleContext.getPrerequisiteArtifact("manifest", Mode.TARGET));
+ } else {
+ semantics.addNonLocalResources(ruleContext, resourceApk, ideInfoProviderBuilder);
+ }
+
+ return ideInfoProviderBuilder.build();
+ }
+
+ public static String getJavaPackage(RuleContext ruleContext) {
+ if (ruleContext.attributes().isAttributeValueExplicitlySpecified("custom_package")) {
+ return ruleContext.attributes().get("custom_package", Type.STRING);
+ } else {
+ PathFragment nameFragment = ruleContext.getRule().getPackage().getNameFragment();
+ String packageName = JavaUtil.getJavaFullClassname(nameFragment);
+ if (packageName != null) {
+ return packageName;
+ } else {
+ // This is a workaround for libraries that don't follow the standard Bazel package format
+ return nameFragment.getPathString().replace('/', '.');
+ }
+ }
+ }
+
Artifact compileDexWithJack(
MultidexMode mode, Optional<Artifact> mainDexList, Collection<Artifact> proguardSpecs) {
return jackCompilationHelper.compileAsDex(mode, mainDexList, proguardSpecs);
@@ -546,7 +598,11 @@ public class AndroidCommon {
}
public RuleConfiguredTargetBuilder addTransitiveInfoProviders(
- RuleConfiguredTargetBuilder builder) {
+ RuleConfiguredTargetBuilder builder,
+ AndroidSemantics androidSemantics,
+ ResourceApk resourceApk,
+ Artifact zipAlignedApk,
+ Iterable<Artifact> apksUnderTest) {
if (!idls.isEmpty()) {
generateAndroidIdlActions(
ruleContext, idls, transitiveIdlImportData, translatedIdlSources);
@@ -557,6 +613,9 @@ public class AndroidCommon {
.build();
javaCommon.addTransitiveInfoProviders(builder, filesToBuild, classJar);
+ builder.add(
+ JavaRuleOutputJarsProvider.class,
+ new JavaRuleOutputJarsProvider(classJar, srcJar, genJar, gensrcJar));
return builder
.setFilesToBuild(filesToBuild)
@@ -567,6 +626,10 @@ public class AndroidCommon {
.add(
AndroidResourcesProvider.class,
new AndroidResourcesProvider(ruleContext.getLabel(), transitiveResources))
+ .add(
+ AndroidIdeInfoProvider.class,
+ createAndroidIdeInfoProvider(
+ ruleContext, androidSemantics, resourceApk, zipAlignedApk, apksUnderTest))
.add(AndroidIdlProvider.class, transitiveIdlImportData)
.add(
JavaCompilationArgsProvider.class,
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdeInfoProvider.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdeInfoProvider.java
new file mode 100644
index 0000000000..5474ccbbd1
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdeInfoProvider.java
@@ -0,0 +1,338 @@
+// Copyright 2015 Google Inc. 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.android;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.Root;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.vfs.PathFragment;
+
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.Objects;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * An Android target provider to provide Android-specific info to IDEs.
+ */
+@Immutable
+public final class AndroidIdeInfoProvider implements TransitiveInfoProvider {
+ /** Represents a directory that contains sources, generated or otherwise, for an IDE.*/
+ @Immutable
+ public static class SourceDirectory {
+ final PathFragment relativePath;
+ final PathFragment rootPath;
+ final boolean isSource;
+
+ public SourceDirectory(PathFragment rootPath, PathFragment relativePath, boolean isSource) {
+ this.rootPath = rootPath;
+ this.relativePath = relativePath;
+ this.isSource = isSource;
+ }
+
+ /**
+ * The root relative path, {@link Artifact#getRootRelativePath()}.
+ */
+ public PathFragment getRelativePath() {
+ return relativePath;
+ }
+
+ /**
+ * The absolute path of the root that contains this directory, {@link Root#getPath()}.
+ */
+ public PathFragment getRootPath() {
+ return rootPath;
+ }
+
+ /** Indicates if the directory is in the gen files tree. */
+ boolean isSource() {
+ return isSource;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(relativePath, rootPath, isSource);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof SourceDirectory) {
+ SourceDirectory otherDir = (SourceDirectory) other;
+ return Objects.equals(rootPath, otherDir.rootPath)
+ && Objects.equals(relativePath, otherDir.relativePath)
+ && Objects.equals(isSource, otherDir.isSource);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "SourceDirectory [relativePath=" + relativePath + ", rootPath=" + rootPath
+ + ", isSource=" + isSource + "]";
+ }
+ }
+
+ /**
+ * Builder for {@link AndroidIdeInfoProvider}
+ */
+ public static class Builder {
+ private Artifact manifest = null;
+ private Artifact generatedManifest = null;
+ private Artifact apk = null;
+ private final Set<SourceDirectory> resourceDirs = new LinkedHashSet<>();
+ private final Set<SourceDirectory> assetDirs = new LinkedHashSet<>();
+ private final Set<SourceDirectory> idlDirs = new LinkedHashSet<>();
+ private final Set<Artifact> idlSrcs = new LinkedHashSet<>();
+ private final Set<Artifact> apksUnderTest = new LinkedHashSet<>();
+
+ public AndroidIdeInfoProvider build() {
+ return new AndroidIdeInfoProvider(
+ manifest,
+ generatedManifest,
+ apk,
+ ImmutableList.copyOf(assetDirs),
+ ImmutableList.copyOf(resourceDirs),
+ ImmutableList.copyOf(idlDirs),
+ ImmutableList.copyOf(idlSrcs),
+ ImmutableList.copyOf(apksUnderTest));
+ }
+
+ public Builder setApk(Artifact apk) {
+ Preconditions.checkState(this.apk == null);
+ this.apk = apk;
+ return this;
+ }
+
+ public Builder setManifest(Artifact manifest) {
+ Preconditions.checkState(this.manifest == null);
+ this.manifest = manifest;
+ return this;
+ }
+
+ public Builder setGeneratedManifest(Artifact manifest) {
+ Preconditions.checkState(this.generatedManifest == null);
+ this.generatedManifest = manifest;
+ return this;
+ }
+
+ /**
+ * Add "idl_srcs" contents.
+ */
+ public Builder addIdlSrcs(Collection<Artifact> idlSrcs) {
+ this.idlSrcs.addAll(idlSrcs);
+ addIdlDirs(idlSrcs);
+ return this;
+ }
+
+ /**
+ * Add "idl_parcelables" contents.
+ */
+ public Builder addIdlParcelables(Collection<Artifact> idlParcelables) {
+ addIdlDirs(idlParcelables);
+ return this;
+ }
+
+ private void addIdlDirs(Collection<Artifact> idlArtifacts) {
+ for (Artifact idl : idlArtifacts) {
+ this.idlDirs.add(
+ new SourceDirectory(
+ idl.getRoot().getPath().asFragment(),
+ idl.getRootRelativePath().getParentDirectory(),
+ idl.isSourceArtifact()));
+ }
+ }
+
+ public Builder addAllResources(Collection<SourceDirectory> resources) {
+ resourceDirs.addAll(resources);
+ return this;
+ }
+
+ public Builder addAllAssets(Collection<SourceDirectory> assets) {
+ assetDirs.addAll(assets);
+ return this;
+ }
+
+ public Builder addResourceSource(Artifact resource) {
+ resourceDirs.add(
+ new SourceDirectory(
+ resource.getRoot().getPath().asFragment(),
+ trimTo(
+ resource.getRootRelativePath(),
+ LocalResourceContainer.Builder.findResourceDir(resource)),
+ resource.isSourceArtifact()));
+ return this;
+ }
+
+ public Builder addResourceSources(Collection<Artifact> resources) {
+ for (Artifact resource : resources) {
+ addResourceSource(resource);
+ }
+ return this;
+ }
+
+ public Builder addAssetSources(Collection<Artifact> assets, PathFragment assetDir) {
+ for (Artifact asset : assets) {
+ addAssetSource(asset, assetDir);
+ }
+ return this;
+ }
+
+ public Builder addAssetSource(Artifact asset, PathFragment assetDir) {
+ assetDirs.add(
+ new SourceDirectory(
+ asset.getRoot().getPath().asFragment(),
+ trimTo(asset.getRootRelativePath(), assetDir),
+ asset.isSourceArtifact()));
+ return this;
+ }
+
+ public Builder addAllApksUnderTest(Iterable<Artifact> apks) {
+ Iterables.addAll(apksUnderTest, apks);
+ return this;
+ }
+
+ /**
+ * Finds the rightmost occurrence of the needle and returns subfragment of the haystack from
+ * left to the end of the occurrence inclusive of the needle.
+ *
+ * <pre>
+ * `Example:
+ * Given the haystack:
+ * res/research/handwriting/res/values/strings.xml
+ * And the needle:
+ * res
+ * Returns:
+ * res/research/handwriting/res
+ * </pre>
+ */
+ private static PathFragment trimTo(PathFragment haystack, PathFragment needle) {
+ if (needle.equals(PathFragment.EMPTY_FRAGMENT)) {
+ return haystack;
+ }
+ // Compute the overlap offset for duplicated parts of the needle.
+ int[] overlap = new int[needle.segmentCount() + 1];
+ // Start overlap at -1, as it will cancel out the increment in the search.
+ // See http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm for the
+ // details.
+ overlap[0] = -1;
+ for (int i = 0, j = -1; i < needle.segmentCount(); j++, i++, overlap[i] = j) {
+ while (j >= 0 && !needle.getSegment(i).equals(needle.getSegment(j))) {
+ // Walk the overlap until the bound is found.
+ j = overlap[j];
+ }
+ }
+ // TODO(corysmith): reverse the search algorithm.
+ // Keep the index of the found so that the rightmost index is taken.
+ int found = -1;
+ for (int i = 0, j = 0; i < haystack.segmentCount(); i++) {
+
+ while (j >= 0 && !haystack.getSegment(i).equals(needle.getSegment(j))) {
+ // Not matching, walk the needle index to attempt another match.
+ j = overlap[j];
+ }
+ j++;
+ // Needle index is exhausted, so the needle must match.
+ if (j == needle.segmentCount()) {
+ // Record the found index + 1 to be inclusive of the end index.
+ found = i + 1;
+ // Subtract one from the needle index to restart the search process
+ j = j - 1;
+ }
+ }
+ if (found != -1) {
+ // Return the subsection of the haystack.
+ return haystack.subFragment(0, found);
+ }
+ throw new IllegalArgumentException(String.format("%s was not found in %s", needle, haystack));
+ }
+ }
+
+ private final Artifact manifest;
+ private final Artifact generatedManifest;
+ private final Artifact signedApk;
+ private final ImmutableCollection<SourceDirectory> resourceDirs;
+ private final ImmutableCollection<SourceDirectory> assetDirs;
+ private final ImmutableCollection<SourceDirectory> idlImports;
+ private final ImmutableCollection<Artifact> idlSrcs;
+ private final ImmutableCollection<Artifact> apksUnderTest;
+
+ AndroidIdeInfoProvider(@Nullable Artifact manifest,
+ @Nullable Artifact generatedManifest,
+ @Nullable Artifact signedApk,
+ ImmutableCollection<SourceDirectory> assetDirs,
+ ImmutableCollection<SourceDirectory> resourceDirs,
+ ImmutableCollection<SourceDirectory> idlImports,
+ ImmutableCollection<Artifact> idlSrcs,
+ ImmutableCollection<Artifact> apksUnderTest) {
+ this.manifest = manifest;
+ this.generatedManifest = generatedManifest;
+ this.signedApk = signedApk;
+ this.assetDirs = assetDirs;
+ this.resourceDirs = resourceDirs;
+ this.idlImports = idlImports;
+ this.idlSrcs = idlSrcs;
+ this.apksUnderTest = apksUnderTest;
+ }
+
+ /** Returns the direct AndroidManifest. */
+ @Nullable
+ public Artifact getManifest() {
+ return manifest;
+ }
+
+ /** Returns the direct generated AndroidManifest. */
+ @Nullable
+ public Artifact getGeneratedManifest() {
+ return generatedManifest;
+ }
+
+
+ /** Returns the direct debug key signed apk, if there is one. */
+ @Nullable
+ public Artifact getSignedApk() {
+ return signedApk;
+ }
+
+ /** A list of the direct Resource directories. */
+ public ImmutableCollection<SourceDirectory> getResourceDirs() {
+ return resourceDirs;
+ }
+
+ /** A list of the direct Asset directories. */
+ public ImmutableCollection<SourceDirectory> getAssetDirs() {
+ return assetDirs;
+ }
+
+ /** A list of direct idl directories. */
+ public ImmutableCollection<SourceDirectory> getIdlImports() {
+ return idlImports;
+ }
+
+ /** A list of sources from the "idl_srcs" attribute. */
+ public ImmutableCollection<Artifact> getIdlSrcs() {
+ return idlSrcs;
+ }
+
+ /** A list of the APKs related to the app under test, if any. */
+ public ImmutableCollection<Artifact> getApksUnderTest() {
+ return apksUnderTest;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java
index 6ab6579f7c..1c69f385c3 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java
@@ -14,7 +14,6 @@
package com.google.devtools.build.lib.rules.android;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -35,8 +34,10 @@ import com.google.devtools.build.lib.rules.android.AndroidResourcesProvider.Reso
import com.google.devtools.build.lib.rules.cpp.LinkerInput;
import com.google.devtools.build.lib.rules.java.JavaCommon;
import com.google.devtools.build.lib.rules.java.JavaNeverlinkInfoProvider;
+import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider;
import com.google.devtools.build.lib.rules.java.JavaSemantics;
import com.google.devtools.build.lib.rules.java.JavaSkylarkApiProvider;
+import com.google.devtools.build.lib.rules.java.JavaSourceInfoProvider;
import com.google.devtools.build.lib.rules.java.JavaSourceJarsProvider;
import com.google.devtools.build.lib.rules.java.JavaTargetAttributes;
import com.google.devtools.build.lib.rules.java.JavaUtil;
@@ -78,12 +79,13 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory {
JavaCommon javaCommon = new JavaCommon(ruleContext, javaSemantics);
AndroidCommon androidCommon = new AndroidCommon(ruleContext, javaCommon);
- boolean definesLocalResources =
+
+ boolean definesLocalResources =
LocalResourceContainer.definesAndroidResources(ruleContext.attributes());
if (definesLocalResources && !LocalResourceContainer.validateRuleContext(ruleContext)) {
return null;
}
-
+
final ResourceApk resourceApk;
if (definesLocalResources) {
ApplicationManifest applicationManifest = androidSemantics.getManifestForRule(ruleContext);
@@ -101,6 +103,7 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory {
null /* versionName */,
false,
null /* proguardCfgOut */);
+
} catch (RuleConfigurationException e) {
// RuleConfigurations exceptions will only be thrown after the RuleContext is updated.
// So, exit.
@@ -117,7 +120,7 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory {
transitiveIdlImportData,
false /* addCoverageSupport */,
true /* collectJavaCompilationArgs */,
- AndroidRuleClasses.ANDROID_LIBRARY_GEN_JAR);
+ AndroidRuleClasses.ANDROID_LIBRARY_GEN_JAR);
if (javaTargetAttributes == null) {
return null;
}
@@ -147,17 +150,7 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory {
Artifact apk = ruleContext.getImplicitOutputArtifact(
AndroidRuleClasses.ANDROID_RESOURCES_APK);
- String javaPackage;
- if (apk.getExecPath().getFirstSegment(ImmutableSet.of("java", "javatests"))
- != PathFragment.INVALID_SEGMENT) {
- javaPackage = JavaUtil.getJavaPackageName(apk.getExecPath());
- } else {
- // This is a workaround for libraries that don't follow the standard Bazel package format
- javaPackage = apk.getRootRelativePath().getPathString().replace('/', '.');
- }
- if (ruleContext.attributes().isAttributeValueExplicitlySpecified("custom_package")) {
- javaPackage = ruleContext.attributes().get("custom_package", Type.STRING);
- }
+ String javaPackage = AndroidCommon.getJavaPackage(ruleContext);
ResourceContainer resourceContainer = new ResourceContainer(ruleContext.getLabel(),
javaPackage, null /* renameManifestPackage */, false /* inlinedConstants */,
@@ -190,11 +183,10 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory {
.build(ruleContext);
RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(ruleContext);
- androidCommon.addTransitiveInfoProviders(builder);
+ androidCommon.addTransitiveInfoProviders(builder, androidSemantics,
+ definesLocalResources ? resourceApk : null, null, ImmutableList.<Artifact>of());
androidSemantics.addTransitiveInfoProviders(
- builder, ruleContext, javaCommon, androidCommon,
- null, definesLocalResources ? resourceApk : null,
- null, ImmutableList.<Artifact>of());
+ builder, ruleContext, javaCommon, androidCommon, null);
return builder
.add(AndroidNativeLibraryProvider.class,
@@ -202,6 +194,15 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory {
.addSkylarkTransitiveInfo(JavaSkylarkApiProvider.NAME, new JavaSkylarkApiProvider())
.add(JavaNeverlinkInfoProvider.class,
new JavaNeverlinkInfoProvider(androidCommon.isNeverLink()))
+ // TODO(ahumesky): The gensrcJar is passed in for the srcJar -- is this a mistake?
+ .add(JavaRuleOutputJarsProvider.class,
+ new JavaRuleOutputJarsProvider(
+ classesJar,
+ androidCommon.getGensrcJar(),
+ androidCommon.getGenJar(),
+ androidCommon.getGensrcJar()))
+ .add(JavaSourceInfoProvider.class,
+ JavaSourceInfoProvider.fromJavaTargetAttributes(javaTargetAttributes, javaSemantics))
.add(JavaSourceJarsProvider.class, androidCommon.getJavaSourceJarsProvider())
.add(AndroidCcLinkParamsProvider.class,
new AndroidCcLinkParamsProvider(androidCommon.getCcLinkParamsStore()))
@@ -367,3 +368,4 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory {
return ruleContext.getPrerequisiteArtifacts("proguard_specs", Mode.TARGET).list();
}
}
+
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java
index f86fd57b14..a25ba935ed 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java
@@ -23,6 +23,8 @@ import com.google.devtools.build.lib.rules.java.JavaCompilationArtifacts;
import com.google.devtools.build.lib.rules.java.JavaSemantics;
import com.google.devtools.build.lib.rules.java.JavaTargetAttributes;
+import javax.annotation.Nullable;
+
/**
* Pluggable semantics for Android rules.
*
@@ -32,12 +34,27 @@ import com.google.devtools.build.lib.rules.java.JavaTargetAttributes;
public interface AndroidSemantics {
/**
* Adds transitive info providers for {@code android_binary} and {@code android_library} rules.
- * @throws InterruptedException
+ * @throws InterruptedException
+ */
+ void addTransitiveInfoProviders(
+ RuleConfiguredTargetBuilder builder,
+ RuleContext ruleContext,
+ JavaCommon javaCommon,
+ AndroidCommon androidCommon,
+ Artifact jarWithAllClasses)
+ throws InterruptedException;
+
+ /**
+ * Add additional resources to IDE info for {@code android_binary} and {@code android_library}
+ *
+ * @param ruleContext rule context for target rule
+ * @param resourceApk resource apk directly provided by the rule
+ * @param ideInfoProviderBuilder
*/
- void addTransitiveInfoProviders(RuleConfiguredTargetBuilder builder,
- RuleContext ruleContext, JavaCommon javaCommon, AndroidCommon androidCommon,
- Artifact jarWithAllClasses, ResourceApk resourceApk, Artifact zipAlignedApk,
- Iterable<Artifact> apksUnderTest) throws InterruptedException;
+ void addNonLocalResources(
+ RuleContext ruleContext,
+ @Nullable ResourceApk resourceApk,
+ AndroidIdeInfoProvider.Builder ideInfoProviderBuilder);
/**
* Returns the manifest to be used when compiling a given rule.
diff --git a/src/main/protobuf/android_studio_ide_info.proto b/src/main/protobuf/android_studio_ide_info.proto
index e81db553fc..ade346000b 100644
--- a/src/main/protobuf/android_studio_ide_info.proto
+++ b/src/main/protobuf/android_studio_ide_info.proto
@@ -37,6 +37,17 @@ message JavaRuleIdeInfo {
repeated ArtifactLocation sources = 4;
}
+message AndroidRuleIdeInfo {
+ repeated ArtifactLocation resources = 1;
+ repeated ArtifactLocation transitive_resources = 2;
+ ArtifactLocation apk = 3;
+ repeated ArtifactLocation dependency_apk = 4;
+ ArtifactLocation manifest = 5;
+ ArtifactLocation generated_manifest = 6;
+ string java_package = 7;
+ bool has_idl_sources = 8;
+}
+
message AndroidSdkRuleInfo {
string android_sdk_path = 1;
string genfiles_path = 2;
@@ -63,9 +74,10 @@ message RuleIdeInfo {
repeated string dependencies = 4;
repeated string transitive_dependencies = 5;
- // kind is one of JAVA_LIBRARY, JAVA_TEST, JAVA_IMPORT
- JavaRuleIdeInfo java_rule_ide_info = 6;
-
// kind is ANDROID_SDK
- AndroidSdkRuleInfo android_sdk_rule_info = 7;
+ AndroidSdkRuleInfo android_sdk_rule_info = 6;
+
+ // kind is one of {JAVA,ANDROID}_{LIBRARY,BINARY,TEST} and JAVA_IMPORT
+ JavaRuleIdeInfo java_rule_ide_info = 7;
+ AndroidRuleIdeInfo android_rule_ide_info = 8;
}
diff --git a/src/test/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspectTest.java b/src/test/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspectTest.java
index 0071a6b130..792be894d2 100644
--- a/src/test/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspectTest.java
+++ b/src/test/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspectTest.java
@@ -416,6 +416,109 @@ public class AndroidStudioInfoAspectTest extends BuildViewTestCase {
"<jar:com/google/example/foobar-exe.jar><source:com/google/example/foobar-exe-src.jar>");
}
+ public void testAndroidLibrary() throws Exception {
+ scratch.file(
+ "com/google/example/BUILD",
+ "android_library(",
+ " name = \"l1\",",
+ " manifest = \"Manifesto.xml\",",
+ " custom_package = \"com.google.example\",",
+ " resource_files = [\"r1/values/a.xml\"],",
+ ")",
+ "android_library(",
+ " name = \"l\",",
+ " srcs = [\"Main.java\"],",
+ " deps = [\":l1\"],",
+ " manifest = \"Abracadabra.xml\",",
+ " custom_package = \"com.google.example\",",
+ " resource_files = [\"res/drawable/a.png\", \"res/drawable/b.png\"],",
+ ")");
+ String target = "//com/google/example:l";
+ Map<String, RuleIdeInfo> ruleIdeInfos = buildRuleIdeInfo(target);
+ RuleIdeInfo ruleInfo = getRuleInfoAndVerifyLabel(target, ruleIdeInfos);
+ assertThat(ruleInfo.getKind()).isEqualTo(Kind.ANDROID_LIBRARY);
+ assertThat(relativePathsForSourcesOf(ruleInfo)).containsExactly("com/google/example/Main.java");
+ assertThat(transform(ruleInfo.getJavaRuleIdeInfo().getJarsList(), LIBRARY_ARTIFACT_TO_STRING))
+ .containsExactly("<jar:com/google/example/libl.jar>");
+ assertThat(
+ transform(
+ ruleInfo.getAndroidRuleIdeInfo().getResourcesList(), ARTIFACT_TO_RELATIVE_PATH))
+ .containsExactly("com/google/example/res");
+ assertThat(ruleInfo.getAndroidRuleIdeInfo().getManifest().getRelativePath())
+ .isEqualTo("com/google/example/Abracadabra.xml");
+ assertThat(ruleInfo.getAndroidRuleIdeInfo().getJavaPackage()).isEqualTo("com.google.example");
+
+ assertThat(ruleInfo.getDependenciesList()).containsExactly("//com/google/example:l1");
+ assertThat(
+ transform(
+ ruleInfo.getAndroidRuleIdeInfo().getTransitiveResourcesList(),
+ ARTIFACT_TO_RELATIVE_PATH))
+ .containsExactly("com/google/example/res", "com/google/example/r1");
+ }
+
+ public void testAndroidBinary() throws Exception {
+ scratch.file(
+ "com/google/example/BUILD",
+ "android_library(",
+ " name = \"l1\",",
+ " manifest = \"Manifesto.xml\",",
+ " custom_package = \"com.google.example\",",
+ " resource_files = [\"r1/values/a.xml\"],",
+ ")",
+ "android_binary(",
+ " name = \"b\",",
+ " srcs = [\"Main.java\"],",
+ " deps = [\":l1\"],",
+ " manifest = \"Abracadabra.xml\",",
+ " custom_package = \"com.google.example\",",
+ " resource_files = [\"res/drawable/a.png\", \"res/drawable/b.png\"],",
+ ")");
+ String target = "//com/google/example:b";
+ Map<String, RuleIdeInfo> ruleIdeInfos = buildRuleIdeInfo(target);
+ RuleIdeInfo ruleInfo = getRuleInfoAndVerifyLabel(target, ruleIdeInfos);
+ assertThat(ruleInfo.getKind()).isEqualTo(Kind.ANDROID_BINARY);
+ assertThat(relativePathsForSourcesOf(ruleInfo)).containsExactly("com/google/example/Main.java");
+ assertThat(transform(ruleInfo.getJavaRuleIdeInfo().getJarsList(), LIBRARY_ARTIFACT_TO_STRING))
+ .containsExactly(
+ "<jar:com/google/example/libb.jar><source:com/google/example/libb-src.jar>");
+ assertThat(
+ transform(
+ ruleInfo.getAndroidRuleIdeInfo().getResourcesList(), ARTIFACT_TO_RELATIVE_PATH))
+ .containsExactly("com/google/example/res");
+ assertThat(ruleInfo.getAndroidRuleIdeInfo().getManifest().getRelativePath())
+ .isEqualTo("com/google/example/Abracadabra.xml");
+ assertThat(ruleInfo.getAndroidRuleIdeInfo().getJavaPackage()).isEqualTo("com.google.example");
+
+ assertThat(ruleInfo.getDependenciesList()).containsExactly("//com/google/example:l1");
+ assertThat(
+ transform(
+ ruleInfo.getAndroidRuleIdeInfo().getTransitiveResourcesList(),
+ ARTIFACT_TO_RELATIVE_PATH))
+ .containsExactly("com/google/example/res", "com/google/example/r1");
+ }
+
+ public void testAndroidInferredPackage() throws Exception {
+ scratch.file(
+ "java/com/google/example/BUILD",
+ "android_library(",
+ " name = \"l\",",
+ " manifest = \"Manifesto.xml\",",
+ ")",
+ "android_binary(",
+ " name = \"b\",",
+ " srcs = [\"Main.java\"],",
+ " deps = [\":l\"],",
+ " manifest = \"Abracadabra.xml\",",
+ ")");
+ String target = "//java/com/google/example:b";
+ Map<String, RuleIdeInfo> ruleIdeInfos = buildRuleIdeInfo(target);
+ RuleIdeInfo lRuleInfo = getRuleInfoAndVerifyLabel("//java/com/google/example:l", ruleIdeInfos);
+ RuleIdeInfo bRuleInfo = getRuleInfoAndVerifyLabel(target, ruleIdeInfos);
+
+ assertThat(bRuleInfo.getAndroidRuleIdeInfo().getJavaPackage()).isEqualTo("com.google.example");
+ assertThat(lRuleInfo.getAndroidRuleIdeInfo().getJavaPackage()).isEqualTo("com.google.example");
+ }
+
private Map<String, RuleIdeInfo> buildRuleIdeInfo(String target) throws Exception {
AnalysisResult analysisResult =
update(