From 16a6a2ae13d2ba8062bbccb7df56b911ddd5f097 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 26 Apr 2026 15:54:22 +0000 Subject: [PATCH] feat(backend): add global libc preference --- crates/vfox/src/config.rs | 2 +- crates/vfox/src/plugin.rs | 8 +- crates/vfox/src/runtime.rs | 7 +- crates/vfox/src/vfox.rs | 20 ++- docs/lang/node.md | 3 + docs/mise-cookbook/docker.md | 14 +- schema/mise.json | 5 + settings.toml | 14 ++ src/backend/aqua.rs | 283 +++++++++++++++++++++++++++++---- src/backend/asset_matcher.rs | 19 ++- src/backend/platform_target.rs | 13 ++ src/cache.rs | 7 +- src/config/settings.rs | 8 + src/platform.rs | 38 +++-- src/plugins/core/bun.rs | 10 +- src/plugins/core/node.rs | 31 +++- src/plugins/core/python.rs | 25 ++- src/plugins/vfox_plugin.rs | 7 + 18 files changed, 439 insertions(+), 75 deletions(-) diff --git a/crates/vfox/src/config.rs b/crates/vfox/src/config.rs index ba6839f21d..4eecc71aba 100644 --- a/crates/vfox/src/config.rs +++ b/crates/vfox/src/config.rs @@ -55,7 +55,7 @@ pub(crate) fn env_type() -> Option { if let Ok(val) = std::env::var("MISE_LIBC") { match val.to_lowercase().as_str() { "musl" => return Some("musl".to_string()), - "gnu" => return Some("gnu".to_string()), + "glibc" | "gnu" => return Some("gnu".to_string()), _ => {} // invalid value ignored, fall through to runtime detection } } diff --git a/crates/vfox/src/plugin.rs b/crates/vfox/src/plugin.rs index b49b440c99..79f3cd6218 100644 --- a/crates/vfox/src/plugin.rs +++ b/crates/vfox/src/plugin.rs @@ -24,6 +24,7 @@ pub enum PluginSource { pub struct Plugin { pub name: String, pub dir: PathBuf, + pub runtime_env_type: Option, source: PluginSource, lua: Lua, metadata: OnceCell, @@ -41,6 +42,7 @@ impl Plugin { Ok(Self { name, dir: dir.to_path_buf(), + runtime_env_type: None, source: PluginSource::Filesystem(dir.to_path_buf()), lua, metadata: OnceCell::new(), @@ -57,6 +59,7 @@ impl Plugin { Ok(Self { name: name.to_string(), dir: dummy_dir, + runtime_env_type: None, source: PluginSource::Embedded(embedded), lua, metadata: OnceCell::new(), @@ -209,7 +212,10 @@ impl Plugin { let metadata = self.load_metadata()?; self.set_global("PLUGIN", metadata.clone())?; - self.set_global("RUNTIME", Runtime::get(self.dir.clone()))?; + self.set_global( + "RUNTIME", + Runtime::get(self.dir.clone(), self.runtime_env_type.as_deref()), + )?; self.set_global("OS_TYPE", config::os())?; self.set_global("ARCH_TYPE", config::arch())?; diff --git a/crates/vfox/src/runtime.rs b/crates/vfox/src/runtime.rs index a65fb07fdb..7dc7a79d5b 100644 --- a/crates/vfox/src/runtime.rs +++ b/crates/vfox/src/runtime.rs @@ -24,14 +24,17 @@ static RUNTIME: Lazy> = Lazy::new(|| { }); impl Runtime { - pub(crate) fn get(plugin_dir_path: PathBuf) -> Runtime { + pub(crate) fn get(plugin_dir_path: PathBuf, env_type_override: Option<&str>) -> Runtime { let mut runtime = RUNTIME.lock().unwrap().clone(); runtime.plugin_dir_path = plugin_dir_path; + if let Some(env_type) = env_type_override { + runtime.env_type = Some(env_type.to_string()); + } runtime } pub(crate) fn with_platform(plugin_dir_path: PathBuf, os: &str, arch: &str) -> Runtime { - let mut runtime = Self::get(plugin_dir_path); + let mut runtime = Self::get(plugin_dir_path, None); runtime.os = os.to_string(); runtime.arch = arch.to_string(); runtime.env_type = None; // target libc is unknown in cross-platform context diff --git a/crates/vfox/src/vfox.rs b/crates/vfox/src/vfox.rs index 4dfd1fda3c..e0316a34ae 100644 --- a/crates/vfox/src/vfox.rs +++ b/crates/vfox/src/vfox.rs @@ -55,6 +55,8 @@ pub struct Vfox { pub cmd_env: Option>, /// Optional GitHub token for Lua http requests to GitHub API endpoints. pub github_token: Option, + /// Optional runtime env type (`gnu` or `musl`) exposed to plugin hooks. + pub runtime_env_type: Option, log_tx: Option>, } @@ -123,7 +125,9 @@ impl Vfox { } pub fn get_sdk(&self, name: &str) -> Result { - Plugin::from_name_or_dir(name, &self.plugin_dir.join(name)) + let mut plugin = Plugin::from_name_or_dir(name, &self.plugin_dir.join(name))?; + plugin.runtime_env_type = self.runtime_env_type.clone(); + Ok(plugin) } fn get_sdk_with_env(&self, name: &str) -> Result { @@ -146,12 +150,16 @@ impl Vfox { // Check filesystem first - allows user to override embedded plugins let plugin_dir = self.plugin_dir.join(sdk); if plugin_dir.exists() { - return Plugin::from_dir(&plugin_dir); + let mut plugin = Plugin::from_dir(&plugin_dir)?; + plugin.runtime_env_type = self.runtime_env_type.clone(); + return Ok(plugin); } // Fall back to embedded plugin if available if let Some(embedded) = crate::embedded_plugins::get_embedded_plugin(sdk) { - return Plugin::from_embedded(sdk, embedded); + let mut plugin = Plugin::from_embedded(sdk, embedded)?; + plugin.runtime_env_type = self.runtime_env_type.clone(); + return Ok(plugin); } // Otherwise install from registry @@ -175,7 +183,9 @@ impl Vfox { debug!("Installing plugin {sdk}"); xx::git::clone(url.as_ref(), &plugin_dir, &Default::default())?; } - Plugin::from_dir(&plugin_dir) + let mut plugin = Plugin::from_dir(&plugin_dir)?; + plugin.runtime_env_type = self.runtime_env_type.clone(); + Ok(plugin) } pub fn uninstall_plugin(&self, sdk: &str) -> Result<()> { @@ -588,6 +598,7 @@ impl Default for Vfox { skip_verification: false, cmd_env: None, github_token: None, + runtime_env_type: None, log_tx: None, } } @@ -615,6 +626,7 @@ mod tests { skip_verification: false, cmd_env: None, github_token: None, + runtime_env_type: None, log_tx: None, } } diff --git a/docs/lang/node.md b/docs/lang/node.md index e4ae9ca10b..11621f4e79 100644 --- a/docs/lang/node.md +++ b/docs/lang/node.md @@ -108,6 +108,9 @@ mise settings node.flavor=musl mise settings node.flavor=glibc-217 ``` +For the common musl case, `mise settings libc=musl` also selects Node's `musl` +flavor when `node.flavor` is unset. + ## Settings