nushell/crates/nu-cli/src/commands/config.rs

189 lines
5.6 KiB
Rust
Raw Normal View History

2019-08-15 07:02:02 +02:00
use crate::commands::WholeStreamCommand;
use crate::context::CommandRegistry;
use crate::data::config;
2019-09-10 12:08:01 +02:00
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;
2019-09-10 12:08:01 +02:00
use std::path::PathBuf;
pub struct Config;
2019-08-02 21:15:07 +02:00
#[derive(Deserialize)]
pub struct ConfigArgs {
2019-09-10 12:08:01 +02:00
load: Option<Tagged<PathBuf>>,
set: Option<(Tagged<String>, Value)>,
2019-11-03 00:43:15 +01:00
set_into: Option<Tagged<String>>,
2019-08-09 06:51:21 +02:00
get: Option<Tagged<String>>,
clear: Tagged<bool>,
remove: Option<Tagged<String>>,
path: Tagged<bool>,
2019-08-02 21:15:07 +02:00
}
2019-07-24 00:22:11 +02:00
2019-08-15 07:02:02 +02:00
impl WholeStreamCommand for Config {
fn name(&self) -> &str {
"config"
}
2019-08-02 21:15:07 +02:00
fn signature(&self) -> Signature {
Signature::build("config")
2019-10-28 06:15:35 +01:00
.named(
"load",
SyntaxShape::Path,
"load the config from the path give",
Some('l'),
2019-10-28 06:15:35 +01:00
)
2019-11-03 00:43:15 +01:00
.named(
"set",
SyntaxShape::Any,
"set a value in the config, eg) --set [key value]",
Some('s'),
2019-11-03 00:43:15 +01:00
)
.named(
"set_into",
SyntaxShape::String,
2019-11-03 00:43:15 +01:00
"sets a variable from values in the pipeline",
Some('i'),
2019-11-03 00:43:15 +01:00
)
.named(
"get",
SyntaxShape::Any,
"get a value from the config",
Some('g'),
)
.named(
"remove",
SyntaxShape::Any,
"remove a value from the config",
Some('r'),
)
.switch("clear", "clear the config", Some('c'))
.switch("path", "return the path to the config file", Some('p'))
}
fn usage(&self) -> &str {
"Configuration management."
}
2019-08-02 21:15:07 +02:00
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
2019-08-02 21:15:07 +02:00
) -> Result<OutputStream, ShellError> {
args.process(registry, config)?.run()
}
}
2019-08-02 21:15:07 +02:00
pub fn config(
ConfigArgs {
2019-09-10 12:08:01 +02:00
load,
2019-08-02 21:15:07 +02:00
set,
2019-11-03 00:43:15 +01:00
set_into,
2019-08-02 21:15:07 +02:00
get,
clear,
remove,
path,
}: ConfigArgs,
2019-11-03 00:43:15 +01:00
RunnableContext { name, input, .. }: RunnableContext,
2019-08-02 21:15:07 +02:00
) -> Result<OutputStream, ShellError> {
let name_span = name.clone();
2019-09-10 12:08:01 +02:00
2019-11-03 00:22:30 +01:00
let stream = async_stream! {
let configuration = if let Some(supplied) = load {
Some(supplied.item().clone())
} else {
None
};
let mut result = crate::data::config::read(name_span, &configuration)?;
if let Some(v) = get {
let key = v.to_string();
let value = result
.get(&key)
.ok_or_else(|| ShellError::labeled_error("Missing key in config", "key", v.tag()))?;
match value {
Value {
value: UntaggedValue::Table(list),
2019-11-03 00:22:30 +01:00
..
} => {
for l in list {
let value = l.clone();
2019-11-03 00:22:30 +01:00
yield ReturnSuccess::value(l.clone());
}
2019-09-10 12:08:01 +02:00
}
2019-11-03 00:22:30 +01:00
x => yield ReturnSuccess::value(x.clone()),
2019-09-10 12:08:01 +02:00
}
}
2019-11-03 00:22:30 +01:00
else if let Some((key, value)) = set {
result.insert(key.to_string(), value.clone());
2019-09-10 12:08:01 +02:00
2019-11-03 00:22:30 +01:00
config::write(&result, &configuration)?;
yield ReturnSuccess::value(UntaggedValue::Row(result.into()).into_value(&value.tag));
2019-11-03 00:22:30 +01:00
}
2019-11-03 00:43:15 +01:00
else if let Some(v) = set_into {
let rows: Vec<Value> = input.collect().await;
2019-11-03 00:43:15 +01:00
let key = v.to_string();
if rows.len() == 0 {
yield 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.to_string(), value.clone());
config::write(&result, &configuration)?;
yield ReturnSuccess::value(UntaggedValue::Row(result.into()).into_value(name));
2019-11-03 00:43:15 +01:00
} else {
// Take in the pipeline as a table
let value = UntaggedValue::Table(rows).into_value(name.clone());
2019-11-03 00:43:15 +01:00
result.insert(key.to_string(), value.clone());
config::write(&result, &configuration)?;
yield ReturnSuccess::value(UntaggedValue::Row(result.into()).into_value(name));
2019-11-03 00:43:15 +01:00
}
}
2019-11-03 00:22:30 +01:00
else if let Tagged { item: true, tag } = clear {
result.clear();
2019-11-03 00:22:30 +01:00
config::write(&result, &configuration)?;
2019-08-02 21:15:07 +02:00
yield ReturnSuccess::value(UntaggedValue::Row(result.into()).into_value(tag));
2019-08-02 21:15:07 +02:00
2019-11-03 00:22:30 +01:00
return;
}
else if let Tagged { item: true, tag } = path {
let path = config::default_path_for(&configuration)?;
yield ReturnSuccess::value(UntaggedValue::Primitive(Primitive::Path(path)).into_value(tag));
}
2019-11-03 00:22:30 +01:00
else if let Some(v) = remove {
let key = v.to_string();
if result.contains_key(&key) {
result.swap_remove(&key);
2020-01-02 06:24:41 +01:00
config::write(&result, &configuration)?
2019-11-03 00:22:30 +01:00
} else {
yield Err(ShellError::labeled_error(
"Key does not exist in config",
"key",
v.tag(),
));
}
yield ReturnSuccess::value(UntaggedValue::Row(result.into()).into_value(v.tag()));
2019-11-03 00:22:30 +01:00
}
else {
yield ReturnSuccess::value(UntaggedValue::Row(result.into()).into_value(name));
2019-11-03 00:22:30 +01:00
}
};
2019-11-03 00:22:30 +01:00
Ok(stream.to_output_stream())
}