blob: 753b7e99f671f96b0c222f928a5596c740e4c43d [file] [log] [blame]
package org.jetbrains.jps.android;
import com.android.tools.idea.jps.AndroidTargetBuilder;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.FileUtilRt;
import org.jetbrains.android.util.AndroidBuildTestingManager;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.android.builder.AndroidPreDexBuildTarget;
import org.jetbrains.jps.builders.BuildOutputConsumer;
import org.jetbrains.jps.builders.DirtyFilesHolder;
import org.jetbrains.jps.builders.FileProcessor;
import org.jetbrains.jps.incremental.CompileContext;
import org.jetbrains.jps.incremental.ProjectBuildException;
import org.jetbrains.jps.incremental.StopBuildException;
import org.jetbrains.jps.incremental.messages.BuildMessage;
import org.jetbrains.jps.incremental.messages.CompilerMessage;
import org.jetbrains.jps.incremental.messages.ProgressMessage;
import org.jetbrains.jps.model.JpsProject;
import org.jetbrains.jps.model.module.JpsModule;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author Eugene.Kudelevsky
*/
public class AndroidPreDexBuilder extends AndroidTargetBuilder<AndroidPreDexBuildTarget.MyRootDescriptor, AndroidPreDexBuildTarget> {
@NonNls private static final String BUILDER_NAME = "Android Pre Dex";
protected AndroidPreDexBuilder() {
super(Collections.singletonList(AndroidPreDexBuildTarget.MyTargetType.INSTANCE));
}
@Nullable
public static String getOutputFileNameForExternalJar(@NotNull File srcFile) {
final String canonicalPath = FileUtil.toCanonicalPath(srcFile.getAbsolutePath());
if (canonicalPath == null) {
return null;
}
if (AndroidBuildTestingManager.getTestingManager() != null) {
return srcFile.getName();
}
final int hashCode = canonicalPath.hashCode();
return FileUtil.getNameWithoutExtension(srcFile) + "-" +
Integer.toHexString(hashCode) + ".jar";
}
@Override
protected void buildTarget(@NotNull AndroidPreDexBuildTarget target,
@NotNull DirtyFilesHolder<AndroidPreDexBuildTarget.MyRootDescriptor, AndroidPreDexBuildTarget> holder,
@NotNull BuildOutputConsumer outputConsumer,
@NotNull final CompileContext context) throws ProjectBuildException, IOException {
if (!doBuild(target, holder, outputConsumer, context)) {
throw new StopBuildException();
}
}
private static boolean doBuild(@NotNull AndroidPreDexBuildTarget target,
@NotNull DirtyFilesHolder<AndroidPreDexBuildTarget.MyRootDescriptor, AndroidPreDexBuildTarget> holder,
@NotNull BuildOutputConsumer outputConsumer,
@NotNull CompileContext context) throws IOException, ProjectBuildException {
final List<Pair<File, String>> filesToPreDex = new ArrayList<Pair<File, String>>();
holder.processDirtyFiles(new FileProcessor<AndroidPreDexBuildTarget.MyRootDescriptor, AndroidPreDexBuildTarget>() {
@Override
public boolean apply(AndroidPreDexBuildTarget target, File file, AndroidPreDexBuildTarget.MyRootDescriptor root) throws IOException {
if (canBePreDexed(file) && file.isFile()) {
filesToPreDex.add(Pair.create(file, root.getModuleName()));
}
return true;
}
});
final JpsProject project = target.getProject();
AndroidPlatform platform = null;
for (JpsModule module : project.getModules()) {
if (AndroidJpsUtil.getExtension(module) != null) {
platform = AndroidJpsUtil.getAndroidPlatform(module, context, BUILDER_NAME);
break;
}
}
if (platform == null) {
return false;
}
if (!filesToPreDex.isEmpty()) {
final File outputDir = target.getOutputFile(context);
for (Pair<File, String> pair : filesToPreDex) {
context.checkCanceled();
final File srcFile = pair.getFirst();
final String moduleName = pair.getSecond();
final String srcFilePath = srcFile.getAbsolutePath();
final File outputFile;
if (moduleName != null) {
context.processMessage(new ProgressMessage("Pre-dex [" + moduleName + "]"));
outputFile = new File(new File(outputDir, moduleName), srcFile.getName());
}
else {
context.processMessage(new ProgressMessage("Pre-dex: " + srcFile.getName()));
final String outputFileName = getOutputFileNameForExternalJar(srcFile);
if (outputFileName == null) {
context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR,
"Cannot pre-dex file " + srcFilePath + ": incorrect path", srcFilePath));
return false;
}
outputFile = new File(outputDir, outputFileName);
}
if (AndroidJpsUtil.createDirIfNotExist(outputFile.getParentFile(), context, BUILDER_NAME) == null) {
return false;
}
if (!AndroidDexBuilder.runDex(platform, outputFile.getPath(), new String[]{srcFilePath}, context,
project, outputConsumer, BUILDER_NAME, srcFile.getName())) {
return false;
}
}
}
return true;
}
public static boolean canBePreDexed(@NotNull File file) {
return "jar".equals(FileUtilRt.getExtension(file.getName()));
}
@NotNull
@Override
public String getPresentableName() {
return BUILDER_NAME;
}
}