[Gradle, JS] Experimenting with making everything transient in npm

This commit is contained in:
Ilya Goncharov
2020-10-15 20:29:42 +03:00
committed by Alexander Likhachev
parent cc51869a2a
commit 19e59fe770
6 changed files with 47 additions and 11 deletions
@@ -7,9 +7,11 @@ package org.jetbrains.kotlin.gradle.targets.js.nodejs
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.plugins.BasePlugin import org.gradle.api.plugins.BasePlugin
import org.jetbrains.kotlin.gradle.targets.js.MultiplePluginDeclarationDetector import org.jetbrains.kotlin.gradle.targets.js.MultiplePluginDeclarationDetector
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension.Companion.EXTENSION_NAME import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension.Companion.EXTENSION_NAME
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.PACKAGE_JSON_UMBRELLA_TASK_NAME
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin
import org.jetbrains.kotlin.gradle.tasks.CleanDataTask import org.jetbrains.kotlin.gradle.tasks.CleanDataTask
@@ -34,7 +36,7 @@ open class NodeJsRootPlugin : Plugin<Project> {
val rootClean = project.rootProject.tasks.named(BasePlugin.CLEAN_TASK_NAME) val rootClean = project.rootProject.tasks.named(BasePlugin.CLEAN_TASK_NAME)
tasks.register(KotlinNpmInstallTask.NAME, KotlinNpmInstallTask::class.java) { registerTask<KotlinNpmInstallTask>(KotlinNpmInstallTask.NAME) {
it.dependsOn(setupTask) it.dependsOn(setupTask)
it.group = TASKS_GROUP_NAME it.group = TASKS_GROUP_NAME
it.description = "Find, download and link NPM dependencies and projects" it.description = "Find, download and link NPM dependencies and projects"
@@ -42,6 +44,8 @@ open class NodeJsRootPlugin : Plugin<Project> {
it.mustRunAfter(rootClean) it.mustRunAfter(rootClean)
} }
registerTask<Task>(PACKAGE_JSON_UMBRELLA_TASK_NAME)
YarnPlugin.apply(project) YarnPlugin.apply(project)
tasks.register("node" + CleanDataTask.NAME_SUFFIX, CleanDataTask::class.java) { tasks.register("node" + CleanDataTask.NAME_SUFFIX, CleanDataTask::class.java) {
@@ -15,7 +15,9 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson
* Resolved [NpmProject] * Resolved [NpmProject]
*/ */
class KotlinCompilationNpmResolution( class KotlinCompilationNpmResolution(
@Transient
val project: Project, val project: Project,
@Transient
val npmProject: NpmProject, val npmProject: NpmProject,
val internalDependencies: Collection<KotlinCompilationNpmResolution>, val internalDependencies: Collection<KotlinCompilationNpmResolution>,
val internalCompositeDependencies: Collection<GradleNodeModule>, val internalCompositeDependencies: Collection<GradleNodeModule>,
@@ -43,16 +43,27 @@ import java.io.Serializable
* See [KotlinNpmResolutionManager] for details about resolution process. * See [KotlinNpmResolutionManager] for details about resolution process.
*/ */
internal class KotlinCompilationNpmResolver( internal class KotlinCompilationNpmResolver(
@Transient
val projectResolver: KotlinProjectNpmResolver, val projectResolver: KotlinProjectNpmResolver,
@Transient
val compilation: KotlinJsCompilation val compilation: KotlinJsCompilation
) { ) {
@Transient
val resolver = projectResolver.resolver val resolver = projectResolver.resolver
@Transient
val npmProject = compilation.npmProject val npmProject = compilation.npmProject
val nodeJs get() = resolver.nodeJs val nodeJs get() = resolver.nodeJs
val target get() = compilation.target val target get() = compilation.target
val project get() = target.project val project get() = target.project
@Transient
val packageJsonTaskHolder = KotlinPackageJsonTask.create(compilation) val packageJsonTaskHolder = KotlinPackageJsonTask.create(compilation)
@Transient
val publicPackageJsonTaskHolder: TaskProvider<PublicPackageJsonTask> = val publicPackageJsonTaskHolder: TaskProvider<PublicPackageJsonTask> =
project.registerTask<PublicPackageJsonTask>( project.registerTask<PublicPackageJsonTask>(
npmProject.publicPackageJsonTaskName, npmProject.publicPackageJsonTaskName,
@@ -71,6 +82,7 @@ internal class KotlinCompilationNpmResolver(
} }
} }
@Transient
val plugins: List<CompilationResolverPlugin> = projectResolver.resolver.plugins val plugins: List<CompilationResolverPlugin> = projectResolver.resolver.plugins
.flatMap { .flatMap {
if (compilation.isMain()) { if (compilation.isMain()) {
@@ -168,6 +180,12 @@ internal class KotlinCompilationNpmResolver(
val artifact: ResolvedArtifact val artifact: ResolvedArtifact
) )
data class FileExternalGradleDependency(
val dependencyName: String,
val dependencyVersion: String,
val file: File
)
data class CompositeDependency( data class CompositeDependency(
val dependency: ResolvedDependency, val dependency: ResolvedDependency,
val includedBuild: IncludedBuild val includedBuild: IncludedBuild
@@ -317,15 +335,26 @@ internal class KotlinCompilationNpmResolver(
inner class PackageJsonProducer( inner class PackageJsonProducer(
val internalDependencies: Collection<KotlinCompilationNpmResolver>, val internalDependencies: Collection<KotlinCompilationNpmResolver>,
val internalCompositeDependencies: Collection<CompositeDependency>, val internalCompositeDependencies: Collection<CompositeDependency>,
@Transient
val externalGradleDependencies: Collection<ExternalGradleDependency>, val externalGradleDependencies: Collection<ExternalGradleDependency>,
val externalNpmDependencies: Collection<NpmDependency>, val externalNpmDependencies: Collection<NpmDependency>,
val fileCollectionDependencies: Collection<FileCollectionDependency> val fileCollectionDependencies: Collection<FileCollectionDependency>
) { ) {
val fileExternalGradleDependencies by lazy {
externalGradleDependencies.map {
FileExternalGradleDependency(
it.dependency.moduleName,
it.dependency.moduleVersion,
it.artifact.file
)
}
}
val inputs: PackageJsonProducerInputs val inputs: PackageJsonProducerInputs
get() = PackageJsonProducerInputs( get() = PackageJsonProducerInputs(
internalDependencies.map { it.npmProject.name }, internalDependencies.map { it.npmProject.name },
internalCompositeDependencies.flatMap { it.getPackages() }, internalCompositeDependencies.flatMap { it.getPackages() },
externalGradleDependencies.map { it.artifact.file }, fileExternalGradleDependencies.map { it.file },
externalNpmDependencies.map { it.uniqueRepresentation() }, externalNpmDependencies.map { it.uniqueRepresentation() },
fileCollectionDependencies.map { it.files }.flatMap { it.files } fileCollectionDependencies.map { it.files }.flatMap { it.files }
) )
@@ -335,8 +364,8 @@ internal class KotlinCompilationNpmResolver(
it.getResolutionOrResolveIfForced() it.getResolutionOrResolveIfForced()
?: error("Unresolved dependent npm package: ${this@KotlinCompilationNpmResolver} -> $it") ?: error("Unresolved dependent npm package: ${this@KotlinCompilationNpmResolver} -> $it")
} }
val importedExternalGradleDependencies = externalGradleDependencies.mapNotNull { val importedExternalGradleDependencies = fileExternalGradleDependencies.mapNotNull {
resolver.gradleNodeModules.get(it.dependency.moduleName, it.dependency.moduleVersion, it.artifact.file) resolver.gradleNodeModules.get(it.dependencyName, it.dependencyVersion, it.file)
} + fileCollectionDependencies.flatMap { dependency -> } + fileCollectionDependencies.flatMap { dependency ->
dependency.files dependency.files
// Gradle can hash with FileHasher only files and only existed files // Gradle can hash with FileHasher only files and only existed files
@@ -45,7 +45,6 @@ internal class KotlinProjectNpmResolver(
init { init {
addContainerListeners() addContainerListeners()
project.whenEvaluated { project.whenEvaluated {
val nodeJs = resolver.nodeJs val nodeJs = resolver.nodeJs
project.tasks.implementing(RequiresNpmDependencies::class) project.tasks.implementing(RequiresNpmDependencies::class)
@@ -49,25 +49,24 @@ internal class KotlinRootNpmResolver internal constructor(
val gradleNodeModules = GradleNodeModulesCache(nodeJs) val gradleNodeModules = GradleNodeModulesCache(nodeJs)
val compositeNodeModules = CompositeNodeModulesCache(nodeJs) val compositeNodeModules = CompositeNodeModulesCache(nodeJs)
val packageJsonUmbrella = rootProject.registerTask(PACKAGE_JSON_UMBRELLA_TASK_NAME, Task::class.java) {} val projectResolvers = mutableMapOf<String, KotlinProjectNpmResolver>()
val projectResolvers = mutableMapOf<Project, KotlinProjectNpmResolver>()
fun alreadyResolvedMessage(action: String) = "Cannot $action. NodeJS projects already resolved." fun alreadyResolvedMessage(action: String) = "Cannot $action. NodeJS projects already resolved."
@Synchronized @Synchronized
fun addProject(target: Project) { fun addProject(target: Project) {
check(state == State.CONFIGURING) { alreadyResolvedMessage("add new project: $target") } check(state == State.CONFIGURING) { alreadyResolvedMessage("add new project: $target") }
projectResolvers[target] = KotlinProjectNpmResolver(target, this) projectResolvers[target.path] = KotlinProjectNpmResolver(target, this)
} }
operator fun get(project: Project) = projectResolvers[project] ?: error("$project is not configured for JS usage") operator fun get(projectPath: String) = projectResolvers[projectPath] ?: error("$projectPath is not configured for JS usage")
val compilations: Collection<KotlinJsCompilation> val compilations: Collection<KotlinJsCompilation>
get() = projectResolvers.values.flatMap { it.compilationResolvers.map { it.compilation } } get() = projectResolvers.values.flatMap { it.compilationResolvers.map { it.compilation } }
fun findDependentResolver(src: Project, target: Project): List<KotlinCompilationNpmResolver>? { fun findDependentResolver(src: Project, target: Project): List<KotlinCompilationNpmResolver>? {
// todo: proper finding using KotlinTargetComponent.findUsageContext // todo: proper finding using KotlinTargetComponent.findUsageContext
val targetResolver = this[target] val targetResolver = this[target.path]
val mainCompilations = targetResolver.compilationResolvers.filter { it.compilation.isMain() } val mainCompilations = targetResolver.compilationResolvers.filter { it.compilation.isMain() }
return if (mainCompilations.isNotEmpty()) { return if (mainCompilations.isNotEmpty()) {
@@ -33,8 +33,11 @@ open class KotlinPackageJsonTask : DefaultTask() {
@Transient @Transient
private lateinit var compilation: KotlinJsCompilation private lateinit var compilation: KotlinJsCompilation
@Input
val projectPath = project.path
private val compilationResolver private val compilationResolver
get() = nodeJs.npmResolutionManager.resolver[project][compilation] get() = nodeJs.npmResolutionManager.resolver[projectPath][compilation]
private val producer: KotlinCompilationNpmResolver.PackageJsonProducer private val producer: KotlinCompilationNpmResolver.PackageJsonProducer
get() = compilationResolver.packageJsonProducer get() = compilationResolver.packageJsonProducer