android: compilers now generate sources outside the project

This commit is contained in:
Eugene Kudelevsky
2012-02-08 15:41:39 +04:00
parent e74298de11
commit ef174126cd
5 changed files with 171 additions and 299 deletions
@@ -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<GenerationItem[]> computation = new Computable<GenerationItem[]>() {
public GenerationItem[] compute() {
if (context.getProject().isDisposed()) {
return EMPTY_GENERATION_ITEM_ARRAY;
}
return doGenerate(context, items);
}
};
GenerationItem[] generationItems = computation.compute();
List<VirtualFile> generatedVFiles = new ArrayList<VirtualFile>();
for (GenerationItem item : generationItems) {
final Set<File> 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<GenerationItem> results = new ArrayList<GenerationItem>(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<CompilerMessageCategory, List<String>> 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<File, String> 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<File, String> myGeneratedFile2Package;
final String myPackage;
final String[] myLibraryPackages;
final boolean myIsLibrary;
private final Set<String> 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<File, String>();
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<String>();
// 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<File, String> 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.<String>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));
}
}
@@ -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());
@@ -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<VirtualFile> generatedVFiles = new ArrayList<VirtualFile>();
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<CompilerMessageCategory, List<String>> 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() {
@@ -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();
@@ -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<GenerationItem> items = new ArrayList<GenerationItem>(files.length);
for (final VirtualFile file : files) {
final Map<Module, Collection<VirtualFile>> module2files = new HashMap<Module, Collection<VirtualFile>>();
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<VirtualFile> filesForModule = module2files.get(module);
if (filesForModule == null) {
filesForModule = new ArrayList<VirtualFile>();
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<Module> usingModules = new HashSet<Module>();
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<GenerationItem> items = new ArrayList<GenerationItem>(files.length);
for (Map.Entry<Module, Collection<VirtualFile>> 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<VirtualFile> sourceFiles,
@NotNull final AndroidFacet facet,
@NotNull final String resourceDirPath,
@NotNull String sdkLocation,
@NotNull final IAndroidTarget target,
@NotNull final String packageName,
@NotNull final List<GenerationItem> 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<VirtualFile> generatedVFiles = new HashSet<VirtualFile>();
final HashSet<VirtualFile> visited = new HashSet<VirtualFile>();
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<GenerationItem> results = new ArrayList<GenerationItem>(items.length);
for (final GenerationItem item : items) {
if (item instanceof MyGenerationItem) {
@@ -183,33 +187,35 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler {
continue;
}
try {
final Map<CompilerMessageCategory, List<String>> 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<CompilerMessageCategory, List<String>> 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<VirtualFile> 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<VirtualFile> 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<String, Long> myTimestamps = new HashMap<String, Long>();
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<VirtualFile> 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<String, Long> entry : myTimestamps.entrySet()) {
out.writeUTF(entry.getKey());
out.writeLong(entry.getValue());
}
}
}
}