diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/dukat/DukatCompilationResolverPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/dukat/DukatCompilationResolverPlugin.kt index 1bea05e1fe6..6e006a41401 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/dukat/DukatCompilationResolverPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/dukat/DukatCompilationResolverPlugin.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinRootNpmResoluti import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinCompilationNpmResolver import org.jetbrains.kotlin.gradle.tasks.dependsOn import org.jetbrains.kotlin.gradle.tasks.registerTask +import org.jetbrains.kotlin.gradle.utils.unavailableValueError internal class DukatCompilationResolverPlugin( @Transient @@ -26,7 +27,8 @@ internal class DukatCompilationResolverPlugin( ) : CompilationResolverPlugin { val project get() = resolver.project val nodeJs get() = resolver.nodeJs - val versions by lazy { nodeJs.versions } + private val nodeJs_ get() = nodeJs ?: unavailableValueError("nodeJs") + val versions by lazy { nodeJs_.versions } val npmProject by lazy { resolver.npmProject } val compilation get() = npmProject.compilation val compilationName by lazy { @@ -50,7 +52,7 @@ internal class DukatCompilationResolverPlugin( it.group = DUKAT_TASK_GROUP it.description = "Integrated generation Kotlin/JS external declarations for .d.ts files in $compilation" it.externalsOutputFormat = externalsOutputFormat - it.dependsOn(nodeJs.npmInstallTaskProvider, npmProject.packageJsonTask) + it.dependsOn(nodeJs_.npmInstallTaskProvider, npmProject.packageJsonTask) } } @@ -80,7 +82,7 @@ internal class DukatCompilationResolverPlugin( ) { it.group = DUKAT_TASK_GROUP it.description = "Generate Kotlin/JS external declarations for .d.ts files of all NPM dependencies in ${compilation}" - it.dependsOn(nodeJs.npmInstallTaskProvider, npmProject.packageJsonTask) + it.dependsOn(nodeJs_.npmInstallTaskProvider, npmProject.packageJsonTask) } } @@ -91,7 +93,7 @@ internal class DukatCompilationResolverPlugin( externalNpmDependencies: Set, fileCollectionDependencies: Set ) { - if (nodeJs.experimental.discoverTypes) { + if (nodeJs_.experimental.discoverTypes) { // todo: discoverTypes } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/KotlinNpmResolutionManager.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/KotlinNpmResolutionManager.kt index b10eff870e0..31be83f6594 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/KotlinNpmResolutionManager.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/KotlinNpmResolutionManager.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinCompilationNpmR import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinProjectNpmResolver import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinRootNpmResolver import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinPackageJsonTask +import org.jetbrains.kotlin.gradle.utils.unavailableValueError import java.io.File /** @@ -80,9 +81,9 @@ import java.io.File * * Note that in this case resolution process will be performed outside of task execution. */ -class KotlinNpmResolutionManager(private val nodeJsSettings: NodeJsRootExtension) { +class KotlinNpmResolutionManager(@Transient private val nodeJsSettings: NodeJsRootExtension?) { private val forceFullResolve: Boolean by lazy { - nodeJsSettings.rootProject.isInIdeaSync + (nodeJsSettings ?: unavailableValueError("nodeJsSettings")).rootProject.isInIdeaSync } internal val resolver = KotlinRootNpmResolver(nodeJsSettings, forceFullResolve) @@ -92,9 +93,11 @@ class KotlinNpmResolutionManager(private val nodeJsSettings: NodeJsRootExtension internal var state: ResolutionState? = null } - private val stateHolderProvider = nodeJsSettings.rootProject.gradle.sharedServices.registerIfAbsent( - "npm-resolution-manager-state-holder", KotlinNpmResolutionManagerStateHolder::class.java) { - } + private val stateHolderProvider = (nodeJsSettings ?: unavailableValueError("nodeJsSettings")) + .rootProject.gradle.sharedServices.registerIfAbsent( + "npm-resolution-manager-state-holder", KotlinNpmResolutionManagerStateHolder::class.java + ) { + } private val stateHolder get() = stateHolderProvider.get() @@ -159,7 +162,7 @@ class KotlinNpmResolutionManager(private val nodeJsSettings: NodeJsRootExtension return (state as ResolutionState.Installed).resolved } - val installUpToDate = nodeJsSettings.npmInstallTaskProvider?.get()?.state?.upToDate ?: false + val installUpToDate = nodeJsSettings?.npmInstallTaskProvider?.get()?.state?.upToDate ?: false val forceUpToDate = installUpToDate && !forceFullResolve val installation = prepareIfNeeded(requireUpToDateReason = reason, logger = logger) @@ -202,7 +205,7 @@ class KotlinNpmResolutionManager(private val nodeJsSettings: NodeJsRootExtension when (state1) { is ResolutionState.Prepared -> alreadyResolved(state1.preparedInstallation) is ResolutionState.Configuring -> { - val upToDate = nodeJsSettings.rootPackageJsonTaskProvider?.get()?.state?.upToDate ?: true + val upToDate = nodeJsSettings?.rootPackageJsonTaskProvider?.get()?.state?.upToDate ?: true if (requireUpToDateReason != null && !upToDate) { error("NPM dependencies should be resolved $requireUpToDateReason") } 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 7c9ec43ed78..532616436cb 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 @@ -11,18 +11,19 @@ import org.gradle.internal.service.ServiceRegistry import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution import java.io.File +import java.io.Serializable /** * NodeJS package manager API */ -interface NpmApi { +interface NpmApi : Serializable { fun setup(project: Project) - fun preparedFiles(nodeJs: NodeJsRootExtension): Collection + fun preparedFiles(nodeJs: NpmEnvironment): Collection fun prepareRootProject( rootProject: Project?, - nodeJs: NodeJsRootExtension, + nodeJs: NpmEnvironment, rootProjectName: String, rootProjectVersion: String, logger: Logger, @@ -34,7 +35,7 @@ interface NpmApi { fun resolveRootProject( services: ServiceRegistry, logger: Logger, - nodeJs: NodeJsRootExtension, + nodeJs: NpmEnvironment, command: String, isStandalone: Boolean, npmProjects: Collection, @@ -51,4 +52,12 @@ interface NpmApi { fun resolveOperationDescription(packageManagerTitle: String): String = "Resolving NPM dependencies using $packageManagerTitle" } -} \ No newline at end of file +} + +data class NpmEnvironment( + val rootPackageDir: File, + val nodeExecutable: String +) : Serializable + +internal val NodeJsRootExtension.asNpmEnvironment + get() = NpmEnvironment(rootPackageDir, requireConfigured().nodeExecutable) 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 80881041e68..9cd986597f5 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 @@ -37,6 +37,7 @@ import org.jetbrains.kotlin.gradle.tasks.registerTask import org.jetbrains.kotlin.gradle.utils.CompositeProjectComponentArtifactMetadata import org.jetbrains.kotlin.gradle.utils.`is` import org.jetbrains.kotlin.gradle.utils.topRealPath +import org.jetbrains.kotlin.gradle.utils.unavailableValueError import java.io.File import java.io.Serializable @@ -61,6 +62,7 @@ internal class KotlinCompilationNpmResolver( } val nodeJs get() = rootResolver.nodeJs + private val nodeJs_ get() = nodeJs ?: unavailableValueError("nodeJs") val target get() = compilation.target @@ -82,7 +84,7 @@ internal class KotlinCompilationNpmResolver( npmProject.publicPackageJsonTaskName, listOf(compilation) ) { - it.dependsOn(nodeJs.npmInstallTaskProvider) + it.dependsOn(nodeJs_.npmInstallTaskProvider) it.dependsOn(packageJsonTaskHolder) }.also { packageJsonTask -> if (compilation.isMain()) { @@ -187,7 +189,7 @@ internal class KotlinCompilationNpmResolver( } // We don't have `kotlin-js-test-runner` in NPM yet - all.dependencies.add(nodeJs.versions.kotlinJsTestRunner.createDependency(project)) + all.dependencies.add(nodeJs_.versions.kotlinJsTestRunner.createDependency(project)) project.dependencies.add( all.name, @@ -413,12 +415,9 @@ internal class KotlinCompilationNpmResolver( var fileCollectionDependencies: Collection, val projectPath: String ) : Serializable { - private val projectPackagesDir by lazy { compilationResolver.nodeJs.projectPackagesDir } - private val rootDir by lazy { compilationResolver.nodeJs.rootProject.rootDir } - - private val dukatPackageVersion by lazy { - compilationResolver.nodeJs.versions.dukat - } + private val projectPackagesDir by lazy { compilationResolver.nodeJs_.projectPackagesDir } + private val rootDir by lazy { compilationResolver.nodeJs_.rootProject.rootDir } + private val dukatPackageVersion by lazy { compilationResolver.nodeJs_.versions.dukat } @Transient internal lateinit var compilationResolver: KotlinCompilationNpmResolver @@ -464,7 +463,7 @@ internal class KotlinCompilationNpmResolver( } .filterNotNull() - val toolsNpmDependencies = compilationResolver.rootResolver.nodeJs.taskRequirements + val toolsNpmDependencies = compilationResolver.rootResolver.taskRequirements .getCompilationNpmRequirements(projectPath, compilationResolver.compilationDisambiguatedName) val dukatIfNecessary = if (externalNpmDependencies.any { it.generateExternals }) { 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 7bb0a91ac48..124386fa282 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 @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget 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.testing.KotlinJsTest +import org.jetbrains.kotlin.gradle.utils.unavailableValueError import java.io.Serializable import kotlin.reflect.KClass @@ -55,7 +56,7 @@ internal class KotlinProjectNpmResolver( addContainerListeners() project.whenEvaluated { - val nodeJs = resolver.nodeJs + val nodeJs = resolver.nodeJs ?: unavailableValueError("resolver.nodeJs") project.tasks.implementing(RequiresNpmDependencies::class) .configureEach { task -> if (task.enabled) { @@ -123,7 +124,7 @@ internal class KotlinProjectNpmResolver( return KotlinProjectNpmResolution( projectPath, byCompilation.values.mapNotNull { it.close() }, - resolver.nodeJs.taskRequirements.byTask + resolver.taskRequirements.byTask ) } } 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 6f00977a694..5c8c6557d4c 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 @@ -14,34 +14,47 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.isMain import org.jetbrains.kotlin.gradle.targets.js.dukat.DukatRootResolverPlugin import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrCompilation import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension -import org.jetbrains.kotlin.gradle.targets.js.npm.CompositeNodeModulesCache -import org.jetbrains.kotlin.gradle.targets.js.npm.GradleNodeModulesCache -import org.jetbrains.kotlin.gradle.targets.js.npm.KotlinNpmResolutionManager +import org.jetbrains.kotlin.gradle.targets.js.nodejs.TasksRequirements +import org.jetbrains.kotlin.gradle.targets.js.npm.* import org.jetbrains.kotlin.gradle.targets.js.npm.plugins.RootResolverPlugin import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinProjectNpmResolution import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinRootNpmResolution +import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnEnv import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin +import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnResolution import org.jetbrains.kotlin.gradle.targets.js.yarn.toVersionString import org.jetbrains.kotlin.gradle.utils.ArchiveOperationsCompat import org.jetbrains.kotlin.gradle.utils.FileSystemOperationsCompat +import org.jetbrains.kotlin.gradle.utils.unavailableValueError /** * See [KotlinNpmResolutionManager] for details about resolution process. + * + * This class contains many transient properties to deduplicate data when configuration cache is used. + * Regularly tasks share the same instance of this class, but with configuration cache each task that holds a reference to the instance will + * create an own copy. We use build services as a single storage for the heavy state of this class. */ internal class KotlinRootNpmResolver internal constructor( - val nodeJs: NodeJsRootExtension, + @Transient + val nodeJs: NodeJsRootExtension?, val forceFullResolve: Boolean ) { - val rootProject: Project - get() = nodeJs.rootProject + private val nodeJs_ + get() = nodeJs ?: unavailableValueError("nodeJs") - val rootProjectName by lazy { - rootProject.name + private val rootProject: Project? + get() = nodeJs?.rootProject + + private val rootProject_: Project + get() = rootProject ?: unavailableValueError("rootProject") + + private val rootProjectName by lazy { + rootProject_.name } - val rootProjectVersion by lazy { - rootProject.version.toString() + private val rootProjectVersion by lazy { + rootProject_.version.toString() } enum class State { @@ -64,14 +77,15 @@ internal class KotlinRootNpmResolver internal constructor( } } - private val archiveOperations by lazy { ArchiveOperationsCompat(rootProject) } - private val fs by lazy { FileSystemOperationsCompat(rootProject) } + private val archiveOperations by lazy { ArchiveOperationsCompat(rootProject_) } + private val fs by lazy { FileSystemOperationsCompat(rootProject_) } internal val gradleNodeModulesProvider: Provider = - rootProject.gradle.sharedServices.registerIfAbsent("gradle-node-modules", GradleNodeModulesCache::class.java) { - it.parameters.cacheDir.set(nodeJs.nodeModulesGradleCacheDir) - it.parameters.rootProjectDir.set(rootProject.projectDir) - } + rootProject_ + .gradle.sharedServices.registerIfAbsent("gradle-node-modules", GradleNodeModulesCache::class.java) { + it.parameters.cacheDir.set(nodeJs_.nodeModulesGradleCacheDir) + it.parameters.rootProjectDir.set(rootProject_.projectDir) + } val gradleNodeModules: GradleNodeModulesCache get() = gradleNodeModulesProvider.get().also { @@ -80,31 +94,53 @@ internal class KotlinRootNpmResolver internal constructor( } internal val compositeNodeModulesProvider: Provider = - rootProject.gradle.sharedServices.registerIfAbsent("composite-node-modules", CompositeNodeModulesCache::class.java) { - it.parameters.cacheDir.set(nodeJs.nodeModulesGradleCacheDir) - it.parameters.rootProjectDir.set(rootProject.projectDir) - } + rootProject_ + .gradle.sharedServices.registerIfAbsent("composite-node-modules", CompositeNodeModulesCache::class.java) { + it.parameters.cacheDir.set(nodeJs_.nodeModulesGradleCacheDir) + it.parameters.rootProjectDir.set(rootProject_.projectDir) + } val compositeNodeModules: CompositeNodeModulesCache get() = compositeNodeModulesProvider.get() - @Suppress("RedundantNullableReturnType") @Transient private val plugins_: MutableList? = mutableListOf().also { it.add(DukatRootResolverPlugin(forceFullResolve)) } - @Suppress("RedundantNullableReturnType") @Transient private val projectResolvers_: MutableMap? = mutableMapOf() + @Transient + private val yarnEnvironment_: Provider? = rootProject_.provider { + YarnPlugin.apply(rootProject_).requireConfigured() + } + + @Transient + private val npmEnvironment_: Provider? = rootProject_.provider { + nodeJs_.asNpmEnvironment + } + + @Transient + private val yarnResolutions_: Provider>? = rootProject_.provider { + YarnPlugin.apply(rootProject_).resolutions + } + + @Transient + private val taskRequirements_: TasksRequirements? = nodeJs_.taskRequirements + private val resolverStateHolder by lazy { - rootProject.gradle.sharedServices.registerIfAbsent( + rootProject_.gradle.sharedServices.registerIfAbsent( KotlinRootNpmResolverStateHolder::class.qualifiedName, KotlinRootNpmResolverStateHolder::class.java ) { it.parameters.plugins.set(plugins_) it.parameters.projectResolvers.set(projectResolvers_) + it.parameters.packageManager.set(nodeJs_.packageManager) + it.parameters.yarnEnvironment.set(yarnEnvironment_?.get()) + it.parameters.npmEnvironment.set(npmEnvironment_?.get()) + it.parameters.yarnResolutions.set(yarnResolutions_?.get()) + it.parameters.taskRequirements.set(taskRequirements_) } } @@ -129,11 +165,23 @@ internal class KotlinRootNpmResolver internal constructor( private val projectResolvers get() = projectResolvers_ ?: configurationCacheProjectResolvers - val yarn by lazy { - YarnPlugin.apply(rootProject) - } + private val packageManager + get() = nodeJs?.packageManager ?: resolverStateHolder.get().parameters.packageManager.get() - internal val mayBeUpToDateTasksRegistry = MayBeUpToDatePackageJsonTasksRegistry.registerIfAbsent(rootProject) + private val yarnEnvironment + get() = yarnEnvironment_?.get() ?: resolverStateHolder.get().parameters.yarnEnvironment.get() + + private val npmEnvironment + get() = npmEnvironment_?.get() ?: resolverStateHolder.get().parameters.npmEnvironment.get() + + private val yarnResolutions + get() = yarnResolutions_?.get() ?: resolverStateHolder.get().parameters.yarnResolutions.get() + + internal val taskRequirements + get() = taskRequirements_ ?: resolverStateHolder.get().parameters.taskRequirements.get() + + internal val mayBeUpToDateTasksRegistry = + MayBeUpToDatePackageJsonTasksRegistry.registerIfAbsent(rootProject_) fun alreadyResolvedMessage(action: String) = "Cannot $action. NodeJS projects already resolved." @@ -194,14 +242,14 @@ internal class KotlinRootNpmResolver internal constructor( gradleNodeModules.close() compositeNodeModules.close() - nodeJs.packageManager.prepareRootProject( + packageManager.prepareRootProject( rootProject, - nodeJs, + npmEnvironment, rootProjectName, rootProjectVersion, logger, allNpmPackages, - yarn.resolutions + yarnResolutions .associate { it.path to it.toVersionString() }, forceFullResolve ) @@ -232,13 +280,12 @@ internal class KotlinRootNpmResolver internal constructor( .values .flatMap { it.npmProjects } - val yarnConfigured = yarn.requireConfigured() - nodeJs.packageManager.resolveRootProject( + packageManager.resolveRootProject( services, logger, - nodeJs, - yarnConfigured.executable, - yarnConfigured.standalone, + npmEnvironment, + yarnEnvironment.executable, + yarnEnvironment.standalone, allNpmPackages, args ) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinRootNpmResolverStateHolder.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinRootNpmResolverStateHolder.kt index 94780b14ba9..c36c50710ad 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinRootNpmResolverStateHolder.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinRootNpmResolverStateHolder.kt @@ -8,17 +8,25 @@ package org.jetbrains.kotlin.gradle.targets.js.npm.resolver import org.gradle.api.provider.ListProperty import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property -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.nodejs.TasksRequirements +import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi +import org.jetbrains.kotlin.gradle.targets.js.npm.NpmEnvironment import org.jetbrains.kotlin.gradle.targets.js.npm.plugins.RootResolverPlugin +import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnEnv +import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnResolution // We use this service as a single storage for duplicated data in configuration cache internal abstract class KotlinRootNpmResolverStateHolder : BuildService { interface Parameters : BuildServiceParameters { val plugins: ListProperty val projectResolvers: MapProperty + val packageManager: Property + val yarnEnvironment: Property + val npmEnvironment: Property + val yarnResolutions: ListProperty + val taskRequirements: Property } var initialized = false 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 108d75b9016..97c5f6286e2 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 @@ -7,7 +7,10 @@ package org.jetbrains.kotlin.gradle.targets.js.npm.tasks import org.gradle.api.DefaultTask import org.gradle.api.tasks.* +import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin +import org.jetbrains.kotlin.gradle.targets.js.npm.asNpmEnvironment +import org.jetbrains.kotlin.gradle.utils.unavailableValueError import java.io.File open class KotlinNpmInstallTask : DefaultTask() { @@ -22,8 +25,8 @@ open class KotlinNpmInstallTask : DefaultTask() { } @Transient - private val nodeJs = NodeJsRootPlugin.apply(project.rootProject) - private val resolutionManager = nodeJs.npmResolutionManager + private val nodeJs: NodeJsRootExtension? = NodeJsRootPlugin.apply(project.rootProject) + private val resolutionManager = (nodeJs ?: unavailableValueError("nodeJs")).npmResolutionManager @Input val args: MutableList = mutableListOf() @@ -40,12 +43,12 @@ open class KotlinNpmInstallTask : DefaultTask() { @get:IgnoreEmptyDirectories @get:InputFiles val preparedFiles: Collection by lazy { - nodeJs.packageManager.preparedFiles(nodeJs) + (nodeJs ?: unavailableValueError("nodeJs")).packageManager.preparedFiles(nodeJs.asNpmEnvironment) } @get:OutputFile val yarnLock: File by lazy { - nodeJs.rootPackageDir.resolve("yarn.lock") + (nodeJs ?: unavailableValueError("nodeJs")).rootPackageDir.resolve("yarn.lock") } @TaskAction diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/Yarn.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/Yarn.kt index d44d68ee9bf..cd6cbe6031a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/Yarn.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/Yarn.kt @@ -11,6 +11,7 @@ import org.gradle.internal.service.ServiceRegistry import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency +import org.jetbrains.kotlin.gradle.targets.js.npm.NpmEnvironment import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution import java.io.File @@ -23,12 +24,12 @@ class Yarn : NpmApi { override fun setup(project: Project) = getDelegate(project.rootProject).setup(project) - override fun preparedFiles(nodeJs: NodeJsRootExtension): Collection = + override fun preparedFiles(nodeJs: NpmEnvironment): Collection = yarnWorkspaces.preparedFiles(nodeJs) override fun prepareRootProject( rootProject: Project?, - nodeJs: NodeJsRootExtension, + nodeJs: NpmEnvironment, rootProjectName: String, rootProjectVersion: String, logger: Logger, @@ -50,7 +51,7 @@ class Yarn : NpmApi { override fun resolveRootProject( services: ServiceRegistry, logger: Logger, - nodeJs: NodeJsRootExtension, + nodeJs: NpmEnvironment, command: String, isStandalone: Boolean, npmProjects: Collection, diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnBasics.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnBasics.kt index d80671b589a..c671ae1c0fc 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnBasics.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnBasics.kt @@ -9,10 +9,10 @@ import org.gradle.api.Project import org.gradle.api.logging.Logger import org.gradle.internal.service.ServiceRegistry import org.jetbrains.kotlin.gradle.internal.execWithProgress -import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency.Scope.PEER +import org.jetbrains.kotlin.gradle.targets.js.npm.NpmEnvironment import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution import java.io.File @@ -28,7 +28,7 @@ abstract class YarnBasics : NpmApi { fun yarnExec( services: ServiceRegistry, logger: Logger, - nodeJs: NodeJsRootExtension, + nodeJs: NpmEnvironment, command: String, isStandalone: Boolean, dir: File, @@ -39,7 +39,7 @@ abstract class YarnBasics : NpmApi { val arguments = args + if (logger.isDebugEnabled) "--verbose" else "" - val nodeExecutable = nodeJs.requireConfigured().nodeExecutable + val nodeExecutable = nodeJs.nodeExecutable exec.environment( "PATH", "$nodeExecutable${File.pathSeparator}${System.getenv("PATH")}" diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnEnv.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnEnv.kt index 67833a9de21..9713750965d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnEnv.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnEnv.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.targets.js.yarn import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore import java.io.File +import java.io.Serializable data class YarnEnv( val downloadUrl: String, @@ -15,4 +16,4 @@ data class YarnEnv( val executable: String, val ivyDependency: String, val standalone: Boolean -) +) : Serializable diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnResolutions.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnResolutions.kt index 316abccb2fe..8aac763aba7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnResolutions.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnResolutions.kt @@ -6,10 +6,11 @@ package org.jetbrains.kotlin.gradle.targets.js.yarn import org.jetbrains.kotlin.gradle.targets.js.npm.buildNpmVersion +import java.io.Serializable class YarnResolution( val path: String -) { +) : Serializable { var includedVersions = mutableListOf() var excludedVersions = mutableListOf() 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 3afe0a36030..9658e805ab3 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 @@ -8,15 +8,15 @@ package org.jetbrains.kotlin.gradle.targets.js.yarn import org.gradle.api.Project import org.gradle.api.logging.Logger import org.gradle.internal.service.ServiceRegistry -import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi +import org.jetbrains.kotlin.gradle.targets.js.npm.NpmEnvironment import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution import java.io.File class YarnWorkspaces : YarnBasics() { - override fun preparedFiles(nodeJs: NodeJsRootExtension): Collection { + override fun preparedFiles(nodeJs: NpmEnvironment): Collection { return listOf( nodeJs .rootPackageDir @@ -26,7 +26,7 @@ class YarnWorkspaces : YarnBasics() { override fun prepareRootProject( rootProject: Project?, - nodeJs: NodeJsRootExtension, + nodeJs: NpmEnvironment, rootProjectName: String, rootProjectVersion: String, logger: Logger, @@ -48,7 +48,7 @@ class YarnWorkspaces : YarnBasics() { } private fun prepareRootPackageJson( - nodeJs: NodeJsRootExtension, + nodeJs: NpmEnvironment, rootProjectName: String, rootProjectVersion: String, logger: Logger, @@ -70,7 +70,7 @@ class YarnWorkspaces : YarnBasics() { override fun resolveRootProject( services: ServiceRegistry, logger: Logger, - nodeJs: NodeJsRootExtension, + nodeJs: NpmEnvironment, command: String, isStandalone: Boolean, npmProjects: Collection, diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/internal/CleanableStore.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/internal/CleanableStore.kt index 28f009618d3..693270430fb 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/internal/CleanableStore.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/internal/CleanableStore.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.gradle.tasks.internal import org.jetbrains.kotlin.gradle.tasks.CleanDataTask +import java.io.Serializable import java.time.Instant /** @@ -16,7 +17,7 @@ import java.time.Instant * Now you will be able to access files via `CleanableStore["/path/to/dir"]["file/name"].use()` * and it would update usage of th store. */ -interface CleanableStore { +interface CleanableStore : Serializable { fun cleanDir(expirationDate: Instant) operator fun get(fileName: String): DownloadedFile diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/configurationCache.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/configurationCache.kt index c8909b7d2d7..315afc519b9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/configurationCache.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/configurationCache.kt @@ -22,4 +22,7 @@ internal fun Project.getSystemProperty(key: String): String? { } else { System.getProperty(key) } -} \ No newline at end of file +} + +internal fun unavailableValueError(propertyName: String): Nothing = + error("'$propertyName' should be available at configuration time but unavailable on configuration cache reuse") \ No newline at end of file