diff --git a/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/resources/NpmVersions.kt.vm b/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/resources/NpmVersions.kt.vm index 60e7cdeda77..9204c558637 100644 --- a/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/resources/NpmVersions.kt.vm +++ b/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/resources/NpmVersions.kt.vm @@ -5,11 +5,13 @@ package $package +import java.io.Serializable + /** * Package versions used by tasks */ // DO NOT MODIFY DIRECTLY! Use org.jetbrains.kotlin.generators.gradle.targets.js.MainKt -class $class { +class $class : Serializable { #foreach( $dep in $dependencies ) val $dep.camelize() = NpmPackageVersion("$dep.name", "$dep.version") #end 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 037b3b0e8eb..4514d08c210 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 @@ -24,7 +24,6 @@ import java.security.MessageDigest * @param version When updating logic in `compute`, `version` should be increased to invalidate cache */ internal open class ProcessedFilesCache( - val logger: Logger, val projectDir: File, val targetDir: File, stateFileName: String, @@ -174,7 +173,8 @@ internal open class ProcessedFilesCache( try { GsonBuilder().setPrettyPrinting().create().newJsonReader(stateFile.reader()).use { readFrom(it) } } catch (e: Throwable) { - logger.warn("Cannot read $stateFile", e) + System.err.println("Cannot read $stateFile") + e.printStackTrace() if (targetDir.exists()) { targetDir.deleteRecursively() } @@ -209,14 +209,14 @@ internal open class ProcessedFilesCache( if (old != null) { if (checkTarget(old.target)) return old.target - else logger.warn("Cannot find ${File(targetDir.relativeTo(projectDir), old.target!!)}, rebuilding") + else System.err.println("Cannot find ${File(targetDir.relativeTo(projectDir), old.target!!)}, rebuilding") } val key = compute()?.relativeTo(targetDir)?.toString() val existedTarget = state.byTarget[key] if (key != null && existedTarget != null) { if (!File(existedTarget.src).exists()) { - logger.warn("Removing cache for removed source `${existedTarget.src}`") + System.err.println("Removing cache for removed source `${existedTarget.src}`") state.remove(existedTarget) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/NpmVersions.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/NpmVersions.kt index 660a2800860..154b38aefbf 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/NpmVersions.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/NpmVersions.kt @@ -5,11 +5,13 @@ package org.jetbrains.kotlin.gradle.targets.js +import java.io.Serializable + /** * Package versions used by tasks */ // DO NOT MODIFY DIRECTLY! Use org.jetbrains.kotlin.generators.gradle.targets.js.MainKt -class NpmVersions { +class NpmVersions : Serializable { val dukat = NpmPackageVersion("dukat", "0.5.8-rc.4") val webpack4 = NpmPackageVersion("webpack", "4.46.0") val sourceMapLoader1 = NpmPackageVersion("source-map-loader", "1.1.3") diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/RequiredKotlinJsDependency.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/RequiredKotlinJsDependency.kt index 27ee560db82..c2306a7336f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/RequiredKotlinJsDependency.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/RequiredKotlinJsDependency.kt @@ -8,7 +8,8 @@ package org.jetbrains.kotlin.gradle.targets.js import org.gradle.api.Project import org.gradle.api.artifacts.Dependency import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency +import java.io.Serializable -interface RequiredKotlinJsDependency { +interface RequiredKotlinJsDependency : Serializable { fun createDependency(project: Project, scope: NpmDependency.Scope = NpmDependency.Scope.DEV): Dependency } \ No newline at end of file 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 be04c1459d4..36205b328e3 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 @@ -21,11 +21,13 @@ import org.jetbrains.kotlin.gradle.tasks.dependsOn import org.jetbrains.kotlin.gradle.tasks.registerTask internal class DukatCompilationResolverPlugin( + @Transient private val resolver: KotlinCompilationNpmResolver ) : CompilationResolverPlugin { val project get() = resolver.project val nodeJs get() = resolver.nodeJs - val npmProject get() = resolver.npmProject + val versions by lazy { nodeJs.versions } + val npmProject by lazy { resolver.npmProject } val compilation get() = npmProject.compilation val compilationName by lazy { compilation.disambiguatedName @@ -83,7 +85,7 @@ internal class DukatCompilationResolverPlugin( } override fun hookDependencies( - internalDependencies: Set, + internalDependencies: Set, internalCompositeDependencies: Set, externalGradleDependencies: Set, externalNpmDependencies: Set, @@ -107,7 +109,7 @@ internal class DukatCompilationResolverPlugin( } DukatExecutor( - nodeJs.versions, + versions, DtsResolver(npmProject).getAllDts(externalNpmDependencies), externalsOutputFormat, npmProject, diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/dukat/DukatRootResolverPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/dukat/DukatRootResolverPlugin.kt index 30e869d6ac9..f23c7cff349 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/dukat/DukatRootResolverPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/dukat/DukatRootResolverPlugin.kt @@ -10,7 +10,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.targets.js.npm.resolver.KotlinRootNpmResolver -internal class DukatRootResolverPlugin(val resolver: KotlinRootNpmResolver) : RootResolverPlugin { +internal class DukatRootResolverPlugin(val forceFullResolve: Boolean) : RootResolverPlugin { val compilations = mutableListOf() override fun createCompilationResolverPlugins(resolver: KotlinCompilationNpmResolver): List { @@ -20,7 +20,7 @@ internal class DukatRootResolverPlugin(val resolver: KotlinRootNpmResolver) : Ro } override fun close(resolution: KotlinRootNpmResolution) { - if (resolver.forceFullResolve) { + if (forceFullResolve) { // inside idea import compilations.forEach { it.executeDukatIfNeeded(true, resolution) 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 742fd24630a..14393c3a0c3 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 @@ -20,8 +20,9 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.RootPackageJsonTask import org.jetbrains.kotlin.gradle.targets.js.yarn.Yarn import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore import java.io.File +import java.io.Serializable -open class NodeJsRootExtension(@Transient val rootProject: Project) : ConfigurationPhaseAware() { +open class NodeJsRootExtension(@Transient val rootProject: Project) : ConfigurationPhaseAware(), Serializable { init { check(rootProject.rootProject == rootProject) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsSetupTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsSetupTask.kt index df4c26eea0c..c64f7165783 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsSetupTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsSetupTask.kt @@ -2,25 +2,29 @@ package org.jetbrains.kotlin.gradle.targets.js.nodejs import org.gradle.api.DefaultTask import org.gradle.api.artifacts.Configuration +import org.gradle.api.file.FileSystemOperations import org.gradle.api.provider.Provider import org.gradle.api.tasks.* import org.jetbrains.kotlin.gradle.logging.kotlinInfo import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService import org.jetbrains.kotlin.gradle.utils.ArchiveOperationsCompat -import org.jetbrains.kotlin.gradle.utils.FileSystemOperationsCompat import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics import java.io.File import java.net.URI +import javax.inject.Inject @CacheableTask -open class NodeJsSetupTask : DefaultTask() { +abstract class NodeJsSetupTask : DefaultTask() { @Transient private val settings = NodeJsRootPlugin.apply(project.rootProject) private val env by lazy { settings.requireConfigured() } - private val fs = FileSystemOperationsCompat(project) private val archiveOperations = ArchiveOperationsCompat(project) private val shouldDownload = settings.download + @get:Inject + internal open val fs: FileSystemOperations + get() = error("Should be injected") + val ivyDependency: String @Input get() = env.ivyDependency diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/TasksRequirements.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/TasksRequirements.kt index ef303010425..3e6cd45620c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/TasksRequirements.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/TasksRequirements.kt @@ -10,8 +10,9 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependencyDeclaration import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies import org.jetbrains.kotlin.gradle.targets.js.npm.toDeclaration +import java.io.Serializable -class TasksRequirements { +class TasksRequirements : Serializable { private val _byTask = mutableMapOf>() private val byCompilation = mutableMapOf>() diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/AbstractNodeModulesCache.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/AbstractNodeModulesCache.kt index 3fdeb996234..83ee6c7201f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/AbstractNodeModulesCache.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/AbstractNodeModulesCache.kt @@ -6,25 +6,29 @@ package org.jetbrains.kotlin.gradle.targets.js.npm import com.google.gson.GsonBuilder -import org.gradle.api.internal.project.ProjectInternal -import org.gradle.internal.hash.FileHasher +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.invocation.Gradle +import org.gradle.api.services.BuildService +import org.gradle.api.services.BuildServiceParameters import org.jetbrains.kotlin.gradle.internal.ProcessedFilesCache -import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension import java.io.File /** * Cache for storing already created [GradleNodeModule]s */ -internal abstract class AbstractNodeModulesCache(nodeJs: NodeJsRootExtension) : AutoCloseable { +internal abstract class AbstractNodeModulesCache : AutoCloseable, BuildService { + internal interface Parameters : BuildServiceParameters { + val rootProjectDir: DirectoryProperty + val cacheDir: DirectoryProperty + } + companion object { const val STATE_FILE_NAME = ".visited" } - internal val dir = nodeJs.nodeModulesGradleCacheDir private val cache = ProcessedFilesCache( - nodeJs.rootProject.logger, - nodeJs.rootProject.projectDir, - dir, + parameters.rootProjectDir.get().asFile, + parameters.cacheDir.get().asFile, STATE_FILE_NAME, "9" ) @@ -52,8 +56,6 @@ internal abstract class AbstractNodeModulesCache(nodeJs: NodeJsRootExtension) : } } -// Synchronized as tasks from configuration cache run in parallel and every task has it's own modules cache -@Synchronized fun makeNodeModule( container: File, packageJson: PackageJson, diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/CompositeNodeModulesCache.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/CompositeNodeModulesCache.kt index e03b844b2c6..93960bfc0d0 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/CompositeNodeModulesCache.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/CompositeNodeModulesCache.kt @@ -5,19 +5,20 @@ package org.jetbrains.kotlin.gradle.targets.js.npm +import org.gradle.api.provider.Provider import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension import java.io.File /** * Cache for storing already created [GradleNodeModule]s */ -internal class CompositeNodeModulesCache(nodeJs: NodeJsRootExtension) : AbstractNodeModulesCache(nodeJs) { +internal abstract class CompositeNodeModulesCache : AbstractNodeModulesCache() { override fun buildImportedPackage( name: String, version: String, file: File ): File? { - val module = CompositeNodeModuleBuilder(file, dir) + val module = CompositeNodeModuleBuilder(file, parameters.cacheDir.get().asFile) return module.rebuild() } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModule.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModule.kt index a9ef64bd18b..b38cce8bcee 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModule.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModule.kt @@ -6,11 +6,12 @@ package org.jetbrains.kotlin.gradle.targets.js.npm import java.io.File +import java.io.Serializable /** * Fake NodeJS module directory created from Gradle external module */ -data class GradleNodeModule(val name: String, val version: String, val path: File) { +data class GradleNodeModule(val name: String, val version: String, val path: File) : Serializable { val semver: SemVer get() = SemVer.from(version) } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModuleBuilder.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModuleBuilder.kt index 2f7d458f9c7..c06e14d05c2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModuleBuilder.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModuleBuilder.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.gradle.targets.js.npm -import org.gradle.api.Project import org.jetbrains.kotlin.gradle.targets.js.JS import org.jetbrains.kotlin.gradle.targets.js.JS_MAP import org.jetbrains.kotlin.gradle.targets.js.META_JS 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 4ff5713ac95..949fd5fd237 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 @@ -5,27 +5,32 @@ package org.jetbrains.kotlin.gradle.targets.js.npm -import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension +import org.gradle.api.file.FileSystemOperations import org.jetbrains.kotlin.gradle.utils.ArchiveOperationsCompat import org.jetbrains.kotlin.gradle.utils.FileSystemOperationsCompat import java.io.File +import javax.inject.Inject /** * Cache for storing already created [GradleNodeModule]s */ -internal class GradleNodeModulesCache(nodeJs: NodeJsRootExtension) : AbstractNodeModulesCache(nodeJs) { - @Transient - private val project = nodeJs.rootProject +internal abstract class GradleNodeModulesCache : AbstractNodeModulesCache() { - private val fs = FileSystemOperationsCompat(project) - private val archiveOperations = ArchiveOperationsCompat(project) + // TODO: replace by injected service org.gradle.api.file.FileSystemOperations once min support Gradle is 6.2 + // https://github.com/gradle/gradle/commit/d02b9d84c08dba64775fb9581e3280f88d319a21 + @Transient + lateinit var fs: FileSystemOperationsCompat + + // TODO: replace by injected service org.gradle.api.file.ArchiveOperations once min supported Gradle is 6.6 + @Transient + lateinit var archiveOperations: ArchiveOperationsCompat override fun buildImportedPackage( name: String, version: String, file: File ): File? { - val module = GradleNodeModuleBuilder(fs, archiveOperations, name, version, listOf(file), dir) + val module = GradleNodeModuleBuilder(fs, archiveOperations, name, version, listOf(file), parameters.cacheDir.get().asFile) module.visitArtifacts() return module.rebuild() } 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 017742a38cb..9f9b4fad5cd 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 @@ -10,6 +10,8 @@ import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.internal.project.ProjectInternal import org.gradle.api.logging.Logger +import org.gradle.api.services.BuildService +import org.gradle.api.services.BuildServiceParameters import org.gradle.internal.service.ServiceRegistry import org.jetbrains.kotlin.gradle.internal.isInIdeaSync import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension @@ -85,9 +87,22 @@ class KotlinNpmResolutionManager(private val nodeJsSettings: NodeJsRootExtension internal val resolver = KotlinRootNpmResolver(nodeJsSettings, forceFullResolve) - @Volatile - private var state: ResolutionState = - ResolutionState.Configuring(resolver) + internal abstract class KotlinNpmResolutionManagerStateHolder : BuildService { + @Volatile + internal var state: ResolutionState? = null + } + + private val stateHolderProvider = nodeJsSettings.rootProject.gradle.sharedServices.registerIfAbsent( + "npm-resolution-manager-state-holder", KotlinNpmResolutionManagerStateHolder::class.java) { + } + + private val stateHolder get() = stateHolderProvider.get() + + private var state: ResolutionState + get() = stateHolder.state ?: ResolutionState.Configuring(resolver) + set(value) { + stateHolder.state = value + } internal sealed class ResolutionState { abstract val npmProjects: List @@ -139,7 +154,7 @@ class KotlinNpmResolutionManager(private val nodeJsSettings: NodeJsRootExtension services: ServiceRegistry, logger: Logger ): KotlinRootNpmResolution { - synchronized(this) { + synchronized(stateHolder) { if (state is ResolutionState.Installed) { return (state as ResolutionState.Installed).resolved } @@ -178,9 +193,11 @@ class KotlinNpmResolutionManager(private val nodeJsSettings: NodeJsRootExtension val state0 = this.state return when (state0) { - is ResolutionState.Prepared -> alreadyResolved(state0.preparedInstallation) + is ResolutionState.Prepared -> { + alreadyResolved(state0.preparedInstallation) + } is ResolutionState.Configuring -> { - synchronized(this) { + synchronized(stateHolder) { val state1 = this.state when (state1) { is ResolutionState.Prepared -> alreadyResolved(state1.preparedInstallation) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmDependencyDeclaration.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmDependencyDeclaration.kt index bfc64d2ed38..ed5486917d5 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmDependencyDeclaration.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmDependencyDeclaration.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.gradle.targets.js.npm import org.gradle.api.tasks.Input +import java.io.Serializable data class NpmDependencyDeclaration( @Input @@ -16,7 +17,7 @@ data class NpmDependencyDeclaration( val version: String, @Input val generateExternals: Boolean -) +) : Serializable fun NpmDependencyDeclaration.uniqueRepresentation() = "$scope $name:$version, $generateExternals" 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 ac66e7af6f2..b54e1738a4b 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 @@ -14,6 +14,7 @@ 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 java.io.File +import java.io.Serializable val KotlinJsCompilation.npmProject: NpmProject get() = NpmProject(this) @@ -24,7 +25,7 @@ val KotlinJsCompilation.npmProject: NpmProject * * More info can be obtained from [KotlinCompilationNpmResolution], which is available after project resolution (after [KotlinNpmInstallTask] execution). */ -open class NpmProject(@Transient val compilation: KotlinJsCompilation) { +open class NpmProject(@Transient val compilation: KotlinJsCompilation) : Serializable { val compilationName = compilation.disambiguatedName val name: String by lazy { @@ -59,6 +60,10 @@ open class NpmProject(@Transient val compilation: KotlinJsCompilation) { val packageJsonTask: KotlinPackageJsonTask get() = project.tasks.getByName(packageJsonTaskName) as KotlinPackageJsonTask + val packageJsonTaskPath by lazy { + packageJsonTask.path + } + val dist: File get() = dir.resolve(DIST_FOLDER) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectModules.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectModules.kt index 78bc6327118..ecae680eded 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectModules.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectModules.kt @@ -10,6 +10,7 @@ import com.google.gson.JsonObject import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject.Companion.NODE_MODULES import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject.Companion.PACKAGE_JSON import java.io.File +import java.io.Serializable /** * Search modules in node_modules according to https://nodejs.org/api/modules.html. @@ -19,7 +20,7 @@ open class NpmProjectModules( val packageJsonEntries: Collection = listOf("main", "module", "browser"), val indexFileNames: Collection = listOf(INDEX_FILE_NAME), val indexFileSuffixes: Collection = listOf(JS_SUFFIX) -) { +) : Serializable { /** * Require [request] nodejs module and return canonical path to it's main js file. */ diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/PackageJson.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/PackageJson.kt index f87c2bc2aad..89b5ccca396 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/PackageJson.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/PackageJson.kt @@ -13,12 +13,13 @@ import org.gradle.api.GradleException import org.gradle.api.tasks.Input import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated import java.io.File +import java.io.Serializable // Gson set nulls reflectively no matter on default values and non-null types class PackageJson( var name: String, var version: String -) { +) : Serializable { internal val customFields = mutableMapOf() val empty: Boolean diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/plugins/CompilationResolverPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/plugins/CompilationResolverPlugin.kt index c1ba9e0f77b..6566a3612e7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/plugins/CompilationResolverPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/plugins/CompilationResolverPlugin.kt @@ -7,10 +7,11 @@ package org.jetbrains.kotlin.gradle.targets.js.npm.plugins import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinCompilationNpmResolver +import java.io.Serializable -internal interface CompilationResolverPlugin { +internal interface CompilationResolverPlugin : Serializable { fun hookDependencies( - internalDependencies: Set, + internalDependencies: Set, internalCompositeDependencies: Set, externalGradleDependencies: Set, externalNpmDependencies: Set, diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/plugins/RootResolverPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/plugins/RootResolverPlugin.kt index 23ea745f691..1926a599194 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/plugins/RootResolverPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/plugins/RootResolverPlugin.kt @@ -7,8 +7,9 @@ package org.jetbrains.kotlin.gradle.targets.js.npm.plugins import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinRootNpmResolution import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinCompilationNpmResolver +import java.io.Serializable -internal interface RootResolverPlugin { +internal interface RootResolverPlugin : Serializable { fun createCompilationResolverPlugins(resolver: KotlinCompilationNpmResolver): List fun close(resolution: KotlinRootNpmResolution) } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolved/KotlinCompilationNpmResolution.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolved/KotlinCompilationNpmResolution.kt index 8dad68be62e..79809bc2dc8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolved/KotlinCompilationNpmResolution.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolved/KotlinCompilationNpmResolution.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.targets.js.npm.resolved import org.gradle.api.Project import org.jetbrains.kotlin.gradle.targets.js.npm.* +import java.io.Serializable /** * Resolved [NpmProject] @@ -19,7 +20,7 @@ class KotlinCompilationNpmResolution( val externalGradleDependencies: Collection, private val _externalNpmDependencies: Collection, val packageJson: PackageJson -) { +) : Serializable { val project get() = _project!! 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 9e593933f1f..90cea197919 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 @@ -5,20 +5,12 @@ package org.jetbrains.kotlin.gradle.targets.js.npm.resolver -import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.FileCollectionDependency -import org.gradle.api.artifacts.ResolvedArtifact -import org.gradle.api.artifacts.ResolvedDependency +import org.gradle.api.artifacts.* import org.gradle.api.artifacts.component.ProjectComponentIdentifier import org.gradle.api.attributes.Usage -import org.gradle.api.file.FileCollection import org.gradle.api.initialization.IncludedBuild import org.gradle.api.internal.artifacts.DefaultProjectComponentIdentifier -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputFiles -import org.gradle.api.tasks.PathSensitive -import org.gradle.api.tasks.PathSensitivity -import org.gradle.api.tasks.TaskProvider +import org.gradle.api.tasks.* import org.gradle.api.tasks.bundling.Zip import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation @@ -38,10 +30,8 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinPackageJsonTask 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.getValue import org.jetbrains.kotlin.gradle.utils.topRealPath -import java.io.File -import java.io.Serializable +import java.io.* /** * See [KotlinNpmResolutionManager] for details about resolution process. @@ -51,49 +41,27 @@ internal class KotlinCompilationNpmResolver( val projectResolver: KotlinProjectNpmResolver, @Transient val compilation: KotlinJsCompilation -) { +) : Serializable { @Transient - val resolver = projectResolver.resolver - - private val gradleNodeModules by lazy { - resolver.gradleNodeModules - } - - private val compositeNodeModules by lazy { - resolver.compositeNodeModules - } + var rootResolver = projectResolver.resolver val npmProject = compilation.npmProject val compilationDisambiguatedName = compilation.disambiguatedName - val npmName by lazy { - npmProject.name - } - val npmVersion by lazy { project.version.toString() } - val npmMain by lazy { - npmProject.main - } - - val prePackageJsonFile by lazy { - npmProject.prePackageJsonFile - } - - val nodeJs get() = resolver.nodeJs - - val taskRequirements by lazy { - nodeJs.taskRequirements - } + val nodeJs get() = rootResolver.nodeJs val target get() = compilation.target val project get() = target.project - private val packageJsonHandlers by project.provider { + val projectPath = project.path + + val packageJsonHandlers by lazy { compilation.packageJsonHandlers } @@ -132,16 +100,24 @@ internal class KotlinCompilationNpmResolver( override fun toString(): String = "KotlinCompilationNpmResolver(${npmProject.name})" + @delegate:Transient private val aggregatedConfiguration: Configuration by lazy { createAggregatedConfiguration() } - val packageJsonProducer: PackageJsonProducer by lazy { + private val packageJsonProducer_: PackageJsonProducer by lazy { val visitor = ConfigurationVisitor() visitor.visit(aggregatedConfiguration) - visitor.toPackageJsonProducer() + visitor.toPackageJsonProducer().also { it.compilationResolver = this } } + val packageJsonProducer: PackageJsonProducer + get() { + val packageJsonProducer = packageJsonProducer_ + packageJsonProducer.compilationResolver = this + return packageJsonProducer + } + private var closed = false private var resolution: KotlinCompilationNpmResolution? = null @@ -159,7 +135,7 @@ internal class KotlinCompilationNpmResolver( fun getResolutionOrResolveIfForced(): KotlinCompilationNpmResolution? { if (resolution != null) return resolution if (packageJsonTaskHolder == null || packageJsonTaskHolder.get().state.upToDate) return resolve(skipWriting = true) - if (resolver.forceFullResolve && resolution == null) { + if (rootResolver.forceFullResolve && resolution == null) { // need to force all NPM tasks to be configured in IDEA import project.tasks.implementing(RequiresNpmDependencies::class).all {} return resolve() @@ -216,26 +192,35 @@ internal class KotlinCompilationNpmResolver( data class ExternalGradleDependency( val dependency: ResolvedDependency, val artifact: ResolvedArtifact - ) + ): Serializable data class FileCollectionExternalGradleDependency( - val fileCollection: FileCollection, + val files: Collection, val dependencyVersion: String? - ) + ): Serializable data class FileExternalGradleDependency( val dependencyName: String, val dependencyVersion: String, val file: File - ) + ) : Serializable data class CompositeDependency( - val dependency: ResolvedDependency, - val includedBuild: IncludedBuild - ) + val dependencyName: String, + val dependencyVersion: String, + val includedBuildDir: File, + @Transient + val includedBuild: IncludedBuild? + ) : Serializable + + data class InternalDependency( + val projectPath: String, + val compilationName: String, + val projectName: String + ) : Serializable inner class ConfigurationVisitor { - private val internalDependencies = mutableSetOf() + private val internalDependencies = mutableSetOf() private val internalCompositeDependencies = mutableSetOf() private val externalGradleDependencies = mutableSetOf() private val externalNpmDependencies = mutableSetOf() @@ -249,14 +234,14 @@ internal class KotlinCompilationNpmResolver( configuration.allDependencies.forEach { dependency -> when (dependency) { is NpmDependency -> externalNpmDependencies.add(dependency) - is FileCollectionDependency -> fileCollectionDependencies.add(FileCollectionExternalGradleDependency(dependency.files, dependency.version)) + is FileCollectionDependency -> fileCollectionDependencies.add(FileCollectionExternalGradleDependency(dependency.files.files, dependency.version)) } } //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]) + internalDependencies.add(InternalDependency(projectResolver.project.path, main.disambiguatedName, projectResolver[main].npmProject.name)) } val hasPublicNpmDependencies = externalNpmDependencies.isNotEmpty() @@ -332,7 +317,9 @@ internal class KotlinCompilationNpmResolver( (componentIdentifier as DefaultProjectComponentIdentifier).let { identifier -> val includedBuild = project.gradle.includedBuild(identifier.identityPath.topRealPath().name!!) - internalCompositeDependencies.add(CompositeDependency(dependency, includedBuild)) + internalCompositeDependencies.add( + CompositeDependency(dependency.moduleName, dependency.moduleVersion, includedBuild.projectDir, includedBuild) + ) } } @@ -342,17 +329,23 @@ internal class KotlinCompilationNpmResolver( val dependentProject = project.findProject(componentIdentifier.projectPath) ?: error("Cannot find project ${componentIdentifier.projectPath}") - resolver.findDependentResolver(project, dependentProject) + rootResolver.findDependentResolver(project, dependentProject) ?.forEach { dependentResolver -> - internalDependencies.add(dependentResolver) + internalDependencies.add(InternalDependency(dependentResolver.projectPath, dependentResolver.compilationDisambiguatedName, dependentResolver.npmProject.name)) } } fun toPackageJsonProducer() = PackageJsonProducer( internalDependencies, internalCompositeDependencies, - externalGradleDependencies, - externalNpmDependencies, + externalGradleDependencies.map { + FileExternalGradleDependency( + it.dependency.moduleName, + it.dependency.moduleVersion, + it.artifact.file + ) + }, + externalNpmDependencies.map { it.toDeclaration() }, fileCollectionDependencies ) } @@ -374,56 +367,44 @@ internal class KotlinCompilationNpmResolver( @get:Input val fileCollectionDependencies: Collection - ) : Serializable + ) @Suppress("MemberVisibilityCanBePrivate") - inner class PackageJsonProducer( - val internalDependencies: Collection, - val internalCompositeDependencies: Collection, - @Transient - val externalGradleDependencies: Collection, - @Transient - val externalNpmDependencies: Collection, - val fileCollectionDependencies: Collection - ) { - val externalNpmDependencyDeclarations by lazy { - externalNpmDependencies.map { - it.toDeclaration() - } - } + class PackageJsonProducer( + var internalDependencies: Collection, + var internalCompositeDependencies: Collection, + var externalGradleDependencies: Collection, + var externalNpmDependencies: Collection, + var fileCollectionDependencies: Collection + ) : Serializable { + private val projectPackagesDir by lazy { compilationResolver.nodeJs.projectPackagesDir } + private val rootDir by lazy { compilationResolver.nodeJs.rootProject.rootDir } - val fileExternalGradleDependencies by lazy { - externalGradleDependencies.map { - FileExternalGradleDependency( - it.dependency.moduleName, - it.dependency.moduleVersion, - it.artifact.file - ) - } - } + @Transient + internal lateinit var compilationResolver: KotlinCompilationNpmResolver val inputs: PackageJsonProducerInputs get() = PackageJsonProducerInputs( - internalDependencies.map { it.npmProject.name }, + internalDependencies.map { it.projectName }, internalCompositeDependencies.flatMap { it.getPackages() }, - fileExternalGradleDependencies.map { it.file }, - externalNpmDependencyDeclarations.map { it.uniqueRepresentation() }, - fileCollectionDependencies.map{ it.fileCollection }.flatMap { it.files } + externalGradleDependencies.map { it.file }, + externalNpmDependencies.map { it.uniqueRepresentation() }, + fileCollectionDependencies.flatMap{ it.files } ) fun createPackageJson(skipWriting: Boolean): KotlinCompilationNpmResolution { val resolvedInternalDependencies = internalDependencies.map { - it.getResolutionOrResolveIfForced() - ?: error("Unresolved dependent npm package: ${this@KotlinCompilationNpmResolver} -> $it") + compilationResolver.rootResolver[it.projectPath][it.compilationName].getResolutionOrResolveIfForced() + ?: error("Unresolved dependent npm package: ${compilationResolver} -> $it") } - val importedExternalGradleDependencies = fileExternalGradleDependencies.mapNotNull { - gradleNodeModules.get(it.dependencyName, it.dependencyVersion, it.file) + val importedExternalGradleDependencies = externalGradleDependencies.mapNotNull { + compilationResolver.rootResolver.gradleNodeModules.get(it.dependencyName, it.dependencyVersion, it.file) } + fileCollectionDependencies.flatMap { dependency -> - dependency.fileCollection.files + dependency.files // Gradle can hash with FileHasher only files and only existed files .filter { it.isFile } .map { file -> - gradleNodeModules.get( + compilationResolver.rootResolver.gradleNodeModules.get( file.name, dependency.dependencyVersion ?: "0.0.1", file @@ -434,26 +415,26 @@ internal class KotlinCompilationNpmResolver( val compositeDependencies = internalCompositeDependencies.flatMap { dependency -> dependency.getPackages() .map { file -> - compositeNodeModules.get( - dependency.dependency.moduleName, - dependency.dependency.moduleVersion, + compilationResolver.rootResolver.compositeNodeModules.get( + dependency.dependencyName, + dependency.dependencyVersion, file ) } } .filterNotNull() - val toolsNpmDependencies = taskRequirements - .getCompilationNpmRequirements(compilationDisambiguatedName) + val toolsNpmDependencies = compilationResolver.rootResolver.nodeJs.taskRequirements + .getCompilationNpmRequirements(compilationResolver.compilationDisambiguatedName) - val allNpmDependencies = externalNpmDependencyDeclarations + toolsNpmDependencies + val allNpmDependencies = externalNpmDependencies + toolsNpmDependencies val packageJson = packageJson( - npmName, - npmVersion, - npmMain, + compilationResolver.npmProject.name, + compilationResolver.npmVersion, + compilationResolver.npmProject.main, allNpmDependencies, - packageJsonHandlers + compilationResolver.packageJsonHandlers ) compositeDependencies.forEach { @@ -468,17 +449,18 @@ internal class KotlinCompilationNpmResolver( packageJson.dependencies[it.name] = fileVersion(it.path) } - packageJsonHandlers.forEach { + compilationResolver.packageJsonHandlers.forEach { it(packageJson) } if (!skipWriting) { - packageJson.saveTo(prePackageJsonFile) + packageJson.saveTo(compilationResolver.npmProject.prePackageJsonFile) } return KotlinCompilationNpmResolution( - if (compilation != null) project else null, - npmProject, + @Suppress("SENSELESS_COMPARISON") + if (compilationResolver.compilation != null) compilationResolver.project else null, + compilationResolver.npmProject, compositeDependencies, importedExternalGradleDependencies, allNpmDependencies, @@ -487,9 +469,7 @@ internal class KotlinCompilationNpmResolver( } private fun CompositeDependency.getPackages(): List { - val packages = includedBuild - .projectDir - .resolve(nodeJs.projectPackagesDir.relativeTo(nodeJs.rootProject.rootDir)) + val packages = includedBuildDir.resolve(projectPackagesDir.relativeTo(rootDir)) return packages .list() ?.map { packages.resolve(it) } 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 d4dcfe2f532..4156f82259f 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 java.io.Serializable import kotlin.reflect.KClass /** @@ -27,8 +28,9 @@ import kotlin.reflect.KClass internal class KotlinProjectNpmResolver( @Transient val project: Project, - val resolver: KotlinRootNpmResolver -) { + @Transient + var resolver: KotlinRootNpmResolver +) : Serializable { override fun toString(): String = "ProjectNpmResolver($project)" private val projectPath by lazy { project.path } 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 27a35745130..d1bd34c00f3 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 @@ -7,12 +7,14 @@ package org.jetbrains.kotlin.gradle.targets.js.npm.resolver import org.gradle.api.Project import org.gradle.api.logging.Logger +import org.gradle.api.provider.Provider import org.gradle.internal.service.ServiceRegistry import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation 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.nodejs.TasksRequirements 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 @@ -23,6 +25,8 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinProjectNpmResol import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinRootNpmResolution import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin import org.jetbrains.kotlin.gradle.targets.js.yarn.toVersionString +import org.jetbrains.kotlin.gradle.utils.ArchiveOperationsCompat +import org.jetbrains.kotlin.gradle.utils.FileSystemOperationsCompat /** * See [KotlinNpmResolutionManager] for details about resolution process. @@ -42,22 +46,90 @@ internal class KotlinRootNpmResolver internal constructor( rootProject.version.toString() } - val plugins = mutableListOf().also { - it.add(DukatRootResolverPlugin(this)) - } - enum class State { CONFIGURING, PROJECTS_CLOSED, INSTALLED } + @Transient @Volatile - private var state: State = State.CONFIGURING + private var state_: State? = State.CONFIGURING - val gradleNodeModules = GradleNodeModulesCache(nodeJs) - val compositeNodeModules = CompositeNodeModulesCache(nodeJs) - val projectResolvers = mutableMapOf() + private var state + get() = state_ ?: resolverStateHolder.get().state + set(value) { + if (state_ != null) { + state_ = value + } else { + resolverStateHolder.get().state = value + } + } + + private val archiveOperations by lazy { ArchiveOperationsCompat(rootProject) } + private val fs by lazy { FileSystemOperationsCompat(rootProject) } + + private 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) + } + + val gradleNodeModules: GradleNodeModulesCache + get() = gradleNodeModulesProvider.get().also { + it.archiveOperations = archiveOperations + it.fs = fs + } + + private 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) + } + + 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() + + private val resolverStateHolder by lazy { + rootProject.gradle.sharedServices.registerIfAbsent( + KotlinRootNpmResolverStateHolder::class.qualifiedName, + KotlinRootNpmResolverStateHolder::class.java + ) { + it.parameters.plugins.set(plugins_) + it.parameters.projectResolvers.set(projectResolvers_) + } + } + + private val configurationCacheProjectResolvers: MutableMap + get() { + val stateHolder = resolverStateHolder.get() + val projResolvers = stateHolder.parameters.projectResolvers.get() + if (stateHolder.initialized) return projResolvers + projResolvers.forEach { (_, value) -> + value.resolver = this + value.compilationResolvers.forEach { compResolver -> + compResolver.rootResolver = this + } + } + stateHolder.initialized = true + return projResolvers + } + + val plugins + get() = plugins_ ?: resolverStateHolder.get().parameters.plugins.get() + + val projectResolvers + get() = projectResolvers_ ?: configurationCacheProjectResolvers val yarn by lazy { YarnPlugin.apply(rootProject) @@ -120,6 +192,7 @@ internal class KotlinRootNpmResolver internal constructor( val allNpmPackages = projectResolutions.values.flatMap { it.npmProjects } gradleNodeModules.close() + compositeNodeModules.close() nodeJs.packageManager.prepareRootProject( rootProject, 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 new file mode 100644 index 00000000000..94780b14ba9 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinRootNpmResolverStateHolder.kt @@ -0,0 +1,28 @@ +/* + * 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.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.plugins.RootResolverPlugin + +// 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 + } + + var initialized = false + + @Volatile + var state = KotlinRootNpmResolver.State.CONFIGURING +} \ 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 d55f2abd36b..f23cf941819 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 @@ -59,10 +59,10 @@ open class KotlinPackageJsonTask : DefaultTask() { } private fun findDependentTasks(): Collection = - producer.internalDependencies.map { dependentResolver -> - dependentResolver.npmProject.packageJsonTask + producer.internalDependencies.map { dependency -> + npmResolutionManager.resolver[dependency.projectPath][dependency.compilationName].npmProject.packageJsonTaskPath } + producer.internalCompositeDependencies.map { dependency -> - dependency.includedBuild.task(":$PACKAGE_JSON_UMBRELLA_TASK_NAME") + dependency.includedBuild?.task(":$PACKAGE_JSON_UMBRELLA_TASK_NAME") ?: "includedBuild instance is not available" } @get:Input diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/compatibiltiy.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/compatibiltiy.kt index 9059622111e..27689d12896 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/compatibiltiy.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/compatibiltiy.kt @@ -32,6 +32,7 @@ import org.gradle.api.tasks.bundling.AbstractArchiveTask import org.gradle.api.tasks.testing.TestDescriptor import org.gradle.util.GradleVersion import java.io.File +import java.io.Serializable const val minSupportedGradleVersion = "6.1" @@ -75,7 +76,7 @@ internal fun checkGradleCompatibility( internal val AbstractArchiveTask.archivePathCompatible: File get() = archiveFile.get().asFile -internal class ArchiveOperationsCompat(@Transient private val project: Project) { +internal class ArchiveOperationsCompat(@Transient private val project: Project) : Serializable { private val archiveOperations: Any? = try { (project as ProjectInternal).services.get(ArchiveOperations::class.java) } catch (e: NoClassDefFoundError) { @@ -98,7 +99,7 @@ internal class ArchiveOperationsCompat(@Transient private val project: Project) } } -internal class FileSystemOperationsCompat(@Transient private val project: Project) { +internal class FileSystemOperationsCompat(@Transient private val project: Project) : Serializable { private val fileSystemOperations: Any? = try { (project as ProjectInternal).services.get(FileSystemOperations::class.java) } catch (e: NoClassDefFoundError) { @@ -124,4 +125,4 @@ internal interface LegacyTestDescriptorInternal : TestDescriptor { fun getOwnerBuildOperationId(): Any? fun getClassDisplayName(): String? -} \ No newline at end of file +}