Skip to content

Commit 71f4036

Browse files
authored
feat: add global --env argument (jdx#2553)
1 parent 2de83b1 commit 71f4036

File tree

9 files changed

+120
-17
lines changed

9 files changed

+120
-17
lines changed

docs/cli/global-flags.md

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ do anything though.
77

88
Change directory before running command
99

10+
## `-P, --profile <PROFILE>`
11+
12+
Set the profile (environment)
13+
1014
## `-q, --quiet`
1115

1216
Suppress non-error messages

docs/profiles.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# Profiles
22

33
It's possible to have separate `.mise.toml` files in the same directory for different
4-
environments like `development` and `production`. To enable, set `MISE_ENV` to an environment like
5-
`development` or `production`. mise will then look for a `.mise.{MISE_ENV}.toml` file in the current directory.
4+
environments like `development` and `production`. To enable, either set the `-P,--profile` option or `MISE_ENV` environment
5+
variable to an environment like `development` or `production`. mise will then look for a `.mise.{MISE_ENV}.toml` file
6+
in the current directory.
67

78
mise will also look for "local" files like `.mise.local.toml` and `.mise.{MISE_ENV}.local.toml` in
89
the current directory. These are intended to not be committed to version control.

src/cli/args/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ pub use backend_arg::BackendArg;
22
pub use cd_arg::CdArg;
33
pub use env_var_arg::EnvVarArg;
44
pub use log_level_arg::{DebugArg, LogLevelArg, TraceArg};
5+
pub use profile_arg::ProfileArg;
56
pub use quiet_arg::QuietArg;
67
pub use tool_arg::{ToolArg, ToolVersionType};
78
pub use verbose_arg::VerboseArg;
@@ -11,6 +12,7 @@ mod backend_arg;
1112
mod cd_arg;
1213
mod env_var_arg;
1314
mod log_level_arg;
15+
mod profile_arg;
1416
mod quiet_arg;
1517
mod tool_arg;
1618
mod verbose_arg;

src/cli/args/profile_arg.rs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use clap::{Arg, ArgAction};
2+
3+
#[derive(Clone, Debug)]
4+
pub struct ProfileArg;
5+
6+
impl ProfileArg {
7+
pub fn arg() -> Arg {
8+
Arg::new("profile")
9+
.short('P')
10+
.long("profile")
11+
.help("Set the profile (environment)")
12+
.value_parser(clap::value_parser!(String))
13+
.value_name("PROFILE")
14+
.action(ArgAction::Set)
15+
.global(true)
16+
}
17+
}

src/cli/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ impl Cli {
190190
.subcommand_required(true)
191191
.after_long_help(AFTER_LONG_HELP)
192192
.arg(args::CdArg::arg())
193+
.arg(args::ProfileArg::arg())
193194
.arg(args::DebugArg::arg())
194195
.arg(args::LogLevelArg::arg())
195196
.arg(args::QuietArg::arg())

src/cli/set.rs

+32-7
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ use tabled::Tabled;
55

66
use crate::config::config_file::mise_toml::MiseToml;
77
use crate::config::config_file::ConfigFile;
8-
use crate::config::Config;
9-
use crate::env;
10-
use crate::file::display_path;
8+
use crate::config::{is_global_config, Config, LOCAL_CONFIG_FILENAMES};
9+
use crate::env::{self, MISE_DEFAULT_CONFIG_FILENAME};
10+
use crate::file::{self, display_path};
1111
use crate::ui::table;
1212

1313
use super::args::EnvVarArg;
@@ -59,10 +59,15 @@ impl Set {
5959
return Ok(());
6060
}
6161

62-
let filename = self.file.unwrap_or_else(|| match self.global {
63-
true => env::MISE_GLOBAL_CONFIG_FILE.clone(),
64-
false => env::MISE_DEFAULT_CONFIG_FILENAME.clone().into(),
65-
});
62+
let filename = if let Some(env) = &*env::MISE_ENV {
63+
config_file_from_dir(&env::current_dir()?.join(format!(".mise.{}.toml", env)))
64+
} else if self.global {
65+
env::MISE_GLOBAL_CONFIG_FILE.clone()
66+
} else if let Some(p) = &self.file {
67+
config_file_from_dir(p)
68+
} else {
69+
env::MISE_DEFAULT_CONFIG_FILENAME.clone().into()
70+
};
6671

6772
let mut mise_toml = get_mise_toml(&filename)?;
6873

@@ -103,6 +108,26 @@ fn get_mise_toml(filename: &Path) -> Result<MiseToml> {
103108
Ok(mise_toml)
104109
}
105110

111+
fn config_file_from_dir(p: &Path) -> PathBuf {
112+
if !p.is_dir() {
113+
return p.to_path_buf();
114+
}
115+
let mise_toml = p.join(&*MISE_DEFAULT_CONFIG_FILENAME);
116+
if mise_toml.exists() {
117+
return mise_toml;
118+
}
119+
let filenames = LOCAL_CONFIG_FILENAMES
120+
.iter()
121+
.rev()
122+
.filter(|f| is_global_config(Path::new(f)))
123+
.map(|f| f.to_string())
124+
.collect::<Vec<_>>();
125+
if let Some(p) = file::find_up(p, &filenames) {
126+
return p;
127+
}
128+
mise_toml
129+
}
130+
106131
#[derive(Tabled)]
107132
struct Row {
108133
key: String,

src/cli/unset.rs

+32-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use eyre::Result;
44

55
use crate::config::config_file::mise_toml::MiseToml;
66
use crate::config::config_file::ConfigFile;
7-
use crate::env;
7+
use crate::config::{is_global_config, LOCAL_CONFIG_FILENAMES};
8+
use crate::env::{self, MISE_DEFAULT_CONFIG_FILENAME};
9+
use crate::file;
810

911
/// Remove environment variable(s) from the config file
1012
///
@@ -28,10 +30,15 @@ pub struct Unset {
2830

2931
impl Unset {
3032
pub fn run(self) -> Result<()> {
31-
let filename = self.file.unwrap_or_else(|| match self.global {
32-
true => env::MISE_GLOBAL_CONFIG_FILE.clone(),
33-
false => env::MISE_DEFAULT_CONFIG_FILENAME.clone().into(),
34-
});
33+
let filename = if let Some(env) = &*env::MISE_ENV {
34+
config_file_from_dir(&env::current_dir()?.join(format!(".mise.{}.toml", env)))
35+
} else if self.global {
36+
env::MISE_GLOBAL_CONFIG_FILE.clone()
37+
} else if let Some(p) = &self.file {
38+
config_file_from_dir(p)
39+
} else {
40+
env::MISE_DEFAULT_CONFIG_FILENAME.clone().into()
41+
};
3542

3643
let mut mise_toml = get_mise_toml(&filename)?;
3744

@@ -54,6 +61,26 @@ fn get_mise_toml(filename: &Path) -> Result<MiseToml> {
5461
Ok(mise_toml)
5562
}
5663

64+
fn config_file_from_dir(p: &Path) -> PathBuf {
65+
if !p.is_dir() {
66+
return p.to_path_buf();
67+
}
68+
let mise_toml = p.join(&*MISE_DEFAULT_CONFIG_FILENAME);
69+
if mise_toml.exists() {
70+
return mise_toml;
71+
}
72+
let filenames = LOCAL_CONFIG_FILENAMES
73+
.iter()
74+
.rev()
75+
.filter(|f| is_global_config(Path::new(f)))
76+
.map(|f| f.to_string())
77+
.collect::<Vec<_>>();
78+
if let Some(p) = file::find_up(p, &filenames) {
79+
return p;
80+
}
81+
mise_toml
82+
}
83+
5784
#[cfg(test)]
5885
mod tests {
5986
use std::path::PathBuf;

src/cli/use.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,9 @@ impl Use {
135135
}
136136

137137
fn get_config_file(&self) -> Result<Box<dyn ConfigFile>> {
138-
let path = if self.global {
138+
let path = if let Some(env) = &*env::MISE_ENV {
139+
config_file_from_dir(&env::current_dir()?.join(format!(".mise.{}.toml", env)))
140+
} else if self.global {
139141
MISE_GLOBAL_CONFIG_FILE.clone()
140142
} else if let Some(env) = &self.env {
141143
config_file_from_dir(&env::current_dir()?.join(format!(".mise.{}.toml", env)))

src/env.rs

+26-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use log::LevelFilter;
1111
use once_cell::sync::Lazy;
1212
use url::Url;
1313

14+
use crate::cli::args::ProfileArg;
1415
use crate::duration::HOURLY;
1516
use crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches};
1617
use crate::file::replace_path;
@@ -71,8 +72,7 @@ pub static MISE_DEFAULT_TOOL_VERSIONS_FILENAME: Lazy<String> = Lazy::new(|| {
7172
});
7273
pub static MISE_DEFAULT_CONFIG_FILENAME: Lazy<String> =
7374
Lazy::new(|| var("MISE_DEFAULT_CONFIG_FILENAME").unwrap_or_else(|_| ".mise.toml".into()));
74-
pub static MISE_ENV: Lazy<Option<String>> =
75-
Lazy::new(|| var("MISE_ENV").or_else(|_| var("MISE_ENVIRONMENT")).ok());
75+
pub static MISE_ENV: Lazy<Option<String>> = Lazy::new(|| environment(&ARGS.read().unwrap()));
7676
pub static MISE_SETTINGS_FILE: Lazy<PathBuf> = Lazy::new(|| {
7777
var_path("MISE_SETTINGS_FILE").unwrap_or_else(|| MISE_CONFIG_DIR.join("settings.toml"))
7878
});
@@ -370,6 +370,30 @@ fn prefer_stale(args: &[String]) -> bool {
370370
.contains(&c.as_str());
371371
}
372372

373+
fn environment(args: &[String]) -> Option<String> {
374+
args.windows(2)
375+
.find_map(|window| {
376+
if window[0] == ProfileArg::arg().get_long().unwrap_or_default()
377+
|| window[0]
378+
== ProfileArg::arg()
379+
.get_short()
380+
.unwrap_or_default()
381+
.to_string()
382+
{
383+
Some(window[1].clone())
384+
} else {
385+
None
386+
}
387+
})
388+
.or_else(|| match var("MISE_ENV") {
389+
Ok(env) => Some(env),
390+
_ => match var("MISE_ENVIRONMENT") {
391+
Ok(env) => Some(env),
392+
_ => None,
393+
},
394+
})
395+
}
396+
373397
fn log_file_level() -> Option<LevelFilter> {
374398
let log_level = var("MISE_LOG_FILE_LEVEL").unwrap_or_default();
375399
log_level.parse::<LevelFilter>().ok()

0 commit comments

Comments
 (0)