mirror of
https://github.com/nushell/nushell.git
synced 2025-01-11 00:38:23 +01:00
Add support for load-env (#752)
This commit is contained in:
parent
75db4a75bc
commit
b78924c777
@ -234,6 +234,7 @@ pub fn create_default_context(cwd: impl AsRef<Path>) -> EngineState {
|
|||||||
|
|
||||||
// Conversions
|
// Conversions
|
||||||
bind_command! {
|
bind_command! {
|
||||||
|
Fmt,
|
||||||
Into,
|
Into,
|
||||||
IntoBool,
|
IntoBool,
|
||||||
IntoBinary,
|
IntoBinary,
|
||||||
@ -242,14 +243,14 @@ pub fn create_default_context(cwd: impl AsRef<Path>) -> EngineState {
|
|||||||
IntoFilesize,
|
IntoFilesize,
|
||||||
IntoInt,
|
IntoInt,
|
||||||
IntoString,
|
IntoString,
|
||||||
Fmt,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Env
|
// Env
|
||||||
bind_command! {
|
bind_command! {
|
||||||
LetEnv,
|
|
||||||
WithEnv,
|
|
||||||
Env,
|
Env,
|
||||||
|
LetEnv,
|
||||||
|
LoadEnv,
|
||||||
|
WithEnv,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Math
|
// 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 env_command;
|
||||||
mod let_env;
|
mod let_env;
|
||||||
|
mod load_env;
|
||||||
mod with_env;
|
mod with_env;
|
||||||
|
|
||||||
pub use env_command::Env;
|
pub use env_command::Env;
|
||||||
pub use let_env::LetEnv;
|
pub use let_env::LetEnv;
|
||||||
|
pub use load_env::LoadEnv;
|
||||||
pub use with_env::WithEnv;
|
pub use with_env::WithEnv;
|
||||||
|
@ -13,7 +13,6 @@ use std::path::Path;
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Open;
|
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 {
|
impl Command for Open {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"open"
|
"open"
|
||||||
|
@ -9,7 +9,6 @@ use std::path::Path;
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Save;
|
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 {
|
impl Command for Save {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"save"
|
"save"
|
||||||
|
@ -2970,6 +2970,8 @@ pub fn parse_value(
|
|||||||
}
|
}
|
||||||
if matches!(shape, SyntaxShape::Block(_)) || matches!(shape, SyntaxShape::Any) {
|
if matches!(shape, SyntaxShape::Block(_)) || matches!(shape, SyntaxShape::Any) {
|
||||||
return parse_block_expression(working_set, shape, span);
|
return parse_block_expression(working_set, shape, span);
|
||||||
|
} else if matches!(shape, SyntaxShape::Record) {
|
||||||
|
return parse_record(working_set, span);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
Expression::garbage(span),
|
Expression::garbage(span),
|
||||||
|
@ -80,6 +80,9 @@ pub enum SyntaxShape {
|
|||||||
/// A boolean value
|
/// A boolean value
|
||||||
Boolean,
|
Boolean,
|
||||||
|
|
||||||
|
/// A record value
|
||||||
|
Record,
|
||||||
|
|
||||||
/// A custom shape with custom completion logic
|
/// A custom shape with custom completion logic
|
||||||
Custom(Box<SyntaxShape>, String),
|
Custom(Box<SyntaxShape>, String),
|
||||||
}
|
}
|
||||||
@ -108,6 +111,7 @@ impl SyntaxShape {
|
|||||||
SyntaxShape::Number => Type::Number,
|
SyntaxShape::Number => Type::Number,
|
||||||
SyntaxShape::Operator => Type::Unknown,
|
SyntaxShape::Operator => Type::Unknown,
|
||||||
SyntaxShape::Range => Type::Unknown,
|
SyntaxShape::Range => Type::Unknown,
|
||||||
|
SyntaxShape::Record => Type::Record(vec![]), // FIXME: Add actual record type
|
||||||
SyntaxShape::RowCondition => Type::Bool,
|
SyntaxShape::RowCondition => Type::Bool,
|
||||||
SyntaxShape::Boolean => Type::Bool,
|
SyntaxShape::Boolean => Type::Bool,
|
||||||
SyntaxShape::Signature => Type::Signature,
|
SyntaxShape::Signature => Type::Signature,
|
||||||
@ -138,6 +142,7 @@ impl Display for SyntaxShape {
|
|||||||
SyntaxShape::Block(_) => write!(f, "block"),
|
SyntaxShape::Block(_) => write!(f, "block"),
|
||||||
SyntaxShape::Table => write!(f, "table"),
|
SyntaxShape::Table => write!(f, "table"),
|
||||||
SyntaxShape::List(x) => write!(f, "list<{}>", x),
|
SyntaxShape::List(x) => write!(f, "list<{}>", x),
|
||||||
|
SyntaxShape::Record => write!(f, "record"),
|
||||||
SyntaxShape::Filesize => write!(f, "filesize"),
|
SyntaxShape::Filesize => write!(f, "filesize"),
|
||||||
SyntaxShape::Duration => write!(f, "duration"),
|
SyntaxShape::Duration => write!(f, "duration"),
|
||||||
SyntaxShape::Operator => write!(f, "operator"),
|
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 {
|
impl FromValue for CaptureBlock {
|
||||||
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||||
match v {
|
match v {
|
||||||
|
Loading…
Reference in New Issue
Block a user