diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ExecutionStrategyIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ExecutionStrategyIT.kt index ee948eb9568..240d6a5048a 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ExecutionStrategyIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ExecutionStrategyIT.kt @@ -9,11 +9,11 @@ class ExecutionStrategyJsIT : ExecutionStrategyIT() { project.setupWorkingDir() val buildGradle = project.projectDir.getFileByName("build.gradle") buildGradle.modify { it.replace("apply plugin: \"kotlin\"", "apply plugin: \"kotlin2js\"") + - "\ncompileKotlin2Js.kotlinOptions.outputFile = \"out.js\"" } + "\ncompileKotlin2Js.kotlinOptions.outputFile = \"web/js/out.js\"" } } override fun CompiledProject.checkOutput() { - assertFileExists("out.js") + assertFileExists("web/js/out.js") } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt index d7ec1d4c7e3..210c53d9142 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt @@ -4,6 +4,8 @@ import org.jetbrains.kotlin.gradle.util.getFileByName import org.jetbrains.kotlin.gradle.util.modify import org.junit.Test import java.io.File +import java.util.zip.ZipFile +import kotlin.test.assertEquals class Kotlin2JsGradlePluginIT : BaseGradleIT() { @Test @@ -38,8 +40,6 @@ class Kotlin2JsGradlePluginIT : BaseGradleIT() { project.build("clean") { assertSuccessful() assertReportExists() - assertContains(":mainProject:cleanCompileKotlin2Js\n") - assertNoSuchFile("mainProject/web/js/app.js") // Test that we don't accidentally remove the containing directory // This would fail if we used the default clean task of the copy task @@ -52,7 +52,38 @@ class Kotlin2JsGradlePluginIT : BaseGradleIT() { project.build("clean") { assertSuccessful() assertReportExists() - assertContains(":mainProject:cleanCompileKotlin2Js UP-TO-DATE") + } + } + + @Test + fun testJarIncludesJsDefaultOutput() { + val project = Project("kotlin2JsNoOutputFileProject", "2.10") + + project.build("jar") { + assertSuccessful() + + assertContains(":compileKotlin2Js") + val jarPath = "build/libs/kotlin2JsNoOutputFileProject.jar" + assertFileExists(jarPath) + val jar = ZipFile(fileInWorkingDir(jarPath)) + assertEquals(1, jar.entries().asSequence().count { it.name == "kotlin2JsNoOutputFileProject_main.js" }, + "The jar should contain an entry `kotlin2JsNoOutputFileProject_main.js` with no duplicates") + } + } + + @Test + fun testJarIncludesJsOutputSetExplicitly() { + val project = Project("kotlin2JsModuleKind", "2.10") + + project.build(":jar") { + assertSuccessful() + + assertContains(":compileKotlin2Js") + val jarPath = "build/libs/kotlin2JsModuleKind.jar" + assertFileExists(jarPath) + val jar = ZipFile(fileInWorkingDir(jarPath)) + assertEquals(1, jar.entries().asSequence().count { it.name == "app.js" }, + "The jar should contain an entry `app.js` with no duplicates") } } @@ -107,6 +138,12 @@ class Kotlin2JsGradlePluginIT : BaseGradleIT() { assertFileExists("build/kotlin2js/main/module.js") assertFileExists("build/kotlin2js/integrationTest/module-inttests.js") + + val jarPath = "build/libs/kotlin2JsProjectWithCustomSourceset-inttests.jar" + assertFileExists(jarPath) + val jar = ZipFile(fileInWorkingDir(jarPath)) + assertEquals(1, jar.entries().asSequence().count { it.name == "module-inttests.js" }, + "The jar should contain an entry `module-inttests.js` with no duplicates") } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsProjectWithCustomSourceset/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsProjectWithCustomSourceset/build.gradle index 2d57f0c95aa..33a301d9be6 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsProjectWithCustomSourceset/build.gradle +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsProjectWithCustomSourceset/build.gradle @@ -33,6 +33,13 @@ dependencies { integrationTestCompile "org.jetbrains.kotlin:kotlin-test-js:$kotlin_version" } +task integrationTestJar(type: Jar) { + from sourceSets.integrationTest.output + classifier = 'inttests' +} + +build.dependsOn integrationTestJar + task jarSources(type: Jar) { from sourceSets.main.allSource classifier = 'source' diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt index bde7f14954c..d33f1496ed8 100755 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt @@ -7,6 +7,7 @@ import com.android.build.gradle.internal.variant.BaseVariantData import com.android.build.gradle.internal.variant.BaseVariantOutputData import com.android.builder.model.SourceProvider import groovy.lang.Closure +import org.gradle.api.InvalidUserDataException import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.artifacts.Configuration @@ -20,16 +21,18 @@ import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.bundling.Zip import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.JavaCompile +import org.jetbrains.kotlin.com.intellij.openapi.util.io.FileUtil import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl -import org.jetbrains.kotlin.gradle.internal.* +import org.jetbrains.kotlin.gradle.internal.AnnotationProcessingManager +import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin +import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin.Companion.getKaptClasssesDir +import org.jetbrains.kotlin.gradle.internal.initKapt import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper import org.jetbrains.kotlin.gradle.plugin.android.KotlinJillTask import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlin.incremental.configureMultiProjectIncrementalCompilation import org.jetbrains.kotlin.incremental.multiproject.ArtifactDifferenceRegistryProviderAndroidWrapper -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import java.io.File import java.net.URL import java.util.* @@ -186,18 +189,30 @@ internal class Kotlin2JsSourceSetProcessor( taskDescription = "Compiles the kotlin sources in $sourceSet to JavaScript.", compileTaskNameSuffix = "kotlin2Js" ) { - private val clean = project.tasks.findByName("clean") - private val build = project.tasks.findByName("build") override fun doCreateTask(project: Project, taskName: String): Kotlin2JsCompile = tasksProvider.createKotlinJSTask(project, taskName, sourceSet.name) override fun doTargetSpecificProcessing() { - val taskName = kotlinTask.name - build?.dependsOn(taskName) - clean?.dependsOn("clean" + taskName.capitalize()) + project.tasks.findByName(sourceSet.classesTaskName).dependsOn(kotlinTask) kotlinTask.source(kotlinSourceSet.kotlin) createCleanSourceMapTask() + + // outputFile can be set later during the configuration phase, get it only after the phase: + project.afterEvaluate { + kotlinTask.kotlinOptions.outputFile = File(kotlinTask.outputFile).absolutePath + val outputDir = File(kotlinTask.outputFile).parentFile + + if (FileUtil.isAncestor(outputDir, project.rootDir, false)) + throw InvalidUserDataException( + "The output directory '$outputDir' (defined by outputFile of $kotlinTask) contains or " + + "matches the project root directory '${project.rootDir}'.\n" + + "Gradle will not be able to build the project because of the root directory lock.\n" + + "To fix this, consider using the default outputFile location instead of providing it explicitly.") + + sourceSet.output.setClassesDir(outputDir) + kotlinTask.destinationDir = outputDir + } } private fun createCleanSourceMapTask() { @@ -207,7 +222,7 @@ internal class Kotlin2JsSourceSetProcessor( task.delete(object : Closure(this) { override fun call(): String? = (kotlinTask.property("outputFile") as String) + ".map" }) - clean?.dependsOn(taskName) + project.tasks.findByName("clean")?.dependsOn(taskName) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index 4e68237d9a0..c5015a77104 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.gradle.tasks -import org.codehaus.groovy.runtime.MethodClosure import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.logging.Logger @@ -44,7 +43,6 @@ import org.jetbrains.kotlin.incremental.multiproject.ArtifactDifferenceRegistry import org.jetbrains.kotlin.incremental.multiproject.ArtifactDifferenceRegistryProvider import org.jetbrains.kotlin.utils.LibraryUtils import java.io.File -import java.rmi.Remote import java.util.* import kotlin.properties.Delegates @@ -322,10 +320,6 @@ open class Kotlin2JsCompile() : AbstractKotlinCompile(), val outputFile: String get() = kotlinOptions.outputFile ?: defaultOutputFile.canonicalPath - init { - @Suppress("LeakingThis") - outputs.file(MethodClosure(this, "getOutputFile")) - } override fun findKotlinCompilerJar(project: Project): File? = findKotlinJsCompilerJar(project) @@ -348,7 +342,6 @@ open class Kotlin2JsCompile() : AbstractKotlinCompile(), logger.debug("Calling compiler") destinationDir.mkdirs() - args.freeArgs = args.freeArgs + sourceRoots.kotlinSourceFiles.map { it.absolutePath } val friendDependency = friendTaskName ?.let { project.getTasksByName(it, false).singleOrNull() as? Kotlin2JsCompile }