| package org.jetbrains.jps.android.builder; |
| |
| import com.intellij.openapi.util.io.FileUtil; |
| import com.intellij.util.containers.HashSet; |
| import org.jetbrains.android.util.AndroidCommonUtils; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.jetbrains.jps.android.AndroidJpsUtil; |
| import org.jetbrains.jps.android.AndroidPlatform; |
| import org.jetbrains.jps.android.model.JpsAndroidModuleExtension; |
| import org.jetbrains.jps.builders.*; |
| import org.jetbrains.jps.builders.impl.BuildRootDescriptorImpl; |
| import org.jetbrains.jps.builders.storage.BuildDataPaths; |
| import org.jetbrains.jps.incremental.CompileContext; |
| import org.jetbrains.jps.indices.IgnoredFileIndex; |
| import org.jetbrains.jps.indices.ModuleExcludeIndex; |
| import org.jetbrains.jps.model.JpsModel; |
| import org.jetbrains.jps.model.JpsProject; |
| import org.jetbrains.jps.model.module.JpsDependencyElement; |
| import org.jetbrains.jps.model.module.JpsModule; |
| import org.jetbrains.jps.model.module.JpsModuleDependency; |
| |
| import java.io.File; |
| import java.util.*; |
| |
| /** |
| * @author Eugene.Kudelevsky |
| */ |
| public class AndroidPreDexBuildTarget extends BuildTarget<AndroidPreDexBuildTarget.MyRootDescriptor> { |
| private static final String ID = "only"; |
| |
| private final JpsProject myProject; |
| |
| public static final String PRE_DEXED_LIBS_DIRECTORY_NAME = "pre_dexed_libs"; |
| |
| public AndroidPreDexBuildTarget(@NotNull JpsProject project) { |
| super(MyTargetType.INSTANCE); |
| myProject = project; |
| } |
| |
| @Override |
| public String getId() { |
| return ID; |
| } |
| |
| @Override |
| public Collection<BuildTarget<?>> computeDependencies(BuildTargetRegistry targetRegistry, TargetOutputIndex outputIndex) { |
| final List<BuildTarget<?>> result = new ArrayList<BuildTarget<?>>(); |
| |
| for (JpsModule module : myProject.getModules()) { |
| final JpsAndroidModuleExtension extension = AndroidJpsUtil.getExtension(module); |
| |
| if (extension != null) { |
| if (extension.isLibrary()) { |
| result.add(new AndroidLibraryPackagingTarget(module)); |
| } |
| else { |
| result.add(new AndroidAarDepsBuildTarget(module)); |
| } |
| } |
| } |
| return result; |
| } |
| |
| private static void fillDepsRecursively(@NotNull JpsModule root, |
| @NotNull Set<JpsModule> libModules, |
| @NotNull Set<String> externalJars, |
| @NotNull BuildDataPaths dataPaths, |
| @NotNull AndroidPlatform platform) { |
| for (String jarOrLibDirPath : AndroidJpsUtil.getExternalLibraries(dataPaths, root, platform, false, false, true)) { |
| final String path = FileUtil.toCanonicalPath(jarOrLibDirPath); |
| |
| if (path != null) { |
| externalJars.add(path); |
| } |
| } |
| |
| for (JpsDependencyElement dependencyElement : root.getDependenciesList().getDependencies()) { |
| if (dependencyElement instanceof JpsModuleDependency) { |
| final JpsModule depModule = ((JpsModuleDependency)dependencyElement).getModule(); |
| |
| if (depModule != null) { |
| final JpsAndroidModuleExtension depExtension = AndroidJpsUtil.getExtension(depModule); |
| |
| if (depExtension != null && depExtension.isLibrary()) { |
| if (libModules.add(depModule)) { |
| fillDepsRecursively(depModule, libModules, externalJars, dataPaths, platform); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| @NotNull |
| @Override |
| public List<AndroidPreDexBuildTarget.MyRootDescriptor> computeRootDescriptors(JpsModel model, |
| ModuleExcludeIndex index, |
| IgnoredFileIndex ignoredFileIndex, |
| BuildDataPaths dataPaths) { |
| final List<AndroidPreDexBuildTarget.MyRootDescriptor> result = |
| new ArrayList<AndroidPreDexBuildTarget.MyRootDescriptor>(); |
| final Set<JpsModule> libModules = new HashSet<JpsModule>(); |
| final Set<String> externalJars = new HashSet<String>(); |
| |
| for (JpsModule module : myProject.getModules()) { |
| final JpsAndroidModuleExtension extension = AndroidJpsUtil.getExtension(module); |
| |
| if (extension != null && !extension.isLibrary() && extension.isPreDexingEnabled()) { |
| final AndroidPlatform platform = AndroidJpsUtil.getAndroidPlatform(module, null, null); |
| |
| if (platform != null) { |
| fillDepsRecursively(module, libModules, externalJars, dataPaths, platform); |
| } |
| } |
| } |
| |
| for (JpsModule libModule : libModules) { |
| final File classesJarFile = new AndroidLibraryPackagingTarget(libModule).getOutputFile(dataPaths); |
| result.add(new MyRootDescriptor(this, classesJarFile, libModule.getName())); |
| } |
| |
| for (String externalJarPath : externalJars) { |
| result.add(new MyRootDescriptor(this, new File(externalJarPath), null)); |
| } |
| return result; |
| } |
| |
| @Nullable |
| @Override |
| public AndroidPreDexBuildTarget.MyRootDescriptor findRootDescriptor(String rootId, BuildRootIndex rootIndex) { |
| for (AndroidPreDexBuildTarget.MyRootDescriptor descriptor : rootIndex.getTargetRoots(this, null)) { |
| if (descriptor.getRootId().equals(rootId)) { |
| return descriptor; |
| } |
| } |
| return null; |
| } |
| |
| @NotNull |
| @Override |
| public String getPresentableName() { |
| return "Android Pre-DEX"; |
| } |
| |
| @NotNull |
| @Override |
| public Collection<File> getOutputRoots(CompileContext context) { |
| return Collections.singletonList(getOutputFile(context)); |
| } |
| |
| @NotNull |
| public File getOutputFile(CompileContext context) { |
| return getOutputDir(context.getProjectDescriptor().dataManager.getDataPaths()); |
| } |
| |
| @NotNull |
| public static File getOutputDir(@NotNull BuildDataPaths dataPaths) { |
| final File dir = AndroidJpsUtil.getDirectoryForIntermediateArtifacts(dataPaths); |
| return new File(dir, PRE_DEXED_LIBS_DIRECTORY_NAME); |
| } |
| |
| @NotNull |
| public JpsProject getProject() { |
| return myProject; |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) return true; |
| if (o == null || getClass() != o.getClass()) return false; |
| |
| AndroidPreDexBuildTarget target = (AndroidPreDexBuildTarget)o; |
| |
| if (!myProject.equals(target.myProject)) return false; |
| |
| return true; |
| } |
| |
| @Override |
| public int hashCode() { |
| return myProject.hashCode(); |
| } |
| |
| public static class MyTargetType extends BuildTargetType<AndroidPreDexBuildTarget> { |
| public static final MyTargetType INSTANCE = new MyTargetType(); |
| |
| private MyTargetType() { |
| super(AndroidCommonUtils.PRE_DEX_BUILD_TARGET_TYPE_ID); |
| } |
| |
| @NotNull |
| @Override |
| public List<AndroidPreDexBuildTarget> computeAllTargets(@NotNull JpsModel model) { |
| if (!AndroidJpsUtil.isAndroidProjectWithoutGradleFacet(model.getProject())) { |
| return Collections.emptyList(); |
| } |
| return Collections.singletonList(new AndroidPreDexBuildTarget(model.getProject())); |
| } |
| |
| @NotNull |
| @Override |
| public BuildTargetLoader<AndroidPreDexBuildTarget> createLoader(@NotNull final JpsModel model) { |
| final JpsProject project = model.getProject(); |
| |
| return new BuildTargetLoader<AndroidPreDexBuildTarget>() { |
| @Nullable |
| @Override |
| public AndroidPreDexBuildTarget createTarget(@NotNull String targetId) { |
| return ID.equals(targetId) && AndroidJpsUtil.isAndroidProjectWithoutGradleFacet(project) ? new AndroidPreDexBuildTarget(project) : null; |
| } |
| }; |
| } |
| } |
| |
| public static class MyRootDescriptor extends BuildRootDescriptorImpl { |
| private final String myModuleName; |
| |
| private MyRootDescriptor(@NotNull BuildTarget target, @NotNull File root, @Nullable String moduleName) { |
| super(target, root); |
| myModuleName = moduleName; |
| } |
| |
| @Nullable |
| public String getModuleName() { |
| return myModuleName; |
| } |
| } |
| } |