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:
Leonhard Kipp 2021-04-09 08:03:12 +02:00 committed by GitHub
parent 111ad868a7
commit ac070ae942
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 357 additions and 254 deletions

View File

@ -173,7 +173,7 @@ pub fn cli(context: EvaluationContext, options: Options) -> Result<(), Box<dyn E
let _ = configure_rustyline_editor(&mut rl, cfg); let _ = configure_rustyline_editor(&mut rl, cfg);
let helper = Some(nu_line_editor_helper(&context, cfg)); let helper = Some(nu_line_editor_helper(&context, cfg));
rl.set_helper(helper); rl.set_helper(helper);
nu_data::config::path::history_path(cfg) nu_data::config::path::history_path_or_default(cfg)
} else { } else {
nu_data::config::path::default_history_path() 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) { 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("")); 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(),
);
} }
} }

View File

@ -1,7 +1,7 @@
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::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value}; use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
pub struct SubCommand; pub struct SubCommand;
@ -32,23 +32,22 @@ impl WholeStreamCommand for SubCommand {
} }
pub fn clear(args: CommandArgs) -> Result<OutputStream, ShellError> { 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") { let result = if let Some(global_cfg) = &mut args.configs.lock().global_config {
Some(Value { global_cfg.vars.clear();
value: UntaggedValue::Primitive(Primitive::FilePath(path)), global_cfg.write()?;
.. ctx.reload_config(global_cfg)?;
}) => Some(path), Ok(OutputStream::one(ReturnSuccess::value(
_ => nu_data::config::default_path().ok(), 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
result.clear();
config::write(&result, &path)?;
Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::Row(result.into()).into_value(args.call_info.name_tag),
)))
} }

View File

@ -32,7 +32,7 @@ impl WholeStreamCommand for Command {
.to_output_stream()) .to_output_stream())
} else { } else {
Ok(vec![ReturnSuccess::value(UntaggedValue::Error( Ok(vec![ReturnSuccess::value(UntaggedValue::Error(
ShellError::untagged_runtime_error("No global config found!"), crate::commands::config::err_no_global_cfg_present(),
))] ))]
.into_iter() .into_iter()
.to_output_stream()) .to_output_stream())

View File

@ -1,9 +1,7 @@
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::{ use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
ColumnPath, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
};
pub struct SubCommand; pub struct SubCommand;
@ -44,33 +42,27 @@ impl WholeStreamCommand for SubCommand {
pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
let name = args.call_info.name_tag.clone(); 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 (Arguments { column_path }, _) = args.process()?;
let path = match scope.get_var("config-path") { let result = if let Some(global_cfg) = &ctx.configs.lock().global_config {
Some(Value { let result = UntaggedValue::row(global_cfg.vars.clone()).into_value(&name);
value: UntaggedValue::Primitive(Primitive::FilePath(path)), let value = crate::commands::get::get_column_path(&column_path, &result)?;
.. Ok(match value {
}) => Some(path), Value {
_ => nu_data::config::default_path().ok(), 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); result
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)),
})
} }

View File

@ -13,3 +13,9 @@ pub use path::SubCommand as ConfigPath;
pub use remove::SubCommand as ConfigRemove; pub use remove::SubCommand as ConfigRemove;
pub use set::SubCommand as ConfigSet; pub use set::SubCommand as ConfigSet;
pub use set_into::SubCommand as ConfigSetInto; 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!")
}

View File

@ -1,7 +1,7 @@
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::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value}; use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue};
pub struct SubCommand; pub struct SubCommand;
@ -32,18 +32,15 @@ impl WholeStreamCommand for SubCommand {
} }
pub fn path(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn path(args: CommandArgs) -> Result<OutputStream, ShellError> {
Ok(OutputStream::one(ReturnSuccess::value( if let Some(global_cfg) = &mut args.configs.lock().global_config {
match args.scope.get_var("config-path") { Ok(OutputStream::one(ReturnSuccess::value(
Some( UntaggedValue::Primitive(Primitive::FilePath(global_cfg.file_path.clone())),
path )))
@ } else {
Value { Ok(vec![ReturnSuccess::value(UntaggedValue::Error(
value: UntaggedValue::Primitive(Primitive::FilePath(_)), crate::commands::config::err_no_global_cfg_present(),
.. ))]
}, .into_iter()
) => path, .to_output_stream())
_ => UntaggedValue::Primitive(Primitive::FilePath(nu_data::config::default_path()?)) }
.into_value(args.call_info.name_tag),
},
)))
} }

