From ea648b323dc0989dbdfd742182ef14e7298f4823 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Thu, 9 Feb 2012 19:46:53 +0400 Subject: [PATCH 1/6] move createSdkManager() to AndroidCommonUtils --- .../android/util/AndroidCommonUtils.java | 42 ++++++++++++++++++- .../org/jetbrains/android/sdk/AndroidSdk.java | 3 +- .../android/sdk/AndroidSdkUtils.java | 23 +--------- 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/plugins/android/rt/src/org/jetbrains/android/util/AndroidCommonUtils.java b/plugins/android/rt/src/org/jetbrains/android/util/AndroidCommonUtils.java index 450687945d47..3b54dcf9532d 100644 --- a/plugins/android/rt/src/org/jetbrains/android/util/AndroidCommonUtils.java +++ b/plugins/android/rt/src/org/jetbrains/android/util/AndroidCommonUtils.java @@ -1,8 +1,15 @@ package org.jetbrains.android.util; +import com.android.sdklib.ISdkLog; +import com.android.sdklib.SdkConstants; +import com.android.sdklib.SdkManager; +import com.intellij.openapi.util.io.FileUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.io.File; +import java.io.IOException; import java.util.Collection; import java.util.Iterator; @@ -11,7 +18,7 @@ import java.util.Iterator; */ public class AndroidCommonUtils { @NonNls public static final Object MANIFEST_JAVA_FILE_NAME = "Manifest.java"; - public static final String R_JAVA_FILENAME = "R.java"; + @NonNls public static final String R_JAVA_FILENAME = "R.java"; private AndroidCommonUtils() { } @@ -29,4 +36,37 @@ public class AndroidCommonUtils { } return builder.toString(); } + + @Nullable + public static SdkManager createSdkManager(@NotNull String path, @NotNull ISdkLog log) { + path = FileUtil.toSystemDependentName(path); + + final File f = new File(path); + if (!f.exists() || !f.isDirectory()) { + return null; + } + + final File platformsDir = new File(f, SdkConstants.FD_PLATFORMS); + if (!platformsDir.exists() || !platformsDir.isDirectory()) { + return null; + } + + return SdkManager.createManager(path + File.separatorChar, log); + } + + public static void moveAllFiles(@NotNull File from, @NotNull File to, @NotNull Collection newFiles) throws IOException { + if (from.isFile()) { + FileUtil.rename(from, to); + newFiles.add(to); + } + else { + final File[] children = from.listFiles(); + + if (children != null) { + for (File child : children) { + moveAllFiles(child, new File(to, child.getName()), newFiles); + } + } + } + } } diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java index 877dc802f84c..78cd3fbf1871 100644 --- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java +++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java @@ -33,6 +33,7 @@ import com.intellij.reference.SoftReference; import com.intellij.util.containers.HashMap; import gnu.trove.TIntObjectHashMap; import org.jetbrains.android.actions.AndroidEnableDdmsAction; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.android.util.AndroidUtils; import org.jetbrains.android.util.BufferingFileWrapper; import org.jetbrains.annotations.NotNull; @@ -152,7 +153,7 @@ public class AndroidSdk { @Nullable public static AndroidSdk parse(@NotNull String path, @NotNull ISdkLog log) { - final SdkManager manager = AndroidSdkUtils.createSdkManager(path, log); + final SdkManager manager = AndroidCommonUtils.createSdkManager(path, log); return manager != null ? new AndroidSdk(manager, path) : null; } diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java index 766e05545306..1536eac0a5e8 100644 --- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java +++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java @@ -17,9 +17,7 @@ package org.jetbrains.android.sdk; import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.ISdkLog; import com.android.sdklib.SdkConstants; -import com.android.sdklib.SdkManager; import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; @@ -36,12 +34,12 @@ import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.HashSet; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.android.util.AndroidUtils; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.File; import java.util.*; /** @@ -55,7 +53,7 @@ public class AndroidSdkUtils { } public static boolean isAndroidSdk(@NotNull String path) { - return createSdkManager(path, new EmptySdkLog()) != null; + return AndroidCommonUtils.createSdkManager(path, new EmptySdkLog()) != null; } @Nullable @@ -370,21 +368,4 @@ public class AndroidSdkUtils { public static void openModuleDependenciesConfigurable(final Module module) { ProjectSettingsService.getInstance(module.getProject()).openModuleDependenciesSettings(module, null); } - - @Nullable - public static SdkManager createSdkManager(@NotNull String path, @NotNull ISdkLog log) { - path = FileUtil.toSystemDependentName(path); - - final File f = new File(path); - if (!f.exists() || !f.isDirectory()) { - return null; - } - - final File platformsDir = new File(f, SdkConstants.FD_PLATFORMS); - if (!platformsDir.exists() || !platformsDir.isDirectory()) { - return null; - } - - return SdkManager.createManager(path + File.separatorChar, log); - } } From 4be123c3a3b1223c3653307ea1231b5986c61706 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Thu, 9 Feb 2012 19:49:22 +0400 Subject: [PATCH 2/6] move renderscript tool wrapper to 'android-rt' module --- .../compiler/tools/AndroidRenderscript.java | 58 ++++++++++++++++ .../compiler/AndroidAutogenerator.java | 29 +++----- .../compiler/AndroidRenderscriptCompiler.java | 69 ++++--------------- 3 files changed, 82 insertions(+), 74 deletions(-) create mode 100644 plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidRenderscript.java diff --git a/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidRenderscript.java b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidRenderscript.java new file mode 100644 index 000000000000..0bd16812613e --- /dev/null +++ b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidRenderscript.java @@ -0,0 +1,58 @@ +package org.jetbrains.android.compiler.tools; + +import com.android.sdklib.IAndroidTarget; +import com.android.sdklib.SdkConstants; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.ArrayUtil; +import org.jetbrains.android.util.AndroidCommonUtils; +import org.jetbrains.android.util.AndroidCompilerMessageKind; +import org.jetbrains.android.util.ExecutionUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidRenderscript { + private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.AndroidRenderscriptCompiler"); + + public static Map> execute(@NotNull final String sdkLocation, + @NotNull IAndroidTarget target, + @NotNull String sourceFilePath, + @NotNull final String genFolderPath, + @Nullable String depFolderPath, + @NotNull final String rawDirPath) + throws IOException { + final List command = new ArrayList(); + command.add( + FileUtil.toSystemDependentName(sdkLocation + '/' + SdkConstants.OS_SDK_PLATFORM_TOOLS_FOLDER + SdkConstants.FN_RENDERSCRIPT)); + command.add("-I"); + command.add(target.getPath(IAndroidTarget.ANDROID_RS_CLANG)); + command.add("-I"); + command.add(target.getPath(IAndroidTarget.ANDROID_RS)); + command.add("-p"); + command.add(FileUtil.toSystemDependentName(genFolderPath)); + command.add("-o"); + command.add(FileUtil.toSystemDependentName(rawDirPath)); + + command.add("-target-api"); + command.add(Integer.toString(target.getVersion().getApiLevel())); + + if (depFolderPath != null) { + command.add("-d"); + command.add(FileUtil.toSystemDependentName(depFolderPath)); + } + + command.add("-MD"); + command.add(FileUtil.toSystemDependentName(sourceFilePath)); + + LOG.info(AndroidCommonUtils.command2string(command)); + return ExecutionUtil.doExecute(ArrayUtil.toStringArray(command)); + } +} diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java index 5121f6a31a6f..54802f56a12e 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java @@ -20,6 +20,7 @@ import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; import org.jetbrains.android.compiler.tools.AndroidApt; import org.jetbrains.android.compiler.tools.AndroidIdl; +import org.jetbrains.android.compiler.tools.AndroidRenderscript; import org.jetbrains.android.dom.manifest.Manifest; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidRootUtil; @@ -448,13 +449,19 @@ public class AndroidAutogenerator { try { tempOutDir = FileUtil.createTempDirectory("android_renderscript_autogeneration", "tmp"); + final VirtualFile vTempOutDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(tempOutDir); - final Map> messages = AndroidRenderscriptCompiler. - launchRenderscriptCompiler(module.getProject(), item.mySdkLocation, item.myTarget, file, tempOutDir.getPath(), item.myRawDirPath); + final String depFolderPath = + vTempOutDir != null ? AndroidRenderscriptCompiler.getDependencyFolder(context.getProject(), file, vTempOutDir) : null; + + final Map> messages = AndroidCompileUtil.toCompilerMessageCategoryKeys( + AndroidRenderscript + .execute(item.mySdkLocation, item.myTarget, file.getPath(), tempOutDir.getPath(), depFolderPath, + item.myRawDirPath)); if (messages.get(CompilerMessageCategory.ERROR).size() == 0) { final List newFiles = new ArrayList(); - moveAllFiles(tempOutDir, new File(item.myGenDirPath), newFiles); + AndroidCommonUtils.moveAllFiles(tempOutDir, new File(item.myGenDirPath), newFiles); for (File newFile : newFiles) { final VirtualFile newVFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(newFile); @@ -502,22 +509,6 @@ public class AndroidAutogenerator { } } - private static void moveAllFiles(@NotNull File from, @NotNull File to, @NotNull Collection newFiles) throws IOException { - if (from.isFile()) { - FileUtil.rename(from, to); - newFiles.add(to); - } - else { - final File[] children = from.listFiles(); - - if (children != null) { - for (File child : children) { - moveAllFiles(child, new File(to, child.getName()), newFiles); - } - } - } - } - private static boolean ensureFilesWritable(@NotNull final Project project, @NotNull final Collection filesToCheck) { if (filesToCheck.size() == 0) { return true; diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java index 9dff00c3448f..d6cbc490baad 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java @@ -2,31 +2,26 @@ package org.jetbrains.android.compiler; import com.android.AndroidConstants; import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.SdkConstants; 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.diagnostic.Logger; 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.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.compiler.tools.AndroidRenderscript; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidRootUtil; import org.jetbrains.android.fileTypes.AndroidRenderscriptFileType; import org.jetbrains.android.sdk.AndroidPlatform; -import org.jetbrains.android.util.AndroidBundle; -import org.jetbrains.android.util.AndroidCommonUtils; -import org.jetbrains.android.util.AndroidUtils; +import org.jetbrains.android.util.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -40,8 +35,7 @@ import java.util.*; * @author Eugene.Kudelevsky */ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { - private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.AndroidRenderscriptCompiler"); - + private static final GenerationItem[] EMPTY_GENERATION_ITEM_ARRAY = {}; @Nullable @@ -190,13 +184,15 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { } for (final VirtualFile sourceFile : genItem.myFiles) { + final String depFolderOsPath = getDependencyFolder(context.getProject(), sourceFile, outputRootDirectory); + try { - final Map> messages = launchRenderscriptCompiler(context.getProject(), - genItem.mySdkLocation, - genItem.myAndroidTarget, - sourceFile, - genRootPath, - genItem.myRawDirPath); + final Map> messages = AndroidCompileUtil.toCompilerMessageCategoryKeys( + AndroidRenderscript + .execute(genItem.mySdkLocation, genItem.myAndroidTarget, sourceFile.getPath(), genRootPath, + depFolderOsPath, + genItem.myRawDirPath)); + ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { if (context.getProject().isDisposed()) { @@ -235,47 +231,10 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler { } } - static Map> launchRenderscriptCompiler(@NotNull Project project, - @NotNull final String sdkLocation, - @NotNull IAndroidTarget target, - @NotNull final VirtualFile sourceFile, - @NotNull final String genFolderPath, - @NotNull final String rawDirPath) - throws IOException { - final List command = new ArrayList(); - command.add( - FileUtil.toSystemDependentName(sdkLocation + '/' + SdkConstants.OS_SDK_PLATFORM_TOOLS_FOLDER + SdkConstants.FN_RENDERSCRIPT)); - command.add("-I"); - command.add(target.getPath(IAndroidTarget.ANDROID_RS_CLANG)); - command.add("-I"); - command.add(target.getPath(IAndroidTarget.ANDROID_RS)); - command.add("-p"); - command.add(FileUtil.toSystemDependentName(genFolderPath)); - command.add("-o"); - command.add(FileUtil.toSystemDependentName(rawDirPath)); - - final String sourceFilePath = FileUtil.toSystemDependentName(sourceFile.getPath()); - - final VirtualFile genFolder = LocalFileSystem.getInstance().refreshAndFindFileByPath(FileUtil.toSystemIndependentName(genFolderPath)); - if (genFolder != null) { - final String dependencyFolderPath = getDependencyFolder(project, sourceFile, genFolder); - if (dependencyFolderPath != null) { - command.add("-d"); - command.add(FileUtil.toSystemDependentName(dependencyFolderPath)); - } - } - - command.add("-MD"); - command.add(sourceFilePath); - - LOG.info(AndroidCommonUtils.command2string(command)); - return AndroidCompileUtil.execute(ArrayUtil.toStringArray(command)); - } - @Nullable - private static String getDependencyFolder(@NotNull final Project project, - @NotNull final VirtualFile sourceFile, - @NotNull final VirtualFile genFolder) { + static String getDependencyFolder(@NotNull final Project project, + @NotNull final VirtualFile sourceFile, + @NotNull final VirtualFile genFolder) { final ProjectFileIndex index = ProjectRootManager.getInstance(project).getFileIndex(); final VirtualFile sourceRoot = index.getSourceRootForFile(sourceFile); From 01ca2633a0fc1f743d8e466c0b3604537667ece1 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Thu, 9 Feb 2012 19:55:49 +0400 Subject: [PATCH 3/6] extract interface JavaSdk --- .../src/org/jetbrains/jps/JavaSdk.groovy | 20 +++++------------- .../src/org/jetbrains/jps/JavaSdkImpl.groovy | 21 +++++++++++++++++++ .../src/org/jetbrains/jps/Project.groovy | 2 +- .../org/jetbrains/jps/idea/JavaSdkType.groovy | 4 ++-- 4 files changed, 29 insertions(+), 18 deletions(-) create mode 100644 jps/model/src/org/jetbrains/jps/JavaSdkImpl.groovy diff --git a/jps/model/src/org/jetbrains/jps/JavaSdk.groovy b/jps/model/src/org/jetbrains/jps/JavaSdk.groovy index 2bd8812ce617..17aa8457d59c 100644 --- a/jps/model/src/org/jetbrains/jps/JavaSdk.groovy +++ b/jps/model/src/org/jetbrains/jps/JavaSdk.groovy @@ -1,21 +1,11 @@ package org.jetbrains.jps /** - * @author nik + * @author Eugene.Kudelevsky */ -class JavaSdk extends Sdk { - String jdkPath +public interface JavaSdk { - def JavaSdk(Project project, String name, String jdkPath, Closure initializer) { - super(project, name, initializer) - this.jdkPath = jdkPath - } + String getJavacExecutable(); - String getJavacExecutable() { - return jdkPath + File.separator + "bin" + File.separator + "javac"; - } - - String getJavaExecutable() { - return jdkPath + File.separator + "bin" + File.separator + "java"; - } -} + String getJavaExecutable(); +} \ No newline at end of file diff --git a/jps/model/src/org/jetbrains/jps/JavaSdkImpl.groovy b/jps/model/src/org/jetbrains/jps/JavaSdkImpl.groovy new file mode 100644 index 000000000000..9caa1092f55d --- /dev/null +++ b/jps/model/src/org/jetbrains/jps/JavaSdkImpl.groovy @@ -0,0 +1,21 @@ +package org.jetbrains.jps + +/** + * @author nik + */ +class JavaSdkImpl extends Sdk implements JavaSdk { + String jdkPath + + def JavaSdkImpl(Project project, String name, String jdkPath, Closure initializer) { + super(project, name, initializer) + this.jdkPath = jdkPath + } + + String getJavacExecutable() { + return jdkPath + File.separator + "bin" + File.separator + "javac"; + } + + String getJavaExecutable() { + return jdkPath + File.separator + "bin" + File.separator + "java"; + } +} diff --git a/jps/model/src/org/jetbrains/jps/Project.groovy b/jps/model/src/org/jetbrains/jps/Project.groovy index 60f0fdc74af5..3a89242c5f6a 100644 --- a/jps/model/src/org/jetbrains/jps/Project.groovy +++ b/jps/model/src/org/jetbrains/jps/Project.groovy @@ -43,7 +43,7 @@ class Project { } def JavaSdk createJavaSdk(String name, String path, Closure initializer) { - def sdk = new JavaSdk(this, name, path, initializer) + def sdk = new JavaSdkImpl(this, name, path, initializer) sdks[name] = sdk return sdk } diff --git a/jps/model/src/org/jetbrains/jps/idea/JavaSdkType.groovy b/jps/model/src/org/jetbrains/jps/idea/JavaSdkType.groovy index 6f8f80dc8032..c300e9235363 100644 --- a/jps/model/src/org/jetbrains/jps/idea/JavaSdkType.groovy +++ b/jps/model/src/org/jetbrains/jps/idea/JavaSdkType.groovy @@ -1,8 +1,8 @@ package org.jetbrains.jps.idea +import org.jetbrains.jps.JavaSdkImpl import org.jetbrains.jps.Project import org.jetbrains.jps.Sdk -import org.jetbrains.jps.JavaSdk /** * @author nik @@ -14,6 +14,6 @@ class JavaSdkType extends SdkTypeService { @Override Sdk createSdk(Project project, String name, String homePath, Node additionalData) { - return new JavaSdk(project, name, homePath, {}) + return new JavaSdkImpl(project, name, homePath, {}) } } From a9a41ab71d1582eacfc53e3564ffdd14b4596b5c Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Thu, 9 Feb 2012 19:57:02 +0400 Subject: [PATCH 4/6] log command --- .../org/jetbrains/android/compiler/tools/AndroidIdl.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidIdl.java b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidIdl.java index 16e0bc1a3175..0984f0a8e9aa 100644 --- a/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidIdl.java +++ b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidIdl.java @@ -16,7 +16,9 @@ package org.jetbrains.android.compiler.tools; import com.android.sdklib.IAndroidTarget; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.util.ArrayUtil; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.android.util.AndroidCompilerMessageKind; import org.jetbrains.android.util.ExecutionUtil; import org.jetbrains.annotations.NotNull; @@ -32,6 +34,8 @@ import java.util.Map; * @author Alexey Efimov */ public final class AndroidIdl { + private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.tools.AndroidIdl"); + private AndroidIdl() { } @@ -51,6 +55,8 @@ public final class AndroidIdl { } commands.add(file); commands.add(outFile); + + LOG.info(AndroidCommonUtils.command2string(commands)); return ExecutionUtil.doExecute(ArrayUtil.toStringArray(commands)); } From 353fcb57a47cf116fd70bd2c07f61102d7c3176a Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Thu, 9 Feb 2012 19:57:45 +0400 Subject: [PATCH 5/6] move MessageBuilderSdkLog to 'android-rt' module --- .../org/jetbrains/android/sdk/MessageBuildingSdkLog.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) rename plugins/android/{ => rt}/src/org/jetbrains/android/sdk/MessageBuildingSdkLog.java (91%) diff --git a/plugins/android/src/org/jetbrains/android/sdk/MessageBuildingSdkLog.java b/plugins/android/rt/src/org/jetbrains/android/sdk/MessageBuildingSdkLog.java similarity index 91% rename from plugins/android/src/org/jetbrains/android/sdk/MessageBuildingSdkLog.java rename to plugins/android/rt/src/org/jetbrains/android/sdk/MessageBuildingSdkLog.java index 7c36b181cd6f..49e083d10236 100644 --- a/plugins/android/src/org/jetbrains/android/sdk/MessageBuildingSdkLog.java +++ b/plugins/android/rt/src/org/jetbrains/android/sdk/MessageBuildingSdkLog.java @@ -21,11 +21,7 @@ import com.intellij.openapi.diagnostic.Logger; import org.jetbrains.annotations.NotNull; /** - * Created by IntelliJ IDEA. - * User: Eugene.Kudelevsky - * Date: Aug 25, 2009 - * Time: 5:54:47 PM - * To change this template use File | Settings | File Templates. + * @author Eugene.Kudelevsky */ public class MessageBuildingSdkLog implements ISdkLog { private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.sdk.MessageBuildingSdkLog"); From c098f1dec72ed3559cec7f9bfef0ab45e8839791 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Thu, 9 Feb 2012 19:58:53 +0400 Subject: [PATCH 6/6] android-jps-plugin initial --- .idea/modules.xml | 1 + build/scripts/layouts.gant | 4 + .../android/jps-plugin/android-jps-plugin.iml | 17 + .../org.jetbrains.jps.idea.FacetTypeService | 1 + .../org.jetbrains.jps.idea.SdkTypeService | 1 + ...g.jetbrains.jps.incremental.BuilderService | 1 + .../jps/android/AndroidBuilderService.java | 20 + .../jetbrains/jps/android/AndroidFacet.groovy | 46 ++ .../jps/android/AndroidFacetType.groovy | 22 + .../jetbrains/jps/android/AndroidSdk.groovy | 34 ++ .../jps/android/AndroidSdkType.groovy | 30 ++ .../AndroidSourceGeneratingBuilder.java | 498 ++++++++++++++++++ plugins/android/src/META-INF/plugin.xml | 6 + 13 files changed, 681 insertions(+) create mode 100644 plugins/android/jps-plugin/android-jps-plugin.iml create mode 100644 plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.idea.FacetTypeService create mode 100644 plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.idea.SdkTypeService create mode 100644 plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.incremental.BuilderService create mode 100644 plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidBuilderService.java create mode 100644 plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy create mode 100644 plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacetType.groovy create mode 100644 plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSdk.groovy create mode 100644 plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSdkType.groovy create mode 100644 plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java diff --git a/.idea/modules.xml b/.idea/modules.xml index ce8d7ca005f3..c7736ee6aa66 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -11,6 +11,7 @@ + diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index 6dc01096ba64..a092e36f46eb 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -366,6 +366,10 @@ public def layoutCommunityPlugins(String home) { } jar("android_rt.jar") {module("android-rt")} + + dir("jps") { + jar("android-jps-plugin.jar") { module("android-jps-plugin") } + } } } } diff --git a/plugins/android/jps-plugin/android-jps-plugin.iml b/plugins/android/jps-plugin/android-jps-plugin.iml new file mode 100644 index 000000000000..a2f02ccd0c76 --- /dev/null +++ b/plugins/android/jps-plugin/android-jps-plugin.iml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.idea.FacetTypeService b/plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.idea.FacetTypeService new file mode 100644 index 000000000000..a75fa45b2aa4 --- /dev/null +++ b/plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.idea.FacetTypeService @@ -0,0 +1 @@ +org.jetbrains.jps.android.AndroidFacetType \ No newline at end of file diff --git a/plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.idea.SdkTypeService b/plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.idea.SdkTypeService new file mode 100644 index 000000000000..f3084a2b366a --- /dev/null +++ b/plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.idea.SdkTypeService @@ -0,0 +1 @@ +org.jetbrains.jps.android.AndroidSdkType \ No newline at end of file diff --git a/plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.incremental.BuilderService b/plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.incremental.BuilderService new file mode 100644 index 000000000000..59103ac8ba86 --- /dev/null +++ b/plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.incremental.BuilderService @@ -0,0 +1 @@ +org.jetbrains.jps.android.AndroidBuilderService \ No newline at end of file diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidBuilderService.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidBuilderService.java new file mode 100644 index 000000000000..81b9e6eba3de --- /dev/null +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidBuilderService.java @@ -0,0 +1,20 @@ +package org.jetbrains.jps.android; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.incremental.BuilderService; +import org.jetbrains.jps.incremental.ModuleLevelBuilder; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutorService; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidBuilderService extends BuilderService { + @NotNull + @Override + public List createModuleLevelBuilders(ExecutorService executorService) { + return Arrays.asList(new AndroidSourceGeneratingBuilder()); + } +} diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy new file mode 100644 index 000000000000..e9530f165ee7 --- /dev/null +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy @@ -0,0 +1,46 @@ +package org.jetbrains.jps.android + +import com.intellij.openapi.util.io.FileUtil +import org.jetbrains.jps.Module +import org.jetbrains.jps.idea.Facet + +/** + * @author nik + */ +class AndroidFacet extends Facet { + final Module module + final String resFolderRelativePath + + AndroidFacet(Module module, String name, String resFolderRelativePath) { + this.module = module + this.name = name; + this.resFolderRelativePath = resFolderRelativePath + } + + File getResourceDir() { + return findFileByRelativeModulePath(resFolderRelativePath, true) + } + + private File findFileByRelativeModulePath(String relativePath, boolean lookInContentRoot) { + if (module.basePath != null) { + def absPath = FileUtil.toSystemIndependentName(module.basePath + relativePath) + def f = new File(absPath) + + if (f.exists()) { + return f + } + } + + if (lookInContentRoot) { + module.contentRoots.each { + def absPath = FileUtil.toSystemIndependentName(contentRoot + relativePath) + def f = new File(absPath) + + if (f.exists()) { + return f + } + } + } + return null; + } +} diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacetType.groovy b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacetType.groovy new file mode 100644 index 000000000000..ca555e24e37e --- /dev/null +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacetType.groovy @@ -0,0 +1,22 @@ +package org.jetbrains.jps.android + +import org.jetbrains.jps.MacroExpander +import org.jetbrains.jps.Module +import org.jetbrains.jps.idea.Facet +import org.jetbrains.jps.idea.FacetTypeService + +/** + * @author Eugene.Kudelevsky + */ +class AndroidFacetType extends FacetTypeService { + public static final String ID = "android" + + AndroidFacetType() { + super(ID) + } + + @Override + Facet createFacet(Module module, String name, Node facetConfiguration, MacroExpander macroExpander) { + return new AndroidFacet(module, name, ""); + } +} diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSdk.groovy b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSdk.groovy new file mode 100644 index 000000000000..b4ce00b91c41 --- /dev/null +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSdk.groovy @@ -0,0 +1,34 @@ +package org.jetbrains.jps.android + +import org.jetbrains.jps.JavaSdk +import org.jetbrains.jps.Project +import org.jetbrains.jps.Sdk +import org.jetbrains.jps.JavaSdkImpl + +/** + * @author Eugene.Kudelevsky + */ +class AndroidSdk extends Sdk implements JavaSdk { + final String sdkPath; + final String buildTargetHashString; + final String javaSdkName; + + AndroidSdk(Project project, String name, String sdkPath, String javaSdkName, String buildTargetHashString) { + super(project, name, {}) + this.sdkPath = sdkPath + this.buildTargetHashString = buildTargetHashString + this.javaSdkName = javaSdkName; + } + + @Override + String getJavacExecutable() { + def javaSdk = project.sdks[javaSdkName] + return javaSdk instanceof JavaSdkImpl ? javaSdk.getJavacExecutable() : null + } + + @Override + String getJavaExecutable() { + def javaSdk = project.sdks[javaSdkName] + return javaSdk instanceof JavaSdkImpl ? javaSdk.getJavaExecutable() : null + } +} diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSdkType.groovy b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSdkType.groovy new file mode 100644 index 000000000000..90d47d29c07c --- /dev/null +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSdkType.groovy @@ -0,0 +1,30 @@ +package org.jetbrains.jps.android + +import org.jetbrains.jps.idea.SdkTypeService +import org.jetbrains.jps.Sdk +import org.jetbrains.jps.Project + +/** + * @author Eugene.Kudelevsky + */ +class AndroidSdkType extends SdkTypeService { + AndroidSdkType() { + super("Android SDK"); + } + + @Override + Sdk createSdk(Project project, String name, String homePath, Node additionalData) { + def attributes = additionalData.attributes() + if (attributes == null) { + return null; + } + + def buildTargetHashString = (String)attributes.get("sdk") + def internalJdkName = (String)attributes.get("jdk") + + if (internalJdkName == null || buildTargetHashString == null) { + return null; + } + return new AndroidSdk(project, name, homePath, internalJdkName, buildTargetHashString) + } +} 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 new file mode 100644 index 000000000000..77abb5082d17 --- /dev/null +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java @@ -0,0 +1,498 @@ +package org.jetbrains.jps.android; + +import com.android.sdklib.IAndroidTarget; +import com.android.sdklib.SdkManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.containers.HashMap; +import com.intellij.util.containers.HashSet; +import org.jetbrains.android.compiler.tools.AndroidIdl; +import org.jetbrains.android.compiler.tools.AndroidRenderscript; +import org.jetbrains.android.sdk.MessageBuildingSdkLog; +import org.jetbrains.android.util.AndroidCommonUtils; +import org.jetbrains.android.util.AndroidCompilerMessageKind; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.*; +import org.jetbrains.jps.idea.Facet; +import org.jetbrains.jps.incremental.*; +import org.jetbrains.jps.incremental.messages.BuildMessage; +import org.jetbrains.jps.incremental.messages.CompilerMessage; +import org.jetbrains.jps.incremental.messages.ProgressMessage; +import org.jetbrains.jps.incremental.storage.SourceToOutputMapping; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.util.*; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { + private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.android.AndroidSourceGeneratingBuilder"); + + @NonNls private static final String BUILDER_NAME = "android-source-generator"; + @NonNls private static final String AIDL_EXTENSION = "aidl"; + @NonNls private static final String RENDERSCRIPT_EXTENSION = "rs"; + + public AndroidSourceGeneratingBuilder() { + super(BuilderCategory.SOURCE_GENERATOR); + } + + @Override + public String getName() { + return BUILDER_NAME; + } + + @Override + public ModuleLevelBuilder.ExitCode build(CompileContext context, ModuleChunk chunk) throws ProjectBuildException { + if (context.isCompilingTests()) { + return ModuleLevelBuilder.ExitCode.OK; + } + + try { + return doBuild(context, chunk); + } + catch (ProjectBuildException e) { + throw e; + } + catch (Exception e) { + String message = e.getMessage(); + + if (message == null) { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + //noinspection IOResourceOpenedButNotSafelyClosed + e.printStackTrace(new PrintStream(out)); + message = "Internal error: \n" + out.toString(); + } + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, message)); + throw new ProjectBuildException(message, e); + } + } + + private static ModuleLevelBuilder.ExitCode doBuild(CompileContext context, ModuleChunk chunk) throws Exception { + final Map idlFilesToCompile = new HashMap(); + final Map rsFilesToCompile = new HashMap(); + final Set modules = new HashSet(); + + context.processFilesToRecompile(chunk, new FileProcessor() { + @Override + public boolean apply(Module module, File file, String sourceRoot) throws IOException { + final AndroidFacet facet = getFacet(module); + + if (facet == null) { + return true; + } + final String ext = FileUtil.getExtension(file.getName()); + + if (AIDL_EXTENSION.equals(ext)) { + idlFilesToCompile.put(file, facet); + modules.add(facet.getModule()); + } + else if (RENDERSCRIPT_EXTENSION.equals(ext)) { + rsFilesToCompile.put(file, facet); + modules.add(facet.getModule()); + } + + return true; + } + }); + + final Map moduleDataMap = computeModuleDatas(modules, context); + + if (moduleDataMap == null) { + return ExitCode.OK; + } + + if (!runAidlCompiler(context, idlFilesToCompile, moduleDataMap)) { + return ExitCode.OK; + } + + if (!runRenderscriptCompiler(context, rsFilesToCompile, moduleDataMap)) { + return ExitCode.OK; + } + + return ExitCode.OK; + } + + private static boolean runAidlCompiler(@NotNull final CompileContext context, + @NotNull Map files, + @NotNull Map moduleDataMap) { + context.processMessage(new ProgressMessage("Processing AIDL files...")); + + boolean success = true; + + for (Map.Entry entry : files.entrySet()) { + final File file = entry.getKey(); + final Module module = entry.getValue().getModule(); + final String filePath = file.getPath(); + + final MyModuleData moduleData = moduleDataMap.get(module); + + if (!LOG.assertTrue(moduleData != null)) { + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Internal error")); + success = false; + continue; + } + final File outputDirectory = moduleData.getOutputDirectory(); + final File aidlOutputDirectory = new File(outputDirectory, "generated-aidl"); + final IAndroidTarget target = moduleData.getAndroidTarget(); + + try { + final File[] sourceRoots = getSourceRootsForModuleAndDependencies(module); + final String[] sourceRootPaths = toPaths(sourceRoots); + final String packageName = computePackageForFile(context, file); + + if (packageName == null) { + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot compute package for file", + filePath)); + success = false; + continue; + } + + final File outputFile = new File(aidlOutputDirectory, packageName.replace('.', File.separatorChar) + + File.separator + FileUtil.getNameWithoutExtension(file) + ".java"); + final String outputFilePath = outputFile.getPath(); + final Map> messages = + AndroidIdl.execute(target, filePath, outputFilePath, sourceRootPaths); + + addMessages(context, messages, filePath); + + if (messages.get(AndroidCompilerMessageKind.ERROR).size() > 0) { + success = false; + continue; + } + + final String moduleName = getCannonicalModuleName(module); + final SourceToOutputMapping sourceToOutputMap = context.getDataManager().getSourceToOutputMap(moduleName, false); + sourceToOutputMap.update(filePath, outputFilePath); + } + catch (final IOException e) { + reportExceptionError(context, filePath, e); + success = false; + } + } + return success; + } + + private static boolean runRenderscriptCompiler(@NotNull final CompileContext context, + @NotNull Map files, + @NotNull Map moduleDataMap) { + context.processMessage(new ProgressMessage("Processing Renderscript files...")); + + boolean success = true; + + for (Map.Entry entry : files.entrySet()) { + final File file = entry.getKey(); + final Module module = entry.getValue().getModule(); + + final MyModuleData moduleData = moduleDataMap.get(module); + if (!LOG.assertTrue(moduleData != null)) { + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Internal error")); + success = false; + continue; + } + + final File outputDirectory = moduleData.getOutputDirectory(); + final File rsOutputDirectory = new File(outputDirectory, "generated-rs"); + final File generatedResourcesDir = new File(outputDirectory, "generated-resources"); + + final IAndroidTarget target = moduleData.getAndroidTarget(); + final String sdkLocation = moduleData.getSdkLocation(); + final String filePath = file.getPath(); + + File tmpOutputDirectory = null; + + 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()); + + addMessages(context, messages, filePath); + + if (messages.get(AndroidCompilerMessageKind.ERROR).size() > 0) { + success = false; + } + else { + final List newFiles = new ArrayList(); + AndroidCommonUtils.moveAllFiles(tmpOutputDirectory, rsOutputDirectory, newFiles); + + final File bcFile = new File(rawDir, FileUtil.getNameWithoutExtension(file) + ".bc"); + if (bcFile.exists()) { + newFiles.add(bcFile); + } + final List newFilePaths = Arrays.asList(toPaths(newFiles.toArray(new File[newFiles.size()]))); + + final String moduleName = getCannonicalModuleName(module); + final SourceToOutputMapping sourceToOutputMap = context.getDataManager().getSourceToOutputMap(moduleName, false); + sourceToOutputMap.update(filePath, newFilePaths); + } + } + catch (IOException e) { + reportExceptionError(context, filePath, e); + success = false; + } + finally { + if (tmpOutputDirectory != null) { + FileUtil.delete(tmpOutputDirectory); + } + } + } + return success; + } + + private static void reportExceptionError(@NotNull CompileContext context, @NotNull String filePath, @NotNull Exception exception) { + final String message = exception.getMessage(); + + if (message != null) { + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, message, filePath)); + LOG.debug(exception); + } + else { + context.processMessage(new CompilerMessage(BUILDER_NAME, exception)); + } + } + + @NotNull + private static String getCannonicalModuleName(@NotNull Module module) { + return module.getName().toLowerCase(Locale.US); + } + + @Nullable + private static String getDependencyFolder(@NotNull CompileContext context, @NotNull File sourceFile, @NotNull File genFolder) { + final RootDescriptor descriptor = context.getRootsIndex().getModuleAndRoot(sourceFile); + if (descriptor == null) { + return null; + } + final File sourceRoot = descriptor.root; + + final File parent = FileUtil.getParentFile(sourceFile); + if (parent == null) { + return null; + } + + if (parent.equals(sourceRoot)) { + return genFolder.getPath(); + } + final String relativePath = FileUtil.getRelativePath(sourceRoot, parent); + assert relativePath != null; + return genFolder.getPath() + '/' + relativePath; + } + + @Nullable + private static Map computeModuleDatas(@NotNull Collection modules, @NotNull CompileContext context) + throws Exception { + final Map moduleDataMap = new HashMap(); + + boolean success = true; + + for (Module module : modules) { + + final Sdk sdk = module.getSdk(); + if (!(sdk instanceof AndroidSdk)) { + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, + "Android SDK is not specified for module " + module.getName())); + success = false; + continue; + } + final AndroidSdk androidSdk = (AndroidSdk)sdk; + + final IAndroidTarget target = parseAndroidTarget(androidSdk, context); + if (target == null) { + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, + "Android SDK is invalid or not specified for module " + module.getName())); + success = false; + continue; + } + + final File outputDir = context.getProjectPaths().getModuleOutputDir(module, false); + if (outputDir == null) { + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, + "Cannot find output directory for module " + module.getName())); + success = false; + continue; + } + + moduleDataMap.put(module, new MyModuleData(outputDir, androidSdk.getSdkPath(), target)); + } + + return success ? moduleDataMap : null; + } + + private static void addMessages(@NotNull CompileContext context, + @NotNull Map> messages, + @Nullable String sourcePath) { + for (Map.Entry> entry : messages.entrySet()) { + final AndroidCompilerMessageKind kind = entry.getKey(); + final BuildMessage.Kind buildMessageKind = toBuildMessageKind(kind); + + if (buildMessageKind == null) { + continue; + } + + for (String message : entry.getValue()) { + context.processMessage(new CompilerMessage(BUILDER_NAME, buildMessageKind, message, sourcePath)); + } + } + } + + @Nullable + private static BuildMessage.Kind toBuildMessageKind(@NotNull AndroidCompilerMessageKind kind) { + switch (kind) { + case ERROR: + return BuildMessage.Kind.ERROR; + case INFORMATION: + return BuildMessage.Kind.INFO; + case WARNING: + return BuildMessage.Kind.WARNING; + default: + LOG.error("unknown AndroidCompilerMessageKind object " + kind); + return null; + } + } + + @Nullable + private static String computePackageForFile(@NotNull CompileContext context, @NotNull File file) throws IOException { + final RootDescriptor descriptor = context.getRootsIndex().getModuleAndRoot(file); + if (descriptor == null) { + return null; + } + + final String relPath = FileUtil.getRelativePath(descriptor.root, FileUtil.getParentFile(file)); + if (relPath == null) { + return null; + } + + return FileUtil.toSystemIndependentName(relPath).replace('/', '.'); + } + + @Nullable + private static IAndroidTarget parseAndroidTarget(@NotNull AndroidSdk sdk, @NotNull CompileContext context) { + final String targetHashString = sdk.getBuildTargetHashString(); + if (targetHashString == null) { + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, + "Cannot parse SDK " + sdk.getName() + ": build target is not specified")); + return null; + } + + final MessageBuildingSdkLog log = new MessageBuildingSdkLog(); + final SdkManager manager = AndroidCommonUtils.createSdkManager(sdk.getSdkPath(), log); + + if (manager == null) { + final String message = log.getErrorMessage(); + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, + "Android SDK is parsed incorrectly." + + (message.length() > 0 ? " Parsing log:\n" + message : ""))); + return null; + } + + final IAndroidTarget target = manager.getTargetFromHashString(targetHashString); + if (target == null) { + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, + "Cannot parse SDK '" + sdk.getName() + "': unknown target " + targetHashString)); + return null; + } + return target; + } + + private static void fillSourceRoots(@NotNull Module module, @NotNull Set visited, @NotNull Set result) + throws IOException { + visited.add(module); + final AndroidFacet facet = getFacet(module); + File resDir = null; + + if (facet != null) { + resDir = facet.getResourceDir(); + if (resDir != null) { + resDir = resDir.getCanonicalFile(); + } + } + + for (String sourceRootPath : module.getSourceRoots()) { + final File sourceRoot = new File(sourceRootPath).getCanonicalFile(); + + if (!sourceRoot.equals(resDir)) { + result.add(sourceRoot); + } + } + + for (ClasspathItem classpathItem : module.getClasspath(ClasspathKind.PRODUCTION_COMPILE)) { + if (classpathItem instanceof Module) { + final Module depModule = (Module)classpathItem; + + if (!visited.contains(depModule)) { + fillSourceRoots(depModule, visited, result); + } + } + } + } + + @NotNull + public static File[] getSourceRootsForModuleAndDependencies(@NotNull Module module) throws IOException { + Set result = new HashSet(); + fillSourceRoots(module, new HashSet(), result); + return result.toArray(new File[result.size()]); + } + + @Override + public String getDescription() { + return "Android Builder"; + } + + @Nullable + private static AndroidFacet getFacet(@NotNull Module module) { + AndroidFacet androidFacet = null; + + for (Facet facet : module.getFacets().values()) { + if (facet instanceof AndroidFacet) { + androidFacet = (AndroidFacet)facet; + } + } + return androidFacet; + } + + @NotNull + private static String[] toPaths(@NotNull File[] files) { + final String[] result = new String[files.length]; + + for (int i = 0; i < result.length; i++) { + result[i] = files[i].getPath(); + } + return result; + } + + private static class MyModuleData { + private final File myOutputDirectory; + private final String mySdkLocation; + private final IAndroidTarget myAndroidTarget; + + private MyModuleData(@NotNull File outputDirectory, + @NotNull String sdkLocation, + @NotNull IAndroidTarget androidTarget) { + myOutputDirectory = outputDirectory; + mySdkLocation = sdkLocation; + myAndroidTarget = androidTarget; + } + + @NotNull + public File getOutputDirectory() { + return myOutputDirectory; + } + + @NotNull + public IAndroidTarget getAndroidTarget() { + return myAndroidTarget; + } + + @NotNull + public String getSdkLocation() { + return mySdkLocation; + } + } +} diff --git a/plugins/android/src/META-INF/plugin.xml b/plugins/android/src/META-INF/plugin.xml index e6e625de60e8..67a616094d46 100644 --- a/plugins/android/src/META-INF/plugin.xml +++ b/plugins/android/src/META-INF/plugin.xml @@ -189,6 +189,12 @@ + + + + + +