aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Googler <noreply@google.com>2015-09-26 20:35:57 +0000
committerGravatar Han-Wen Nienhuys <hanwen@google.com>2015-09-28 11:39:56 +0000
commit22616ae8ea53df3909fd16b74e0d9210138dc2c2 (patch)
tree42740e6f6eba481ff858d7e48cc1605ece0ddb92 /src
parenta72be0f1d68ec449d463f825afa0aaabc4f05246 (diff)
Add Android IDL jar outputs.
These outputs are a jar and source jar for the results of aidl processing. This is used to add aidl output to IDEs separate from the source code, similar to annotation output (gen jars). -- MOS_MIGRATED_REVID=104024453
Diffstat (limited to 'src')
-rw-r--r--src/java_tools/buildjar/BUILD1
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidRepositoryRules.java3
-rw-r--r--src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspect.java15
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java1
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java191
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdeInfoProvider.java32
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdlHelper.java373
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdlProvider.java16
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java78
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java8
-rw-r--r--src/main/protobuf/android_studio_ide_info.proto1
-rw-r--r--src/test/java/com/google/devtools/build/android/idlclass/BUILD12
-rw-r--r--src/test/java/com/google/devtools/build/android/idlclass/IdlClassTest.java170
-rw-r--r--src/test/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspectTest.java34
-rwxr-xr-xsrc/test/shell/bazel/test-setup.sh20
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/idlclass/BUILD23
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/idlclass/IdlClass.java175
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/idlclass/IdlClassOptions.java67
19 files changed, 972 insertions, 250 deletions
diff --git a/src/java_tools/buildjar/BUILD b/src/java_tools/buildjar/BUILD
index a9f6276cf0..1edd5828cc 100644
--- a/src/java_tools/buildjar/BUILD
+++ b/src/java_tools/buildjar/BUILD
@@ -160,6 +160,7 @@ java_library(
],
visibility = [
"//src/java_tools/buildjar/java/com/google/devtools/build/buildjar/genclass:__pkg__",
+ "//src/tools/android/java/com/google/devtools/build/android/idlclass:__pkg__",
],
deps = [
"//third_party:guava",
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidRepositoryRules.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidRepositoryRules.java
index 45ecc0301d..d57d1f6c82 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidRepositoryRules.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidRepositoryRules.java
@@ -51,7 +51,8 @@ public class AndroidRepositoryRules {
"aar_generator",
"shuffle_jars",
"merge_dexzips",
- "debug_keystore");
+ "debug_keystore",
+ "IdlClass");
private static final Function<? super Rule, Map<String, Label>> BINDINGS_FUNCTION =
new Function< Rule, Map<String, Label>>() {
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 a88f4a8646..2db796563d 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
@@ -260,6 +260,21 @@ public class AndroidStudioInfoAspect implements ConfiguredAspectFactory {
builder.addTransitiveResources(makeArtifactLocation(transitiveResource));
}
+ boolean hasIdlSources = !provider.getIdlSrcs().isEmpty();
+ builder.setHasIdlSources(hasIdlSources);
+ if (hasIdlSources) {
+ LibraryArtifact.Builder jarBuilder = LibraryArtifact.newBuilder();
+ Artifact idlClassJar = provider.getIdlClassJar();
+ if (idlClassJar != null) {
+ jarBuilder.setJar(makeArtifactLocation(idlClassJar));
+ }
+ Artifact idlSourceJar = provider.getIdlSourceJar();
+ if (idlSourceJar != null) {
+ jarBuilder.setSourceJar(makeArtifactLocation(idlSourceJar));
+ }
+ builder.setIdlJar(jarBuilder.build());
+ }
+
return builder.build();
}
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 d28420cfad..e5bac926f7 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
@@ -264,7 +264,6 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
javaSemantics,
androidSemantics,
resourceApk,
- AndroidIdlProvider.EMPTY,
ruleContext.getConfiguration().isCodeCoverageEnabled(),
true /* collectJavaCompilationArgs */);
if (resourceClasses == null) {
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 b2bf36fbcb..f4e5d67d2b 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
@@ -21,7 +21,6 @@ import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.actions.MiddlemanFactory;
import com.google.devtools.build.lib.actions.ResourceSet;
import com.google.devtools.build.lib.analysis.AnalysisUtils;
import com.google.devtools.build.lib.analysis.FilesToRunProvider;
@@ -35,7 +34,6 @@ import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration.StrictDepsMode;
-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.collect.nestedset.Order;
@@ -65,16 +63,13 @@ 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;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import javax.annotation.Nullable;
@@ -102,12 +97,11 @@ public class AndroidCommon {
private Artifact genClassJar;
private Artifact genSourceJar;
- private Collection<Artifact> idls;
- private AndroidIdlProvider transitiveIdlImportData;
private NestedSet<ResourceContainer> transitiveResources;
- private Map<Artifact, Artifact> translatedIdlSources = ImmutableMap.of();
private boolean asNeverLink;
private boolean exportDeps;
+ private Artifact manifestProtoOutput;
+ private AndroidIdlHelper idlHelper;
public AndroidCommon(RuleContext ruleContext, JavaCommon javaCommon) {
this.ruleContext = ruleContext;
@@ -212,13 +206,16 @@ public class AndroidCommon {
public static AndroidIdeInfoProvider createAndroidIdeInfoProvider(
RuleContext ruleContext,
AndroidSemantics semantics,
+ AndroidIdlHelper idlHelper,
ResourceApk resourceApk,
Artifact zipAlignedApk,
Iterable<Artifact> apksUnderTest) {
AndroidIdeInfoProvider.Builder ideInfoProviderBuilder =
new AndroidIdeInfoProvider.Builder()
- .addIdlParcelables(getIdlParcelables(ruleContext))
- .addIdlSrcs(getIdlSrcs(ruleContext))
+ .setIdlClassJar(idlHelper.getIdlClassJar())
+ .setIdlSourceJar(idlHelper.getIdlSourceJar())
+ .addIdlParcelables(idlHelper.getIdlParcelables())
+ .addIdlSrcs(idlHelper.getIdlSources())
.addAllApksUnderTest(apksUnderTest);
if (zipAlignedApk != null) {
@@ -385,17 +382,22 @@ public class AndroidCommon {
public JavaTargetAttributes init(
JavaSemantics javaSemantics, AndroidSemantics androidSemantics,
- ResourceApk resourceApk, AndroidIdlProvider transitiveIdlImportData,
+ ResourceApk resourceApk,
boolean addCoverageSupport, boolean collectJavaCompilationArgs) throws InterruptedException {
- ImmutableList<Artifact> extraSources =
- resourceApk.isLegacy() || resourceApk.getResourceJavaSrcJar() == null
+
+ classJar = ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_LIBRARY_CLASS_JAR);
+ idlHelper = new AndroidIdlHelper(ruleContext, classJar);
+
+ ImmutableList.Builder<Artifact> extraSourcesBuilder = ImmutableList.<Artifact>builder()
+ .addAll(resourceApk.isLegacy() || resourceApk.getResourceJavaSrcJar() == null
? ImmutableList.<Artifact>of()
- : ImmutableList.of(resourceApk.getResourceJavaSrcJar());
+ : ImmutableList.of(resourceApk.getResourceJavaSrcJar()))
+ .addAll(idlHelper.getIdlGeneratedJavaSources());
+
JavaTargetAttributes.Builder attributes = init(
androidSemantics,
- transitiveIdlImportData,
resourceApk.getTransitiveResources(),
- extraSources);
+ extraSourcesBuilder.build());
JavaCompilationArtifacts.Builder artifactsBuilder = new JavaCompilationArtifacts.Builder();
if (resourceApk.isLegacy()) {
compileResources(javaSemantics, artifactsBuilder, attributes,
@@ -430,23 +432,11 @@ public class AndroidCommon {
private JavaTargetAttributes.Builder init(
AndroidSemantics androidSemantics,
- AndroidIdlProvider transitiveIdlImportData,
NestedSet<AndroidResourcesProvider.ResourceContainer> transitiveResources,
Collection<Artifact> extraArtifacts) {
- this.transitiveIdlImportData = transitiveIdlImportData;
this.transitiveResources = transitiveResources;
-
- ImmutableList.Builder<Artifact> extraSrcsBuilder =
- new ImmutableList.Builder<Artifact>().addAll(extraArtifacts);
-
- idls = getIdlSrcs(ruleContext);
- if (!idls.isEmpty() && !ruleContext.hasErrors()) {
- translatedIdlSources = generateTranslatedIdlArtifacts(ruleContext, idls);
- }
-
javaCommon.initializeJavacOpts(androidSemantics.getJavacArguments());
- JavaTargetAttributes.Builder attributes = javaCommon.initCommon(
- extraSrcsBuilder.addAll(translatedIdlSources.values()).build());
+ JavaTargetAttributes.Builder attributes = javaCommon.initCommon(extraArtifacts);
attributes.setBootClassPath(ImmutableList.of(
AndroidSdkProvider.fromRuleContext(ruleContext).getAndroidJar()));
@@ -533,7 +523,6 @@ public class AndroidCommon {
}
Artifact jar = null;
- classJar = ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_LIBRARY_CLASS_JAR);
if (attributes.hasSourceFiles() || attributes.hasSourceJars() || attributes.hasResources()) {
// We only want to add a jar to the classpath of a dependent rule if it has content.
javaArtifactsBuilder.addRuntimeJar(classJar);
@@ -542,7 +531,7 @@ public class AndroidCommon {
filesBuilder.add(classJar);
- Artifact manifestProtoOutput = helper.createManifestProtoOutput(classJar);
+ manifestProtoOutput = helper.createManifestProtoOutput(classJar);
// The gensrc jar is created only if the target uses annotation processing. Otherwise,
// it is null, and the source jar action will not depend on the compile action.
@@ -597,17 +586,13 @@ public class AndroidCommon {
ResourceApk resourceApk,
Artifact zipAlignedApk,
Iterable<Artifact> apksUnderTest) {
- if (!idls.isEmpty()) {
- generateAndroidIdlActions(
- ruleContext, idls, transitiveIdlImportData, translatedIdlSources);
- }
-
Runfiles runfiles = new Runfiles.Builder(ruleContext.getWorkspaceName())
.addRunfiles(ruleContext, RunfilesProvider.DEFAULT_RUNFILES)
.build();
javaCommon.addTransitiveInfoProviders(builder, filesToBuild, classJar);
javaCommon.addGenJarsProvider(builder, genClassJar, genSourceJar);
+ idlHelper.addTransitiveInfoProviders(builder, classJar, manifestProtoOutput);
return builder
.setFilesToBuild(filesToBuild)
@@ -621,9 +606,8 @@ public class AndroidCommon {
new AndroidResourcesProvider(ruleContext.getLabel(), transitiveResources))
.add(
AndroidIdeInfoProvider.class,
- createAndroidIdeInfoProvider(
- ruleContext, androidSemantics, resourceApk, zipAlignedApk, apksUnderTest))
- .add(AndroidIdlProvider.class, transitiveIdlImportData)
+ createAndroidIdeInfoProvider(ruleContext, androidSemantics, idlHelper,
+ resourceApk, zipAlignedApk, apksUnderTest))
.add(
JavaCompilationArgsProvider.class,
new JavaCompilationArgsProvider(
@@ -647,38 +631,6 @@ public class AndroidCommon {
Type.STRING));
}
- public static ImmutableList<Artifact> getIdlParcelables(RuleContext ruleContext) {
- return ruleContext.getRule().isAttrDefined("idl_parcelables", BuildType.LABEL_LIST)
- ? ImmutableList.copyOf(ruleContext.getPrerequisiteArtifacts(
- "idl_parcelables", Mode.TARGET).filter(AndroidRuleClasses.ANDROID_IDL).list())
- : ImmutableList.<Artifact>of();
- }
-
- public static Collection<Artifact> getIdlSrcs(RuleContext ruleContext) {
- if (!ruleContext.getRule().isAttrDefined("idl_srcs", BuildType.LABEL_LIST)) {
- return ImmutableList.of();
- }
- checkIdlSrcsSamePackage(ruleContext);
- return ruleContext.getPrerequisiteArtifacts(
- "idl_srcs", Mode.TARGET).filter(AndroidRuleClasses.ANDROID_IDL).list();
- }
-
- public static void checkIdlSrcsSamePackage(RuleContext ruleContext) {
- PathFragment packageName = ruleContext.getLabel().getPackageFragment();
- Collection<Artifact> idls = ruleContext
- .getPrerequisiteArtifacts("idl_srcs", Mode.TARGET)
- .filter(AndroidRuleClasses.ANDROID_IDL)
- .list();
- for (Artifact idl : idls) {
- Label idlLabel = idl.getOwner();
- if (!packageName.equals(idlLabel.getPackageFragment())) {
- ruleContext.attributeError("idl_srcs", "do not import '" + idlLabel + "' directly. "
- + "You should either move the file to this package or depend on "
- + "an appropriate rule there");
- }
- }
- }
-
public static NestedSet<LinkerInput> collectTransitiveNativeLibraries(
Iterable<? extends TransitiveInfoCollection> deps) {
NestedSetBuilder<LinkerInput> builder = NestedSetBuilder.stableOrder();
@@ -733,24 +685,6 @@ public class AndroidCommon {
return applicationApksBuilder.build();
}
- private ImmutableMap<Artifact, Artifact> generateTranslatedIdlArtifacts(
- RuleContext ruleContext, Collection<Artifact> idls) {
- ImmutableMap.Builder<Artifact, Artifact> outputJavaSources = ImmutableMap.builder();
- String ruleName = ruleContext.getRule().getName();
- // for each aidl file use aggregated preprocessed files to generate Java code
- for (Artifact idl : idls) {
- // Reconstruct the package tree under <rule>_aidl to avoid a name conflict
- // if the same AIDL files are used in multiple targets.
- PathFragment javaOutputPath = FileSystemUtils.replaceExtension(
- new PathFragment(ruleName + "_aidl").getRelative(idl.getRootRelativePath()),
- ".java");
- Artifact output = ruleContext.getPackageRelativeArtifact(
- javaOutputPath, ruleContext.getConfiguration().getGenfilesDirectory());
- outputJavaSources.put(idl, output);
- }
- return outputJavaSources.build();
- }
-
private JavaCompilationArgs collectJavaCompilationArgs(RuleContext ruleContext,
boolean recursive, boolean neverLink, boolean hasSrcs) {
JavaCompilationArgs.Builder builder = JavaCompilationArgs.builder()
@@ -762,85 +696,6 @@ public class AndroidCommon {
return builder.build();
}
- private void generateAndroidIdlActions(RuleContext ruleContext,
- Collection<Artifact> idls, AndroidIdlProvider transitiveIdlImportData,
- Map<Artifact, Artifact> translatedIdlSources) {
- AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext);
- Set<Artifact> preprocessedIdls = new LinkedHashSet<>();
- List<String> preprocessedArgs = new ArrayList<>();
-
- // add imports
- for (String idlImport : transitiveIdlImportData.getTransitiveIdlImportRoots()) {
- preprocessedArgs.add("-I" + idlImport);
- }
-
- // preprocess each aidl file
- preprocessedArgs.add("-p" + sdk.getFrameworkAidl().getExecPathString());
- String ruleName = ruleContext.getRule().getName();
- for (Artifact idl : idls) {
- // Reconstruct the package tree under <rule>_aidl to avoid a name conflict
- // if the source AIDL files are also generated.
- PathFragment preprocessedPath = new PathFragment(ruleName + "_aidl")
- .getRelative(idl.getRootRelativePath());
- Artifact preprocessed = ruleContext.getPackageRelativeArtifact(
- preprocessedPath, ruleContext.getConfiguration().getGenfilesDirectory());
- preprocessedIdls.add(preprocessed);
- preprocessedArgs.add("-p" + preprocessed.getExecPathString());
-
- createAndroidIdlPreprocessAction(ruleContext, idl, preprocessed);
- }
-
- // aggregate all preprocessed aidl files
- MiddlemanFactory middlemanFactory = ruleContext.getAnalysisEnvironment().getMiddlemanFactory();
- Artifact preprocessedIdlsMiddleman = middlemanFactory.createAggregatingMiddleman(
- ruleContext.getActionOwner(), "AndroidIDLMiddleman", preprocessedIdls,
- ruleContext.getConfiguration().getMiddlemanDirectory());
-
- for (Artifact idl : translatedIdlSources.keySet()) {
- createAndroidIdlAction(ruleContext, idl,
- transitiveIdlImportData.getTransitiveIdlImports(),
- preprocessedIdlsMiddleman, translatedIdlSources.get(idl), preprocessedArgs);
- }
- }
-
- private void createAndroidIdlPreprocessAction(RuleContext ruleContext,
- Artifact idl, Artifact preprocessed) {
- AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext);
- ruleContext.registerAction(new SpawnAction.Builder()
- .setExecutable(sdk.getAidl())
- // Note the below may be an overapproximation of the actual runfiles, due to "conditional
- // artifacts" (see Runfiles.PruningManifest).
- // TODO(bazel-team): When using getFilesToRun(), the middleman is
- // not expanded. Fix by providing code to expand and use getFilesToRun here.
- .addInput(idl)
- .addOutput(preprocessed)
- .addArgument("--preprocess")
- .addArgument(preprocessed.getExecPathString())
- .addArgument(idl.getExecPathString())
- .setProgressMessage("Android IDL preprocessing")
- .setMnemonic("AndroidIDLPreprocess")
- .build(ruleContext));
- }
-
- private void createAndroidIdlAction(RuleContext ruleContext,
- Artifact idl, Iterable<Artifact> idlImports, Artifact preprocessedIdls,
- Artifact output, List<String> preprocessedArgs) {
- AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext);
- ruleContext.registerAction(new SpawnAction.Builder()
- .setExecutable(sdk.getAidl())
- .addInput(idl)
- .addInputs(idlImports)
- .addInput(preprocessedIdls)
- .addInput(sdk.getFrameworkAidl())
- .addOutput(output)
- .addArgument("-b") // Fail if trying to compile a parcelable.
- .addArguments(preprocessedArgs)
- .addArgument(idl.getExecPathString())
- .addArgument(output.getExecPathString())
- .setProgressMessage("Android IDL generation")
- .setMnemonic("AndroidIDLGnerate")
- .build(ruleContext));
- }
public ImmutableList<String> getJavacOpts() {
return javaCommon.getJavacOpts();
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
index 5d3ce1c7db..9fe1faf096 100644
--- 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
@@ -97,6 +97,8 @@ public final class AndroidIdeInfoProvider implements TransitiveInfoProvider {
private Artifact manifest = null;
private Artifact generatedManifest = null;
private Artifact apk = null;
+ private Artifact idlClassJar = null;
+ private Artifact idlSourceJar = null;
private final Set<SourceDirectory> resourceDirs = new LinkedHashSet<>();
private final Set<SourceDirectory> assetDirs = new LinkedHashSet<>();
private final Set<SourceDirectory> idlDirs = new LinkedHashSet<>();
@@ -108,6 +110,8 @@ public final class AndroidIdeInfoProvider implements TransitiveInfoProvider {
manifest,
generatedManifest,
apk,
+ idlClassJar,
+ idlSourceJar,
ImmutableList.copyOf(assetDirs),
ImmutableList.copyOf(resourceDirs),
ImmutableList.copyOf(idlDirs),
@@ -133,6 +137,18 @@ public final class AndroidIdeInfoProvider implements TransitiveInfoProvider {
return this;
}
+ public Builder setIdlClassJar(@Nullable Artifact idlClassJar) {
+ Preconditions.checkState(this.idlClassJar == null);
+ this.idlClassJar = idlClassJar;
+ return this;
+ }
+
+ public Builder setIdlSourceJar(@Nullable Artifact idlSourceJar) {
+ Preconditions.checkState(this.idlSourceJar == null);
+ this.idlSourceJar = idlSourceJar;
+ return this;
+ }
+
/**
* Add "idl_srcs" contents.
*/
@@ -268,6 +284,8 @@ public final class AndroidIdeInfoProvider implements TransitiveInfoProvider {
private final Artifact manifest;
private final Artifact generatedManifest;
private final Artifact signedApk;
+ @Nullable private final Artifact idlClassJar;
+ @Nullable private final Artifact idlSourceJar;
private final ImmutableCollection<SourceDirectory> resourceDirs;
private final ImmutableCollection<SourceDirectory> assetDirs;
private final ImmutableCollection<SourceDirectory> idlImports;
@@ -277,6 +295,8 @@ public final class AndroidIdeInfoProvider implements TransitiveInfoProvider {
AndroidIdeInfoProvider(@Nullable Artifact manifest,
@Nullable Artifact generatedManifest,
@Nullable Artifact signedApk,
+ @Nullable Artifact idlClassJar,
+ @Nullable Artifact idlSourceJar,
ImmutableCollection<SourceDirectory> assetDirs,
ImmutableCollection<SourceDirectory> resourceDirs,
ImmutableCollection<SourceDirectory> idlImports,
@@ -285,6 +305,8 @@ public final class AndroidIdeInfoProvider implements TransitiveInfoProvider {
this.manifest = manifest;
this.generatedManifest = generatedManifest;
this.signedApk = signedApk;
+ this.idlClassJar = idlClassJar;
+ this.idlSourceJar = idlSourceJar;
this.assetDirs = assetDirs;
this.resourceDirs = resourceDirs;
this.idlImports = idlImports;
@@ -311,6 +333,16 @@ public final class AndroidIdeInfoProvider implements TransitiveInfoProvider {
return signedApk;
}
+ @Nullable
+ public Artifact getIdlClassJar() {
+ return idlClassJar;
+ }
+
+ @Nullable
+ public Artifact getIdlSourceJar() {
+ return idlSourceJar;
+ }
+
/** A list of the direct Resource directories. */
public ImmutableCollection<SourceDirectory> getResourceDirs() {
return resourceDirs;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdlHelper.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdlHelper.java
new file mode 100644
index 0000000000..ff4e5f85b4
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdlHelper.java
@@ -0,0 +1,373 @@
+// 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.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MiddlemanFactory;
+import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
+import com.google.devtools.build.lib.analysis.actions.SpawnAction;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.packages.BuildType;
+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;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * Helper class for Android IDL processing.
+ */
+public class AndroidIdlHelper {
+
+ private final RuleContext ruleContext;
+ private final AndroidIdlProvider androidIdlProvider;
+ private final Collection<Artifact> idls;
+ private final Map<Artifact, Artifact> translatedIdlSources;
+ private final Artifact idlClassJar;
+ private final Artifact idlSourceJar;
+
+ public AndroidIdlHelper(RuleContext ruleContext, Artifact classJar) {
+ this.ruleContext = ruleContext;
+
+ checkIdlRootImport(ruleContext);
+
+ idls = getIdlSrcs(ruleContext);
+
+ if (!idls.isEmpty() && !ruleContext.hasErrors()) {
+ translatedIdlSources = generateTranslatedIdlArtifacts(ruleContext, idls);
+ idlClassJar = createIdlJar(classJar, "-idl.jar");
+ idlSourceJar = createIdlJar(classJar, "-idl.srcjar");
+ } else {
+ translatedIdlSources = ImmutableMap.of();
+ idlClassJar = null;
+ idlSourceJar = null;
+ }
+
+ androidIdlProvider = createAndroidIdlProvider(
+ ruleContext, idlClassJar, idlSourceJar);
+ }
+
+ public void addTransitiveInfoProviders(RuleConfiguredTargetBuilder builder,
+ Artifact classJar, Artifact manifestProtoOutput) {
+ if (!idls.isEmpty()) {
+ generateAndroidIdlCompilationActions(
+ ruleContext, idls, androidIdlProvider, translatedIdlSources);
+ createIdlClassJarAction(ruleContext, classJar, translatedIdlSources.values(),
+ manifestProtoOutput, idlClassJar, idlSourceJar);
+ }
+ builder
+ .add(AndroidIdlProvider.class, androidIdlProvider)
+ .addOutputGroup(
+ AndroidSemantics.IDL_JARS_OUTPUT_GROUP, androidIdlProvider.getTransitiveIdlJars());
+ }
+
+ public Collection<Artifact> getIdlSources() {
+ return idls;
+ }
+
+ public Collection<Artifact> getIdlParcelables() {
+ return getIdlParcelables(ruleContext);
+ }
+
+ public Collection<Artifact> getIdlGeneratedJavaSources() {
+ return translatedIdlSources.values();
+ }
+
+ @Nullable
+ public Artifact getIdlClassJar() {
+ return idlClassJar;
+ }
+
+ @Nullable
+ public Artifact getIdlSourceJar() {
+ return idlSourceJar;
+ }
+
+ /**
+ * Returns the artifact for a jar file containing class files that were generated by
+ * annotation processors.
+ */
+ private Artifact createIdlJar(Artifact outputJar, String suffix) {
+ return ruleContext.getDerivedArtifact(
+ FileSystemUtils.replaceExtension(outputJar.getRootRelativePath(), suffix),
+ outputJar.getRoot());
+ }
+
+ private static ImmutableList<Artifact> getIdlParcelables(RuleContext ruleContext) {
+ return ruleContext.getRule().isAttrDefined("idl_parcelables", BuildType.LABEL_LIST)
+ ? ImmutableList.copyOf(ruleContext.getPrerequisiteArtifacts(
+ "idl_parcelables", Mode.TARGET).filter(AndroidRuleClasses.ANDROID_IDL).list())
+ : ImmutableList.<Artifact>of();
+ }
+
+ private static Collection<Artifact> getIdlSrcs(RuleContext ruleContext) {
+ if (!ruleContext.getRule().isAttrDefined("idl_srcs", BuildType.LABEL_LIST)) {
+ return ImmutableList.of();
+ }
+ checkIdlSrcsSamePackage(ruleContext);
+ return ruleContext.getPrerequisiteArtifacts(
+ "idl_srcs", Mode.TARGET).filter(AndroidRuleClasses.ANDROID_IDL).list();
+ }
+
+ private static void checkIdlSrcsSamePackage(RuleContext ruleContext) {
+ PathFragment packageName = ruleContext.getLabel().getPackageFragment();
+ Collection<Artifact> idls = ruleContext
+ .getPrerequisiteArtifacts("idl_srcs", Mode.TARGET)
+ .filter(AndroidRuleClasses.ANDROID_IDL)
+ .list();
+ for (Artifact idl : idls) {
+ Label idlLabel = idl.getOwner();
+ if (!packageName.equals(idlLabel.getPackageFragment())) {
+ ruleContext.attributeError("idl_srcs", "do not import '" + idlLabel + "' directly. "
+ + "You should either move the file to this package or depend on "
+ + "an appropriate rule there");
+ }
+ }
+ }
+
+ private static ImmutableMap<Artifact, Artifact> generateTranslatedIdlArtifacts(
+ RuleContext ruleContext, Collection<Artifact> idls) {
+ ImmutableMap.Builder<Artifact, Artifact> outputJavaSources = ImmutableMap.builder();
+ String ruleName = ruleContext.getRule().getName();
+ // for each aidl file use aggregated preprocessed files to generate Java code
+ for (Artifact idl : idls) {
+ // Reconstruct the package tree under <rule>_aidl to avoid a name conflict
+ // if the same AIDL files are used in multiple targets.
+ PathFragment javaOutputPath = FileSystemUtils.replaceExtension(
+ new PathFragment(ruleName + "_aidl").getRelative(idl.getRootRelativePath()),
+ ".java");
+ Artifact output = ruleContext.getPackageRelativeArtifact(
+ javaOutputPath, ruleContext.getConfiguration().getGenfilesDirectory());
+ outputJavaSources.put(idl, output);
+ }
+ return outputJavaSources.build();
+ }
+
+ private static void generateAndroidIdlCompilationActions(
+ RuleContext ruleContext,
+ Collection<Artifact> idls,
+ AndroidIdlProvider transitiveIdlImportData,
+ Map<Artifact, Artifact> translatedIdlSources) {
+ AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext);
+ Set<Artifact> preprocessedIdls = new LinkedHashSet<>();
+ List<String> preprocessedArgs = new ArrayList<>();
+
+ // add imports
+ for (String idlImport : transitiveIdlImportData.getTransitiveIdlImportRoots()) {
+ preprocessedArgs.add("-I" + idlImport);
+ }
+
+ // preprocess each aidl file
+ preprocessedArgs.add("-p" + sdk.getFrameworkAidl().getExecPathString());
+ String ruleName = ruleContext.getRule().getName();
+ for (Artifact idl : idls) {
+ // Reconstruct the package tree under <rule>_aidl to avoid a name conflict
+ // if the source AIDL files are also generated.
+ PathFragment preprocessedPath = new PathFragment(ruleName + "_aidl")
+ .getRelative(idl.getRootRelativePath());
+ Artifact preprocessed = ruleContext.getPackageRelativeArtifact(
+ preprocessedPath, ruleContext.getConfiguration().getGenfilesDirectory());
+ preprocessedIdls.add(preprocessed);
+ preprocessedArgs.add("-p" + preprocessed.getExecPathString());
+
+ createAndroidIdlPreprocessAction(ruleContext, idl, preprocessed);
+ }
+
+ // aggregate all preprocessed aidl files
+ MiddlemanFactory middlemanFactory = ruleContext.getAnalysisEnvironment().getMiddlemanFactory();
+ Artifact preprocessedIdlsMiddleman = middlemanFactory.createAggregatingMiddleman(
+ ruleContext.getActionOwner(), "AndroidIDLMiddleman", preprocessedIdls,
+ ruleContext.getConfiguration().getMiddlemanDirectory());
+
+ for (Artifact idl : translatedIdlSources.keySet()) {
+ createAndroidIdlAction(ruleContext, idl,
+ transitiveIdlImportData.getTransitiveIdlImports(),
+ preprocessedIdlsMiddleman, translatedIdlSources.get(idl), preprocessedArgs);
+ }
+ }
+
+ /**
+ * Creates the idl class jar action.
+ */
+ private static void createIdlClassJarAction(
+ RuleContext ruleContext,
+ Artifact classJar,
+ Iterable<Artifact> generatedIdlJavaFiles,
+ Artifact manifestProtoOutput,
+ Artifact idlClassJar,
+ Artifact idlSourceJar) {
+ ruleContext.registerAction(new SpawnAction.Builder()
+ .addInput(manifestProtoOutput)
+ .addInput(classJar)
+ .addInputs(generatedIdlJavaFiles)
+ .addOutput(idlClassJar)
+ .addOutput(idlSourceJar)
+ .setExecutable(ruleContext.getExecutablePrerequisite("$idlclass", Mode.HOST))
+ .setCommandLine(CustomCommandLine.builder()
+ .addExecPath("--manifest_proto", manifestProtoOutput)
+ .addExecPath("--class_jar", classJar)
+ .addExecPath("--output_class_jar", idlClassJar)
+ .addExecPath("--output_source_jar", idlSourceJar)
+ .add("--temp_dir").addPath(idlTempDir(ruleContext, idlClassJar))
+ .addExecPaths(generatedIdlJavaFiles)
+ .build())
+ .useParameterFile(ParameterFileType.SHELL_QUOTED)
+ .setProgressMessage("Building idl jars " + idlClassJar.prettyPrint())
+ .setMnemonic("AndroidIdlJars")
+ .build(ruleContext));
+ }
+
+ private static PathFragment idlTempDir(RuleContext ruleContext, Artifact outputJar) {
+ String basename = FileSystemUtils.removeExtension(outputJar.getExecPath().getBaseName());
+ return ruleContext.getConfiguration().getBinDirectory().getExecPath()
+ .getRelative(ruleContext.getUniqueDirectory("_idl"))
+ .getRelative(basename + "_temp");
+ }
+
+ private static void createAndroidIdlPreprocessAction(RuleContext ruleContext,
+ Artifact idl, Artifact preprocessed) {
+ AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext);
+ ruleContext.registerAction(new SpawnAction.Builder()
+ .setExecutable(sdk.getAidl())
+ // Note the below may be an overapproximation of the actual runfiles, due to "conditional
+ // artifacts" (see Runfiles.PruningManifest).
+ // TODO(bazel-team): When using getFilesToRun(), the middleman is
+ // not expanded. Fix by providing code to expand and use getFilesToRun here.
+ .addInput(idl)
+ .addOutput(preprocessed)
+ .addArgument("--preprocess")
+ .addArgument(preprocessed.getExecPathString())
+ .addArgument(idl.getExecPathString())
+ .setProgressMessage("Android IDL preprocessing")
+ .setMnemonic("AndroidIDLPreprocess")
+ .build(ruleContext));
+ }
+
+ private static void createAndroidIdlAction(RuleContext ruleContext,
+ Artifact idl, Iterable<Artifact> idlImports, Artifact preprocessedIdls,
+ Artifact output, List<String> preprocessedArgs) {
+ AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext);
+ ruleContext.registerAction(new SpawnAction.Builder()
+ .setExecutable(sdk.getAidl())
+ .addInput(idl)
+ .addInputs(idlImports)
+ .addInput(preprocessedIdls)
+ .addInput(sdk.getFrameworkAidl())
+ .addOutput(output)
+ .addArgument("-b") // Fail if trying to compile a parcelable.
+ .addArguments(preprocessedArgs)
+ .addArgument(idl.getExecPathString())
+ .addArgument(output.getExecPathString())
+ .setProgressMessage("Android IDL generation")
+ .setMnemonic("AndroidIDLGnerate")
+ .build(ruleContext));
+ }
+
+ /**
+ * Returns the union of "idl_srcs" and "idl_parcelables", i.e. all .aidl files
+ * provided by this library that contribute to .aidl --> .java compilation.
+ */
+ private static Collection<Artifact> getIdlImports(RuleContext ruleContext) {
+ return ImmutableList.<Artifact>builder()
+ .addAll(getIdlParcelables(ruleContext))
+ .addAll(getIdlSrcs(ruleContext))
+ .build();
+ }
+
+ private static AndroidIdlProvider createAndroidIdlProvider(RuleContext ruleContext,
+ @Nullable Artifact idlClassJar, @Nullable Artifact idlSourceJar) {
+ NestedSetBuilder<String> rootsBuilder = NestedSetBuilder.naiveLinkOrder();
+ NestedSetBuilder<Artifact> importsBuilder = NestedSetBuilder.naiveLinkOrder();
+ NestedSetBuilder<Artifact> jarsBuilder = NestedSetBuilder.stableOrder();
+ if (idlClassJar != null) {
+ jarsBuilder.add(idlClassJar);
+ }
+ if (idlSourceJar != null) {
+ jarsBuilder.add(idlSourceJar);
+ }
+
+ for (AndroidIdlProvider dep : ruleContext.getPrerequisites(
+ "deps", Mode.TARGET, AndroidIdlProvider.class)) {
+ rootsBuilder.addTransitive(dep.getTransitiveIdlImportRoots());
+ importsBuilder.addTransitive(dep.getTransitiveIdlImports());
+ jarsBuilder.addTransitive(dep.getTransitiveIdlJars());
+ }
+
+ Collection<Artifact> idlImports = getIdlImports(ruleContext);
+ if (!hasExplicitlySpecifiedIdlImportRoot(ruleContext)) {
+ for (Artifact idlImport : idlImports) {
+ PathFragment javaRoot = JavaUtil.getJavaRoot(idlImport.getExecPath());
+ if (javaRoot == null) {
+ ruleContext.ruleError("Cannot determine java/javatests root for import "
+ + idlImport.getExecPathString());
+ } else {
+ rootsBuilder.add(javaRoot.toString());
+ }
+ }
+ } else {
+ PathFragment pkgFragment = ruleContext.getLabel().getPackageFragment();
+ Set<PathFragment> idlImportRoots = new HashSet<>();
+ for (Artifact idlImport : idlImports) {
+ idlImportRoots.add(idlImport.getRoot().getExecPath()
+ .getRelative(pkgFragment)
+ .getRelative(getIdlImportRoot(ruleContext)));
+ }
+ for (PathFragment idlImportRoot : idlImportRoots) {
+ rootsBuilder.add(idlImportRoot.toString());
+ }
+ }
+ importsBuilder.addAll(idlImports);
+
+ return new AndroidIdlProvider(rootsBuilder.build(),
+ importsBuilder.build(), jarsBuilder.build());
+ }
+
+ private static void checkIdlRootImport(RuleContext ruleContext) {
+ if (hasExplicitlySpecifiedIdlImportRoot(ruleContext)
+ && !hasExplicitlySpecifiedIdlSrcsOrParcelables(ruleContext)) {
+ ruleContext.attributeError("idl_import_root",
+ "Neither idl_srcs nor idl_parcelables were specified, "
+ + "but 'idl_import_root' attribute was set");
+ }
+ }
+
+ private static boolean hasExplicitlySpecifiedIdlImportRoot(RuleContext ruleContext) {
+ return ruleContext.getRule().isAttributeValueExplicitlySpecified("idl_import_root");
+ }
+
+ private static boolean hasExplicitlySpecifiedIdlSrcsOrParcelables(RuleContext ruleContext) {
+ return ruleContext.getRule().isAttributeValueExplicitlySpecified("idl_srcs")
+ || ruleContext.getRule().isAttributeValueExplicitlySpecified("idl_parcelables");
+ }
+
+ private static String getIdlImportRoot(RuleContext ruleContext) {
+ return ruleContext.attributes().get("idl_import_root", Type.STRING);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdlProvider.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdlProvider.java
index 2c98727aa9..c7365db8d2 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdlProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdlProvider.java
@@ -29,15 +29,20 @@ public final class AndroidIdlProvider implements TransitiveInfoProvider {
public static final AndroidIdlProvider EMPTY = new AndroidIdlProvider(
NestedSetBuilder.<String>emptySet(Order.STABLE_ORDER),
+ NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER));
private final NestedSet<String> transitiveIdlImportRoots;
private final NestedSet<Artifact> transitiveIdlImports;
+ private final NestedSet<Artifact> transitiveIdlJars;
- public AndroidIdlProvider(NestedSet<String> transitiveIdlImportRoots,
- NestedSet<Artifact> transitiveIdlImports) {
+ public AndroidIdlProvider(
+ NestedSet<String> transitiveIdlImportRoots,
+ NestedSet<Artifact> transitiveIdlImports,
+ NestedSet<Artifact> transitiveIdlJars) {
this.transitiveIdlImportRoots = transitiveIdlImportRoots;
this.transitiveIdlImports = transitiveIdlImports;
+ this.transitiveIdlJars = transitiveIdlJars;
}
/**
@@ -53,4 +58,11 @@ public final class AndroidIdlProvider implements TransitiveInfoProvider {
public NestedSet<Artifact> getTransitiveIdlImports() {
return transitiveIdlImports;
}
+
+ /**
+ * The IDL jars in the transitive closure, both class and source jars.
+ */
+ public NestedSet<Artifact> getTransitiveIdlJars() {
+ return transitiveIdlJars;
+ }
}
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 f83553b5ed..67156b0ba8 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
@@ -39,14 +39,11 @@ 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;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.Collection;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
/**
* An implementation for the "android_library" rule.
@@ -66,7 +63,6 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory {
List<? extends TransitiveInfoCollection> deps =
ruleContext.getPrerequisites("deps", Mode.TARGET);
checkResourceInlining(ruleContext);
- checkIdlRootImport(ruleContext);
NestedSet<AndroidResourcesProvider.ResourceContainer> transitiveResources =
AndroidCommon.getTransitiveResourceContainers(ruleContext, true);
NestedSetBuilder<Aar> transitiveAars = collectTransitiveAars(ruleContext);
@@ -74,11 +70,9 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory {
AndroidCommon.collectTransitiveNativeLibraries(deps);
NestedSet<Artifact> transitiveProguardConfigs =
collectTransitiveProguardConfigs(ruleContext);
- AndroidIdlProvider transitiveIdlImportData = collectTransitiveIdlImports(ruleContext);
JavaCommon javaCommon = new JavaCommon(ruleContext, javaSemantics);
AndroidCommon androidCommon = new AndroidCommon(ruleContext, javaCommon);
-
boolean definesLocalResources =
LocalResourceContainer.definesAndroidResources(ruleContext.attributes());
if (definesLocalResources && !LocalResourceContainer.validateRuleContext(ruleContext)) {
@@ -116,7 +110,6 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory {
javaSemantics,
androidSemantics,
resourceApk,
- transitiveIdlImportData,
false /* addCoverageSupport */,
true /* collectJavaCompilationArgs */);
if (javaTargetAttributes == null) {
@@ -221,53 +214,6 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory {
return mergedJar;
}
- private AndroidIdlProvider collectTransitiveIdlImports(RuleContext ruleContext) {
- NestedSetBuilder<String> rootsBuilder = NestedSetBuilder.naiveLinkOrder();
- NestedSetBuilder<Artifact> importsBuilder = NestedSetBuilder.naiveLinkOrder();
-
- for (AndroidIdlProvider dep : ruleContext.getPrerequisites(
- "deps", Mode.TARGET, AndroidIdlProvider.class)) {
- rootsBuilder.addTransitive(dep.getTransitiveIdlImportRoots());
- importsBuilder.addTransitive(dep.getTransitiveIdlImports());
- }
-
- Collection<Artifact> idlImports = getIdlImports(ruleContext);
- if (!hasExplicitlySpecifiedIdlImportRoot(ruleContext)) {
- for (Artifact idlImport : idlImports) {
- PathFragment javaRoot = JavaUtil.getJavaRoot(idlImport.getExecPath());
- if (javaRoot == null) {
- ruleContext.ruleError("Cannot determine java/javatests root for import "
- + idlImport.getExecPathString());
- } else {
- rootsBuilder.add(javaRoot.toString());
- }
- }
- } else {
- PathFragment pkgFragment = ruleContext.getLabel().getPackageFragment();
- Set<PathFragment> idlImportRoots = new HashSet<>();
- for (Artifact idlImport : idlImports) {
- idlImportRoots.add(idlImport.getRoot().getExecPath()
- .getRelative(pkgFragment)
- .getRelative(getIdlImportRoot(ruleContext)));
- }
- for (PathFragment idlImportRoot : idlImportRoots) {
- rootsBuilder.add(idlImportRoot.toString());
- }
- }
- importsBuilder.addAll(idlImports);
-
- return new AndroidIdlProvider(rootsBuilder.build(), importsBuilder.build());
- }
-
- private void checkIdlRootImport(RuleContext ruleContext) {
- if (hasExplicitlySpecifiedIdlImportRoot(ruleContext)
- && !hasExplicitlySpecifiedIdlSrcsOrParcelables(ruleContext)) {
- ruleContext.attributeError("idl_import_root",
- "Neither idl_srcs nor idl_parcelables were specified, "
- + "but 'idl_import_root' attribute was set");
- }
- }
-
private void checkResourceInlining(RuleContext ruleContext) {
AndroidResourcesProvider resources = AndroidCommon.getAndroidResources(ruleContext);
if (resources == null) {
@@ -293,30 +239,6 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory {
return builder;
}
- private boolean hasExplicitlySpecifiedIdlImportRoot(RuleContext ruleContext) {
- return ruleContext.getRule().isAttributeValueExplicitlySpecified("idl_import_root");
- }
-
- private boolean hasExplicitlySpecifiedIdlSrcsOrParcelables(RuleContext ruleContext) {
- return ruleContext.getRule().isAttributeValueExplicitlySpecified("idl_srcs")
- || ruleContext.getRule().isAttributeValueExplicitlySpecified("idl_parcelables");
- }
-
- private String getIdlImportRoot(RuleContext ruleContext) {
- return ruleContext.attributes().get("idl_import_root", Type.STRING);
- }
-
- /**
- * Returns the union of "idl_srcs" and "idl_parcelables", i.e. all .aidl files
- * provided by this library that contribute to .aidl --> .java compilation.
- */
- private static Collection<Artifact> getIdlImports(RuleContext ruleContext) {
- return ImmutableList.<Artifact>builder()
- .addAll(AndroidCommon.getIdlParcelables(ruleContext))
- .addAll(AndroidCommon.getIdlSrcs(ruleContext))
- .build();
- }
-
private NestedSet<Artifact> collectTransitiveProguardConfigs(RuleContext ruleContext) {
NestedSetBuilder<Artifact> specsBuilder = NestedSetBuilder.naiveLinkOrder();
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
index 5372fc10b0..c1e14989a3 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
@@ -531,6 +531,8 @@ public final class AndroidRuleClasses {
// like all the rest of android tools.
.add(attr("$jarjar_bin", LABEL).cfg(HOST).exec()
.value(env.getLabel("//third_party/java/jarjar:jarjar_bin")))
+ .add(attr("$idlclass", LABEL).cfg(HOST).exec()
+ .value(env.getLabel(Constants.ANDROID_DEP_PREFIX + "IdlClass")))
.build();
}
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 ea6a4588b2..e11c46038c 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
@@ -15,6 +15,7 @@ package com.google.devtools.build.lib.rules.android;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.OutputGroupProvider;
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;
@@ -33,6 +34,13 @@ import javax.annotation.Nullable;
*/
public interface AndroidSemantics {
/**
+ * Name of the output group used for idl jars (the jars containing the class files for sources
+ * generated from annotation processors).
+ */
+ String IDL_JARS_OUTPUT_GROUP =
+ OutputGroupProvider.HIDDEN_OUTPUT_GROUP_PREFIX + "idl_jars";
+
+ /**
* Adds transitive info providers for {@code android_binary} and {@code android_library} rules.
* @throws InterruptedException
*/
diff --git a/src/main/protobuf/android_studio_ide_info.proto b/src/main/protobuf/android_studio_ide_info.proto
index 36ec0feba8..ee0d327e87 100644
--- a/src/main/protobuf/android_studio_ide_info.proto
+++ b/src/main/protobuf/android_studio_ide_info.proto
@@ -46,6 +46,7 @@ message AndroidRuleIdeInfo {
ArtifactLocation generated_manifest = 6;
string java_package = 7;
bool has_idl_sources = 8;
+ LibraryArtifact idl_jar = 9;
}
message AndroidSdkRuleInfo {
diff --git a/src/test/java/com/google/devtools/build/android/idlclass/BUILD b/src/test/java/com/google/devtools/build/android/idlclass/BUILD
new file mode 100644
index 0000000000..f9255e4083
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/idlclass/BUILD
@@ -0,0 +1,12 @@
+java_test(
+ name = "IdlClassTest",
+ size = "medium",
+ srcs = glob(["*.java"]),
+ deps = [
+ "//src/main/protobuf:proto_java_compilation",
+ "//src/tools/android/java/com/google/devtools/build/android/idlclass:idlclass_lib",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
diff --git a/src/test/java/com/google/devtools/build/android/idlclass/IdlClassTest.java b/src/test/java/com/google/devtools/build/android/idlclass/IdlClassTest.java
new file mode 100644
index 0000000000..740f753b49
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/android/idlclass/IdlClassTest.java
@@ -0,0 +1,170 @@
+// 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.android.idlclass;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.Sets;
+import com.google.devtools.build.buildjar.proto.JavaCompilation.CompilationUnit;
+import com.google.devtools.build.buildjar.proto.JavaCompilation.Manifest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+/** {@link IdlClass} test */
+@RunWith(JUnit4.class)
+public class IdlClassTest {
+
+ static final Manifest MANIFEST =
+ Manifest.newBuilder()
+ .addCompilationUnit(
+ CompilationUnit.newBuilder()
+ .setPath("c/g/Foo.java")
+ .setPkg("c.g")
+ .addTopLevel("Foo")
+ .addTopLevel("Bar"))
+ .addCompilationUnit(
+ CompilationUnit.newBuilder()
+ .setPath("c/g/Bar.java")
+ .setPkg("c.g")
+ .addTopLevel("Bar")
+ .addTopLevel("Bar2"))
+ .addCompilationUnit(
+ CompilationUnit.newBuilder()
+ // default package
+ .setPath("wrong/source/dir/Baz.java")
+ .addTopLevel("Baz"))
+ .build();
+
+ @Rule public TemporaryFolder tempFolder = new TemporaryFolder();
+
+ @Test
+ public void generatedPrefixes() {
+ Set<String> idlSources = Sets.newHashSet(
+ "c/g/Bar.java",
+ "wrong/source/dir/Baz.java"
+ );
+ assertThat(IdlClass.getIdlPrefixes(MANIFEST, idlSources))
+ .containsExactly("c/g/Bar", "c/g/Bar2", "Baz");
+ }
+
+ @Test
+ public void idlClass() throws IOException {
+ File classJar = tempFolder.newFile("lib.jar");
+ File manifestProto = tempFolder.newFile("lib.manifest");
+ File tempDir = tempFolder.newFolder("temp_files");
+ File outputClassJar = tempFolder.newFile("lib-idl.jar");
+ File outputSourceJar = tempFolder.newFile("lib-idl-src.jar");
+
+ List<String> classes =
+ Arrays.asList(
+ "Baz.class",
+ "Baz$0.class",
+ "Baz$1.class",
+ "c/g/Foo.class",
+ "c/g/Foo$0.class",
+ "c/g/Foo$Inner.class",
+ "c/g/Foo$Inner$InnerMost.class",
+ "c/g/Bar.class",
+ "c/g/Bar2.class",
+ "c/g/Bar$Inner.class",
+ "c/g/Bar2$Inner.class");
+
+ try (OutputStream os = new FileOutputStream(classJar);
+ ZipOutputStream zos = new ZipOutputStream(os)) {
+ for (String path : classes) {
+ zos.putNextEntry(new ZipEntry(path));
+ }
+ }
+
+ tempFolder.newFolder("c");
+ tempFolder.newFolder("c/g");
+ tempFolder.newFolder("wrong");
+ tempFolder.newFolder("wrong/source");
+ tempFolder.newFolder("wrong/source/dir");
+ for (String file : Arrays.asList("c/g/Foo.java", "c/g/Bar.java", "wrong/source/dir/Baz.java")) {
+ tempFolder.newFile(file);
+ }
+
+ try (OutputStream os = new FileOutputStream(manifestProto)) {
+ MANIFEST.writeTo(os);
+ }
+
+ IdlClass.main(
+ new String[]{
+ "--manifest_proto",
+ manifestProto.toString(),
+ "--class_jar",
+ classJar.toString(),
+ "--output_class_jar",
+ outputClassJar.toString(),
+ "--output_source_jar",
+ outputSourceJar.toString(),
+ "--temp_dir",
+ tempDir.toString(),
+ "--idl_source_base_dir",
+ tempFolder.getRoot().getPath(),
+ "c/g/Bar.java",
+ "wrong/source/dir/Baz.java"
+ });
+
+ List<String> classJarEntries = getJarEntries(outputClassJar);
+ assertThat(classJarEntries)
+ .containsExactly(
+ "c/g/Bar.class",
+ "c/g/Bar$Inner.class",
+ "c/g/Bar2.class",
+ "c/g/Bar2$Inner.class",
+ "Baz.class",
+ "Baz$0.class",
+ "Baz$1.class");
+
+ List<String> sourceJarEntries = getJarEntries(outputSourceJar);
+ assertThat(sourceJarEntries)
+ .containsExactly(
+ "c/g/Bar.java",
+ "Baz.java");
+ }
+
+ private List<String> getJarEntries(File outputJar) throws IOException {
+ List<String> jarEntries = new ArrayList<>();
+ try (ZipFile zf = new ZipFile(outputJar)) {
+ Enumeration<? extends ZipEntry> entries = zf.entries();
+ while (entries.hasMoreElements()) {
+ String name = entries.nextElement().getName();
+ if (name.endsWith("/") || name.equals("META-INF/MANIFEST.MF")) {
+ continue;
+ }
+ jarEntries.add(name);
+ }
+ }
+ return jarEntries;
+ }
+}
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 2383b6497b..aff6d9251b 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
@@ -520,6 +520,40 @@ public class AndroidStudioInfoAspectTest extends BuildViewTestCase {
assertThat(lRuleInfo.getAndroidRuleIdeInfo().getJavaPackage()).isEqualTo("com.google.example");
}
+ public void testAndroidLibraryWithoutAidlHasNoIdlJars() throws Exception {
+ scratch.file(
+ "java/com/google/example/BUILD",
+ "android_library(",
+ " name = 'no_idl',",
+ " srcs = ['Test.java'],",
+ ")"
+ );
+ String noIdlTarget = "//java/com/google/example:no_idl";
+ Map<String, RuleIdeInfo> ruleIdeInfos = buildRuleIdeInfo(noIdlTarget);
+ RuleIdeInfo noIdlRuleInfo = getRuleInfoAndVerifyLabel(noIdlTarget, ruleIdeInfos);
+
+ assertThat(noIdlRuleInfo.getAndroidRuleIdeInfo().getHasIdlSources()).isFalse();
+ }
+
+ public void testAndroidLibraryWithAidlHasIdlJars() throws Exception {
+ scratch.file(
+ "java/com/google/example/BUILD",
+ "android_library(",
+ " name = 'has_idl',",
+ " idl_srcs = ['a.aidl'],",
+ ")"
+ );
+ String idlTarget = "//java/com/google/example:has_idl";
+ Map<String, RuleIdeInfo> ruleIdeInfos = buildRuleIdeInfo(idlTarget);
+ RuleIdeInfo idlRuleInfo = getRuleInfoAndVerifyLabel(idlTarget, ruleIdeInfos);
+
+ assertThat(idlRuleInfo.getAndroidRuleIdeInfo().getHasIdlSources()).isTrue();
+ assertThat(LIBRARY_ARTIFACT_TO_STRING.apply(idlRuleInfo.getAndroidRuleIdeInfo().getIdlJar()))
+ .isEqualTo(
+ "<jar:java/com/google/example/libhas_idl-idl.jar>"
+ + "<source:java/com/google/example/libhas_idl-idl.srcjar>");
+ }
+
private Map<String, RuleIdeInfo> buildRuleIdeInfo(String target) throws Exception {
AnalysisResult analysisResult =
update(
diff --git a/src/test/shell/bazel/test-setup.sh b/src/test/shell/bazel/test-setup.sh
index 1b37a13d5e..d08484d958 100755
--- a/src/test/shell/bazel/test-setup.sh
+++ b/src/test/shell/bazel/test-setup.sh
@@ -175,6 +175,7 @@ sh_binary(
EOF
cat > third_party/java/jarjar/fail.sh <<EOF
+
#!/bin/bash
exit 1
@@ -182,6 +183,25 @@ EOF
chmod +x third_party/java/jarjar/fail.sh
+ mkdir -p src/tools/android/java/com/google/devtools/build/android/idlclass
+ cat > src/tools/android/java/com/google/devtools/build/android/idlclass/BUILD <<EOF
+licenses(["unencumbered"])
+sh_binary(
+ name = "IdlClass",
+ srcs = ["fail.sh"],
+ visibility = ["//visibility:public"],
+)
+EOF
+
+ cat > src/tools/android/java/com/google/devtools/build/android/idlclass/fail.sh <<EOF
+
+#!/bin/bash
+
+exit 1
+EOF
+
+ chmod +x src/tools/android/java/com/google/devtools/build/android/idlclass/fail.sh
+
ANDROID_NDK=$PWD/android_ndk
ANDROID_SDK=$PWD/android_sdk
diff --git a/src/tools/android/java/com/google/devtools/build/android/idlclass/BUILD b/src/tools/android/java/com/google/devtools/build/android/idlclass/BUILD
new file mode 100644
index 0000000000..a22f833748
--- /dev/null
+++ b/src/tools/android/java/com/google/devtools/build/android/idlclass/BUILD
@@ -0,0 +1,23 @@
+java_binary(
+ name = "IdlClass",
+ main_class = "com.google.devtools.build.android.idlclass.IdlClass",
+ visibility = ["//visibility:public"],
+ runtime_deps = [":idlclass_lib"],
+)
+
+java_library(
+ name = "idlclass_lib",
+ srcs = glob(["*.java"]),
+ visibility = [
+ "//devtools/blaze/integration:__pkg__",
+ "//src/test/java/com/google/devtools/build/android/idlclass:__pkg__",
+ ],
+ deps = [
+ "//src/java_tools/buildjar:jarhelper",
+ "//src/main/java:options",
+ "//src/main/protobuf:proto_java_compilation",
+ "//src/tools/android/java/com/google/devtools/build/android:android_builder_lib",
+ "//third_party:guava",
+ "//third_party:jsr305",
+ ],
+)
diff --git a/src/tools/android/java/com/google/devtools/build/android/idlclass/IdlClass.java b/src/tools/android/java/com/google/devtools/build/android/idlclass/IdlClass.java
new file mode 100644
index 0000000000..c31a66a8f9
--- /dev/null
+++ b/src/tools/android/java/com/google/devtools/build/android/idlclass/IdlClass.java
@@ -0,0 +1,175 @@
+// 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.android.idlclass;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.devtools.build.buildjar.JarCreator;
+import com.google.devtools.build.buildjar.proto.JavaCompilation.CompilationUnit;
+import com.google.devtools.build.buildjar.proto.JavaCompilation.Manifest;
+import com.google.devtools.common.options.OptionsParser;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * IdlClass post-processes the output of a Java compilation, and produces
+ * a jar containing only the class files for sources that were generated
+ * from idl processing.
+ */
+public class IdlClass {
+
+ public static void main(String[] args) throws IOException {
+ OptionsParser optionsParser = OptionsParser.newOptionsParser(IdlClassOptions.class);
+ optionsParser.parseAndExitUponError(args);
+ IdlClassOptions options = optionsParser.getOptions(IdlClassOptions.class);
+ Preconditions.checkNotNull(options.manifestProto);
+ Preconditions.checkNotNull(options.classJar);
+ Preconditions.checkNotNull(options.outputClassJar);
+ Preconditions.checkNotNull(options.outputSourceJar);
+ Preconditions.checkNotNull(options.tempDir);
+
+ List<Path> idlSources = Lists.newArrayList();
+ for (String idlSource : optionsParser.getResidue()) {
+ idlSources.add(Paths.get(idlSource));
+ }
+
+ Manifest manifest = readManifest(options.manifestProto);
+ writeClassJar(options, idlSources, manifest);
+ writeSourceJar(options, idlSources, manifest);
+ }
+
+ private static void writeClassJar(IdlClassOptions options,
+ List<Path> idlSources, Manifest manifest) throws IOException {
+ Path tempDir = options.tempDir.resolve("classjar");
+ Set<String> idlSourceSet = Sets.newHashSet();
+ for (Path path : idlSources) {
+ idlSourceSet.add(path.toString());
+ }
+ extractIdlClasses(options.classJar, manifest, tempDir, idlSourceSet);
+ writeOutputJar(options.outputClassJar, tempDir);
+ }
+
+ private static void writeSourceJar(IdlClassOptions options,
+ List<Path> idlSources, Manifest manifest) throws IOException {
+ Path tempDir = options.tempDir.resolve("sourcejar");
+ Path idlSourceBaseDir = options.idlSourceBaseDir;
+
+ for (Path path : idlSources) {
+ for (CompilationUnit unit : manifest.getCompilationUnitList()) {
+ if (unit.getPath().equals(path.toString())) {
+ String pkg = unit.getPkg();
+ Path source = idlSourceBaseDir != null ? idlSourceBaseDir.resolve(path) : path;
+ Path target = tempDir.resolve(pkg.replace('.', '/')).resolve(path.getFileName());
+ Files.createDirectories(target.getParent());
+ Files.copy(source, target);
+ break;
+ }
+ }
+ }
+ writeOutputJar(options.outputSourceJar, tempDir);
+ }
+
+ /**
+ * Reads the compilation manifest.
+ */
+ private static Manifest readManifest(Path path) throws IOException {
+ Manifest manifest;
+ try (InputStream inputStream = Files.newInputStream(path)) {
+ manifest = Manifest.parseFrom(inputStream);
+ }
+ return manifest;
+ }
+
+ /**
+ * For each top-level class in the compilation, determine the path prefix
+ * of classes corresponding to that compilation unit.
+ *
+ * <p>Prefixes are used to correctly handle inner classes, e.g. the top-level
+ * class "c.g.Foo" may correspond to "c/g/Foo.class" and also
+ * "c/g/Foo$Inner.class" or "c/g/Foo$0.class".
+ */
+ @VisibleForTesting
+ static ImmutableSet<String> getIdlPrefixes(Manifest manifest, Set<String> idlSources) {
+ ImmutableSet.Builder<String> prefixes = ImmutableSet.builder();
+ for (CompilationUnit unit : manifest.getCompilationUnitList()) {
+ if (!idlSources.contains(unit.getPath())) {
+ continue;
+ }
+ String pkg;
+ if (unit.hasPkg()) {
+ pkg = unit.getPkg().replace('.', '/') + "/";
+ } else {
+ pkg = "";
+ }
+ for (String toplevel : unit.getTopLevelList()) {
+ prefixes.add(pkg + toplevel);
+ }
+ }
+ return prefixes.build();
+ }
+
+ /**
+ * Unzip all the class files that correspond to idl processor-
+ * generated sources into the temporary directory.
+ */
+ private static void extractIdlClasses(
+ Path classJar,
+ Manifest manifest,
+ Path tempDir,
+ Set<String> idlSources)
+ throws IOException {
+ ImmutableSet<String> prefixes = getIdlPrefixes(manifest, idlSources);
+ try (JarFile jar = new JarFile(classJar.toFile())) {
+ Enumeration<JarEntry> entries = jar.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry entry = entries.nextElement();
+ String name = entry.getName();
+ if (!name.endsWith(".class")) {
+ continue;
+ }
+ String prefix = name.substring(0, name.length() - ".class".length());
+ int idx = prefix.indexOf('$');
+ if (idx > 0) {
+ prefix = prefix.substring(0, idx);
+ }
+ if (prefixes.contains(prefix)) {
+ Files.createDirectories(tempDir.resolve(name).getParent());
+ Files.copy(jar.getInputStream(entry), tempDir.resolve(name));
+ }
+ }
+ }
+ }
+
+ /** Writes the generated class files to the output jar. */
+ private static void writeOutputJar(Path outputJar, Path tempDir) throws IOException {
+ JarCreator output = new JarCreator(outputJar.toString());
+ output.setCompression(true);
+ output.setNormalize(true);
+ output.addDirectory(tempDir.toString());
+ output.execute();
+ }
+}
diff --git a/src/tools/android/java/com/google/devtools/build/android/idlclass/IdlClassOptions.java b/src/tools/android/java/com/google/devtools/build/android/idlclass/IdlClassOptions.java
new file mode 100644
index 0000000000..d36bd1a1fd
--- /dev/null
+++ b/src/tools/android/java/com/google/devtools/build/android/idlclass/IdlClassOptions.java
@@ -0,0 +1,67 @@
+// 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.android.idlclass;
+
+import com.google.devtools.build.android.Converters.ExistingPathConverter;
+import com.google.devtools.build.android.Converters.PathConverter;
+import com.google.devtools.common.options.Option;
+import com.google.devtools.common.options.OptionsBase;
+
+import java.nio.file.Path;
+
+/** The options for a {@IdlClass} action. */
+public final class IdlClassOptions extends OptionsBase {
+ @Option(name = "manifest_proto",
+ defaultValue = "null",
+ converter = ExistingPathConverter.class,
+ category = "input",
+ help = "The path to the manifest file output by the Java compiler.")
+ public Path manifestProto;
+
+ @Option(name = "class_jar",
+ defaultValue = "null",
+ converter = ExistingPathConverter.class,
+ category = "input",
+ help = "The path to the class jar output by the Java compiler.")
+ public Path classJar;
+
+ @Option(name = "output_class_jar",
+ defaultValue = "null",
+ converter = PathConverter.class,
+ category = "output",
+ help = "The path to write the class jar output to.")
+ public Path outputClassJar;
+
+ @Option(name = "output_source_jar",
+ defaultValue = "null",
+ converter = PathConverter.class,
+ category = "output",
+ help = "The path to write the source jar output to.")
+ public Path outputSourceJar;
+
+ @Option(name = "temp_dir",
+ defaultValue = "null",
+ converter = PathConverter.class,
+ category = "input",
+ help = "The path to a temp directory.")
+ public Path tempDir;
+
+ @Option(name = "idl_source_base_dir",
+ defaultValue = "null",
+ converter = PathConverter.class,
+ category = "input",
+ help = "The path to the base directory of the idl sources. Optional; Used for testing.")
+ public Path idlSourceBaseDir;
+}