Skip to content
Merged
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
63 changes: 54 additions & 9 deletions crates/vp_pm_cli/src/package_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -945,9 +945,7 @@ fn open_lock_file(lock_path: &Path) -> io::Result<File> {
fs::OpenOptions::new().read(true).write(true).create(true).truncate(false).open(lock_path)
}

/// Get the platform-specific npm package name for bun.
/// Returns the `@oven/bun-{os}-{arch}` package name for the current platform.
fn get_bun_platform_package_name() -> Result<&'static str, Error> {
fn get_bun_platform_package_name() -> Result<String, Error> {
let name = match (env::consts::OS, env::consts::ARCH) {
("macos", "aarch64") => "@oven/bun-darwin-aarch64",
("macos", "x86_64") => "@oven/bun-darwin-x64",
Expand All @@ -967,7 +965,21 @@ fn get_bun_platform_package_name() -> Result<&'static str, Error> {
));
}
};
Ok(name)
Ok(with_bun_baseline(name, bun_requires_baseline()))
}

fn with_bun_baseline(name: &str, requires_baseline: bool) -> String {
if requires_baseline { format!("{name}-baseline") } else { name.to_string() }
}

#[cfg(target_arch = "x86_64")]
fn bun_requires_baseline() -> bool {
!std::arch::is_x86_feature_detected!("avx2")
}

#[cfg(not(target_arch = "x86_64"))]
fn bun_requires_baseline() -> bool {
false
}

/// Download bun package manager (native binary) from npm.
Expand All @@ -981,7 +993,6 @@ async fn download_bun_package_manager(
home_dir: &AbsolutePath,
) -> Result<(AbsolutePathBuf, Str, Str), Error> {
let package_name: Str = "bun".into();
let platform_package_name = get_bun_platform_package_name()?;

// $VP_HOME/package_manager/bun/{version}
let target_dir = home_dir.join("package_manager").join("bun").join(version.as_str());
Expand All @@ -993,15 +1004,17 @@ async fn download_bun_package_manager(
return Ok((install_dir, package_name, version.clone()));
}

// Temporary by design: select a CPU-compatible package for new downloads without replacing existing installs.
let platform_package_name = get_bun_platform_package_name()?;
// The declared hash never covers the platform tarball, so verify it
// against the registry's `dist.integrity` for the platform package.
let platform_hash = fetch_platform_integrity("bun", platform_package_name, version).await?;
let platform_hash = fetch_platform_integrity("bun", &platform_package_name, version).await?;

let parent_dir = target_dir.parent().unwrap();
tokio::fs::create_dir_all(parent_dir).await?;

// Download the platform-specific package directly
let platform_tgz_url = get_npm_package_tgz_url(platform_package_name, version);
let platform_tgz_url = get_npm_package_tgz_url(&platform_package_name, version);
// Keep the TempDir guard alive so a failure path cleans up the temp dir.
let tmp_dir = tempfile::tempdir_in(parent_dir)?;
let target_dir_tmp = tmp_dir.path().to_path_buf();
Expand Down Expand Up @@ -3671,11 +3684,42 @@ mod tests {
// On musl targets, the package name should contain "-musl"
#[cfg(target_env = "musl")]
assert!(
name.ends_with("-musl"),
"On musl targets, package name should end with -musl, got: {name}"
name.contains("-musl"),
"On musl targets, package name should contain -musl, got: {name}"
);
}

#[test]
fn test_get_bun_platform_package_name_uses_baseline_without_avx2() {
for (name, expected) in [
("@oven/bun-darwin-x64", "@oven/bun-darwin-x64-baseline"),
("@oven/bun-linux-x64", "@oven/bun-linux-x64-baseline"),
("@oven/bun-linux-x64-musl", "@oven/bun-linux-x64-musl-baseline"),
("@oven/bun-windows-x64", "@oven/bun-windows-x64-baseline"),
] {
assert_eq!(with_bun_baseline(name, true), expected);
}
assert_eq!(with_bun_baseline("@oven/bun-linux-x64", false), "@oven/bun-linux-x64");
}

#[tokio::test]
async fn test_download_bun_package_manager_preserves_existing_install() {
let temp_dir = create_temp_dir();
let vp_home = AbsolutePathBuf::new(temp_dir.path().to_path_buf()).unwrap();
let version: Str = "1.3.14".into();
write_pm_install(&vp_home, "bun", version.as_str(), InstallState::Complete);
let native_bin = vp_home
.join("package_manager")
.join("bun")
.join(version.as_str())
.join("bun/bin/bun.native");
fs::write(&native_bin, "existing bun").unwrap();

download_bun_package_manager(&version, &vp_home).await.unwrap();

assert_eq!(fs::read_to_string(native_bin).unwrap(), "existing bun");
}

#[test]
fn test_get_pnpm_platform_package_name() {
let result = get_pnpm_platform_package_name();
Expand Down Expand Up @@ -3729,6 +3773,7 @@ mod tests {
let result = create_pnpm_native_shim_files(&bin_prefix).await;
assert!(result.is_err(), "should error when bin/pnpm.native is missing");
}

/// Note: The true ERROR_SHARING_VIOLATION occurs when *multiple processes*
/// attempt to lock the file concurrently on Windows (e.g. during parallel MSBuild tasks).
/// Standard cargo tests run in a single process, which the Windows OS allows to bypass
Expand Down
Loading