From ef174126cdc2957b29978308c22012ba017d5d57 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Tue, 7 Feb 2012 18:46:24 +0400 Subject: [PATCH] android: compilers now generate sources outside the project --- .../android/compiler/AndroidAptCompiler.java | 100 +------- .../android/compiler/AndroidCompileUtil.java | 39 ++- .../android/compiler/AndroidIdlCompiler.java | 66 +----- .../compiler/AndroidPrecompileTask.java | 42 +--- .../compiler/AndroidRenderscriptCompiler.java | 223 +++++++++--------- 5 files changed, 171 insertions(+), 299 deletions(-) diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java index 2d56bf86d2e9..a2f70b19129c 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java @@ -17,20 +17,16 @@ package org.jetbrains.android.compiler; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; -import com.intellij.compiler.impl.CompilerUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.*; -import com.intellij.openapi.compiler.ex.CompileContextEx; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; -import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; import org.jetbrains.android.compiler.tools.AndroidApt; import org.jetbrains.android.dom.manifest.Manifest; @@ -47,7 +43,6 @@ import org.jetbrains.annotations.Nullable; import java.io.DataInput; import java.io.DataOutput; -import java.io.File; import java.io.IOException; import java.util.*; @@ -80,37 +75,15 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { public GenerationItem[] generate(final CompileContext context, final GenerationItem[] items, VirtualFile outputRootDirectory) { if (items != null && items.length > 0) { context.getProgressIndicator().setText(AndroidBundle.message("android.compile.messages.generating.r.java")); - Computable computation = new Computable() { - public GenerationItem[] compute() { - if (context.getProject().isDisposed()) { - return EMPTY_GENERATION_ITEM_ARRAY; - } - return doGenerate(context, items); - } - }; - GenerationItem[] generationItems = computation.compute(); - List generatedVFiles = new ArrayList(); - for (GenerationItem item : generationItems) { - final Set generatedFiles = ((AptGenerationItem)item).myGeneratedFile2Package.keySet(); - for (File generatedFile : generatedFiles) { - CompilerUtil.refreshIOFile(generatedFile); - CompilerUtil.refreshIOFile(generatedFile.getParentFile()); - VirtualFile generatedVFile = LocalFileSystem.getInstance().findFileByIoFile(generatedFile); - if (generatedVFile != null) { - generatedVFiles.add(generatedVFile); - } - } + if (!context.getProject().isDisposed()) { + return doGenerate(context, items, outputRootDirectory); } - if (context instanceof CompileContextEx) { - ((CompileContextEx)context).markGenerated(generatedVFiles); - } - return generationItems; } return EMPTY_GENERATION_ITEM_ARRAY; } - private static GenerationItem[] doGenerate(final CompileContext context, GenerationItem[] items) { + private static GenerationItem[] doGenerate(final CompileContext context, GenerationItem[] items, VirtualFile outputRootDirectory) { List results = new ArrayList(items.length); for (GenerationItem item : items) { if (item instanceof AptGenerationItem) { @@ -120,34 +93,19 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { continue; } + final String outputDirOsPath = FileUtil.toSystemDependentName(outputRootDirectory.getPath()); + try { Map> messages = AndroidCompileUtil.toCompilerMessageCategoryKeys( AndroidApt.compile(aptItem.myAndroidTarget, aptItem.myPlatformToolsRevision, aptItem.myManifestFile.getPath(), aptItem.myPackage, - aptItem.mySourceRootPath, aptItem.myResourcesPaths, + outputDirOsPath, aptItem.myResourcesPaths, aptItem.myLibraryPackages, aptItem.myIsLibrary)); AndroidCompileUtil.addMessages(context, messages); if (messages.get(CompilerMessageCategory.ERROR).isEmpty()) { results.add(aptItem); } - for (Map.Entry entry : aptItem.myGeneratedFile2Package.entrySet()) { - final File generatedFile = entry.getKey(); - final String aPackage = entry.getValue(); - - if (generatedFile.exists()) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - if (context.getProject().isDisposed() || aptItem.myModule.isDisposed()) { - return; - } - String className = FileUtil.getNameWithoutExtension(generatedFile); - AndroidCompileUtil.removeDuplicatingClasses(aptItem.myModule, aPackage, className, - generatedFile, aptItem.mySourceRootPath); - } - }); - } - } } catch (final IOException e) { LOG.info(e); @@ -187,22 +145,17 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { final Module myModule; final VirtualFile myManifestFile; final String[] myResourcesPaths; - final String mySourceRootPath; final IAndroidTarget myAndroidTarget; - final Map myGeneratedFile2Package; - final String myPackage; final String[] myLibraryPackages; final boolean myIsLibrary; - private final Set myNonExistingFiles; final int myPlatformToolsRevision; private AptGenerationItem(@NotNull Module module, @NotNull VirtualFile manifestFile, @NotNull String[] resourcesPaths, - @NotNull String sourceRootPath, @NotNull IAndroidTarget target, int platformToolsRevision, @NotNull String aPackage, @@ -211,48 +164,11 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { myModule = module; myManifestFile = manifestFile; myResourcesPaths = resourcesPaths; - mySourceRootPath = sourceRootPath; myAndroidTarget = target; myPackage = aPackage; myLibraryPackages = libPackages; myIsLibrary = isLibrary; myPlatformToolsRevision = platformToolsRevision; - - myGeneratedFile2Package = new HashMap(); - - myGeneratedFile2Package - .put(new File(sourceRootPath, aPackage.replace('.', File.separatorChar) + File.separator + AndroidCommonUtils.R_JAVA_FILENAME), - aPackage); - - for (String libPackage : myLibraryPackages) { - myGeneratedFile2Package.put( - new File(sourceRootPath, libPackage.replace('.', File.separatorChar) + File.separator + AndroidCommonUtils.R_JAVA_FILENAME), - libPackage); - } - - myNonExistingFiles = new HashSet(); - - // We need to check only R.java files, not Manifest.java files, so add Manifest files LATER - for (File generatedFile : myGeneratedFile2Package.keySet()) { - if (!generatedFile.exists()) { - myNonExistingFiles.add(FileUtil.toSystemIndependentName(generatedFile.getPath())); - } - } - - myGeneratedFile2Package.put( - new File(sourceRootPath, aPackage.replace('.', File.separatorChar) + File.separator + AndroidCommonUtils.MANIFEST_JAVA_FILE_NAME), - aPackage); - - for (String libraryPackage : myLibraryPackages) { - myGeneratedFile2Package.put(new File(sourceRootPath, libraryPackage.replace('.', File.separatorChar) + - File.separator + - AndroidCommonUtils.MANIFEST_JAVA_FILE_NAME), libraryPackage); - } - } - - @NotNull - public Map getGeneratedFiles() { - return myGeneratedFile2Package; } public String getPath() { @@ -260,7 +176,7 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { } public ValidityState getValidityState() { - return new MyValidityState(myModule, myNonExistingFiles, myPlatformToolsRevision); + return new MyValidityState(myModule, Collections.emptySet(), myPlatformToolsRevision); } public Module getModule() { @@ -345,7 +261,7 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { final String[] libPackages = getLibPackages(module, packageName); - items.add(new AptGenerationItem(module, manifestFile, resPaths, sourceRootPath, target, platformToolsRevision, + items.add(new AptGenerationItem(module, manifestFile, resPaths, target, platformToolsRevision, packageName, libPackages, facet.getConfiguration().LIBRARY_PROJECT)); } } diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java index 9cadbdfff611..88a51f5c8cf4 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java @@ -17,6 +17,8 @@ package org.jetbrains.android.compiler; import com.android.resources.ResourceType; import com.intellij.CommonBundle; +import com.intellij.compiler.CompilerConfiguration; +import com.intellij.compiler.CompilerConfigurationImpl; import com.intellij.compiler.impl.CompileContextImpl; import com.intellij.compiler.impl.ModuleCompileScope; import com.intellij.compiler.options.CompileStepBeforeRun; @@ -27,6 +29,8 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.compiler.*; import com.intellij.openapi.compiler.Compiler; +import com.intellij.openapi.compiler.options.ExcludeEntryDescription; +import com.intellij.openapi.compiler.options.ExcludedEntriesConfiguration; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; @@ -285,17 +289,40 @@ public class AndroidCompileUtil { if (root != null) { final ModuleRootManager manager = ModuleRootManager.getInstance(module); unexcludeRootIfNeccessary(root, manager); + + boolean markedAsSource = false; + for (VirtualFile existingRoot : manager.getSourceRoots()) { - if (existingRoot == root) return; - } - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - addSourceRoot(manager, root); + if (existingRoot == root) { + markedAsSource = true; } - }); + } + + if (!markedAsSource) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + addSourceRoot(manager, root); + } + }); + } + + excludeFromCompilation(project, root); } } + private static void excludeFromCompilation(@NotNull Project project, @NotNull VirtualFile dir) { + final ExcludedEntriesConfiguration configuration = + ((CompilerConfigurationImpl)CompilerConfiguration.getInstance(project)).getExcludedEntriesConfiguration(); + + for (ExcludeEntryDescription description : configuration.getExcludeEntryDescriptions()) { + if (description.getVirtualFile() == dir) { + return; + } + } + + configuration.addExcludeEntryDescription(new ExcludeEntryDescription(dir, true, false, project)); + } + private static void removeGenModule(@NotNull final Module libModule) { final String genModuleName = getGenModuleName(libModule); final ModuleManager moduleManager = ModuleManager.getInstance(libModule.getProject()); diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidIdlCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidIdlCompiler.java index 8897732c4985..0c74c8766383 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidIdlCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidIdlCompiler.java @@ -17,18 +17,15 @@ package org.jetbrains.android.compiler; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; -import com.intellij.compiler.impl.CompilerUtil; import com.intellij.facet.FacetManager; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.*; -import com.intellij.openapi.compiler.ex.CompileContextEx; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.android.compiler.tools.AndroidIdl; import org.jetbrains.android.facet.AndroidFacet; @@ -39,7 +36,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.DataInput; -import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -59,6 +55,7 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { myProject = project; } + @Nullable @Override public VirtualFile getPresentableFile(CompileContext context, Module module, VirtualFile outputRoot, VirtualFile generatedFile) { return null; @@ -71,23 +68,7 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { public GenerationItem[] generate(CompileContext context, GenerationItem[] items, VirtualFile outputRootDirectory) { if (items != null && items.length > 0) { context.getProgressIndicator().setText("Generating AIDL files..."); - //Application application = ApplicationManager.getApplication(); - GenerationItem[] generationItems = /*application.runReadAction(new GenerateAction(context, items))*/ doGenerate(context, items); - List generatedVFiles = new ArrayList(); - for (GenerationItem item : generationItems) { - File generatedFile = ((IdlGenerationItem)item).myGeneratedFile; - if (generatedFile != null) { - CompilerUtil.refreshIOFile(generatedFile); - VirtualFile generatedVFile = LocalFileSystem.getInstance().findFileByIoFile(generatedFile); - if (generatedVFile != null) { - generatedVFiles.add(generatedVFile); - } - } - } - if (context instanceof CompileContextEx) { - ((CompileContextEx)context).markGenerated(generatedVFiles); - } - return generationItems; + return doGenerate(context, items, outputRootDirectory); } return EMPTY_GENERATION_ITEM_ARRAY; } @@ -103,7 +84,7 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { @Nullable public ValidityState createValidityState(DataInput is) throws IOException { - return null; + return TimestampValidityState.load(is); } private final static class IdlGenerationItem implements GenerationItem { @@ -111,13 +92,10 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { final VirtualFile myFile; final boolean myTestSource; final IAndroidTarget myAndroidTarget; - final File myGeneratedFile; final String myPackageName; - final String mySourceRootPath; public IdlGenerationItem(@NotNull Module module, @NotNull VirtualFile file, - @NotNull String sourceRootPath, boolean testSource, @NotNull IAndroidTarget androidTarget, @NotNull String packageName) { @@ -126,19 +104,16 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { myTestSource = testSource; myAndroidTarget = androidTarget; myPackageName = packageName; - mySourceRootPath = sourceRootPath; - myGeneratedFile = - new File(sourceRootPath, packageName.replace('.', File.separatorChar) + File.separator + file.getNameWithoutExtension() + ".java"); } @Nullable public String getPath() { - return null; + return myPackageName.replace('.', '/') + '/' + myFile.getNameWithoutExtension() + ".java"; } @Nullable public ValidityState getValidityState() { - return null; + return new TimestampValidityState(myFile.getTimeStamp()); } public Module getModule() { @@ -198,21 +173,11 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { return; } ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); - IdlGenerationItem generationItem = - new IdlGenerationItem(module, file, sourceRootPath, fileIndex.isInTestSourceContent(file), target, packageName); - if (myContext.isMake()) { - File generatedFile = generationItem.myGeneratedFile; - if (generatedFile == null || !generatedFile.exists() || generatedFile.lastModified() <= file.getModificationCount()) { - items.add(generationItem); - } - } - else { - items.add(generationItem); - } + items.add(new IdlGenerationItem(module, file, fileIndex.isInTestSourceContent(file), target, packageName)); } } - private static GenerationItem[] doGenerate(final CompileContext context, GenerationItem[] items) { + private static GenerationItem[] doGenerate(final CompileContext context, GenerationItem[] items, VirtualFile outputRootDirectory) { if (context.getProject().isDisposed()) { return EMPTY_GENERATION_ITEM_ARRAY; } @@ -229,8 +194,12 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { VirtualFile[] sourceRoots = AndroidPackagingCompiler.getSourceRootsForModuleAndDependencies(idlItem.myModule, false); final String[] sourceRootPaths = AndroidCompileUtil.toOsPaths(sourceRoots); + final String outFilePath = FileUtil.toSystemDependentName( + outputRootDirectory.getPath() + '/' + idlItem.myPackageName.replace('.', '/') + '/' + + idlItem.myFile.getNameWithoutExtension() + ".java"); + final Map> messages = AndroidCompileUtil.toCompilerMessageCategoryKeys( - AndroidIdl.execute(idlItem.myAndroidTarget, idlItem.myFile.getPath(), idlItem.myGeneratedFile.getPath(), sourceRootPaths)); + AndroidIdl.execute(idlItem.myAndroidTarget, idlItem.myFile.getPath(), outFilePath, sourceRootPaths)); ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { @@ -241,17 +210,6 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { if (messages.get(CompilerMessageCategory.ERROR).isEmpty()) { results.add(idlItem); } - if (idlItem.myGeneratedFile.exists()) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - if (idlItem.myModule.getProject().isDisposed()) return; - String className = FileUtil.getNameWithoutExtension(idlItem.myGeneratedFile); - AndroidCompileUtil.removeDuplicatingClasses(idlItem.myModule, idlItem.myPackageName, className, - idlItem.myGeneratedFile.exists() ? idlItem.myGeneratedFile : null, - idlItem.mySourceRootPath); - } - }); - } } catch (final IOException e) { ApplicationManager.getApplication().runReadAction(new Runnable() { diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java index f8355f3b7b68..2201045a0502 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidPrecompileTask.java @@ -19,7 +19,10 @@ import com.intellij.compiler.CompilerConfiguration; import com.intellij.compiler.CompilerConfigurationImpl; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.compiler.*; +import com.intellij.openapi.compiler.CompilationStatusAdapter; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.CompileTask; +import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.compiler.options.ExcludeEntryDescription; import com.intellij.openapi.compiler.options.ExcludedEntriesConfiguration; import com.intellij.openapi.diagnostic.Logger; @@ -30,16 +33,12 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.hash.HashSet; import org.jetbrains.android.AndroidProjectComponent; import org.jetbrains.android.facet.AndroidFacet; -import org.jetbrains.android.facet.AndroidRootUtil; import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.io.File; import java.util.Arrays; @@ -85,7 +84,7 @@ public class AndroidPrecompileTask implements CompileTask { }, indicator != null ? indicator.getModalityState() : ModalityState.NON_MODAL); if (context.isRebuild()) { - clearGenRootsAndResCache(facet, context); + clearResCache(facet, context); } final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform(); @@ -124,12 +123,8 @@ public class AndroidPrecompileTask implements CompileTask { return true; } - private static void clearGenRootsAndResCache(@NotNull AndroidFacet facet, @NotNull CompileContext context) { + private static void clearResCache(@NotNull AndroidFacet facet, @NotNull CompileContext context) { final Module module = facet.getModule(); - - removeAllPackages(AndroidRootUtil.getRenderscriptGenSourceRootPath(module), context); - removeAllPackages(facet.getAptGenSourceRootPath(), context); - removeAllPackages(facet.getAidlGenSourceRootPath(), context); final String dirPath = AndroidCompileUtil.findResourcesCacheDirectory(module, false, null); if (dirPath != null) { @@ -139,32 +134,7 @@ public class AndroidPrecompileTask implements CompileTask { } } } - - private static void removeAllPackages(@Nullable String sourceRootPath, @NotNull CompileContext context) { - final File sourceRoot = new File(sourceRootPath); - final File[] children = sourceRoot.listFiles(); - - if (children != null) { - for (File child : children) { - if (child.isDirectory() && - child.getName() != null && - StringUtil.isJavaIdentifier(child.getName())) { - - if (!FileUtil.delete(child)) { - context.addMessage(CompilerMessageCategory.ERROR, "Cannot delete file " + child.getAbsolutePath(), - null, -1, -1); - } - } - } - } - final VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(sourceRoot); - - if (vFile != null) { - vFile.refresh(false, true); - } - } - private static void unexcludeAllSourceRoots(Module module, ExcludedEntriesConfiguration configuration) { final VirtualFile[] sourceRoots = ModuleRootManager.getInstance(module).getSourceRoots(); diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java index 553cebfba03c..02fd7b7b83aa 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java @@ -3,7 +3,6 @@ package org.jetbrains.android.compiler; import com.android.AndroidConstants; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; -import com.intellij.compiler.impl.CompilerUtil; import com.intellij.facet.FacetManager; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.*; @@ -19,6 +18,7 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidRootUtil; @@ -60,68 +60,64 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { } final VirtualFile[] files = context.getProjectCompileScope().getFiles(AndroidRenderscriptFileType.INSTANCE, true); - final List items = new ArrayList(files.length); - for (final VirtualFile file : files) { + final Map> module2files = new HashMap>(); + + for (VirtualFile file : files) { final Module module = context.getModuleByFile(file); - final AndroidFacet facet = FacetManager.getInstance(module).getFacetByType(AndroidFacet.ID); - if (facet != null) { - final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform(); - if (platform == null) { - context.addMessage(CompilerMessageCategory.ERROR, - AndroidBundle.message("android.compilation.error.specify.platform", module.getName()), null, -1, -1); - continue; + + if (module != null) { + Collection filesForModule = module2files.get(module); + + if (filesForModule == null) { + filesForModule = new ArrayList(); + module2files.put(module, filesForModule); } - final IAndroidTarget target = platform.getTarget(); - final String sdkLocation = platform.getSdk().getLocation(); - - final String packageName = AndroidUtils.getPackageName(module, file); - if (packageName == null) { - context.addMessage(CompilerMessageCategory.ERROR, "Cannot compute package for file", file.getUrl(), -1, -1); - continue; - } - - final String resourceDirPath = AndroidRootUtil.getResourceDirPath(facet); - assert resourceDirPath != null; - - addItem(context, file, facet, resourceDirPath, sdkLocation, target, packageName, items); - - if (facet.getConfiguration().LIBRARY_PROJECT) { - final HashSet usingModules = new HashSet(); - AndroidUtils.collectModulesDependingOn(module, usingModules); - - for (final Module module1 : usingModules) { - final AndroidFacet facet1 = AndroidFacet.getInstance(module1); - if (facet1 != null) { - addItem(context, file, facet1, resourceDirPath, sdkLocation, target, packageName, items); - } - } - } + filesForModule.add(file); } } + final List items = new ArrayList(files.length); + + for (Map.Entry> entry : module2files.entrySet()) { + final Module module = entry.getKey(); + final AndroidFacet facet = FacetManager.getInstance(module).getFacetByType(AndroidFacet.ID); + if (facet == null) { + continue; + } + + final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform(); + if (platform == null) { + context.addMessage(CompilerMessageCategory.ERROR, + AndroidBundle.message("android.compilation.error.specify.platform", module.getName()), null, -1, -1); + continue; + } + + final IAndroidTarget target = platform.getTarget(); + final String sdkLocation = platform.getSdk().getLocation(); + + final String resourceDirPath = AndroidRootUtil.getResourceDirPath(facet); + assert resourceDirPath != null; + + addItem(entry.getValue(), facet, resourceDirPath, sdkLocation, target, items); + } return items.toArray(new GenerationItem[items.size()]); } }); } - private static void addItem(@NotNull final CompileContext context, - @NotNull final VirtualFile sourceFile, + private static void addItem(@NotNull final Collection sourceFiles, @NotNull final AndroidFacet facet, @NotNull final String resourceDirPath, @NotNull String sdkLocation, @NotNull final IAndroidTarget target, - @NotNull final String packageName, @NotNull final List items) { final Module module = facet.getModule(); final String sourceRootPath = AndroidRootUtil.getRenderscriptGenSourceRootPath(module); if (sourceRootPath == null) { return; } - final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(context.getProject()).getFileIndex(); final String rawDirPath = resourceDirPath + '/' + AndroidConstants.FD_RES_RAW; - - items.add(new MyGenerationItem(module, sourceFile, sourceRootPath, packageName, rawDirPath, fileIndex.isInTestSourceContent(sourceFile), - sdkLocation, target)); + items.add(new MyGenerationItem(module, sourceFiles, rawDirPath, sdkLocation, target)); } @Override @@ -133,19 +129,13 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { } context.getProgressIndicator().setText("Compiling RenderScript files..."); - final GenerationItem[] generationItems = doGenerate(context, items); + final GenerationItem[] generationItems = doGenerate(context, items, outputRootDirectory); final Set generatedVFiles = new HashSet(); final HashSet visited = new HashSet(); - for (GenerationItem item : generationItems) { - final MyGenerationItem genItem = (MyGenerationItem)item; - final File genDir = new File(genItem.myGenRootPath); - CompilerUtil.refreshIODirectories(Arrays.asList(genDir)); - final VirtualFile generatedVFile = LocalFileSystem.getInstance().findFileByIoFile(genDir); - if (generatedVFile != null) { - AndroidUtils.collectFiles(generatedVFile, visited, generatedVFiles); - } - } + outputRootDirectory.refresh(false, true); + AndroidUtils.collectFiles(outputRootDirectory, visited, generatedVFiles); + if (context instanceof CompileContextEx) { ((CompileContextEx)context).markGenerated(generatedVFiles); } @@ -169,11 +159,25 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { return new MyValidityState(in); } - private static GenerationItem[] doGenerate(@NotNull final CompileContext context, @NotNull final GenerationItem[] items) { + private static GenerationItem[] doGenerate(@NotNull final CompileContext context, + @NotNull final GenerationItem[] items, + VirtualFile outputRootDirectory) { if (context.getProject().isDisposed()) { return EMPTY_GENERATION_ITEM_ARRAY; } + // we have one item per module there, so clear output directory + final String genRootPath = FileUtil.toSystemDependentName(outputRootDirectory.getPath()); + final File genRootDir = new File(genRootPath); + if (genRootDir.exists()) { + if (!FileUtil.delete(genRootDir)) { + LOG.error("Cannot delete directory " + genRootPath); + } + if (!genRootDir.mkdir()) { + LOG.error("Cannot create directory " + genRootPath); + } + } + final List results = new ArrayList(items.length); for (final GenerationItem item : items) { if (item instanceof MyGenerationItem) { @@ -183,33 +187,35 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { continue; } - try { - final Map> messages = launchRenderscriptCompiler(context.getProject(), - genItem.mySdkLocation, - genItem.myAndroidTarget, - genItem.mySourceFile, - genItem.myGenRootPath, - genItem.myRawDirPath); - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - if (context.getProject().isDisposed()) { - return; + for (final VirtualFile sourceFile : genItem.myFiles) { + try { + final Map> messages = launchRenderscriptCompiler(context.getProject(), + genItem.mySdkLocation, + genItem.myAndroidTarget, + sourceFile, + genRootPath, + genItem.myRawDirPath); + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (context.getProject().isDisposed()) { + return; + } + addMessages(context, messages, sourceFile.getUrl()); } - addMessages(context, messages, genItem.mySourceFile.getUrl()); - } - }); + }); - if (messages.get(CompilerMessageCategory.ERROR).isEmpty()) { - results.add(genItem); - } - } - catch (final IOException e) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - if (context.getProject().isDisposed()) return; - context.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), genItem.mySourceFile.getUrl(), -1, -1); + if (messages.get(CompilerMessageCategory.ERROR).isEmpty()) { + results.add(genItem); } - }); + } + catch (final IOException e) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + public void run() { + if (context.getProject().isDisposed()) return; + context.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), sourceFile.getUrl(), -1, -1); + } + }); + } } } } @@ -288,43 +294,30 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { private static class MyGenerationItem implements GenerationItem { final Module myModule; final String mySdkLocation; - final VirtualFile mySourceFile; - final boolean myTestSource; + final Collection myFiles; final IAndroidTarget myAndroidTarget; - final String myGenRootPath; final String myRawDirPath; - final String myPackageName; - final boolean myFileExists; - final File myParentDirectory; public MyGenerationItem(@NotNull Module module, - @NotNull VirtualFile sourceFile, - @NotNull String genRootPath, - @NotNull String packageName, + @NotNull Collection files, @NotNull String rawDirPath, - boolean testSource, @NotNull String sdkLocation, @NotNull IAndroidTarget target) { myModule = module; - mySourceFile = sourceFile; + myFiles = files; myRawDirPath = rawDirPath; - myTestSource = testSource; mySdkLocation = sdkLocation; myAndroidTarget = target; - myGenRootPath = genRootPath; - myPackageName = packageName; - myParentDirectory = new File(myGenRootPath, myPackageName.replace('.', File.separatorChar)); - myFileExists = myParentDirectory.exists(); } @Nullable public String getPath() { - return null; + return ""; } @Nullable public ValidityState getValidityState() { - return new MyValidityState(mySourceFile, myFileExists); + return new MyValidityState(myFiles); } public Module getModule() { @@ -332,22 +325,28 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { } public boolean isTestSource() { - return myTestSource; + return false; } } - + private static class MyValidityState implements ValidityState { - private final long myTimestamp; - private final boolean myFileExists; - - public MyValidityState(@NotNull DataInput in) throws IOException { - myTimestamp = in.readLong(); - myFileExists = true; + private final Map myTimestamps = new HashMap(); + + MyValidityState(DataInput in) throws IOException { + final int size = in.readInt(); + + for (int i = 0; i < size; i++) { + final String path = in.readUTF(); + final long timestamp = in.readLong(); + + myTimestamps.put(path, timestamp); + } } - public MyValidityState(@NotNull VirtualFile file, boolean fileExists) { - myTimestamp = file.getTimeStamp(); - myFileExists = fileExists; + MyValidityState(@NotNull Collection files) { + for (VirtualFile file : files) { + myTimestamps.put(file.getPath(), file.getTimeStamp()); + } } @Override @@ -355,15 +354,17 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { if (!(otherState instanceof MyValidityState)) { return false; } - - final MyValidityState st = (MyValidityState)otherState; - return myTimestamp == st.myTimestamp && - myFileExists == st.myFileExists; + return ((MyValidityState)otherState).myTimestamps.equals(myTimestamps); } @Override public void save(DataOutput out) throws IOException { - out.writeLong(myTimestamp); + out.writeInt(myTimestamps.size()); + + for (Map.Entry entry : myTimestamps.entrySet()) { + out.writeUTF(entry.getKey()); + out.writeLong(entry.getValue()); + } } } }