-
-
Notifications
You must be signed in to change notification settings - Fork 769
feat(lock): add resolve_lock_info to core backends for checksum fetching #7180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements resolve_lock_info for core backends (node, bun, go, deno, zig) to enable checksum fetching during mise lock operations without downloading full tarballs. It also introduces HTTP caching infrastructure to prevent redundant network requests when fetching checksums for multiple platforms.
Key Changes:
- Added
resolve_lock_infoimplementations for 5 core backends to fetch checksums from upstream sources - Introduced HTTP caching with per-URL
OnceCellto deduplicate concurrent requests - Added shared helper functions to reduce code duplication across backends
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/plugins/core/zig.rs | Implements resolve_lock_info using cached JSON index with embedded checksums/sizes |
| src/plugins/core/node.rs | Implements resolve_lock_info using cached SHASUMS256.txt file |
| src/plugins/core/go.rs | Implements resolve_lock_info using individual .sha256 files per tarball |
| src/plugins/core/deno.rs | Implements resolve_lock_info using individual .sha256sum files per zip |
| src/plugins/core/bun.rs | Implements resolve_lock_info using cached SHASUMS256.txt from GitHub releases |
| src/http.rs | Adds get_text_cached and json_cached methods with per-URL OnceCell caching |
| src/backend/static_helpers.rs | Adds fetch_checksum_from_shasums and fetch_checksum_from_file helper functions |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Ok(PlatformInfo { | ||
| url: Some(format!( | ||
| "https://ziglang.org/download/{}/zig-{}-{}-{}.tar.xz", | ||
| tv.version, os, arch, tv.version |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tarball filename format is incorrect - it should be zig-{os}-{arch}-{version}.tar.xz but the code generates zig-{version}-{os}-{arch}.tar.xz. The correct order based on standard Zig release naming is zig-{os}-{arch}-{version}.tar.xz.
| // Get or create the OnceCell for this URL | ||
| let cell = { | ||
| let mut cache = HTTP_CACHE.lock().unwrap(); | ||
| cache.entry(key).or_default().clone() |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The HashMap uses String keys which requires cloning the URL string. Consider using Arc<str> or a reference-counted key to avoid string clones on cache hits.
| /// when locking multiple platforms). Concurrent requests for the same URL will | ||
| /// wait for the first fetch to complete. | ||
| pub async fn get_text_cached<U: IntoUrl>(&self, url: U) -> Result<String> { | ||
| let url = url.into_url().unwrap(); |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using unwrap() here will panic on invalid URLs without a helpful error message. Consider using ? operator to propagate the error with proper context, or provide a descriptive error message.
| let url = url.into_url().unwrap(); | |
| let url = url.into_url().map_err(Into::into)?; |
52b498d to
56ce108
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 9 out of 10 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| impl PlatformInfo { | ||
| /// Returns true if this PlatformInfo has no meaningful data (for serde skip) | ||
| pub fn is_empty(&self) -> bool { | ||
| self.checksum.is_none() && self.url.is_none() && self.url_api.is_none() |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The is_empty() method doesn't check the size field. If size is the only populated field, this method will incorrectly return true. Either include size in the check or document why it's intentionally excluded.
| self.checksum.is_none() && self.url.is_none() && self.url_api.is_none() | |
| self.checksum.is_none() | |
| && self.size.is_none() | |
| && self.url.is_none() | |
| && self.url_api.is_none() |
|
|
||
| // Get or create the OnceCell for this URL | ||
| let cell = { | ||
| let mut cache = HTTP_CACHE.lock().unwrap(); |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using unwrap() on a Mutex::lock() can cause panics if the mutex is poisoned. Consider using lock().expect() with a descriptive message or handle the poison error explicitly to improve debugging.
| let mut cache = HTTP_CACHE.lock().unwrap(); | |
| let mut cache = HTTP_CACHE.lock().expect("Failed to lock HTTP_CACHE mutex (possibly poisoned)"); |
| Ok(PlatformInfo { | ||
| url: Some(format!( | ||
| "https://ziglang.org/download/{}/zig-{}-{}-{}.tar.xz", | ||
| tv.version, os, arch, tv.version |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The version appears twice in the URL format string (positions 1 and 4). Consider using a temporary variable to make this clearer and avoid potential inconsistencies if the format string is modified.
| Ok(PlatformInfo { | |
| url: Some(format!( | |
| "https://ziglang.org/download/{}/zig-{}-{}-{}.tar.xz", | |
| tv.version, os, arch, tv.version | |
| let version = &tv.version; | |
| Ok(PlatformInfo { | |
| url: Some(format!( | |
| "https://ziglang.org/download/{}/zig-{}-{}-{}.tar.xz", | |
| version, os, arch, version |
Implement resolve_lock_info for core backends (node, bun, go, zig, deno) to fetch checksums during `mise lock` without downloading full tarballs: - Node: fetches SHASUMS256.txt from nodejs.org mirror - Bun: fetches SHASUMS256.txt from GitHub releases - Go: fetches individual .sha256 files per tarball - Deno: fetches individual .sha256sum files per zip - Zig: extracts shasum/size from JSON version index Add HTTP caching infrastructure: - HTTP.get_text_cached() with per-URL OnceCell for concurrent-safe caching - HTTP_FETCH.json_cached() for repeated JSON index fetches - Prevents redundant network requests when fetching checksums for multiple platforms Add shared helper functions in static_helpers.rs: - fetch_checksum_from_shasums() for SHASUMS256.txt pattern - fetch_checksum_from_file() for individual checksum files 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
56ce108 to
b533ed6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Node flavor setting incorrectly applied to all platforms
The build_platform_slug method unconditionally applies the local node.flavor setting (like "glibc") to all target platforms during mise lock. However, flavor variants are platform-specific (e.g., glibc only exists for Linux). The original slug() function correctly uses the current platform's OS and arch, but this new method applies the local flavor to cross-platform targets like macOS, generating invalid URLs like node-v24-darwin-arm64-glibc.tar.gz. The checksum lookup in SHASUMS256.txt will fail to find these non-existent files.
src/plugins/core/node.rs#L668-L680
Lines 668 to 680 in b533ed6
| /// 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}") | |
| } else { | |
| format!("node-v{version}-{os}-{arch}") | |
| } | |
| } |
Bun has compile-time variants (baseline, musl) that result in different download URLs and checksums. This caused checksum mismatches when the lockfile had checksums for one variant but a different variant was downloaded at install time (e.g., windows-x64 vs windows-x64-baseline). Changes: - Add platform_variants() method to Backend trait for declaring variants - Update mise lock to expand platforms into all declared variants - Implement platform_variants for bun (baseline, musl, musl-baseline) - Override get_platform_key in bun to return correct variant at install - Add baseline and musl-baseline as valid platform qualifiers The lockfile now stores checksums for all platform variants, and at install time the correct variant is looked up based on compile-time features (AVX2, musl libc). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
The node.flavor setting (like "glibc") was being applied to all platforms during `mise lock`, but flavor variants only exist for Linux. This caused invalid URLs like `node-v24-darwin-arm64-glibc.tar.gz` to be generated, which would fail checksum lookup in SHASUMS256.txt. Now only apply the flavor setting when the target platform is Linux. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
|
bugbot run |
|
bugbot run |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Compound qualifiers cannot be parsed from platform keys
The Platform::parse function splits platform strings by - and only handles 2 or 3 parts. However, this PR adds "musl-baseline" as a valid qualifier (which contains a hyphen). When a Platform with this qualifier calls to_key(), it produces "linux-x64-musl-baseline" (4 parts when split). This cannot be parsed back because Platform::parse rejects strings with more than 3 hyphen-separated parts. This affects the lock command's determine_target_platforms function which silently ignores lockfile platform keys that fail to parse, and prevents users from explicitly specifying compound qualifier platforms via --platform.
src/platform.rs#L14-L33
Lines 14 to 33 in 852f661
| /// Parse a platform string in the format "os-arch" or "os-arch-qualifier" | |
| pub fn parse(platform_str: &str) -> Result<Self> { | |
| let parts: Vec<&str> = platform_str.split('-').collect(); | |
| match parts.len() { | |
| 2 => Ok(Platform { | |
| os: parts[0].to_string(), | |
| arch: parts[1].to_string(), | |
| qualifier: None, | |
| }), | |
| 3 => Ok(Platform { | |
| os: parts[0].to_string(), | |
| arch: parts[1].to_string(), | |
| qualifier: Some(parts[2].to_string()), | |
| }), | |
| _ => bail!( | |
| "Invalid platform format '{}'. Expected 'os-arch' or 'os-arch-qualifier'", | |
| platform_str | |
| ), | |
| } |
src/plugins/core/bun.rs#L225-L230
Lines 225 to 230 in 852f661
| }); | |
| variants.push(Platform { | |
| os: platform.os.clone(), | |
| arch: platform.arch.clone(), | |
| qualifier: Some("musl-baseline".to_string()), | |
| }); |
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.11.11 x -- echo |
19.0 ± 0.4 | 18.4 | 21.7 | 1.00 |
mise x -- echo |
19.0 ± 0.3 | 18.4 | 20.2 | 1.00 ± 0.02 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.11.11 env |
18.3 ± 0.3 | 17.8 | 19.3 | 1.00 |
mise env |
18.7 ± 0.5 | 17.9 | 22.4 | 1.02 ± 0.03 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.11.11 hook-env |
18.5 ± 0.4 | 17.9 | 23.4 | 1.00 |
mise hook-env |
18.7 ± 0.4 | 18.0 | 20.6 | 1.01 ± 0.03 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.11.11 ls |
15.7 ± 0.3 | 15.1 | 16.9 | 1.00 |
mise ls |
16.0 ± 0.4 | 15.3 | 18.1 | 1.02 ± 0.03 |
xtasks/test/perf
| Command | mise-2025.11.11 | mise | Variance |
|---|---|---|---|
| install (cached) | 105ms | 106ms | +0% |
| ls (cached) | 64ms | 64ms | +0% |
| bin-paths (cached) | 70ms | 70ms | +0% |
| task-ls (cached) | 430ms | 421ms | +2% |
Two fixes: 1. Platform parsing now handles compound qualifiers like "musl-baseline" by joining all parts after os-arch. Previously, "linux-x64-musl-baseline" would fail to parse because it has 4 hyphen-separated parts. 2. Bun's AVX2 detection now uses runtime CPUID instead of compile-time cfg! checks. This ensures the correct variant is selected based on the actual CPU capabilities, not how mise was compiled. musl detection remains compile-time since it depends on the binary's libc linkage. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
The node.flavor setting should only apply when locking the current platform, not all Linux platforms during cross-platform locking. This matches the behavior in resolve_lockfile_options which checks is_current_platform before including the flavor option. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
When platform_variants receives a platform that already has a qualifier (like linux-x64-musl), it should return just that platform instead of expanding variants. This prevents duplicate HTTP requests and tasks when a lockfile already contains variant platforms. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
The show_dry_run function now calls backend.platform_variants() to expand platforms into their variants, matching the behavior of process_tools. This ensures the dry-run output accurately shows all platform variants that would be locked (e.g., bun's baseline, musl variants). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…7181) ## Summary Fix a bug where invalid platform keys (like `linux-x64-wait-for-gh-rate-limit`) from tool-specific entries in the lockfile were being propagated as target platforms for all tools during `mise lock`. The issue was introduced in #7180 when collecting existing platforms from lockfiles. `Platform::parse()` accepts any qualifier string (like `wait-for-gh-rate-limit` from the `wait-for-gh-rate-limit` tool's lockfile entry), but these should not be used as target platforms for other tools. ### Root cause When `mise lock` runs, it collects target platforms from: 1. Common platforms (linux-x64, linux-arm64, macos-x64, macos-arm64, windows-x64) 2. Current platform 3. **Existing platforms in the lockfile** Step 3 was reading all `platforms.*` keys from all tools in the lockfile without validating that they're valid platform qualifiers. So when a tool like `wait-for-gh-rate-limit` had its own unique platform key `linux-x64-wait-for-gh-rate-limit`, that was added to the set of target platforms for ALL tools. ### The fix Now we call `platform.validate()` after parsing to ensure only known-valid qualifiers (`gnu`, `musl`, `msvc`, `baseline`, `musl-baseline`) are included as target platforms. ## Test plan - [x] Build succeeds - [x] Lint passes 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Validate lockfile platform keys and ignore invalid/tool-specific qualifiers when deriving target platforms for `mise lock`. > > - **Lock CLI**: > - Update `src/cli/lock.rs` `determine_target_platforms` to include lockfile platforms only if `Platform::validate()` succeeds, preventing tool-specific/invalid qualifiers from becoming target platforms. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit d7ef083. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Claude <[email protected]>
### 🚀 Features - **(config)** add support for netrc by @RobotSupervisor in [#7164](#7164) - **(lock)** add resolve_lock_info to core backends for checksum fetching by @jdx in [#7180](#7180) - **(ruby)** Install ruby from a zip file over HTTPS by @KaanYT in [#7167](#7167) - **(tasks)** add `usage` args to Tera context in run scripts by @iamkroot in [#7041](#7041) ### 🐛 Bug Fixes - **(lock)** validate platform qualifiers when reading from lockfile by @jdx in [#7181](#7181) - **(task)** retry shebang scripts on ETXTBUSY by @iamkroot in [#7162](#7162) - **(ui)** remove duplicate 'mise' prefix in verbose footer output by @jdx in [#7174](#7174) ### 📦️ Dependency Updates - bump usage-lib to 2.9.0 by @jdx in [#7177](#7177) ### 📦 Registry - remove duplicated ubi and github backends from gping by @risu729 in [#7144](#7144) - disable bashly test (not working in CI) by @jdx in [#7173](#7173) - disable cfn-lint test (failing in CI) by @jdx in [#7176](#7176) ### Chore - add fd to mise.toml by @blampe in [#7178](#7178) ### New Contributors - @RobotSupervisor made their first contribution in [#7164](#7164) ## 📦 Aqua Registry Updates #### New Packages (2) - [`Kitware/CMake`](https://github.com/Kitware/CMake) - [`quarto-dev/quarto-cli`](https://github.com/quarto-dev/quarto-cli) #### Updated Packages (6) - [`apache/jena`](https://github.com/apache/jena) - [`apache/spark`](https://github.com/apache/spark) - [`danielfoehrKn/kubeswitch`](https://github.com/danielfoehrKn/kubeswitch) - [`danielfoehrKn/kubeswitch/switch-sh`](https://github.com/danielfoehrKn/kubeswitch/switch-sh) - [`evilmartians/lefthook`](https://github.com/evilmartians/lefthook) - [`updatecli/updatecli`](https://github.com/updatecli/updatecli)
Summary
resolve_lock_infofor core backends (node, bun, go, zig, deno) to fetch checksums duringmise lockwithout downloading full tarballsOnceCellto prevent redundant network requests when fetching checksums for multiple platformsfetch_checksum_from_shasums,fetch_checksum_from_file) to reduce code duplicationBackend Status
HTTP Caching
Added
HTTP.get_text_cached()andHTTP_FETCH.json_cached()methods that use a per-URLOnceCellto:mise lockoperationThis addresses the issue where checksums were only being added during installation (via blake3 hash of downloaded files) rather than during
mise lock, which caused autofix CI to add checksums on release branches.Test plan
mise lockwith these tools and verify checksums are populated🤖 Generated with Claude Code
Note
Add resolve_lock_info to core backends to populate URLs/checksums during
mise lock, with per-URL HTTP caching and platform variant support.Backend::resolve_lock_infoacrosscore:node,core:bun,core:go,core:deno,core:zig, andcore:rubyto return downloadurlandchecksum(andsizefor zig) without installing.cli lockexpands backend-declared platform variants and processes each variant in parallel; dry-run reflects variants.SHASUMS256.txt.SHASUMS256.txt; overrideget_platform_key; exposeplatform_variants..sha256sidecar (honorsgo_skip_checksum)..sha256sumsidecar.HTTP.get_text_cachedandHTTP_FETCH.json_cachedusing per-URLOnceCellto dedupe concurrent/repeated requests.fetch_checksum_from_shasumsandfetch_checksum_from_filefor checksum retrieval.Platformparsing supports compound qualifiers (e.g.,musl-baseline) and validates new qualifiers.Backend::platform_variantshook; default returns base platform.PlatformInfo::is_empty;set_platform_infonow merges with existing data and skips empty entries.Locktool selection constrained to current config root.Written by Cursor Bugbot for commit 733c67f. This will update automatically on new commits. Configure here.