diff --git a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/KotlinMavenImporter.kt b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/KotlinMavenImporter.kt
index 147f18d7358..07843544fc9 100644
--- a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/KotlinMavenImporter.kt
+++ b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/KotlinMavenImporter.kt
@@ -22,11 +22,14 @@ import com.intellij.openapi.components.Storage
import com.intellij.openapi.components.StoragePathMacros
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
import com.intellij.openapi.module.Module
+import com.intellij.openapi.roots.CompilerModuleExtension
+import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.openapi.roots.OrderEnumerator
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.impl.libraries.LibraryEx
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.util.AsyncResult
+import com.intellij.util.PathUtil
import org.jdom.Element
import org.jdom.Text
import org.jetbrains.idea.maven.importing.MavenImporter
@@ -139,6 +142,39 @@ class KotlinMavenImporter : MavenImporter(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_
}
}
+ private fun configureJSOutputPaths(
+ mavenProject: MavenProject,
+ modifiableRootModel: ModifiableRootModel,
+ facetSettings: KotlinFacetSettings,
+ mavenPlugin: MavenPlugin
+ ) {
+ fun parentPath(path: String): String =
+ File(path).absoluteFile.parentFile.absolutePath
+
+ val sharedOutputFile = mavenPlugin.configurationElement?.getChild("outputFile")?.text
+
+ val compilerModuleExtension = modifiableRootModel.getModuleExtension(CompilerModuleExtension::class.java) ?: return
+ val buildDirectory = mavenProject.buildDirectory
+
+ val executions = mavenPlugin.executions
+
+ executions.forEach {
+ val explicitOutputFile = it.configurationElement?.getChild("outputFile")?.text ?: sharedOutputFile
+ if (PomFile.KotlinGoals.Js in it.goals) {
+ // see org.jetbrains.kotlin.maven.K2JSCompilerMojo
+ val outputFilePath = PathUtil.toSystemDependentName(explicitOutputFile ?: "$buildDirectory/js/${mavenProject.mavenId.artifactId}.js")
+ compilerModuleExtension.setCompilerOutputPath(parentPath(outputFilePath))
+ facetSettings.productionOutputPath = outputFilePath
+ }
+ if (PomFile.KotlinGoals.TestJs in it.goals) {
+ // see org.jetbrains.kotlin.maven.KotlinTestJSCompilerMojo
+ val outputFilePath = PathUtil.toSystemDependentName(explicitOutputFile ?: "$buildDirectory/test-js/${mavenProject.mavenId.artifactId}-tests.js")
+ compilerModuleExtension.setCompilerOutputPathForTests(parentPath(outputFilePath))
+ facetSettings.testOutputPath = outputFilePath
+ }
+ }
+ }
+
private fun getCompilerArgumentsByConfigurationElement(
mavenProject: MavenProject,
configuration: Element?,
@@ -215,6 +251,7 @@ class KotlinMavenImporter : MavenImporter(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_
val platform = detectPlatform(mavenProject)
kotlinFacet.configureFacet(compilerVersion, LanguageFeature.Coroutines.defaultState, platform, modifiableModelsProvider)
+ val facetSettings = kotlinFacet.configuration.settings
val configuredPlatform = kotlinFacet.configuration.settings.targetPlatformKind!!
val configuration = mavenPlugin.configurationElement
val sharedArguments = getCompilerArgumentsByConfigurationElement(mavenProject, configuration, configuredPlatform)
@@ -225,6 +262,9 @@ class KotlinMavenImporter : MavenImporter(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_
if (executionArguments != null) {
parseCompilerArgumentsToFacet(executionArguments, emptyList(), kotlinFacet, modifiableModelsProvider)
}
+ if (facetSettings.compilerArguments is K2JSCompilerArguments) {
+ configureJSOutputPaths(mavenProject, modifiableModelsProvider.getModifiableRootModel(module), facetSettings, mavenPlugin)
+ }
MavenProjectImportHandler.getInstances(module.project).forEach { it(kotlinFacet, mavenProject) }
setImplementedModuleName(kotlinFacet, mavenProject, module)
kotlinFacet.noVersionAutoAdvance()
diff --git a/idea/idea-maven/test/org/jetbrains/kotlin/idea/maven/KotlinMavenImporterTest.kt b/idea/idea-maven/test/org/jetbrains/kotlin/idea/maven/KotlinMavenImporterTest.kt
index 89b4dcbece9..5bdb11696ce 100644
--- a/idea/idea-maven/test/org/jetbrains/kotlin/idea/maven/KotlinMavenImporterTest.kt
+++ b/idea/idea-maven/test/org/jetbrains/kotlin/idea/maven/KotlinMavenImporterTest.kt
@@ -20,9 +20,11 @@ import com.intellij.openapi.application.Result
import com.intellij.openapi.application.WriteAction
import com.intellij.openapi.projectRoots.JavaSdk
import com.intellij.openapi.projectRoots.ProjectJdkTable
+import com.intellij.openapi.roots.CompilerModuleExtension
import com.intellij.openapi.roots.LibraryOrderEntry
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.impl.libraries.LibraryEx
+import com.intellij.util.PathUtil
import junit.framework.TestCase
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
@@ -632,6 +634,75 @@ class KotlinMavenImporterTest : MavenImportingTestCase() {
Assert.assertTrue(ModuleRootManager.getInstance(getModule("project")).sdk!!.sdkType is KotlinSdkType)
}
+ fun testJsCustomOutputPaths() {
+ createProjectSubDirs("src/main/kotlin", "src/test/kotlin")
+ importProject(
+ """
+ test
+ project
+ 1.0.0
+
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib-js
+ $kotlinVersion
+
+
+
+
+ src/main/kotlin
+
+
+
+ kotlin-maven-plugin
+ org.jetbrains.kotlin
+ $kotlinVersion
+
+
+
+ compile
+ compile
+
+ js
+
+
+ ${'$'}{project.basedir}/prod/main.js
+
+
+
+ test-compile
+ test-compile
+
+ test-js
+
+
+ ${'$'}{project.basedir}/test/test.js
+
+
+
+
+
+
+ """
+ )
+
+ assertModules("project")
+ assertImporterStatePresent()
+
+ val projectBasePath = myProjectsManager.projects.first().file.parent.path
+
+ with(facetSettings) {
+ Assert.assertEquals("$projectBasePath/prod/main.js", PathUtil.toSystemIndependentName(productionOutputPath))
+ Assert.assertEquals("$projectBasePath/test/test.js", PathUtil.toSystemIndependentName(testOutputPath))
+ }
+
+ with (CompilerModuleExtension.getInstance(getModule("project"))!!) {
+ Assert.assertEquals("$projectBasePath/prod", PathUtil.toSystemIndependentName(compilerOutputUrl))
+ Assert.assertEquals("$projectBasePath/test", PathUtil.toSystemIndependentName(compilerOutputUrlForTests))
+ }
+ }
+
fun testFacetSplitConfiguration() {
createProjectSubDirs("src/main/kotlin", "src/main/kotlin.jvm", "src/test/kotlin", "src/test/kotlin.jvm")
diff --git a/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/KotlinJpsBuildTest.kt b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/KotlinJpsBuildTest.kt
index c9131cc476d..15240773946 100644
--- a/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/KotlinJpsBuildTest.kt
+++ b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/KotlinJpsBuildTest.kt
@@ -262,6 +262,13 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
return list.toTypedArray()
}
+ fun testKotlinJavaScriptProjectWithCustomOutputPaths() {
+ initProject(JS_STDLIB)
+ buildAllModules().assertSuccessful()
+
+ checkOutputFilesList(File(workDir, "target"))
+ }
+
fun testKotlinJavaScriptProjectWithSourceMap() {
initProject(JS_STDLIB)
buildAllModules().assertSuccessful()
@@ -686,7 +693,7 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
}
- private fun checkOutputFilesList() {
+ private fun checkOutputFilesList(outputDir: File = productionOutputDir) {
if (!expectedOutputFile.exists()) {
expectedOutputFile.writeText("")
throw IllegalStateException("$expectedOutputFile did not exist. Created empty file.")
@@ -694,7 +701,7 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
val sb = StringBuilder()
val p = Printer(sb, " ")
- productionOutputDir.printFilesRecursively(p)
+ outputDir.printFilesRecursively(p)
UsefulTestCase.assertSameLinesWithFile(expectedOutputFile.canonicalPath, sb.toString(), true)
}
diff --git a/jps-plugin/src/org/jetbrains/kotlin/jps/JpsKotlinCompilerSettings.kt b/jps-plugin/src/org/jetbrains/kotlin/jps/JpsKotlinCompilerSettings.kt
index f54ec737ba3..512b45fc59a 100644
--- a/jps-plugin/src/org/jetbrains/kotlin/jps/JpsKotlinCompilerSettings.kt
+++ b/jps-plugin/src/org/jetbrains/kotlin/jps/JpsKotlinCompilerSettings.kt
@@ -115,4 +115,18 @@ class JpsKotlinCompilerSettings : JpsElementBase() {
}
val JpsModule.targetPlatform: TargetPlatformKind<*>?
- get() = kotlinFacetExtension?.settings?.targetPlatformKind
\ No newline at end of file
+ get() = kotlinFacetExtension?.settings?.targetPlatformKind
+
+val JpsModule.productionOutputFilePath: String?
+ get() {
+ val facetSettings = kotlinFacetExtension?.settings ?: return null
+ if (facetSettings.useProjectSettings) return null
+ return facetSettings.productionOutputPath
+ }
+
+val JpsModule.testOutputFilePath: String?
+ get() {
+ val facetSettings = kotlinFacetExtension?.settings ?: return null
+ if (facetSettings.useProjectSettings) return null
+ return facetSettings.testOutputPath
+ }
\ No newline at end of file
diff --git a/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt b/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt
index abd199ac521..fad89465a20 100644
--- a/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt
+++ b/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt
@@ -56,6 +56,8 @@ import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.jps.JpsKotlinCompilerSettings
import org.jetbrains.kotlin.jps.build.JpsJsModuleUtils.getOutputMetaFile
import org.jetbrains.kotlin.jps.incremental.*
+import org.jetbrains.kotlin.jps.productionOutputFilePath
+import org.jetbrains.kotlin.jps.testOutputFilePath
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
import org.jetbrains.kotlin.modules.TargetId
@@ -681,7 +683,9 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
val representativeModule = representativeTarget.module
val moduleName = representativeModule.name
- val outputFile = JpsJsModuleUtils.getOutputFile(outputDir, moduleName, representativeTarget.isTests)
+ val isTests = representativeTarget.isTests
+ val explicitOutputPath = if (isTests) representativeModule.testOutputFilePath else representativeModule.productionOutputFilePath
+ val outputFile = explicitOutputPath?.let { File(it) } ?: JpsJsModuleUtils.getOutputFile(outputDir, moduleName, isTests)
val libraries = JpsJsModuleUtils.getLibraryFilesAndDependencies(representativeTarget)
val compilerSettings = JpsKotlinCompilerSettings.getCompilerSettings(representativeModule)
val k2JsArguments = JpsKotlinCompilerSettings.getK2JsCompilerArguments(representativeModule)
diff --git a/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilderModuleScriptGenerator.kt b/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilderModuleScriptGenerator.kt
index 04b2855d212..47584a2cf2d 100644
--- a/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilderModuleScriptGenerator.kt
+++ b/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilderModuleScriptGenerator.kt
@@ -34,6 +34,8 @@ import org.jetbrains.jps.model.module.JpsSdkDependency
import org.jetbrains.kotlin.build.JvmSourceRoot
import org.jetbrains.kotlin.config.IncrementalCompilation
import org.jetbrains.kotlin.jps.build.JpsUtils.getAllDependencies
+import org.jetbrains.kotlin.jps.productionOutputFilePath
+import org.jetbrains.kotlin.jps.testOutputFilePath
import org.jetbrains.kotlin.modules.KotlinModuleXmlBuilder
import org.jetbrains.kotlin.modules.TargetId
import org.jetbrains.kotlin.utils.addIfNotNull
@@ -161,8 +163,11 @@ object KotlinBuilderModuleScriptGenerator {
}
}
- fun getOutputDirSafe(target: ModuleBuildTarget): File =
- target.outputDir ?: throw ProjectBuildException("No output directory found for " + target)
+ fun getOutputDirSafe(target: ModuleBuildTarget): File {
+ val explicitOutputPath = if (target.isTests) target.module.testOutputFilePath else target.module.productionOutputFilePath
+ val explicitOutputDir = explicitOutputPath?.let { File(it).absoluteFile.parentFile }
+ return explicitOutputDir ?: target.outputDir ?: throw ProjectBuildException("No output directory found for " + target)
+ }
fun getProductionModulesWhichInternalsAreVisible(from: ModuleBuildTarget): List {
if (!from.isTests) return emptyList()
diff --git a/jps-plugin/testData/general/KotlinJavaScriptProjectWithCustomOutputPaths/expected-output.txt b/jps-plugin/testData/general/KotlinJavaScriptProjectWithCustomOutputPaths/expected-output.txt
new file mode 100644
index 00000000000..2d80d94ec34
--- /dev/null
+++ b/jps-plugin/testData/general/KotlinJavaScriptProjectWithCustomOutputPaths/expected-output.txt
@@ -0,0 +1,16 @@
+my_js/
+ lib/
+ kotlin.js
+ kotlin.meta.js
+ myproject/
+ root-package.kjsm
+ myproject.js
+ myproject.meta.js
+my_test-js/
+ lib/
+ kotlin.js
+ kotlin.meta.js
+ myproject-tests/
+ root-package.kjsm
+ myproject-tests.js
+ myproject-tests.meta.js
\ No newline at end of file
diff --git a/jps-plugin/testData/general/KotlinJavaScriptProjectWithCustomOutputPaths/kotlinProject.iml b/jps-plugin/testData/general/KotlinJavaScriptProjectWithCustomOutputPaths/kotlinProject.iml
new file mode 100644
index 00000000000..2b070ee7b93
--- /dev/null
+++ b/jps-plugin/testData/general/KotlinJavaScriptProjectWithCustomOutputPaths/kotlinProject.iml
@@ -0,0 +1,32 @@
+
+
+
+
+
+ $MODULE_DIR$/target/my_js/myproject.js
+ $MODULE_DIR$/target/my_test-js/myproject-tests.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jps-plugin/testData/general/KotlinJavaScriptProjectWithCustomOutputPaths/kotlinProject.ipr b/jps-plugin/testData/general/KotlinJavaScriptProjectWithCustomOutputPaths/kotlinProject.ipr
new file mode 100644
index 00000000000..90747786771
--- /dev/null
+++ b/jps-plugin/testData/general/KotlinJavaScriptProjectWithCustomOutputPaths/kotlinProject.ipr
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jps-plugin/testData/general/KotlinJavaScriptProjectWithCustomOutputPaths/src/main.kt b/jps-plugin/testData/general/KotlinJavaScriptProjectWithCustomOutputPaths/src/main.kt
new file mode 100644
index 00000000000..adb5b33c573
--- /dev/null
+++ b/jps-plugin/testData/general/KotlinJavaScriptProjectWithCustomOutputPaths/src/main.kt
@@ -0,0 +1,3 @@
+fun main(args: Array) {
+
+}
\ No newline at end of file
diff --git a/jps-plugin/testData/general/KotlinJavaScriptProjectWithCustomOutputPaths/src/main/kotlin/main.kt b/jps-plugin/testData/general/KotlinJavaScriptProjectWithCustomOutputPaths/src/main/kotlin/main.kt
new file mode 100644
index 00000000000..adb5b33c573
--- /dev/null
+++ b/jps-plugin/testData/general/KotlinJavaScriptProjectWithCustomOutputPaths/src/main/kotlin/main.kt
@@ -0,0 +1,3 @@
+fun main(args: Array) {
+
+}
\ No newline at end of file
diff --git a/jps-plugin/testData/general/KotlinJavaScriptProjectWithCustomOutputPaths/src/test/kotlin/test.kt b/jps-plugin/testData/general/KotlinJavaScriptProjectWithCustomOutputPaths/src/test/kotlin/test.kt
new file mode 100644
index 00000000000..442858bd7b3
--- /dev/null
+++ b/jps-plugin/testData/general/KotlinJavaScriptProjectWithCustomOutputPaths/src/test/kotlin/test.kt
@@ -0,0 +1,3 @@
+fun test() {
+
+}
\ No newline at end of file