Skip to content

Commit

Permalink
feat(node): allow using node unofficial build flavors (#2637)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdx authored Sep 24, 2024
1 parent 0902d7d commit 98d969d
Show file tree
Hide file tree
Showing 10 changed files with 172 additions and 50 deletions.
23 changes: 23 additions & 0 deletions docs/lang/node.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,26 @@ mise uses a `.tool-versions` or `.mise.toml` file for auto-switching between sof
You cannot install/use a plugin named "nodejs". If you attempt this, mise will just rename it to
"node". See the [FAQ](https://github.com/jdx/mise#what-is-the-difference-between-nodejs-and-node-or-golang-and-go)
for an explanation.

## Unofficial Builds

Nodejs.org offers a set of [unofficial builds](https://unofficial-builds.nodejs.org/) which are
compatible with some platforms are not supported by the official binaries. These are a nice alternative to
compiling from source for these platforms.

To use, first set the mirror url to point to the unofficial builds:

```sh
mise settings set node.mirror_url https://unofficial-builds.nodejs.org/download/release/
```

If your goal is to simply support an alternative arch/os like linux-loong64 or linux-armv6l, this is
all that is required. Node also provides flavors such as musl or glibc-217 (an older glibc version
than what the official binaries are built with).

To use these, set `node.flavor`:

```sh
mise settings set node.flavor musl
mise settings set node.flavor glibc-217
```
20 changes: 20 additions & 0 deletions schema/mise.json
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,26 @@
"description": "path to file containing shorthand mappings",
"type": "string"
},
"node": {
"description": "settings specific to node",
"type": "object",
"additionalProperties": false,
"properties": {
"compile": {
"type": "boolean",
"description": "do not use precompiled binaries for node"
},
"flavor": {
"type": "string",
"description": "node flavor to use, generally used for unofficial builds"
},
"mirror_url": {
"type": "string",
"description": "url to use as a mirror for node downloads",
"default": "https://nodejs.org/dist"
}
}
},
"ruby": {
"description": "settings specific to ruby",
"type": "object",
Expand Down
5 changes: 4 additions & 1 deletion src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,10 @@ pub trait Backend: Debug + Send + Sync {
false
}
})
.collect();
.collect_vec();
if versions.is_empty() {
warn!("No versions found for {}", self.id());
}
Ok(versions)
}
fn _list_remote_versions(&self) -> eyre::Result<Vec<String>>;
Expand Down
5 changes: 3 additions & 2 deletions src/cli/settings/ls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ mod tests {
legacy_version_file = true
legacy_version_file_disable_tools = []
libgit2 = true
node_compile = false
not_found_auto_install = true
paranoid = false
pipx_uvx = false
Expand All @@ -98,6 +97,8 @@ mod tests {
vfox = false
yes = true
[node]
[ruby]
default_packages_file = "~/.default-gems"
ruby_build_repo = "https://github.com/rbenv/ruby-build.git"
Expand Down Expand Up @@ -139,7 +140,7 @@ mod tests {
legacy_version_file
legacy_version_file_disable_tools
libgit2
node_compile
node
not_found_auto_install
paranoid
pipx_uvx
Expand Down
22 changes: 17 additions & 5 deletions src/cli/settings/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ impl SettingsSet {
self.value.split(',').map(|s| s.to_string()).collect()
}
"libgit2" => parse_bool(&self.value)?,
"node_compile" => parse_bool(&self.value)?,
"node.compile" => parse_bool(&self.value)?,
"node.flavor" => self.value.into(),
"node.mirror_url" => self.value.into(),
"not_found_auto_install" => parse_bool(&self.value)?,
"paranoid" => parse_bool(&self.value)?,
"pipx_uvx" => parse_bool(&self.value)?,
Expand All @@ -57,6 +59,14 @@ impl SettingsSet {
"python_venv_auto_create" => parse_bool(&self.value)?,
"quiet" => parse_bool(&self.value)?,
"raw" => parse_bool(&self.value)?,
"ruby.apply_patches" => self.value.into(),
"ruby.default_packages_file" => self.value.into(),
"ruby.ruby_build_repo" => self.value.into(),
"ruby.ruby_build_opts" => self.value.into(),
"ruby.ruby_install" => parse_bool(&self.value)?,
"ruby.ruby_install_repo" => self.value.into(),
"ruby.ruby_install_opts" => self.value.into(),
"ruby.verbose_install" => parse_bool(&self.value)?,
"shorthands_file" => self.value.into(),
"status.missing_tools" => self.value.into(),
"status.show_env" => parse_bool(&self.value)?,
Expand All @@ -77,13 +87,14 @@ impl SettingsSet {
config["settings"] = toml_edit::Item::Table(toml_edit::Table::new());
}
let settings = config["settings"].as_table_mut().unwrap();
if self.setting.as_str().starts_with("status.") {
if self.setting.as_str().contains(".") {
let mut parts = self.setting.splitn(2, '.');
let status = settings
.entry("status")
.entry(parts.next().unwrap())
.or_insert(toml_edit::Item::Table(toml_edit::Table::new()))
.as_table_mut()
.unwrap();
status.insert(&self.setting[7..], toml_edit::Item::Value(value));
status.insert(parts.next().unwrap(), toml_edit::Item::Value(value));
} else {
settings.insert(&self.setting, toml_edit::Item::Value(value));
}
Expand Down Expand Up @@ -159,7 +170,6 @@ pub mod tests {
legacy_version_file = false
legacy_version_file_disable_tools = []
libgit2 = true
node_compile = false
not_found_auto_install = true
paranoid = false
pipx_uvx = false
Expand All @@ -174,6 +184,8 @@ pub mod tests {
vfox = false
yes = true
[node]
[ruby]
default_packages_file = "~/.default-gems"
ruby_build_repo = "https://github.com/rbenv/ruby-build.git"
Expand Down
3 changes: 2 additions & 1 deletion src/cli/settings/unset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ mod tests {
legacy_version_file = true
legacy_version_file_disable_tools = []
libgit2 = true
node_compile = false
not_found_auto_install = true
paranoid = false
pipx_uvx = false
Expand All @@ -89,6 +88,8 @@ mod tests {
vfox = false
yes = true
[node]
[ruby]
default_packages_file = "~/.default-gems"
ruby_build_repo = "https://github.com/rbenv/ruby-build.git"
Expand Down
43 changes: 36 additions & 7 deletions src/config/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ use std::iter::once;
use std::path::PathBuf;
use std::sync::{Arc, Mutex, RwLock};
use std::time::Duration;
use url::Url;

pub static SETTINGS: Lazy<Arc<Settings>> = Lazy::new(Settings::get);

#[rustfmt::skip]
#[derive(Config, Default, Debug, Clone, Serialize)]
Expand Down Expand Up @@ -93,8 +96,8 @@ pub struct Settings {
pub legacy_version_file_disable_tools: BTreeSet<String>,
#[config(env = "MISE_LIBGIT2", default = true)]
pub libgit2: bool,
#[config(env = "MISE_NODE_COMPILE", default = false)]
pub node_compile: bool,
#[config(nested)]
pub node: SettingsNode,
#[config(env = "MISE_NOT_FOUND_AUTO_INSTALL", default = true)]
pub not_found_auto_install: bool,
#[config(env = "MISE_PARANOID", default = false)]
Expand Down Expand Up @@ -163,6 +166,19 @@ pub struct Settings {
pub python_venv_auto_create: bool,
}

#[derive(Config, Default, Debug, Clone, Serialize)]
#[config(partial_attr(derive(Clone, Serialize, Default)))]
#[config(partial_attr(serde(deny_unknown_fields)))]
#[rustfmt::skip]
pub struct SettingsNode {
#[config(env = "MISE_NODE_COMPILE")]
pub compile: Option<bool>,
#[config(env = "MISE_NODE_FLAVOR")]
pub flavor: Option<String>,
#[config(env = "MISE_NODE_MIRROR_URL")]
pub mirror_url: Option<String>
}

#[derive(Config, Default, Debug, Clone, Serialize)]
#[config(partial_attr(derive(Clone, Serialize, Default)))]
#[config(partial_attr(serde(deny_unknown_fields)))]
Expand Down Expand Up @@ -221,7 +237,7 @@ pub enum SettingsStatusMissingTools {

pub type SettingsPartial = <Settings as Config>::Partial;

static SETTINGS: RwLock<Option<Arc<Settings>>> = RwLock::new(None);
static BASE_SETTINGS: RwLock<Option<Arc<Settings>>> = RwLock::new(None);
static CLI_SETTINGS: Mutex<Option<SettingsPartial>> = Mutex::new(None);
static DEFAULT_SETTINGS: Lazy<SettingsPartial> = Lazy::new(|| {
let mut s = SettingsPartial::empty();
Expand All @@ -245,7 +261,7 @@ impl Settings {
Self::try_get().unwrap()
}
pub fn try_get() -> Result<Arc<Self>> {
if let Some(settings) = SETTINGS.read().unwrap().as_ref() {
if let Some(settings) = BASE_SETTINGS.read().unwrap().as_ref() {
return Ok(settings.clone());
}

Expand Down Expand Up @@ -306,13 +322,13 @@ impl Settings {
settings.yes = true;
}
if settings.all_compile {
settings.node_compile = true;
settings.node.compile = Some(true);
if settings.python_compile.is_none() {
settings.python_compile = Some(true);
}
}
let settings = Arc::new(settings);
*SETTINGS.write().unwrap() = Some(settings.clone());
*BASE_SETTINGS.write().unwrap() = Some(settings.clone());
Ok(settings)
}
pub fn add_cli_matches(m: &clap::ArgMatches) {
Expand Down Expand Up @@ -429,7 +445,7 @@ impl Settings {

pub fn reset(cli_settings: Option<SettingsPartial>) {
*CLI_SETTINGS.lock().unwrap() = cli_settings;
*SETTINGS.write().unwrap() = None;
*BASE_SETTINGS.write().unwrap() = None;
}

pub fn ensure_experimental(&self, what: &str) -> Result<()> {
Expand Down Expand Up @@ -494,3 +510,16 @@ impl Display for Settings {
pub fn ensure_experimental(what: &str) -> Result<()> {
Settings::get().ensure_experimental(what)
}

pub const DEFAULT_NODE_MIRROR_URL: &str = "https://nodejs.org/dist/";

impl SettingsNode {
pub fn mirror_url(&self) -> Url {
let s = self
.mirror_url
.clone()
.or(env::var("NODE_BUILD_MIRROR_URL").ok())
.unwrap_or_else(|| DEFAULT_NODE_MIRROR_URL.to_string());
Url::parse(&s).unwrap()
}
}
10 changes: 0 additions & 10 deletions src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use std::{path, process};
use itertools::Itertools;
use log::LevelFilter;
use once_cell::sync::Lazy;
use url::Url;

use crate::cli::args::ProfileArg;
use crate::duration::HOURLY;
Expand Down Expand Up @@ -173,11 +172,6 @@ pub static PYENV_ROOT: Lazy<PathBuf> =
Lazy::new(|| var_path("PYENV_ROOT").unwrap_or_else(|| HOME.join(".pyenv")));

// node
pub static MISE_NODE_MIRROR_URL: Lazy<Url> = Lazy::new(|| {
var_url("MISE_NODE_MIRROR_URL")
.or_else(|| var_url("NODE_BUILD_MIRROR_URL"))
.unwrap_or_else(|| Url::parse("https://nodejs.org/dist/").unwrap())
});
pub static MISE_NODE_CONCURRENCY: Lazy<Option<usize>> = Lazy::new(|| {
var("MISE_NODE_CONCURRENCY")
.ok()
Expand Down Expand Up @@ -279,10 +273,6 @@ pub fn var_path(key: &str) -> Option<PathBuf> {
var_os(key).map(PathBuf::from).map(replace_path)
}

fn var_url(key: &str) -> Option<Url> {
var(key).ok().map(|v| Url::parse(&v).unwrap())
}

fn var_duration(key: &str) -> Option<Duration> {
var(key)
.ok()
Expand Down
Loading

0 comments on commit 98d969d

Please sign in to comment.