View File

@ -1,7 +1,7 @@
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::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
use nu_source::Tagged; use nu_source::Tagged;
pub struct SubCommand; pub struct SubCommand;
@ -42,35 +42,35 @@ impl WholeStreamCommand for SubCommand {
} }
pub fn remove(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn remove(args: CommandArgs) -> Result<OutputStream, ShellError> {
let name_span = args.call_info.name_tag.clone(); let ctx = EvaluationContext::from_args(&args);
let scope = args.scope.clone();
let (Arguments { remove }, _) = args.process()?; 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(); let key = remove.to_string();
if result.contains_key(&key) { let result = if let Some(global_cfg) = &mut ctx.configs.lock().global_config {
result.swap_remove(&key); if global_cfg.vars.contains_key(&key) {
config::write(&result, &path)?; global_cfg.vars.swap_remove(&key);
Ok(vec![ReturnSuccess::value( global_cfg.write()?;
UntaggedValue::Row(result.into()).into_value(remove.tag()), 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() .into_iter()
.to_output_stream()) .to_output_stream())
} else { };
Err(ShellError::labeled_error(
"Key does not exist in config", result
"key",
remove.tag(),
))
}
} }

View File

@ -1,9 +1,7 @@
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::{ use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
ColumnPath, ConfigPath, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
};
pub struct SubCommand; pub struct SubCommand;
@ -61,7 +59,6 @@ impl WholeStreamCommand for SubCommand {
pub fn set(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn set(args: CommandArgs) -> Result<OutputStream, ShellError> {
let name = args.call_info.name_tag.clone(); let name = args.call_info.name_tag.clone();
let ctx = EvaluationContext::from_args(&args); let ctx = EvaluationContext::from_args(&args);
let scope = args.scope.clone();
let ( let (
Arguments { Arguments {
column_path, column_path,
@ -70,38 +67,38 @@ pub fn set(args: CommandArgs) -> Result<OutputStream, ShellError> {
_, _,
) = args.process()?; ) = args.process()?;
let path = match scope.get_var("config-path") { let result = if let Some(global_cfg) = &mut ctx.configs.lock().global_config {
Some(Value { let configuration = UntaggedValue::row(global_cfg.vars.clone()).into_value(&name);
value: UntaggedValue::Primitive(Primitive::FilePath(path)),
.. if let UntaggedValue::Table(rows) = &value.value {
}) => Some(path), if rows.len() == 1 && rows[0].is_row() {
_ => nu_data::config::default_path().ok(), 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)?; result
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),
}
} }

View File

@ -1,9 +1,7 @@
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::{ use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
ConfigPath, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
};
use nu_source::Tagged; use nu_source::Tagged;
pub struct SubCommand; pub struct SubCommand;
@ -46,55 +44,43 @@ impl WholeStreamCommand for SubCommand {
pub fn set_into(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn set_into(args: CommandArgs) -> Result<OutputStream, ShellError> {
let name = args.call_info.name_tag.clone(); let name = args.call_info.name_tag.clone();
let ctx = EvaluationContext::from_args(&args); let ctx = EvaluationContext::from_args(&args);
let scope = args.scope.clone();
let (Arguments { set_into: v }, input) = args.process()?; 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 rows: Vec<Value> = input.collect();
let key = v.to_string(); let key = v.to_string();
Ok(if rows.is_empty() { let result = if let Some(global_cfg) = &mut ctx.configs.lock().global_config {
return Err(ShellError::labeled_error( if rows.is_empty() {
"No values given for set_into", return Err(ShellError::labeled_error(
"needs value(s) from pipeline", "No values given for set_into",
v.tag(), "needs value(s) from pipeline",
)); v.tag(),
} else if rows.len() == 1 { ));
// A single value } else if rows.len() == 1 {
let value = &rows[0]; // 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)?; global_cfg.vars.insert(key, value);
ctx.reload_config(&ConfigPath::Global( }
path.expect("Global config path is always some"),
))?;
OutputStream::one(ReturnSuccess::value( global_cfg.write()?;
UntaggedValue::Row(result.into()).into_value(name), ctx.reload_config(global_cfg)?;
))
Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::row(global_cfg.vars.clone()).into_value(name),
)))
} else { } else {
// Take in the pipeline as a table Ok(vec![ReturnSuccess::value(UntaggedValue::Error(
let value = UntaggedValue::Table(rows).into_value(name.clone()); crate::commands::config::err_no_global_cfg_present(),
))]
.into_iter()
.to_output_stream())
};
result.insert(key, value); result
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),
))
})
} }

