org.opentorah.node.NodeDependency.scala Maven / Gradle / Ivy
The newest version!
package org.opentorah.node
import org.opentorah.build.{Dependency, InstallableDependency, Repository, Version}
import org.opentorah.platform.{Architecture, Os}
import org.opentorah.util.Strings
import java.io.File
import java.nio.file.{Files, Path, Paths}
// Heavily inspired by (read: copied and reworked from :)) https://github.com/srs/gradle-node-plugin by srs.
// That plugin is not used directly because its tasks are not reusable unless the plugin is applied to the project,
// and I do not want to apply Node plugin to every project that uses DocBook, for instance.
// Also, I want to be able to run npm from within my code without creating tasks.
// Also, I would like to be able to use Node available via GraalVM's polyglot support.
// My simplified Node support is under 200 lines.
// Describes Node distribution's packaging and structure.
object NodeDependency extends Dependency.Simple(
group = "org.nodejs",
artifact = "node"
) with InstallableDependency[NodeInstallation]:
// Anything later than that breaks ScalaJS: 17.9.1, 18.15.0, 19.8.1
val versionDefault: Version = Version("16.19.1")
override def cacheDirectory: String = "nodejs"
override def repository: Option[Repository] = Some(Repository(
url = "https://nodejs.org/dist",
artifactPattern = "v[revision]/[artifact](-v[revision]-[classifier]).[ext]",
ivy = "v[revision]/ivy.xml"
))
private val os: Os = Os.get
private val isWindows: Boolean = os == Os.Windows
private val architecture: Architecture = Architecture.get
// TODO override def toString: String = s"Node v$version for $os on $architecture"
private val osName: String = os match
case Os.Windows => "win"
case Os.Mac => "darwin"
case Os.Linux => "linux"
case Os.FreeBSD => "linux"
case Os.SunOS => "sunos"
case Os.Aix => "aix"
case _ => throw IllegalArgumentException(s"Unsupported OS: $os")
private val osArch: String = architecture match
case Architecture.x86_64 => "x64"
case Architecture.amd64 => "x64"
case Architecture.aarch64 => "x64"
case Architecture.ppc64 => "ppc64"
case Architecture.ppc64le => "ppc64le"
case Architecture.s390x => "s390x"
case Architecture.armv6l => "armv6l"
case Architecture.armv7l => "armv7l"
case Architecture.armv8l => "arm64" // *not* "armv8l"!
case Architecture.i686 => "x86"
case Architecture.nacl => "x86"
//https://github.com/nodejs/node/pull/5995
private def hasWindowsZip(version: Version): Boolean =
val (majorVersion: Int, minorVersion: Int, microVersion: Int) = version.majorMinorMicro
((majorVersion == 4) && (minorVersion >= 5)) || // >= 4.5.0..6
((majorVersion == 6) && ((minorVersion > 2) || ((minorVersion == 2) && (microVersion >= 1)))) || // >= 6.2.1..7
(majorVersion > 6) // 7..
override def classifier(version: Version): Option[String] =
val fixUpOsAndArch: Boolean = isWindows && !hasWindowsZip(version)
val dependencyOsName: String = if fixUpOsAndArch then "linux" else osName
val dependencyOsArch: String = if fixUpOsAndArch then "x86" else osArch
Some(s"$dependencyOsName-$dependencyOsArch")
override def isZip(version: Version): Boolean = isWindows && hasWindowsZip(version)
override def extension(version: Version): Option[String] = Some(if isZip(version) then "zip" else "tar.gz")
override def archiveSubdirectoryPath(version: Version): Seq[String] =
val classifierStr: String = Strings.prefix("-", classifier(version))
Seq(
s"$artifact-v${version.version}$classifierStr"
)
override def installation(root: File): NodeInstallation =
val bin: File = if !isWindows then File(root, "bin") else root
NodeInstallation(
nodeExec = File(bin, if isWindows then "node.exe" else "node"),
npmExec = File(bin, if isWindows then "npm.cmd" else "npm" )
)
override def exists(installation: NodeInstallation): Boolean =
installation.nodeExec.exists && installation.npmExec.exists
override def fixup(installation: NodeInstallation): Unit = if !isWindows then
val npm: Path = installation.npmExec.toPath
val deleted: Boolean = Files.deleteIfExists(npm)
if deleted then
val root: File = installation.getRoot
val npmCliJs: String = File(root, s"lib/node_modules/npm/bin/npm-cli.js").getAbsolutePath
Files.createSymbolicLink(
npm,
npm.getParent.relativize(Paths.get(npmCliJs))
)