Add export-env command (#6355)

* WIP Start export-env

* Add missing file

* Do not modify the parser

Let's leave that for later

* Enable tests for export-env; Fmt
This commit is contained in:
Jakub Žádník 2022-08-18 23:24:39 +03:00 committed by GitHub
parent 529c98085a
commit 5a56d47f25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 104 additions and 21 deletions

View File

@ -3,9 +3,9 @@ use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Value}; use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Value};
#[derive(Clone)] #[derive(Clone)]
pub struct ExportEnv; pub struct ExportEnvModule;
impl Command for ExportEnv { impl Command for ExportEnvModule {
fn name(&self) -> &str { fn name(&self) -> &str {
"export env" "export env"
} }

View File

@ -40,7 +40,7 @@ pub use export::ExportCommand;
pub use export_alias::ExportAlias; pub use export_alias::ExportAlias;
pub use export_def::ExportDef; pub use export_def::ExportDef;
pub use export_def_env::ExportDefEnv; pub use export_def_env::ExportDefEnv;
pub use export_env::ExportEnv; pub use export_env::ExportEnvModule;
pub use export_extern::ExportExtern; pub use export_extern::ExportExtern;
pub use export_use::ExportUse; pub use export_use::ExportUse;
pub use extern_::Extern; pub use extern_::Extern;

View File

@ -40,7 +40,7 @@ pub fn create_default_context() -> EngineState {
ExportCommand, ExportCommand,
ExportDef, ExportDef,
ExportDefEnv, ExportDefEnv,
ExportEnv, ExportEnvModule,
ExportExtern, ExportExtern,
ExportUse, ExportUse,
Extern, Extern,
@ -352,6 +352,7 @@ pub fn create_default_context() -> EngineState {
// Env // Env
bind_command! { bind_command! {
Env, Env,
ExportEnv,
LetEnv, LetEnv,
LoadEnv, LoadEnv,
WithEnv, WithEnv,

74
crates/nu-command/src/env/export_env.rs vendored Normal file
View File

@ -0,0 +1,74 @@
use nu_engine::{eval_block, redirect_env, CallExt};
use nu_protocol::{
ast::Call,
engine::{CaptureBlock, Command, EngineState, Stack},
Category, Example, PipelineData, Signature, Span, SyntaxShape, Value,
};
#[derive(Clone)]
pub struct ExportEnv;
impl Command for ExportEnv {
fn name(&self) -> &str {
"export-env"
}
fn signature(&self) -> Signature {
Signature::build("export-env")
.required(
"block",
SyntaxShape::Block(Some(vec![])),
"the block to run to set the environment",
)
.category(Category::Env)
}
fn usage(&self) -> &str {
"Run a block and preserve its environment in a current scope."
}
fn run(
&self,
engine_state: &EngineState,
caller_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let capture_block: CaptureBlock = call.req(engine_state, caller_stack, 0)?;
let block = engine_state.get_block(capture_block.block_id);
let mut callee_stack = caller_stack.captures_to_stack(&capture_block.captures);
let _ = eval_block(
engine_state,
&mut callee_stack,
block,
input,
call.redirect_stdout,
call.redirect_stderr,
);
redirect_env(engine_state, caller_stack, &callee_stack);
Ok(PipelineData::new(call.head))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Set an environment",
example: r#"export-env { let-env SPAM = 'eggs' }; $env.SPAM"#,
result: Some(Value::string("eggs", Span::test_data())),
}]
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(ExportEnv {})
}
}

View File

@ -1,5 +1,6 @@
mod config; mod config;
mod env_command; mod env_command;
mod export_env;
mod let_env; mod let_env;
mod load_env; mod load_env;
mod with_env; mod with_env;
@ -9,6 +10,7 @@ pub use config::ConfigMeta;
pub use config::ConfigNu; pub use config::ConfigNu;
pub use config::ConfigReset; pub use config::ConfigReset;
pub use env_command::Env; pub use env_command::Env;
pub use export_env::ExportEnv;
pub use let_env::LetEnv; pub use let_env::LetEnv;
pub use load_env::LoadEnv; pub use load_env::LoadEnv;
pub use with_env::WithEnv; pub use with_env::WithEnv;

View File

@ -13,8 +13,8 @@ use crate::To;
#[cfg(test)] #[cfg(test)]
use super::{ use super::{
Ansi, Date, From, If, Into, Math, Path, Random, Split, SplitColumn, SplitRow, Str, StrCollect, Ansi, Date, From, If, Into, LetEnv, Math, Path, Random, Split, SplitColumn, SplitRow, Str,
StrLength, StrReplace, Url, Wrap, StrCollect, StrLength, StrReplace, Url, Wrap,
}; };
#[cfg(test)] #[cfg(test)]
@ -47,6 +47,7 @@ pub fn test_examples(cmd: impl Command + 'static) {
working_set.add_decl(Box::new(Url)); working_set.add_decl(Box::new(Url));
working_set.add_decl(Box::new(Ansi)); working_set.add_decl(Box::new(Ansi));
working_set.add_decl(Box::new(Wrap)); working_set.add_decl(Box::new(Wrap));
working_set.add_decl(Box::new(LetEnv));
use super::Echo; use super::Echo;
working_set.add_decl(Box::new(Echo)); working_set.add_decl(Box::new(Echo));

View File

@ -159,20 +159,7 @@ pub fn eval_call(
); );
if block.redirect_env { if block.redirect_env {
let caller_env_vars = caller_stack.get_env_var_names(engine_state); redirect_env(engine_state, caller_stack, &callee_stack);
// remove env vars that are present in the caller but not in the callee
// (the callee hid them)
for var in caller_env_vars.iter() {
if !callee_stack.has_env_var(engine_state, var) {
caller_stack.remove_env_var(engine_state, var);
}
}
// add new env vars from callee to caller
for (var, value) in callee_stack.get_stack_env_vars() {
caller_stack.add_env_var(var, value);
}
} }
result result
@ -184,6 +171,24 @@ pub fn eval_call(
} }
} }
/// Redirect the environment from callee to the caller.
pub fn redirect_env(engine_state: &EngineState, caller_stack: &mut Stack, callee_stack: &Stack) {
let caller_env_vars = caller_stack.get_env_var_names(engine_state);
// remove env vars that are present in the caller but not in the callee
// (the callee hid them)
for var in caller_env_vars.iter() {
if !callee_stack.has_env_var(engine_state, var) {
caller_stack.remove_env_var(engine_state, var);
}
}
// add new env vars from callee to caller
for (var, value) in callee_stack.get_stack_env_vars() {
caller_stack.add_env_var(var, value);
}
}
/// Eval extarnal expression /// Eval extarnal expression
/// ///
/// It returns PipelineData with a boolean flag, indicate that if the external runs to failed. /// It returns PipelineData with a boolean flag, indicate that if the external runs to failed.

View File

@ -11,6 +11,6 @@ pub use documentation::get_full_help;
pub use env::*; pub use env::*;
pub use eval::{ pub use eval::{
eval_block, eval_call, eval_expression, eval_expression_with_input, eval_operator, eval_block, eval_call, eval_expression, eval_expression_with_input, eval_operator,
eval_subexpression, eval_variable, eval_subexpression, eval_variable, redirect_env,
}; };
pub use glob_from::glob_from; pub use glob_from::glob_from;