blob: 4e6538f350233e13c6d9655aa4407b118d2915ef [file] [log] [blame]
package org.jetbrains.jps.android.builder;
import com.intellij.openapi.util.io.FileUtil;
import gnu.trove.THashMap;
import gnu.trove.THashSet;
import org.jetbrains.android.util.AndroidCommonUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.android.*;
import org.jetbrains.jps.android.model.JpsAndroidDexCompilerConfiguration;
import org.jetbrains.jps.android.model.JpsAndroidExtensionService;
import org.jetbrains.jps.android.model.JpsAndroidModuleExtension;
import org.jetbrains.jps.builders.BuildRootDescriptor;
import org.jetbrains.jps.builders.BuildTarget;
import org.jetbrains.jps.builders.BuildTargetRegistry;
import org.jetbrains.jps.builders.TargetOutputIndex;
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
import org.jetbrains.jps.builders.storage.BuildDataPaths;
import org.jetbrains.jps.cmdline.ProjectDescriptor;
import org.jetbrains.jps.incremental.CompileContext;
import org.jetbrains.jps.incremental.ModuleBuildTarget;
import org.jetbrains.jps.indices.IgnoredFileIndex;
import org.jetbrains.jps.indices.ModuleExcludeIndex;
import org.jetbrains.jps.model.JpsModel;
import org.jetbrains.jps.model.module.JpsModule;
import java.io.File;
import java.io.PrintWriter;
import java.util.*;
/**
* @author Eugene.Kudelevsky
*/
public class AndroidDexBuildTarget extends AndroidBuildTarget {
public AndroidDexBuildTarget(@NotNull JpsModule module) {
super(MyTargetType.INSTANCE, module);
}
@Override
public void writeConfiguration(ProjectDescriptor pd, PrintWriter out) {
super.writeConfiguration(pd, out);
final JpsAndroidDexCompilerConfiguration c = JpsAndroidExtensionService.
getInstance().getDexCompilerConfiguration(getModule().getProject());
if (c != null) {
out.println(c.getVmOptions());
out.println(c.getMaxHeapSize());
out.println(c.isOptimize());
out.println(c.isForceJumbo());
out.println(c.isCoreLibrary());
out.println(c.getProguardVmOptions());
}
}
@NotNull
@Override
protected List<BuildRootDescriptor> doComputeRootDescriptors(JpsModel model,
ModuleExcludeIndex index,
IgnoredFileIndex ignoredFileIndex,
BuildDataPaths dataPaths) {
final JpsAndroidModuleExtension extension = AndroidJpsUtil.getExtension(myModule);
assert extension != null;
if (extension.isLibrary()) {
return Collections.emptyList();
}
final Map<String, String> libPackage2ModuleName = new THashMap<String, String>(FileUtil.PATH_HASHING_STRATEGY);
final Set<String> appClassesDirs = new THashSet<String>(FileUtil.PATH_HASHING_STRATEGY);
final Set<String> javaClassesDirs = new THashSet<String>(FileUtil.PATH_HASHING_STRATEGY);
final Set<String> libClassesDirs = new THashSet<String>(FileUtil.PATH_HASHING_STRATEGY);
final File moduleClassesDir = new ModuleBuildTarget(
myModule, JavaModuleBuildTargetType.PRODUCTION).getOutputDir();
if (moduleClassesDir != null) {
appClassesDirs.add(moduleClassesDir.getPath());
}
AndroidJpsUtil.processClasspath(dataPaths, myModule, new AndroidDependencyProcessor() {
@Override
public void processAndroidLibraryPackage(@NotNull File file, @NotNull JpsModule depModule) {
libPackage2ModuleName.put(file.getPath(), depModule.getName());
}
@Override
public void processAndroidLibraryOutputDirectory(@NotNull File dir) {
libClassesDirs.add(dir.getPath());
}
@Override
public void processJavaModuleOutputDirectory(@NotNull File dir) {
javaClassesDirs.add(dir.getPath());
}
@Override
public boolean isToProcess(@NotNull AndroidDependencyType type) {
return type == AndroidDependencyType.ANDROID_LIBRARY_PACKAGE ||
type == AndroidDependencyType.ANDROID_LIBRARY_OUTPUT_DIRECTORY ||
type == AndroidDependencyType.JAVA_MODULE_OUTPUT_DIR;
}
}, false, false);
if (extension.isPackTestCode()) {
final File testModuleClassesDir = new ModuleBuildTarget(
myModule, JavaModuleBuildTargetType.TEST).getOutputDir();
if (testModuleClassesDir != null) {
appClassesDirs.add(testModuleClassesDir.getPath());
}
}
final List<BuildRootDescriptor> result = new ArrayList<BuildRootDescriptor>();
for (String classesDir : appClassesDirs) {
result.add(new MyClassesDirBuildRootDescriptor(this, new File(classesDir), ClassesDirType.ANDROID_APP));
}
for (String classesDir : libClassesDirs) {
result.add(new MyClassesDirBuildRootDescriptor(this, new File(classesDir), ClassesDirType.ANDROID_LIB));
}
for (String classesDir : javaClassesDirs) {
result.add(new MyClassesDirBuildRootDescriptor(this, new File(classesDir), ClassesDirType.JAVA));
}
final File preDexOutputDir = AndroidPreDexBuildTarget.getOutputDir(dataPaths);
for (Map.Entry<String, String> entry : libPackage2ModuleName.entrySet()) {
final String libPackage = entry.getKey();
final String moduleName = entry.getValue();
final File libPackageJarFile = new File(libPackage);
assert AndroidPreDexBuilder.canBePreDexed(libPackageJarFile);
result.add(new MyJarBuildRootDescriptor(this, libPackageJarFile, true, false));
result.add(new MyJarBuildRootDescriptor(this, new File(
new File(preDexOutputDir, moduleName), libPackageJarFile.getName()), true, true));
}
final AndroidPlatform platform = AndroidJpsUtil.getAndroidPlatform(myModule, null, null);
if (platform != null) {
for (String jarOrLibDir : AndroidJpsUtil.getExternalLibraries(dataPaths, myModule, platform, false, false, true)) {
File file = new File(jarOrLibDir);
File preDexedFile = file;
if (AndroidPreDexBuilder.canBePreDexed(file)) {
final String preDexedFileName = AndroidPreDexBuilder.getOutputFileNameForExternalJar(file);
if (preDexedFileName != null) {
preDexedFile = new File(preDexOutputDir, preDexedFileName);
}
}
result.add(new MyJarBuildRootDescriptor(this, file, false, false));
result.add(new MyJarBuildRootDescriptor(this, preDexedFile, false, true));
}
}
for (String path : AndroidJpsUtil.getProvidedLibraries(dataPaths, myModule)) {
result.add(new MyProvidedJarBuildRootDescriptor(this, new File(path)));
}
return result;
}
@NotNull
@Override
public Collection<File> getOutputRoots(CompileContext context) {
return Collections.singletonList(getOutputFile(context));
}
@NotNull
public File getOutputFile(CompileContext context) {
return getOutputFile(context.getProjectDescriptor().dataManager.getDataPaths(), myModule);
}
@NotNull
public static File getOutputFile(@NotNull BuildDataPaths dataPaths, @NotNull JpsModule module) {
final File dir = AndroidJpsUtil.getDirectoryForIntermediateArtifacts(dataPaths, module);
return new File(dir, AndroidCommonUtils.CLASSES_FILE_NAME);
}
@Override
public Collection<BuildTarget<?>> computeDependencies(BuildTargetRegistry registry, TargetOutputIndex outputIndex) {
final List<BuildTarget<?>> result = new ArrayList<BuildTarget<?>>(
super.computeDependencies(registry, outputIndex));
result.add(new AndroidAarDepsBuildTarget(myModule));
result.add(new AndroidPreDexBuildTarget(myModule.getProject()));
return result;
}
public static class MyTargetType extends AndroidBuildTargetType<AndroidDexBuildTarget> {
public static final MyTargetType INSTANCE = new MyTargetType();
private MyTargetType() {
super(AndroidCommonUtils.DEX_BUILD_TARGET_TYPE_ID, "DEX");
}
@Override
public AndroidDexBuildTarget createBuildTarget(@NotNull JpsAndroidModuleExtension extension) {
return !extension.isLibrary() ? new AndroidDexBuildTarget(extension.getModule()) : null;
}
}
public enum ClassesDirType {
ANDROID_APP, ANDROID_LIB, JAVA
}
public static class MyClassesDirBuildRootDescriptor extends AndroidClassesDirBuildRootDescriptor {
private final ClassesDirType myClassesDirType;
public MyClassesDirBuildRootDescriptor(@NotNull BuildTarget target,
@NotNull File root,
@NotNull ClassesDirType classesDirType) {
super(target, root);
myClassesDirType = classesDirType;
}
@NotNull
public ClassesDirType getClassesDirType() {
return myClassesDirType;
}
}
public static class MyProvidedJarBuildRootDescriptor extends AndroidFileBasedBuildRootDescriptor {
public MyProvidedJarBuildRootDescriptor(@NotNull BuildTarget target, @NotNull File file) {
super(target, file);
}
}
public static class MyJarBuildRootDescriptor extends AndroidFileBasedBuildRootDescriptor {
private final boolean myLibPackage;
private final boolean myPreDexed;
public MyJarBuildRootDescriptor(@NotNull BuildTarget target, @NotNull File file, boolean libPackage, boolean preDexed) {
super(target, file);
myLibPackage = libPackage;
myPreDexed = preDexed;
}
public boolean isLibPackage() {
return myLibPackage;
}
public boolean isPreDexed() {
return myPreDexed;
}
}
}