From f4dcc18baf1a9a32a80f9ad2c9a0efe5815c9f16 Mon Sep 17 00:00:00 2001 From: Sergey Rostov Date: Tue, 2 Jul 2019 00:41:33 +0300 Subject: [PATCH] Gradle, JS: rework NpmResolver Now resolving works per compilation, so transitive dependency between compilations in same project can be resolved (KT-31917). Resolving gradle configurations now occurs in separate per-project `KotlinPackageJsonTask`s. Global install called in `KotlinNpmInstallTask`. Tasks inputs configured, so tasks now reported as UP-TO-DATE if nothing was changed. #KT-31565 Fixed #KT-32015 Fixed #KT-31917 Fixed --- .../targets/js/KotlinJsTargetConfigurator.kt | 16 +- .../gradle/targets/js/nodejs/NodeJsExec.kt | 2 +- .../gradle/targets/js/nodejs/NodeJsPlugin.kt | 4 +- .../targets/js/nodejs/NodeJsRootExtension.kt | 6 +- .../targets/js/npm/GradleNodeModulesCache.kt | 52 ++--- .../kotlin/gradle/targets/js/npm/NpmApi.kt | 3 +- .../gradle/targets/js/npm/NpmDependency.kt | 19 +- .../gradle/targets/js/npm/NpmProject.kt | 7 +- .../targets/js/npm/NpmProjectVisitor.kt | 180 ------------------ .../gradle/targets/js/npm/NpmResolveTask.kt | 20 -- .../gradle/targets/js/npm/NpmResolver.kt | 151 --------------- .../gradle/targets/js/npm/NpmSimpleLinker.kt | 1 + .../js/npm/resolved/KotlinNpmResolution.kt | 12 ++ .../KotlinProjectNpmResolution.kt} | 26 ++- .../npm/{ => resolved}/NpmProjectPackage.kt | 9 +- .../resolver/KotlinCompilationNpmResolver.kt | 169 ++++++++++++++++ .../js/npm/resolver/KotlinNpmResolver.kt | 160 ++++++++++++++++ .../npm/resolver/KotlinProjectNpmResolver.kt | 87 +++++++++ .../js/npm/tasks/KotlinNpmInstallTask.kt | 39 ++++ .../js/npm/tasks/KotlinPackageJsonTask.kt | 39 ++++ .../targets/js/subtargets/KotlinBrowserJs.kt | 4 +- .../js/subtargets/KotlinJsSubTarget.kt | 2 +- .../targets/js/subtargets/KotlinNodeJs.kt | 4 +- .../gradle/targets/js/testing/KotlinJsTest.kt | 5 +- .../targets/js/webpack/KotlinWebpack.kt | 4 +- .../kotlin/gradle/targets/js/yarn/Yarn.kt | 4 +- .../YarnImportedPackagesVersionResolver.kt | 4 +- .../gradle/targets/js/yarn/YarnSimple.kt | 4 +- .../gradle/targets/js/yarn/YarnWorkspaces.kt | 7 +- 29 files changed, 601 insertions(+), 439 deletions(-) delete mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectVisitor.kt delete mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolveTask.kt delete mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolver.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolved/KotlinNpmResolution.kt rename libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/{NpmProjects.kt => resolved/KotlinProjectNpmResolution.kt} (50%) rename libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/{ => resolved}/NpmProjectPackage.kt (57%) create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinCompilationNpmResolver.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinNpmResolver.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinProjectNpmResolver.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/tasks/KotlinNpmInstallTask.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/tasks/KotlinPackageJsonTask.kt diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTargetConfigurator.kt index ec884d7dfc8..c62192d08a2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTargetConfigurator.kt @@ -11,7 +11,10 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinTargetConfigurator import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinOnlyTarget import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs +import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinPackageJsonTask +import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider +import org.jetbrains.kotlin.gradle.tasks.createOrRegisterTask open class KotlinJsTargetConfigurator(kotlinPluginVersion: String) : KotlinTargetConfigurator(true, true, kotlinPluginVersion) { @@ -22,7 +25,18 @@ open class KotlinJsTargetConfigurator(kotlinPluginVersion: String) : super.configureTarget(target) target.compilations.forEach { - it.compileKotlinTask.dependsOn(target.project.nodeJs.root.npmResolveTask) + val npmResolveTask = target.project.nodeJs.root.npmInstallTask + val npmProject = it.npmProject + + val packageJsonTaskName = npmProject.packageJsonTaskName + npmResolveTask.dependsOn(packageJsonTaskName) + + target.project.createOrRegisterTask(packageJsonTaskName) { task -> + task.compilation = it + task.description = "Create package.json file for $it" + } + + it.compileKotlinTask.dependsOn(npmResolveTask) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsExec.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsExec.kt index 35aa27dfa41..ce9a06e33bb 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsExec.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsExec.kt @@ -10,7 +10,7 @@ import org.gradle.api.tasks.AbstractExecTask open class NodeJsExec : AbstractExecTask(NodeJsExec::class.java) { init { val nodeJs = NodeJsPlugin.apply(project).root - dependsOn(nodeJs.npmResolveTask) + dependsOn(nodeJs.npmInstallTask) executable = nodeJs.environment.nodeExecutable } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsPlugin.kt index 8e15b7bfdc9..11adbaeb591 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/nodejs/NodeJsPlugin.kt @@ -5,7 +5,7 @@ import org.gradle.api.Project import org.gradle.api.plugins.BasePlugin import org.gradle.api.tasks.Delete import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension.Companion.EXTENSION_NAME -import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolveTask +import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask open class NodeJsPlugin : Plugin { override fun apply(project: Project): Unit = project.run { @@ -20,7 +20,7 @@ open class NodeJsPlugin : Plugin { it.description = "Download and install a local node/npm version" } - tasks.create(NpmResolveTask.NAME, NpmResolveTask::class.java) { + tasks.create(KotlinNpmInstallTask.NAME, KotlinNpmInstallTask::class.java) { it.dependsOn(setupTask) it.outputs.upToDateWhen { false } it.group = TASKS_GROUP_NAME 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 1a9e226891d..b799ba54221 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 @@ -3,7 +3,7 @@ package org.jetbrains.kotlin.gradle.targets.js.nodejs import org.gradle.api.Project import org.jetbrains.kotlin.gradle.logging.kotlinInfo import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi -import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolveTask +import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask import org.jetbrains.kotlin.gradle.targets.js.yarn.Yarn import java.io.File @@ -25,8 +25,8 @@ open class NodeJsRootExtension(project: Project) : NodeJsExtension(project) { val nodeJsSetupTask: NodeJsSetupTask get() = project.tasks.getByName(NodeJsSetupTask.NAME) as NodeJsSetupTask - val npmResolveTask: NpmResolveTask - get() = project.tasks.getByName(NpmResolveTask.NAME) as NpmResolveTask + val npmInstallTask: KotlinNpmInstallTask + get() = project.tasks.getByName(KotlinNpmInstallTask.NAME) as KotlinNpmInstallTask val rootPackageDir: File get() = project.buildDir.resolve("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 16e4010cdf1..6e516478387 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 @@ -23,53 +23,25 @@ internal class GradleNodeModulesCache(val project: Project) : AutoCloseable { internal val dir = project.nodeJs.root.nodeModulesGradleCacheDir private val cache = ProcessedFilesCache(project, dir, STATE_FILE_NAME, "8") - private val visited = mutableSetOf() - fun collectDependenciesFromConfiguration(configuration: Configuration, result: NpmGradleDependencies) { - if (configuration.isCanBeResolved) { - configuration.resolvedConfiguration.firstLevelModuleDependencies.forEach { - visitDependency(it, result) - } - } - } - - private fun visitDependency(dependency: ResolvedDependency, result: NpmGradleDependencies) { - if (!visited.add(dependency)) return - - visitArtifacts(dependency, dependency.moduleArtifacts, result) - - dependency.children.forEach { - visitDependency(it, result) - } - } - - private fun visitArtifacts( + fun ensureImported( + artifact: ResolvedArtifact, dependency: ResolvedDependency, artifacts: MutableSet, result: NpmGradleDependencies ) { - artifacts.forEach { artifact -> - val componentIdentifier = artifact.id.componentIdentifier - if (componentIdentifier is ProjectComponentIdentifier) { - val dependentProject = project.findProject(componentIdentifier.projectPath) - ?: error("Cannot find project ${componentIdentifier.projectPath}") - - result.internalModules.add(dependentProject) - } else { - val key = cache.getOrCompute(artifact.file) { - val module = GradleNodeModuleBuilder(project, dependency, artifacts, this) - module.visitArtifacts() - module.rebuild()?.let { - it.name + ":" + it.version - } - } - - if (key != null) { - val (name, version) = key.split(":") - result.externalModules.add(GradleNodeModule(name, version, importedPackageDir(dir, name, version))) - } + val key = cache.getOrCompute(artifact.file) { + val module = GradleNodeModuleBuilder(project, dependency, artifacts, this) + module.visitArtifacts() + module.rebuild()?.let { + it.name + ":" + it.version } } + + if (key != null) { + val (name, version) = key.split(":") + result.externalModules.add(GradleNodeModule(name, version, importedPackageDir(dir, name, version))) + } } override fun close() { 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 a5d9af85e7b..b1ad3faf853 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 @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.gradle.targets.js.npm import org.gradle.api.Project +import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.NpmProjectPackage /** * NodeJS package manager API @@ -17,7 +18,7 @@ interface NpmApi { fun resolveRootProject( rootProject: Project, - subProjects: MutableList + subProjects: Collection ) companion object { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmDependency.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmDependency.kt index 06648bbf813..a23514b74de 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmDependency.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmDependency.kt @@ -16,7 +16,9 @@ import org.gradle.api.internal.artifacts.dependencies.SelfResolvingDependencyInt import org.gradle.api.tasks.TaskDependency import org.gradle.internal.component.local.model.DefaultLibraryBinaryIdentifier import org.jetbrains.kotlin.gradle.internal.isInIdeaSync -import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolver.ResolutionCallResult.* +import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinProjectNpmResolution +import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.NpmProjectPackage +import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinNpmResolver import java.io.File data class NpmDependency( @@ -82,20 +84,17 @@ data class NpmDependency( } private fun resolveProject(): NpmProjectPackage? { - val result = - if (isInIdeaSync) NpmResolver.resolveIfNeeded(project) - else NpmResolver.getAlreadyResolvedOrNull(project) + val resolvedProject = + if (isInIdeaSync) KotlinNpmResolver.resolveIfNeeded(project) + else KotlinNpmResolver.getAlreadyResolvedOrNull(project) - return when (result) { + return when (resolvedProject) { null -> null - is AlreadyInProgress -> null - is AlreadyResolved -> findIn(result.resolution) - ?: error("Project hierarchy is already resolved in NPM without $this") - is ResolvedNow -> findIn(result.resolution) ?: error("Cannot find $this after NPM project resolve") + else -> findIn(resolvedProject) ?: error("Project hierarchy is already resolved in NPM without $this") } } - private fun findIn(npmProjects: NpmProjects) = + private fun findIn(npmProjects: KotlinProjectNpmResolution) = npmProjects.npmProjectsByNpmDependency[this] val key: String = if (org == null) name else "@$org/$name" 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 f44e6dfb267..7fc4624e08e 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 @@ -10,7 +10,9 @@ import org.gradle.process.ExecSpec import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.KotlinTarget import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation +import org.jetbrains.kotlin.gradle.plugin.mpp.disambiguateName import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs +import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinNpmResolver import java.io.File val KotlinJsCompilation.npmProject: NpmProject @@ -41,6 +43,9 @@ open class NpmProject(val compilation: KotlinJsCompilation) { val packageJsonFile: File get() = dir.resolve(PACKAGE_JSON) + val packageJsonTaskName: String + get() = compilation.disambiguateName("packageJson") + val main: String get() = "kotlin/$name.js" @@ -61,7 +66,7 @@ open class NpmProject(val compilation: KotlinJsCompilation) { * Require [request] nodejs module and return canonical path to it's main js file. */ fun require(request: String): String { - NpmResolver.requireResolved(project) + KotlinNpmResolver.requireResolved(project) return modules.require(request) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectVisitor.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectVisitor.kt deleted file mode 100644 index dc46a4766c3..00000000000 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectVisitor.kt +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.gradle.targets.js.npm - -import org.gradle.api.Project -import org.gradle.api.artifacts.Configuration -import org.gradle.api.attributes.Usage -import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension -import org.jetbrains.kotlin.gradle.dsl.KotlinSingleTargetExtension -import org.jetbrains.kotlin.gradle.dsl.kotlinExtensionOrNull -import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType -import org.jetbrains.kotlin.gradle.plugin.KotlinTarget -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages -import org.jetbrains.kotlin.gradle.plugin.usesPlatformOf -import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency -import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension -import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs - -/** - * Visits given gradle [project] for all of its [NpmProject], - * creates `package.json` for them ([NpmProjectPackage]) and runs - * selected [NodeJsRootExtension.packageManager] to download and install all of it's dependencies. - */ -internal class NpmProjectVisitor(val resolver: NpmResolver, val project: Project) { - private val npmProjects = mutableListOf() - private val byCompilation = mutableMapOf() - private val byNpmDependency = mutableMapOf() - private val taskRequirements = mutableMapOf>() - private val requiredFromTasksByCompilation = mutableMapOf>() - - private fun addTaskRequirements(task: RequiresNpmDependencies) { - val requirements = task.requiredNpmDependencies.toList() - - taskRequirements[task] = requirements - - requiredFromTasksByCompilation - .getOrPut(task.compilation) { mutableListOf() } - .add(task) - } - - private fun addNpmProject(resolved: NpmProjectPackage) { - val compilation = resolved.npmProject.compilation - byCompilation[compilation] = resolved - resolved.npmDependencies.forEach { - byNpmDependency[it] = resolved - } - npmProjects.add(resolved) - } - - fun visitProject(): NpmProjects { - visitTasksRequiredDependencies() - - val kotlin = project.kotlinExtensionOrNull - - if (kotlin != null) { - when (kotlin) { - is KotlinSingleTargetExtension -> visitTarget(kotlin.target) - is KotlinMultiplatformExtension -> kotlin.targets.forEach { - visitTarget(it) - } - } - } - - return NpmProjects( - project, - npmProjects, - byCompilation, - byNpmDependency, - taskRequirements - ) - } - - private fun visitTasksRequiredDependencies() { - project.tasks.toList().forEach { task -> - if (task.enabled && task is RequiresNpmDependencies) { - addTaskRequirements(task) - } - } - } - - private fun visitTarget(target: KotlinTarget) { - if (target.platformType == KotlinPlatformType.js) { - target.compilations.toList().forEach { compilation -> - if (compilation is KotlinJsCompilation) { - // compilation may be KotlinWithJavaTarget for old Kotlin2JsPlugin - visitCompilation(compilation) - } - } - } - } - - private fun visitCompilation(compilation: KotlinJsCompilation) { - val project = compilation.target.project - val npmProject = compilation.npmProject - val name = npmProject.name - val packageJson = PackageJson( - name, - fixSemver(project.version.toString()) - ) - val npmDependencies = mutableSetOf() - val gradleDeps = NpmGradleDependencies() - - val aggregateConfiguration = project.configurations.create("$name-npm") { - it.usesPlatformOf(compilation.target) - it.attributes.attribute(Usage.USAGE_ATTRIBUTE, KotlinUsages.consumerRuntimeUsage(compilation.target)) - it.isVisible = false - it.isCanBeConsumed = false - it.isCanBeResolved = true - it.description = "NPM configuration for $compilation." - } - - compilation.allKotlinSourceSets.forEach { sourceSet -> - sourceSet.relatedConfigurationNames.forEach { configurationName -> - val configuration = project.configurations.getByName(configurationName) - aggregateConfiguration.extendsFrom(configuration) - } - } - - packageJson.main = npmProject.main - - val requiredByTasks = requiredFromTasksByCompilation[compilation] - var nodeModulesRequired = false - if (requiredByTasks != null && requiredByTasks.isNotEmpty()) { - val toolsConfiguration = project.configurations.create("$name-jsTools") - requiredByTasks.forEach { - if (it.nodeModulesRequired) nodeModulesRequired = true - it.requiredNpmDependencies.forEach { requirement -> - toolsConfiguration.dependencies.add(requirement.createDependency(project)) - } - } - aggregateConfiguration.extendsFrom(toolsConfiguration) - } - - visitConfiguration(aggregateConfiguration, npmDependencies, gradleDeps) - - npmDependencies.forEach { - packageJson.dependencies[it.key] = resolver.chooseVersion(packageJson.dependencies[it.key], it.version) - } - - gradleDeps.externalModules.forEach { - packageJson.dependencies[it.name] = it.version - } - - gradleDeps.internalModules.forEach { target -> - val resolvedTarget = resolver.findDependentResolvedNpmProject(project, target) - if (resolvedTarget != null) { - packageJson.dependencies[resolvedTarget.packageJson.name] = resolvedTarget.packageJson.version - } - } - - project.nodeJs.packageJsonHandlers.forEach { - it(packageJson) - } - - val npmPackage = NpmProjectPackage(project, npmProject, npmDependencies, gradleDeps, packageJson, nodeModulesRequired) - npmPackage.packageJson.saveTo(npmProject.packageJsonFile) - - resolver.packageManager.resolveProject(npmPackage) - - addNpmProject(npmPackage) - } - - private fun visitConfiguration( - configuration: Configuration, - npmDependencies: MutableSet, - gradleDependencies: NpmGradleDependencies - ) { - resolver.gradleNodeModules.collectDependenciesFromConfiguration(configuration, gradleDependencies) - - configuration.allDependencies.forEach { dependency -> - when (dependency) { - is NpmDependency -> npmDependencies.add(dependency) - } - } - } -} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolveTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolveTask.kt deleted file mode 100644 index cc50048394d..00000000000 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolveTask.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.gradle.targets.js.npm - -import org.gradle.api.internal.AbstractTask -import org.gradle.api.tasks.TaskAction - -open class NpmResolveTask : AbstractTask() { - @TaskAction - fun resolve() { - NpmResolver.resolveIfNeeded(project) - } - - companion object { - const val NAME = "kotlinNpmResolve" - } -} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolver.kt deleted file mode 100644 index b02a7a36e6b..00000000000 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolver.kt +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.gradle.targets.js.npm - -import org.gradle.api.Project -import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation -import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsPlugin -import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension -import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs -import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolver.ResolutionCallResult.* -import java.nio.file.Files - -/** - * Generates `package.json` file for [NpmProject] with npm or js dependencies and - * runs selected [NodeJsRootExtension.packageManager] to download and install all of it's dependencies. - * - * All [NpmDependency] for configurations related to kotlin/js will be added to `package.json`. - * For external gradle modules, fake npm packages will be created and added to `package.json` - * as path to directory. - */ -internal class NpmResolver private constructor(val rootProject: Project) { - companion object { - fun resolveIfNeeded(project: Project): ResolutionCallResult { - val process = ProjectData[project] - - if (process != null && process.visit == null) return AlreadyInProgress - - val resolved = process?.visit - - return if (resolved != null) AlreadyResolved(resolved) - else { - run(project.rootProject) - ResolvedNow(ProjectData[project]!!.visit!!) - } - } - - private fun run(rootProject: Project) { - NpmResolver(rootProject).resolve() - } - - fun getAlreadyResolvedOrNull(project: Project): ResolutionCallResult? { - val rootProject = project.rootProject - val process = ProjectData[rootProject] - if (process != null && process.visit == null) return AlreadyInProgress - val resolved = process?.visit - if (resolved != null) return AlreadyResolved(ProjectData[project]!!.visit!!) - - return null - } - - fun requireResolved(project: Project, reason: String = ""): NpmProjects = - ProjectData[project]?.visit ?: error("NPM dependencies should be resolved $reason") - - fun checkRequiredDependencies(project: Project, target: RequiresNpmDependencies) { - val requestedTaskDependencies = requireResolved(project, "before $target execution").taskRequirements - val targetRequired = requestedTaskDependencies[target]?.toSet() ?: setOf() - - target.requiredNpmDependencies.forEach { - check(it in targetRequired) { - "$it required by $target was not found resolved at the time of nodejs package manager call. " + - "This may be caused by changing $target configuration after npm dependencies resolution." - } - } - } - } - - sealed class ResolutionCallResult { - object AlreadyInProgress : ResolutionCallResult() - class AlreadyResolved(val resolution: NpmProjects) : ResolutionCallResult() - class ResolvedNow(val resolution: NpmProjects) : ResolutionCallResult() - } - - val gradleNodeModules = GradleNodeModulesCache(rootProject) - val nodeJs = NodeJsPlugin.apply(rootProject).root - val packageManager - get() = nodeJs.packageManager - - private val allNpmPackages = mutableListOf() - - class ProjectData(var visit: NpmProjects? = null) { - companion object { - private const val KEY = "npmResolverData" - operator fun get(project: Project) = project.extensions.findByName(KEY) as ProjectData? - operator fun set(project: Project, value: ProjectData) = project.extensions.add(KEY, value) - fun getOrPut(project: Project) = this[project] ?: ProjectData().also { this[project] = it } - } - } - - fun resolve() { - resolve(rootProject) - removeOutdatedPackages() - gradleNodeModules.close() - - if (allNpmPackages.any { it.npmDependencies.isNotEmpty() }) { - packageManager.resolveRootProject(rootProject, allNpmPackages) - } else if (allNpmPackages.any { it.hasNodeModulesDependentTasks }) { - NpmSimpleLinker(rootProject).link(allNpmPackages) - } - } - - private fun removeOutdatedPackages() { - val packages = allNpmPackages.mapTo(mutableSetOf()) { it.npmProject.name } - nodeJs.projectPackagesDir.listFiles()?.forEach { - if (it.name !in packages) { - it.deleteRecursively() - } - } - } - - private fun getOrResolve(project: Project): NpmProjects { - return ProjectData[project]?.visit ?: resolve(project) - } - - private fun resolve(project: Project): NpmProjects { - val data = ProjectData.getOrPut(project) - - project.subprojects.forEach { - getOrResolve(it) - } - - val visited = NpmProjectVisitor(this, project).visitProject() - data.visit = visited - - allNpmPackages.addAll(visited.npmProjects) - - return visited - } - - fun findDependentResolvedNpmProject(src: Project, target: Project): NpmProjectPackage? { - // todo: proper finding using KotlinTargetComponent.findUsageContext - val resolvedTarget = getOrResolve(target) - val mainCompilations = resolvedTarget.npmProjectsByCompilation.entries.filter { it.key.name == KotlinCompilation.MAIN_COMPILATION_NAME } - - return if (mainCompilations.isNotEmpty()) { - if (mainCompilations.size > 1) { - error( - "Cannot resolve project dependency $src -> $target." + - "Dependency to project with multiple js compilation not supported yet." - ) - } - - mainCompilations.single().value - } else null - } - - fun chooseVersion(oldVersion: String?, newVersion: String): String = - oldVersion ?: newVersion // todo: real versions conflict resolution -} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmSimpleLinker.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmSimpleLinker.kt index bbb6d8417f9..399a8d15430 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmSimpleLinker.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmSimpleLinker.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.targets.js.npm import com.google.gson.stream.JsonWriter import org.gradle.api.Project import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs +import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.NpmProjectPackage import java.io.ByteArrayInputStream import java.io.File import java.io.StringWriter diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolved/KotlinNpmResolution.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolved/KotlinNpmResolution.kt new file mode 100644 index 00000000000..c84d76a97b2 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolved/KotlinNpmResolution.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.targets.js.npm.resolved + +import org.gradle.api.Project + +class KotlinNpmResolution(private val projects: Map) { + operator fun get(project: Project) = projects[project] ?: KotlinProjectNpmResolution.empty(project) +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjects.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolved/KotlinProjectNpmResolution.kt similarity index 50% rename from libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjects.kt rename to libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolved/KotlinProjectNpmResolution.kt index 8ca4c5e8f41..9df26a59b6a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjects.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolved/KotlinProjectNpmResolution.kt @@ -3,21 +3,33 @@ * 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 +package org.jetbrains.kotlin.gradle.targets.js.npm.resolved import org.gradle.api.Project import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency +import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency +import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies /** * Info about NPM projects inside particular gradle [project]. */ -class NpmProjects( +class KotlinProjectNpmResolution( val project: Project, - val npmProjects: List, - val npmProjectsByCompilation: Map, - val npmProjectsByNpmDependency: Map, - val taskRequirements: Map> -) \ No newline at end of file +) { + val npmProjectsByCompilation: Map = npmProjects.associateBy { it.npmProject.compilation } + val npmProjectsByNpmDependency: Map = + mutableMapOf().also { result -> + npmProjects.forEach { npmPackage -> + npmPackage.npmDependencies.forEach { npmDependency -> + result[npmDependency] = npmPackage + } + } + } + + companion object { + fun empty(project: Project) = KotlinProjectNpmResolution(project, listOf(), mapOf()) + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectPackage.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolved/NpmProjectPackage.kt similarity index 57% rename from libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectPackage.kt rename to libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolved/NpmProjectPackage.kt index 12149b4d6b7..d262584c375 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectPackage.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolved/NpmProjectPackage.kt @@ -3,9 +3,13 @@ * 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 +package org.jetbrains.kotlin.gradle.targets.js.npm.resolved import org.gradle.api.Project +import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency +import org.jetbrains.kotlin.gradle.targets.js.npm.NpmGradleDependencies +import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject +import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson /** * [NpmProject] full package info @@ -15,6 +19,5 @@ class NpmProjectPackage( val npmProject: NpmProject, val npmDependencies: Collection, val gradleDependencies: NpmGradleDependencies, - val packageJson: PackageJson, - val hasNodeModulesDependentTasks: Boolean + val packageJson: PackageJson ) \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinCompilationNpmResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinCompilationNpmResolver.kt new file mode 100644 index 00000000000..7d9b30c8f1b --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinCompilationNpmResolver.kt @@ -0,0 +1,169 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.targets.js.npm.resolver + +import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.ResolvedArtifact +import org.gradle.api.artifacts.ResolvedDependency +import org.gradle.api.artifacts.component.ProjectComponentIdentifier +import org.gradle.api.attributes.Usage +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages +import org.jetbrains.kotlin.gradle.plugin.usesPlatformOf +import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs +import org.jetbrains.kotlin.gradle.targets.js.npm.* +import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.NpmProjectPackage + +internal class KotlinCompilationNpmResolver( + val projectResolver: KotlinProjectNpmResolver, + val compilation: KotlinJsCompilation +) { + val resolver = projectResolver.resolver + val target get() = compilation.target + val project get() = target.project + + val aggregatedConfiguration: Configuration by lazy { + createAggregatedConfiguration() + } + + val projectPackage by lazy { + createPackageJson(aggregatedConfiguration) + } + + private fun createAggregatedConfiguration(): Configuration { + val all = project.configurations.create("${compilation.name}Npm") + + all.usesPlatformOf(target) + all.attributes.attribute(Usage.USAGE_ATTRIBUTE, KotlinUsages.consumerRuntimeUsage(target)) + all.isVisible = false + all.isCanBeConsumed = false + all.isCanBeResolved = true + all.description = "NPM configuration for $compilation." + + compilation.allKotlinSourceSets.forEach { sourceSet -> + sourceSet.relatedConfigurationNames.forEach { configurationName -> + val configuration = project.configurations.getByName(configurationName) + all.extendsFrom(configuration) + } + } + + createNpmToolsConfiguration()?.let { tools -> + all.extendsFrom(tools) + } + + return all + } + + private fun createNpmToolsConfiguration(): Configuration? { + val taskRequirements = projectResolver.requiredFromTasksByCompilation[compilation] + ?.takeIf { it.isNotEmpty() } ?: return null + + val toolsConfiguration = project.configurations.create("${compilation.name}NpmTools") + + toolsConfiguration.isVisible = false + toolsConfiguration.isCanBeConsumed = false + toolsConfiguration.isCanBeResolved = true + toolsConfiguration.description = "NPM Tools configuration for $compilation." + + taskRequirements.forEach { requirement -> + requirement.requiredNpmDependencies.forEach { requiredNpmDependency -> + toolsConfiguration.dependencies.add(requiredNpmDependency.createDependency(project)) + } + } + + return toolsConfiguration + } + + private fun createPackageJson(configuration: Configuration): NpmProjectPackage { + val npmProject = compilation.npmProject + val name = npmProject.name + val packageJson = PackageJson( + name, + fixSemver(project.version.toString()) + ) + val npmDependencies = mutableSetOf() + val gradleDependencies = NpmGradleDependencies() + + packageJson.main = npmProject.main + + collectDependenciesFromConfiguration(configuration, gradleDependencies) + + configuration.allDependencies.forEach { dependency -> + when (dependency) { + is NpmDependency -> npmDependencies.add(dependency) + } + } + + npmDependencies.forEach { + packageJson.dependencies[it.key] = chooseVersion(packageJson.dependencies[it.key], it.version) + } + + gradleDependencies.externalModules.forEach { + packageJson.dependencies[it.name] = it.version + } + + gradleDependencies.internalModules.forEach { target -> + val targetResolver = resolver.findDependentResolver(project, target) + if (targetResolver != null) { + val targetPackageJson = targetResolver.projectPackage.packageJson + packageJson.dependencies[targetPackageJson.name] = targetPackageJson.version + } + } + + project.nodeJs.packageJsonHandlers.forEach { + it(packageJson) + } + + val npmPackage = NpmProjectPackage( + project, + npmProject, + npmDependencies, + gradleDependencies, + packageJson + ) + npmPackage.packageJson.saveTo(npmProject.packageJsonFile) + + return npmPackage + } + + fun chooseVersion(oldVersion: String?, newVersion: String): String = + oldVersion ?: newVersion // todo: real versions conflict resolution + + + private fun collectDependenciesFromConfiguration(configuration: Configuration, result: NpmGradleDependencies) { + if (configuration.isCanBeResolved) { + configuration.resolvedConfiguration.firstLevelModuleDependencies.forEach { + visitDependency(it, result) + } + } + } + + private fun visitDependency(dependency: ResolvedDependency, result: NpmGradleDependencies) { + visitArtifacts(dependency, dependency.moduleArtifacts, result) + + dependency.children.forEach { + visitDependency(it, result) + } + } + + private fun visitArtifacts( + dependency: ResolvedDependency, + artifacts: MutableSet, + result: NpmGradleDependencies + ) { + artifacts.forEach { artifact -> + val componentIdentifier = artifact.id.componentIdentifier + if (componentIdentifier is ProjectComponentIdentifier) { + val dependentProject = project.findProject(componentIdentifier.projectPath) + ?: error("Cannot find project ${componentIdentifier.projectPath}") + + result.internalModules.add(dependentProject) + } else { + resolver.gradleNodeModules.ensureImported(artifact, dependency, artifacts, result) + } + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinNpmResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinNpmResolver.kt new file mode 100644 index 00000000000..980ae0c4463 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinNpmResolver.kt @@ -0,0 +1,160 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.targets.js.npm.resolver + +import org.gradle.api.Project +import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation +import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsPlugin +import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension +import org.jetbrains.kotlin.gradle.targets.js.npm.* +import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinNpmResolution +import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinProjectNpmResolution +import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.NpmProjectPackage + +/** + * Generates `package.json` file for [NpmProject] with npm or js dependencies and + * runs selected [NodeJsRootExtension.packageManager] to download and install all of it's dependencies. + * + * All [NpmDependency] for configurations related to kotlin/js will be added to `package.json`. + * For external gradle modules, fake npm packages will be created and added to `package.json` + * as path to directory. + */ +internal class KotlinNpmResolver private constructor(val rootProject: Project) { + companion object { + private sealed class State { + class Resolving(val resolver: KotlinNpmResolver) : State() + class Resolved(val resolved: KotlinNpmResolution) : State() + } + + @Volatile + private var initializedRootProject: Project? = null + private var state: State? = null + + private fun getState(rootProject: Project): State { + check(rootProject == rootProject.rootProject) + + if (initializedRootProject == null) { + synchronized(this) { + if (initializedRootProject == null) { + initializedRootProject = rootProject + state = State.Resolving(KotlinNpmResolver(rootProject)) + } + } + } + + check(initializedRootProject == rootProject) + + return state!! + } + + private fun setResolution(resolution: KotlinNpmResolution) { + state = State.Resolved(resolution) + } + + fun getResolver(rootProject: Project): KotlinNpmResolver = + (getState(rootProject) as? State.Resolving ?: error("NPM Dependencies already resolved and installed")) + .resolver + + fun resolveIfNeeded(project: Project): KotlinProjectNpmResolution { + val state = getState(project.rootProject) + val resolution = when (state) { + is State.Resolved -> state.resolved + is State.Resolving -> state.resolver.installAndClose() + } + return resolution[project] + } + + fun getAlreadyResolvedOrNull(project: Project): KotlinProjectNpmResolution? { + val state = getState(project.rootProject) + return when (state) { + is State.Resolved -> state.resolved[project] + is State.Resolving -> null + } + } + + fun requireResolved(project: Project, reason: String = ""): KotlinProjectNpmResolution = + getAlreadyResolvedOrNull(project) ?: error("NPM dependencies should be resolved $reason") + + fun checkRequiredDependencies(project: Project, target: RequiresNpmDependencies) { + val requestedTaskDependencies = requireResolved( + project, + "before $target execution" + ).taskRequirements + val targetRequired = requestedTaskDependencies[target]?.toSet() ?: setOf() + + target.requiredNpmDependencies.forEach { + check(it in targetRequired) { + "$it required by $target was not found resolved at the time of nodejs package manager call. " + + "This may be caused by changing $target configuration after npm dependencies resolution." + } + } + } + } + + val gradleNodeModules = GradleNodeModulesCache(rootProject) + val projectResolvers = mutableMapOf() + + init { + if (rootProject.logger.isDebugEnabled) { + rootProject.logger.debug("KotlinNpmResolver initialization triggered at: ${Thread.currentThread().stackTrace.joinToString("\n")}") + } + + rootProject.allprojects.toList().forEach { + projectResolvers[it] = KotlinProjectNpmResolver(it, this) + } + } + + fun installAndClose(): KotlinNpmResolution { + if (rootProject.logger.isDebugEnabled) { + rootProject.logger.debug("KotlinNpmResolver installation triggered at: ${Thread.currentThread().stackTrace.joinToString("\n")}") + } + + val nodeJs = NodeJsPlugin.apply(rootProject).root + val packageManager = nodeJs.packageManager + val allNpmPackages = projectResolvers.values.flatMap { it.byCompilation.values.map { it.projectPackage } } + + removeOutdatedPackages(nodeJs, allNpmPackages) + gradleNodeModules.close() + + if (allNpmPackages.any { it.npmDependencies.isNotEmpty() }) { + packageManager.resolveRootProject(rootProject, allNpmPackages) + } else if (projectResolvers.values.any { it.hasNodeModulesDependentTasks }) { + NpmSimpleLinker(rootProject).link(allNpmPackages) + } + + val resolution = KotlinNpmResolution(projectResolvers.values.map { it.toResolved() }.associateBy { it.project }) + setResolution(resolution) + return resolution + } + + private fun removeOutdatedPackages(nodeJs: NodeJsRootExtension, allNpmPackages: List) { + val packages = allNpmPackages.mapTo(mutableSetOf()) { it.npmProject.name } + nodeJs.projectPackagesDir.listFiles()?.forEach { + if (it.name !in packages) { + it.deleteRecursively() + } + } + } + + fun findDependentResolver(src: Project, target: Project): KotlinCompilationNpmResolver? { + // todo: proper finding using KotlinTargetComponent.findUsageContext + val targetResolver = getResolver(target.rootProject).projectResolvers[target] ?: return null + val mainCompilations = + targetResolver.byCompilation.entries.filter { it.key.name == KotlinCompilation.MAIN_COMPILATION_NAME } + + return if (mainCompilations.isNotEmpty()) { + if (mainCompilations.size > 1) { + error( + "Cannot resolve project dependency $src -> $target." + + "Dependency to project with multiple js compilation not supported yet." + ) + } + + mainCompilations.single().value + } else null + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinProjectNpmResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinProjectNpmResolver.kt new file mode 100644 index 00000000000..8ecf8ab1623 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/resolver/KotlinProjectNpmResolver.kt @@ -0,0 +1,87 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.targets.js.npm.resolver + +import org.gradle.api.Project +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import org.jetbrains.kotlin.gradle.dsl.KotlinSingleTargetExtension +import org.jetbrains.kotlin.gradle.dsl.kotlinExtensionOrNull +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType +import org.jetbrains.kotlin.gradle.plugin.KotlinTarget +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation +import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency +import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies +import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinProjectNpmResolution + +internal class KotlinProjectNpmResolver( + val project: Project, + val resolver: KotlinNpmResolver +) { + val byCompilation = mutableMapOf() + + private val taskRequirements = mutableMapOf>() + val requiredFromTasksByCompilation = mutableMapOf>() + var hasNodeModulesDependentTasks = false + private set + + init { + visit() + } + + fun visit() { + project.tasks.toList().forEach { task -> + if (task.enabled && task is RequiresNpmDependencies) { + addTaskRequirements(task) + } + } + + val kotlin = project.kotlinExtensionOrNull + + if (kotlin != null) { + when (kotlin) { + is KotlinSingleTargetExtension -> visitTarget(kotlin.target) + is KotlinMultiplatformExtension -> kotlin.targets.forEach { + visitTarget(it) + } + } + } + } + + private fun visitTarget(target: KotlinTarget) { + if (target.platformType == KotlinPlatformType.js) { + target.compilations.toList().forEach { compilation -> + if (compilation is KotlinJsCompilation) { + // compilation may be KotlinWithJavaTarget for old Kotlin2JsPlugin + visitCompilation(compilation) + } + } + } + } + + private fun visitCompilation(compilation: KotlinJsCompilation) { + byCompilation[compilation] = KotlinCompilationNpmResolver(this, compilation) + } + + private fun addTaskRequirements(task: RequiresNpmDependencies) { + if (!hasNodeModulesDependentTasks && task.nodeModulesRequired) { + hasNodeModulesDependentTasks = true + } + + val requirements = task.requiredNpmDependencies.toList() + + taskRequirements[task] = requirements + + requiredFromTasksByCompilation + .getOrPut(task.compilation) { mutableListOf() } + .add(task) + } + + fun toResolved() = KotlinProjectNpmResolution( + project, + byCompilation.values.map { it.projectPackage }, + taskRequirements + ) +} \ 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/KotlinNpmInstallTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/tasks/KotlinNpmInstallTask.kt new file mode 100644 index 00000000000..c0c8d996262 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/tasks/KotlinNpmInstallTask.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.targets.js.npm.tasks + +import org.gradle.api.DefaultTask +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.TaskAction +import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject +import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinNpmResolver +import java.io.File + +open class KotlinNpmInstallTask : DefaultTask() { + private val resolver: KotlinNpmResolver + get() = KotlinNpmResolver.getResolver(project) + + init { + check(project == project.rootProject) + } + + @get:InputFiles + val packageJsonFiles: Collection + get() = resolver.projectResolvers.values.flatMap { projectResolver -> + projectResolver.byCompilation.keys.map { compilation -> + compilation.npmProject.packageJsonFile + } + } + + @TaskAction + fun resolve() { + resolver.installAndClose() + } + + companion object { + const val NAME = "kotlinNpmInstall" + } +} \ 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 new file mode 100644 index 00000000000..ccc809c63d3 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/tasks/KotlinPackageJsonTask.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.targets.js.npm.tasks + +import org.gradle.api.DefaultTask +import org.gradle.api.artifacts.Configuration +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation +import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject +import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinCompilationNpmResolver +import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinNpmResolver +import java.io.File + +class KotlinPackageJsonTask : DefaultTask() { + @Internal + lateinit var compilation: KotlinJsCompilation + + private val compilationResolver: KotlinCompilationNpmResolver + get() = KotlinNpmResolver.getResolver(project.rootProject).projectResolvers[project]!!.byCompilation[compilation]!! + + @get:InputFiles + val configuration: Configuration + get() = compilationResolver.aggregatedConfiguration + + @get:OutputFile + val packageJson: File + get() = compilation.npmProject.packageJsonFile + + @TaskAction + fun resolve() { + compilationResolver.projectPackage + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinBrowserJs.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinBrowserJs.kt index b6c3d4fef48..6c9eeeec611 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinBrowserJs.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinBrowserJs.kt @@ -44,7 +44,7 @@ class KotlinBrowserJs(target: KotlinJsTarget) : project.createOrRegisterTask(disambiguateCamelCased("webpack")) { val compileKotlinTask = compilation.compileKotlinTask it.dependsOn( - target.project.nodeJs.root.npmResolveTask, + target.project.nodeJs.root.npmInstallTask, compileKotlinTask ) @@ -57,7 +57,7 @@ class KotlinBrowserJs(target: KotlinJsTarget) : val run = project.createOrRegisterTask(disambiguateCamelCased("run")) { val compileKotlinTask = compilation.compileKotlinTask it.dependsOn( - target.project.nodeJs.root.npmResolveTask, + target.project.nodeJs.root.npmInstallTask, compileKotlinTask, compilation.processResourcesTaskName ) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinJsSubTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinJsSubTarget.kt index 16493865f9c..ca376b46dda 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinJsSubTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinJsSubTarget.kt @@ -74,7 +74,7 @@ abstract class KotlinJsSubTarget( testJs.group = LifecycleBasePlugin.VERIFICATION_GROUP testJs.description = testTaskDescription - testJs.dependsOn(target.project.nodeJs.root.npmResolveTask, compileTask, nodeJs.nodeJsSetupTask) + testJs.dependsOn(target.project.nodeJs.root.npmInstallTask, compileTask, nodeJs.nodeJsSetupTask) testJs.onlyIf { compileTask.outputFile.exists() diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinNodeJs.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinNodeJs.kt index c98ce6a89ef..56a7aefac11 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinNodeJs.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinNodeJs.kt @@ -39,7 +39,7 @@ class KotlinNodeJs(target: KotlinJsTarget) : runTask.description = "run compiled js in nodejs" val compileKotlinTask = compilation.compileKotlinTask - runTask.dependsOn(target.project.nodeJs.root.npmResolveTask, compileKotlinTask) + runTask.dependsOn(target.project.nodeJs.root.npmInstallTask, compileKotlinTask) runTask.args(compileKotlinTask.outputFile) } @@ -57,7 +57,7 @@ class KotlinNodeJs(target: KotlinJsTarget) : runtimeOnly(kotlin("test-nodejs-runner")) } - target.project.nodeJs.root.npmResolveTask.doLast { + target.project.nodeJs.root.npmInstallTask.doLast { runTaskHolder.configure { runTask -> runTask.args( "--require", diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTest.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTest.kt index cdfcace335c..5d6bf02d77c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTest.kt @@ -13,7 +13,7 @@ import org.gradle.util.ConfigureUtil import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsPlugin -import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolver +import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinNpmResolver import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject @@ -21,7 +21,6 @@ import org.jetbrains.kotlin.gradle.targets.js.testing.karma.KotlinKarma import org.jetbrains.kotlin.gradle.targets.js.testing.mocha.KotlinMocha import org.jetbrains.kotlin.gradle.targets.js.testing.nodejs.KotlinNodeJsTestRunner import org.jetbrains.kotlin.gradle.tasks.KotlinTest -import java.io.File open class KotlinJsTest : KotlinTest(), RequiresNpmDependencies { @get:Internal @@ -93,7 +92,7 @@ open class KotlinJsTest : KotlinTest(), RequiresNpmDependencies { } override fun executeTests() { - NpmResolver.checkRequiredDependencies(project, this) + KotlinNpmResolver.checkRequiredDependencies(project, this) super.executeTests() } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/webpack/KotlinWebpack.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/webpack/KotlinWebpack.kt index b3853545079..ef53b186fe7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/webpack/KotlinWebpack.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/webpack/KotlinWebpack.kt @@ -17,7 +17,7 @@ import org.gradle.process.internal.ExecHandleFactory import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs import org.jetbrains.kotlin.gradle.targets.js.NpmPackageVersion -import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolver +import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinNpmResolver import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject import org.jetbrains.kotlin.gradle.testing.internal.reportsDir @@ -127,7 +127,7 @@ open class KotlinWebpack : DefaultTask(), RequiresNpmDependencies { @TaskAction fun doExecute() { - NpmResolver.checkRequiredDependencies(project, this) + KotlinNpmResolver.checkRequiredDependencies(project, this) val runner = createRunner() 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 bea6cef3b7e..af1aabf495b 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 @@ -7,7 +7,7 @@ package org.jetbrains.kotlin.gradle.targets.js.yarn import org.gradle.api.Project import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi -import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProjectPackage +import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.NpmProjectPackage object Yarn : NpmApi { private fun getDelegate(project: Project): NpmApi = @@ -20,6 +20,6 @@ object Yarn : NpmApi { override fun resolveProject(resolvedNpmProject: NpmProjectPackage) = getDelegate(resolvedNpmProject.project).resolveProject(resolvedNpmProject) - override fun resolveRootProject(rootProject: Project, subProjects: MutableList) = + override fun resolveRootProject(rootProject: Project, subProjects: Collection) = getDelegate(rootProject.project).resolveRootProject(rootProject, subProjects) } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnImportedPackagesVersionResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnImportedPackagesVersionResolver.kt index 2c46d2d5f51..7ea0c444992 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnImportedPackagesVersionResolver.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnImportedPackagesVersionResolver.kt @@ -9,13 +9,13 @@ import com.google.gson.Gson import org.gradle.api.Project import org.jetbrains.kotlin.gradle.targets.js.npm.GradleNodeModule import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject -import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProjectPackage +import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.NpmProjectPackage import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson import java.io.File class YarnImportedPackagesVersionResolver( private val rootProject: Project, - private val npmProjects: MutableList, + private val npmProjects: Collection, private val nodeJsWorldDir: File ) { private val resolvedVersion = mutableMapOf() diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnSimple.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnSimple.kt index 2d218db72a3..380d4e300e5 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnSimple.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnSimple.kt @@ -7,7 +7,7 @@ package org.jetbrains.kotlin.gradle.targets.js.yarn import org.gradle.api.Project import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi -import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProjectPackage +import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.NpmProjectPackage object YarnSimple : YarnBasics() { override fun resolveProject(resolvedNpmProject: NpmProjectPackage) { @@ -21,5 +21,5 @@ object YarnSimple : YarnBasics() { } } - override fun resolveRootProject(rootProject: Project, subProjects: MutableList) = Unit + override fun resolveRootProject(rootProject: Project, subProjects: Collection) = Unit } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnWorkspaces.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/yarn/YarnWorkspaces.kt index 6eeab592fc1..739fc79d9ce 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,12 +8,13 @@ package org.jetbrains.kotlin.gradle.targets.js.yarn import org.gradle.api.Project import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs import org.jetbrains.kotlin.gradle.targets.js.npm.* +import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.NpmProjectPackage import java.io.File object YarnWorkspaces : YarnBasics() { override fun resolveProject(resolvedNpmProject: NpmProjectPackage) = Unit - override fun resolveRootProject(rootProject: Project, subProjects: MutableList) { + override fun resolveRootProject(rootProject: Project, subProjects: Collection) { check(rootProject == rootProject.rootProject) setup(rootProject) resolveWorkspaces(rootProject, subProjects) @@ -21,7 +22,7 @@ object YarnWorkspaces : YarnBasics() { private fun resolveWorkspaces( rootProject: Project, - npmProjects: MutableList + npmProjects: Collection ) { val upToDateChecks = npmProjects.map { YarnUpToDateCheck(it.npmProject) @@ -43,7 +44,7 @@ object YarnWorkspaces : YarnBasics() { private fun saveRootProjectWorkspacesPackageJson( rootProject: Project, - npmProjects: MutableList, + npmProjects: Collection, nodeJsWorldDir: File ) { val rootPackageJson = PackageJson(rootProject.name, rootProject.version.toString())