From 982f08ce7ac5483eb91c8ea0071df8c7c5505364 Mon Sep 17 00:00:00 2001 From: Sergey Rostov Date: Sun, 7 Jul 2019 01:53:37 +0300 Subject: [PATCH] Gradle, JS: replace NodeJs plugin and extension with NpmResolver plugin --- .../gradle/internal/ProcessedFilesCache.kt | 1 - .../gradle/targets/js/KotlinJsCompilation.kt | 8 ++ .../gradle/targets/js/KotlinJsTarget.kt | 2 + .../targets/js/KotlinJsTargetConfigurator.kt | 4 - .../targets/js/nodejs/NodeJsExtension.kt | 19 ---- .../gradle/targets/js/nodejs/NodeJsPlugin.kt | 28 ----- .../targets/js/nodejs/NodeJsRootExtension.kt | 34 +++--- .../targets/js/npm/GradleNodeModulesCache.kt | 2 +- .../kotlin/gradle/targets/js/npm/NpmApi.kt | 6 +- .../gradle/targets/js/npm/NpmDependency.kt | 3 +- .../gradle/targets/js/npm/NpmProject.kt | 2 +- .../targets/js/npm/NpmResolverPlugin.kt | 26 +++++ .../gradle/targets/js/npm/NpmSimpleLinker.kt | 2 +- .../npm/resolved/KotlinRootNpmResolution.kt | 1 + .../resolver/KotlinCompilationNpmResolver.kt | 33 ++++-- .../npm/resolver/KotlinProjectNpmResolver.kt | 104 +++++++++--------- .../js/npm/resolver/KotlinRootNpmResolver.kt | 22 ++-- .../js/npm/tasks/KotlinNpmInstallTask.kt | 2 +- .../js/npm/tasks/KotlinPackageJsonTask.kt | 28 ++--- .../js/subtargets/KotlinJsSubTarget.kt | 5 +- .../gradle/targets/js/yarn/YarnSimple.kt | 2 +- .../gradle/targets/js/yarn/YarnWorkspaces.kt | 16 +-- 22 files changed, 177 insertions(+), 173 deletions(-) delete mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsExtension.kt delete mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsPlugin.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolverPlugin.kt diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/ProcessedFilesCache.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/ProcessedFilesCache.kt index 2a75d55dc12..20e5e392117 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/ProcessedFilesCache.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/ProcessedFilesCache.kt @@ -147,7 +147,6 @@ internal open class ProcessedFilesCache( operator fun get(elementHash: ByteArray) = byHash[ByteArrayWrapper(elementHash)] operator fun set(elementHash: ByteArray, element: Element) { - elementHash.toHexString() byHash[ByteArrayWrapper(elementHash)] = element val target = element.target if (target != null) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsCompilation.kt index ec3d396590f..11464c86b80 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsCompilation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsCompilation.kt @@ -9,6 +9,7 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import org.jetbrains.kotlin.gradle.dsl.KotlinJsOptions import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationWithResources import org.jetbrains.kotlin.gradle.plugin.KotlinTarget +import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile class KotlinJsCompilation( @@ -20,4 +21,11 @@ class KotlinJsCompilation( override val compileKotlinTask: Kotlin2JsCompile get() = super.compileKotlinTask as Kotlin2JsCompile + + internal val packageJsonHandlers = mutableListOf Unit>() + + @Suppress("unused") + fun packageJson(handler: PackageJson.() -> Unit) { + packageJsonHandlers.add(handler) + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTarget.kt index 2802ab41385..fb4f3589199 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTarget.kt @@ -16,6 +16,8 @@ import org.jetbrains.kotlin.gradle.plugin.whenEvaluated import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBrowserDsl import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsNodeDsl import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl +import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin +import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinPackageJsonTask import org.jetbrains.kotlin.gradle.targets.js.subtargets.KotlinBrowserJs import org.jetbrains.kotlin.gradle.targets.js.subtargets.KotlinNodeJs import org.jetbrains.kotlin.gradle.testing.internal.KotlinTestReport diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTargetConfigurator.kt index 9dea1329563..1583e6be590 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTargetConfigurator.kt @@ -20,10 +20,6 @@ open class KotlinJsTargetConfigurator(kotlinPluginVersion: String) : target as KotlinJsTarget super.configureTarget(target) - - target.compilations.forEach { compilation -> - KotlinPackageJsonTask.create(compilation) - } } override fun configureTest(target: KotlinOnlyTarget) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsExtension.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsExtension.kt deleted file mode 100644 index b1c85770226..00000000000 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsExtension.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.gradle.targets.js.nodejs - -import org.gradle.api.Project -import org.jetbrains.kotlin.gradle.targets.js.NpmVersions -import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson - -open class NodeJsExtension(val project: Project) { - internal val packageJsonHandlers = mutableListOf Unit>() - - @Suppress("unused") - fun packageJson(handler: PackageJson.() -> Unit) { - packageJsonHandlers.add(handler) - } -} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsPlugin.kt deleted file mode 100644 index 94f73caaea5..00000000000 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsPlugin.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.gradle.targets.js.nodejs - -import org.gradle.api.Plugin -import org.gradle.api.Project - -class NodeJsPlugin : Plugin { - override fun apply(target: Project) { - val root = NodeJsRootPlugin.apply(target.rootProject) - - if (target != target.rootProject) { - target.extensions.create(NodeJsRootExtension.EXTENSION_NAME, NodeJsExtension::class.java, target) - } - - root.requireResolver().addProject(target) - } - - companion object { - fun apply(project: Project): NodeJsExtension { - project.plugins.apply(NodeJsPlugin::class.java) - return project.extensions.getByName(NodeJsRootExtension.EXTENSION_NAME) as NodeJsExtension - } - } -} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsRootExtension.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsRootExtension.kt index e5ecd4da49f..85e9efc62d0 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsRootExtension.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsRootExtension.kt @@ -13,13 +13,13 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask import org.jetbrains.kotlin.gradle.targets.js.yarn.Yarn import java.io.File -open class NodeJsRootExtension(project: Project) : NodeJsExtension(project) { +open class NodeJsRootExtension(val rootProject: Project) { init { - check(project.rootProject == project) + check(rootProject.rootProject == rootProject) } - private val gradleHome = project.gradle.gradleUserHomeDir.also { - project.logger.kotlinInfo("Storing cached files in $it") + private val gradleHome = rootProject.gradle.gradleUserHomeDir.also { + rootProject.logger.kotlinInfo("Storing cached files in $it") } var installationDir = gradleHome.resolve("nodejs") @@ -33,13 +33,13 @@ open class NodeJsRootExtension(project: Project) : NodeJsExtension(project) { var packageManager: NpmApi = Yarn val nodeJsSetupTask: NodeJsSetupTask - get() = project.tasks.getByName(NodeJsSetupTask.NAME) as NodeJsSetupTask + get() = rootProject.tasks.getByName(NodeJsSetupTask.NAME) as NodeJsSetupTask val npmInstallTask: KotlinNpmInstallTask - get() = project.tasks.getByName(KotlinNpmInstallTask.NAME) as KotlinNpmInstallTask + get() = rootProject.tasks.getByName(KotlinNpmInstallTask.NAME) as KotlinNpmInstallTask val rootPackageDir: File - get() = project.buildDir.resolve("js") + get() = rootProject.buildDir.resolve("js") val projectPackagesDir: File get() = rootPackageDir.resolve("packages") @@ -105,7 +105,7 @@ open class NodeJsRootExtension(project: Project) : NodeJsExtension(project) { internal fun requireResolver(): KotlinRootNpmResolver = (resolutionState as? ResolutionState.Resolving ?: error("NPM Dependencies already resolved and installed")).resolver - internal fun resolveIfNeeded(project: Project): KotlinProjectNpmResolution { + internal fun resolveIfNeeded(requireUpToDateReason: String? = null): KotlinRootNpmResolution { val state0 = _resolutionState val resolution = when (state0) { is ResolutionState.Resolved -> state0.resolved @@ -116,15 +116,21 @@ open class NodeJsRootExtension(project: Project) : NodeJsExtension(project) { is ResolutionState.Resolved -> state1.resolved is ResolutionState.Resolving -> state1.resolver.close().also { _resolutionState = ResolutionState.Resolved(it) + if (requireUpToDateReason != null && !it.wasUpToDate) { + error("NPM dependencies should be resolved $requireUpToDateReason") + } } } } } } - return resolution[project] + return resolution } + internal fun requireAlreadyResolved(project: Project, reason: String = ""): KotlinProjectNpmResolution = + resolveIfNeeded(reason)[project] + internal fun getAlreadyResolvedOrNull(project: Project): KotlinProjectNpmResolution? { val state0 = resolutionState return when (state0) { @@ -133,19 +139,13 @@ open class NodeJsRootExtension(project: Project) : NodeJsExtension(project) { } } - internal fun requireResolved(project: Project, reason: String = ""): KotlinProjectNpmResolution = - getAlreadyResolvedOrNull(project) ?: error("NPM dependencies should be resolved $reason") - internal fun checkRequiredDependencies(project: Project, target: RequiresNpmDependencies) { - val requestedTaskDependencies = requireResolved( - project, - "before $target execution" - ).taskRequirements + val requestedTaskDependencies = requireAlreadyResolved(project, "before $target execution").taskRequirements val targetRequired = requestedTaskDependencies[target]?.toSet() ?: setOf() target.requiredNpmDependencies.forEach { check(it in targetRequired) { - "$it required by $target was not found resolved at the time of nodejs package manager call. " + + "${it.createDependency(project)} required by $target was not found resolved at the time of nodejs package manager call. " + "This may be caused by changing $target configuration after npm dependencies resolution." } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModulesCache.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModulesCache.kt index d7c7e5b7581..07daf453c14 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModulesCache.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModulesCache.kt @@ -20,7 +20,7 @@ internal class GradleNodeModulesCache(val nodeJs: NodeJsRootExtension) : AutoClo const val STATE_FILE_NAME = ".visited" } - val project: Project get() = nodeJs.project + val project: Project get() = nodeJs.rootProject internal val dir = nodeJs.nodeModulesGradleCacheDir private val cache = ProcessedFilesCache(project, dir, STATE_FILE_NAME, "9") diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmApi.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmApi.kt index c6375b2afaa..518a601d367 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmApi.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmApi.kt @@ -16,10 +16,14 @@ interface NpmApi { fun resolveProject(resolvedNpmProject: KotlinCompilationNpmResolution) + enum class Result { + upToDate, executed + } + fun resolveRootProject( rootProject: Project, subProjects: Collection - ) + ): Result companion object { fun resolveOperationDescription(packageManagerTitle: String): String = diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmDependency.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmDependency.kt index ddc4b0c5250..58faf1afbe1 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmDependency.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmDependency.kt @@ -86,8 +86,9 @@ data class NpmDependency( private fun resolveProject(): KotlinCompilationNpmResolution? { val nodeJs = NodeJsRootPlugin.apply(project.rootProject) + // may return null only while resolving configuration in ConfigurationVisitor.visit val resolvedProject = - if (isInIdeaSync) nodeJs.resolveIfNeeded(project) + if (isInIdeaSync) nodeJs.resolveIfNeeded()[project] else nodeJs.getAlreadyResolvedOrNull(project) return when (resolvedProject) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProject.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProject.kt index f2a772c3256..c10ef75e89a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProject.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProject.kt @@ -72,7 +72,7 @@ open class NpmProject(val compilation: KotlinJsCompilation) { * Require [request] nodejs module and return canonical path to it's main js file. */ fun require(request: String): String { - nodeJs.requireResolved(project) + nodeJs.requireAlreadyResolved(project) return modules.require(request) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolverPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolverPlugin.kt new file mode 100644 index 00000000000..df9e87ee51e --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolverPlugin.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.targets.js.npm + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.jetbrains.kotlin.gradle.dsl.kotlinExtension +import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin +import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinPackageJsonTask + +class NpmResolverPlugin : Plugin { + override fun apply(target: Project) { + val project = target + val nodeJs = NodeJsRootPlugin.apply(project.rootProject) + nodeJs.requireResolver().addProject(project) + } + + companion object { + fun apply(project: Project) { + project.plugins.apply(NpmResolverPlugin::class.java) + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmSimpleLinker.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmSimpleLinker.kt index e207a78f594..50062a29c25 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmSimpleLinker.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmSimpleLinker.kt @@ -19,7 +19,7 @@ import java.nio.file.Files * node_modules with symlinked packages and packages_imported */ class NpmSimpleLinker(val nodeJs: NodeJsRootExtension) { - private val rootProject = nodeJs.project + private val rootProject = nodeJs.rootProject private val rootProjectNodeModules = nodeJs.rootPackageDir.resolve(NpmProject.NODE_MODULES) fun link(projects: Collection) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolved/KotlinRootNpmResolution.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolved/KotlinRootNpmResolution.kt index cd800ca4855..99bd7230855 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolved/KotlinRootNpmResolution.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolved/KotlinRootNpmResolution.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension class KotlinRootNpmResolution( + val wasUpToDate: Boolean, val rootProject: Project, private val projects: Map ) : NodeJsRootExtension.ResolutionStateData { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinCompilationNpmResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinCompilationNpmResolver.kt index f6e898902c7..0befc2e3f73 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinCompilationNpmResolver.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinCompilationNpmResolver.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson import org.jetbrains.kotlin.gradle.targets.js.npm.fixSemver import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution +import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinPackageJsonTask import java.io.File import java.io.Serializable @@ -33,6 +34,7 @@ internal class KotlinCompilationNpmResolver( val nodeJs get() = resolver.nodeJs val target get() = compilation.target val project get() = target.project + val packageJsonTaskHolder = KotlinPackageJsonTask.create(compilation) override fun toString(): String = "KotlinCompilationNpmResolver(${npmProject.name})" @@ -47,19 +49,31 @@ internal class KotlinCompilationNpmResolver( } private var closed = false - private var resolution: KotlinCompilationNpmResolution? = null + private var resolveCalled = false + private val resolution: KotlinCompilationNpmResolution by lazy { + check(!closed) { "$this already closed" } + resolveCalled = true + packageJsonProducer.createPackageJson() + } + + /** + * Called from packageJson task + */ fun resolve() { check(!closed) { "$this already closed" } - check(resolution == null) { "$this already resolved" } + check(!resolveCalled) { "$this already resolved" } - resolution = packageJsonProducer.createPackageJson() + // call getter + resolution } fun close(): KotlinCompilationNpmResolution? { check(!closed) { "$this already closed" } + val result = resolution closed = true - return resolution + + return result } private fun createAggregatedConfiguration(): Configuration { @@ -87,7 +101,7 @@ internal class KotlinCompilationNpmResolver( } private fun createNpmToolsConfiguration(): Configuration? { - val taskRequirements = projectResolver.getTaskRequirements(compilation) + val taskRequirements = projectResolver.taskRequirements.getTaskRequirements(compilation) if (taskRequirements.isEmpty()) return null val toolsConfiguration = project.configurations.create("${compilation.name}NpmTools") @@ -127,6 +141,7 @@ internal class KotlinCompilationNpmResolver( } } + //TODO: rewrite when we get general way to have inter compilation dependencies if (compilation.name == KotlinCompilation.TEST_COMPILATION_NAME) { val main = compilation.target.compilations.findByName(KotlinCompilation.MAIN_COMPILATION_NAME) as KotlinJsCompilation internalDependencies.add(projectResolver[main]) @@ -190,8 +205,10 @@ internal class KotlinCompilationNpmResolver( fun createPackageJson(): KotlinCompilationNpmResolution { val resolvedInternalDependencies = internalDependencies.map { +// check(it.resolveCalled) { +// "Unresolved dependent npm package: ${this@KotlinCompilationNpmResolver} -> $it" +// } it.resolution - ?: error("Unresolved dependent npm package: ${this@KotlinCompilationNpmResolver} -> $it") } val importedExternalGradleDependencies = externalGradleDependencies.mapNotNull { resolver.gradleNodeModules.get(it.dependency, it.artifact) @@ -202,6 +219,8 @@ internal class KotlinCompilationNpmResolver( fixSemver(project.version.toString()) ) + packageJson.main = npmProject.main + resolvedInternalDependencies.forEach { packageJson.dependencies[it.packageJson.name] = it.packageJson.version } @@ -214,7 +233,7 @@ internal class KotlinCompilationNpmResolver( packageJson.dependencies[it.key] = chooseVersion(packageJson.dependencies[it.key], it.version) } - nodeJs.packageJsonHandlers.forEach { + compilation.packageJsonHandlers.forEach { it(packageJson) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinProjectNpmResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinProjectNpmResolver.kt index 28a1f889924..eb69aeafe17 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinProjectNpmResolver.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinProjectNpmResolver.kt @@ -6,8 +6,10 @@ package org.jetbrains.kotlin.gradle.targets.js.npm.resolver import org.gradle.api.Project +import org.gradle.api.Task import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.KotlinSingleTargetExtension +import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.dsl.kotlinExtensionOrNull import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.KotlinTarget @@ -15,6 +17,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinProjectNpmResolution +import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinPackageJsonTask internal class KotlinProjectNpmResolver( val project: Project, @@ -26,59 +29,30 @@ internal class KotlinProjectNpmResolver( operator fun get(compilation: KotlinJsCompilation): KotlinCompilationNpmResolver { check(compilation.target.project == project) - requireContainerListeners() return byCompilation[compilation] ?: error("$compilation was not registered in $this") } private var closed = false val compilationResolvers: Collection - get() { - requireContainerListeners() - return byCompilation.values - } + get() = byCompilation.values - private val taskRequirements = mutableMapOf>() - private val requiredFromTasksByCompilation = mutableMapOf>() + val taskRequirements by lazy { TasksRequirements(this) } - fun getTaskRequirements(compilation: KotlinJsCompilation): Collection { - requireContainerListeners() - return requiredFromTasksByCompilation[compilation] ?: listOf() - } - - val hasNodeModulesDependentTasks: Boolean - get() { - requireContainerListeners() - return _hasNodeModulesDependentTasks - } - - @Volatile - var _hasNodeModulesDependentTasks = false - private set - - var listenersInstalled = false - - @Synchronized - private fun requireContainerListeners() { - if (!listenersInstalled) { - listenersInstalled = true - addContainerListeners() - } + init { + addContainerListeners() } private fun addContainerListeners() { - project.tasks.forEach { task -> - if (task.enabled && task is RequiresNpmDependencies) { - addTaskRequirements(task) - } - } - val kotlin = project.kotlinExtensionOrNull + ?: error("NpmResolverPlugin should be applied after kotlin plugin") + when (kotlin) { is KotlinSingleTargetExtension -> addTargetListeners(kotlin.target) is KotlinMultiplatformExtension -> kotlin.targets.forEach { addTargetListeners(it) } + else -> error("Unsupported kotlin model: $kotlin") } } @@ -102,23 +76,6 @@ internal class KotlinProjectNpmResolver( byCompilation[compilation] = KotlinCompilationNpmResolver(this, compilation) } - @Synchronized - private fun addTaskRequirements(task: RequiresNpmDependencies) { - check(!closed) { resolver.alreadyResolvedMessage("create task $task that requires npm dependencies") } - - if (!_hasNodeModulesDependentTasks && task.nodeModulesRequired) { - _hasNodeModulesDependentTasks = true - } - - val requirements = task.requiredNpmDependencies.toList() - - taskRequirements[task] = requirements - - requiredFromTasksByCompilation - .getOrPut(task.compilation) { mutableListOf() } - .add(task) - } - fun close(): KotlinProjectNpmResolution { check(!closed) closed = true @@ -126,7 +83,46 @@ internal class KotlinProjectNpmResolver( return KotlinProjectNpmResolution( project, byCompilation.values.mapNotNull { it.close() }, - taskRequirements + taskRequirements.byTask ) } + + class TasksRequirements(val projectNpmResolver: KotlinProjectNpmResolver) { + val byTask = mutableMapOf>() + val byCompilation = mutableMapOf>() + + fun getTaskRequirements(compilation: KotlinJsCompilation): Collection = + byCompilation[compilation] ?: listOf() + + val hasNodeModulesDependentTasks: Boolean + get() = _hasNodeModulesDependentTasks + + @Volatile + var _hasNodeModulesDependentTasks = false + private set + + init { + projectNpmResolver.project.tasks.forEach { task -> + if (task.enabled && task is RequiresNpmDependencies) { + addTaskRequirements(task) + task.dependsOn(projectNpmResolver[task.compilation].packageJsonTaskHolder.getTaskOrProvider()) + task.dependsOn(projectNpmResolver.resolver.nodeJs.npmInstallTask) + } + } + } + + private fun addTaskRequirements(task: RequiresNpmDependencies) { + if (!_hasNodeModulesDependentTasks && task.nodeModulesRequired) { + _hasNodeModulesDependentTasks = true + } + + val requirements = task.requiredNpmDependencies.toList() + + byTask[task] = requirements + + byCompilation + .getOrPut(task.compilation) { mutableListOf() } + .add(task) + } + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinRootNpmResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinRootNpmResolver.kt index ab2c67602dd..a637ff44abd 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinRootNpmResolver.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinRootNpmResolver.kt @@ -9,10 +9,8 @@ import org.gradle.api.Project import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension +import org.jetbrains.kotlin.gradle.targets.js.npm.* import org.jetbrains.kotlin.gradle.targets.js.npm.GradleNodeModulesCache -import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency -import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject -import org.jetbrains.kotlin.gradle.targets.js.npm.NpmSimpleLinker import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinRootNpmResolution @@ -26,7 +24,7 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinRootNpmResoluti */ internal class KotlinRootNpmResolver internal constructor(val nodeJs: NodeJsRootExtension) : NodeJsRootExtension.ResolutionStateData { val rootProject: Project - get() = nodeJs.project + get() = nodeJs.rootProject private var closed: Boolean = false @@ -73,16 +71,20 @@ internal class KotlinRootNpmResolver internal constructor(val nodeJs: NodeJsRoot val projectResolutions = projectResolvers.values.map { it.close() }.associateBy { it.project } val allNpmPackages = projectResolutions.values.flatMap { it.npmProjects } - removeOutdatedPackages(nodeJs, allNpmPackages) gradleNodeModules.close() - if (allNpmPackages.any { it.externalNpmDependencies.isNotEmpty() }) { - nodeJs.packageManager.resolveRootProject(rootProject, allNpmPackages) - } else if (projectResolvers.values.any { it.hasNodeModulesDependentTasks }) { - NpmSimpleLinker(nodeJs).link(allNpmPackages) + val wasUpToDate = when { + allNpmPackages.any { it.externalNpmDependencies.isNotEmpty() } -> { + nodeJs.packageManager.resolveRootProject(rootProject, allNpmPackages) == NpmApi.Result.upToDate + } + projectResolvers.values.any { it.taskRequirements.hasNodeModulesDependentTasks } -> { + NpmSimpleLinker(nodeJs).link(allNpmPackages) + true // todo + } + else -> true } - return KotlinRootNpmResolution(rootProject, projectResolutions) + return KotlinRootNpmResolution(wasUpToDate, rootProject, projectResolutions) } private fun removeOutdatedPackages(nodeJs: NodeJsRootExtension, allNpmPackages: List) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/tasks/KotlinNpmInstallTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/tasks/KotlinNpmInstallTask.kt index 0f1558c5564..018ace663be 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/tasks/KotlinNpmInstallTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/tasks/KotlinNpmInstallTask.kt @@ -31,7 +31,7 @@ open class KotlinNpmInstallTask : DefaultTask() { @TaskAction fun resolve() { - nodeJs.resolveIfNeeded(project) + nodeJs.resolveIfNeeded() } companion object { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/tasks/KotlinPackageJsonTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/tasks/KotlinPackageJsonTask.kt index 6a7e50c70c2..12c529aafd7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/tasks/KotlinPackageJsonTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/tasks/KotlinPackageJsonTask.kt @@ -35,6 +35,20 @@ open class KotlinPackageJsonTask : DefaultTask() { dependentResolver.npmProject.packageJsonTask } + @get:Input + @get:Nested + internal val producerInputs: KotlinCompilationNpmResolver.PackageJsonProducerInputs + get() = producer.inputs + + @get:OutputFile + val packageJson: File + get() = compilationResolver.npmProject.packageJsonFile + + @TaskAction + fun resolve() { + compilationResolver.resolve() + } + companion object { fun create(compilation: KotlinJsCompilation): TaskHolder { val target = compilation.target @@ -66,18 +80,4 @@ open class KotlinPackageJsonTask : DefaultTask() { return packageJsonTask } } - - @get:Input - @get:Nested - internal val producerInputs: KotlinCompilationNpmResolver.PackageJsonProducerInputs - get() = producer.inputs - - @get:OutputFile - val packageJson: File - get() = compilationResolver.npmProject.packageJsonFile - - @TaskAction - fun resolve() { - compilationResolver.resolve() - } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinJsSubTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinJsSubTarget.kt index a77eddf17e8..c0b64a6135a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinJsSubTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinJsSubTarget.kt @@ -11,9 +11,10 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.plugin.whenEvaluated import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsSubTargetDsl -import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsPlugin import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin +import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolverPlugin import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject +import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinPackageJsonTask import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest import org.jetbrains.kotlin.gradle.tasks.createOrRegisterTask import org.jetbrains.kotlin.gradle.testing.internal.configureConventions @@ -31,7 +32,7 @@ abstract class KotlinJsSubTarget( val testTaskName = disambiguateCamelCased("test") fun configure() { - NodeJsPlugin.apply(project) + NpmResolverPlugin.apply(project) configureTests() configureRun() diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnSimple.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnSimple.kt index 083a42f1f8c..4f016750358 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnSimple.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnSimple.kt @@ -21,5 +21,5 @@ object YarnSimple : YarnBasics() { } } - override fun resolveRootProject(rootProject: Project, subProjects: Collection) = Unit + override fun resolveRootProject(rootProject: Project, subProjects: Collection) = NpmApi.Result.upToDate } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnWorkspaces.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnWorkspaces.kt index e9b55249be7..2c478ab9e63 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnWorkspaces.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnWorkspaces.kt @@ -14,21 +14,21 @@ import java.io.File object YarnWorkspaces : YarnBasics() { override fun resolveProject(resolvedNpmProject: KotlinCompilationNpmResolution) = Unit - override fun resolveRootProject(rootProject: Project, subProjects: Collection) { + override fun resolveRootProject(rootProject: Project, subProjects: Collection): NpmApi.Result { check(rootProject == rootProject.rootProject) setup(rootProject) - resolveWorkspaces(rootProject, subProjects) + return resolveWorkspaces(rootProject, subProjects) } private fun resolveWorkspaces( rootProject: Project, npmProjects: Collection - ) { + ): NpmApi.Result { val upToDateChecks = npmProjects.map { YarnUpToDateCheck(it.npmProject) } - if (upToDateChecks.all { it.upToDate }) return + if (upToDateChecks.all { it.upToDate }) return NpmApi.Result.upToDate val nodeJsWorldDir = NodeJsRootPlugin.apply(rootProject).rootPackageDir @@ -40,6 +40,8 @@ object YarnWorkspaces : YarnBasics() { upToDateChecks.forEach { it.commit() } + + return NpmApi.Result.executed } private fun saveRootProjectWorkspacesPackageJson( @@ -54,12 +56,6 @@ object YarnWorkspaces : YarnBasics() { val importedProjectWorkspaces = YarnImportedPackagesVersionResolver(rootProject, npmProjects, nodeJsWorldDir).resolveAndUpdatePackages() rootPackageJson.workspaces = npmProjectWorkspaces + importedProjectWorkspaces - - val nodeJs = NodeJsRootPlugin.apply(rootProject) - nodeJs.packageJsonHandlers.forEach { - it(rootPackageJson) - } - rootPackageJson.saveTo( nodeJsWorldDir.resolve(NpmProject.PACKAGE_JSON) )