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 21b927910c6..8b1a3d3ded2 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 @@ -139,15 +139,18 @@ internal class KotlinCompilationNpmResolver( @Synchronized fun getResolutionOrResolveIfForced(): KotlinCompilationNpmResolution? { if (resolution != null) return resolution - if (packageJsonTaskHolder == null || packageJsonTaskHolder.get().state.upToDate) return resolve(skipWriting = true) - if (rootResolver.forceFullResolve && resolution == null) { + if (rootResolver.mayBeUpToDateTasksRegistry.get().shouldResolveNpmDependenciesFor(npmProject.packageJsonTaskPath)) { + // when we need to resolve the compilation but the task is UP-TO-DATE, so we don't have ready resolution yet + return resolve(skipWriting = true) + } + if (rootResolver.forceFullResolve) { // need to force all NPM tasks to be configured in IDEA import rootResolver.gradleNodeModules.fileHasher = project.serviceOf() rootResolver.compositeNodeModules.fileHasher = project.serviceOf() project.tasks.implementing(RequiresNpmDependencies::class).all {} return resolve() } - return null + return null // we don't need to resolve NPM dependencies for the compilation } @Synchronized 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 cbde0f34c55..6f00977a694 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 @@ -133,6 +133,8 @@ internal class KotlinRootNpmResolver internal constructor( YarnPlugin.apply(rootProject) } + internal val mayBeUpToDateTasksRegistry = MayBeUpToDatePackageJsonTasksRegistry.registerIfAbsent(rootProject) + fun alreadyResolvedMessage(action: String) = "Cannot $action. NodeJS projects already resolved." @Synchronized diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/MayBeUpToDatePackageJsonTasksRegistry.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/MayBeUpToDatePackageJsonTasksRegistry.kt new file mode 100644 index 00000000000..a91ab393e2f --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/MayBeUpToDatePackageJsonTasksRegistry.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2010-2021 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.resolver + +import org.gradle.api.Project +import org.gradle.api.provider.Provider +import org.gradle.api.services.BuildService +import org.gradle.api.services.BuildServiceParameters +import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinPackageJsonTask + +internal abstract class MayBeUpToDatePackageJsonTasksRegistry : BuildService { + private val mayBeUpToDateTasks = mutableSetOf() + + fun markForNpmDependenciesResolve(task: KotlinPackageJsonTask) { + mayBeUpToDateTasks.add(task.path) + } + + fun shouldResolveNpmDependenciesFor(taskPath: String) = taskPath in mayBeUpToDateTasks + + companion object { + fun registerIfAbsent(project: Project): Provider = + project.rootProject.gradle.sharedServices.registerIfAbsent( + MayBeUpToDatePackageJsonTasksRegistry::class.qualifiedName, + MayBeUpToDatePackageJsonTasksRegistry::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/tasks/KotlinPackageJsonTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/tasks/KotlinPackageJsonTask.kt index 67e83770ff6..a4302895b61 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 @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.targets.js.npm.tasks import org.gradle.api.DefaultTask import org.gradle.api.plugins.BasePlugin +import org.gradle.api.provider.Property import org.gradle.api.tasks.* import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension @@ -14,6 +15,7 @@ import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson import org.jetbrains.kotlin.gradle.targets.js.npm.fakePackageJsonValue import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject +import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.MayBeUpToDatePackageJsonTasksRegistry import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinCompilationNpmResolver import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.PACKAGE_JSON_UMBRELLA_TASK_NAME import org.jetbrains.kotlin.gradle.tasks.dependsOn @@ -21,12 +23,18 @@ import org.jetbrains.kotlin.gradle.tasks.registerTask import org.jetbrains.kotlin.gradle.utils.getValue import java.io.File -open class KotlinPackageJsonTask : DefaultTask() { +abstract class KotlinPackageJsonTask : DefaultTask() { init { onlyIf { npmResolutionManager.isConfiguringState() } + outputs.upToDateWhen { + // this way we will ensure that we need to resolve dependencies for the compilation in case of UP-TO-DATE task + // used in KotlinCompilationNpmResolver#getResolutionOrResolveIfForced + mayBeUpToDateTasksRegistry.get().markForNpmDependenciesResolve(it as KotlinPackageJsonTask) + true + } } @Transient @@ -37,6 +45,9 @@ open class KotlinPackageJsonTask : DefaultTask() { @Transient private lateinit var compilation: KotlinJsCompilation + @get:Internal + internal abstract val mayBeUpToDateTasksRegistry: Property + private val compilationDisambiguatedName by lazy { compilation.disambiguatedName } @@ -106,6 +117,10 @@ open class KotlinPackageJsonTask : DefaultTask() { task.compilation = compilation task.description = "Create package.json file for $compilation" task.group = NodeJsRootPlugin.TASKS_GROUP_NAME + task.mayBeUpToDateTasksRegistry.apply { + set(MayBeUpToDatePackageJsonTasksRegistry.registerIfAbsent(project)) + disallowChanges() + } task.dependsOn(target.project.provider { task.findDependentTasks() }) task.dependsOn(npmCachesSetupTask)