mirror of
https://github.com/nushell/nushell
synced 2025-01-10 20:29:06 +00:00
522a828687
* Refactor InputStream and affected commands. First, making `values` private and leaning on the `Stream` implementation makes consumes of `InputStream` less likely to have to change in the future, if we change what an `InputStream` is internally. Second, we're dropping `Option<InputStream>` as the input to pipelines, internals, and externals. Instead, `InputStream.is_empty` can be used to check for "emptiness". Empty streams are typically only ever used as the first input to a pipeline. * Add run_external internal command. We want to push external commands closer to internal commands, eventually eliminating the concept of "external" completely. This means we can consolidate a couple of things: - Variable evaluation (for example, `$it`, `$nu`, alias vars) - Behaviour of whole stream vs per-item external execution It should also make it easier for us to start introducing argument signatures for external commands, * Update run_external.rs * Update run_external.rs * Update run_external.rs * Update run_external.rs Co-authored-by: Jonathan Turner <jonathandturner@users.noreply.github.com>
128 lines
3.7 KiB
Rust
128 lines
3.7 KiB
Rust
use crate::commands::classified::external;
|
|
use crate::commands::WholeStreamCommand;
|
|
use crate::prelude::*;
|
|
|
|
use derive_new::new;
|
|
use parking_lot::Mutex;
|
|
|
|
use nu_errors::ShellError;
|
|
use nu_protocol::hir::{
|
|
Expression, ExternalArg, ExternalArgs, ExternalCommand, Literal, SpannedExpression,
|
|
};
|
|
use nu_protocol::{ReturnSuccess, Scope, Signature, SyntaxShape};
|
|
|
|
#[derive(Deserialize)]
|
|
pub struct RunExternalArgs {}
|
|
|
|
#[derive(new)]
|
|
pub struct RunExternalCommand;
|
|
|
|
fn spanned_expression_to_string(expr: &SpannedExpression) -> String {
|
|
if let SpannedExpression {
|
|
expr: Expression::Literal(Literal::String(s)),
|
|
..
|
|
} = expr
|
|
{
|
|
s.clone()
|
|
} else {
|
|
"notacommand!!!".to_string()
|
|
}
|
|
}
|
|
|
|
impl WholeStreamCommand for RunExternalCommand {
|
|
fn name(&self) -> &str {
|
|
"run_external"
|
|
}
|
|
|
|
fn signature(&self) -> Signature {
|
|
Signature::build(self.name()).rest(SyntaxShape::Any, "external command arguments")
|
|
}
|
|
|
|
fn usage(&self) -> &str {
|
|
""
|
|
}
|
|
|
|
fn run(
|
|
&self,
|
|
args: CommandArgs,
|
|
registry: &CommandRegistry,
|
|
) -> Result<OutputStream, ShellError> {
|
|
let positionals = args.call_info.args.positional.ok_or_else(|| {
|
|
ShellError::untagged_runtime_error("positional arguments unexpectedly empty")
|
|
})?;
|
|
|
|
let mut command_args = positionals.iter();
|
|
let name = command_args
|
|
.next()
|
|
.map(spanned_expression_to_string)
|
|
.ok_or_else(|| {
|
|
ShellError::untagged_runtime_error(
|
|
"run_external unexpectedly missing external name positional arg",
|
|
)
|
|
})?;
|
|
|
|
let command = ExternalCommand {
|
|
name,
|
|
name_tag: Tag::unknown(),
|
|
args: ExternalArgs {
|
|
list: command_args
|
|
.map(|arg| ExternalArg {
|
|
arg: spanned_expression_to_string(arg),
|
|
tag: Tag::unknown(),
|
|
})
|
|
.collect(),
|
|
span: Default::default(),
|
|
},
|
|
};
|
|
|
|
let mut external_context;
|
|
#[cfg(windows)]
|
|
{
|
|
external_context = Context {
|
|
registry: registry.clone(),
|
|
host: args.host.clone(),
|
|
shell_manager: args.shell_manager.clone(),
|
|
ctrl_c: args.ctrl_c.clone(),
|
|
current_errors: Arc::new(Mutex::new(vec![])),
|
|
windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())),
|
|
};
|
|
}
|
|
#[cfg(not(windows))]
|
|
{
|
|
external_context = Context {
|
|
registry: registry.clone(),
|
|
host: args.host.clone(),
|
|
shell_manager: args.shell_manager.clone(),
|
|
ctrl_c: args.ctrl_c.clone(),
|
|
current_errors: Arc::new(Mutex::new(vec![])),
|
|
};
|
|
}
|
|
|
|
let is_last = args.call_info.args.is_last;
|
|
let input = args.input;
|
|
let stream = async_stream! {
|
|
let scope = Scope::empty();
|
|
let result = external::run_external_command(
|
|
command,
|
|
&mut external_context,
|
|
input,
|
|
&scope,
|
|
is_last,
|
|
).await;
|
|
|
|
match result {
|
|
Ok(mut stream) => {
|
|
while let Some(value) = stream.next().await {
|
|
yield Ok(ReturnSuccess::Value(value));
|
|
}
|
|
},
|
|
Err(e) => {
|
|
yield Err(e);
|
|
},
|
|
_ => {}
|
|
}
|
|
};
|
|
|
|
Ok(stream.to_output_stream())
|
|
}
|
|
}
|