Skip to content

NPM Exec ValueSource #337

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 47 additions & 7 deletions src/main/kotlin/com/github/gradle/node/NodeExtension.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,29 @@
package com.github.gradle.node

import com.github.gradle.node.npm.exec.NpmExecResult
import com.github.gradle.node.npm.exec.NpmExecSource
import com.github.gradle.node.npm.exec.NpmExecSpec
import com.github.gradle.node.npm.proxy.ProxySettings
import com.github.gradle.node.util.Platform
import com.github.gradle.node.variant.VariantComputer
import com.github.gradle.node.variant.computeNodeExec
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.provider.ProviderFactory
import org.gradle.kotlin.dsl.create
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.of
import org.gradle.kotlin.dsl.property

open class NodeExtension(project: Project) {
import javax.inject.Inject

abstract class NodeExtension
@Inject
internal constructor(
project: Project,
private val providers: ProviderFactory,
) {
private val cacheDir = project.layout.projectDirectory.dir(".gradle")

/**
Expand All @@ -18,7 +34,7 @@ open class NodeExtension(project: Project) {
/**
* The directory where npm is installed (when a specific version is defined)
*/
val npmWorkDir = project.objects.directoryProperty().convention(cacheDir.dir("npm"))
val npmWorkDir: DirectoryProperty = project.objects.directoryProperty().convention(cacheDir.dir("npm"))

/**
* The directory where pnpm is installed (when a pnpm task is used)
Expand Down Expand Up @@ -53,7 +69,7 @@ open class NodeExtension(project: Project) {
* If specified, installs it in the npmWorkDir
* If empty, the plugin will use the npm command bundled with Node.js
*/
val npmVersion = project.objects.property<String>().convention("")
val npmVersion: Property<String> = project.objects.property<String>().convention("")

/**
* Version of pnpm to use
Expand Down Expand Up @@ -111,7 +127,7 @@ open class NodeExtension(project: Project) {
* If true, it will download node using above parameters
* Note that npm is bundled with Node.js
*/
val download = project.objects.property<Boolean>().convention(false)
val download: Property<Boolean> = project.objects.property<Boolean>().convention(false)

/**
* Whether the plugin automatically should add the proxy configuration to npm and yarn commands
Expand Down Expand Up @@ -168,7 +184,7 @@ open class NodeExtension(project: Project) {
/**
* Computed path to nodejs directory
*/
val resolvedNodeDir = project.objects.directoryProperty()
val resolvedNodeDir: DirectoryProperty = project.objects.directoryProperty()

/**
* Operating system and architecture
Expand All @@ -179,7 +195,7 @@ open class NodeExtension(project: Project) {
/**
* Operating system and architecture
*/
val resolvedPlatform = project.objects.property<Platform>()
val resolvedPlatform: Property<Platform> = project.objects.property<Platform>()

init {
distBaseUrl.set("https://nodejs.org/dist")
Expand All @@ -193,6 +209,30 @@ open class NodeExtension(project: Project) {
nodeProxySettings.set(if (value) ProxySettings.SMART else ProxySettings.OFF)
}

@Suppress("UnstableApiUsage")
fun npmExec(
configuration: NpmExecSpec.() -> Unit
): Provider<NpmExecResult> {

val vc = VariantComputer()
val nodeDirProvider = resolvedNodeDir
val npmDirProvider = vc.computeNpmDir(this, nodeDirProvider)
val nodeBinDirProvider = vc.computeNodeBinDir(nodeDirProvider, resolvedPlatform)
val npmBinDirProvider = vc.computeNpmBinDir(npmDirProvider, resolvedPlatform)
val nodeExecProvider = computeNodeExec(this, nodeBinDirProvider)

vc.computeNpmExec(this, npmBinDirProvider)

return providers.of(NpmExecSource::class) {
parameters.apply(configuration)
// parameters {
// executable
// ignoreExitValue
// workingDir
// }
}
}

companion object {
/**
* Extension name in Gradle
Expand Down
30 changes: 30 additions & 0 deletions src/main/kotlin/com/github/gradle/node/npm/exec/NpmExecResult.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.github.gradle.node.npm.exec

import org.gradle.api.GradleException
import org.gradle.process.ExecResult

class NpmExecResult internal constructor(
val exitValue: Int,
val failure: GradleException?,
val capturedOutput: String,
) {

internal fun asExecResult(): ExecResult = object : ExecResult {

override fun assertNormalExitValue(): ExecResult {
if (failure != null) {
throw failure
}
return this
}

override fun getExitValue(): Int = exitValue

override fun rethrowFailure(): ExecResult {
assertNormalExitValue()
return this
}
}

override fun toString(): String = "NpmExecResult(exitValue=$exitValue, failure=$failure)"
}
48 changes: 31 additions & 17 deletions src/main/kotlin/com/github/gradle/node/npm/exec/NpmExecRunner.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,26 @@ abstract class NpmExecRunner {
project: ProjectApiHelper,
extension: NodeExtension,
nodeExecConfiguration: NodeExecConfiguration,
variants: VariantComputer
variants: VariantComputer,
): ExecResult {
val npmExecConfiguration = NpmExecConfiguration(
"npm"
) { variantComputer, nodeExtension, npmBinDir -> variantComputer.computeNpmExec(nodeExtension, npmBinDir) }
command = "npm",
commandExecComputer = { variantComputer, nodeExtension, npmBinDir ->
variantComputer.computeNpmExec(
nodeExtension,
npmBinDir
)
}
)
return executeCommand(
project,
extension,
NpmProxy.addProxyEnvironmentVariables(extension.nodeProxySettings.get(), nodeExecConfiguration),
npmExecConfiguration,
variants
project = project,
extension = extension,
nodeExecConfiguration = NpmProxy.addProxyEnvironmentVariables(
proxySettings = extension.nodeProxySettings.get(),
nodeExecConfiguration = nodeExecConfiguration
),
npmExecConfiguration = npmExecConfiguration,
variantComputer = variants
)
}

Expand Down Expand Up @@ -78,9 +87,13 @@ abstract class NpmExecRunner {
if (executableAndScript.script != null) listOf(executableAndScript.script) else listOf()
val args = argsPrefix.plus(nodeExecConfiguration.command)
ExecConfiguration(
executableAndScript.executable, args, additionalBinPath,
nodeExecConfiguration.environment, nodeExecConfiguration.workingDir,
nodeExecConfiguration.ignoreExitValue, nodeExecConfiguration.execOverrides
executable = executableAndScript.executable,
args = args,
additionalBinPaths = additionalBinPath,
environment = nodeExecConfiguration.environment,
workingDir = nodeExecConfiguration.workingDir,
ignoreExitValue = nodeExecConfiguration.ignoreExitValue,
execOverrides = nodeExecConfiguration.execOverrides,
)
}
}
Expand All @@ -101,11 +114,12 @@ abstract class NpmExecRunner {
val npmScriptFileProvider =
computeNpmScriptFile(nodeDirProvider, npmExecConfiguration.command, isWindows)
return zip(
nodeExtension.download, nodeExtension.nodeProjectDir, executableProvider, nodeExecProvider,
npmScriptFileProvider
).map {
val (download, nodeProjectDir, executable, nodeExec,
npmScriptFile) = it
nodeExtension.download,
nodeExtension.nodeProjectDir,
executableProvider,
nodeExecProvider,
npmScriptFileProvider,
).map { (download, nodeProjectDir, executable, nodeExec, npmScriptFile) ->
if (download) {
val localCommandScript = nodeProjectDir.dir("node_modules/npm/bin")
.file("${npmExecConfiguration.command}-cli.js").asFile
Expand All @@ -121,7 +135,7 @@ abstract class NpmExecRunner {

private data class ExecutableAndScript(
val executable: String,
val script: String? = null
val script: String? = null,
)

private fun computeAdditionalBinPath(
Expand Down
Loading