blob: 9ff9c0855e2150601006f0e4c8f810916139caa5 [file] [log] [blame]
package org.jetbrains.jps.android.builder;
import com.android.tools.idea.jps.AndroidTargetBuilder;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.util.Processor;
import com.intellij.util.io.ZipUtil;
import org.jetbrains.android.util.AndroidBuildTestingManager;
import org.jetbrains.android.util.AndroidCommonUtils;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.android.AndroidJpsBundle;
import org.jetbrains.jps.android.AndroidJpsUtil;
import org.jetbrains.jps.android.model.JpsAndroidModuleExtension;
import org.jetbrains.jps.builders.BuildOutputConsumer;
import org.jetbrains.jps.builders.BuildRootDescriptor;
import org.jetbrains.jps.builders.DirtyFilesHolder;
import org.jetbrains.jps.incremental.CompileContext;
import org.jetbrains.jps.incremental.ProjectBuildException;
import org.jetbrains.jps.incremental.StopBuildException;
import org.jetbrains.jps.incremental.messages.ProgressMessage;
import org.jetbrains.jps.model.module.JpsModule;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.jar.JarOutputStream;
/**
* @author Eugene.Kudelevsky
*/
public class AndroidAarDepsBuilder extends AndroidTargetBuilder<BuildRootDescriptor, AndroidAarDepsBuildTarget> {
@NonNls private static final String BUILDER_NAME = "Android AAR Dependencies Packaging";
public AndroidAarDepsBuilder() {
super(Collections.singleton(AndroidAarDepsBuildTarget.MyTargetType.INSTANCE));
}
@Override
protected void buildTarget(@NotNull AndroidAarDepsBuildTarget target,
@NotNull DirtyFilesHolder<BuildRootDescriptor, AndroidAarDepsBuildTarget> holder,
@NotNull BuildOutputConsumer outputConsumer,
@NotNull CompileContext context) throws ProjectBuildException, IOException {
if (!holder.hasDirtyFiles() && !holder.hasRemovedFiles()) {
return;
}
assert !AndroidJpsUtil.isLightBuild(context);
if (!doBuild(context, target, outputConsumer)) {
throw new StopBuildException();
}
}
private static boolean doBuild(final CompileContext context,
AndroidAarDepsBuildTarget target,
BuildOutputConsumer outputConsumer) {
final JpsModule module = target.getModule();
final JpsAndroidModuleExtension extension = AndroidJpsUtil.getExtension(module);
if (extension == null || extension.isLibrary()) {
return true;
}
File outputDir = AndroidJpsUtil.getDirectoryForIntermediateArtifacts(context, module);
outputDir = AndroidJpsUtil.createDirIfNotExist(outputDir, context, BUILDER_NAME);
if (outputDir == null) {
return false;
}
final List<String> srcJarFiles = new ArrayList<String>();
for (BuildRootDescriptor descriptor : context.getProjectDescriptor().getBuildRootIndex().getTargetRoots(target, context)) {
final File file = descriptor.getRootFile();
if (file.exists()) {
srcJarFiles.add(file.getPath());
}
}
if (srcJarFiles.size() == 0) {
return true;
}
context.processMessage(new ProgressMessage(AndroidJpsBundle.message(
"android.jps.progress.aar.dependencies.packaging", module.getName())));
File tempDir = null;
try {
tempDir = FileUtil.createTempDirectory("extracted_aar_deps", "tmp");
for (int i = srcJarFiles.size() - 1; i >= 0; i--) {
ZipUtil.extract(new File(srcJarFiles.get(i)), tempDir, null, true);
}
final File outputJarFile = new File(outputDir, AndroidCommonUtils.AAR_DEPS_JAR_FILE_NAME);
if (!packDirectoryIntoJar(tempDir, outputJarFile, context)) {
return false;
}
final AndroidBuildTestingManager testingManager = AndroidBuildTestingManager.getTestingManager();
if (testingManager != null && outputJarFile.isFile()) {
testingManager.getCommandExecutor().checkJarContent("aar_dependencies_package_jar", outputJarFile.getPath());
}
outputConsumer.registerOutputFile(outputJarFile, srcJarFiles);
return true;
}
catch (IOException e) {
AndroidJpsUtil.reportExceptionError(context, null, e, BUILDER_NAME);
return false;
}
finally {
if (tempDir != null) {
FileUtil.delete(tempDir);
}
}
}
private static boolean packDirectoryIntoJar(final File srcDir, File dstJar, final CompileContext context) throws IOException {
final JarOutputStream jos = new JarOutputStream(new FileOutputStream(dstJar));
try {
return FileUtil.processFilesRecursively(srcDir, new Processor<File>() {
@Override
public boolean process(File file) {
if (FileUtilRt.extensionEquals(file.getName(), "class")) {
final String relPath = FileUtil.getRelativePath(srcDir, file);
if (relPath != null) {
try {
AndroidCommonUtils.packIntoJar(jos, file, relPath);
}
catch (IOException e) {
AndroidJpsUtil.reportExceptionError(context, null, e, BUILDER_NAME);
return false;
}
}
}
return true;
}
});
}
finally {
jos.close();
}
}
@NotNull
@Override
public String getPresentableName() {
return BUILDER_NAME;
}
}