diff --git a/crates/vite_install/src/package_manager.rs b/crates/vite_install/src/package_manager.rs index e7fcb975f1..24d60f2fb3 100644 --- a/crates/vite_install/src/package_manager.rs +++ b/crates/vite_install/src/package_manager.rs @@ -936,9 +936,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", @@ -958,7 +956,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. @@ -972,7 +984,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()); @@ -984,11 +995,14 @@ 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()?; + 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(); @@ -3450,10 +3464,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"); + } + /// 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