Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ pub struct Settings {"#
.to_string(),
];

println!("cargo:rerun-if-changed=settings.toml");
let settings_toml = fs::read_to_string("settings.toml").expect("Failed to read settings.toml");
let settings: toml::Table =
toml::de::from_str(&settings_toml).expect("Failed to parse settings.toml");
Expand Down
3 changes: 2 additions & 1 deletion schema/mise.json
Original file line number Diff line number Diff line change
Expand Up @@ -919,7 +919,8 @@
"package_manager": {
"default": "npm",
"description": "Package manager to use for installing npm packages.",
"type": "string"
"type": "string",
"enum": ["npm", "bun", "pnpm"]
}
}
},
Expand Down
2 changes: 2 additions & 0 deletions settings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1030,7 +1030,9 @@ Can be one of:
- `bun`
- `pnpm`
"""
enum = ["npm", "bun", "pnpm"]
env = "MISE_NPM_PACKAGE_MANAGER"
rust_type = "NpmPackageManager"
type = "String"

[offline]
Expand Down
27 changes: 14 additions & 13 deletions src/backend/npm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::backend::backend_type::BackendType;
use crate::cache::{CacheManager, CacheManagerBuilder};
use crate::cli::args::BackendArg;
use crate::cmd::CmdLineRunner;
use crate::config::settings::NpmPackageManager;
use crate::config::{Config, Settings};
use crate::install_context::InstallContext;
use crate::timeout;
Expand Down Expand Up @@ -39,31 +40,31 @@ impl Backend for NPMBackend {
// package manager for installation. We avoid listing all package managers to
// prevent incorrect dependency edges.
let settings = Settings::get();
let package_manager = settings.npm.package_manager.as_str();
let package_manager = settings.npm.package_manager;
let tool_name = self.tool_name();

// Avoid circular dependency when installing npm itself
// But we still need the configured package manager for installation
if tool_name == "npm" {
return match package_manager {
"bun" => Ok(vec!["node", "bun"]),
"pnpm" => Ok(vec!["node", "pnpm"]),
NpmPackageManager::Bun => Ok(vec!["node", "bun"]),
NpmPackageManager::Pnpm => Ok(vec!["node", "pnpm"]),
_ => Ok(vec!["node"]),
Comment thread
risu729 marked this conversation as resolved.
Outdated
Comment thread
risu729 marked this conversation as resolved.
Outdated
};
}

// Avoid circular dependency when installing the configured package manager
// e.g., npm:bun with bun configured, or npm:pnpm with pnpm configured
if tool_name == package_manager {
if tool_name == package_manager.to_string() {
// Still need npm for version queries
return Ok(vec!["node", "npm"]);
}

// For regular packages: need npm (for version queries) + configured package manager
let mut deps = vec!["node", "npm"];
match package_manager {
"bun" => deps.push("bun"),
"pnpm" => deps.push("pnpm"),
NpmPackageManager::Bun => deps.push("bun"),
NpmPackageManager::Pnpm => deps.push("pnpm"),
// npm is already in deps
_ => {}
Comment thread
risu729 marked this conversation as resolved.
Outdated
Comment thread
risu729 marked this conversation as resolved.
Outdated
}
Expand Down Expand Up @@ -149,8 +150,8 @@ impl Backend for NPMBackend {

async fn install_version_(&self, ctx: &InstallContext, tv: ToolVersion) -> Result<ToolVersion> {
self.check_install_deps(&ctx.config).await;
match Settings::get().npm.package_manager.as_str() {
"bun" => {
match Settings::get().npm.package_manager {
NpmPackageManager::Bun => {
CmdLineRunner::new("bun")
.arg("install")
.arg(format!("{}@{}", self.tool_name(), tv.version))
Expand All @@ -174,7 +175,7 @@ impl Backend for NPMBackend {
.current_dir(tv.install_path())
.execute()?;
}
"pnpm" => {
NpmPackageManager::Pnpm => {
let bin_dir = tv.install_path().join("bin");
crate::file::create_dir_all(&bin_dir)?;
CmdLineRunner::new("pnpm")
Expand Down Expand Up @@ -228,7 +229,7 @@ impl Backend for NPMBackend {
_config: &Arc<Config>,
tv: &crate::toolset::ToolVersion,
) -> eyre::Result<Vec<std::path::PathBuf>> {
if Settings::get().npm.package_manager == "npm" {
if Settings::get().npm.package_manager == NpmPackageManager::Npm {
Ok(vec![tv.install_path()])
} else {
Ok(vec![tv.install_path().join("bin")])
Expand Down Expand Up @@ -264,8 +265,8 @@ impl NPMBackend {

/// Check dependencies for package installation (npm or bun based on settings)
async fn check_install_deps(&self, config: &Arc<Config>) {
match Settings::get().npm.package_manager.as_str() {
"bun" => {
match Settings::get().npm.package_manager {
NpmPackageManager::Bun => {
self.warn_if_dependency_missing(
config,
"bun",
Expand All @@ -276,7 +277,7 @@ impl NPMBackend {
)
.await
}
"pnpm" => {
NpmPackageManager::Pnpm => {
self.warn_if_dependency_missing(
config,
"pnpm",
Expand Down
23 changes: 22 additions & 1 deletion src/config/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,27 @@ pub enum SettingsStatusMissingTools {
Always,
}

#[derive(
Debug,
Clone,
Copy,
Serialize,
Deserialize,
Default,
strum::EnumString,
strum::Display,
PartialEq,
Eq,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum NpmPackageManager {
#[default]
Npm,
Bun,
Pnpm,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum PythonUvVenvAuto {
#[default]
Expand Down Expand Up @@ -359,7 +380,7 @@ impl Settings {
self.python.venv_auto_create = python_venv_auto_create;
}
if self.npm.bun {
self.npm.package_manager = "bun".to_string();
self.npm.package_manager = NpmPackageManager::Bun;
}
}

Expand Down
Loading