Module script generation moved to a separate module

To be re-used by the external build later
This commit is contained in:
Andrey Breslav
2012-11-08 20:41:41 +04:00
parent 32745f1202
commit 2584ba5246
6 changed files with 165 additions and 69 deletions
+1
View File
@@ -16,6 +16,7 @@
<element id="module-output" name="j2k" />
<element id="module-output" name="js.translator" />
<element id="module-output" name="cli-common" />
<element id="module-output" name="ide-compiler-runner" />
</element>
<element id="library" level="project" name="js-libs" />
<element id="archive" name="kotlin-js-libraries.zip">
+1
View File
@@ -13,6 +13,7 @@
<module fileurl="file://$PROJECT_DIR$/compiler/frontend/frontend.iml" filepath="$PROJECT_DIR$/compiler/frontend/frontend.iml" />
<module fileurl="file://$PROJECT_DIR$/compiler/frontend.java/frontend.java.iml" filepath="$PROJECT_DIR$/compiler/frontend.java/frontend.java.iml" />
<module fileurl="file://$PROJECT_DIR$/grammar/grammar.iml" filepath="$PROJECT_DIR$/grammar/grammar.iml" />
<module fileurl="file://$PROJECT_DIR$/ide-compiler-runner/ide-compiler-runner.iml" filepath="$PROJECT_DIR$/ide-compiler-runner/ide-compiler-runner.iml" />
<module fileurl="file://$PROJECT_DIR$/idea/idea.iml" filepath="$PROJECT_DIR$/idea/idea.iml" />
<module fileurl="file://$PROJECT_DIR$/idea_runner/idea_runner.iml" filepath="$PROJECT_DIR$/idea_runner/idea_runner.iml" />
<module fileurl="file://$PROJECT_DIR$/injector-generator/injector-generator.iml" filepath="$PROJECT_DIR$/injector-generator/injector-generator.iml" />
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="1.6" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="idea-full" level="project" />
</component>
</module>
@@ -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<String> paths);
void processAnnotationRoots(@NotNull List<String> paths);
}
public static CharSequence generateModuleScript(String moduleName,
DependencyProvider dependencyProvider,
List<String> sourceFilePaths,
boolean tests,
final Set<String> 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<String> 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<String> 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;
}
}
+1
View File
@@ -29,6 +29,7 @@
<orderEntry type="module" module-name="j2k" />
<orderEntry type="module" module-name="js.translator" />
<orderEntry type="module" module-name="cli" scope="TEST" />
<orderEntry type="module" module-name="ide-compiler-runner" />
</component>
</module>
@@ -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<Module> moduleChunk,
List<VirtualFile> files,
Module module,
boolean tests, VirtualFile mainOutput, VirtualFile outputDir) {
ModuleChunk
chunk = new ModuleChunk((CompileContextEx)compileContext, moduleChunk, Collections.<Module, List<VirtualFile>>emptyMap());
boolean tests, VirtualFile mainOutput, VirtualFile outputDir
) {
ArrayList<String> sourceFilePaths = ContainerUtil.newArrayList(paths(files));
ModuleChunk chunk = new ModuleChunk((CompileContextEx)compileContext, moduleChunk, Collections.<Module, List<VirtualFile>>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<VirtualFile> outputDirectoriesToFilter = Sets.newHashSet(compileContext.getModuleOutputDirectoryForTests(module));
Set<String> 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<VirtualFile> files,
boolean tests,
VirtualFile mainOutput,
Set<VirtualFile> 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<String> getAnnotationRootPaths(ModuleChunk chunk) {
List<String> 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<String> paths(Collection<VirtualFile> files) {
return ContainerUtil.map(files, new Function<VirtualFile, String>() {
@Override
public String fun(VirtualFile file) {
return path(file);
}
});
}
private static String path(VirtualFile root) {
String path = root.getPath();
if (path.endsWith("!/")) {