View File

@ -1,5 +1,4 @@
use crate::prelude::*; use crate::prelude::*;
use nu_data::config::{Conf, NuConfig};
use nu_engine::WholeStreamCommand; use nu_engine::WholeStreamCommand;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue}; use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
@ -32,11 +31,15 @@ impl WholeStreamCommand for History {
} }
fn history(args: CommandArgs) -> Result<OutputStream, ShellError> { 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 tag = args.call_info.name_tag.clone();
let ctx = EvaluationContext::from_args(&args);
let (Arguments { clear }, _) = args.process()?; 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 { match clear {
Some(_) => { Some(_) => {

View 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())
);
});
}

View File

@ -4,6 +4,7 @@ mod append;
mod cal; mod cal;
mod cd; mod cd;
mod compact; mod compact;
mod config;
mod cp; mod cp;
mod def; mod def;
mod default; mod default;

View File

@ -16,8 +16,8 @@ use indexmap::IndexMap;
use log::trace; use log::trace;
use nu_errors::{CoerceInto, ShellError}; use nu_errors::{CoerceInto, ShellError};
use nu_protocol::{ use nu_protocol::{
ConfigPath, Dictionary, Primitive, ShellTypeName, TaggedDictBuilder, UnspannedPathMember, Dictionary, Primitive, ShellTypeName, TaggedDictBuilder, UnspannedPathMember, UntaggedValue,
UntaggedValue, Value, Value,
}; };
use nu_source::{SpannedItem, Tag, TaggedItem}; use nu_source::{SpannedItem, Tag, TaggedItem};
use std::fs::{self, OpenOptions}; 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 { pub fn cfg_path_to_scope_tag(cfg_path: &Path) -> String {
cfg_path.get_path().to_string_lossy().to_string() cfg_path.to_string_lossy().to_string()
} }

View File

