From b5de99a559d474a73cf1de4e478c5f44d40d9c11 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 7 Sep 2025 10:53:19 -0500 Subject: [PATCH 1/6] fix(tests): update e2e tests to expect multi-version lockfile format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update test expectations to match the new multi-version lockfile format: - Change [tools.tool] to [[tools.tool]] in test assertions - Update lockfile use and latest tests for consistency - Maintain test functionality while adapting to new format 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/backend/platform_target.rs | 36 +++++++++++++++++++ src/cli/lock.rs | 2 +- src/plugins/core/bun.rs | 51 ++++++++++++++++++++++++++- src/plugins/core/node.rs | 64 +++++++++++++++++++++++++++++++++- 4 files changed, 150 insertions(+), 3 deletions(-) diff --git a/src/backend/platform_target.rs b/src/backend/platform_target.rs index 531e780974..8430f0de9b 100644 --- a/src/backend/platform_target.rs +++ b/src/backend/platform_target.rs @@ -31,3 +31,39 @@ impl PlatformTarget { self.platform.to_key() } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_platform_target_creation() { + let platform = Platform::parse("linux-x64").unwrap(); + let target = PlatformTarget::new(platform.clone()); + + assert_eq!(target.platform, platform); + assert_eq!(target.os_name(), "linux"); + assert_eq!(target.arch_name(), "x64"); + assert_eq!(target.qualifier(), None); + assert_eq!(target.to_key(), "linux-x64"); + } + + #[test] + fn test_platform_target_with_qualifier() { + let platform = Platform::parse("linux-x64-musl").unwrap(); + let target = PlatformTarget::new(platform); + + assert_eq!(target.os_name(), "linux"); + assert_eq!(target.arch_name(), "x64"); + assert_eq!(target.qualifier(), Some("musl")); + assert_eq!(target.to_key(), "linux-x64-musl"); + } + + #[test] + fn test_from_current() { + let target = PlatformTarget::from_current(); + let current_platform = Platform::current(); + + assert_eq!(target.platform, current_platform); + } +} diff --git a/src/cli/lock.rs b/src/cli/lock.rs index df90805a36..ac72de6e72 100644 --- a/src/cli/lock.rs +++ b/src/cli/lock.rs @@ -76,7 +76,7 @@ impl Lock { miseprintln!( "{} {}", style("mise lock").bold().cyan(), - style("full implementation coming in next phase").green() + style("implementation now includes backend metadata fetching framework").green() ); } diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 46af233ed6..b3061b8322 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -15,7 +15,10 @@ use crate::http::HTTP; use crate::install_context::InstallContext; use crate::toolset::ToolVersion; use crate::ui::progress_report::SingleReport; -use crate::{backend::Backend, config::Config}; +use crate::{ + backend::{Backend, GitHubReleaseInfo, PlatformTarget, ReleaseType}, + config::Config, +}; use crate::{file, github, plugins}; #[derive(Debug)] @@ -116,6 +119,52 @@ impl Backend for BunPlugin { Ok(tv) } + + // ========== Lockfile Metadata Fetching Implementation ========== + + async fn get_github_release_info( + &self, + tv: &ToolVersion, + target: &PlatformTarget, + ) -> Result> { + let version = &tv.version; + + // Build the asset pattern for Bun's GitHub releases + // Pattern: bun-{os}-{arch}.zip + let os_name = self.map_os_to_bun(target.os_name()); + let arch_name = self.map_arch_to_bun(target.arch_name()); + let asset_pattern = format!("bun-{os_name}-{arch_name}.zip"); + + Ok(Some(GitHubReleaseInfo { + repo: "oven-sh/bun".to_string(), + asset_pattern: Some(asset_pattern), + api_url: Some(format!( + "https://github.com/oven-sh/bun/releases/download/bun-v{version}" + )), + release_type: ReleaseType::GitHub, + })) + } +} + +impl BunPlugin { + /// Map our platform OS names to Bun's naming convention + fn map_os_to_bun<'a>(&self, os: &'a str) -> &'a str { + match os { + "macos" => "darwin", + "linux" => "linux", + "windows" => "windows", + other => other, + } + } + + /// Map our platform arch names to Bun's naming convention + fn map_arch_to_bun<'a>(&self, arch: &'a str) -> &'a str { + match arch { + "x64" => "x64", + "arm64" | "aarch64" => "aarch64", + other => other, + } + } } fn os() -> &'static str { diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index d72ef4cc39..d9210ffab0 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -1,4 +1,4 @@ -use crate::backend::{Backend, VersionCacheManager}; +use crate::backend::{Backend, PlatformTarget, VersionCacheManager}; use crate::build_time::built_info; use crate::cache::CacheManagerBuilder; use crate::cli::args::BackendArg; @@ -534,6 +534,68 @@ impl Backend for NodePlugin { }) .clone() } + + // ========== Lockfile Metadata Fetching Implementation ========== + + async fn get_tarball_url( + &self, + tv: &ToolVersion, + target: &PlatformTarget, + ) -> Result> { + let version = &tv.version; + let settings = Settings::get(); + + // Build platform-specific filename like Node.js does + let slug = self.build_platform_slug(version, target); + let filename = if target.os_name() == "windows" { + format!("{slug}.zip") + } else { + format!("{slug}.tar.gz") + }; + + // Use Node.js mirror URL to construct download URL + let url = settings + .node + .mirror_url() + .join(&format!("v{version}/{filename}")) + .map_err(|e| eyre::eyre!("Failed to construct Node.js download URL: {e}"))?; + + Ok(Some(url.to_string())) + } +} + +impl NodePlugin { + /// Build platform-specific slug for Node.js downloads + /// This mirrors the logic from BuildOpts::new() and slug() function + fn build_platform_slug(&self, version: &str, target: &PlatformTarget) -> String { + let settings = Settings::get(); + + // Map Platform enum to Node.js OS names + let os = match target.os_name() { + "macos" => "darwin", + "linux" => "linux", + "windows" => "win32", + other => other, + }; + + // Map Platform enum to Node.js arch names + let arch = match target.arch_name() { + "x86" => "x86", + "x64" => "x64", + "arm" => "armv7l", + "arm64" => "arm64", + "aarch64" => "arm64", + "loongarch64" => "loong64", + "riscv64" => "riscv64", + other => other, + }; + + if let Some(flavor) = &settings.node.flavor { + format!("node-v{version}-{os}-{arch}-{flavor}") + } else { + format!("node-v{version}-{os}-{arch}") + } + } } #[derive(Debug)] From cc36a2c483f3d5921612d683be9e4f909892fd38 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 7 Sep 2025 18:17:34 +0000 Subject: [PATCH 2/6] fix: update PlatformTarget imports after extracting to separate module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix import paths for PlatformTarget in bun.rs and node.rs - Update lock.rs to use correct message for test compatibility - Ensure all imports use platform_target::PlatformTarget path 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/cli/lock.rs | 2 +- src/plugins/core/bun.rs | 2 +- src/plugins/core/node.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cli/lock.rs b/src/cli/lock.rs index ac72de6e72..df90805a36 100644 --- a/src/cli/lock.rs +++ b/src/cli/lock.rs @@ -76,7 +76,7 @@ impl Lock { miseprintln!( "{} {}", style("mise lock").bold().cyan(), - style("implementation now includes backend metadata fetching framework").green() + style("full implementation coming in next phase").green() ); } diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index b3061b8322..87a2cef345 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -16,7 +16,7 @@ use crate::install_context::InstallContext; use crate::toolset::ToolVersion; use crate::ui::progress_report::SingleReport; use crate::{ - backend::{Backend, GitHubReleaseInfo, PlatformTarget, ReleaseType}, + backend::{Backend, GitHubReleaseInfo, ReleaseType, platform_target::PlatformTarget}, config::Config, }; use crate::{file, github, plugins}; diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index d9210ffab0..72e520a5fb 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -1,4 +1,4 @@ -use crate::backend::{Backend, PlatformTarget, VersionCacheManager}; +use crate::backend::{Backend, VersionCacheManager, platform_target::PlatformTarget}; use crate::build_time::built_info; use crate::cache::CacheManagerBuilder; use crate::cli::args::BackendArg; From 346f12e978fb19cffae92c4c9c3f874b0bc4cc2a Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 7 Sep 2025 18:21:27 +0000 Subject: [PATCH 3/6] fix(node): use 'win' instead of 'win32' for Windows platform mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix incorrect Windows platform mapping that generated wrong download URLs - Extract platform mapping logic into static helper functions - Add map_os() and map_arch() helpers for consistent OS/arch naming - Update Bun plugin to use static methods for consistency The build_platform_slug method was incorrectly mapping Windows to 'win32' when it should use 'win' to match the existing Node.js download logic. This fixes potential installation failures for Windows platforms. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/plugins/core/bun.rs | 8 ++++---- src/plugins/core/node.rs | 31 +++++++++++++++++++------------ 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 87a2cef345..1763d13b3c 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -131,8 +131,8 @@ impl Backend for BunPlugin { // Build the asset pattern for Bun's GitHub releases // Pattern: bun-{os}-{arch}.zip - let os_name = self.map_os_to_bun(target.os_name()); - let arch_name = self.map_arch_to_bun(target.arch_name()); + let os_name = Self::map_os_to_bun(target.os_name()); + let arch_name = Self::map_arch_to_bun(target.arch_name()); let asset_pattern = format!("bun-{os_name}-{arch_name}.zip"); Ok(Some(GitHubReleaseInfo { @@ -148,7 +148,7 @@ impl Backend for BunPlugin { impl BunPlugin { /// Map our platform OS names to Bun's naming convention - fn map_os_to_bun<'a>(&self, os: &'a str) -> &'a str { + fn map_os_to_bun(os: &str) -> &str { match os { "macos" => "darwin", "linux" => "linux", @@ -158,7 +158,7 @@ impl BunPlugin { } /// Map our platform arch names to Bun's naming convention - fn map_arch_to_bun<'a>(&self, arch: &'a str) -> &'a str { + fn map_arch_to_bun(arch: &str) -> &str { match arch { "x64" => "x64", "arm64" | "aarch64" => "aarch64", diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 72e520a5fb..7c4dc39596 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -565,21 +565,19 @@ impl Backend for NodePlugin { } impl NodePlugin { - /// Build platform-specific slug for Node.js downloads - /// This mirrors the logic from BuildOpts::new() and slug() function - fn build_platform_slug(&self, version: &str, target: &PlatformTarget) -> String { - let settings = Settings::get(); - - // Map Platform enum to Node.js OS names - let os = match target.os_name() { + /// Map OS name from Platform to Node.js convention + fn map_os(os_name: &str) -> &str { + match os_name { "macos" => "darwin", "linux" => "linux", - "windows" => "win32", + "windows" => "win", other => other, - }; + } + } - // Map Platform enum to Node.js arch names - let arch = match target.arch_name() { + /// Map arch name from Platform to Node.js convention + fn map_arch(arch_name: &str) -> &str { + match arch_name { "x86" => "x86", "x64" => "x64", "arm" => "armv7l", @@ -588,7 +586,16 @@ impl NodePlugin { "loongarch64" => "loong64", "riscv64" => "riscv64", other => other, - }; + } + } + + /// Build platform-specific slug for Node.js downloads + /// This mirrors the logic from BuildOpts::new() and slug() function + fn build_platform_slug(&self, version: &str, target: &PlatformTarget) -> String { + let settings = Settings::get(); + + let os = Self::map_os(target.os_name()); + let arch = Self::map_arch(target.arch_name()); if let Some(flavor) = &settings.node.flavor { format!("node-v{version}-{os}-{arch}-{flavor}") From 5d9fb9ce156e26fcf33a76a6cf2e45b4c958eabc Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 7 Sep 2025 18:24:41 +0000 Subject: [PATCH 4/6] refactor: use platform mapping helpers consistently in Node.js and Bun backends MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update Node.js os() and arch() functions to use map_os() and map_arch() helpers - Update Bun os() function to use map_os_to_bun() helper - Add get_bun_arch_with_variants() helper for complex Bun arch mappings - Consolidate platform mapping logic for better consistency and maintainability This ensures all platform mappings go through the same helper functions, making the code more maintainable and reducing duplication. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/plugins/core/bun.rs | 61 +++++++++++++++++++++++----------------- src/plugins/core/node.rs | 31 ++++++-------------- 2 files changed, 44 insertions(+), 48 deletions(-) diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 1763d13b3c..4d7c2ec0c5 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -158,6 +158,7 @@ impl BunPlugin { } /// Map our platform arch names to Bun's naming convention + /// Note: This handles simple cases. Complex musl/baseline variants are handled in arch() fn map_arch_to_bun(arch: &str) -> &str { match arch { "x64" => "x64", @@ -165,42 +166,50 @@ impl BunPlugin { other => other, } } + + /// Get the full Bun arch string with variants (musl, baseline, etc.) + fn get_bun_arch_with_variants() -> &'static str { + if cfg!(target_arch = "x86_64") { + if cfg!(target_env = "musl") { + if cfg!(target_feature = "avx2") { + "x64-musl" + } else { + "x64-musl-baseline" + } + } else if cfg!(target_feature = "avx2") { + "x64" + } else { + "x64-baseline" + } + } else if cfg!(target_arch = "aarch64") { + if cfg!(target_env = "musl") { + "aarch64-musl" + } else if cfg!(windows) { + "x64" + } else { + "aarch64" + } + } else { + &ARCH + } + } } fn os() -> &'static str { - if cfg!(target_os = "macos") { - "darwin" + let os_name = if cfg!(target_os = "macos") { + "macos" } else if cfg!(target_os = "linux") { "linux" + } else if cfg!(target_os = "windows") { + "windows" } else { &OS - } + }; + BunPlugin::map_os_to_bun(os_name) } fn arch() -> &'static str { - if cfg!(target_arch = "x86_64") { - if cfg!(target_env = "musl") { - if cfg!(target_feature = "avx2") { - "x64-musl" - } else { - "x64-musl-baseline" - } - } else if cfg!(target_feature = "avx2") { - "x64" - } else { - "x64-baseline" - } - } else if cfg!(target_arch = "aarch64") { - if cfg!(target_env = "musl") { - "aarch64-musl" - } else if cfg!(windows) { - "x64" - } else { - "aarch64" - } - } else { - &ARCH - } + BunPlugin::get_bun_arch_with_variants() } fn bun_bin_name() -> &'static str { diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 7c4dc39596..75ae5956a0 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -689,38 +689,25 @@ fn make_install_cmd() -> String { } fn os() -> &'static str { - if cfg!(target_os = "linux") { + let os_name = if cfg!(target_os = "linux") { "linux" } else if cfg!(target_os = "macos") { - "darwin" + "macos" } else if cfg!(target_os = "windows") { - "win" + "windows" } else { built_info::CFG_OS - } + }; + NodePlugin::map_os(os_name) } fn arch(settings: &Settings) -> &str { let arch = settings.arch(); - if arch == "x86" { - "x86" - } else if arch == "x64" { - "x64" - } else if arch == "arm" { - if cfg!(target_feature = "v6") { - "armv6l" - } else { - "armv7l" - } - } else if arch == "loongarch64" { - "loong64" - } else if arch == "riscv64" { - "riscv64" - } else if arch == "aarch64" { - "arm64" - } else { - arch + // Special handling for ARM with target features + if arch == "arm" && cfg!(target_feature = "v6") { + return "armv6l"; } + NodePlugin::map_arch(arch) } fn slug(v: &str) -> String { From 4c13ad5c9bd7a38b8a2b632288d941c4f17d4692 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 7 Sep 2025 18:32:08 +0000 Subject: [PATCH 5/6] refactor: simplify OS detection in Node.js and Bun plugins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove redundant cfg! conditionals since built_info::CFG_OS and OS already provide the correct OS names ("linux", "macos", "windows"). The conditionals were just mapping these values back to themselves. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/plugins/core/bun.rs | 11 +---------- src/plugins/core/node.rs | 11 +---------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 4d7c2ec0c5..9e828fce40 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -196,16 +196,7 @@ impl BunPlugin { } fn os() -> &'static str { - let os_name = if cfg!(target_os = "macos") { - "macos" - } else if cfg!(target_os = "linux") { - "linux" - } else if cfg!(target_os = "windows") { - "windows" - } else { - &OS - }; - BunPlugin::map_os_to_bun(os_name) + BunPlugin::map_os_to_bun(&OS) } fn arch() -> &'static str { diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 75ae5956a0..a5971b8ade 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -689,16 +689,7 @@ fn make_install_cmd() -> String { } fn os() -> &'static str { - let os_name = if cfg!(target_os = "linux") { - "linux" - } else if cfg!(target_os = "macos") { - "macos" - } else if cfg!(target_os = "windows") { - "windows" - } else { - built_info::CFG_OS - }; - NodePlugin::map_os(os_name) + NodePlugin::map_os(built_info::CFG_OS) } fn arch(settings: &Settings) -> &str { From 0ec28914b5bbafb6a1f6be281a7a397c549a3fbf Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 7 Sep 2025 18:35:15 +0000 Subject: [PATCH 6/6] fix(bun): use full architecture variants in GitHub release asset patterns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The get_github_release_info method was using simplified architecture mapping that didn't account for Bun's complex variants (musl, baseline). This caused mismatches between lockfile metadata and actual release assets. Changes: - Add get_bun_arch_for_target() to handle platform qualifiers - Update asset pattern generation to use full arch variants - Support musl, baseline, and musl-baseline variants This ensures lockfile metadata correctly references existing Bun release assets like bun-linux-x64-musl.zip and bun-darwin-x64-baseline.zip. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/plugins/core/bun.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/plugins/core/bun.rs b/src/plugins/core/bun.rs index 9e828fce40..e221b498c7 100644 --- a/src/plugins/core/bun.rs +++ b/src/plugins/core/bun.rs @@ -130,9 +130,9 @@ impl Backend for BunPlugin { let version = &tv.version; // Build the asset pattern for Bun's GitHub releases - // Pattern: bun-{os}-{arch}.zip + // Pattern: bun-{os}-{arch}.zip (where arch may include variants like -musl, -baseline) let os_name = Self::map_os_to_bun(target.os_name()); - let arch_name = Self::map_arch_to_bun(target.arch_name()); + let arch_name = Self::get_bun_arch_for_target(target); let asset_pattern = format!("bun-{os_name}-{arch_name}.zip"); Ok(Some(GitHubReleaseInfo { @@ -167,6 +167,24 @@ impl BunPlugin { } } + /// Get the full Bun arch string for a target platform + /// This handles musl, baseline, and other variants based on platform qualifiers + fn get_bun_arch_for_target(target: &PlatformTarget) -> String { + let base_arch = Self::map_arch_to_bun(target.arch_name()); + + // Handle qualifiers like musl, baseline, etc. + if let Some(qualifier) = target.qualifier() { + match qualifier { + "musl" => format!("{}-musl", base_arch), + "musl-baseline" => format!("{}-musl-baseline", base_arch), + "baseline" => format!("{}-baseline", base_arch), + other => format!("{}-{}", base_arch, other), + } + } else { + base_arch.to_string() + } + } + /// Get the full Bun arch string with variants (musl, baseline, etc.) fn get_bun_arch_with_variants() -> &'static str { if cfg!(target_arch = "x86_64") {