use color_eyre::eyre::{eyre, ContextCompat, Result};
use crate::cli::args::runtime::{RuntimeArg, RuntimeArgParser};
use crate::cli::command::Command;
use crate::config::{config_file, Config};
use crate::output::Output;
use crate::plugins::PluginName;
use crate::{dirs, env, file};
#[derive(Debug, clap::Args)]
#[clap(verbatim_doc_comment, visible_alias = "l", after_long_help = AFTER_LONG_HELP)]
pub struct Local {
#[clap(value_parser = RuntimeArgParser)]
runtime: Option<Vec<RuntimeArg>>,
#[clap(short, long)]
parent: bool,
#[clap(long)]
fuzzy: bool,
#[clap(long, value_name = "PLUGIN")]
remove: Option<Vec<PluginName>>,
}
impl Command for Local {
fn run(self, config: Config, out: &mut Output) -> Result<()> {
let cf_path = match self.parent {
true => file::find_up(
&dirs::CURRENT,
&[env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()],
)
.with_context(|| {
eyre!(
"no {} file found",
env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()
)
})?,
false => dirs::CURRENT.join(env::RTX_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()),
};
let mut cf = match cf_path.exists() {
true => config_file::parse(&cf_path)?,
false => config_file::init(&cf_path),
};
if let Some(plugins) = &self.remove {
for plugin in plugins {
cf.remove_plugin(plugin);
}
}
if let Some(runtimes) = &self.runtime {
let runtimes = RuntimeArg::double_runtime_condition(runtimes);
cf.add_runtimes(&config, &runtimes, self.fuzzy)?;
}
if self.runtime.is_some() || self.remove.is_some() {
cf.save()?;
}
rtxprint!(out, "{}", cf.dump());
Ok(())
}
}
const AFTER_LONG_HELP: &str = r#"
Examples:
# set the current version of nodejs to 20.x for the current directory
# will use a precise version (e.g.: 20.0.0) in .tool-versions file
$ rtx local nodejs@20
# set nodejs to 20.x for the current project (recurses up to find .tool-versions)
$ rtx local -p nodejs@20
# set the current version of nodejs to 20.x for the current directory
# will use a fuzzy version (e.g.: 20) in .tool-versions file
$ rtx local --fuzzy nodejs@20
# removes nodejs from .tool-versions
$ rtx local --remove=nodejs
"#;
#[cfg(test)]
mod test {
use std::fs;
use insta::assert_snapshot;
use pretty_assertions::assert_str_eq;
use crate::cli::test::grep;
use crate::{assert_cli, dirs};
#[test]
fn test_local() {
let cf_path = dirs::CURRENT.join(".tool-versions");
let orig = fs::read_to_string(&cf_path).unwrap();
assert_cli!("plugin", "add", "nodejs");
assert_cli!("install", "shfmt@2");
let stdout = assert_cli!("local", "shfmt@2");
assert_snapshot!(stdout);
let stdout = assert_cli!("local", "--fuzzy", "shfmt@2");
assert_snapshot!(stdout);
let stdout = assert_cli!("local", "--remove", "nodejs");
assert_snapshot!(stdout);
let stdout = assert_cli!("ls", "--current");
assert_str_eq!(
grep(stdout, "nodejs"),
" nodejs 18.0.0 (missing) (set by ~/cwd/.node-version)"
);
let stdout = assert_cli!("local", "tiny@1");
assert_str_eq!(grep(stdout, "tiny"), "tiny 1.0.1");
let stdout = assert_cli!("local", "tiny", "2");
assert_str_eq!(grep(stdout, "tiny"), "tiny 2.1.0");
fs::write(cf_path, orig).unwrap();
}
}