diff --git a/CHANGELOG.md b/CHANGELOG.md index aafac324..21a9ea4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## Version 7.x *(unreleased)* +## Version 7.1.0 *(2024-09-27)* +* Add support for ARM64 Windows [#315](https://github.com/node-gradle/gradle-node-plugin/issues/315) +* Add support for AIX [#320](https://github.com/node-gradle/gradle-node-plugin/issues/320) +* Add license to publications POM [#319](https://github.com/node-gradle/gradle-node-plugin/issues/319) + ## Version 7.0.2 *(2024-02-02)* * Prevent misconfigured `workDir` from removing all unrelated files [#297](https://github.com/node-gradle/gradle-node-plugin/issues/297) diff --git a/README.md b/README.md index 1d47c229..0cb258ab 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ![Build Status](https://github.com/node-gradle/gradle-node-plugin/workflows/Build/badge.svg?branch=main) [![License](https://img.shields.io/github/license/node-gradle/gradle-node-plugin.svg)](http://www.apache.org/licenses/LICENSE-2.0.html) -![Version](https://img.shields.io/badge/Version-7.0.2-orange.svg) +![Version](https://img.shields.io/badge/Version-7.1.0-orange.svg) This plugin enables you to use a lot of [Node.js](https://nodejs.org)-based technologies as part of your build without having Node.js installed locally on your system. It integrates the following Node.js-based system @@ -39,7 +39,8 @@ issue to [GitHub Issues](https://github.com/node-gradle/gradle-node-plugin/issue Here's the documentation for older releases of the plugin: -* [7.0.2](https://github.com/node-gradle/gradle-node-plugin/blob/7.0.2/README.md) (current) +* [7.1.0](https://github.com/node-gradle/gradle-node-plugin/blob/7.1.0/README.md) (current) +* [7.0.2](https://github.com/node-gradle/gradle-node-plugin/blob/7.0.2/README.md) * [6.0.0](https://github.com/node-gradle/gradle-node-plugin/blob/6.0.0/README.md) * [5.0.0](https://github.com/node-gradle/gradle-node-plugin/blob/5.0.0/README.md) * [4.0.0](https://github.com/node-gradle/gradle-node-plugin/blob/4.0.0/README.md) diff --git a/build.gradle.kts b/build.gradle.kts index 1b0a5af9..cea9b7df 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -185,4 +185,12 @@ tasks.wrapper { tasks.withType().configureEach { jvmArgs("--add-opens=java.base/java.util=ALL-UNNAMED") -} \ No newline at end of file +} +publishing.publications.withType().configureEach { + pom.licenses { + license { + name.set("Apache License, Version 2.0") + url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") + } + } +} diff --git a/docs/installation.md b/docs/installation.md index daae414e..aad6a6e9 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -5,7 +5,7 @@ in your `build.gradle` file: ```gradle plugins { - id "com.github.node-gradle.node" version "7.0.2" + id "com.github.node-gradle.node" version "7.1.0" } ``` @@ -18,7 +18,7 @@ buildscript { } dependencies { - classpath "com.github.node-gradle:gradle-node-plugin:7.0.2" + classpath "com.github.node-gradle:gradle-node-plugin:7.1.0" } } diff --git a/docs/usage.md b/docs/usage.md index 42ee1066..90619f1c 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -18,7 +18,7 @@ file (see [Installing](installation.md) for details): ```gradle plugins { - id "com.github.node-gradle.node" version "7.0.2" + id "com.github.node-gradle.node" version "7.1.0" } ``` diff --git a/src/main/kotlin/com/github/gradle/node/NodePlugin.kt b/src/main/kotlin/com/github/gradle/node/NodePlugin.kt index 846b8e20..2b97b46a 100644 --- a/src/main/kotlin/com/github/gradle/node/NodePlugin.kt +++ b/src/main/kotlin/com/github/gradle/node/NodePlugin.kt @@ -20,10 +20,12 @@ import com.github.gradle.node.variant.computeNodeDir import com.github.gradle.node.yarn.task.YarnInstallTask import com.github.gradle.node.yarn.task.YarnSetupTask import com.github.gradle.node.yarn.task.YarnTask +import org.gradle.api.Action import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.provider.Property import org.gradle.kotlin.dsl.* +import org.gradle.process.ExecSpec import org.gradle.util.GradleVersion import java.io.ByteArrayOutputStream import java.io.File @@ -66,18 +68,32 @@ class NodePlugin : Plugin { } private fun addPlatform(extension: NodeExtension) { + val osType = parseOsType(System.getProperty("os.name")) + val arch = System.getProperty("os.arch") + + val unameSpec: Action = Action { + if (osType == OsType.WINDOWS) { + this.executable = "powershell" + this.args = listOf( + "-NoProfile", // Command runs in ~175ms, -NoProfile saves ~300ms + "-Command", + "(Get-WmiObject Win32_Processor).Architecture", + ) + } else { + this.executable = "uname" + this.args = listOf("-m") + } + } + val uname = { if (GradleVersion.current() >= GradleVersion.version("7.5")) { - val cmd = project.providers.exec { - this.executable = "uname" - this.args = listOf("-m") - } + val cmd = project.providers.exec(unameSpec) cmd.standardOutput.asText.get().trim() } else { val out = ByteArrayOutputStream() + project.exec(unameSpec) val cmd = project.exec { - this.executable = "uname" - this.args = listOf("-m") + unameSpec.execute(this) this.standardOutput = out } @@ -85,9 +101,7 @@ class NodePlugin : Plugin { out.toString().trim() } } - val name = System.getProperty("os.name") - val arch = System.getProperty("os.arch") - val platform = parsePlatform(name, arch, uname) + val platform = parsePlatform(osType, arch, uname) extension.resolvedPlatform.set(platform) extension.computedPlatform.convention(extension.resolvedPlatform) } diff --git a/src/main/kotlin/com/github/gradle/node/util/PlatformHelper.kt b/src/main/kotlin/com/github/gradle/node/util/PlatformHelper.kt index ee9f7c1d..ad641def 100644 --- a/src/main/kotlin/com/github/gradle/node/util/PlatformHelper.kt +++ b/src/main/kotlin/com/github/gradle/node/util/PlatformHelper.kt @@ -2,6 +2,34 @@ package com.github.gradle.node.util import java.util.concurrent.Callable +internal enum class OsType(val osName: String) { + WINDOWS("win"), + MAC("darwin"), + LINUX("linux"), + FREEBSD("linux"), // https://github.com/node-gradle/gradle-node-plugin/issues/178 + SUN("sunos"), + AIX("aix"), +} + +internal fun parsePlatform(type: OsType, arch: String, uname: () -> String): Platform { + val osArch = if (type == OsType.WINDOWS) parseWindowsArch(arch.toLowerCase(), uname) + else parseOsArch(arch.toLowerCase(), uname) + return Platform(type.osName, osArch) +} + +internal fun parseOsType(type: String): OsType { + val name = type.toLowerCase() + return when { + name.contains("windows") -> OsType.WINDOWS + name.contains("mac") -> OsType.MAC + name.contains("linux") -> OsType.LINUX + name.contains("freebsd") -> OsType.FREEBSD + name.contains("sunos") -> OsType.SUN + name.contains("aix") -> OsType.AIX + else -> error("Unsupported OS: $name") + } +} + fun parsePlatform(name: String, arch: String, uname: () -> String): Platform { return Platform(parseOsName(name.toLowerCase()), parseOsArch(arch.toLowerCase(), uname)) } @@ -35,10 +63,45 @@ fun parseOsArch(arch: String, uname: Callable): String { } } +fun parseWindowsArch(arch: String, uname: Callable): String { + // + return when { + arch.startsWith("aarch") || arch.startsWith("arm") + -> { + val wmiArch = uname.call() + return when (wmiArch) { + /* + * Parse Win32_Processor.Architectures to real processor type + * + * Table from https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info#members + */ + "12" -> "arm64" + "9" -> "x64" + // "6" -> "IA64" + // "5" -> "arm" // 32-bit + "0" -> "x86" + // "0xffff" -> "Unknown" + else -> error("Unexpected Win32_Processor.Architecture: $arch") + } + } + arch.contains("64") -> "x64" + else -> "x86" + } +} + fun main(args: Array) { val osName = System.getProperty("os.name") val osArch = System.getProperty("os.arch") - val uname = { execute("uname", "-m", timeout = 10) } + + val osType = parseOsType(osName) + val uname = { + val args = if (osType == OsType.WINDOWS) { + listOf("powershell", "-NoProfile", "-Command", "(Get-WmiObject Win32_Processor).Architecture") + } else { + listOf("uname", "-m") + } + execute(*args.toTypedArray(), timeout = 10) + } val platform = parsePlatform(osName, osArch, uname) println("Your os.name is: '${osName}' and is parsed as: '${platform.name}'") diff --git a/src/test/groovy/com/github/gradle/node/util/PlatformHelperTest.groovy b/src/test/groovy/com/github/gradle/node/util/PlatformHelperTest.groovy index c90d6983..ecf9d6f8 100644 --- a/src/test/groovy/com/github/gradle/node/util/PlatformHelperTest.groovy +++ b/src/test/groovy/com/github/gradle/node/util/PlatformHelperTest.groovy @@ -16,54 +16,45 @@ class PlatformHelperTest extends Specification { platform.windows == isWindows where: - osProp | archProp | osName | osArch | isWindows - 'Windows 8' | 'x86' | 'win' | 'x86' | true - 'Windows 8' | 'x86_64' | 'win' | 'x64' | true - 'Mac OS X' | 'x86' | 'darwin' | 'x86' | false - 'Mac OS X' | 'x86_64' | 'darwin' | 'x64' | false - 'Linux' | 'x86' | 'linux' | 'x86' | false - 'Linux' | 'x86_64' | 'linux' | 'x64' | false - 'Linux' | 'ppc64le' | 'linux' | 'ppc64le' | false - 'Linux' | 's390x' | 'linux' | 's390x' | false - 'SunOS' | 'x86' | 'sunos' | 'x86' | false - 'SunOS' | 'x86_64' | 'sunos' | 'x64' | false - 'AIX' | 'ppc64' | 'aix' | 'ppc64' | false + osProp | archProp || osName | osArch | isWindows + 'Windows 8' | 'x86' || 'win' | 'x86' | true + 'Windows 8' | 'x86_64' || 'win' | 'x64' | true + 'Windows 10' | 'x86_64' || 'win' | 'x64' | true + 'Mac OS X' | 'x86' || 'darwin' | 'x86' | false + 'Mac OS X' | 'x86_64' || 'darwin' | 'x64' | false + 'Linux' | 'x86' || 'linux' | 'x86' | false + 'Linux' | 'x86_64' || 'linux' | 'x64' | false + 'Linux' | 'ppc64le' || 'linux' | 'ppc64le' | false + 'Linux' | 's390x' || 'linux' | 's390x' | false + 'SunOS' | 'x86' || 'sunos' | 'x86' | false + 'SunOS' | 'x86_64' || 'sunos' | 'x64' | false + 'AIX' | 'ppc64' || 'aix' | 'ppc64' | false } @Unroll - def "verify ARM handling #archProp (#unameProp)"() { + def "verify #osProp ARM handling #archProp (#unameProp)"() { given: - def platform = PlatformHelperKt.parsePlatform("Linux", archProp, { unameProp }) + def osType = PlatformHelperKt.parseOsType(osProp) + def platform = PlatformHelperKt.parsePlatform(osType, archProp, { unameProp }) expect: - platform.name == "linux" - platform.arch == osArch - - where: - archProp | unameProp | osArch - 'arm' | 'armv7l' | 'armv7l' // Raspberry Pi 3 - 'arm' | 'armv8l' | 'arm64' - 'aarch32' | 'arm' | 'arm' - 'aarch64' | 'arm64' | 'arm64' - 'aarch64' | 'aarch64' | 'arm64' - 'ppc64le' | 'ppc64le' | 'ppc64le' - } - - @Unroll - def "verify ARM handling Mac OS #archProp (#unameProp)"() { - given: - def platform = PlatformHelperKt.parsePlatform("Mac OS X", archProp, { unameProp }) - - expect: - platform.name == "darwin" + platform.name == osName platform.arch == osArch where: - archProp | unameProp | osArch - 'aarch32' | 'arm' | 'arm' - 'aarch64' | 'arm64' | 'arm64' - 'aarch64' | 'aarch64' | 'arm64' - 'aarch64' | 'x86_64' | 'x64' // This shouldn't really happen but according to PR #204 it does + osProp | archProp || osName | unameProp | osArch + 'Linux' | 'arm' || 'linux' | 'armv7l' | 'armv7l' // Raspberry Pi 3 + 'Linux' | 'arm' || 'linux' | 'armv8l' | 'arm64' + 'Linux' | 'aarch32' || 'linux' | 'arm' | 'arm' + 'Linux' | 'aarch64' || 'linux' | 'arm64' | 'arm64' + 'Linux' | 'aarch64' || 'linux' | 'aarch64' | 'arm64' + 'Linux' | 'ppc64le' || 'linux' | 'ppc64le' | 'ppc64le' + 'Mac OS X' | 'aarch32' || 'darwin' | 'arm' | 'arm' + 'Mac OS X' | 'aarch64' || 'darwin' | 'arm64' | 'arm64' + 'Mac OS X' | 'aarch64' || 'darwin' | 'aarch64' | 'arm64' + 'Mac OS X' | 'aarch64' || 'darwin' | 'x86_64' | 'x64' // This unfortunately happens see PR #204 + 'Windows 10' | 'aarch64' || 'win' | '12' | 'arm64' + 'Windows 11' | 'aarch64' || 'win' | '9' | 'x64' // Not sure if this can actually happen } def "throw exception if unsupported os"() {