mirror of
https://github.com/nushell/nushell.git
synced 2025-02-22 05:21:44 +01:00
Refactor/config commands (#3265)
* Use ctx.configs in all config commands * Remove all setting/accessing of vars.("config-path") * Add tests * Add comment * Reload cfg on remove * Hypocratic ws change * Use history_path in hist_or_default * Make clippy happy * Fix rebase stuff * Fix clippy lint
This commit is contained in:
parent
111ad868a7
commit
ac070ae942
@ -173,7 +173,7 @@ pub fn cli(context: EvaluationContext, options: Options) -> Result<(), Box<dyn E
|
||||
let _ = configure_rustyline_editor(&mut rl, cfg);
|
||||
let helper = Some(nu_line_editor_helper(&context, cfg));
|
||||
rl.set_helper(helper);
|
||||
nu_data::config::path::history_path(cfg)
|
||||
nu_data::config::path::history_path_or_default(cfg)
|
||||
} else {
|
||||
nu_data::config::path::default_history_path()
|
||||
};
|
||||
@ -420,15 +420,8 @@ pub fn load_local_cfg_if_present(context: &EvaluationContext) {
|
||||
}
|
||||
|
||||
fn load_cfg_as_global_cfg(context: &EvaluationContext, path: PathBuf) {
|
||||
if let Err(err) = context.load_config(&ConfigPath::Global(path.clone())) {
|
||||
if let Err(err) = context.load_config(&ConfigPath::Global(path)) {
|
||||
context.host.lock().print_err(err, &Text::from(""));
|
||||
} else {
|
||||
//TODO current commands assume to find path to global cfg file under config-path
|
||||
//TODO use newly introduced nuconfig::file_path instead
|
||||
context.scope.add_var(
|
||||
"config-path",
|
||||
UntaggedValue::filepath(path).into_untagged_value(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
@ -32,23 +32,22 @@ impl WholeStreamCommand for SubCommand {
|
||||
}
|
||||
|
||||
pub fn clear(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name_span = args.call_info.name_tag.clone();
|
||||
let ctx = EvaluationContext::from_args(&args);
|
||||
|
||||
let path = match args.scope.get_var("config-path") {
|
||||
Some(Value {
|
||||
value: UntaggedValue::Primitive(Primitive::FilePath(path)),
|
||||
..
|
||||
}) => Some(path),
|
||||
_ => nu_data::config::default_path().ok(),
|
||||
let result = if let Some(global_cfg) = &mut args.configs.lock().global_config {
|
||||
global_cfg.vars.clear();
|
||||
global_cfg.write()?;
|
||||
ctx.reload_config(global_cfg)?;
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::Row(global_cfg.vars.clone().into()).into_value(args.call_info.name_tag),
|
||||
)))
|
||||
} else {
|
||||
Ok(vec![ReturnSuccess::value(UntaggedValue::Error(
|
||||
crate::commands::config::err_no_global_cfg_present(),
|
||||
))]
|
||||
.into_iter()
|
||||
.to_output_stream())
|
||||
};
|
||||
|
||||
let mut result = nu_data::config::read(name_span, &path)?;
|
||||
|
||||
result.clear();
|
||||
|
||||
config::write(&result, &path)?;
|
||||
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::Row(result.into()).into_value(args.call_info.name_tag),
|
||||
)))
|
||||
result
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ impl WholeStreamCommand for Command {
|
||||
.to_output_stream())
|
||||
} else {
|
||||
Ok(vec![ReturnSuccess::value(UntaggedValue::Error(
|
||||
ShellError::untagged_runtime_error("No global config found!"),
|
||||
crate::commands::config::err_no_global_cfg_present(),
|
||||
))]
|
||||
.into_iter()
|
||||
.to_output_stream())
|
||||
|
@ -1,9 +1,7 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
ColumnPath, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
};
|
||||
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
@ -44,33 +42,27 @@ impl WholeStreamCommand for SubCommand {
|
||||
|
||||
pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let scope = args.scope.clone();
|
||||
let ctx = EvaluationContext::from_args(&args);
|
||||
|
||||
let (Arguments { column_path }, _) = args.process()?;
|
||||
|
||||
let path = match scope.get_var("config-path") {
|
||||
Some(Value {
|
||||
value: UntaggedValue::Primitive(Primitive::FilePath(path)),
|
||||
..
|
||||
}) => Some(path),
|
||||
_ => nu_data::config::default_path().ok(),
|
||||
let result = if let Some(global_cfg) = &ctx.configs.lock().global_config {
|
||||
let result = UntaggedValue::row(global_cfg.vars.clone()).into_value(&name);
|
||||
let value = crate::commands::get::get_column_path(&column_path, &result)?;
|
||||
Ok(match value {
|
||||
Value {
|
||||
value: UntaggedValue::Table(list),
|
||||
..
|
||||
} => list.into_iter().to_output_stream(),
|
||||
x => OutputStream::one(ReturnSuccess::value(x)),
|
||||
})
|
||||
} else {
|
||||
Ok(vec![ReturnSuccess::value(UntaggedValue::Error(
|
||||
crate::commands::config::err_no_global_cfg_present(),
|
||||
))]
|
||||
.into_iter()
|
||||
.to_output_stream())
|
||||
};
|
||||
|
||||
let result = UntaggedValue::row(nu_data::config::read(&name, &path)?).into_value(&name);
|
||||
|
||||
let value = crate::commands::get::get_column_path(&column_path, &result)?;
|
||||
|
||||
Ok(match value {
|
||||
Value {
|
||||
value: UntaggedValue::Table(list),
|
||||
..
|
||||
} => {
|
||||
let list: Vec<_> = list
|
||||
.iter()
|
||||
.map(|x| ReturnSuccess::value(x.clone()))
|
||||
.collect();
|
||||
|
||||
list.into_iter().to_output_stream()
|
||||
}
|
||||
x => OutputStream::one(ReturnSuccess::value(x)),
|
||||
})
|
||||
result
|
||||
}
|
||||
|
@ -13,3 +13,9 @@ pub use path::SubCommand as ConfigPath;
|
||||
pub use remove::SubCommand as ConfigRemove;
|
||||
pub use set::SubCommand as ConfigSet;
|
||||
pub use set_into::SubCommand as ConfigSetInto;
|
||||
|
||||
use nu_errors::ShellError;
|
||||
|
||||
pub fn err_no_global_cfg_present() -> ShellError {
|
||||
ShellError::untagged_runtime_error("No global config found!")
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
@ -32,18 +32,15 @@ impl WholeStreamCommand for SubCommand {
|
||||
}
|
||||
|
||||
pub fn path(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
match args.scope.get_var("config-path") {
|
||||
Some(
|
||||
path
|
||||
@
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::FilePath(_)),
|
||||
..
|
||||
},
|
||||
) => path,
|
||||
_ => UntaggedValue::Primitive(Primitive::FilePath(nu_data::config::default_path()?))
|
||||
.into_value(args.call_info.name_tag),
|
||||
},
|
||||
)))
|
||||
if let Some(global_cfg) = &mut args.configs.lock().global_config {
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::Primitive(Primitive::FilePath(global_cfg.file_path.clone())),
|
||||
)))
|
||||
} else {
|
||||
Ok(vec![ReturnSuccess::value(UntaggedValue::Error(
|
||||
crate::commands::config::err_no_global_cfg_present(),
|
||||
))]
|
||||
.into_iter()
|
||||
.to_output_stream())
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
|
||||
use nu_source::Tagged;
|
||||
|
||||
pub struct SubCommand;
|
||||
@ -42,35 +42,35 @@ impl WholeStreamCommand for SubCommand {
|
||||
}
|
||||
|
||||
pub fn remove(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name_span = args.call_info.name_tag.clone();
|
||||
let scope = args.scope.clone();
|
||||
let ctx = EvaluationContext::from_args(&args);
|
||||
let (Arguments { remove }, _) = args.process()?;
|
||||
|
||||
let path = match scope.get_var("config-path") {
|
||||
Some(Value {
|
||||
value: UntaggedValue::Primitive(Primitive::FilePath(path)),
|
||||
..
|
||||
}) => Some(path),
|
||||
_ => nu_data::config::default_path().ok(),
|
||||
};
|
||||
|
||||
let mut result = nu_data::config::read(name_span, &path)?;
|
||||
|
||||
let key = remove.to_string();
|
||||
|
||||
if result.contains_key(&key) {
|
||||
result.swap_remove(&key);
|
||||
config::write(&result, &path)?;
|
||||
Ok(vec![ReturnSuccess::value(
|
||||
UntaggedValue::Row(result.into()).into_value(remove.tag()),
|
||||
)]
|
||||
let result = if let Some(global_cfg) = &mut ctx.configs.lock().global_config {
|
||||
if global_cfg.vars.contains_key(&key) {
|
||||
global_cfg.vars.swap_remove(&key);
|
||||
global_cfg.write()?;
|
||||
ctx.reload_config(global_cfg)?;
|
||||
Ok(vec![ReturnSuccess::value(
|
||||
UntaggedValue::row(global_cfg.vars.clone()).into_value(remove.tag()),
|
||||
)]
|
||||
.into_iter()
|
||||
.to_output_stream())
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"Key does not exist in config",
|
||||
"key",
|
||||
remove.tag(),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Ok(vec![ReturnSuccess::value(UntaggedValue::Error(
|
||||
crate::commands::config::err_no_global_cfg_present(),
|
||||
))]
|
||||
.into_iter()
|
||||
.to_output_stream())
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"Key does not exist in config",
|
||||
"key",
|
||||
remove.tag(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
result
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
ColumnPath, ConfigPath, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
};
|
||||
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
@ -61,7 +59,6 @@ impl WholeStreamCommand for SubCommand {
|
||||
pub fn set(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let ctx = EvaluationContext::from_args(&args);
|
||||
let scope = args.scope.clone();
|
||||
let (
|
||||
Arguments {
|
||||
column_path,
|
||||
@ -70,38 +67,38 @@ pub fn set(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
_,
|
||||
) = args.process()?;
|
||||
|
||||
let path = match scope.get_var("config-path") {
|
||||
Some(Value {
|
||||
value: UntaggedValue::Primitive(Primitive::FilePath(path)),
|
||||
..
|
||||
}) => Some(path),
|
||||
_ => nu_data::config::default_path().ok(),
|
||||
let result = if let Some(global_cfg) = &mut ctx.configs.lock().global_config {
|
||||
let configuration = UntaggedValue::row(global_cfg.vars.clone()).into_value(&name);
|
||||
|
||||
if let UntaggedValue::Table(rows) = &value.value {
|
||||
if rows.len() == 1 && rows[0].is_row() {
|
||||
value = rows[0].clone();
|
||||
}
|
||||
}
|
||||
|
||||
match configuration.forgiving_insert_data_at_column_path(&column_path, value) {
|
||||
Ok(Value {
|
||||
value: UntaggedValue::Row(changes),
|
||||
..
|
||||
}) => {
|
||||
global_cfg.vars = changes.entries;
|
||||
global_cfg.write()?;
|
||||
ctx.reload_config(global_cfg)?;
|
||||
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::row(global_cfg.vars.clone()).into_value(name),
|
||||
)))
|
||||
}
|
||||
Ok(_) => Ok(OutputStream::empty()),
|
||||
Err(reason) => Err(reason),
|
||||
}
|
||||
} else {
|
||||
Ok(vec![ReturnSuccess::value(UntaggedValue::Error(
|
||||
crate::commands::config::err_no_global_cfg_present(),
|
||||
))]
|
||||
.into_iter()
|
||||
.to_output_stream())
|
||||
};
|
||||
|
||||
let raw_entries = nu_data::config::read(&name, &path)?;
|
||||
let configuration = UntaggedValue::row(raw_entries).into_value(&name);
|
||||
|
||||
if let UntaggedValue::Table(rows) = &value.value {
|
||||
if rows.len() == 1 && rows[0].is_row() {
|
||||
value = rows[0].clone();
|
||||
}
|
||||
}
|
||||
|
||||
match configuration.forgiving_insert_data_at_column_path(&column_path, value) {
|
||||
Ok(Value {
|
||||
value: UntaggedValue::Row(changes),
|
||||
..
|
||||
}) => {
|
||||
config::write(&changes.entries, &path)?;
|
||||
ctx.reload_config(&ConfigPath::Global(
|
||||
path.expect("Global config path is always some"),
|
||||
))?;
|
||||
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::Row(changes).into_value(name),
|
||||
)))
|
||||
}
|
||||
Ok(_) => Ok(OutputStream::empty()),
|
||||
Err(reason) => Err(reason),
|
||||
}
|
||||
result
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
ConfigPath, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
};
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
|
||||
pub struct SubCommand;
|
||||
@ -46,55 +44,43 @@ impl WholeStreamCommand for SubCommand {
|
||||
pub fn set_into(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let ctx = EvaluationContext::from_args(&args);
|
||||
let scope = args.scope.clone();
|
||||
let (Arguments { set_into: v }, input) = args.process()?;
|
||||
|
||||
let path = match scope.get_var("config-path") {
|
||||
Some(Value {
|
||||
value: UntaggedValue::Primitive(Primitive::FilePath(path)),
|
||||
..
|
||||
}) => Some(path),
|
||||
_ => nu_data::config::default_path().ok(),
|
||||
};
|
||||
|
||||
let mut result = nu_data::config::read(&name, &path)?;
|
||||
|
||||
let rows: Vec<Value> = input.collect();
|
||||
let key = v.to_string();
|
||||
|
||||
Ok(if rows.is_empty() {
|
||||
return Err(ShellError::labeled_error(
|
||||
"No values given for set_into",
|
||||
"needs value(s) from pipeline",
|
||||
v.tag(),
|
||||
));
|
||||
} else if rows.len() == 1 {
|
||||
// A single value
|
||||
let value = &rows[0];
|
||||
let result = if let Some(global_cfg) = &mut ctx.configs.lock().global_config {
|
||||
if rows.is_empty() {
|
||||
return Err(ShellError::labeled_error(
|
||||
"No values given for set_into",
|
||||
"needs value(s) from pipeline",
|
||||
v.tag(),
|
||||
));
|
||||
} else if rows.len() == 1 {
|
||||
// A single value
|
||||
let value = &rows[0];
|
||||
|
||||
result.insert(key, value.clone());
|
||||
global_cfg.vars.insert(key, value.clone());
|
||||
} else {
|
||||
// Take in the pipeline as a table
|
||||
let value = UntaggedValue::Table(rows).into_value(name.clone());
|
||||
|
||||
config::write(&result, &path)?;
|
||||
ctx.reload_config(&ConfigPath::Global(
|
||||
path.expect("Global config path is always some"),
|
||||
))?;
|
||||
global_cfg.vars.insert(key, value);
|
||||
}
|
||||
|
||||
OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::Row(result.into()).into_value(name),
|
||||
))
|
||||
global_cfg.write()?;
|
||||
ctx.reload_config(global_cfg)?;
|
||||
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::row(global_cfg.vars.clone()).into_value(name),
|
||||
)))
|
||||
} else {
|
||||
// Take in the pipeline as a table
|
||||
let value = UntaggedValue::Table(rows).into_value(name.clone());
|
||||
Ok(vec![ReturnSuccess::value(UntaggedValue::Error(
|
||||
crate::commands::config::err_no_global_cfg_present(),
|
||||
))]
|
||||
.into_iter()
|
||||
.to_output_stream())
|
||||
};
|
||||
|
||||
result.insert(key, value);
|
||||
|
||||
config::write(&result, &path)?;
|
||||
ctx.reload_config(&ConfigPath::Global(
|
||||
path.expect("Global config path is always some"),
|
||||
))?;
|
||||
|
||||
OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::Row(result.into()).into_value(name),
|
||||
))
|
||||
})
|
||||
result
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
use crate::prelude::*;
|
||||
use nu_data::config::{Conf, NuConfig};
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
@ -32,11 +31,15 @@ impl WholeStreamCommand for History {
|
||||
}
|
||||
|
||||
fn history(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let config: Box<dyn Conf> = Box::new(NuConfig::new());
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let ctx = EvaluationContext::from_args(&args);
|
||||
let (Arguments { clear }, _) = args.process()?;
|
||||
|
||||
let path = nu_data::config::path::history_path(&config);
|
||||
let path = if let Some(global_cfg) = &ctx.configs.lock().global_config {
|
||||
nu_data::config::path::history_path_or_default(global_cfg)
|
||||
} else {
|
||||
nu_data::config::path::default_history_path()
|
||||
};
|
||||
|
||||
match clear {
|
||||
Some(_) => {
|
||||
|
138
crates/nu-command/tests/commands/config.rs
Normal file
138
crates/nu-command/tests/commands/config.rs
Normal file
@ -0,0 +1,138 @@
|
||||
use nu_test_support::fs::AbsolutePath;
|
||||
use nu_test_support::fs::Stub::FileWithContent;
|
||||
use nu_test_support::playground::{says, Playground};
|
||||
|
||||
use hamcrest2::assert_that;
|
||||
use hamcrest2::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn clearing_config_clears_config() {
|
||||
Playground::setup("environment_syncing_test_1", |dirs, nu| {
|
||||
let file = AbsolutePath::new(dirs.test().join("config.toml"));
|
||||
|
||||
nu.with_config(&file);
|
||||
nu.with_files(vec![FileWithContent(
|
||||
"config.toml",
|
||||
r#"
|
||||
skip_welcome_message = true
|
||||
"#,
|
||||
)]);
|
||||
|
||||
assert_that!(
|
||||
nu.pipeline("config clear; config get skip_welcome_message"),
|
||||
says().to_stdout("")
|
||||
);
|
||||
let config_contents = std::fs::read_to_string(file).expect("Could not read file");
|
||||
assert!(config_contents.is_empty());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_get_returns_value() {
|
||||
Playground::setup("environment_syncing_test_1", |dirs, nu| {
|
||||
let file = AbsolutePath::new(dirs.test().join("config.toml"));
|
||||
|
||||
nu.with_config(&file);
|
||||
nu.with_files(vec![FileWithContent(
|
||||
"config.toml",
|
||||
r#"
|
||||
skip_welcome_message = true
|
||||
"#,
|
||||
)]);
|
||||
|
||||
assert_that!(
|
||||
//Clears config
|
||||
nu.pipeline("config get skip_welcome_message"),
|
||||
says().to_stdout("true")
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_set_sets_value() {
|
||||
Playground::setup("environment_syncing_test_1", |dirs, nu| {
|
||||
let file = AbsolutePath::new(dirs.test().join("config.toml"));
|
||||
|
||||
nu.with_config(&file);
|
||||
nu.with_files(vec![FileWithContent(
|
||||
"config.toml",
|
||||
r#"
|
||||
skip_welcome_message = true
|
||||
"#,
|
||||
)]);
|
||||
|
||||
assert_that!(
|
||||
//Clears config
|
||||
nu.pipeline("config set key value; config get key"),
|
||||
says().to_stdout("value")
|
||||
);
|
||||
let config_contents = std::fs::read_to_string(file).expect("Could not read file");
|
||||
assert!(config_contents.contains("key = \"value\""));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_set_into_sets_value() {
|
||||
Playground::setup("environment_syncing_test_1", |dirs, nu| {
|
||||
let file = AbsolutePath::new(dirs.test().join("config.toml"));
|
||||
|
||||
nu.with_config(&file);
|
||||
nu.with_files(vec![FileWithContent(
|
||||
"config.toml",
|
||||
r#"
|
||||
skip_welcome_message = true
|
||||
"#,
|
||||
)]);
|
||||
|
||||
assert_that!(
|
||||
//Clears config
|
||||
nu.pipeline("echo value | config set_into key; config get key"),
|
||||
says().to_stdout("value")
|
||||
);
|
||||
let config_contents = std::fs::read_to_string(file).expect("Could not read file");
|
||||
assert!(config_contents.contains("key = \"value\""));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_rm_removes_value() {
|
||||
Playground::setup("environment_syncing_test_1", |dirs, nu| {
|
||||
let file = AbsolutePath::new(dirs.test().join("config.toml"));
|
||||
|
||||
nu.with_config(&file);
|
||||
nu.with_files(vec![FileWithContent(
|
||||
"config.toml",
|
||||
r#"
|
||||
key = "value"
|
||||
skip_welcome_message = true
|
||||
"#,
|
||||
)]);
|
||||
|
||||
assert_that!(
|
||||
nu.pipeline("config remove key; config get key"),
|
||||
says().to_stdout("")
|
||||
);
|
||||
let config_contents = std::fs::read_to_string(file).expect("Could not read file");
|
||||
assert!(!config_contents.contains("key = \"value\""));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_path_returns_correct_path() {
|
||||
Playground::setup("environment_syncing_test_1", |dirs, nu| {
|
||||
let file = AbsolutePath::new(dirs.test().join("config.toml"));
|
||||
|
||||
nu.with_config(&file);
|
||||
nu.with_files(vec![FileWithContent(
|
||||
"config.toml",
|
||||
r#"
|
||||
skip_welcome_message = true
|
||||
"#,
|
||||
)]);
|
||||
|
||||
assert_that!(
|
||||
nu.pipeline("config path"),
|
||||
says().to_stdout(&file.inner.to_string_lossy().to_string())
|
||||
);
|
||||
});
|
||||
}
|
@ -4,6 +4,7 @@ mod append;
|
||||
mod cal;
|
||||
mod cd;
|
||||
mod compact;
|
||||
mod config;
|
||||
mod cp;
|
||||
mod def;
|
||||
mod default;
|
||||
|
@ -16,8 +16,8 @@ use indexmap::IndexMap;
|
||||
use log::trace;
|
||||
use nu_errors::{CoerceInto, ShellError};
|
||||
use nu_protocol::{
|
||||
ConfigPath, Dictionary, Primitive, ShellTypeName, TaggedDictBuilder, UnspannedPathMember,
|
||||
UntaggedValue, Value,
|
||||
Dictionary, Primitive, ShellTypeName, TaggedDictBuilder, UnspannedPathMember, UntaggedValue,
|
||||
Value,
|
||||
};
|
||||
use nu_source::{SpannedItem, Tag, TaggedItem};
|
||||
use std::fs::{self, OpenOptions};
|
||||
@ -328,6 +328,6 @@ fn touch(path: &Path) -> io::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cfg_path_to_scope_tag(cfg_path: &ConfigPath) -> String {
|
||||
cfg_path.get_path().to_string_lossy().to_string()
|
||||
pub fn cfg_path_to_scope_tag(cfg_path: &Path) -> String {
|
||||
cfg_path.to_string_lossy().to_string()
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ use nu_protocol::Value;
|
||||
use nu_source::Tag;
|
||||
use std::{fmt::Debug, path::PathBuf};
|
||||
|
||||
use super::write;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct NuConfig {
|
||||
pub vars: IndexMap<String, Value>,
|
||||
@ -63,6 +65,11 @@ impl NuConfig {
|
||||
})
|
||||
}
|
||||
|
||||
/// Writes self.values under self.file_path
|
||||
pub fn write(&self) -> Result<(), ShellError> {
|
||||
write(&self.vars, &Some(self.file_path.clone()))
|
||||
}
|
||||
|
||||
pub fn new() -> NuConfig {
|
||||
let vars = if let Ok(variables) = read(Tag::unknown(), &None) {
|
||||
variables
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::config::Conf;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::NuConfig;
|
||||
|
||||
const DEFAULT_LOCATION: &str = "history.txt";
|
||||
|
||||
pub fn default_history_path() -> PathBuf {
|
||||
@ -12,14 +13,18 @@ pub fn default_history_path() -> PathBuf {
|
||||
.unwrap_or_else(|_| PathBuf::from(DEFAULT_LOCATION))
|
||||
}
|
||||
|
||||
pub fn history_path(config: &dyn Conf) -> PathBuf {
|
||||
let default_history_path = default_history_path();
|
||||
|
||||
config.var("history-path").map_or(
|
||||
default_history_path.clone(),
|
||||
|custom_path| match custom_path.as_string() {
|
||||
Ok(path) => PathBuf::from(path),
|
||||
Err(_) => default_history_path,
|
||||
},
|
||||
)
|
||||
/// Get history path of config, if present
|
||||
pub fn history_path(config: &NuConfig) -> Option<PathBuf> {
|
||||
config
|
||||
.var("history-path")
|
||||
.map(|custom_path| match custom_path.as_string() {
|
||||
Ok(path) => Some(PathBuf::from(path)),
|
||||
Err(_) => None,
|
||||
})
|
||||
.flatten()
|
||||
}
|
||||
|
||||
/// Get history path in config or default
|
||||
pub fn history_path_or_default(config: &NuConfig) -> PathBuf {
|
||||
history_path(config).unwrap_or_else(default_history_path)
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ fn evaluate_literal(literal: &hir::Literal, span: Span) -> Value {
|
||||
|
||||
fn evaluate_reference(name: &str, ctx: &EvaluationContext, tag: Tag) -> Result<Value, ShellError> {
|
||||
match name {
|
||||
"$nu" => crate::evaluate::variables::nu(&ctx.scope, tag),
|
||||
"$nu" => crate::evaluate::variables::nu(&ctx.scope, tag, ctx),
|
||||
|
||||
"$scope" => crate::evaluate::variables::scope(&ctx.scope.get_aliases(), tag),
|
||||
|
||||
|
@ -1,11 +1,15 @@
|
||||
use crate::evaluate::scope::Scope;
|
||||
use crate::{evaluate::scope::Scope, EvaluationContext};
|
||||
use indexmap::IndexMap;
|
||||
use nu_data::config::path::history_path;
|
||||
use nu_data::config::path::{default_history_path, history_path};
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, TaggedDictBuilder, UntaggedValue, Value};
|
||||
use nu_protocol::{TaggedDictBuilder, UntaggedValue, Value};
|
||||
use nu_source::{Spanned, Tag};
|
||||
|
||||
pub fn nu(scope: &Scope, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||
pub fn nu(
|
||||
scope: &Scope,
|
||||
tag: impl Into<Tag>,
|
||||
ctx: &EvaluationContext,
|
||||
) -> Result<Value, ShellError> {
|
||||
let env = &scope.get_env_vars();
|
||||
let tag = tag.into();
|
||||
|
||||
@ -17,18 +21,33 @@ pub fn nu(scope: &Scope, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||
dict.insert_untagged(v.0, UntaggedValue::string(v.1));
|
||||
}
|
||||
}
|
||||
|
||||
nu_dict.insert_value("env", dict.into_value());
|
||||
|
||||
let config_file = match scope.get_var("config-path") {
|
||||
Some(Value {
|
||||
value: UntaggedValue::Primitive(Primitive::FilePath(path)),
|
||||
..
|
||||
}) => Some(path),
|
||||
_ => None,
|
||||
};
|
||||
nu_dict.insert_value(
|
||||
"history-path",
|
||||
UntaggedValue::filepath(default_history_path()).into_value(&tag),
|
||||
);
|
||||
|
||||
let config = nu_data::config::read(&tag, &config_file)?;
|
||||
nu_dict.insert_value("config", UntaggedValue::row(config).into_value(&tag));
|
||||
if let Some(global_cfg) = &ctx.configs.lock().global_config {
|
||||
nu_dict.insert_value(
|
||||
"config",
|
||||
UntaggedValue::row(global_cfg.vars.clone()).into_value(&tag),
|
||||
);
|
||||
|
||||
nu_dict.insert_value(
|
||||
"config-path",
|
||||
UntaggedValue::filepath(global_cfg.file_path.clone()).into_value(&tag),
|
||||
);
|
||||
|
||||
// overwrite hist-path if present
|
||||
if let Some(hist_path) = history_path(global_cfg) {
|
||||
nu_dict.insert_value(
|
||||
"history-path",
|
||||
UntaggedValue::filepath(hist_path).into_value(&tag),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let mut table = vec![];
|
||||
for v in env.iter() {
|
||||
@ -50,17 +69,6 @@ pub fn nu(scope: &Scope, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||
let temp = std::env::temp_dir();
|
||||
nu_dict.insert_value("temp-dir", UntaggedValue::filepath(temp).into_value(&tag));
|
||||
|
||||
let config = if let Some(path) = config_file {
|
||||
path
|
||||
} else {
|
||||
nu_data::config::default_path()?
|
||||
};
|
||||
|
||||
nu_dict.insert_value(
|
||||
"config-path",
|
||||
UntaggedValue::filepath(config).into_value(&tag),
|
||||
);
|
||||
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
{
|
||||
let keybinding_path = nu_data::keybinding::keybinding_path()?;
|
||||
@ -70,13 +78,6 @@ pub fn nu(scope: &Scope, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||
);
|
||||
}
|
||||
|
||||
let config: Box<dyn nu_data::config::Conf> = Box::new(nu_data::config::NuConfig::new());
|
||||
let history = history_path(&config);
|
||||
nu_dict.insert_value(
|
||||
"history-path",
|
||||
UntaggedValue::filepath(history).into_value(&tag),
|
||||
);
|
||||
|
||||
Ok(nu_dict.into_value())
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,7 @@ impl EvaluationContext {
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
let tag = config::cfg_path_to_scope_tag(cfg_path);
|
||||
let tag = config::cfg_path_to_scope_tag(cfg_path.get_path());
|
||||
|
||||
self.scope.enter_scope_with_tag(tag);
|
||||
self.scope.add_env(cfg.env_map());
|
||||
@ -188,30 +188,8 @@ impl EvaluationContext {
|
||||
/// If an error occurs while reloading the config:
|
||||
/// The config is not reloaded
|
||||
/// The error is returned
|
||||
pub fn reload_config(&self, cfg_path: &ConfigPath) -> Result<(), ShellError> {
|
||||
trace!("Reloading cfg {:?}", cfg_path);
|
||||
|
||||
let mut configs = self.configs.lock();
|
||||
let cfg = match cfg_path {
|
||||
ConfigPath::Global(path) => {
|
||||
configs.global_config.iter_mut().find(|cfg| &cfg.file_path == path).ok_or_else(||
|
||||
ShellError::labeled_error(
|
||||
&format!("Error reloading global config with path of {}. No such global config present.", path.display()),
|
||||
"Config path error",
|
||||
Span::unknown(),
|
||||
)
|
||||
)?
|
||||
}
|
||||
ConfigPath::Local(path) => {
|
||||
configs.local_configs.iter_mut().find(|cfg| &cfg.file_path == path).ok_or_else(||
|
||||
ShellError::labeled_error(
|
||||
&format!("Error reloading local config with path of {}. No such local config present.", path.display()),
|
||||
"Config path error",
|
||||
Span::unknown(),
|
||||
)
|
||||
)?
|
||||
}
|
||||
};
|
||||
pub fn reload_config(&self, cfg: &mut NuConfig) -> Result<(), ShellError> {
|
||||
trace!("Reloading cfg {:?}", cfg.file_path);
|
||||
|
||||
cfg.reload();
|
||||
|
||||
@ -244,7 +222,7 @@ impl EvaluationContext {
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
let tag = config::cfg_path_to_scope_tag(cfg_path);
|
||||
let tag = config::cfg_path_to_scope_tag(&cfg.file_path);
|
||||
let mut frame = ScopeFrame::with_tag(tag.clone());
|
||||
|
||||
frame.env = cfg.env_map();
|
||||
@ -265,7 +243,7 @@ impl EvaluationContext {
|
||||
pub fn unload_config(&self, cfg_path: &ConfigPath) {
|
||||
trace!("UnLoading cfg {:?}", cfg_path);
|
||||
|
||||
let tag = config::cfg_path_to_scope_tag(cfg_path);
|
||||
let tag = config::cfg_path_to_scope_tag(cfg_path.get_path());
|
||||
|
||||
//Run exitscripts with scope frame and cfg still applied
|
||||
if let Some(scripts) = self.scope.get_exitscripts_of_frame_with_tag(&tag) {
|
||||
|
@ -45,7 +45,7 @@ impl From<AbsoluteFile> for PathBuf {
|
||||
}
|
||||
|
||||
pub struct AbsolutePath {
|
||||
inner: PathBuf,
|
||||
pub inner: PathBuf,
|
||||
}
|
||||
|
||||
impl AbsolutePath {
|
||||
|
Loading…
Reference in New Issue
Block a user