Skip to content
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

Support arm64 binaries since Node.js v16 #970

Merged
merged 1 commit into from
May 6, 2021
Merged
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
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Last public release: [![Maven Central](https://maven-badges.herokuapp.com/maven-

## Changelog

### 1.11.2

### 1.11.4
* Support node arm64 binaries since v16 major release

### 1.11.1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ private void installNodeDefault() throws InstallationException {
this.config.getPlatform().getLongNodeFilename(this.nodeVersion, false);
String downloadUrl = this.nodeDownloadRoot
+ this.config.getPlatform().getNodeDownloadFilename(this.nodeVersion, false);
String classifier = this.config.getPlatform().getNodeClassifier();
String classifier = this.config.getPlatform().getNodeClassifier(this.nodeVersion);

File tmpDirectory = getTempDirectory();

Expand Down Expand Up @@ -216,7 +216,7 @@ private void installNodeWithNpmForWindows() throws InstallationException {
this.config.getPlatform().getLongNodeFilename(this.nodeVersion, true);
String downloadUrl = this.nodeDownloadRoot
+ this.config.getPlatform().getNodeDownloadFilename(this.nodeVersion, true);
String classifier = this.config.getPlatform().getNodeClassifier();
String classifier = this.config.getPlatform().getNodeClassifier(this.nodeVersion);

File tmpDirectory = getTempDirectory();

Expand Down Expand Up @@ -274,7 +274,7 @@ private void installNodeForWindows() throws InstallationException {

File destination = new File(destinationDirectory, "node.exe");

String classifier = this.config.getPlatform().getNodeClassifier();
String classifier = this.config.getPlatform().getNodeClassifier(this.nodeVersion);

CacheDescriptor cacheDescriptor =
new CacheDescriptor("node", this.nodeVersion, classifier, "exe");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.github.eirslett.maven.plugins.frontend.lib;

import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

enum Architecture { x86, x64, ppc64le, s390x, arm64, armv7l, ppc, ppc64;
public static Architecture guess(){
Expand Down Expand Up @@ -60,6 +62,13 @@ public String getCodename(){
}

class Platform {

/**
* Node.js supports Apple silicon since v16
* https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V16.md#toolchain-and-compiler-upgrades
*/
private static final int NODE_VERSION_THRESHOLD_MAC_ARM64 = 16;

private final String nodeDownloadRoot;
private final OS os;
private final Architecture architecture;
Expand Down Expand Up @@ -117,7 +126,7 @@ public String getLongNodeFilename(String nodeVersion, boolean archiveOnWindows)
if(isWindows() && !archiveOnWindows){
return "node.exe";
} else {
return "node-" + nodeVersion + "-" + this.getNodeClassifier();
return "node-" + nodeVersion + "-" + this.getNodeClassifier(nodeVersion);
}
}

Expand All @@ -141,13 +150,30 @@ public String getNodeDownloadFilename(String nodeVersion, boolean archiveOnWindo
}
}

public String getNodeClassifier() {
final String result;
if(isMac() && architecture == Architecture.arm64) { // this check is required to download the x64 binary until there is an arm64 version available for macOS (darwin).
result = getCodename() + "-" + Architecture.x64.name();
public String getNodeClassifier(String nodeVersion) {
String result = getCodename() + "-" + resolveArchitecture(nodeVersion).name();
return classifier != null ? result + "-" + classifier : result;
}

private Architecture resolveArchitecture(String nodeVersion) {
if (isMac() && architecture == Architecture.arm64) {
Integer nodeMajorVersion = getNodeMajorVersion(nodeVersion);
if (nodeMajorVersion == null || nodeMajorVersion < NODE_VERSION_THRESHOLD_MAC_ARM64) {
return Architecture.x64;
}
}

return architecture;
}

static Integer getNodeMajorVersion(String nodeVersion) {
Matcher matcher = Pattern.compile("^v(\\d+)\\..*$").matcher(nodeVersion);
if (matcher.matches()) {
return Integer.parseInt(matcher.group(1));
} else {
result = getCodename() + "-" + architecture.name();
// malformed node version
return null;
}
return classifier != null ? result + "-" + classifier : result;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
@PrepareForTest({Platform.class, OS.class, Architecture.class, File.class})
public class PlatformTest {

private static final String NODE_VERSION_8 = "v8.17.2";
private static final String NODE_VERSION_15 = "v15.14.0";
private static final String NODE_VERSION_16 = "v16.1.0";

@Test
public void detect_win_doesntLookForAlpine() {
mockStatic(OS.class);
Expand All @@ -26,21 +30,33 @@ public void detect_win_doesntLookForAlpine() {
when(Architecture.guess()).thenReturn(Architecture.x86);

Platform platform = Platform.guess();
assertEquals("win-x86", platform.getNodeClassifier());
assertEquals("win-x86", platform.getNodeClassifier(NODE_VERSION_15));

verifyNoMoreInteractions(File.class); // doesn't look for a file path
}

@Test
public void detect_arm_mac_download_x64_binary() {
public void detect_arm_mac_download_x64_binary_node15() {
mockStatic(OS.class);
mockStatic(Architecture.class);

when(OS.guess()).thenReturn(OS.Mac);
when(Architecture.guess()).thenReturn(Architecture.arm64);

Platform platform = Platform.guess();
assertEquals("darwin-x64", platform.getNodeClassifier());
assertEquals("darwin-x64", platform.getNodeClassifier(NODE_VERSION_15));
}

@Test
public void detect_arm_mac_download_x64_binary_node16() {
mockStatic(OS.class);
mockStatic(Architecture.class);

when(OS.guess()).thenReturn(OS.Mac);
when(Architecture.guess()).thenReturn(Architecture.arm64);

Platform platform = Platform.guess();
assertEquals("darwin-arm64", platform.getNodeClassifier(NODE_VERSION_16));
}

@Test
Expand All @@ -58,7 +74,7 @@ public void detect_linux_notAlpine() throws Exception {
when(alpineRelease.exists()).thenReturn(false);

Platform platform = Platform.guess();
assertEquals("linux-x86", platform.getNodeClassifier());
assertEquals("linux-x86", platform.getNodeClassifier(NODE_VERSION_15));
assertEquals("https://nodejs.org/dist/", platform.getNodeDownloadRoot());
}

Expand All @@ -77,7 +93,7 @@ public void detect_linux_alpine() throws Exception {
when(alpineRelease.exists()).thenReturn(true);

Platform platform = Platform.guess();
assertEquals("linux-x86-musl", platform.getNodeClassifier());
assertEquals("linux-x86-musl", platform.getNodeClassifier(NODE_VERSION_15));
assertEquals("https://unofficial-builds.nodejs.org/download/release/",
platform.getNodeDownloadRoot());
}
Expand All @@ -91,6 +107,14 @@ public void detect_aix_ppc64() {
when(Architecture.guess()).thenReturn(Architecture.ppc64);

Platform platform = Platform.guess();
assertEquals("aix-ppc64", platform.getNodeClassifier());
assertEquals("aix-ppc64", platform.getNodeClassifier(NODE_VERSION_15));
}

@Test
public void getNodeMajorVersion() {
assertEquals(Integer.valueOf(8), Platform.getNodeMajorVersion(NODE_VERSION_8));
assertEquals(Integer.valueOf(15), Platform.getNodeMajorVersion(NODE_VERSION_15));
assertEquals(Integer.valueOf(16), Platform.getNodeMajorVersion(NODE_VERSION_16));
}

}