[Gradle, JS] Divide creating root package and install tasks

#KT-34832 fixed
This commit is contained in:
Ilya Goncharov
2020-04-15 17:16:34 +03:00
parent 3ad597ca5c
commit 86573c6dd1
11 changed files with 159 additions and 48 deletions
@@ -1,3 +1,8 @@
/*
* Copyright 2010-2020 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.nodejs
import org.gradle.api.Project
@@ -7,6 +12,7 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.targets.js.NpmVersions
import org.jetbrains.kotlin.gradle.targets.js.npm.KotlinNpmResolutionManager
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask
import org.jetbrains.kotlin.gradle.targets.js.yarn.Yarn
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
@@ -53,6 +59,9 @@ open class NodeJsRootExtension(val rootProject: Project) : ConfigurationPhaseAwa
val rootPackageDir: File
get() = rootProject.buildDir.resolve("js")
val rootPackageJson: File
get() = rootPackageDir.resolve(NpmProject.PACKAGE_JSON)
internal val rootNodeModulesStateFile: File
get() = rootPackageDir.resolve("node_modules.state")
@@ -1,3 +1,8 @@
/*
* Copyright 2010-2020 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.nodejs
import org.gradle.api.Plugin
@@ -5,6 +10,7 @@ import org.gradle.api.Project
import org.gradle.api.plugins.BasePlugin
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension.Companion.EXTENSION_NAME
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.RootPackageJsonTask
import org.jetbrains.kotlin.gradle.tasks.CleanDataTask
open class NodeJsRootPlugin : Plugin<Project> {
@@ -22,8 +28,13 @@ open class NodeJsRootPlugin : Plugin<Project> {
it.description = "Download and install a local node/npm version"
}
val rootPackageJson = tasks.register(RootPackageJsonTask.NAME, RootPackageJsonTask::class.java) {
it.group = TASKS_GROUP_NAME
it.description = "Create root package.json"
}
tasks.register(KotlinNpmInstallTask.NAME, KotlinNpmInstallTask::class.java) {
it.dependsOn(setupTask)
it.dependsOn(setupTask, rootPackageJson)
it.group = TASKS_GROUP_NAME
it.description = "Find, download and link NPM dependencies and projects"
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 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.
*/
@@ -84,8 +84,19 @@ class KotlinNpmResolutionManager(private val nodeJsSettings: NodeJsRootExtension
)
internal sealed class ResolutionState {
class Configuring(val resolver: KotlinRootNpmResolver) : ResolutionState()
class Installed(val resolved: KotlinRootNpmResolution) : ResolutionState()
abstract val npmProjects: List<NpmProject>
class Configuring(val resolver: KotlinRootNpmResolver) : ResolutionState() {
override val npmProjects: List<NpmProject>
get() = resolver.compilations.map { it.npmProject }
}
class Installed(val resolved: KotlinRootNpmResolution) : ResolutionState() {
override val npmProjects: List<NpmProject>
get() = resolved.projects.values.flatMap { it.npmProjects.map { it.npmProject } }
}
}
@Incubating
@@ -100,7 +111,7 @@ class KotlinNpmResolutionManager(private val nodeJsSettings: NodeJsRootExtension
installIfNeeded(requireUpToDateReason = reason)[project]
internal val packageJsonFiles: Collection<File>
get() = (state as ResolutionState.Configuring).resolver.compilations.map { it.npmProject.packageJsonFile }
get() = state.npmProjects.map { it.packageJsonFile }
/**
* @param requireUpToDateReason Check that project already resolved,
@@ -1,6 +1,6 @@
/*
* 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.
* Copyright 2010-2020 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
@@ -17,13 +17,20 @@ interface NpmApi {
fun resolveProject(resolvedNpmProject: KotlinCompilationNpmResolution)
fun resolveRootProject(
fun prepareRootProject(
rootProject: Project,
subProjects: Collection<KotlinCompilationNpmResolution>,
skipExecution: Boolean,
cliArgs: List<String>
)
fun resolveRootProject(
rootProject: Project,
npmProjects: Collection<KotlinCompilationNpmResolution>,
skipExecution: Boolean,
cliArgs: List<String>
)
fun resolveDependency(
npmResolution: KotlinCompilationNpmResolution,
dependency: NpmDependency,
@@ -1,17 +1,15 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 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
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
import org.jetbrains.kotlin.gradle.targets.js.npm.KotlinNpmResolutionManager
class KotlinRootNpmResolution(
val rootProject: Project,
private val projects: Map<Project, KotlinProjectNpmResolution>
val projects: Map<Project, KotlinProjectNpmResolution>
) {
operator fun get(project: Project) = projects[project] ?: KotlinProjectNpmResolution.empty(project)
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 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.
*/
@@ -42,7 +42,7 @@ internal class KotlinRootNpmResolver internal constructor(
val gradleNodeModules = GradleNodeModulesCache(nodeJs)
val compositeNodeModules = CompositeNodeModulesCache(nodeJs)
val packageJsonUmbrella = rootProject.registerTask(PACKAGE_JSON_UMBRELLA_TASK_NAME, Task::class.java) {}
private val projectResolvers = mutableMapOf<Project, KotlinProjectNpmResolver>()
val projectResolvers = mutableMapOf<Project, KotlinProjectNpmResolver>()
fun alreadyResolvedMessage(action: String) = "Cannot $action. NodeJS projects already resolved."
@@ -86,7 +86,7 @@ internal class KotlinRootNpmResolver internal constructor(
}
/**
* Don't use directly, use [NodeJsRootExtension.resolveIfNeeded] instead.
* Don't use directly, use [KotlinNpmResolutionManager.installIfNeeded] instead.
*/
internal fun close(forceUpToDate: Boolean): KotlinRootNpmResolution {
check(!closed)
@@ -108,15 +108,13 @@ internal class KotlinRootNpmResolver internal constructor(
}
val upToDate = forceUpToDate || upToDateChecks.all { it.upToDate }
nodeJs.packageManager.resolveRootProject(
nodeJs.packageManager.prepareRootProject(
rootProject,
allNpmPackages,
upToDate,
nodeJs.npmInstallTask.args
)
nodeJs.rootNodeModulesStateFile.writeText(System.currentTimeMillis().toString())
upToDateChecks.forEach { it.commit() }
return KotlinRootNpmResolution(rootProject, projectResolutions)
@@ -1,15 +1,12 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 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.Input
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.*
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
import java.io.File
@@ -29,6 +26,10 @@ open class KotlinNpmInstallTask : DefaultTask() {
val packageJsonFiles: Collection<File>
get() = resolutionManager.packageJsonFiles
@get:InputFile
val rootPackageJson: File
get() = nodeJs.rootPackageJson
// avoid using node_modules as output directory, as it is significantly slows down build
@get:OutputFile
val nodeModulesState: File
@@ -40,7 +41,15 @@ open class KotlinNpmInstallTask : DefaultTask() {
@TaskAction
fun resolve() {
resolutionManager.install()
val npmResolutions = resolutionManager.requireInstalled()
.projects
.values
nodeJs.packageManager.resolveRootProject(
project,
npmResolutions.flatMap { it.npmProjects },
false,
args
)
}
companion object {
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2020 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.OutputFile
import org.gradle.api.tasks.TaskAction
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
import java.io.File
open class RootPackageJsonTask : DefaultTask() {
init {
check(project == project.rootProject)
outputs.upToDateWhen {
false
}
}
private val nodeJs get() = NodeJsRootPlugin.apply(project.rootProject)
private val resolutionManager get() = nodeJs.npmResolutionManager
@get:OutputFile
val rootPackageJson: File
get() = nodeJs.rootPackageJson
@TaskAction
fun resolve() {
resolutionManager.install()
}
companion object {
const val NAME = "rootPackageJson"
}
}
@@ -1,6 +1,6 @@
/*
* 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.
* Copyright 2010-2020 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.yarn
@@ -24,6 +24,16 @@ class Yarn : NpmApi {
override fun resolveProject(resolvedNpmProject: KotlinCompilationNpmResolution) =
getDelegate(resolvedNpmProject.project).resolveProject(resolvedNpmProject)
override fun resolveRootProject(
rootProject: Project,
npmProjects: Collection<KotlinCompilationNpmResolution>,
skipExecution: Boolean,
cliArgs: List<String>
) {
getDelegate(rootProject.project)
.resolveRootProject(rootProject, npmProjects, skipExecution, cliArgs)
}
override fun resolveDependency(
npmResolution: KotlinCompilationNpmResolution,
dependency: NpmDependency,
@@ -35,13 +45,13 @@ class Yarn : NpmApi {
transitive
)
override fun resolveRootProject(
override fun prepareRootProject(
rootProject: Project,
subProjects: Collection<KotlinCompilationNpmResolution>,
skipExecution: Boolean,
cliArgs: List<String>
) = getDelegate(rootProject.project)
.resolveRootProject(
.prepareRootProject(
rootProject,
subProjects,
skipExecution,
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 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.
*/
@@ -28,6 +28,15 @@ class YarnSimple : YarnBasics() {
}
override fun resolveRootProject(
rootProject: Project,
npmProjects: Collection<KotlinCompilationNpmResolution>,
skipExecution: Boolean,
cliArgs: List<String>
) {
TODO("Not yet implemented")
}
override fun prepareRootProject(
rootProject: Project,
subProjects: Collection<KotlinCompilationNpmResolution>,
skipExecution: Boolean,
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 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.
*/
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.gradle.targets.js.yarn
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution
import java.io.File
@@ -16,7 +15,7 @@ import java.io.File
class YarnWorkspaces : YarnBasics() {
override fun resolveProject(resolvedNpmProject: KotlinCompilationNpmResolution) = Unit
override fun resolveRootProject(
override fun prepareRootProject(
rootProject: Project,
subProjects: Collection<KotlinCompilationNpmResolution>,
skipExecution: Boolean,
@@ -24,31 +23,42 @@ class YarnWorkspaces : YarnBasics() {
) {
check(rootProject == rootProject.rootProject)
if (!skipExecution) setup(rootProject)
return resolveWorkspaces(
return prepareRootPackageJson(
rootProject,
subProjects,
skipExecution,
cliArgs
skipExecution
)
}
private fun resolveWorkspaces(
private fun prepareRootPackageJson(
rootProject: Project,
npmProjects: Collection<KotlinCompilationNpmResolution>,
skipExecution: Boolean
) {
val nodeJs = NodeJsRootPlugin.apply(rootProject)
val rootPackageJsonFile = nodeJs.rootPackageJson
if (!skipExecution) {
saveRootProjectWorkspacesPackageJson(rootProject, npmProjects, rootPackageJsonFile)
}
}
override fun resolveRootProject(
rootProject: Project,
npmProjects: Collection<KotlinCompilationNpmResolution>,
skipExecution: Boolean,
cliArgs: List<String>
) {
val nodeJsWorldDir = NodeJsRootPlugin.apply(rootProject).rootPackageDir
val nodeJs = NodeJsRootPlugin.apply(rootProject)
val nodeJsWorldDir = nodeJs.rootPackageDir
if (!skipExecution) {
saveRootProjectWorkspacesPackageJson(rootProject, npmProjects, nodeJsWorldDir)
yarnExec(
rootProject,
nodeJsWorldDir,
NpmApi.resolveOperationDescription("yarn"),
cliArgs
)
}
yarnExec(
rootProject,
nodeJsWorldDir,
NpmApi.resolveOperationDescription("yarn"),
cliArgs
)
nodeJs.rootNodeModulesStateFile.writeText(System.currentTimeMillis().toString())
yarnLockReadTransitiveDependencies(nodeJsWorldDir, npmProjects.flatMap { it.externalNpmDependencies })
}
@@ -56,8 +66,9 @@ class YarnWorkspaces : YarnBasics() {
private fun saveRootProjectWorkspacesPackageJson(
rootProject: Project,
npmProjects: Collection<KotlinCompilationNpmResolution>,
nodeJsWorldDir: File
rootPackageJsonFile: File
) {
val nodeJsWorldDir = rootPackageJsonFile.parentFile
val rootPackageJson = PackageJson(rootProject.name, rootProject.version.toString())
rootPackageJson.private = true
@@ -67,7 +78,7 @@ class YarnWorkspaces : YarnBasics() {
rootPackageJson.workspaces = npmProjectWorkspaces + importedProjectWorkspaces
rootPackageJson.saveTo(
nodeJsWorldDir.resolve(NpmProject.PACKAGE_JSON)
rootPackageJsonFile
)
}
}