Skip to content
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
23 changes: 10 additions & 13 deletions crates/volta-core/src/tool/node/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ cfg_if! {
}
}

fn npm_manifest_path(version: &str) -> PathBuf {
fn npm_manifest_path(version: &Version) -> PathBuf {
let mut manifest = PathBuf::from(Node::archive_basename(version));

#[cfg(unix)]
Expand All @@ -46,7 +46,7 @@ fn npm_manifest_path(version: &str) -> PathBuf {
pub fn fetch(version: &Version, hooks: Option<&ToolHooks<Node>>) -> Fallible<NodeVersion> {
let home = volta_home()?;
let node_dir = home.node_inventory_dir();
let cache_file = node_dir.join(Node::archive_filename(&version.to_string()));
let cache_file = node_dir.join(Node::archive_filename(version));

let (archive, staging) = match load_cached_distro(&cache_file) {
Some(archive) => {
Expand Down Expand Up @@ -107,22 +107,20 @@ fn unpack_archive(archive: Box<dyn Archive>, version: &Version) -> Fallible<Node
})?;

// Save the npm version number in the npm version file for this distro
let npm_package_json = temp.path().join(npm_manifest_path(&version_string));
let npm_package_json = temp.path().join(npm_manifest_path(version));
let npm = Manifest::version(&npm_package_json)?;
save_default_npm_version(&version, &npm)?;

let dest = volta_home()?.node_image_dir(&version_string);
ensure_containing_dir_exists(&dest)
.with_context(|| ErrorKind::ContainingDirError { path: dest.clone() })?;

rename(
temp.path().join(Node::archive_basename(&version_string)),
&dest,
)
.with_context(|| ErrorKind::SetupToolImageError {
tool: "Node".into(),
version: version_string,
dir: dest.clone(),
rename(temp.path().join(Node::archive_basename(version)), &dest).with_context(|| {
ErrorKind::SetupToolImageError {
tool: "Node".into(),
version: version_string,
dir: dest.clone(),
}
})?;

progress.finish_and_clear();
Expand Down Expand Up @@ -151,8 +149,7 @@ fn load_cached_distro(file: &Path) -> Option<Box<dyn Archive>> {

/// Determine the remote URL to download from, using the hooks if available
fn determine_remote_url(version: &Version, hooks: Option<&ToolHooks<Node>>) -> Fallible<String> {
let version_str = version.to_string();
let distro_file_name = Node::archive_filename(&version_str);
let distro_file_name = Node::archive_filename(version);
match hooks {
Some(&ToolHooks {
distro: Some(ref hook),
Expand Down
16 changes: 16 additions & 0 deletions crates/volta-core/src/tool/node/metadata.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::collections::HashSet;

use super::NODE_DISTRO_IDENTIFIER;
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
use super::NODE_DISTRO_IDENTIFIER_FALLBACK;
use crate::version::{option_version_serde, version_serde};
use semver::Version;
use serde::{Deserialize, Deserializer};
Expand Down Expand Up @@ -37,6 +39,7 @@ impl From<RawNodeIndex> for NodeIndex {
.0
.into_iter()
.filter_map(|entry| {
#[cfg(not(all(target_os = "macos", target_arch = "aarch64")))]
if entry.npm.is_some() && entry.files.contains(NODE_DISTRO_IDENTIFIER) {
Some(NodeEntry {
version: entry.version,
Expand All @@ -45,6 +48,19 @@ impl From<RawNodeIndex> for NodeIndex {
} else {
None
}

#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
if entry.npm.is_some()
&& (entry.files.contains(NODE_DISTRO_IDENTIFIER)
|| entry.files.contains(NODE_DISTRO_IDENTIFIER_FALLBACK))
{
Some(NodeEntry {
version: entry.version,
lts: entry.lts,
})
} else {
None
}
})
.collect();

Expand Down
49 changes: 39 additions & 10 deletions crates/volta-core/src/tool/node/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,7 @@ cfg_if! {
pub const NODE_DISTRO_EXTENSION: &str = "zip";
/// The file identifier in the Node index `files` array
pub const NODE_DISTRO_IDENTIFIER: &str = "win-x64-zip";
} else if #[cfg(all(target_os = "macos", any(target_arch = "x86_64", target_arch = "aarch64")))] {
// NOTE: Currently, Node does not provide prebuilt binaries for Apple M1 machines, so we
// fall back to using the x64 binaries through Rosetta 2. When Node starts shipping M1
// binaries, then we will need to adjust our logic to search for those first and only fall
// back if they aren't found

} else if #[cfg(all(target_os = "macos", target_arch = "x86_64"))] {
/// The OS component of a Node distro filename
pub const NODE_DISTRO_OS: &str = "darwin";
/// The architecture component of a Node distro filename
Expand All @@ -53,6 +48,23 @@ cfg_if! {
pub const NODE_DISTRO_EXTENSION: &str = "tar.gz";
/// The file identifier in the Node index `files` array
pub const NODE_DISTRO_IDENTIFIER: &str = "osx-x64-tar";
} else if #[cfg(all(target_os = "macos", target_arch = "aarch64"))] {
/// The OS component of a Node distro filename
pub const NODE_DISTRO_OS: &str = "darwin";
/// The architecture component of a Node distro filename
pub const NODE_DISTRO_ARCH: &str = "arm64";
/// The extension for Node distro files
pub const NODE_DISTRO_EXTENSION: &str = "tar.gz";
/// The file identifier in the Node index `files` array
pub const NODE_DISTRO_IDENTIFIER: &str = "osx-arm64-tar";

// NOTE: Node support for pre-built Apple Silicon binaries was added in major version 16
// For versions prior to that, we need to fall back on the x64 binaries via Rosetta 2

/// The fallback architecture component of a Node distro filename
pub const NODE_DISTRO_ARCH_FALLBACK: &str = "x64";
/// The fallback file identifier in the Node index `files` array
pub const NODE_DISTRO_IDENTIFIER_FALLBACK: &str = "osx-x64-tar";
} else if #[cfg(all(target_os = "linux", target_arch = "x86_64"))] {
/// The OS component of a Node distro filename
pub const NODE_DISTRO_OS: &str = "linux";
Expand Down Expand Up @@ -117,11 +129,28 @@ impl Node {
Node { version }
}

pub fn archive_basename(version: &str) -> String {
#[cfg(not(all(target_os = "macos", target_arch = "aarch64")))]
pub fn archive_basename(version: &Version) -> String {
format!("node-v{}-{}-{}", version, NODE_DISTRO_OS, NODE_DISTRO_ARCH)
}

pub fn archive_filename(version: &str) -> String {
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
pub fn archive_basename(version: &Version) -> String {
// Note: Node began shipping pre-built binaries for Apple Silicon with Major version 16
// Prior to that, we need to fall back on the x64 binaries
format!(
"node-v{}-{}-{}",
version,
NODE_DISTRO_OS,
if version.major >= 16 {
NODE_DISTRO_ARCH
} else {
NODE_DISTRO_ARCH_FALLBACK
}
)
}

pub fn archive_filename(version: &Version) -> String {
format!(
"{}.{}",
Node::archive_basename(version),
Expand Down Expand Up @@ -230,15 +259,15 @@ mod tests {
#[test]
fn test_node_archive_basename() {
assert_eq!(
Node::archive_basename("1.2.3"),
Node::archive_basename(&Version::new(1, 2, 3)),
format!("node-v1.2.3-{}-{}", NODE_DISTRO_OS, NODE_DISTRO_ARCH)
);
}

#[test]
fn test_node_archive_filename() {
assert_eq!(
Node::archive_filename("1.2.3"),
Node::archive_filename(&Version::new(1, 2, 3)),
format!(
"node-v1.2.3-{}-{}.{}",
NODE_DISTRO_OS, NODE_DISTRO_ARCH, NODE_DISTRO_EXTENSION
Expand Down
5 changes: 3 additions & 2 deletions tests/acceptance/corrupted_download.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::support::sandbox::{sandbox, DistroMetadata, NodeFixture, YarnFixture};
use hamcrest2::assert_that;
use hamcrest2::prelude::*;
use semver::Version;
use test_support::matchers::execs;

use volta_core::error::ExitCode;
Expand Down Expand Up @@ -58,7 +59,7 @@ fn install_corrupted_node_leaves_inventory_unchanged() {
execs().with_status(ExitCode::UnknownError as i32)
);

assert!(!s.node_inventory_archive_exists("0.0.1"));
assert!(!s.node_inventory_archive_exists(&Version::new(0, 0, 1)));
}

#[test]
Expand All @@ -73,7 +74,7 @@ fn install_valid_node_saves_to_inventory() {
execs().with_status(ExitCode::Success as i32)
);

assert!(s.node_inventory_archive_exists("10.99.1040"));
assert!(s.node_inventory_archive_exists(&Version::new(10, 99, 1040)));
}

#[test]
Expand Down
3 changes: 2 additions & 1 deletion tests/acceptance/support/sandbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::time::{Duration, SystemTime};

use hyperx::header::HttpDate;
use mockito::{self, mock, Matcher};
use semver::Version;
use test_support::{self, ok_or_panic, paths, paths::PathExt, process::ProcessBuilder};
use volta_core::fs::symlink_file;
use volta_core::tool::{Node, Yarn, NODE_DISTRO_ARCH, NODE_DISTRO_EXTENSION, NODE_DISTRO_OS};
Expand Down Expand Up @@ -631,7 +632,7 @@ impl Sandbox {

// check that files in the sandbox exist

pub fn node_inventory_archive_exists(&self, version: &str) -> bool {
pub fn node_inventory_archive_exists(&self, version: &Version) -> bool {
node_inventory_dir()
.join(Node::archive_filename(version))
.exists()
Expand Down