diff --git a/.idea/artifacts/KotlinPlugin.xml b/.idea/artifacts/KotlinPlugin.xml index 2d499134d9c..e9b1e4e22be 100644 --- a/.idea/artifacts/KotlinPlugin.xml +++ b/.idea/artifacts/KotlinPlugin.xml @@ -16,6 +16,7 @@ + diff --git a/.idea/modules.xml b/.idea/modules.xml index 3c414759cd4..b208f13d4ec 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -13,6 +13,7 @@ + diff --git a/ide-compiler-runner/ide-compiler-runner.iml b/ide-compiler-runner/ide-compiler-runner.iml new file mode 100644 index 00000000000..8aa91671dfd --- /dev/null +++ b/ide-compiler-runner/ide-compiler-runner.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/KotlinModuleScriptGenerator.java b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/KotlinModuleScriptGenerator.java new file mode 100644 index 00000000000..ba66efdfeda --- /dev/null +++ b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/KotlinModuleScriptGenerator.java @@ -0,0 +1,87 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.compiler.runner; + +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +public class KotlinModuleScriptGenerator { + + public interface DependencyProvider { + void processClassPath(@NotNull DependencyProcessor processor); + } + + public interface DependencyProcessor { + void processClassPathSection(@NotNull String sectionDescription, @NotNull Collection paths); + void processAnnotationRoots(@NotNull List paths); + } + + public static CharSequence generateModuleScript(String moduleName, + DependencyProvider dependencyProvider, + List sourceFilePaths, + boolean tests, + final Set directoriesToFilterOut) { + final StringBuilder script = new StringBuilder(); + + if (tests) { + script.append("// Module script for tests\n"); + } + else { + script.append("// Module script for production\n"); + } + + script.append("import kotlin.modules.*\n"); + script.append("fun project() {\n"); + script.append(" module(\"" + moduleName + "\") {\n"); + + for (String sourceFile : sourceFilePaths) { + script.append(" sources += \"" + sourceFile + "\"\n"); + } + + dependencyProvider.processClassPath(new DependencyProcessor() { + @Override + public void processClassPathSection(@NotNull String sectionDescription, @NotNull Collection paths) { + script.append(" // " + sectionDescription + "\n"); + for (String path : paths) { + if (directoriesToFilterOut.contains(path)) { + // For IDEA's make (incremental compilation) purposes, output directories of the current module and its dependencies + // appear on the class path, so we are at risk of seeing the results of the previous build, i.e. if some class was + // removed in the sources, it may still be there in binaries. Thus, we delete these entries from the classpath. + script.append(" // Output directory, commented out\n"); + script.append(" // "); + } + script.append(" classpath += \"" + path + "\"\n"); + } + } + + @Override + public void processAnnotationRoots(@NotNull List paths) { + script.append(" // External annotations\n"); + for (String path : paths) { + script.append(" annotationsPath += \"").append(path).append("\"\n"); + } + } + }); + + script.append(" }\n"); + script.append("}\n"); + return script; + } +} diff --git a/idea/idea.iml b/idea/idea.iml index f2f75412f36..423f3f24465 100644 --- a/idea/idea.iml +++ b/idea/idea.iml @@ -29,6 +29,7 @@ + diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java b/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java index a2e35482e99..7af40db1c5d 100644 --- a/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java +++ b/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java @@ -16,13 +16,13 @@ package org.jetbrains.jet.plugin.compiler; -import com.google.common.collect.Sets; import com.intellij.compiler.impl.javaCompiler.ModuleChunk; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.configurations.SimpleJavaParameters; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.CompileContext; import com.intellij.openapi.compiler.CompileScope; +import com.intellij.openapi.compiler.CompilerMessageCategory; import com.intellij.openapi.compiler.TranslatingCompiler; import com.intellij.openapi.compiler.ex.CompileContextEx; import com.intellij.openapi.module.Module; @@ -35,9 +35,12 @@ import com.intellij.openapi.roots.OrderEnumerator; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Chunk; +import com.intellij.util.Function; import com.intellij.util.SystemProperties; +import com.intellij.util.containers.ContainerUtil; import jet.Function1; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.compiler.runner.KotlinModuleScriptGenerator; import org.jetbrains.jet.plugin.JetFileType; import org.jetbrains.jet.plugin.project.JsModuleDetector; @@ -119,9 +122,9 @@ public class JetCompiler implements TranslatingCompiler { return; } - File scriptFile = - tryToWriteScriptFile(compileContext, moduleChunk, files, module, tests, compileContext.getModuleOutputDirectory(module), - environment.getOutput()); + File scriptFile = tryToWriteScriptFile(compileContext, moduleChunk, files, module, tests, + compileContext.getModuleOutputDirectory(module), + environment.getOutput()); if (scriptFile == null) return; @@ -142,96 +145,67 @@ public class JetCompiler implements TranslatingCompiler { } } - private static File tryToWriteScriptFile(CompileContext compileContext, + public static File tryToWriteScriptFile( + CompileContext compileContext, Chunk moduleChunk, List files, Module module, - boolean tests, VirtualFile mainOutput, VirtualFile outputDir) { - ModuleChunk - chunk = new ModuleChunk((CompileContextEx)compileContext, moduleChunk, Collections.>emptyMap()); + boolean tests, VirtualFile mainOutput, VirtualFile outputDir + ) { + ArrayList sourceFilePaths = ContainerUtil.newArrayList(paths(files)); + ModuleChunk chunk = new ModuleChunk((CompileContextEx)compileContext, moduleChunk, Collections.>emptyMap()); String moduleName = moduleChunk.getNodes().iterator().next().getName(); + String outputDirectoryForTests = path(compileContext.getModuleOutputDirectoryForTests(module)); + String moduleOutputDirectory = path(compileContext.getModuleOutputDirectory(module)); // Filter the output we are writing to - Set outputDirectoriesToFilter = Sets.newHashSet(compileContext.getModuleOutputDirectoryForTests(module)); + Set outputDirectoriesToFilter = ContainerUtil.newHashSet(outputDirectoryForTests); if (!tests) { - outputDirectoriesToFilter.add(compileContext.getModuleOutputDirectory(module)); + outputDirectoriesToFilter.add(moduleOutputDirectory); } - CharSequence script = generateModuleScript(moduleName, chunk, files, tests, mainOutput, outputDirectoriesToFilter); + CharSequence script = KotlinModuleScriptGenerator.generateModuleScript( + moduleName, + getDependencyProvider(chunk, tests, mainOutput), + sourceFilePaths, + tests, + outputDirectoriesToFilter + ); File scriptFile = new File(path(outputDir), "script.kts"); try { FileUtil.writeToFile(scriptFile, script.toString()); } catch (IOException e) { - compileContext.addMessage(ERROR, "[Internal Error] Cannot write script to " + scriptFile.getAbsolutePath(), "", -1, -1); + compileContext.addMessage(CompilerMessageCategory.ERROR, "[Internal Error] Cannot write script to " + scriptFile.getAbsolutePath(), "", -1, -1); return null; } return scriptFile; } - private static CharSequence generateModuleScript(String moduleName, - ModuleChunk chunk, - List files, - boolean tests, - VirtualFile mainOutput, - Set directoriesToFilterOut) { - StringBuilder script = new StringBuilder(); + private static KotlinModuleScriptGenerator.DependencyProvider getDependencyProvider( + final ModuleChunk chunk, + final boolean tests, + final VirtualFile mainOutputPath + ) { + return new KotlinModuleScriptGenerator.DependencyProvider() { + @Override + public void processClassPath(@NotNull KotlinModuleScriptGenerator.DependencyProcessor processor) { + // TODO: have a bootclasspath in script API + processor.processClassPathSection("Boot classpath", paths(chunk.getCompilationBootClasspathFiles())); - if (tests) { - script.append("// Module script for tests\n"); - } - else { - script.append("// Module script for production\n"); - } + processor.processClassPathSection("Compilation classpath", paths(chunk.getCompilationClasspathFiles())); - script.append("import kotlin.modules.*\n"); - script.append("fun project() {\n"); - script.append(" module(\"" + moduleName + "\") {\n"); + // This is for java files in same roots + processor.processClassPathSection("Java classpath (for Java sources)", paths(Arrays.asList(chunk.getSourceRoots()))); - for (VirtualFile sourceFile : files) { - script.append(" sources += \"" + path(sourceFile) + "\"\n"); - } - // TODO: have a bootclasspath in script API - script.append(" // Boot classpath\n"); - for (VirtualFile root : chunk.getCompilationBootClasspathFiles()) { - script.append(" classpath += \"" + path(root) + "\"\n"); - } + if (tests && mainOutputPath != null) { + processor.processClassPathSection("Main output", Arrays.asList(path(mainOutputPath))); + } - script.append(" // Compilation classpath\n"); - for (VirtualFile root : chunk.getCompilationClasspathFiles()) { - String path = path(root); - if (directoriesToFilterOut.contains(root)) { - // For IDEA's make (incremental compilation) purposes, output directories of the current module and its dependencies - // appear on the class path, so we are at risk of seeing the results of the previous build, i.e. if some class was - // removed in the sources, it may still be there in binaries. Thus, we delete these entries from the classpath. - script.append(" // Output directory, commented out\n"); - script.append(" // "); + processor.processAnnotationRoots(getAnnotationRootPaths(chunk)); } - script.append(" classpath += \"" + path + "\"\n"); - } - - // This is for java files in same roots - script.append(" // Java classpath (for Java sources)\n"); - for (VirtualFile root : chunk.getSourceRoots()) { - script.append(" classpath += \"" + path(root) + "\"\n"); - } - - script.append(" // Main output\n"); - if (tests && mainOutput != null) { - script.append(" classpath += \"" + path(mainOutput) + "\"\n"); - } - - script.append(" // External annotations\n"); - for (Module module : chunk.getModules()) { - for (VirtualFile file : OrderEnumerator.orderEntries(module).roots(AnnotationOrderRootType.getInstance()).getRoots()) { - script.append(" annotationsPath += \"").append(path(file)).append("\"\n"); - } - } - - script.append(" }\n"); - script.append("}\n"); - return script; + }; } private static void runInProcess(final CompileContext compileContext, @@ -331,6 +305,25 @@ public class JetCompiler implements TranslatingCompiler { } } + private static List getAnnotationRootPaths(ModuleChunk chunk) { + List annotationPaths = ContainerUtil.newArrayList(); + for (Module module : chunk.getModules()) { + for (VirtualFile file : OrderEnumerator.orderEntries(module).roots(AnnotationOrderRootType.getInstance()).getRoots()) { + annotationPaths.add(path(file)); + } + } + return annotationPaths; + } + + private static Collection paths(Collection files) { + return ContainerUtil.map(files, new Function() { + @Override + public String fun(VirtualFile file) { + return path(file); + } + }); + } + private static String path(VirtualFile root) { String path = root.getPath(); if (path.endsWith("!/")) {