Skip to content

Commit

Permalink
#1
Browse files Browse the repository at this point in the history
  • Loading branch information
ilgonmic committed Dec 4, 2023
1 parent b2740d8 commit bdb9a7f
Show file tree
Hide file tree
Showing 17 changed files with 364 additions and 81 deletions.
Expand Up @@ -16,7 +16,7 @@ data class NodeJsEnv(
val ivyDependency: String,
val downloadBaseUrl: String,

val packageManager: NpmApi,
val packageManager: NpmApi<*>,
) {
val isWindows: Boolean
get() = platformName == "win"
Expand Down
Expand Up @@ -67,7 +67,7 @@ open class NodeJsRootExtension(

var nodeCommand by Property("node")

var packageManager: NpmApi by Property(Yarn())
var packageManager: NpmApi<*> by Property(Yarn())

val taskRequirements: TasksRequirements
get() = resolver.tasksRequirements
Expand All @@ -90,7 +90,7 @@ open class NodeJsRootExtension(
val name = platform.get().name
val architecture = platform.get().arch

val nodeDirName = "node-v$nodeVersion-$name-$architecture"
val nodeDirName = "node-v$version-$name-$architecture"
val cleanableStore = CleanableStore[installationDir.absolutePath]
val nodeDir = cleanableStore[nodeDirName].use()
val isWindows = platform.get().isWindows()
Expand All @@ -103,19 +103,19 @@ open class NodeJsRootExtension(

fun getIvyDependency(): String {
val type = if (isWindows) "zip" else "tar.gz"
return "org.nodejs:node:$nodeVersion:$name-$architecture@$type"
return "org.nodejs:node:$version:$name-$architecture@$type"
}

return NodeJsEnv(
cleanableStore = cleanableStore,
rootPackageDir = rootPackageDir,
nodeDir = nodeDir,
nodeBinDir = nodeBinDir,
nodeExecutable = getExecutable("node", nodeCommand, "exe"),
nodeExecutable = getExecutable("node", command, "exe"),
platformName = name,
architectureName = architecture,
ivyDependency = getIvyDependency(),
downloadBaseUrl = nodeDownloadBaseUrl,
downloadBaseUrl = downloadBaseUrl,
packageManager = packageManager
)
}
Expand Down
Expand Up @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinRootNpmResoluti
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinCompilationNpmResolver
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinProjectNpmResolver
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinRootNpmResolver
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnEnvironment

internal interface UsesKotlinNpmResolutionManager : Task {
@get:Internal
Expand Down Expand Up @@ -71,15 +72,15 @@ abstract class KotlinNpmResolutionManager : BuildService<KotlinNpmResolutionMana

internal fun prepare(
logger: Logger,
npmEnvironment: NpmEnvironment,
nodeJsEnvironment: NodeJsEnvironment,
yarnEnvironment: YarnEnvironment,
) = prepareIfNeeded(logger = logger, npmEnvironment, yarnEnvironment)
) = prepareIfNeeded(logger = logger, nodeJsEnvironment, yarnEnvironment)

internal fun installIfNeeded(
args: List<String> = emptyList(),
services: ServiceRegistry,
logger: Logger,
npmEnvironment: NpmEnvironment,
nodeJsEnvironment: NodeJsEnvironment,
yarnEnvironment: YarnEnvironment,
): Unit? {
synchronized(this) {
Expand All @@ -92,8 +93,8 @@ abstract class KotlinNpmResolutionManager : BuildService<KotlinNpmResolutionMana
}

return try {
val installation: Installation = prepareIfNeeded(logger = logger, npmEnvironment, yarnEnvironment)
installation.install(args, services, logger, npmEnvironment, yarnEnvironment)
val installation: Installation = prepareIfNeeded(logger = logger, nodeJsEnvironment, yarnEnvironment)
installation.install(args, services, logger, nodeJsEnvironment, yarnEnvironment)
state = ResolutionState.Installed()
} catch (e: Exception) {
state = ResolutionState.Error(e)
Expand All @@ -104,7 +105,7 @@ abstract class KotlinNpmResolutionManager : BuildService<KotlinNpmResolutionMana

private fun prepareIfNeeded(
logger: Logger,
npmEnvironment: NpmEnvironment,
nodeJsEnvironment: NodeJsEnvironment,
yarnEnvironment: YarnEnvironment,
): Installation {
val state0 = this.state
Expand All @@ -121,7 +122,7 @@ abstract class KotlinNpmResolutionManager : BuildService<KotlinNpmResolutionMana
is ResolutionState.Configuring -> {
state1.resolution.prepareInstallation(
logger,
npmEnvironment,
nodeJsEnvironment,
yarnEnvironment,
this
).also {
Expand Down
@@ -0,0 +1,142 @@
/*
* Copyright 2010-2023 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.logging.Logger
import org.gradle.internal.service.ServiceRegistry
import org.jetbrains.kotlin.gradle.internal.execWithProgress
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsEnv
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.PreparedKotlinCompilationNpmResolution
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnEnvironment
import java.io.File

class Npm : NpmApi<NpmEnvironment> {
override fun preparedFiles(nodeJs: NodeJsEnvironment): Collection<File> {
return listOf(
nodeJs
.rootPackageDir
.resolve(NpmProject.PACKAGE_JSON)
)
}

override fun prepareRootProject(
nodeJs: NodeJsEnvironment,
rootProjectName: String,
rootProjectVersion: String,
subProjects: Collection<PreparedKotlinCompilationNpmResolution>,
resolutions: Map<String, String>,
) {
return prepareRootPackageJson(
nodeJs,
rootProjectName,
rootProjectVersion,
subProjects,
resolutions
)
}

private fun prepareRootPackageJson(
nodeJs: NodeJsEnvironment,
rootProjectName: String,
rootProjectVersion: String,
npmProjects: Collection<PreparedKotlinCompilationNpmResolution>,
resolutions: Map<String, String>
) {
val rootPackageJsonFile = preparedFiles(nodeJs).single()

saveRootProjectWorkspacesPackageJson(
rootProjectName,
rootProjectVersion,
npmProjects,
resolutions,
rootPackageJsonFile
)
}

override fun resolveRootProject(
services: ServiceRegistry,
logger: Logger,
nodeJs: NodeJsEnvironment,
environment: NpmEnvironment,
npmProjects: Collection<PreparedKotlinCompilationNpmResolution>,
cliArgs: List<String>
) {
val nodeJsWorldDir = nodeJs.rootPackageDir

npmExec(
services,
logger,
nodeJs,
environment,
nodeJsWorldDir,
NpmApi.resolveOperationDescription("yarn"),
cliArgs
)
}

fun npmExec(
services: ServiceRegistry,
logger: Logger,
nodeJs: NodeJsEnvironment,
environment: NpmEnvironment,
dir: File,
description: String,
args: List<String>
) {
services.execWithProgress(description) { exec ->
val arguments = args
.plus(
if (logger.isDebugEnabled) "--verbose" else ""
)
.plus(
if (environment.ignoreScripts) "--ignore-scripts" else ""
).filter { it.isNotEmpty() }

val nodeExecutable = nodeJs.nodeExecutable
if (!environment.ignoreScripts) {
val nodePath = if (nodeJs.isWindows) {
File(nodeExecutable).parent
} else {
nodeExecutable
}
exec.environment(
"PATH",
"$nodePath${File.pathSeparator}${System.getenv("PATH")}"
)
}

val command = environment.executable

exec.executable = command
exec.args = arguments

exec.workingDir = dir
}

}

private fun saveRootProjectWorkspacesPackageJson(
rootProjectName: String,
rootProjectVersion: String,
npmProjects: Collection<PreparedKotlinCompilationNpmResolution>,
resolutions: Map<String, String>,
rootPackageJsonFile: File
) {
val nodeJsWorldDir = rootPackageJsonFile.parentFile
val rootPackageJson = PackageJson(rootProjectName, rootProjectVersion)
rootPackageJson.private = true

val npmProjectWorkspaces = npmProjects.map { it.npmProjectDir.relativeTo(nodeJsWorldDir).path }
val importedProjectWorkspaces =
NpmImportedPackagesVersionResolver(npmProjects, nodeJsWorldDir).resolveAndUpdatePackages()

rootPackageJson.workspaces = npmProjectWorkspaces + importedProjectWorkspaces
rootPackageJson.resolutions = resolutions
rootPackageJson.saveTo(
rootPackageJsonFile
)
}
}
Expand Up @@ -9,31 +9,28 @@ import org.gradle.api.logging.Logger
import org.gradle.internal.service.ServiceRegistry
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsEnv
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.PreparedKotlinCompilationNpmResolution
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnEnv
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnResolution
import java.io.File
import java.io.Serializable

/**
* NodeJS package manager API
*/
interface NpmApi : Serializable {
fun preparedFiles(nodeJs: NpmEnvironment): Collection<File>
interface NpmApi<T : Serializable> : Serializable {
fun preparedFiles(nodeJs: NodeJsEnvironment): Collection<File>

fun prepareRootProject(
nodeJs: NpmEnvironment,
nodeJs: NodeJsEnvironment,
rootProjectName: String,
rootProjectVersion: String,
logger: Logger,
subProjects: Collection<PreparedKotlinCompilationNpmResolution>,
resolutions: Map<String, String>,
)

fun resolveRootProject(
services: ServiceRegistry,
logger: Logger,
nodeJs: NpmEnvironment,
yarn: YarnEnvironment,
nodeJs: NodeJsEnvironment,
packageManagerEnvironment: T,
npmProjects: Collection<PreparedKotlinCompilationNpmResolution>,
cliArgs: List<String>
)
Expand All @@ -44,32 +41,17 @@ interface NpmApi : Serializable {
}
}

data class NpmEnvironment(
data class NodeJsEnvironment(
val rootPackageDir: File,
val nodeExecutable: String,
val isWindows: Boolean,
val packageManager: NpmApi
val packageManager: NpmApi<*>
) : Serializable

internal val NodeJsEnv.asNpmEnvironment
get() = NpmEnvironment(
internal val NodeJsEnv.asNodeJsEnvironment
get() = NodeJsEnvironment(
rootPackageDir,
nodeExecutable,
isWindows,
packageManager
)

data class YarnEnvironment(
val executable: String,
val standalone: Boolean,
val ignoreScripts: Boolean,
val yarnResolutions: List<YarnResolution>
) : Serializable

internal val YarnEnv.asYarnEnvironment
get() = YarnEnvironment(
executable,
standalone,
ignoreScripts,
yarnResolutions
)
@@ -0,0 +1,12 @@
/*
* Copyright 2010-2023 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

data class NpmEnv(
val executable: String,
val ignoreScripts: Boolean,
val overrides: List<NpmOverride>
)
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2023 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 java.io.Serializable

data class NpmEnvironment(
val executable: String,
val ignoreScripts: Boolean,
val overrides: List<NpmOverride>
) : Serializable

internal val NpmEnv.asNpmEnvironment
get() = NpmEnvironment(
executable,
ignoreScripts,
overrides
)

0 comments on commit bdb9a7f

Please sign in to comment.