@ -5,6 +5,8 @@ use nu_protocol::Value;
use nu_source::Tag; use nu_source::Tag;
use std::{fmt::Debug, path::PathBuf}; use std::{fmt::Debug, path::PathBuf};
use super::write;
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct NuConfig { pub struct NuConfig {
pub vars: IndexMap<String, Value>, 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 { pub fn new() -> NuConfig {
let vars = if let Ok(variables) = read(Tag::unknown(), &None) { let vars = if let Ok(variables) = read(Tag::unknown(), &None) {
variables variables

View File

@ -1,6 +1,7 @@
use crate::config::Conf;
use std::path::PathBuf; use std::path::PathBuf;
use super::NuConfig;
const DEFAULT_LOCATION: &str = "history.txt"; const DEFAULT_LOCATION: &str = "history.txt";
pub fn default_history_path() -> PathBuf { pub fn default_history_path() -> PathBuf {
@ -12,14 +13,18 @@ pub fn default_history_path() -> PathBuf {
.unwrap_or_else(|_| PathBuf::from(DEFAULT_LOCATION)) .unwrap_or_else(|_| PathBuf::from(DEFAULT_LOCATION))
} }
pub fn history_path(config: &dyn Conf) -> PathBuf { /// Get history path of config, if present
let default_history_path = default_history_path(); pub fn history_path(config: &NuConfig) -> Option<PathBuf> {
config
config.var("history-path").map_or( .var("history-path")
default_history_path.clone(), .map(|custom_path| match custom_path.as_string() {
|custom_path| match custom_path.as_string() { Ok(path) => Some(PathBuf::from(path)),
Ok(path) => PathBuf::from(path), Err(_) => None,
Err(_) => default_history_path, })
}, .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)
} }

View File

@ -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> { fn evaluate_reference(name: &str, ctx: &EvaluationContext, tag: Tag) -> Result<Value, ShellError> {
match name { 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), "$scope" => crate::evaluate::variables::scope(&ctx.scope.get_aliases(), tag),

View File

@ -1,11 +1,15 @@
use crate::evaluate::scope::Scope; use crate::{evaluate::scope::Scope, EvaluationContext};
use indexmap::IndexMap; 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_errors::ShellError;
use nu_protocol::{Primitive, TaggedDictBuilder, UntaggedValue, Value}; use nu_protocol::{TaggedDictBuilder, UntaggedValue, Value};
use nu_source::{Spanned, Tag}; 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 env = &scope.get_env_vars();
let tag = tag.into(); 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)); dict.insert_untagged(v.0, UntaggedValue::string(v.1));
} }
} }
nu_dict.insert_value("env", dict.into_value()); nu_dict.insert_value("env", dict.into_value());
let config_file = match scope.get_var("config-path") { nu_dict.insert_value(
Some(Value { "history-path",
value: UntaggedValue::Primitive(Primitive::FilePath(path)), UntaggedValue::filepath(default_history_path()).into_value(&tag),
.. );
}) => Some(path),
_ => None,
};
let config = nu_data::config::read(&tag, &config_file)?; if let Some(global_cfg) = &ctx.configs.lock().global_config {
nu_dict.insert_value("config", UntaggedValue::row(config).into_value(&tag)); 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![]; let mut table = vec![];
for v in env.iter() { 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(); let temp = std::env::temp_dir();
nu_dict.insert_value("temp-dir", UntaggedValue::filepath(temp).into_value(&tag)); 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")] #[cfg(feature = "rustyline-support")]
{ {
let keybinding_path = nu_data::keybinding::keybinding_path()?; 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()) Ok(nu_dict.into_value())
} }

View File

@ -161,7 +161,7 @@ impl EvaluationContext {
}) })
.transpose()?; .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.enter_scope_with_tag(tag);
self.scope.add_env(cfg.env_map()); self.scope.add_env(cfg.env_map());
@ -188,30 +188,8 @@ impl EvaluationContext {
/// If an error occurs while reloading the config: /// If an error occurs while reloading the config:
/// The config is not reloaded /// The config is not reloaded
/// The error is returned /// The error is returned
pub fn reload_config(&self, cfg_path: &ConfigPath) -> Result<(), ShellError> { pub fn reload_config(&self, cfg: &mut NuConfig) -> Result<(), ShellError> {
trace!("Reloading cfg {:?}", cfg_path); trace!("Reloading cfg {:?}", cfg.file_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(),
)
)?
}
};
cfg.reload(); cfg.reload();
@ -244,7 +222,7 @@ impl EvaluationContext {
}) })
.transpose()?; .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()); let mut frame = ScopeFrame::with_tag(tag.clone());
frame.env = cfg.env_map(); frame.env = cfg.env_map();
@ -265,7 +243,7 @@ impl EvaluationContext {
pub fn unload_config(&self, cfg_path: &ConfigPath) { pub fn unload_config(&self, cfg_path: &ConfigPath) {
trace!("UnLoading cfg {:?}", cfg_path); 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 //Run exitscripts with scope frame and cfg still applied
if let Some(scripts) = self.scope.get_exitscripts_of_frame_with_tag(&tag) { if let Some(scripts) = self.scope.get_exitscripts_of_frame_with_tag(&tag) {

View File

@ -45,7 +45,7 @@ impl From<AbsoluteFile> for PathBuf {
} }
pub struct AbsolutePath { pub struct AbsolutePath {
inner: PathBuf, pub inner: PathBuf,
} }
impl AbsolutePath { impl AbsolutePath {