diff --git a/jps/jps-plugin/jps-plugin.iml b/jps/jps-plugin/jps-plugin.iml
index 8aa91671dfd..e58e9906a3c 100644
--- a/jps/jps-plugin/jps-plugin.iml
+++ b/jps/jps-plugin/jps-plugin.iml
@@ -8,6 +8,8 @@
+
+
diff --git a/jps/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java b/jps/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java
index 86113e5e85f..fde3fcdbcdc 100644
--- a/jps/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java
+++ b/jps/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java
@@ -16,50 +16,149 @@
package org.jetbrains.jet.jps.build;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.cli.common.messages.CompilerMessageLocation;
+import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity;
+import org.jetbrains.jet.cli.common.messages.MessageCollector;
+import org.jetbrains.jet.compiler.runner.*;
import org.jetbrains.jps.ModuleChunk;
+import org.jetbrains.jps.builders.ChunkBuildOutputConsumer;
import org.jetbrains.jps.builders.DirtyFilesHolder;
-import org.jetbrains.jps.builders.FileProcessor;
import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor;
import org.jetbrains.jps.incremental.*;
+import org.jetbrains.jps.incremental.messages.BuildMessage;
+import org.jetbrains.jps.incremental.messages.CompilerMessage;
import java.io.File;
import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
+
+import static org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity.ERROR;
public class KotlinBuilder extends ModuleLevelBuilder {
+
+ private static final String KOTLIN_COMPILER_NAME = "Kotlin";
+ private static final String KOTLIN_BUILDER_NAME = "Kotlin Builder";
+
protected KotlinBuilder() {
super(BuilderCategory.SOURCE_PROCESSOR);
}
+ @NotNull
+ @Override
+ public String getPresentableName() {
+ return KOTLIN_BUILDER_NAME;
+ }
+
@Override
public ExitCode build(
- CompileContext context, ModuleChunk chunk, DirtyFilesHolder dirtyFilesHolder
- ) throws ProjectBuildException {
- try {
- dirtyFilesHolder.processDirtyFiles(new FileProcessor() {
- @Override
- public boolean apply(ModuleBuildTarget target, File file, JavaSourceRootDescriptor root) throws IOException {
- if (file.getName().endsWith(".kt") || file.getName().endsWith(".java")) {
+ CompileContext context,
+ ModuleChunk chunk,
+ DirtyFilesHolder dirtyFilesHolder,
+ ChunkBuildOutputConsumer outputConsumer
+ ) throws ProjectBuildException, IOException {
- }
- return true;
- }
- });
+ MessageCollector messageCollector = new MessageCollectorAdapter(context);
+
+ if (chunk.getModules().size() > 1) {
+ messageCollector.report(
+ ERROR, "Circular dependencies are not supported: " + chunk.getModules(),
+ CompilerMessageLocation.NO_LOCATION);
+ return ExitCode.ABORT;
}
- catch (IOException e) {
- throw new ProjectBuildException(e);
+
+ ModuleBuildTarget representativeTarget = chunk.representativeTarget();
+
+ // For non-incremental build: take all sources
+ List sourceFiles = KotlinSourceFileCollector.getAllKotlinSourceFiles(representativeTarget);
+ //List sourceFiles = getDirtySourceFiles(dirtyFilesHolder);
+
+ if (sourceFiles.isEmpty()) {
+ return ExitCode.NOTHING_DONE;
}
- //context.processMessage(new CompilerMessage());
- //JpsJavaExtensionService.dependencies().recursively().productionOnly().classes().getRoots()
+
+ File scriptFile = KotlinBuilderModuleScriptGenerator.generateModuleScript(context, representativeTarget, sourceFiles);
+
+ File outputDir = representativeTarget.getOutputDir();
+
+ CompilerEnvironment environment = CompilerEnvironment.getEnvironmentFor(outputDir);
+ if (!environment.success()) {
+ environment.reportErrorsTo(messageCollector);
+ return ExitCode.ABORT;
+ }
+
+ assert outputDir != null : "CompilerEnvironment must have checked for outputDir to be not null, but it didn't";
+
+ OutputItemsCollectorImpl outputItemCollector = new OutputItemsCollectorImpl(outputDir);
+
+ KotlinCompilerRunner.runCompiler(
+ messageCollector,
+ environment,
+ scriptFile,
+ outputItemCollector,
+ /*runOutOfProcess = */false);
+
+ for (SimpleOutputItem outputItem : outputItemCollector.getOutputs()) {
+ outputConsumer.registerOutputFile(
+ representativeTarget,
+ outputItem.getOutputFile().getPath(),
+ paths(outputItem.getSourceFiles()));
+ }
+
return ExitCode.OK;
}
- @Override
- public String getName() {
- return "KotlinBuilder";
+ private static Collection paths(Collection files) {
+ Collection result = ContainerUtil.newArrayList();
+ for (File file : files) {
+ result.add(file.getPath());
+ }
+ return result;
}
- @Override
- public String getDescription() {
- return "KotlinBuilder";
+ public static class MessageCollectorAdapter implements MessageCollector {
+
+ private final CompileContext context;
+
+ public MessageCollectorAdapter(@NotNull CompileContext context) {
+ this.context = context;
+ }
+
+ @Override
+ public void report(
+ @NotNull CompilerMessageSeverity severity,
+ @NotNull String message,
+ @NotNull CompilerMessageLocation location
+ ) {
+ context.processMessage(new CompilerMessage(
+ KOTLIN_COMPILER_NAME,
+ kind(severity),
+ message,
+ location.getPath(),
+ -1, -1, -1,
+ location.getLine(),
+ location.getColumn()
+ ));
+ }
+
+ @NotNull
+ private static BuildMessage.Kind kind(@NotNull CompilerMessageSeverity severity) {
+ switch (severity) {
+ case INFO:
+ return BuildMessage.Kind.INFO;
+ case ERROR:
+ case EXCEPTION:
+ return BuildMessage.Kind.ERROR;
+ case WARNING:
+ return BuildMessage.Kind.WARNING;
+ case LOGGING:
+ return BuildMessage.Kind.PROGRESS;
+ default:
+ throw new IllegalArgumentException("Unsupported severity: " + severity);
+ }
+ }
+
}
}
diff --git a/jps/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilderModuleScriptGenerator.java b/jps/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilderModuleScriptGenerator.java
new file mode 100644
index 00000000000..860ea5ddf8a
--- /dev/null
+++ b/jps/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilderModuleScriptGenerator.java
@@ -0,0 +1,133 @@
+/*
+ * 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.jps.build;
+
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jet.compiler.runner.KotlinModuleScriptGenerator;
+import org.jetbrains.jps.incremental.CompileContext;
+import org.jetbrains.jps.incremental.ModuleBuildTarget;
+import org.jetbrains.jps.incremental.messages.BuildMessage;
+import org.jetbrains.jps.incremental.messages.CompilerMessage;
+import org.jetbrains.jps.model.java.JpsAnnotationRootType;
+import org.jetbrains.jps.model.java.JpsJavaClasspathKind;
+import org.jetbrains.jps.model.java.JpsJavaDependenciesEnumerator;
+import org.jetbrains.jps.model.java.JpsJavaExtensionService;
+import org.jetbrains.jps.model.library.JpsLibrary;
+import org.jetbrains.jps.model.library.JpsLibraryRoot;
+import org.jetbrains.jps.model.module.JpsDependencyElement;
+import org.jetbrains.jps.model.module.JpsLibraryDependency;
+import org.jetbrains.jps.model.module.JpsModule;
+import org.jetbrains.jps.model.module.JpsSdkDependency;
+import org.jetbrains.jps.util.JpsPathUtil;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import static org.jetbrains.jet.compiler.runner.KotlinModuleScriptGenerator.DependencyProvider;
+
+public class KotlinBuilderModuleScriptGenerator {
+ public static File generateModuleScript(CompileContext context, ModuleBuildTarget target, List sourceFiles)
+ throws IOException
+ {
+ CharSequence moduleScriptText = KotlinModuleScriptGenerator.generateModuleScript(
+ target.getModuleName(),
+ getKotlinModuleDependencies(target),
+ sourceFiles,
+ target.isTests(),
+ // this excludes the output directory from the class path, to be removed for true incremental compilation
+ Collections.singleton(target.getOutputDir())
+ );
+
+ File scriptFile = new File(target.getOutputDir(), "script.kts");
+
+ writeScriptToFile(context, moduleScriptText, scriptFile);
+
+ return scriptFile;
+ }
+
+ private static DependencyProvider getKotlinModuleDependencies(final ModuleBuildTarget target) {
+ return new DependencyProvider() {
+ @Override
+ public void processClassPath(@NotNull KotlinModuleScriptGenerator.DependencyProcessor processor) {
+ processor.processClassPathSection("All", findClassPathRoots(target));
+ processor.processAnnotationRoots(findAnnotationRoots(target));
+ }
+ };
+ }
+
+ private static void writeScriptToFile(CompileContext context, CharSequence moduleScriptText, File scriptFile) throws IOException {
+ FileUtil.writeToFile(scriptFile, moduleScriptText.toString());
+ context.processMessage(new CompilerMessage(
+ "Kotlin",
+ BuildMessage.Kind.INFO,
+ "Created script file: " + scriptFile
+ ));
+ }
+
+ @NotNull
+ private static Collection findClassPathRoots(@NotNull ModuleBuildTarget target) {
+ JpsModule module = target.getModule();
+ JpsJavaDependenciesEnumerator dependencies = JpsJavaExtensionService.dependencies(module)
+ .includedIn(JpsJavaClasspathKind.compile(target.isTests()));
+
+ return dependencies.classes().getRoots();
+ }
+
+ @NotNull
+ private static List findAnnotationRoots(@NotNull ModuleBuildTarget target) {
+ JpsModule module = target.getModule();
+ List dependencies = module.getDependenciesList().getDependencies();
+
+ List annotationRootFiles = ContainerUtil.newArrayList();
+ for (JpsDependencyElement dependencyElement : dependencies) {
+ JpsLibrary library = getLibrary(dependencyElement);
+ if (library == null) continue;
+
+ List annotationRoots = library.getRoots(JpsAnnotationRootType.INSTANCE);
+ for (JpsLibraryRoot root : annotationRoots) {
+ File file = new File(JpsPathUtil.urlToPath(root.getUrl()));
+
+ annotationRootFiles.add(file);
+ }
+ }
+
+ return annotationRootFiles;
+ }
+
+ @Nullable
+ private static JpsLibrary getLibrary(@NotNull JpsDependencyElement dependencyElement) {
+ if (dependencyElement instanceof JpsSdkDependency) {
+ JpsSdkDependency sdkDependency = (JpsSdkDependency) dependencyElement;
+ return sdkDependency.resolveSdk();
+ }
+
+ if (dependencyElement instanceof JpsLibraryDependency) {
+ JpsLibraryDependency libraryDependency = (JpsLibraryDependency) dependencyElement;
+ return libraryDependency.getLibrary();
+ }
+
+ return null;
+ }
+
+ private KotlinBuilderModuleScriptGenerator() {}
+}
diff --git a/jps/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinSourceFileCollector.java b/jps/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinSourceFileCollector.java
new file mode 100644
index 00000000000..d92306714e1
--- /dev/null
+++ b/jps/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinSourceFileCollector.java
@@ -0,0 +1,82 @@
+/*
+ * 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.jps.build;
+
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.util.Processor;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.builders.DirtyFilesHolder;
+import org.jetbrains.jps.builders.FileProcessor;
+import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor;
+import org.jetbrains.jps.incremental.ModuleBuildTarget;
+import org.jetbrains.jps.model.java.JavaSourceRootType;
+import org.jetbrains.jps.model.module.JpsModuleSourceRoot;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+public class KotlinSourceFileCollector {
+ // For incremental compilation
+ public static List getDirtySourceFiles(DirtyFilesHolder dirtyFilesHolder)
+ throws IOException
+ {
+ final List sourceFiles = ContainerUtil.newArrayList();
+
+ dirtyFilesHolder.processDirtyFiles(new FileProcessor() {
+ @Override
+ public boolean apply(ModuleBuildTarget target, File file, JavaSourceRootDescriptor root) throws IOException {
+ if (isKotlinSourceFile(file)) {
+ sourceFiles.add(file);
+ }
+ return true;
+ }
+ });
+ return sourceFiles;
+ }
+
+ @NotNull
+ public static List getAllKotlinSourceFiles(@NotNull ModuleBuildTarget target) {
+ final List result = ContainerUtil.newArrayList();
+ for (JpsModuleSourceRoot sourceRoot : getRelevantSourceRoots(target)) {
+ FileUtil.processFilesRecursively(sourceRoot.getFile(), new Processor() {
+ @Override
+ public boolean process(File file) {
+ if (file.isFile() && isKotlinSourceFile(file)) {
+ result.add(file);
+ }
+ return true;
+ }
+ });
+ }
+ return result;
+ }
+
+ private static Iterable getRelevantSourceRoots(ModuleBuildTarget target) {
+ JavaSourceRootType sourceRootType = target.isTests() ? JavaSourceRootType.TEST_SOURCE : JavaSourceRootType.SOURCE;
+
+ //noinspection unchecked
+ return (Iterable) target.getModule().getSourceRoots(sourceRootType);
+ }
+
+ private static boolean isKotlinSourceFile(File file) {
+ return file.getPath().endsWith(".kt");
+ }
+
+ private KotlinSourceFileCollector() {}
+}