mirror of
https://github.com/nushell/nushell
synced 2024-12-26 13:03:07 +00:00
Add support for load-env (#752)
This commit is contained in:
parent
75db4a75bc
commit
b78924c777
8 changed files with 136 additions and 5 deletions
|
@ -234,6 +234,7 @@ pub fn create_default_context(cwd: impl AsRef<Path>) -> EngineState {
|
|||
|
||||
// Conversions
|
||||
bind_command! {
|
||||
Fmt,
|
||||
Into,
|
||||
IntoBool,
|
||||
IntoBinary,
|
||||
|
@ -242,14 +243,14 @@ pub fn create_default_context(cwd: impl AsRef<Path>) -> EngineState {
|
|||
IntoFilesize,
|
||||
IntoInt,
|
||||
IntoString,
|
||||
Fmt,
|
||||
};
|
||||
|
||||
// Env
|
||||
bind_command! {
|
||||
LetEnv,
|
||||
WithEnv,
|
||||
Env,
|
||||
LetEnv,
|
||||
LoadEnv,
|
||||
WithEnv,
|
||||
};
|
||||
|
||||
// Math
|
||||
|
|
109
crates/nu-command/src/env/load_env.rs
vendored
Normal file
109
crates/nu-command/src/env/load_env.rs
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
use nu_engine::{current_dir, CallExt};
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Value};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct LoadEnv;
|
||||
|
||||
impl Command for LoadEnv {
|
||||
fn name(&self) -> &str {
|
||||
"load-env"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Loads an environment update from a record."
|
||||
}
|
||||
|
||||
fn signature(&self) -> nu_protocol::Signature {
|
||||
Signature::build("load-env")
|
||||
.optional(
|
||||
"update",
|
||||
SyntaxShape::Record,
|
||||
"the record to use for updates",
|
||||
)
|
||||
.category(Category::FileSystem)
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
let arg: Option<(Vec<String>, Vec<Value>)> = call.opt(engine_state, stack, 0)?;
|
||||
let span = call.head;
|
||||
|
||||
match arg {
|
||||
Some((cols, vals)) => {
|
||||
for (env_var, rhs) in cols.into_iter().zip(vals) {
|
||||
if env_var == "PWD" {
|
||||
let cwd = current_dir(engine_state, stack)?;
|
||||
let rhs = rhs.as_string()?;
|
||||
let rhs = nu_path::expand_path_with(rhs, cwd);
|
||||
stack.add_env_var(
|
||||
env_var,
|
||||
Value::String {
|
||||
val: rhs.to_string_lossy().to_string(),
|
||||
span: call.head,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
stack.add_env_var(env_var, rhs);
|
||||
}
|
||||
}
|
||||
Ok(PipelineData::new(call.head))
|
||||
}
|
||||
None => match input {
|
||||
PipelineData::Value(Value::Record { cols, vals, .. }, ..) => {
|
||||
for (env_var, rhs) in cols.into_iter().zip(vals) {
|
||||
if env_var == "PWD" {
|
||||
let cwd = current_dir(engine_state, stack)?;
|
||||
let rhs = rhs.as_string()?;
|
||||
let rhs = nu_path::expand_path_with(rhs, cwd);
|
||||
stack.add_env_var(
|
||||
env_var,
|
||||
Value::String {
|
||||
val: rhs.to_string_lossy().to_string(),
|
||||
span: call.head,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
stack.add_env_var(env_var, rhs);
|
||||
}
|
||||
}
|
||||
Ok(PipelineData::new(call.head))
|
||||
}
|
||||
_ => Err(ShellError::UnsupportedInput("Record".into(), span)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Load variables from an input stream",
|
||||
example: r#"{NAME: ABE, AGE: UNKNOWN} | load-env; echo $env.NAME"#,
|
||||
result: Some(Value::test_string("ABE")),
|
||||
},
|
||||
Example {
|
||||
description: "Load variables from an argument",
|
||||
example: r#"load-env {NAME: ABE, AGE: UNKNOWN}; echo $env.NAME"#,
|
||||
result: Some(Value::test_string("ABE")),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::LoadEnv;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::test_examples;
|
||||
|
||||
test_examples(LoadEnv {})
|
||||
}
|
||||
}
|
2
crates/nu-command/src/env/mod.rs
vendored
2
crates/nu-command/src/env/mod.rs
vendored
|
@ -1,7 +1,9 @@
|
|||
mod env_command;
|
||||
mod let_env;
|
||||
mod load_env;
|
||||
mod with_env;
|
||||
|
||||
pub use env_command::Env;
|
||||
pub use let_env::LetEnv;
|
||||
pub use load_env::LoadEnv;
|
||||
pub use with_env::WithEnv;
|
||||
|
|
|
@ -13,7 +13,6 @@ use std::path::Path;
|
|||
#[derive(Clone)]
|
||||
pub struct Open;
|
||||
|
||||
//NOTE: this is not a real implementation :D. It's just a simple one to test with until we port the real one.
|
||||
impl Command for Open {
|
||||
fn name(&self) -> &str {
|
||||
"open"
|
||||
|
|
|
@ -9,7 +9,6 @@ use std::path::Path;
|
|||
#[derive(Clone)]
|
||||
pub struct Save;
|
||||
|
||||
//NOTE: this is not a real implementation :D. It's just a simple one to test with until we port the real one.
|
||||
impl Command for Save {
|
||||
fn name(&self) -> &str {
|
||||
"save"
|
||||
|
|
|
@ -2970,6 +2970,8 @@ pub fn parse_value(
|
|||
}
|
||||
if matches!(shape, SyntaxShape::Block(_)) || matches!(shape, SyntaxShape::Any) {
|
||||
return parse_block_expression(working_set, shape, span);
|
||||
} else if matches!(shape, SyntaxShape::Record) {
|
||||
return parse_record(working_set, span);
|
||||
} else {
|
||||
return (
|
||||
Expression::garbage(span),
|
||||
|
|
|
@ -80,6 +80,9 @@ pub enum SyntaxShape {
|
|||
/// A boolean value
|
||||
Boolean,
|
||||
|
||||
/// A record value
|
||||
Record,
|
||||
|
||||
/// A custom shape with custom completion logic
|
||||
Custom(Box<SyntaxShape>, String),
|
||||
}
|
||||
|
@ -108,6 +111,7 @@ impl SyntaxShape {
|
|||
SyntaxShape::Number => Type::Number,
|
||||
SyntaxShape::Operator => Type::Unknown,
|
||||
SyntaxShape::Range => Type::Unknown,
|
||||
SyntaxShape::Record => Type::Record(vec![]), // FIXME: Add actual record type
|
||||
SyntaxShape::RowCondition => Type::Bool,
|
||||
SyntaxShape::Boolean => Type::Bool,
|
||||
SyntaxShape::Signature => Type::Signature,
|
||||
|
@ -138,6 +142,7 @@ impl Display for SyntaxShape {
|
|||
SyntaxShape::Block(_) => write!(f, "block"),
|
||||
SyntaxShape::Table => write!(f, "table"),
|
||||
SyntaxShape::List(x) => write!(f, "list<{}>", x),
|
||||
SyntaxShape::Record => write!(f, "record"),
|
||||
SyntaxShape::Filesize => write!(f, "filesize"),
|
||||
SyntaxShape::Duration => write!(f, "duration"),
|
||||
SyntaxShape::Operator => write!(f, "operator"),
|
||||
|
|
|
@ -353,6 +353,20 @@ impl FromValue for Vec<Value> {
|
|||
}
|
||||
}
|
||||
|
||||
// A record
|
||||
impl FromValue for (Vec<String>, Vec<Value>) {
|
||||
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||
match v {
|
||||
Value::Record { cols, vals, .. } => Ok((cols.clone(), vals.clone())),
|
||||
v => Err(ShellError::CantConvert(
|
||||
"Record".into(),
|
||||
v.get_type().to_string(),
|
||||
v.span()?,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromValue for CaptureBlock {
|
||||
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||
match v {
|
||||
|
|
Loading…
Reference in a new issue