[Gradle, JS] Fix uname system call for configuration cache compatibility

[Gradle, JS] Fix problem with configuration cache in KotlinKarma

^KT-58969 fixed
^KT-58970 fixed
This commit is contained in:
Ilya Goncharov
2023-06-05 15:21:34 +00:00
committed by Space Team
parent d81084f66f
commit d1b775f157
20 changed files with 571 additions and 110 deletions
@@ -0,0 +1,50 @@
/*
* 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
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType
import org.jetbrains.kotlin.gradle.testbase.*
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.condition.OS
// This test is a JS test
// but, as it is the only one to required to run on MacOS
// we are running this test as a part of Native tests
// This allows us to keep CI configuration simpler.
@OsCondition(supportedOn = [OS.LINUX, OS.MAC, OS.WINDOWS], enabledOnCI = [OS.LINUX, OS.MAC, OS.WINDOWS])
@NativeGradlePluginTests
class JsSetupConfigurationCacheIT : KGPBaseTest() {
@Suppress("DEPRECATION")
private val defaultJsOptions = BuildOptions.JsOptions(
useIrBackend = true,
jsCompilerType = KotlinJsCompilerType.IR
)
override val defaultBuildOptions =
super.defaultBuildOptions.copy(
jsOptions = defaultJsOptions,
configurationCache = true,
configurationCacheProblems = BaseGradleIT.ConfigurationCacheProblems.FAIL
)
// hack to be run on Mac m*
@DisplayName("Check Node.JS setup on different platforms")
@GradleTest
fun checkNodeJsSetup(gradleVersion: GradleVersion) {
project("kotlin-js-browser-project", gradleVersion) {
build("kotlinUpgradeYarnLock") {
assertTasksExecuted(":kotlinUpgradeYarnLock")
assertConfigurationCacheStored()
}
build("kotlinUpgradeYarnLock") {
assertTasksUpToDate(":kotlinUpgradeYarnLock")
assertConfigurationCacheReused()
}
}
}
}
@@ -45,6 +45,8 @@ import org.jetbrains.kotlin.gradle.report.BuildMetricsService
import org.jetbrains.kotlin.gradle.plugin.statistics.BuildFlowService
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsCompilerAttribute
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsPlugin
import org.jetbrains.kotlin.gradle.targets.js.nodejs.DefaultUnameExecutorVariantFactory
import org.jetbrains.kotlin.gradle.targets.js.nodejs.UnameExecutor
import org.jetbrains.kotlin.gradle.targets.js.npm.addNpmDependencyExtension
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropKlibLibraryElements
@@ -185,6 +187,11 @@ abstract class DefaultKotlinBasePlugin : KotlinBasePlugin {
CompatibilityConventionRegistrar.Factory::class,
DefaultCompatibilityConventionRegistrar.Factory()
)
factories.putIfAbsent(
UnameExecutor.UnameExecutorVariantFactory::class,
DefaultUnameExecutorVariantFactory()
)
}
protected fun setupAttributeMatchingStrategy(
@@ -21,10 +21,11 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.RootPackageJsonTask
import org.jetbrains.kotlin.gradle.targets.js.yarn.Yarn
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockCopyTask
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
import org.jetbrains.kotlin.gradle.utils.property
import java.io.File
open class NodeJsRootExtension(
val project: Project
val project: Project,
) : ConfigurationPhaseAware<NodeJsEnv>() {
init {
@@ -81,17 +82,18 @@ open class NodeJsRootExtension(
val nodeModulesGradleCacheDir: File
get() = rootPackageDir.resolve("packages_imported")
internal val platform: org.gradle.api.provider.Property<Platform> = project.objects.property<Platform>()
val versions = NpmVersions()
override fun finalizeConfiguration(): NodeJsEnv {
val platformHelper = PlatformHelper
val platform = platformHelper.osName
val architecture = platformHelper.osArch
val name = platform.get().name
val architecture = platform.get().arch
val nodeDirName = "node-v$nodeVersion-$platform-$architecture"
val nodeDirName = "node-v$nodeVersion-$name-$architecture"
val cleanableStore = CleanableStore[installationDir.absolutePath]
val nodeDir = cleanableStore[nodeDirName].use()
val isWindows = platformHelper.isWindows
val isWindows = platform.get().isWindows()
val nodeBinDir = if (isWindows) nodeDir else nodeDir.resolve("bin")
fun getExecutable(command: String, customCommand: String, windowsExtension: String): String {
@@ -101,7 +103,7 @@ open class NodeJsRootExtension(
fun getIvyDependency(): String {
val type = if (isWindows) "zip" else "tar.gz"
return "org.nodejs:node:$nodeVersion:$platform-$architecture@$type"
return "org.nodejs:node:$nodeVersion:$name-$architecture@$type"
}
return NodeJsEnv(
@@ -110,7 +112,7 @@ open class NodeJsRootExtension(
nodeDir = nodeDir,
nodeBinDir = nodeBinDir,
nodeExecutable = getExecutable("node", nodeCommand, "exe"),
platformName = platform,
platformName = name,
architectureName = architecture,
ivyDependency = getIvyDependency(),
downloadBaseUrl = nodeDownloadBaseUrl,
@@ -10,6 +10,10 @@ import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.plugins.BasePlugin
import org.gradle.api.provider.Provider
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.plugin.internal.configurationTimePropertiesAccessor
import org.jetbrains.kotlin.gradle.plugin.internal.usedAtConfigurationTime
import org.jetbrains.kotlin.gradle.plugin.variantImplementationFactory
import org.jetbrains.kotlin.gradle.targets.js.MultiplePluginDeclarationDetector
import org.jetbrains.kotlin.gradle.targets.js.npm.GradleNodeModulesCache
import org.jetbrains.kotlin.gradle.targets.js.npm.KotlinNpmResolutionManager
@@ -23,11 +27,6 @@ import org.jetbrains.kotlin.gradle.tasks.CleanDataTask
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.tasks.withType
import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.gradle.utils.SingleActionPerProject
import org.jetbrains.kotlin.gradle.utils.castIsolatedKotlinPluginClassLoaderAware
import org.jetbrains.kotlin.gradle.utils.doNotTrackStateCompat
import org.jetbrains.kotlin.gradle.utils.markResolvable
import org.jetbrains.kotlin.gradle.utils.providerWithLazyConvention
open class NodeJsRootPlugin : Plugin<Project> {
override fun apply(project: Project) {
@@ -45,6 +44,8 @@ open class NodeJsRootPlugin : Plugin<Project> {
project
)
addPlatform(project, nodeJs)
val setupTask = project.registerTask<NodeJsSetupTask>(NodeJsSetupTask.NAME) {
it.group = TASKS_GROUP_NAME
it.description = "Download and install a local node/npm version"
@@ -131,6 +132,24 @@ open class NodeJsRootPlugin : Plugin<Project> {
}
}
// from https://github.com/node-gradle/gradle-node-plugin
private fun addPlatform(project: Project, extension: NodeJsRootExtension) {
val uname = project.variantImplementationFactory<UnameExecutor.UnameExecutorVariantFactory>()
.getInstance(project)
.unameExecResult
extension.platform.value(
project.providers.systemProperty("os.name")
.usedAtConfigurationTime(project.configurationTimePropertiesAccessor)
.zip(
project.providers.systemProperty("os.arch")
.usedAtConfigurationTime(project.configurationTimePropertiesAccessor)
) { name, arch ->
parsePlatform(name, arch, uname)
}
).disallowChanges()
}
companion object {
const val TASKS_GROUP_NAME: String = "nodeJs"
@@ -0,0 +1,76 @@
// from https://github.com/node-gradle/gradle-node-plugin
package org.jetbrains.kotlin.gradle.targets.js.nodejs
import org.gradle.api.provider.Provider
import java.io.File
internal data class Platform(
val name: String,
val arch: String,
) {
fun isWindows(): Boolean {
return name == "win"
}
}
internal fun parsePlatform(name: String, arch: String, uname: Provider<String>): Platform {
return Platform(
parseOsName(name.toLowerCase()),
parseOsArch(
arch.toLowerCase(),
uname
)
)
}
internal fun parseOsName(name: String): String {
return when {
name.contains("windows") -> "win"
name.contains("mac") -> "darwin"
name.contains("linux") -> "linux"
name.contains("freebsd") -> "linux"
name.contains("sunos") -> "sunos"
else -> error("Unsupported OS: $name")
}
}
internal fun parseOsArch(arch: String, uname: Provider<String>): String {
return when {
/*
* As Java just returns "arm" on all ARM variants, we need a system call to determine the exact arch. Unfortunately some JVMs say aarch32/64, so we need an additional
* conditional. Additionally, the node binaries for 'armv8l' are called 'arm64', so we need to distinguish here.
*/
arch == "arm" || arch.startsWith("aarch") -> uname.get()
.let {
if (it == "armv8l" || it == "aarch64") {
"arm64"
} else it
}
.let {
if (it == "x86_64") {
"x64"
} else it
}
arch == "ppc64le" -> "ppc64le"
arch == "s390x" -> "s390x"
arch.contains("64") -> "x64"
else -> "x86"
}
}
internal fun computeNpmScriptFile(
nodeDirProvider: File,
command: String,
isWindows: Boolean
): String {
return nodeDirProvider.let { nodeDir ->
if (isWindows) nodeDir.resolve("node_modules/npm/bin/$command-cli.js").path
else nodeDir.resolve("lib/node_modules/npm/bin/$command-cli.js").path
}
}
internal fun computeNodeBinDir(
nodeDirProvider: File,
isWindows: Boolean
) =
if (isWindows) nodeDirProvider else nodeDirProvider.resolve("bin")
@@ -1,91 +0,0 @@
package org.jetbrains.kotlin.gradle.targets.js.nodejs
import java.io.File
import java.util.concurrent.TimeUnit
object PlatformHelper {
val osName: String by lazy {
val name = property("os.name").toLowerCase()
when {
name.contains("windows") -> "win"
name.contains("mac") -> "darwin"
name.contains("linux") -> "linux"
name.contains("freebsd") -> "linux"
name.contains("sunos") -> "sunos"
else -> error("Unsupported OS: $name")
}
}
val osArch: String by lazy {
val arch = property("os.arch").toLowerCase()
when {
/*
* As Java just returns "arm" on all ARM variants, we need a system call to determine the exact arch. Unfortunately some JVMs say aarch32/64, so we need an additional
* conditional. Additionally, the node binaries for 'armv8l' are called 'arm64', so we need to distinguish here.
*/
arch == "arm" || arch.startsWith("aarch") -> property("uname")
.let {
if (it == "armv8l" || it == "aarch64") {
"arm64"
} else it
}
.let {
if (it == "x86_64") {
"x64"
} else it
}
arch == "ppc64le" -> "ppc64le"
arch == "s390x" -> "s390x"
arch.contains("64") -> "x64"
else -> "x86"
}
}
val isWindows: Boolean by lazy { osName == "win" }
private fun property(name: String): String {
return getSystemProperty(name) ?:
// Added so that we can test osArch on Windows and on non-arm systems
if (name == "uname") execute("uname", "-m")
else error("Unable to find a value for property [$name].")
}
private fun getSystemProperty(name: String): String? {
return System.getProperty(name);
}
}
fun computeNpmScriptFile(
nodeDirProvider: File,
command: String,
isWindows: Boolean
): String {
return nodeDirProvider.let { nodeDir ->
if (isWindows) nodeDir.resolve("node_modules/npm/bin/$command-cli.js").path
else nodeDir.resolve("lib/node_modules/npm/bin/$command-cli.js").path
}
}
fun computeNodeBinDir(
nodeDirProvider: File,
isWindows: Boolean
) =
if (isWindows) nodeDirProvider else nodeDirProvider.resolve("bin")
/**
* Executes the given command and returns its output.
*
* This is based on an aggregate of the answers provided here: [https://stackoverflow.com/questions/35421699/how-to-invoke-external-command-from-within-kotlin-code]
*/
private fun execute(vararg args: String, timeout: Long = 60): String {
return ProcessBuilder(args.toList())
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.start()
.apply { waitFor(timeout, TimeUnit.SECONDS) }
.inputStream.bufferedReader().readText().trim()
}
@@ -0,0 +1,37 @@
/*
* 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.nodejs
import org.gradle.api.Project
import org.gradle.api.provider.Provider
import org.gradle.api.provider.ProviderFactory
import org.jetbrains.kotlin.gradle.plugin.VariantImplementationFactories
internal interface UnameExecutor {
val unameExecResult: Provider<String>
interface UnameExecutorVariantFactory : VariantImplementationFactories.VariantImplementationFactory {
fun getInstance(project: Project): UnameExecutor
}
}
internal class DefaultUnameExecutorVariantFactory : UnameExecutor.UnameExecutorVariantFactory {
override fun getInstance(project: Project): UnameExecutor = DefaultUnameExecutor(project.providers)
}
internal class DefaultUnameExecutor(
private val providerFactory: ProviderFactory,
) : UnameExecutor {
override val unameExecResult: Provider<String>
get() {
val cmd = providerFactory.exec {
it.executable = "uname"
it.args = listOf("-m")
}
return cmd.standardOutput.asText.map { it.trim() }
}
}
@@ -53,6 +53,8 @@ class KotlinKarma(
private val project: Project = compilation.target.project
private val npmProject = compilation.npmProject
private val platformType = compilation.platformType
@Transient
private val nodeJs = project.rootProject.kotlinNodeJsExtension
private val nodeRootPackageDir by lazy { nodeJs.rootPackageDir }
@@ -333,7 +335,7 @@ class KotlinKarma(
config.files.add(npmProject.require("kotlin-test-js-runner/kotlin-test-karma-runner.js"))
if (!debug) {
if (compilation.platformType == KotlinPlatformType.wasm) {
if (platformType == KotlinPlatformType.wasm) {
val wasmFile = file.parentFile.resolve("${file.nameWithoutExtension}.wasm")
val wasmFileString = wasmFile.normalize().absolutePath
config.files.add(
@@ -39,6 +39,9 @@ open class YarnPlugin : Plugin<Project> {
val nodeJs = this.kotlinNodeJsExtension
val nodeJsTaskProviders = this.kotlinNodeJsExtension
yarnRootExtension.platform.value(nodeJs.platform)
.disallowChanges()
val setupTask = registerTask<YarnSetupTask>(YarnSetupTask.NAME) {
it.dependsOn(nodeJsTaskProviders.nodeJsSetupTaskProvider)
@@ -5,15 +5,12 @@
package org.jetbrains.kotlin.gradle.targets.js.yarn
import org.jetbrains.kotlin.gradle.targets.js.nodejs.PlatformHelper
import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.internal.ConfigurationPhaseAware
import org.jetbrains.kotlin.gradle.logging.kotlinInfo
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.implementing
import org.jetbrains.kotlin.gradle.targets.js.nodejs.Platform
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.RootPackageJsonTask
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
import java.io.File
@@ -58,6 +55,8 @@ open class YarnRootExtension(
.withType(RootPackageJsonTask::class.java)
.named(RootPackageJsonTask.NAME)
internal val platform: org.gradle.api.provider.Property<Platform> = project.objects.property(Platform::class.java)
var resolutions: MutableList<YarnResolution> by Property(mutableListOf())
fun resolution(path: String, configure: Action<YarnResolution>) {
@@ -76,7 +75,7 @@ open class YarnRootExtension(
override fun finalizeConfiguration(): YarnEnv {
val cleanableStore = CleanableStore[installationDir.path]
val isWindows = PlatformHelper.isWindows
val isWindows = platform.get().isWindows()
val home = cleanableStore["yarn-v$version"].use()
@@ -15,6 +15,7 @@ import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.gradle.plugin.internal.*
import org.jetbrains.kotlin.gradle.plugin.internal.BasePluginConfigurationG70
import org.jetbrains.kotlin.gradle.plugin.internal.JavaSourceSetsAccessorG70
import org.jetbrains.kotlin.gradle.targets.js.nodejs.UnameExecutor
import javax.inject.Inject
private const val PLUGIN_VARIANT_NAME = "gradle70"
@@ -163,4 +164,6 @@ private fun Project.registerVariantImplementations() {
ProjectIsolationStartParameterAccessorG70.Factory()
factories[CompatibilityConventionRegistrar.Factory::class] =
CompatibilityConventionRegistrarG70.Factory()
factories[UnameExecutor.UnameExecutorVariantFactory::class] =
UnameExecutorG70.UnameExecutorVariantFactoryG70()
}
@@ -0,0 +1,35 @@
/*
* 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.plugin.internal
import org.gradle.api.Project
import org.gradle.api.provider.Provider
import org.jetbrains.kotlin.gradle.targets.js.nodejs.UnameExecutor
import java.io.ByteArrayOutputStream
internal class UnameExecutorG70(
private val project: Project,
) : UnameExecutor {
override val unameExecResult: Provider<String>
get() {
return project.provider {
val out = ByteArrayOutputStream()
val cmd = project.exec {
it.executable = "uname"
it.args = listOf("-m")
it.standardOutput = out
}
cmd.assertNormalExitValue()
out.toString().trim()
}
}
internal class UnameExecutorVariantFactoryG70 : UnameExecutor.UnameExecutorVariantFactory {
override fun getInstance(project: Project): UnameExecutor = UnameExecutorG70(project)
}
}
@@ -15,6 +15,7 @@ import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.gradle.plugin.internal.*
import org.jetbrains.kotlin.gradle.plugin.internal.ConfigurationTimePropertiesAccessorG71
import org.jetbrains.kotlin.gradle.plugin.internal.IdeaSyncDetectorG71
import org.jetbrains.kotlin.gradle.targets.js.nodejs.UnameExecutor
import javax.inject.Inject
private const val PLUGIN_VARIANT_NAME = "gradle71"
@@ -164,4 +165,6 @@ private fun Project.registerVariantImplementations() {
ProjectIsolationStartParameterAccessorG71.Factory()
factories[CompatibilityConventionRegistrar.Factory::class] =
CompatibilityConventionRegistrarG71.Factory()
factories[UnameExecutor.UnameExecutorVariantFactory::class] =
UnameExecutorG71.UnameExecutorVariantFactoryG71()
}
@@ -0,0 +1,35 @@
/*
* 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.plugin.internal
import org.gradle.api.Project
import org.gradle.api.provider.Provider
import org.jetbrains.kotlin.gradle.targets.js.nodejs.UnameExecutor
import java.io.ByteArrayOutputStream
internal class UnameExecutorG71(
private val project: Project,
) : UnameExecutor {
override val unameExecResult: Provider<String>
get() {
return project.provider {
val out = ByteArrayOutputStream()
val cmd = project.exec {
it.executable = "uname"
it.args = listOf("-m")
it.standardOutput = out
}
cmd.assertNormalExitValue()
out.toString().trim()
}
}
internal class UnameExecutorVariantFactoryG71 : UnameExecutor.UnameExecutorVariantFactory {
override fun getInstance(project: Project): UnameExecutor = UnameExecutorG71(project)
}
}
@@ -13,6 +13,7 @@ import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.model.ObjectFactory
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.gradle.plugin.internal.*
import org.jetbrains.kotlin.gradle.targets.js.nodejs.UnameExecutor
import javax.inject.Inject
private const val PLUGIN_VARIANT_NAME = "gradle74"
@@ -153,4 +154,6 @@ private fun Project.registerVariantImplementations() {
ProjectIsolationStartParameterAccessorG74.Factory()
factories[CompatibilityConventionRegistrar.Factory::class] =
CompatibilityConventionRegistrarG74.Factory()
factories[UnameExecutor.UnameExecutorVariantFactory::class] =
UnameExecutorG74.UnameExecutorVariantFactoryG74()
}
@@ -0,0 +1,35 @@
/*
* 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.plugin.internal
import org.gradle.api.Project
import org.gradle.api.provider.Provider
import org.jetbrains.kotlin.gradle.targets.js.nodejs.UnameExecutor
import java.io.ByteArrayOutputStream
internal class UnameExecutorG74(
private val project: Project,
) : UnameExecutor {
override val unameExecResult: Provider<String>
get() {
return project.provider {
val out = ByteArrayOutputStream()
val cmd = project.exec {
it.executable = "uname"
it.args = listOf("-m")
it.standardOutput = out
}
cmd.assertNormalExitValue()
out.toString().trim()
}
}
internal class UnameExecutorVariantFactoryG74 : UnameExecutor.UnameExecutorVariantFactory {
override fun getInstance(project: Project): UnameExecutor = UnameExecutorG74(project)
}
}
@@ -14,6 +14,7 @@ import org.gradle.api.model.ObjectFactory
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.gradle.plugin.internal.*
import org.jetbrains.kotlin.gradle.plugin.internal.JavaSourceSetsAccessorG6
import org.jetbrains.kotlin.gradle.targets.js.nodejs.UnameExecutor
import javax.inject.Inject
private const val PLUGIN_VARIANT_NAME = "main"
@@ -169,4 +170,6 @@ private fun Project.registerVariantImplementations() {
ProjectIsolationStartParameterAccessorG6.Factory()
factories[CompatibilityConventionRegistrar.Factory::class] =
CompatibilityConventionRegistrarG6.Factory()
factories[UnameExecutor.UnameExecutorVariantFactory::class] =
UnameExecutorG6.UnameExecutorVariantFactoryG6()
}
@@ -0,0 +1,35 @@
/*
* 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.plugin.internal
import org.gradle.api.Project
import org.gradle.api.provider.Provider
import org.jetbrains.kotlin.gradle.targets.js.nodejs.UnameExecutor
import java.io.ByteArrayOutputStream
internal class UnameExecutorG6(
private val project: Project,
) : UnameExecutor {
override val unameExecResult: Provider<String>
get() {
return project.provider {
val out = ByteArrayOutputStream()
val cmd = project.exec {
it.executable = "uname"
it.args = listOf("-m")
it.standardOutput = out
}
cmd.assertNormalExitValue()
out.toString().trim()
}
}
internal class UnameExecutorVariantFactoryG6 : UnameExecutor.UnameExecutorVariantFactory {
override fun getInstance(project: Project): UnameExecutor = UnameExecutorG6(project)
}
}