[Gradle, JS] rootPackageJson and kotlinNpmInstall cache-friendly

This commit is contained in:
Ilya Goncharov
2020-12-17 19:08:30 +03:00
committed by Alexander Likhachev
parent 8c79baa998
commit 4566b7c6e5
21 changed files with 203 additions and 100 deletions
@@ -44,7 +44,10 @@ abstract class DukatTask(
@get:Internal
@delegate:Transient
val dts by lazy {
val resolvedCompilation = nodeJs.npmResolutionManager.requireInstalled()[project.path][compilation]
val resolvedCompilation = nodeJs.npmResolutionManager.requireInstalled(
services,
logger
)[project.path][compilation]
val dtsResolver = DtsResolver(resolvedCompilation.npmProject)
dtsResolver.getAllDts(
resolvedCompilation.externalNpmDependencies,
@@ -57,8 +57,8 @@ open class NodeJsRootExtension(@Transient val rootProject: Project) : Configurat
val nodeJsSetupTaskProvider: TaskProvider<out NodeJsSetupTask>
get() = rootProject.tasks.withType(NodeJsSetupTask::class.java).named(NodeJsSetupTask.NAME)
val npmInstallTaskProvider: TaskProvider<out KotlinNpmInstallTask>
get() = rootProject.tasks.withType(KotlinNpmInstallTask::class.java).named(KotlinNpmInstallTask.NAME)
val npmInstallTaskProvider: TaskProvider<out KotlinNpmInstallTask>?
get() = rootProject?.tasks?.withType(KotlinNpmInstallTask::class.java)?.named(KotlinNpmInstallTask.NAME)
val packageJsonUmbrellaTaskProvider: TaskProvider<Task>
get() = rootProject.tasks.named(PACKAGE_JSON_UMBRELLA_TASK_NAME)
@@ -6,8 +6,10 @@
package org.jetbrains.kotlin.gradle.targets.js.npm
import org.gradle.api.Incubating
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.logging.Logger
import org.gradle.internal.service.ServiceRegistry
import org.jetbrains.kotlin.gradle.internal.isInIdeaSync
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution
@@ -116,7 +118,10 @@ class KotlinNpmResolutionManager(private val nodeJsSettings: NodeJsRootExtension
}
@Incubating
internal fun requireInstalled() = installIfNeeded(reason = "")
internal fun requireInstalled(
services: ServiceRegistry,
logger: Logger
) = installIfNeeded(reason = "", services = services, logger = logger)
internal fun requireConfiguringState(): KotlinRootNpmResolver =
(this.state as? ResolutionState.Configuring ?: error("NPM Dependencies already resolved and installed")).resolver
@@ -124,23 +129,25 @@ class KotlinNpmResolutionManager(private val nodeJsSettings: NodeJsRootExtension
internal fun isConfiguringState(): Boolean =
this.state is ResolutionState.Configuring
internal fun prepare() = prepareIfNeeded(requireNotPrepared = true)
internal fun prepare(logger: Logger) = prepareIfNeeded(requireNotPrepared = true, logger = logger)
internal fun installIfNeeded(
reason: String? = "",
args: List<String> = emptyList()
args: List<String> = emptyList(),
services: ServiceRegistry,
logger: Logger
): KotlinRootNpmResolution {
synchronized(this) {
if (state is ResolutionState.Installed) {
return (state as ResolutionState.Installed).resolved
}
val installUpToDate = nodeJsSettings.npmInstallTaskProvider.get().state.upToDate
val installUpToDate = nodeJsSettings.npmInstallTaskProvider?.get()?.state?.upToDate ?: false
val forceUpToDate = installUpToDate && !forceFullResolve
val installation = prepareIfNeeded(requireUpToDateReason = reason)
val installation = prepareIfNeeded(requireUpToDateReason = reason, logger = logger)
val resolution = installation
.install(forceUpToDate, args)
.install(forceUpToDate, args, services, logger)
state = ResolutionState.Installed(resolution)
installation.closePlugins(resolution)
@@ -149,8 +156,8 @@ class KotlinNpmResolutionManager(private val nodeJsSettings: NodeJsRootExtension
}
}
internal fun requireAlreadyInstalled(project: Project, reason: String = ""): KotlinProjectNpmResolution =
installIfNeeded(reason = reason)[project.path]
// internal fun requireAlreadyInstalled(project: Project, reason: String = ""): KotlinProjectNpmResolution =
// installIfNeeded(reason = reason)[project.path]
internal val packageJsonFiles: Collection<File>
get() = state.npmProjects.map { it.packageJsonFile }
@@ -162,7 +169,8 @@ class KotlinNpmResolutionManager(private val nodeJsSettings: NodeJsRootExtension
*/
private fun prepareIfNeeded(
requireUpToDateReason: String? = null,
requireNotPrepared: Boolean = false
requireNotPrepared: Boolean = false,
logger: Logger
): KotlinRootNpmResolver.Installation {
fun alreadyResolved(installation: KotlinRootNpmResolver.Installation): KotlinRootNpmResolver.Installation {
if (requireNotPrepared) error("Project already prepared")
@@ -183,7 +191,7 @@ class KotlinNpmResolutionManager(private val nodeJsSettings: NodeJsRootExtension
error("NPM dependencies should be resolved $requireUpToDateReason")
}
state1.resolver.prepareInstallation().also {
state1.resolver.prepareInstallation(logger).also {
this.state = ResolutionState.Prepared(it)
}
}
@@ -196,23 +204,26 @@ class KotlinNpmResolutionManager(private val nodeJsSettings: NodeJsRootExtension
}
internal fun getNpmDependencyResolvedCompilation(npmDependency: NpmDependency): KotlinCompilationNpmResolution? {
val project = npmDependency.project.path
val project = npmDependency.project!!
val projectPath = project.path
val services = (project as ProjectInternal).services
val logger = project.logger
val resolvedProject =
if (forceFullResolve) {
installIfNeeded(reason = null)[project]
installIfNeeded(reason = null, services = services, logger = logger)[projectPath]
} else {
// may return null only during npm resolution
// (it can be called since NpmDependency added to configuration that
// requires resolve to build package.json, in this case we should just skip this call)
val state0 = state
when (state0) {
is ResolutionState.Prepared -> state0.preparedInstallation[project]
is ResolutionState.Prepared -> state0.preparedInstallation[projectPath]
is ResolutionState.Configuring -> {
return null
//error("Cannot use NpmDependency before :kotlinNpmInstall task execution")
}
is ResolutionState.Installed -> state0.resolved[project]
is ResolutionState.Installed -> state0.resolved[projectPath]
}
}
@@ -6,6 +6,9 @@
package org.jetbrains.kotlin.gradle.targets.js.npm
import org.gradle.api.Project
import org.gradle.api.logging.Logger
import org.gradle.internal.service.ServiceRegistry
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution
import java.io.File
@@ -17,16 +20,23 @@ interface NpmApi {
fun resolveProject(resolvedNpmProject: KotlinCompilationNpmResolution)
fun preparedFiles(project: Project): Collection<File>
fun preparedFiles(nodeJs: NodeJsRootExtension): Collection<File>
fun prepareRootProject(
rootProject: Project,
rootProject: Project?,
nodeJs: NodeJsRootExtension,
rootProjectName: String,
rootProjectVersion: String,
logger: Logger,
subProjects: Collection<KotlinCompilationNpmResolution>,
resolutions: Map<String, String>
)
fun resolveRootProject(
rootProject: Project,
services: ServiceRegistry,
logger: Logger,
nodeJs: NodeJsRootExtension,
yarnHome: File,
npmProjects: Collection<KotlinCompilationNpmResolution>,
skipExecution: Boolean,
cliArgs: List<String>
@@ -22,7 +22,7 @@ import java.io.File
data class NpmDependency(
@Transient
internal val project: Project,
internal val project: Project?,
private val name: String,
private val version: String,
val scope: Scope = Scope.NORMAL,
@@ -82,7 +82,7 @@ data class NpmDependency(
// (it can be called since NpmDependency added to configuration that
// requires resolve to build package.json, in this case we should just skip this call)
private fun resolveProject(): KotlinCompilationNpmResolution? {
val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
val nodeJs = NodeJsRootPlugin.apply(project!!.rootProject)
return nodeJs.npmResolutionManager.getNpmDependencyResolvedCompilation(this)
}
@@ -90,7 +90,7 @@ data class NpmDependency(
override fun toString() = "$key: $version"
override fun getFiles(): FileCollection = project.files(resolve(true))
override fun getFiles(): FileCollection = project!!.files(resolve(true))
override fun getName() = name
@@ -100,7 +100,7 @@ data class NpmDependency(
override fun contentEquals(dependency: Dependency) = this == dependency
override fun getTargetComponentId() = DefaultLibraryBinaryIdentifier(project.path, key, "npm")
override fun getTargetComponentId() = DefaultLibraryBinaryIdentifier(project!!.path, key, "npm")
override fun copy(): Dependency = this.copy(name = name)
@@ -8,13 +8,12 @@ package org.jetbrains.kotlin.gradle.targets.js.npm
import org.gradle.api.Project
import org.gradle.api.internal.project.ProjectInternal
import org.gradle.internal.hash.FileHasher
import org.gradle.internal.service.ServiceRegistry
import org.jetbrains.kotlin.daemon.common.toHexString
import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated
import java.io.File
class PackageJsonUpToDateCheck(val npmProject: NpmProject) {
val project: Project
get() = npmProject.project
class PackageJsonUpToDateCheck(val services: ServiceRegistry, val npmProject: NpmProject) {
private val NpmProject.packageJsonHashFile: File
get() = dir.resolve("package.json.hash")
@@ -24,10 +23,10 @@ class PackageJsonUpToDateCheck(val npmProject: NpmProject) {
if (packageJsonHashFile.exists()) packageJsonHashFile.readText() else null
}
private val packageJsonFile = npmProject.prePackageJsonFile
private val packageJsonFile = npmProject.packageJsonFile
private val hash by lazy {
val hasher = (project as ProjectInternal).services.get(FileHasher::class.java)
val hasher = services.get(FileHasher::class.java)
hasher.hash(packageJsonFile).toByteArray().toHexString()
}
@@ -27,7 +27,10 @@ constructor(
private val nodeJs = npmProject.nodeJs
private val compilationResolution
get() = nodeJs.npmResolutionManager.requireInstalled()[project.path][npmProject.compilation]
get() = nodeJs.npmResolutionManager.requireInstalled(
services,
logger
)[project.path][npmProject.compilation]
init {
// TODO: temporary workaround for configuration cache enabled builds
@@ -14,8 +14,7 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.*
class KotlinCompilationNpmResolution(
@Transient
private val _project: Project?,
@Transient
private val _npmProject: NpmProject?,
val npmProject: NpmProject,
val internalDependencies: Collection<KotlinCompilationNpmResolution>,
val internalCompositeDependencies: Collection<GradleNodeModule>,
val externalGradleDependencies: Collection<GradleNodeModule>,
@@ -24,14 +23,12 @@ class KotlinCompilationNpmResolution(
) {
val project
get() = _project!!
val npmProject
get() = _npmProject!!
val externalNpmDependencies
get() = _externalNpmDependencies
.map {
NpmDependency(
project = project,
project = _project,
name = it.name,
version = it.version,
scope = it.scope,
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.gradle.targets.js.npm.resolved
import org.gradle.api.Project
internal class KotlinRootNpmResolution(
val rootProject: Project,
val rootProject: Project?,
internal val projects: Map<String, KotlinProjectNpmResolution>
) {
operator fun get(project: String) = projects[project] ?: KotlinProjectNpmResolution.empty(project)
@@ -59,7 +59,6 @@ internal class KotlinCompilationNpmResolver(
resolver.compositeNodeModules
}
@Transient
val npmProject = compilation.npmProject
val compilationName = compilation.name
@@ -463,7 +462,7 @@ internal class KotlinCompilationNpmResolver(
return KotlinCompilationNpmResolution(
if (compilation != null) project else null,
if (compilation != null) npmProject else null,
npmProject,
resolvedInternalDependencies,
compositeDependencies,
importedExternalGradleDependencies,
@@ -6,7 +6,8 @@
package org.jetbrains.kotlin.gradle.targets.js.npm.resolver
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.logging.Logger
import org.gradle.internal.service.ServiceRegistry
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.isMain
import org.jetbrains.kotlin.gradle.targets.js.dukat.DukatRootResolverPlugin
@@ -22,7 +23,6 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinProjectNpmResol
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinRootNpmResolution
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin
import org.jetbrains.kotlin.gradle.targets.js.yarn.toVersionString
import org.jetbrains.kotlin.gradle.tasks.registerTask
/**
* See [KotlinNpmResolutionManager] for details about resolution process.
@@ -34,6 +34,14 @@ internal class KotlinRootNpmResolver internal constructor(
val rootProject: Project
get() = nodeJs.rootProject
val rootProjectName by lazy {
rootProject.name
}
val rootProjectVersion by lazy {
rootProject.version.toString()
}
val plugins = mutableListOf<RootResolverPlugin>().also {
it.add(DukatRootResolverPlugin(this))
}
@@ -51,6 +59,10 @@ internal class KotlinRootNpmResolver internal constructor(
val compositeNodeModules = CompositeNodeModulesCache(nodeJs)
val projectResolvers = mutableMapOf<String, KotlinProjectNpmResolver>()
val yarn by lazy {
YarnPlugin.apply(rootProject)
}
fun alreadyResolvedMessage(action: String) = "Cannot $action. NodeJS projects already resolved."
@Synchronized
@@ -95,7 +107,7 @@ internal class KotlinRootNpmResolver internal constructor(
/**
* Don't use directly, use [KotlinNpmResolutionManager.installIfNeeded] instead.
*/
internal fun prepareInstallation(): Installation {
internal fun prepareInstallation(logger: Logger): Installation {
synchronized(this@KotlinRootNpmResolver) {
check(state == State.CONFIGURING) {
"Projects must be configuring"
@@ -109,14 +121,15 @@ internal class KotlinRootNpmResolver internal constructor(
gradleNodeModules.close()
val yarn = YarnPlugin.apply(rootProject)
nodeJs.packageManager.prepareRootProject(
rootProject,
nodeJs,
rootProjectName,
rootProjectVersion,
logger,
allNpmPackages,
yarn.resolutions
.associate { it.path to it.toVersionString() }
)
.associate { it.path to it.toVersionString() })
return Installation(
projectResolutions
@@ -130,7 +143,9 @@ internal class KotlinRootNpmResolver internal constructor(
internal fun install(
forceUpToDate: Boolean,
args: List<String>
args: List<String>,
services: ServiceRegistry,
logger: Logger
): KotlinRootNpmResolution {
synchronized(this@KotlinRootNpmResolver) {
check(state == State.PROJECTS_CLOSED) {
@@ -147,12 +162,15 @@ internal class KotlinRootNpmResolver internal constructor(
// we should call it even kotlinNpmInstall task is up-to-date (skipPackageManager is true)
// because our upToDateChecks saves state for next execution
val upToDateChecks = allNpmPackages.map {
PackageJsonUpToDateCheck(it.npmProject)
PackageJsonUpToDateCheck(services, it.npmProject)
}
val upToDate = forceUpToDate || upToDateChecks.all { it.upToDate }
nodeJs.packageManager.resolveRootProject(
nodeJs.rootProject,
services,
logger,
nodeJs,
yarn.requireConfigured().home,
allNpmPackages,
upToDate,
args
@@ -11,7 +11,6 @@ import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
import org.jetbrains.kotlin.gradle.utils.disableTaskOnConfigurationCacheBuild
import java.io.File
open class KotlinNpmInstallTask : DefaultTask() {
@@ -44,7 +43,7 @@ open class KotlinNpmInstallTask : DefaultTask() {
@get:InputFiles
val preparedFiles: Collection<File> by lazy {
nodeJs.packageManager.preparedFiles(project)
nodeJs.packageManager.preparedFiles(nodeJs)
}
// avoid using node_modules as output directory, as it is significantly slows down build
@@ -58,7 +57,11 @@ open class KotlinNpmInstallTask : DefaultTask() {
@TaskAction
fun resolve() {
resolutionManager.installIfNeeded(args = args)
resolutionManager.installIfNeeded(
args = args,
services = services,
logger = logger
)
}
companion object {
@@ -107,9 +107,9 @@ open class KotlinPackageJsonTask : DefaultTask() {
task.inputs.file(packageJsonTask.map { it.packageJson })
}
nodeJs.rootPackageJsonTaskProvider?.configure { it.mustRunAfter(packageJsonTask) }
nodeJs.rootPackageJsonTaskProvider!!.configure { it.mustRunAfter(packageJsonTask) }
compilation.compileKotlinTaskProvider.dependsOn(npmInstallTask)
compilation.compileKotlinTaskProvider.dependsOn(npmInstallTask!!)
compilation.compileKotlinTaskProvider.dependsOn(packageJsonTask)
return packageJsonTask
@@ -40,7 +40,7 @@ open class RootPackageJsonTask : DefaultTask() {
@TaskAction
fun resolve() {
resolutionManager.prepare()
resolutionManager.prepare(logger)
}
companion object {
@@ -250,7 +250,6 @@ constructor(
@TaskAction
fun doExecute() {
println(services.get(org.gradle.internal.logging.progress.ProgressLoggerFactory::class.java))
// nodeJs.npmResolutionManager?.checkRequiredDependencies(this)
val runner = createRunner()
@@ -6,6 +6,9 @@
package org.jetbrains.kotlin.gradle.targets.js.yarn
import org.gradle.api.Project
import org.gradle.api.logging.Logger
import org.gradle.internal.service.ServiceRegistry
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution
@@ -25,29 +28,43 @@ class Yarn : NpmApi {
override fun resolveProject(resolvedNpmProject: KotlinCompilationNpmResolution) =
getDelegate(resolvedNpmProject.project).resolveProject(resolvedNpmProject)
override fun preparedFiles(project: Project): Collection<File> =
getDelegate(project).preparedFiles(project)
override fun preparedFiles(nodeJs: NodeJsRootExtension): Collection<File> =
yarnWorkspaces.preparedFiles(nodeJs)
override fun prepareRootProject(
rootProject: Project,
rootProject: Project?,
nodeJs: NodeJsRootExtension,
rootProjectName: String,
rootProjectVersion: String,
logger: Logger,
subProjects: Collection<KotlinCompilationNpmResolution>,
resolutions: Map<String, String>
) = getDelegate(rootProject.project)
) = yarnWorkspaces
.prepareRootProject(
rootProject,
nodeJs,
rootProjectName,
rootProjectVersion,
logger,
subProjects,
resolutions
)
override fun resolveRootProject(
rootProject: Project,
services: ServiceRegistry,
logger: Logger,
nodeJs: NodeJsRootExtension,
yarnHome: File,
npmProjects: Collection<KotlinCompilationNpmResolution>,
skipExecution: Boolean,
cliArgs: List<String>
) {
getDelegate(rootProject.project)
yarnWorkspaces
.resolveRootProject(
rootProject,
services,
logger,
nodeJs,
yarnHome,
npmProjects,
skipExecution,
cliArgs
@@ -7,7 +7,10 @@ package org.jetbrains.kotlin.gradle.targets.js.yarn
import org.gradle.api.Project
import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.logging.Logger
import org.gradle.internal.service.ServiceRegistry
import org.jetbrains.kotlin.gradle.internal.execWithProgress
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency
@@ -25,19 +28,19 @@ abstract class YarnBasics : NpmApi {
}
fun yarnExec(
project: Project,
services: ServiceRegistry,
logger: Logger,
nodeJs: NodeJsRootExtension,
yarnHome: File,
dir: File,
description: String,
args: List<String>
) {
val nodeJs = NodeJsRootPlugin.apply(project)
val yarnPlugin = YarnPlugin.apply(project)
(project as ProjectInternal).services.execWithProgress(description) { exec ->
services.execWithProgress(description) { exec ->
exec.executable = nodeJs.requireConfigured().nodeExecutable
exec.args = listOf(yarnPlugin.requireConfigured().home.resolve("bin/yarn.js").absolutePath) +
exec.args = listOf(yarnHome.resolve("bin/yarn.js").absolutePath) +
args +
if (project.logger.isDebugEnabled) "--verbose" else ""
if (logger.isDebugEnabled) "--verbose" else ""
exec.workingDir = dir
}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.targets.js.yarn
import com.google.gson.Gson
import org.gradle.api.Project
import org.gradle.api.logging.Logger
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.PackageJson
@@ -15,7 +16,7 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmR
import java.io.File
class YarnImportedPackagesVersionResolver(
private val rootProject: Project,
private val logger: Logger,
private val npmProjects: Collection<KotlinCompilationNpmResolution>,
private val nodeJsWorldDir: File
) {
@@ -53,7 +54,7 @@ class YarnImportedPackagesVersionResolver(
modules.groupBy { it.name }.forEach { (name, versions) ->
val selected: GradleNodeModule = if (versions.size > 1) {
val sorted = versions.sortedBy { it.semver }
rootProject.logger.warn(
logger.warn(
"There are multiple versions of \"$name\" used in nodejs build: ${sorted.joinToString(", ") { it.version }}. " +
"Only latest version will be used."
)
@@ -17,7 +17,10 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.implementing
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.RootPackageJsonTask
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
open class YarnRootExtension(val project: Project) : ConfigurationPhaseAware<YarnEnv>() {
open class YarnRootExtension(
@Transient
val project: Project
) : ConfigurationPhaseAware<YarnEnv>() {
init {
check(project == project.rootProject)
}
@@ -6,6 +6,11 @@
package org.jetbrains.kotlin.gradle.targets.js.yarn
import org.gradle.api.Project
import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.logging.Logger
import org.gradle.internal.service.ServiceRegistry
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi
import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJsonUpToDateCheck
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution
@@ -17,28 +22,38 @@ class YarnSimple : YarnBasics() {
val project = resolvedNpmProject.project
PackageJsonUpToDateCheck(resolvedNpmProject.npmProject).updateIfNeeded {
yarnExec(
project,
resolvedNpmProject.npmProject.dir,
NpmApi.resolveOperationDescription("yarn for ${project.path}"),
emptyList()
)
yarnLockReadTransitiveDependencies(resolvedNpmProject.npmProject.dir, resolvedNpmProject.externalNpmDependencies)
}
// PackageJsonUpToDateCheck(resolvedNpmProject.npmProject).updateIfNeeded {
// yarnExec(
// (project as ProjectInternal).services,
// project.logger,
// NodeJsRootPlugin.apply(project),
// YarnPlugin.apply(project).requireConfigured().home,
// resolvedNpmProject.npmProject.dir,
// NpmApi.resolveOperationDescription("yarn for ${project.path}"),
// emptyList()
// )
// yarnLockReadTransitiveDependencies(resolvedNpmProject.npmProject.dir, resolvedNpmProject.externalNpmDependencies)
// }
}
override fun preparedFiles(project: Project): Collection<File> =
override fun preparedFiles(nodeJs: NodeJsRootExtension): Collection<File> =
emptyList()
override fun prepareRootProject(
rootProject: Project,
rootProject: Project?,
nodeJs: NodeJsRootExtension,
rootProjectName: String,
rootProjectVersion: String,
logger: Logger,
subProjects: Collection<KotlinCompilationNpmResolution>,
resolutions: Map<String, String>
) = Unit
override fun resolveRootProject(
rootProject: Project,
services: ServiceRegistry,
logger: Logger,
nodeJs: NodeJsRootExtension,
yarnHome: File,
npmProjects: Collection<KotlinCompilationNpmResolution>,
skipExecution: Boolean,
cliArgs: List<String>
@@ -6,6 +6,9 @@
package org.jetbrains.kotlin.gradle.targets.js.yarn
import org.gradle.api.Project
import org.gradle.api.logging.Logger
import org.gradle.internal.service.ServiceRegistry
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
@@ -16,37 +19,49 @@ import java.io.File
class YarnWorkspaces : YarnBasics() {
override fun resolveProject(resolvedNpmProject: KotlinCompilationNpmResolution) = Unit
override fun preparedFiles(project: Project): Collection<File> {
override fun preparedFiles(nodeJs: NodeJsRootExtension): Collection<File> {
return listOf(
NodeJsRootPlugin.apply(project.rootProject)
nodeJs
.rootPackageDir
.resolve(NpmProject.PACKAGE_JSON)
)
}
override fun prepareRootProject(
rootProject: Project,
rootProject: Project?,
nodeJs: NodeJsRootExtension,
rootProjectName: String,
rootProjectVersion: String,
logger: Logger,
subProjects: Collection<KotlinCompilationNpmResolution>,
resolutions: Map<String, String>
) {
check(rootProject == rootProject.rootProject)
setup(rootProject)
// check(rootProject == rootProject.rootProject)
rootProject?.let { setup(it) }
return prepareRootPackageJson(
rootProject,
nodeJs,
rootProjectName,
rootProjectVersion,
logger,
subProjects,
resolutions
)
}
private fun prepareRootPackageJson(
rootProject: Project,
nodeJs: NodeJsRootExtension,
rootProjectName: String,
rootProjectVersion: String,
logger: Logger,
npmProjects: Collection<KotlinCompilationNpmResolution>,
resolutions: Map<String, String>
) {
val rootPackageJsonFile = preparedFiles(rootProject).single()
val rootPackageJsonFile = preparedFiles(nodeJs).single()
saveRootProjectWorkspacesPackageJson(
rootProject,
rootProjectName,
rootProjectVersion,
logger,
npmProjects,
resolutions,
rootPackageJsonFile
@@ -54,16 +69,21 @@ class YarnWorkspaces : YarnBasics() {
}
override fun resolveRootProject(
rootProject: Project,
services: ServiceRegistry,
logger: Logger,
nodeJs: NodeJsRootExtension,
yarnHome: File,
npmProjects: Collection<KotlinCompilationNpmResolution>,
skipExecution: Boolean,
cliArgs: List<String>
) {
val nodeJs = NodeJsRootPlugin.apply(rootProject)
val nodeJsWorldDir = nodeJs.rootPackageDir
yarnExec(
rootProject,
services,
logger,
nodeJs,
yarnHome,
nodeJsWorldDir,
NpmApi.resolveOperationDescription("yarn"),
cliArgs
@@ -74,18 +94,20 @@ class YarnWorkspaces : YarnBasics() {
}
private fun saveRootProjectWorkspacesPackageJson(
rootProject: Project,
rootProjectName: String,
rootProjectVersion: String,
logger: Logger,
npmProjects: Collection<KotlinCompilationNpmResolution>,
resolutions: Map<String, String>,
rootPackageJsonFile: File
) {
val nodeJsWorldDir = rootPackageJsonFile.parentFile
val rootPackageJson = PackageJson(rootProject.name, rootProject.version.toString())
val rootPackageJson = PackageJson(rootProjectName, rootProjectVersion)
rootPackageJson.private = true
val npmProjectWorkspaces = npmProjects.map { it.npmProject.dir.relativeTo(nodeJsWorldDir).path }
val importedProjectWorkspaces =
YarnImportedPackagesVersionResolver(rootProject, npmProjects, nodeJsWorldDir).resolveAndUpdatePackages()
YarnImportedPackagesVersionResolver(logger, npmProjects, nodeJsWorldDir).resolveAndUpdatePackages()
rootPackageJson.workspaces = npmProjectWorkspaces + importedProjectWorkspaces
rootPackageJson.resolutions = resolutions