Skip to content
Merged
Show file tree
Hide file tree
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
24 changes: 22 additions & 2 deletions docs/dev-tools/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,28 @@ ripgrep = { version = "latest", os = ["linux", "macos"] }
The `os` field accepts an array of operating system identifiers:

- `"linux"` - All Linux distributions
- `"macos"` - macOS (Darwin)
- `"windows"` - Windows
- `"macos"` - macOS (Darwin). `"darwin"` is also accepted as an alias.
- `"windows"` - Windows. `"win"` is also accepted as an alias.

### OS/Architecture Combinations

You can also restrict tools to specific OS and architecture combinations using the `os/arch` syntax:

```toml
[tools]
# Only install on macOS ARM64 and all Linux (skips macOS x86_64)
hk = { version = "latest", os = ["linux", "macos/arm64"] }

# Only install on Linux x86_64
mytool = { version = "latest", os = ["linux/x64"] }
```

Supported architecture identifiers:

- `"arm64"` (or `"aarch64"`)
- `"x64"` (or `"x86_64"` or `"amd64"`)

When an entry contains `/`, both the OS and architecture must match. When an entry is just an OS name, it matches any architecture on that OS.

If a tool specifies an `os` restriction and the current operating system is not in the list, mise will skip installing and using that tool.

Expand Down
62 changes: 62 additions & 0 deletions e2e/tools/test_os_arch_filter
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env bash

# Test that os field supports os/arch compound syntax for filtering tools.

# Tool with a non-matching os/arch should be skipped (not installed).
# "windows/arm64" won't match any CI runner or dev machine running this test.
cat >mise.toml <<'EOF'
[tools]
tiny = { version = "latest", os = ["windows/arm64"] }
EOF
mise i
assert_fail_contains "mise ls --installed tiny" "tiny is not installed"

# Tool matching just the OS (no arch) should still work as before.
cat >mise.toml <<'EOF'
[tools]
tiny = { version = "latest", os = ["macos", "linux"] }
EOF
mise i
assert_contains "mise ls --installed tiny" "tiny"
mise uninstall --all tiny

# Tool with matching os/arch should install on this platform.
# Detect current platform to construct a matching entry.
case "$(uname -s)" in
Darwin) _os="macos" ;;
Linux) _os="linux" ;;
*) _os="windows" ;;
esac
case "$(uname -m)" in
x86_64) _arch="x64" ;;
aarch64 | arm64) _arch="arm64" ;;
*) _arch="$(uname -m)" ;;
Comment thread
greptile-apps[bot] marked this conversation as resolved.
esac

cat >mise.toml <<EOF
[tools]
tiny = { version = "latest", os = ["${_os}/${_arch}"] }
EOF
mise i
assert_contains "mise ls --installed tiny" "tiny"
mise uninstall --all tiny

# Tool with a mix: matching os (any arch) + non-matching os/arch should install.
cat >mise.toml <<EOF
[tools]
tiny = { version = "latest", os = ["${_os}", "windows/arm64"] }
EOF
mise i
assert_contains "mise ls --installed tiny" "tiny"
mise uninstall --all tiny

# darwin alias should work in compound syntax.
if [ "$_os" = "macos" ]; then
cat >mise.toml <<EOF
[tools]
tiny = { version = "latest", os = ["darwin/${_arch}"] }
EOF
mise i
assert_contains "mise ls --installed tiny" "tiny"
mise uninstall --all tiny
fi
58 changes: 54 additions & 4 deletions src/toolset/tool_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,15 +358,43 @@ impl ToolRequest {
}

pub fn is_os_supported(&self) -> bool {
if let Some(os) = self.os()
&& !os.contains(&crate::cli::version::OS)
{
return false;
if let Some(os_list) = self.os() {
let current_os = &crate::cli::version::OS;
let current_arch = &crate::cli::version::ARCH;
let matched = os_list.iter().any(|entry| {
if let Some((os, arch)) = entry.split_once('/') {
normalize_os(os) == current_os.as_str()
&& normalize_arch(arch) == current_arch.as_str()
} else {
normalize_os(entry) == current_os.as_str()
}
});
if !matched {
return false;
}
}
self.ba().is_os_supported()
}
}

/// Normalize OS name aliases to the canonical form used by `std::env::consts::OS`.
fn normalize_os(os: &str) -> &str {
match os {
"darwin" | "macos" => "macos",
"windows" | "win" => "windows",
other => other,
}
}

/// Normalize architecture name aliases to the canonical form used by `cli::version::ARCH`.
fn normalize_arch(arch: &str) -> &str {
match arch {
"x86_64" | "amd64" | "x64" => "x64",
"aarch64" | "arm64" => "arm64",
other => other,
}
}

pub fn effective_before_date(
request: &ToolRequest,
opts: &ResolveOptions,
Expand Down Expand Up @@ -516,4 +544,26 @@ mod tests {
assert_str_eq!(version_sub("1.2.3", "0.2.4"), "0");
assert_str_eq!(version_sub("1.3.3", "0.2.4"), "1.0");
}

#[test]
fn test_normalize_os() {
use super::normalize_os;
assert_eq!(normalize_os("macos"), "macos");
assert_eq!(normalize_os("darwin"), "macos");
assert_eq!(normalize_os("linux"), "linux");
assert_eq!(normalize_os("windows"), "windows");
assert_eq!(normalize_os("win"), "windows");
assert_eq!(normalize_os("freebsd"), "freebsd");
}

#[test]
fn test_normalize_arch() {
use super::normalize_arch;
assert_eq!(normalize_arch("arm64"), "arm64");
assert_eq!(normalize_arch("aarch64"), "arm64");
assert_eq!(normalize_arch("x64"), "x64");
assert_eq!(normalize_arch("x86_64"), "x64");
assert_eq!(normalize_arch("amd64"), "x64");
assert_eq!(normalize_arch("riscv64"), "riscv64");
}
}
Loading