diff --git a/crates/vp_pm_cli/src/package_manager.rs b/crates/vp_pm_cli/src/package_manager.rs index cffab42ad3..8460fa18b9 100644 --- a/crates/vp_pm_cli/src/package_manager.rs +++ b/crates/vp_pm_cli/src/package_manager.rs @@ -945,9 +945,7 @@ fn open_lock_file(lock_path: &Path) -> io::Result { 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 { let name = match (env::consts::OS, env::consts::ARCH) { ("macos", "aarch64") => "@oven/bun-darwin-aarch64", ("macos", "x86_64") => "@oven/bun-darwin-x64", @@ -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. @@ -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()); @@ -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(); @@ -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(); @@ -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