From 0f13b66bc3e8eefe2bfcbe164571772397553018 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Tue, 13 Mar 2012 17:52:17 +0400 Subject: [PATCH] android-jps: support circular dependencies between android libs (IDEA-79737), create generated dirs before compilation if necessary, clear them when rebuild --- .../AndroidAdditionalRootProviderService.java | 17 +-- .../AndroidSourceGeneratingBuilder.java | 127 +++++++++++++++--- .../android/compiler/AndroidAptCompiler.java | 2 - 3 files changed, 113 insertions(+), 33 deletions(-) diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidAdditionalRootProviderService.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidAdditionalRootProviderService.java index d7314e4312ab..4e02aecbbeca 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidAdditionalRootProviderService.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidAdditionalRootProviderService.java @@ -1,6 +1,5 @@ package org.jetbrains.jps.android; -import com.intellij.openapi.diagnostic.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.jps.Module; import org.jetbrains.jps.idea.AdditionalRootsProviderService; @@ -13,7 +12,6 @@ import java.util.List; * @author Eugene.Kudelevsky */ public class AndroidAdditionalRootProviderService extends AdditionalRootsProviderService { - private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.android.AndroidAdditionalRootProviderService"); @NotNull @Override @@ -21,19 +19,10 @@ public class AndroidAdditionalRootProviderService extends AdditionalRootsProvide final File generatedSourcesRoot = AndroidJpsUtil.getGeneratedSourcesStorage(module); final List result = new ArrayList(); - result.add(createSubdir(generatedSourcesRoot, AndroidJpsUtil.AAPT_GENERATED_SOURCE_ROOT_NAME)); - result.add(createSubdir(generatedSourcesRoot, AndroidJpsUtil.AIDL_GENERATED_SOURCE_ROOT_NAME)); - result.add(createSubdir(generatedSourcesRoot, AndroidJpsUtil.RENDERSCRIPT_GENERATED_SOURCE_ROOT_NAME)); + result.add(new File(generatedSourcesRoot, AndroidJpsUtil.AAPT_GENERATED_SOURCE_ROOT_NAME).getPath()); + result.add(new File(generatedSourcesRoot, AndroidJpsUtil.AIDL_GENERATED_SOURCE_ROOT_NAME).getPath()); + result.add(new File(generatedSourcesRoot, AndroidJpsUtil.RENDERSCRIPT_GENERATED_SOURCE_ROOT_NAME).getPath()); return result; } - - @NotNull - private static String createSubdir(@NotNull File dir, @NotNull String name) { - final File aaptSourceRoot = new File(dir, name); - if (!aaptSourceRoot.exists() && !aaptSourceRoot.mkdirs()) { - LOG.info("Cannot create folder " + aaptSourceRoot.getPath()); - } - return aaptSourceRoot.getPath(); - } } diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java index 150af9e43129..c3f8d80ef2cd 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java @@ -63,7 +63,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { if (context.isCompilingTests() || !AndroidJpsUtil.containsAndroidFacet(chunk)) { return ModuleLevelBuilder.ExitCode.OK; } - + try { return doBuild(context, chunk); } @@ -104,6 +104,26 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { } boolean success = true; + if (context.isProjectRebuild()) { + for (Module module : moduleDataMap.keySet()) { + final File generatedSourcesStorage = AndroidJpsUtil.getGeneratedSourcesStorage(module); + if (generatedSourcesStorage.exists() && + !deleteAndMarkRecursively(generatedSourcesStorage, context)) { + success = false; + } + + final File generatedResourcesStorage = AndroidJpsUtil.getGeneratedResourcesStorage(module); + if (generatedResourcesStorage.exists() && + !deleteAndMarkRecursively(generatedResourcesStorage, context)) { + success = false; + } + } + } + + if (!success) { + return ExitCode.ABORT; + } + if (!runAidlCompiler(context, idlFilesToCompile, moduleDataMap)) { success = false; } @@ -148,13 +168,21 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { } final File generatedSourcesDir = AndroidJpsUtil.getGeneratedSourcesStorage(module); final File aidlOutputDirectory = new File(generatedSourcesDir, AndroidJpsUtil.AIDL_GENERATED_SOURCE_ROOT_NAME); + + if (!aidlOutputDirectory.exists() && !aidlOutputDirectory.mkdirs()) { + context.processMessage( + new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot create directory " + aidlOutputDirectory.getPath())); + success = false; + continue; + } + final IAndroidTarget target = moduleData.getAndroidTarget(); try { final File[] sourceRoots = AndroidJpsUtil.getSourceRootsForModuleAndDependencies(module); final String[] sourceRootPaths = AndroidJpsUtil.toPaths(sourceRoots); final String packageName = computePackageForFile(context, file); - + if (packageName == null) { context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, AndroidJpsBundle.message("android.jps.errors.cannot.compute.package", filePath))); @@ -210,7 +238,21 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { final File generatedSourcesDir = AndroidJpsUtil.getGeneratedSourcesStorage(module); final File rsOutputDirectory = new File(generatedSourcesDir, AndroidJpsUtil.RENDERSCRIPT_GENERATED_SOURCE_ROOT_NAME); + if (!rsOutputDirectory.exists() && !rsOutputDirectory.mkdirs()) { + context.processMessage( + new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot create directory " + rsOutputDirectory.getPath())); + success = false; + continue; + } + final File generatedResourcesDir = AndroidJpsUtil.getGeneratedResourcesStorage(module); + final File rawDir = new File(generatedResourcesDir, "raw"); + + if (!rawDir.exists() && !rawDir.mkdirs()) { + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot create directory " + rawDir.getPath())); + success = false; + continue; + } final IAndroidTarget target = moduleData.getAndroidTarget(); final String sdkLocation = moduleData.getSdkLocation(); @@ -221,7 +263,6 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { try { tmpOutputDirectory = FileUtil.createTempDirectory("generated-rs-temp", null); final String depFolderPath = getDependencyFolder(context, file, tmpOutputDirectory); - final File rawDir = new File(generatedResourcesDir, "raw"); final Map> messages = AndroidRenderscript.execute(sdkLocation, target, filePath, tmpOutputDirectory.getPath(), depFolderPath, rawDir.getPath()); @@ -299,7 +340,15 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { continue; } - final Set depLibPackagesSet = getDepLibPackages(module); + final Map depLibPackageMap = getDepLibPackages(module); + final Map packageMap = new HashMap(depLibPackageMap); + packageMap.put(module, packageName); + + if (hasBadCircularDependencies(facet, packageMap)) { + continue; + } + + final Set depLibPackagesSet = new HashSet(depLibPackageMap.values()); depLibPackagesSet.remove(packageName); final Set resources = collectResources(resPaths); @@ -315,14 +364,17 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { final File generatedSourcesDir = AndroidJpsUtil.getGeneratedSourcesStorage(module); final File aptOutputDirectory = new File(generatedSourcesDir, AndroidJpsUtil.AAPT_GENERATED_SOURCE_ROOT_NAME); - if (aptOutputDirectory.exists()) { - // clear directory, because it may contain obsolete files (ex. if package name was changed) - final List filesToDelete = collectJavaFilesRecursively(aptOutputDirectory); - FileUtil.delete(aptOutputDirectory); + // clear directory, because it may contain obsolete files (ex. if package name was changed) + if (!deleteAndMarkRecursively(aptOutputDirectory, context)) { + success = false; + continue; + } - for (File file : filesToDelete) { - context.markDeleted(file); - } + if (!aptOutputDirectory.mkdirs()) { + context.processMessage( + new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot create directory " + aptOutputDirectory.getPath())); + success = false; + continue; } context.processMessage(new ProgressMessage(AndroidJpsBundle.message("android.jps.progress.aapt", module.getName()))); @@ -350,6 +402,21 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { return success; } + private static boolean deleteAndMarkRecursively(@NotNull File dir, @NotNull CompileContext context) throws IOException { + if (dir.exists()) { + final List filesToDelete = collectJavaFilesRecursively(dir); + if (!FileUtil.delete(dir)) { + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot delete " + dir.getPath())); + return false; + } + + for (File file : filesToDelete) { + context.markDeleted(file); + } + } + return true; + } + private static boolean markDirtyRecursively(@NotNull File dir, @NotNull final CompileContext context) { final Ref success = Ref.create(true); @@ -389,8 +456,8 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { } @NotNull - private static Set getDepLibPackages(@NotNull Module module) throws IOException { - final Set result = new HashSet(); + private static Map getDepLibPackages(@NotNull Module module) throws IOException { + final Map result = new HashMap(); for (AndroidFacet depFacet : AndroidJpsUtil.getAllDependentAndroidLibraries(module)) { final File depManifestFile = AndroidJpsUtil.getManifestFileForCompilationPath(depFacet); @@ -399,7 +466,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { final String packageName = parsePackageNameFromManifestFile(depManifestFile); if (packageName != null) { - result.add(packageName); + result.put(depFacet.getModule(), packageName); } } } @@ -562,7 +629,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { assert relativePath != null; return genFolder.getPath() + '/' + relativePath; } - + @Nullable private static Map computeModuleDatas(@NotNull Collection modules, @NotNull CompileContext context) { final Map moduleDataMap = new HashMap(); @@ -575,7 +642,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { continue; } - final Pair pair = AndroidJpsUtil.getAndroidPlatform(module, context, BUILDER_NAME); + final Pair pair = AndroidJpsUtil.getAndroidPlatform(module, context, BUILDER_NAME); if (pair == null) { success = false; continue; @@ -600,7 +667,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { if (relPath == null) { return null; } - + return FileUtil.toSystemIndependentName(relPath).replace('/', '.'); } @@ -609,6 +676,32 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { return "Android Source Generating Builder"; } + // see IDEA-79737 for details + private static boolean hasBadCircularDependencies(@NotNull AndroidFacet facet, @NotNull Map packages) throws IOException { + final String aPackage = packages.get(facet.getModule()); + if (aPackage == null || aPackage.length() == 0) { + return false; + } + + final List dependencies = AndroidJpsUtil.getAllDependentAndroidLibraries(facet.getModule()); + + for (AndroidFacet depFacet : dependencies) { + final String depPackage = packages.get(depFacet.getModule()); + + if (!aPackage.equals(depPackage)) { + continue; + } + final List depDependencies = AndroidJpsUtil.getAllDependentAndroidLibraries(depFacet.getModule()); + + if (depDependencies.contains(facet) && + dependencies.contains(depFacet) && + depFacet.getModule().getName().compareTo(facet.getModule().getName()) < 0) { + return true; + } + } + return false; + } + private static void addMessages(@NotNull CompileContext context, @NotNull Map> messages, @NotNull String sourcePath, diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java index dcdc59d8d4dd..e69076432b2c 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java @@ -260,8 +260,6 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { return items.toArray(new GenerationItem[items.size()]); } - - // todo: support this in android-jps // see IDEA-79737 for details private static boolean hasBadCircularDependencies(@NotNull AndroidFacet facet) { final List dependencies = AndroidUtils.getAllAndroidDependencies(facet.getModule(), true);