blob: 0ea8c48a45e39e4ee4e463618a1487f6a2bcd2ee [file] [log] [blame]
package org.robolectric.gradle;
import com.android.build.gradle.internal.dependency.ExtractAarTransform;
import com.google.common.base.Joiner;
import org.gradle.api.Action;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.transform.TransformOutputs;
import org.gradle.api.file.FileCollection;
import org.gradle.api.tasks.compile.JavaCompile;
import org.jetbrains.annotations.NotNull;
import javax.inject.Inject;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import static org.gradle.api.internal.artifacts.ArtifactAttributes.ARTIFACT_FORMAT;
/**
* Resolve aar dependencies into jars for non-Android projects.
*/
public class AarDepsPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project
.getDependencies()
.registerTransform(ClassesJarExtractor.class, reg -> {
reg.getParameters().getProjectName().set(project.getName());
reg.getFrom().attribute(ARTIFACT_FORMAT, "aar");
reg.getTo().attribute(ARTIFACT_FORMAT, "jar");
});
project.afterEvaluate(
p ->
project
.getConfigurations()
.forEach(
c -> {
// I suspect we're meant to use the org.gradle.usage attribute, but this
// works.
if (c.getName().endsWith("Classpath")) {
c.attributes(cfgAttrs -> cfgAttrs.attribute(ARTIFACT_FORMAT, "jar"));
}
}));
// warn if any AARs do make it through somehow; there must be a gradle configuration
// that isn't matched above.
//noinspection Convert2Lambda
project
.getTasks()
.withType(JavaCompile.class)
.all(
// the following Action<Task needs to remain an anonymous subclass or gradle's
// incremental compile breaks (run `gradlew -i classes` twice to see impact):
t -> t.doFirst(new Action<Task>() {
@Override
public void execute(Task task) {
List<File> aarFiles = AarDepsPlugin.this.findAarFiles(t.getClasspath());
if (!aarFiles.isEmpty()) {
throw new IllegalStateException(
"AARs on classpath: " + Joiner.on("\n ").join(aarFiles));
}
}
}));
}
private List<File> findAarFiles(FileCollection files) {
List<File> bad = new ArrayList<>();
for (File file : files.getFiles()) {
if (file.getName().toLowerCase().endsWith(".aar")) {
bad.add(file);
}
}
return bad;
}
public static abstract class ClassesJarExtractor extends ExtractAarTransform {
@Inject
public ClassesJarExtractor() {
}
@Override
public void transform(@NotNull TransformOutputs outputs) {
AtomicReference<File> classesJarFile = new AtomicReference<>();
AtomicReference<File> outJarFile = new AtomicReference<>();
super.transform(new TransformOutputs() {
// This is the one that ExtractAarTransform calls.
@Override
public File dir(Object o) {
// ExtractAarTransform needs a place to extract the AAR. We don't really need to
// register this as an output, but it'd be tricky to avoid it.
File dir = outputs.dir(o);
// Also, register our jar file. Its name needs to be quasi-unique or
// IntelliJ Gradle/Android plugins get confused.
classesJarFile.set(new File(new File(dir, "jars"), "classes.jar"));
outJarFile.set(new File(new File(dir, "jars"), o + ".jar"));
outputs.file(o + "/jars/" + o + ".jar");
return outputs.dir(o);
}
@Override
public File file(Object o) {
throw new IllegalStateException("shouldn't be called");
}
});
classesJarFile.get().renameTo(outJarFile.get());
}
}
}