diff --git a/jps/jps-plugin/jps-plugin.iml b/jps/jps-plugin/jps-plugin.iml
index 6878e4f6683..23016075fe8 100644
--- a/jps/jps-plugin/jps-plugin.iml
+++ b/jps/jps-plugin/jps-plugin.iml
@@ -12,7 +12,7 @@
-
+
diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java
new file mode 100644
index 00000000000..f2329867d68
--- /dev/null
+++ b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2010-2015 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.kotlin.compilerRunner;
+
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.Function;
+import com.intellij.util.containers.ComparatorUtil;
+import com.sampullara.cli.Argument;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ArgumentUtils {
+ private ArgumentUtils() {}
+
+ @NotNull
+ public static List convertArgumentsToStringList(@NotNull CommonCompilerArguments arguments)
+ throws InstantiationException, IllegalAccessException {
+ List result = new ArrayList();
+ convertArgumentsToStringList(arguments, arguments.getClass().newInstance(), arguments.getClass(), result);
+ result.addAll(arguments.freeArgs);
+ return result;
+ }
+
+ private static void convertArgumentsToStringList(
+ @NotNull CommonCompilerArguments arguments,
+ @NotNull CommonCompilerArguments defaultArguments,
+ @NotNull Class> clazz,
+ @NotNull List result
+ ) throws IllegalAccessException, InstantiationException {
+ for (Field field : clazz.getDeclaredFields()) {
+ Argument argument = field.getAnnotation(Argument.class);
+ if (argument == null) continue;
+
+ Object value;
+ Object defaultValue;
+ try {
+ value = field.get(arguments);
+ defaultValue = field.get(defaultArguments);
+ }
+ catch (IllegalAccessException ignored) {
+ // skip this field
+ continue;
+ }
+
+ if (ComparatorUtil.equalsNullable(value, defaultValue)) continue;
+
+ String name = getAlias(argument);
+ if (name == null) {
+ name = getName(argument, field);
+ }
+
+ Class> fieldType = field.getType();
+
+ if (fieldType.isArray()) {
+ Object[] values = (Object[]) value;
+ if (values.length == 0) continue;
+ //noinspection unchecked
+ value = StringUtil.join(values, Function.TO_STRING, argument.delimiter());
+ }
+
+ result.add(argument.prefix() + name);
+
+ if (fieldType == boolean.class || fieldType == Boolean.class) continue;
+
+ result.add(value.toString());
+ }
+
+ Class> superClazz = clazz.getSuperclass();
+ if (superClazz != null) {
+ convertArgumentsToStringList(arguments, defaultArguments, superClazz, result);
+ }
+ }
+
+ private static String getAlias(Argument argument) {
+ String alias = argument.alias();
+ return alias.isEmpty() ? null : alias;
+ }
+
+ private static String getName(Argument argument, Field field) {
+ String name = argument.value();
+ return name.isEmpty() ? field.getName() : name;
+ }
+}
diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/CompilerEnvironment.java b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/CompilerEnvironment.java
new file mode 100644
index 00000000000..c4df720924d
--- /dev/null
+++ b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/CompilerEnvironment.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2010-2015 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.kotlin.compilerRunner;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
+import org.jetbrains.kotlin.config.Services;
+import org.jetbrains.kotlin.preloading.ClassCondition;
+import org.jetbrains.kotlin.utils.KotlinPaths;
+import org.jetbrains.kotlin.utils.PathUtil;
+
+import static org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation.NO_LOCATION;
+import static org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR;
+
+public class CompilerEnvironment {
+ @NotNull
+ public static CompilerEnvironment getEnvironmentFor(
+ @NotNull KotlinPaths kotlinPaths,
+ @NotNull ClassCondition classesToLoadByParent,
+ @NotNull Services compilerServices
+ ) {
+ return new CompilerEnvironment(kotlinPaths, classesToLoadByParent, compilerServices);
+ }
+
+ private final KotlinPaths kotlinPaths;
+ private final ClassCondition classesToLoadByParent;
+ private final Services services;
+
+ private CompilerEnvironment(
+ @NotNull KotlinPaths kotlinPaths,
+ @NotNull ClassCondition classesToLoadByParent,
+ @NotNull Services services
+ ) {
+ this.kotlinPaths = kotlinPaths;
+ this.classesToLoadByParent = classesToLoadByParent;
+ this.services = services;
+ }
+
+ public boolean success() {
+ return kotlinPaths.getHomePath().exists();
+ }
+
+ @NotNull
+ public KotlinPaths getKotlinPaths() {
+ return kotlinPaths;
+ }
+
+ @NotNull
+ public ClassCondition getClassesToLoadByParent() {
+ return classesToLoadByParent;
+ }
+
+ public void reportErrorsTo(@NotNull MessageCollector messageCollector) {
+ if (!kotlinPaths.getHomePath().exists()) {
+ messageCollector.report(ERROR, "Cannot find kotlinc home: " + kotlinPaths.getHomePath() + ". Make sure plugin is properly installed, " +
+ "or specify " + PathUtil.JPS_KOTLIN_HOME_PROPERTY + " system property", NO_LOCATION);
+ }
+ }
+
+ @NotNull
+ public Services getServices() {
+ return services;
+ }
+}
diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/CompilerOutputParser.java b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/CompilerOutputParser.java
new file mode 100644
index 00000000000..e5bb3d4ea3d
--- /dev/null
+++ b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/CompilerOutputParser.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2010-2015 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.kotlin.compilerRunner;
+
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.Stack;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation;
+import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity;
+import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
+import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Map;
+
+import static org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation.NO_LOCATION;
+import static org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*;
+import static org.jetbrains.kotlin.cli.common.messages.MessageCollectorUtil.reportException;
+
+public class CompilerOutputParser {
+ public static void parseCompilerMessagesFromReader(MessageCollector messageCollector, final Reader reader, OutputItemsCollector collector) {
+ // Sometimes the compiler doesn't output valid XML.
+ // Example: error in command line arguments passed to the compiler.
+ // The compiler will print the usage and the SAX parser will break.
+ // In this case, we want to read everything from this stream and report it as an IDE error.
+ final StringBuilder stringBuilder = new StringBuilder();
+ Reader wrappingReader = new Reader() {
+ @Override
+ public int read(@NotNull char[] cbuf, int off, int len) throws IOException {
+ int read = reader.read(cbuf, off, len);
+ stringBuilder.append(cbuf, off, len);
+ return read;
+ }
+
+ @Override
+ public void close() throws IOException {
+ // Do nothing:
+ // If the SAX parser sees a syntax error, it throws an exception
+ // and calls close() on the reader.
+ // We prevent hte reader from being closed here, and close it later,
+ // when all the text is read from it
+ }
+ };
+ try {
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ SAXParser parser = factory.newSAXParser();
+ parser.parse(new InputSource(wrappingReader), new CompilerOutputSAXHandler(messageCollector, collector));
+ }
+ catch (Throwable e) {
+ // Load all the text into the stringBuilder
+ try {
+ // This will not close the reader (see the wrapper above)
+ FileUtil.loadTextAndClose(wrappingReader);
+ }
+ catch (IOException ioException) {
+ reportException(messageCollector, ioException);
+ }
+ String message = stringBuilder.toString();
+ reportException(messageCollector, new IllegalStateException(message, e));
+ messageCollector.report(ERROR, message, NO_LOCATION);
+ }
+ finally {
+ try {
+ reader.close();
+ }
+ catch (IOException e) {
+ reportException(messageCollector, e);
+ }
+ }
+ }
+
+ private static class CompilerOutputSAXHandler extends DefaultHandler {
+ private static final Map CATEGORIES = new ContainerUtil.ImmutableMapBuilder()
+ .put("error", ERROR)
+ .put("warning", WARNING)
+ .put("logging", LOGGING)
+ .put("output", OUTPUT)
+ .put("exception", EXCEPTION)
+ .put("info", INFO)
+ .put("messages", INFO) // Root XML element
+ .build();
+
+ private final MessageCollector messageCollector;
+ private final OutputItemsCollector collector;
+
+ private final StringBuilder message = new StringBuilder();
+ private final Stack tags = new Stack();
+ private String path;
+ private int line;
+ private int column;
+
+ public CompilerOutputSAXHandler(MessageCollector messageCollector, OutputItemsCollector collector) {
+ this.messageCollector = messageCollector;
+ this.collector = collector;
+ }
+
+ @Override
+ public void startElement(@NotNull String uri, @NotNull String localName, @NotNull String qName, @NotNull Attributes attributes)
+ throws SAXException {
+ tags.push(qName);
+
+ message.setLength(0);
+
+ path = attributes.getValue("path");
+ line = safeParseInt(attributes.getValue("line"), -1);
+ column = safeParseInt(attributes.getValue("column"), -1);
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ if (tags.size() == 1) {
+ // We're directly inside the root tag:
+ String message = new String(ch, start, length);
+ if (!message.trim().isEmpty()) {
+ messageCollector.report(ERROR, "Unhandled compiler output: " + message, NO_LOCATION);
+ }
+ }
+ else {
+ message.append(ch, start, length);
+ }
+ }
+
+ @Override
+ public void endElement(String uri, @NotNull String localName, @NotNull String qName) throws SAXException {
+ if (tags.size() == 1) {
+ // We're directly inside the root tag:
+ return;
+ }
+ String qNameLowerCase = qName.toLowerCase();
+ CompilerMessageSeverity category = CATEGORIES.get(qNameLowerCase);
+ if (category == null) {
+ messageCollector.report(ERROR, "Unknown compiler message tag: " + qName, NO_LOCATION);
+ category = INFO;
+ }
+ String text = message.toString();
+
+ if (category == OUTPUT) {
+ reportToCollector(text);
+ }
+ else {
+ messageCollector.report(category, text, CompilerMessageLocation.create(path, line, column));
+ }
+ tags.pop();
+ }
+
+ private void reportToCollector(String text) {
+ OutputMessageUtil.Output output = OutputMessageUtil.parseOutputMessage(text);
+ if (output != null) {
+ collector.add(output.sourceFiles, output.outputFile);
+ }
+ }
+
+ private static int safeParseInt(@Nullable String value, int defaultValue) {
+ if (value == null) {
+ return defaultValue;
+ }
+ try {
+ return Integer.parseInt(value.trim());
+ }
+ catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+ }
+}
diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/CompilerRunnerUtil.java b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/CompilerRunnerUtil.java
new file mode 100644
index 00000000000..75036a84842
--- /dev/null
+++ b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/CompilerRunnerUtil.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2010-2015 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.kotlin.compilerRunner;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
+import org.jetbrains.kotlin.preloading.ClassPreloadingUtils;
+import org.jetbrains.kotlin.utils.KotlinPaths;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.ref.SoftReference;
+import java.lang.reflect.Method;
+import java.util.Collections;
+
+import static org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation.NO_LOCATION;
+import static org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR;
+
+public class CompilerRunnerUtil {
+
+ private static SoftReference ourClassLoaderRef = new SoftReference(null);
+
+ @NotNull
+ private static synchronized ClassLoader getOrCreateClassLoader(
+ @NotNull CompilerEnvironment environment,
+ @NotNull File libPath
+ ) throws IOException {
+ ClassLoader classLoader = ourClassLoaderRef.get();
+ if (classLoader == null) {
+ classLoader = ClassPreloadingUtils.preloadClasses(
+ Collections.singletonList(new File(libPath, "kotlin-compiler.jar")),
+ /* estimatedClassNumber = */ 4096,
+ CompilerRunnerUtil.class.getClassLoader(),
+ environment.getClassesToLoadByParent()
+ );
+ ourClassLoaderRef = new SoftReference(classLoader);
+ }
+ return classLoader;
+ }
+
+ @Nullable
+ private static File getLibPath(@NotNull KotlinPaths paths, @NotNull MessageCollector messageCollector) {
+ File libs = paths.getLibPath();
+ if (libs.exists() && !libs.isFile()) return libs;
+
+ messageCollector.report(
+ ERROR,
+ "Broken compiler at '" + libs.getAbsolutePath() + "'. Make sure plugin is properly installed",
+ NO_LOCATION
+ );
+
+ return null;
+ }
+
+ @Nullable
+ public static Object invokeExecMethod(
+ @NotNull String compilerClassName,
+ @NotNull String[] arguments,
+ @NotNull CompilerEnvironment environment,
+ @NotNull MessageCollector messageCollector,
+ @NotNull PrintStream out
+ ) throws Exception {
+ File libPath = getLibPath(environment.getKotlinPaths(), messageCollector);
+ if (libPath == null) return null;
+
+ ClassLoader classLoader = getOrCreateClassLoader(environment, libPath);
+
+ Class> kompiler = Class.forName(compilerClassName, true, classLoader);
+ Method exec = kompiler.getMethod(
+ "execAndOutputXml",
+ PrintStream.class,
+ Class.forName("org.jetbrains.kotlin.config.Services", true, classLoader),
+ String[].class
+ );
+
+ return exec.invoke(kompiler.newInstance(), out, environment.getServices(), arguments);
+ }
+}
diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.java b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.java
new file mode 100644
index 00000000000..22515bce97f
--- /dev/null
+++ b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2010-2015 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.kotlin.compilerRunner;
+
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.Function;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.xmlb.Accessor;
+import com.intellij.util.xmlb.XmlSerializerUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.cli.common.ExitCode;
+import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments;
+import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments;
+import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments;
+import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
+import org.jetbrains.kotlin.cli.common.messages.MessageCollectorUtil;
+import org.jetbrains.kotlin.config.CompilerSettings;
+
+import java.io.*;
+import java.util.Collection;
+import java.util.List;
+
+import static org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation.NO_LOCATION;
+import static org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR;
+import static org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.INFO;
+
+public class KotlinCompilerRunner {
+ private static final String K2JVM_COMPILER = "org.jetbrains.kotlin.cli.jvm.K2JVMCompiler";
+ private static final String K2JS_COMPILER = "org.jetbrains.kotlin.cli.js.K2JSCompiler";
+ private static final String INTERNAL_ERROR = ExitCode.INTERNAL_ERROR.toString();
+
+ public static void runK2JvmCompiler(
+ CommonCompilerArguments commonArguments,
+ K2JVMCompilerArguments k2jvmArguments,
+ CompilerSettings compilerSettings,
+ MessageCollector messageCollector,
+ CompilerEnvironment environment,
+ File moduleFile,
+ OutputItemsCollector collector
+ ) {
+ K2JVMCompilerArguments arguments = mergeBeans(commonArguments, k2jvmArguments);
+ setupK2JvmArguments(moduleFile, arguments);
+
+ runCompiler(K2JVM_COMPILER, arguments, compilerSettings.getAdditionalArguments(), messageCollector, collector, environment);
+ }
+
+ public static void runK2JsCompiler(
+ CommonCompilerArguments commonArguments,
+ K2JSCompilerArguments k2jsArguments,
+ CompilerSettings compilerSettings,
+ MessageCollector messageCollector,
+ CompilerEnvironment environment,
+ OutputItemsCollector collector,
+ Collection sourceFiles,
+ List libraryFiles,
+ File outputFile
+ ) {
+ K2JSCompilerArguments arguments = mergeBeans(commonArguments, k2jsArguments);
+ setupK2JsArguments(outputFile, sourceFiles, libraryFiles, arguments);
+
+ runCompiler(K2JS_COMPILER, arguments, compilerSettings.getAdditionalArguments(), messageCollector, collector, environment);
+ }
+
+ private static void runCompiler(
+ String compilerClassName,
+ CommonCompilerArguments arguments,
+ String additionalArguments,
+ MessageCollector messageCollector,
+ OutputItemsCollector collector,
+ CompilerEnvironment environment
+ ) {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ PrintStream out = new PrintStream(stream);
+
+ String exitCode = execCompiler(compilerClassName, arguments, additionalArguments, environment, out, messageCollector);
+
+ BufferedReader reader = new BufferedReader(new StringReader(stream.toString()));
+ CompilerOutputParser.parseCompilerMessagesFromReader(messageCollector, reader, collector);
+
+ if (INTERNAL_ERROR.equals(exitCode)) {
+ messageCollector.report(ERROR, "Compiler terminated with internal error", NO_LOCATION);
+ }
+ }
+
+ @NotNull
+ private static String execCompiler(
+ String compilerClassName,
+ CommonCompilerArguments arguments,
+ String additionalArguments,
+ CompilerEnvironment environment,
+ PrintStream out,
+ MessageCollector messageCollector
+ ) {
+ try {
+ messageCollector.report(INFO, "Using kotlin-home = " + environment.getKotlinPaths().getHomePath(), NO_LOCATION);
+
+ List argumentsList = ArgumentUtils.convertArgumentsToStringList(arguments);
+ argumentsList.addAll(StringUtil.split(additionalArguments, " "));
+
+ Object rc = CompilerRunnerUtil.invokeExecMethod(
+ compilerClassName, ArrayUtil.toStringArray(argumentsList), environment, messageCollector, out
+ );
+
+ // exec() returns an ExitCode object, class of which is loaded with a different class loader,
+ // so we take it's contents through reflection
+ return getReturnCodeFromObject(rc);
+ }
+ catch (Throwable e) {
+ MessageCollectorUtil.reportException(messageCollector, e);
+ return INTERNAL_ERROR;
+ }
+ }
+
+ @NotNull
+ private static String getReturnCodeFromObject(@Nullable Object rc) throws Exception {
+ if (rc == null) {
+ return INTERNAL_ERROR;
+ }
+ else if (ExitCode.class.getName().equals(rc.getClass().getName())) {
+ return rc.toString();
+ }
+ else {
+ throw new IllegalStateException("Unexpected return: " + rc);
+ }
+ }
+
+ private static T mergeBeans(F from, T to) {
+ T copy = XmlSerializerUtil.createCopy(to);
+
+ for (Accessor accessor : XmlSerializerUtil.getAccessors(from.getClass())) {
+ accessor.write(copy, accessor.read(from));
+ }
+
+ return copy;
+ }
+
+ private static void setupK2JvmArguments(File moduleFile, K2JVMCompilerArguments settings) {
+ settings.module = moduleFile.getAbsolutePath();
+ settings.noStdlib = true;
+ settings.noJdkAnnotations = true;
+ settings.noJdk = true;
+ }
+
+ private static void setupK2JsArguments(
+ File outputFile,
+ Collection sourceFiles,
+ List libraryFiles,
+ K2JSCompilerArguments settings
+ ) {
+ settings.noStdlib = true;
+ settings.freeArgs = ContainerUtil.map(sourceFiles, new Function() {
+ @Override
+ public String fun(File file) {
+ return file.getPath();
+ }
+ });
+ settings.outputFile = outputFile.getPath();
+ settings.libraryFiles = ArrayUtil.toStringArray(libraryFiles);
+ }
+}
diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/OutputItemsCollector.java b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/OutputItemsCollector.java
new file mode 100644
index 00000000000..a05fe540e47
--- /dev/null
+++ b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/OutputItemsCollector.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2010-2015 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.kotlin.compilerRunner;
+
+import java.io.File;
+import java.util.Collection;
+
+public interface OutputItemsCollector {
+ void add(Collection sourceFiles, File outputFile);
+}
diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/OutputItemsCollectorImpl.java b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/OutputItemsCollectorImpl.java
new file mode 100644
index 00000000000..b2b40cd1811
--- /dev/null
+++ b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/OutputItemsCollectorImpl.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010-2015 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.kotlin.compilerRunner;
+
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+
+public class OutputItemsCollectorImpl implements OutputItemsCollector {
+ private final List outputs = ContainerUtil.newArrayList();
+
+ @Override
+ public void add(Collection sourceFiles, File outputFile) {
+ outputs.add(new SimpleOutputItem(sourceFiles, outputFile));
+ }
+
+ @NotNull
+ public List getOutputs() {
+ return outputs;
+ }
+}
diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/SimpleOutputItem.java b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/SimpleOutputItem.java
new file mode 100644
index 00000000000..ed9c716f7cb
--- /dev/null
+++ b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/SimpleOutputItem.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010-2015 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.kotlin.compilerRunner;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.util.Collection;
+
+public class SimpleOutputItem {
+ private final Collection sourceFiles;
+ private final File outputFile;
+
+ public SimpleOutputItem(@NotNull Collection sourceFiles, @NotNull File outputFile) {
+ this.sourceFiles = sourceFiles;
+ this.outputFile = outputFile;
+ }
+
+ @NotNull
+ public Collection getSourceFiles() {
+ return sourceFiles;
+ }
+
+ @NotNull
+ public File getOutputFile() {
+ return outputFile;
+ }
+
+ @Override
+ public String toString() {
+ return sourceFiles + " -> " + outputFile;
+ }
+}
diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt
index 1989aa73f36..ac2a1951f6a 100644
--- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt
+++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.compilerRunner.CompilerEnvironment
-import org.jetbrains.kotlin.compilerRunner.CompilerRunnerConstants
+import org.jetbrains.kotlin.config.CompilerRunnerConstants
import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.config.IncrementalCompilation
@@ -43,7 +43,7 @@ import java.io.File
import java.util.*
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation.NO_LOCATION
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
-import org.jetbrains.kotlin.compilerRunner.CompilerRunnerConstants.INTERNAL_ERROR_PREFIX
+import org.jetbrains.kotlin.config.CompilerRunnerConstants.INTERNAL_ERROR_PREFIX
import org.jetbrains.kotlin.compilerRunner.KotlinCompilerRunner.runK2JsCompiler
import org.jetbrains.kotlin.compilerRunner.KotlinCompilerRunner.runK2JvmCompiler
import org.jetbrains.kotlin.utils.keysToMap
diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/modules/KotlinModuleDescriptionBuilder.java b/jps/jps-plugin/src/org/jetbrains/kotlin/modules/KotlinModuleDescriptionBuilder.java
new file mode 100644
index 00000000000..43722755430
--- /dev/null
+++ b/jps/jps-plugin/src/org/jetbrains/kotlin/modules/KotlinModuleDescriptionBuilder.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010-2015 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.kotlin.modules;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+public interface KotlinModuleDescriptionBuilder {
+ KotlinModuleDescriptionBuilder addModule(
+ String moduleName,
+ String outputDir,
+ List sourceFiles,
+ List javaSourceRoots,
+ Collection classpathRoots,
+ List annotationRoots,
+ boolean tests,
+ Set directoriesToFilterOut
+ );
+
+ CharSequence asText();
+}
diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/modules/KotlinModuleDescriptionBuilderFactory.java b/jps/jps-plugin/src/org/jetbrains/kotlin/modules/KotlinModuleDescriptionBuilderFactory.java
new file mode 100644
index 00000000000..322c75dfbd0
--- /dev/null
+++ b/jps/jps-plugin/src/org/jetbrains/kotlin/modules/KotlinModuleDescriptionBuilderFactory.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2010-2015 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.kotlin.modules;
+
+public interface KotlinModuleDescriptionBuilderFactory {
+ KotlinModuleDescriptionBuilder create();
+ String getFileExtension();
+}
diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/modules/KotlinModuleScriptBuilderFactory.java b/jps/jps-plugin/src/org/jetbrains/kotlin/modules/KotlinModuleScriptBuilderFactory.java
new file mode 100644
index 00000000000..83b5ef59715
--- /dev/null
+++ b/jps/jps-plugin/src/org/jetbrains/kotlin/modules/KotlinModuleScriptBuilderFactory.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2010-2015 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.kotlin.modules;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import static com.intellij.openapi.util.io.FileUtil.toSystemIndependentName;
+
+public class KotlinModuleScriptBuilderFactory implements KotlinModuleDescriptionBuilderFactory {
+
+ public static final KotlinModuleScriptBuilderFactory INSTANCE = new KotlinModuleScriptBuilderFactory();
+
+ private KotlinModuleScriptBuilderFactory() {}
+
+ @Override
+ public KotlinModuleDescriptionBuilder create() {
+ return new Builder();
+ }
+
+ @Override
+ public String getFileExtension() {
+ return "kts";
+ }
+
+ private static class Builder implements KotlinModuleDescriptionBuilder {
+ private final StringBuilder script = new StringBuilder();
+ private boolean done = false;
+
+ {
+ script.append("import kotlin.modules.*\n");
+ script.append("fun project() {\n");
+ }
+
+ @Override
+ public KotlinModuleDescriptionBuilder addModule(
+ String moduleName,
+ String outputDir,
+ List sourceFiles,
+ List javaSourceRoots,
+ Collection classpathRoots,
+ List annotationRoots,
+ boolean tests,
+ Set directoriesToFilterOut
+ ) {
+ assert !done : "Already done";
+
+ if (tests) {
+ script.append("// Module script for tests\n");
+ }
+ else {
+ script.append("// Module script for production\n");
+ }
+
+ script.append(" module(\"" + moduleName + "\", outputDir = \"" + toSystemIndependentName(outputDir) + "\") {\n");
+
+ for (File sourceFile : sourceFiles) {
+ script.append(" sources += \"" + toSystemIndependentName(sourceFile.getPath()) + "\"\n");
+ }
+
+ if (!javaSourceRoots.isEmpty()) {
+ processClassPathSection("Java source roots", javaSourceRoots, directoriesToFilterOut);
+ }
+
+ processClassPathSection("Classpath", classpathRoots, directoriesToFilterOut);
+ processAnnotationRoots(annotationRoots);
+
+ script.append(" }\n");
+ return this;
+ }
+
+ private void processClassPathSection(
+ @NotNull String sectionDescription,
+ @NotNull Collection files,
+ @NotNull Set directoriesToFilterOut
+ ) {
+ script.append(" // " + sectionDescription + "\n");
+ for (File file : files) {
+ if (directoriesToFilterOut.contains(file)) {
+ // 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 += \"" + toSystemIndependentName(file.getPath()) + "\"\n");
+ }
+ }
+
+ private void processAnnotationRoots(@NotNull List files) {
+ script.append(" // External annotations\n");
+ for (File file : files) {
+ script.append(" annotationsPath += \"").append(toSystemIndependentName(file.getPath())).append("\"\n");
+ }
+ }
+
+ @Override
+ public CharSequence asText() {
+ if (!done) {
+ script.append("}\n");
+ done = true;
+ }
+
+ return script;
+ }
+ }
+}
diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/modules/KotlinModuleXmlBuilderFactory.java b/jps/jps-plugin/src/org/jetbrains/kotlin/modules/KotlinModuleXmlBuilderFactory.java
new file mode 100644
index 00000000000..8ecbca258c3
--- /dev/null
+++ b/jps/jps-plugin/src/org/jetbrains/kotlin/modules/KotlinModuleXmlBuilderFactory.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2010-2015 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.kotlin.modules;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.kotlin.config.IncrementalCompilation;
+import org.jetbrains.kotlin.utils.Printer;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import static com.intellij.openapi.util.io.FileUtil.toSystemIndependentName;
+import static com.intellij.openapi.util.text.StringUtil.escapeXml;
+import static org.jetbrains.kotlin.cli.common.modules.ModuleXmlParser.*;
+
+public class KotlinModuleXmlBuilderFactory implements KotlinModuleDescriptionBuilderFactory {
+
+ public static final KotlinModuleXmlBuilderFactory INSTANCE = new KotlinModuleXmlBuilderFactory();
+
+ private KotlinModuleXmlBuilderFactory() {}
+
+ @Override
+ public KotlinModuleDescriptionBuilder create() {
+ return new Builder();
+ }
+
+ @Override
+ public String getFileExtension() {
+ return "xml";
+ }
+
+ private static class Builder implements KotlinModuleDescriptionBuilder {
+ private final StringBuilder xml = new StringBuilder();
+ private final Printer p = new Printer(xml);
+ private boolean done = false;
+
+ public Builder() {
+ openTag(p, MODULES);
+ }
+
+ @Override
+ public KotlinModuleDescriptionBuilder addModule(
+ String moduleName,
+ String outputDir,
+ List sourceFiles,
+ List javaSourceRoots,
+ Collection classpathRoots,
+ List annotationRoots,
+ boolean tests,
+ Set directoriesToFilterOut
+ ) {
+ assert !done : "Already done";
+
+ if (tests) {
+ p.println("");
+ }
+ else {
+ p.println("");
+ }
+
+ p.println("<", MODULE, " ",
+ NAME, "=\"", escapeXml(moduleName), "\" ",
+ OUTPUT_DIR, "=\"", getEscapedPath(new File(outputDir)), "\">"
+ );
+ p.pushIndent();
+
+ for (File sourceFile : sourceFiles) {
+ p.println("<", SOURCES, " ", PATH, "=\"", getEscapedPath(sourceFile), "\"/>");
+ }
+
+ if (!javaSourceRoots.isEmpty()) {
+ processClassPathSection("Java source roots", javaSourceRoots, directoriesToFilterOut);
+ }
+
+ processClassPathSection("Classpath", classpathRoots, directoriesToFilterOut);
+ processAnnotationRoots(annotationRoots);
+
+ closeTag(p, MODULE);
+ return this;
+ }
+
+ private void processClassPathSection(
+ @NotNull String sectionDescription,
+ @NotNull Collection files,
+ @NotNull Set directoriesToFilterOut
+ ) {
+ p.println("");
+ for (File file : files) {
+ boolean isOutput = directoriesToFilterOut.contains(file) && !IncrementalCompilation.ENABLED;
+ if (isOutput) {
+ // 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.
+ p.println("");
+ p.println("");
+ }
+ }
+ }
+
+ private void processAnnotationRoots(@NotNull List files) {
+ p.println("");
+ for (File file : files) {
+ p.println("<", EXTERNAL_ANNOTATIONS, " ", PATH, "=\"", getEscapedPath(file), "\"/>");
+ }
+ }
+
+ @Override
+ public CharSequence asText() {
+ if (!done) {
+ closeTag(p, MODULES);
+ done = true;
+ }
+ return xml;
+ }
+ }
+
+ private static void openTag(Printer p, String tag) {
+ p.println("<" + tag + ">");
+ p.pushIndent();
+ }
+
+ private static void closeTag(Printer p, String tag) {
+ p.popIndent();
+ p.println("" + tag + ">");
+ }
+
+ private static String getEscapedPath(File sourceFile) {
+ return escapeXml(toSystemIndependentName(sourceFile.getPath()));
+ }
+}
diff --git a/jps/jps-plugin/test/org/jetbrains/kotlin/jvm/compiler/ClasspathOrderTest.kt b/jps/jps-plugin/test/org/jetbrains/kotlin/jvm/compiler/ClasspathOrderTest.kt
new file mode 100644
index 00000000000..7652295c2f9
--- /dev/null
+++ b/jps/jps-plugin/test/org/jetbrains/kotlin/jvm/compiler/ClasspathOrderTest.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2010-2015 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.kotlin.jvm.compiler
+
+import org.jetbrains.kotlin.test.TestCaseWithTmpdir
+import org.jetbrains.kotlin.test.JetTestUtils
+import org.jetbrains.kotlin.test.MockLibraryUtil
+import org.jetbrains.kotlin.modules.KotlinModuleXmlBuilderFactory
+import java.io.File
+import org.jetbrains.kotlin.utils.PathUtil
+
+/**
+ * This test checks that Java classes from sources have higher priority in Kotlin resolution process than classes from binaries.
+ * To test this, we compile a Kotlin+Java module (in two modes: CLI and module-based) where a runtime Java class was replaced
+ * with a "newer" version in sources, and check that this class resolves to the one from sources by calling a method absent in the runtime
+ */
+public class ClasspathOrderTest : TestCaseWithTmpdir() {
+ class object {
+ val sourceDir = File(JetTestUtils.getTestDataPathBase() + "/classpathOrder").getAbsoluteFile()
+ }
+
+ public fun testClasspathOrderForCLI() {
+ MockLibraryUtil.compileKotlin(sourceDir.getPath(), tmpdir)
+ }
+
+ public fun testClasspathOrderForModuleScriptBuild() {
+ val xmlContent = KotlinModuleXmlBuilderFactory.INSTANCE.create().addModule(
+ "name",
+ File(tmpdir, "output").getAbsolutePath(),
+ listOf(sourceDir),
+ listOf(sourceDir),
+ listOf(PathUtil.getKotlinPathsForDistDirectory().getRuntimePath()),
+ listOf(),
+ false,
+ setOf()
+ ).asText().toString()
+
+ val xml = File(tmpdir, "module.xml")
+ xml.writeText(xmlContent)
+
+ MockLibraryUtil.compileKotlinModule(xml.getAbsolutePath())
+ }
+}
\ No newline at end of file
diff --git a/jps/jps-plugin/test/org/jetbrains/kotlin/modules/KotlinModuleXmlGeneratorTest.java b/jps/jps-plugin/test/org/jetbrains/kotlin/modules/KotlinModuleXmlGeneratorTest.java
new file mode 100644
index 00000000000..e024e504827
--- /dev/null
+++ b/jps/jps-plugin/test/org/jetbrains/kotlin/modules/KotlinModuleXmlGeneratorTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2010-2015 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.kotlin.modules;
+
+import junit.framework.TestCase;
+import org.jetbrains.kotlin.test.JetTestUtils;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collections;
+
+public class KotlinModuleXmlGeneratorTest extends TestCase {
+ public void testBasic() throws Exception {
+ String actual = KotlinModuleXmlBuilderFactory.INSTANCE.create().addModule(
+ "name",
+ "output",
+ Arrays.asList(new File("s1"), new File("s2")),
+ Collections.singletonList(new File("java")),
+ Arrays.asList(new File("cp1"), new File("cp2")),
+ Arrays.asList(new File("a1/f1"), new File("a2")),
+ false,
+ Collections.emptySet()
+ ).asText().toString();
+ JetTestUtils.assertEqualsToFile(new File("idea/testData/modules.xml/basic.xml"), actual);
+ }
+
+ public void testFiltered() throws Exception {
+ String actual = KotlinModuleXmlBuilderFactory.INSTANCE.create().addModule(
+ "name",
+ "output",
+ Arrays.asList(new File("s1"), new File("s2")),
+ Collections.emptyList(),
+ Arrays.asList(new File("cp1"), new File("cp2")),
+ Arrays.asList(new File("a1/f1"), new File("a2")),
+ false,
+ Collections.singleton(new File("cp1"))
+ ).asText().toString();
+ JetTestUtils.assertEqualsToFile(new File("idea/testData/modules.xml/filtered.xml"), actual);
+ }
+
+ public void testMultiple() throws Exception {
+ KotlinModuleDescriptionBuilder builder = KotlinModuleXmlBuilderFactory.INSTANCE.create();
+ builder.addModule(
+ "name",
+ "output",
+ Arrays.asList(new File("s1"), new File("s2")),
+ Collections.emptyList(),
+ Arrays.asList(new File("cp1"), new File("cp2")),
+ Arrays.asList(new File("a1/f1"), new File("a2")),
+ false,
+ Collections.singleton(new File("cp1"))
+ );
+ builder.addModule(
+ "name2",
+ "output2",
+ Arrays.asList(new File("s12"), new File("s22")),
+ Collections.emptyList(),
+ Arrays.asList(new File("cp12"), new File("cp22")),
+ Arrays.asList(new File("a12/f12"), new File("a22")),
+ true,
+ Collections.singleton(new File("cp12"))
+ );
+ String actual = builder.asText().toString();
+ JetTestUtils.assertEqualsToFile(new File("idea/testData/modules.xml/multiple.xml"), actual);
+ }
+}