mirror of
https://github.com/nushell/nushell
synced 2024-12-30 15:03:25 +00:00
Support other variables than PATH in pathvar (#3791)
* Fix swapped PATH env var separators * Support pathvar to manipulate other vars than PATH * Add tests for pathvar and its subcommands * Fix PATH env name for Windows Seems like Windows uses PATH as well. Co-authored-by: Jakub Žádník <jakub.zadnik@tuni.fi>
This commit is contained in:
parent
d88d7f26e4
commit
f9f39c0a1c
10 changed files with 504 additions and 44 deletions
|
@ -1,9 +1,10 @@
|
||||||
|
use super::get_var;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use nu_engine::WholeStreamCommand;
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Signature, SyntaxShape};
|
use nu_protocol::{Signature, SyntaxShape};
|
||||||
use nu_source::Tagged;
|
use nu_source::Tagged;
|
||||||
use nu_test_support::{NATIVE_PATH_ENV_SEPARATOR, NATIVE_PATH_ENV_VAR};
|
use nu_test_support::NATIVE_PATH_ENV_SEPARATOR;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
@ -14,7 +15,14 @@ impl WholeStreamCommand for SubCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("pathvar add").required("path", SyntaxShape::FilePath, "path to add")
|
Signature::build("pathvar add")
|
||||||
|
.required("path", SyntaxShape::FilePath, "path to add")
|
||||||
|
.named(
|
||||||
|
"var",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"Use a different variable than PATH",
|
||||||
|
Some('v'),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
|
@ -37,17 +45,21 @@ impl WholeStreamCommand for SubCommand {
|
||||||
pub fn add(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn add(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let ctx = &args.context;
|
let ctx = &args.context;
|
||||||
|
|
||||||
|
let var = get_var(&args)?;
|
||||||
let path_to_add: Tagged<PathBuf> = args.req(0)?;
|
let path_to_add: Tagged<PathBuf> = args.req(0)?;
|
||||||
let path = path_to_add.item.into_os_string().into_string();
|
let path = path_to_add.item.into_os_string().into_string();
|
||||||
|
|
||||||
if let Ok(mut path) = path {
|
if let Ok(mut path) = path {
|
||||||
path.push(NATIVE_PATH_ENV_SEPARATOR);
|
path.push(NATIVE_PATH_ENV_SEPARATOR);
|
||||||
if let Some(old_pathvar) = ctx.scope.get_env(NATIVE_PATH_ENV_VAR) {
|
if let Some(old_pathvar) = ctx.scope.get_env(&var) {
|
||||||
path.push_str(&old_pathvar);
|
path.push_str(&old_pathvar);
|
||||||
ctx.scope.add_env_var(NATIVE_PATH_ENV_VAR, path);
|
ctx.scope.add_env_var(&var.item, path);
|
||||||
Ok(OutputStream::empty())
|
Ok(OutputStream::empty())
|
||||||
} else {
|
} else {
|
||||||
Err(ShellError::unexpected("PATH not set"))
|
Err(ShellError::unexpected(&format!(
|
||||||
|
"Variable {} not set",
|
||||||
|
&var.item
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(ShellError::labeled_error(
|
Err(ShellError::labeled_error(
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
use super::get_var;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use nu_engine::WholeStreamCommand;
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Signature, SyntaxShape};
|
use nu_protocol::{Signature, SyntaxShape};
|
||||||
use nu_source::Tagged;
|
use nu_source::Tagged;
|
||||||
use nu_test_support::{NATIVE_PATH_ENV_SEPARATOR, NATIVE_PATH_ENV_VAR};
|
use nu_test_support::NATIVE_PATH_ENV_SEPARATOR;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
@ -14,7 +15,14 @@ impl WholeStreamCommand for SubCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("pathvar append").required("path", SyntaxShape::FilePath, "path to append")
|
Signature::build("pathvar append")
|
||||||
|
.required("path", SyntaxShape::FilePath, "path to append")
|
||||||
|
.named(
|
||||||
|
"var",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"Use a different variable than PATH",
|
||||||
|
Some('v'),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
|
@ -36,17 +44,22 @@ impl WholeStreamCommand for SubCommand {
|
||||||
|
|
||||||
pub fn add(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn add(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let ctx = &args.context;
|
let ctx = &args.context;
|
||||||
|
|
||||||
|
let var = get_var(&args)?;
|
||||||
let path_to_append_arg: Tagged<PathBuf> = args.req(0)?;
|
let path_to_append_arg: Tagged<PathBuf> = args.req(0)?;
|
||||||
let path_to_append = path_to_append_arg.item.into_os_string().into_string();
|
let path_to_append = path_to_append_arg.item.into_os_string().into_string();
|
||||||
|
|
||||||
if let Ok(path) = path_to_append {
|
if let Ok(path) = path_to_append {
|
||||||
if let Some(mut pathvar) = ctx.scope.get_env(NATIVE_PATH_ENV_VAR) {
|
if let Some(mut pathvar) = ctx.scope.get_env(&var) {
|
||||||
pathvar.push(NATIVE_PATH_ENV_SEPARATOR);
|
pathvar.push(NATIVE_PATH_ENV_SEPARATOR);
|
||||||
pathvar.push_str(&path);
|
pathvar.push_str(&path);
|
||||||
ctx.scope.add_env_var(NATIVE_PATH_ENV_VAR, pathvar);
|
ctx.scope.add_env_var(&var.item, pathvar);
|
||||||
Ok(OutputStream::empty())
|
Ok(OutputStream::empty())
|
||||||
} else {
|
} else {
|
||||||
Err(ShellError::unexpected("PATH not set"))
|
Err(ShellError::unexpected(&format!(
|
||||||
|
"Variable {} not set",
|
||||||
|
&var.item
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(ShellError::labeled_error(
|
Err(ShellError::labeled_error(
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
use super::get_var;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use nu_engine::WholeStreamCommand;
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Signature, Value};
|
use nu_protocol::{Signature, SyntaxShape, Value};
|
||||||
use nu_test_support::{NATIVE_PATH_ENV_SEPARATOR, NATIVE_PATH_ENV_VAR};
|
use nu_test_support::NATIVE_PATH_ENV_SEPARATOR;
|
||||||
|
|
||||||
pub struct Command;
|
pub struct Command;
|
||||||
|
|
||||||
|
@ -12,11 +13,17 @@ impl WholeStreamCommand for Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("pathvar")
|
Signature::build("pathvar").named(
|
||||||
|
"var",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"Use a different variable than PATH",
|
||||||
|
Some('v'),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"Manipulate the PATH variable (or pathvar)."
|
r#"Manipulate the PATH variable (pathvar) or a different variable following the
|
||||||
|
same rules."#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
|
@ -30,6 +37,11 @@ impl WholeStreamCommand for Command {
|
||||||
example: "pathvar",
|
example: "pathvar",
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
|
Example {
|
||||||
|
description: "Display the current session's LD_LIBRARY_PATH",
|
||||||
|
example: "pathvar -v LD_LIBRARY_PATH",
|
||||||
|
result: None,
|
||||||
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Add /usr/bin to the pathvar",
|
description: "Add /usr/bin to the pathvar",
|
||||||
example: "pathvar add /usr/bin",
|
example: "pathvar add /usr/bin",
|
||||||
|
@ -45,7 +57,9 @@ impl WholeStreamCommand for Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_pathvar(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn get_pathvar(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
if let Some(pathvar) = args.context.scope.get_env(NATIVE_PATH_ENV_VAR) {
|
let var = get_var(&args)?;
|
||||||
|
|
||||||
|
if let Some(pathvar) = args.context.scope.get_env(&var) {
|
||||||
let pathvar: Vec<Value> = pathvar
|
let pathvar: Vec<Value> = pathvar
|
||||||
.split(NATIVE_PATH_ENV_SEPARATOR)
|
.split(NATIVE_PATH_ENV_SEPARATOR)
|
||||||
.map(Value::from)
|
.map(Value::from)
|
||||||
|
@ -53,6 +67,9 @@ pub fn get_pathvar(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
|
|
||||||
Ok(OutputStream::from(pathvar))
|
Ok(OutputStream::from(pathvar))
|
||||||
} else {
|
} else {
|
||||||
Err(ShellError::unexpected("PATH not set"))
|
Err(ShellError::unexpected(&format!(
|
||||||
|
"Variable {} not set",
|
||||||
|
&var.item
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,3 +11,15 @@ pub use command::Command as Pathvar;
|
||||||
pub use remove::SubCommand as PathvarRemove;
|
pub use remove::SubCommand as PathvarRemove;
|
||||||
pub use reset::SubCommand as PathvarReset;
|
pub use reset::SubCommand as PathvarReset;
|
||||||
pub use save::SubCommand as PathvarSave;
|
pub use save::SubCommand as PathvarSave;
|
||||||
|
|
||||||
|
use nu_engine::CommandArgs;
|
||||||
|
use nu_errors::ShellError;
|
||||||
|
use nu_source::{Tagged, TaggedItem};
|
||||||
|
use nu_test_support::NATIVE_PATH_ENV_VAR;
|
||||||
|
|
||||||
|
fn get_var(args: &CommandArgs) -> Result<Tagged<String>, ShellError> {
|
||||||
|
Ok(args
|
||||||
|
.get_flag("var")?
|
||||||
|
.unwrap_or_else(|| String::from(NATIVE_PATH_ENV_VAR))
|
||||||
|
.tagged_unknown())
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
use super::get_var;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use nu_engine::WholeStreamCommand;
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Signature, SyntaxShape};
|
use nu_protocol::{Signature, SyntaxShape};
|
||||||
use nu_source::Tagged;
|
use nu_source::Tagged;
|
||||||
use nu_test_support::{NATIVE_PATH_ENV_SEPARATOR, NATIVE_PATH_ENV_VAR};
|
use nu_test_support::NATIVE_PATH_ENV_SEPARATOR;
|
||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
|
||||||
|
@ -13,11 +14,18 @@ impl WholeStreamCommand for SubCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("pathvar remove").required(
|
Signature::build("pathvar remove")
|
||||||
|
.required(
|
||||||
"index",
|
"index",
|
||||||
SyntaxShape::Int,
|
SyntaxShape::Int,
|
||||||
"index of the path to remove (starting at 0)",
|
"index of the path to remove (starting at 0)",
|
||||||
)
|
)
|
||||||
|
.named(
|
||||||
|
"var",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"Use a different variable than PATH",
|
||||||
|
Some('v'),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
|
@ -39,10 +47,12 @@ impl WholeStreamCommand for SubCommand {
|
||||||
|
|
||||||
pub fn remove(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn remove(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let ctx = &args.context;
|
let ctx = &args.context;
|
||||||
|
|
||||||
|
let var = get_var(&args)?;
|
||||||
let index_to_remove_arg: Tagged<u64> = args.req(0)?;
|
let index_to_remove_arg: Tagged<u64> = args.req(0)?;
|
||||||
let index_to_remove = index_to_remove_arg.item as usize;
|
let index_to_remove = index_to_remove_arg.item as usize;
|
||||||
|
|
||||||
if let Some(old_pathvar) = ctx.scope.get_env(NATIVE_PATH_ENV_VAR) {
|
if let Some(old_pathvar) = ctx.scope.get_env(&var) {
|
||||||
let mut paths: Vec<&str> = old_pathvar.split(NATIVE_PATH_ENV_SEPARATOR).collect();
|
let mut paths: Vec<&str> = old_pathvar.split(NATIVE_PATH_ENV_SEPARATOR).collect();
|
||||||
|
|
||||||
if index_to_remove >= paths.len() {
|
if index_to_remove >= paths.len() {
|
||||||
|
@ -55,12 +65,15 @@ pub fn remove(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
|
|
||||||
paths.remove(index_to_remove);
|
paths.remove(index_to_remove);
|
||||||
ctx.scope.add_env_var(
|
ctx.scope.add_env_var(
|
||||||
NATIVE_PATH_ENV_VAR,
|
&var.item,
|
||||||
paths.join(&NATIVE_PATH_ENV_SEPARATOR.to_string()),
|
paths.join(&NATIVE_PATH_ENV_SEPARATOR.to_string()),
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(OutputStream::empty())
|
Ok(OutputStream::empty())
|
||||||
} else {
|
} else {
|
||||||
Err(ShellError::unexpected("PATH not set"))
|
Err(ShellError::unexpected(&format!(
|
||||||
|
"Variable {} not set",
|
||||||
|
&var.item
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
use super::get_var;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use nu_engine::WholeStreamCommand;
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Signature, UntaggedValue};
|
use nu_protocol::{Signature, SyntaxShape, UntaggedValue};
|
||||||
use nu_test_support::{NATIVE_PATH_ENV_SEPARATOR, NATIVE_PATH_ENV_VAR};
|
use nu_test_support::NATIVE_PATH_ENV_SEPARATOR;
|
||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
|
||||||
|
@ -12,7 +13,12 @@ impl WholeStreamCommand for SubCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("pathvar reset")
|
Signature::build("pathvar reset").named(
|
||||||
|
"var",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"Use a different variable than PATH",
|
||||||
|
Some('v'),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
|
@ -23,24 +29,29 @@ impl WholeStreamCommand for SubCommand {
|
||||||
reset(args)
|
reset(args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn reset(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let name = args.call_info.name_tag.clone();
|
let name = args.call_info.name_tag.clone();
|
||||||
let ctx = &args.context;
|
let ctx = &args.context;
|
||||||
|
|
||||||
|
let var = get_var(&args)?;
|
||||||
|
let var_lower = var.clone().map(|s| s.to_lowercase());
|
||||||
|
|
||||||
if let Some(global_cfg) = &mut ctx.configs().lock().global_config {
|
if let Some(global_cfg) = &mut ctx.configs().lock().global_config {
|
||||||
let default_pathvar = global_cfg.vars.get("path");
|
let default_pathvar = global_cfg.vars.get(&var_lower.item);
|
||||||
if let Some(pathvar) = default_pathvar {
|
if let Some(pathvar) = default_pathvar {
|
||||||
if let UntaggedValue::Table(paths) = &pathvar.value {
|
if let UntaggedValue::Table(paths) = &pathvar.value {
|
||||||
let pathvar_str = paths
|
let pathvar_str = paths
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| x.as_string().expect("Error converting path to string"))
|
.map(|x| x.as_string().expect("Error converting path to string"))
|
||||||
.join(&NATIVE_PATH_ENV_SEPARATOR.to_string());
|
.join(&NATIVE_PATH_ENV_SEPARATOR.to_string());
|
||||||
ctx.scope.add_env_var(NATIVE_PATH_ENV_VAR, pathvar_str);
|
ctx.scope.add_env_var(&var.item, pathvar_str);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(ShellError::untagged_runtime_error(
|
return Err(ShellError::untagged_runtime_error(&format!(
|
||||||
"Default path is not set in config file.",
|
"Default {} is not set in config file.",
|
||||||
));
|
&var_lower.item
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
Ok(OutputStream::empty())
|
Ok(OutputStream::empty())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
use super::get_var;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use nu_engine::WholeStreamCommand;
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Signature, UntaggedValue, Value};
|
use nu_protocol::{Signature, SyntaxShape, UntaggedValue, Value};
|
||||||
use nu_test_support::{NATIVE_PATH_ENV_SEPARATOR, NATIVE_PATH_ENV_VAR};
|
use nu_test_support::NATIVE_PATH_ENV_SEPARATOR;
|
||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
|
||||||
|
@ -12,7 +13,12 @@ impl WholeStreamCommand for SubCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("pathvar save")
|
Signature::build("pathvar save").named(
|
||||||
|
"var",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"Use a different variable than PATH",
|
||||||
|
Some('v'),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
|
@ -27,8 +33,11 @@ pub fn save(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let name = args.call_info.name_tag.clone();
|
let name = args.call_info.name_tag.clone();
|
||||||
let ctx = &args.context;
|
let ctx = &args.context;
|
||||||
|
|
||||||
|
let var = get_var(&args)?;
|
||||||
|
let var_lower = var.clone().map(|s| s.to_lowercase());
|
||||||
|
|
||||||
if let Some(global_cfg) = &mut ctx.configs().lock().global_config {
|
if let Some(global_cfg) = &mut ctx.configs().lock().global_config {
|
||||||
if let Some(pathvar) = ctx.scope.get_env(NATIVE_PATH_ENV_VAR) {
|
if let Some(pathvar) = ctx.scope.get_env(&var) {
|
||||||
let paths: Vec<Value> = pathvar
|
let paths: Vec<Value> = pathvar
|
||||||
.split(NATIVE_PATH_ENV_SEPARATOR)
|
.split(NATIVE_PATH_ENV_SEPARATOR)
|
||||||
.map(Value::from)
|
.map(Value::from)
|
||||||
|
@ -40,13 +49,16 @@ pub fn save(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
Tag::from(Span::from(&span_range)),
|
Tag::from(Span::from(&span_range)),
|
||||||
);
|
);
|
||||||
|
|
||||||
global_cfg.vars.insert("path".to_string(), row);
|
global_cfg.vars.insert(var_lower.item, row);
|
||||||
global_cfg.write()?;
|
global_cfg.write()?;
|
||||||
ctx.reload_config(global_cfg)?;
|
ctx.reload_config(global_cfg)?;
|
||||||
|
|
||||||
Ok(OutputStream::empty())
|
Ok(OutputStream::empty())
|
||||||
} else {
|
} else {
|
||||||
Err(ShellError::unexpected("PATH not set"))
|
Err(ShellError::unexpected(&format!(
|
||||||
|
"Variable {} not set",
|
||||||
|
&var.item
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let value = UntaggedValue::Error(crate::commands::config::err_no_global_cfg_present())
|
let value = UntaggedValue::Error(crate::commands::config::err_no_global_cfg_present())
|
||||||
|
|
|
@ -37,6 +37,7 @@ mod move_;
|
||||||
mod open;
|
mod open;
|
||||||
mod parse;
|
mod parse;
|
||||||
mod path;
|
mod path;
|
||||||
|
mod pathvar;
|
||||||
mod prepend;
|
mod prepend;
|
||||||
mod random;
|
mod random;
|
||||||
mod range;
|
mod range;
|
||||||
|
|
372
crates/nu-command/tests/commands/pathvar/mod.rs
Normal file
372
crates/nu-command/tests/commands/pathvar/mod.rs
Normal file
|
@ -0,0 +1,372 @@
|
||||||
|
use nu_test_support::fs::Stub::FileWithContent;
|
||||||
|
use nu_test_support::fs::{AbsolutePath, DisplayPath};
|
||||||
|
use nu_test_support::playground::{says, Playground};
|
||||||
|
use nu_test_support::{nu, NATIVE_PATH_ENV_SEPARATOR};
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use hamcrest2::assert_that;
|
||||||
|
use hamcrest2::prelude::*;
|
||||||
|
|
||||||
|
/// Helper function that joins string literals with ':' or ';', based on host OS
|
||||||
|
fn join_env_sep(pieces: &[&str]) -> String {
|
||||||
|
let sep_string = String::from(NATIVE_PATH_ENV_SEPARATOR);
|
||||||
|
pieces.join(&sep_string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
#[test]
|
||||||
|
fn joins_env_on_windows() {
|
||||||
|
let pieces = ["sausage", "bacon", "spam"];
|
||||||
|
let actual = join_env_sep(&pieces);
|
||||||
|
|
||||||
|
assert_eq!(&actual, "sausage;bacon;spam");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
#[test]
|
||||||
|
fn joins_env_on_non_windows() {
|
||||||
|
let pieces = ["sausage", "bacon", "spam"];
|
||||||
|
let actual = join_env_sep(&pieces);
|
||||||
|
|
||||||
|
assert_eq!(&actual, "sausage:bacon:spam");
|
||||||
|
}
|
||||||
|
|
||||||
|
// pathvar
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pathvar_correctly_reads_path_from_config_and_env() {
|
||||||
|
Playground::setup("hi_there", |dirs, sandbox| {
|
||||||
|
let file = AbsolutePath::new(dirs.test().join("config.toml"));
|
||||||
|
|
||||||
|
sandbox
|
||||||
|
.with_files(vec![FileWithContent(
|
||||||
|
"config.toml",
|
||||||
|
r#"
|
||||||
|
skip_welcome_message = true
|
||||||
|
|
||||||
|
path = ["/Users/andresrobalino/.volta/bin", "/Users/mosqueteros/bin"]
|
||||||
|
"#,
|
||||||
|
)])
|
||||||
|
.with_config(&file)
|
||||||
|
.with_env(
|
||||||
|
nu_test_support::NATIVE_PATH_ENV_VAR,
|
||||||
|
&PathBuf::from("/Users/mosquito/proboscis").display_path(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected =
|
||||||
|
"/Users/andresrobalino/.volta/bin-/Users/mosqueteros/bin-/Users/mosquito/proboscis";
|
||||||
|
let actual = sandbox.pipeline(r#" pathvar | str collect '-' "#);
|
||||||
|
|
||||||
|
assert_that!(actual, says().stdout(&expected));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pathvar_correctly_reads_env_var_from_config_and_env() {
|
||||||
|
Playground::setup("hi_there", |_, sandbox| {
|
||||||
|
sandbox.with_env(
|
||||||
|
"BREAKFAST",
|
||||||
|
&join_env_sep(&["egg", "sausage", "bacon", "spam"]),
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected = "egg-sausage-bacon-spam";
|
||||||
|
let actual = sandbox.pipeline(r#" pathvar -v BREAKFAST | str collect '-' "#);
|
||||||
|
|
||||||
|
assert_that!(actual, says().stdout(&expected));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// pathvar add
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pathvar_adds_to_path() {
|
||||||
|
Playground::setup("hi_there", |_, sandbox| {
|
||||||
|
sandbox.with_env(
|
||||||
|
nu_test_support::NATIVE_PATH_ENV_VAR,
|
||||||
|
&PathBuf::from("/Users/mosquito/proboscis").display_path(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected = "spam-/Users/mosquito/proboscis";
|
||||||
|
let actual = sandbox.pipeline(r#" pathvar add spam; $nu.path | str collect '-' "#);
|
||||||
|
|
||||||
|
assert_that!(actual, says().stdout(&expected));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pathvar_adds_to_env_var() {
|
||||||
|
Playground::setup("hi_there", |_, sandbox| {
|
||||||
|
sandbox.with_env("BREAKFAST", &join_env_sep(&["egg", "sausage", "bacon"]));
|
||||||
|
|
||||||
|
let expected = join_env_sep(&["spam", "egg", "sausage", "bacon"]);
|
||||||
|
let actual = sandbox.pipeline(r#" pathvar add -v BREAKFAST spam; $nu.env.BREAKFAST "#);
|
||||||
|
|
||||||
|
assert_that!(actual, says().stdout(&expected));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// pathvar append
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pathvar_appends_to_path() {
|
||||||
|
Playground::setup("hi_there", |_, sandbox| {
|
||||||
|
sandbox.with_env(
|
||||||
|
nu_test_support::NATIVE_PATH_ENV_VAR,
|
||||||
|
&PathBuf::from("/Users/mosquito/proboscis").display_path(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected = "/Users/mosquito/proboscis-spam";
|
||||||
|
let actual = sandbox.pipeline(r#" pathvar append spam; $nu.path | str collect '-' "#);
|
||||||
|
|
||||||
|
assert_that!(actual, says().stdout(&expected));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pathvar_appends_to_env_var() {
|
||||||
|
Playground::setup("hi_there", |_, sandbox| {
|
||||||
|
sandbox.with_env("BREAKFAST", &join_env_sep(&["egg", "sausage", "bacon"]));
|
||||||
|
|
||||||
|
let expected = join_env_sep(&["egg", "sausage", "bacon", "spam"]);
|
||||||
|
let actual = sandbox.pipeline(r#" pathvar append -v BREAKFAST spam; $nu.env.BREAKFAST "#);
|
||||||
|
|
||||||
|
assert_that!(actual, says().stdout(&expected));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// pathvar remove
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pathvar_removes_from_path() {
|
||||||
|
Playground::setup("hi_there", |_, sandbox| {
|
||||||
|
sandbox.with_env(
|
||||||
|
nu_test_support::NATIVE_PATH_ENV_VAR,
|
||||||
|
&join_env_sep(&["/Users/mosquito/proboscis", "spam"]),
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected = "/Users/mosquito/proboscis";
|
||||||
|
let actual = sandbox.pipeline(r#" pathvar remove 1; $nu.path"#);
|
||||||
|
|
||||||
|
assert_that!(actual, says().stdout(&expected));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pathvar_removes_from_env_var() {
|
||||||
|
Playground::setup("hi_there", |_, sandbox| {
|
||||||
|
sandbox.with_env(
|
||||||
|
"BREAKFAST",
|
||||||
|
&join_env_sep(&["egg", "sausage", "bacon", "spam"]),
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected = join_env_sep(&["egg", "sausage", "bacon"]);
|
||||||
|
let actual = sandbox.pipeline(r#" pathvar remove -v BREAKFAST 3; $nu.env.BREAKFAST "#);
|
||||||
|
|
||||||
|
assert_that!(actual, says().stdout(&expected));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// pathvar reset
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pathvar_resets_path_from_config() {
|
||||||
|
Playground::setup("hi_there", |dirs, sandbox| {
|
||||||
|
let file = AbsolutePath::new(dirs.test().join("config.toml"));
|
||||||
|
|
||||||
|
sandbox
|
||||||
|
.with_files(vec![FileWithContent(
|
||||||
|
"config.toml",
|
||||||
|
r#"
|
||||||
|
skip_welcome_message = true
|
||||||
|
|
||||||
|
path = ["/Users/andresrobalino/.volta/bin", "/Users/mosqueteros/bin"]
|
||||||
|
"#,
|
||||||
|
)])
|
||||||
|
.with_config(&file)
|
||||||
|
.with_env(
|
||||||
|
nu_test_support::NATIVE_PATH_ENV_VAR,
|
||||||
|
&PathBuf::from("/Users/mosquito/proboscis").display_path(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected = "/Users/andresrobalino/.volta/bin-/Users/mosqueteros/bin";
|
||||||
|
let actual = sandbox.pipeline(
|
||||||
|
r#"
|
||||||
|
pathvar reset
|
||||||
|
pathvar | str collect '-'
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_that!(actual, says().stdout(&expected));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pathvar_resets_env_var_from_config() {
|
||||||
|
Playground::setup("hi_there", |dirs, sandbox| {
|
||||||
|
let file = AbsolutePath::new(dirs.test().join("config.toml"));
|
||||||
|
|
||||||
|
sandbox
|
||||||
|
.with_files(vec![FileWithContent(
|
||||||
|
"config.toml",
|
||||||
|
r#"
|
||||||
|
skip_welcome_message = true
|
||||||
|
|
||||||
|
breakfast = ["egg", "sausage", "bacon"]
|
||||||
|
"#,
|
||||||
|
)])
|
||||||
|
.with_config(&file)
|
||||||
|
.with_env(
|
||||||
|
"BREAKFAST",
|
||||||
|
&join_env_sep(&["egg", "sausage", "bacon", "spam"]),
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected = "egg-sausage-bacon";
|
||||||
|
let actual = sandbox.pipeline(
|
||||||
|
r#"
|
||||||
|
pathvar reset -v BREAKFAST
|
||||||
|
pathvar -v BREAKFAST | str collect '-'
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_that!(actual, says().stdout(&expected));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// pathvar save
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pathvar_saves_path_to_config() {
|
||||||
|
Playground::setup("hi_there", |dirs, sandbox| {
|
||||||
|
let file = AbsolutePath::new(dirs.test().join("config.toml"));
|
||||||
|
|
||||||
|
sandbox
|
||||||
|
.with_files(vec![FileWithContent(
|
||||||
|
"config.toml",
|
||||||
|
r#"
|
||||||
|
skip_welcome_message = true
|
||||||
|
|
||||||
|
path = ["/Users/andresrobalino/.volta/bin", "/Users/mosqueteros/bin"]
|
||||||
|
"#,
|
||||||
|
)])
|
||||||
|
.with_config(&file)
|
||||||
|
.with_env(
|
||||||
|
nu_test_support::NATIVE_PATH_ENV_VAR,
|
||||||
|
&PathBuf::from("/Users/mosquito/proboscis").display_path(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected =
|
||||||
|
"/Users/andresrobalino/.volta/bin-/Users/mosqueteros/bin-/Users/mosquito/proboscis";
|
||||||
|
let actual = sandbox.pipeline(
|
||||||
|
r#"
|
||||||
|
pathvar save
|
||||||
|
$nu.path | str collect '-'
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_that!(actual, says().stdout(&expected));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pathvar_saves_env_var_to_config() {
|
||||||
|
Playground::setup("hi_there", |dirs, sandbox| {
|
||||||
|
let file = AbsolutePath::new(dirs.test().join("config.toml"));
|
||||||
|
|
||||||
|
sandbox
|
||||||
|
.with_files(vec![FileWithContent(
|
||||||
|
"config.toml",
|
||||||
|
r#"
|
||||||
|
skip_welcome_message = true
|
||||||
|
|
||||||
|
breakfast = ["egg", "sausage", "bacon"]
|
||||||
|
"#,
|
||||||
|
)])
|
||||||
|
.with_config(&file)
|
||||||
|
.with_env("BREAKFAST", "spam");
|
||||||
|
|
||||||
|
let expected = "spam";
|
||||||
|
let actual = sandbox.pipeline(
|
||||||
|
r#"
|
||||||
|
pathvar save -v BREAKFAST
|
||||||
|
(config).breakfast | str collect '-'
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_that!(actual, says().stdout(&expected));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pathvar_saves_new_path_to_config() {
|
||||||
|
Playground::setup("hi_there", |dirs, sandbox| {
|
||||||
|
let file = AbsolutePath::new(dirs.test().join("config.toml"));
|
||||||
|
|
||||||
|
sandbox
|
||||||
|
.with_files(vec![FileWithContent(
|
||||||
|
"config.toml",
|
||||||
|
r#"
|
||||||
|
skip_welcome_message = true
|
||||||
|
"#,
|
||||||
|
)])
|
||||||
|
.with_config(&file)
|
||||||
|
.with_env(
|
||||||
|
nu_test_support::NATIVE_PATH_ENV_VAR,
|
||||||
|
&PathBuf::from("/Users/mosquito/proboscis").display_path(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected = "/Users/mosquito/proboscis";
|
||||||
|
let actual = sandbox.pipeline(
|
||||||
|
r#"
|
||||||
|
pathvar save
|
||||||
|
$nu.path | str collect '-'
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_that!(actual, says().stdout(&expected));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pathvar_saves_new_env_var_to_config() {
|
||||||
|
Playground::setup("hi_there", |dirs, sandbox| {
|
||||||
|
let file = AbsolutePath::new(dirs.test().join("config.toml"));
|
||||||
|
|
||||||
|
sandbox
|
||||||
|
.with_files(vec![FileWithContent(
|
||||||
|
"config.toml",
|
||||||
|
r#"
|
||||||
|
skip_welcome_message = true
|
||||||
|
"#,
|
||||||
|
)])
|
||||||
|
.with_config(&file)
|
||||||
|
.with_env("BREAKFAST", "spam");
|
||||||
|
|
||||||
|
let expected = "spam";
|
||||||
|
let actual = sandbox.pipeline(
|
||||||
|
r#"
|
||||||
|
pathvar save -v BREAKFAST
|
||||||
|
(config).breakfast | str collect '-'
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_that!(actual, says().stdout(&expected));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// test some errors
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pathvar_error_non_existent_env_var() {
|
||||||
|
Playground::setup("hi_there", |dirs, _| {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: dirs.test(),
|
||||||
|
"pathvar -v EGGS_BACON_SPAM_SAUSAGE_SPAM_AND_SPAM_WITH_EXTRA_SPAM"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(actual.err.contains("Error"));
|
||||||
|
assert!(actual.err.contains("not set"));
|
||||||
|
})
|
||||||
|
}
|
|
@ -9,15 +9,12 @@ pub struct Outcome {
|
||||||
pub err: String,
|
pub err: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
pub const NATIVE_PATH_ENV_VAR: &str = "Path";
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
pub const NATIVE_PATH_ENV_VAR: &str = "PATH";
|
pub const NATIVE_PATH_ENV_VAR: &str = "PATH";
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub const NATIVE_PATH_ENV_SEPARATOR: char = ':';
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
pub const NATIVE_PATH_ENV_SEPARATOR: char = ';';
|
pub const NATIVE_PATH_ENV_SEPARATOR: char = ';';
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
pub const NATIVE_PATH_ENV_SEPARATOR: char = ':';
|
||||||
|
|
||||||
impl Outcome {
|
impl Outcome {
|
||||||
pub fn new(out: String, err: String) -> Outcome {
|
pub fn new(out: String, err: String) -> Outcome {
|
||||||
|
|
Loading…
Reference in a new issue