mirror of
https://github.com/nushell/nushell
synced 2025-01-13 21:55:07 +00:00
Refactor classified.rs into separate modules.
Adds modules for internal, external, and dynamic commands, as well as the pipeline functionality. These are exported as their old names from the classified module so as to keep its "interface" the same.
This commit is contained in:
parent
8f9dd6516e
commit
4e9afd6698
6 changed files with 232 additions and 355 deletions
0
crates/nu-parser/src/commands/classified/external.rs
Normal file
0
crates/nu-parser/src/commands/classified/external.rs
Normal file
|
@ -1,6 +1,6 @@
|
||||||
use crate::commands::classified::{
|
use crate::commands::classified::external::{run_external_command, StreamNext};
|
||||||
run_external_command, run_internal_command, ClassifiedInputStream, StreamNext,
|
use crate::commands::classified::internal::run_internal_command;
|
||||||
};
|
use crate::commands::classified::ClassifiedInputStream;
|
||||||
use crate::commands::plugin::JsonRpc;
|
use crate::commands::plugin::JsonRpc;
|
||||||
use crate::commands::plugin::{PluginCommand, PluginSink};
|
use crate::commands::plugin::{PluginCommand, PluginSink};
|
||||||
use crate::commands::whole_stream_command;
|
use crate::commands::whole_stream_command;
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
use super::ClassifiedInputStream;
|
|
||||||
use crate::data::value;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use bytes::{BufMut, BytesMut};
|
use bytes::{BufMut, BytesMut};
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
use futures_codec::{Decoder, Encoder, Framed};
|
use futures_codec::{Decoder, Encoder, Framed};
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
|
use nu_parser::ExternalCommand;
|
||||||
use nu_protocol::Value;
|
use nu_protocol::Value;
|
||||||
use std::io::{Error, ErrorKind};
|
use std::io::{Error, ErrorKind};
|
||||||
use subprocess::Exec;
|
use subprocess::Exec;
|
||||||
|
|
||||||
|
use super::ClassifiedInputStream;
|
||||||
|
|
||||||
/// A simple `Codec` implementation that splits up data into lines.
|
/// A simple `Codec` implementation that splits up data into lines.
|
||||||
pub struct LinesCodec {}
|
pub struct LinesCodec {}
|
||||||
|
|
||||||
|
@ -46,36 +47,6 @@ impl Decoder for LinesCodec {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub struct Command {
|
|
||||||
pub(crate) name: String,
|
|
||||||
|
|
||||||
pub(crate) name_tag: Tag,
|
|
||||||
pub(crate) args: ExternalArgs,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasSpan for Command {
|
|
||||||
fn span(&self) -> Span {
|
|
||||||
self.name_tag.span.until(self.args.span)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PrettyDebug for Command {
|
|
||||||
fn pretty(&self) -> DebugDocBuilder {
|
|
||||||
b::typed(
|
|
||||||
"external command",
|
|
||||||
b::description(&self.name)
|
|
||||||
+ b::preceded(
|
|
||||||
b::space(),
|
|
||||||
b::intersperse(
|
|
||||||
self.args.iter().map(|a| b::primitive(format!("{}", a.arg))),
|
|
||||||
b::space(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum StreamNext {
|
pub(crate) enum StreamNext {
|
||||||
Last,
|
Last,
|
||||||
|
@ -83,9 +54,8 @@ pub(crate) enum StreamNext {
|
||||||
Internal,
|
Internal,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Command {
|
pub(crate) async fn run_external_command(
|
||||||
pub(crate) async fn run(
|
command: ExternalCommand,
|
||||||
self,
|
|
||||||
context: &mut Context,
|
context: &mut Context,
|
||||||
input: ClassifiedInputStream,
|
input: ClassifiedInputStream,
|
||||||
stream_next: StreamNext,
|
stream_next: StreamNext,
|
||||||
|
@ -93,15 +63,15 @@ impl Command {
|
||||||
let stdin = input.stdin;
|
let stdin = input.stdin;
|
||||||
let inputs: Vec<Value> = input.objects.into_vec().await;
|
let inputs: Vec<Value> = input.objects.into_vec().await;
|
||||||
|
|
||||||
trace!(target: "nu::run::external", "-> {}", self.name);
|
trace!(target: "nu::run::external", "-> {}", command.name);
|
||||||
trace!(target: "nu::run::external", "inputs = {:?}", inputs);
|
trace!(target: "nu::run::external", "inputs = {:?}", inputs);
|
||||||
|
|
||||||
let mut arg_string = format!("{}", self.name);
|
let mut arg_string = format!("{}", command.name);
|
||||||
for arg in &self.args.list {
|
for arg in command.args.iter() {
|
||||||
arg_string.push_str(&arg);
|
arg_string.push_str(&arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!(target: "nu::run::external", "command = {:?}", self.name);
|
trace!(target: "nu::run::external", "command = {:?}", command.name);
|
||||||
|
|
||||||
let mut process;
|
let mut process;
|
||||||
if arg_string.contains("$it") {
|
if arg_string.contains("$it") {
|
||||||
|
@ -109,7 +79,7 @@ impl Command {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
i.as_string().map(|s| s.to_string()).map_err(|_| {
|
i.as_string().map(|s| s.to_string()).map_err(|_| {
|
||||||
let arg = self.args.iter().find(|arg| arg.arg.contains("$it"));
|
let arg = command.args.iter().find(|arg| arg.contains("$it"));
|
||||||
if let Some(arg) = arg {
|
if let Some(arg) = arg {
|
||||||
ShellError::labeled_error(
|
ShellError::labeled_error(
|
||||||
"External $it needs string data",
|
"External $it needs string data",
|
||||||
|
@ -120,7 +90,7 @@ impl Command {
|
||||||
ShellError::labeled_error(
|
ShellError::labeled_error(
|
||||||
"$it needs string data",
|
"$it needs string data",
|
||||||
"given something else",
|
"given something else",
|
||||||
self.name_tag.clone(),
|
command.name_tag.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -128,7 +98,7 @@ impl Command {
|
||||||
.collect::<Result<Vec<String>, ShellError>>()?;
|
.collect::<Result<Vec<String>, ShellError>>()?;
|
||||||
|
|
||||||
let commands = input_strings.iter().map(|i| {
|
let commands = input_strings.iter().map(|i| {
|
||||||
let args = self.args.iter().filter_map(|arg| {
|
let args = command.args.iter().filter_map(|arg| {
|
||||||
if arg.chars().all(|c| c.is_whitespace()) {
|
if arg.chars().all(|c| c.is_whitespace()) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -136,18 +106,15 @@ impl Command {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
format!("{} {}", self.name, itertools::join(args, " "))
|
format!("{} {}", command.name, itertools::join(args, " "))
|
||||||
});
|
});
|
||||||
|
|
||||||
process = Exec::shell(itertools::join(commands, " && "))
|
process = Exec::shell(itertools::join(commands, " && "))
|
||||||
} else {
|
} else {
|
||||||
process = Exec::cmd(&self.name);
|
process = Exec::cmd(&command.name);
|
||||||
for arg in &self.args.list {
|
for arg in command.args.iter() {
|
||||||
let arg_chars: Vec<_> = arg.chars().collect();
|
let arg_chars: Vec<_> = arg.chars().collect();
|
||||||
if arg_chars.len() > 1
|
if arg_chars.len() > 1 && arg_chars[0] == '"' && arg_chars[arg_chars.len() - 1] == '"' {
|
||||||
&& arg_chars[0] == '"'
|
|
||||||
&& arg_chars[arg_chars.len() - 1] == '"'
|
|
||||||
{
|
|
||||||
// quoted string
|
// quoted string
|
||||||
let new_arg: String = arg_chars[1..arg_chars.len() - 1].iter().collect();
|
let new_arg: String = arg_chars[1..arg_chars.len() - 1].iter().collect();
|
||||||
process = process.arg(new_arg);
|
process = process.arg(new_arg);
|
||||||
|
@ -181,7 +148,7 @@ impl Command {
|
||||||
|
|
||||||
trace!(target: "nu::run::external", "next = {:?}", stream_next);
|
trace!(target: "nu::run::external", "next = {:?}", stream_next);
|
||||||
|
|
||||||
let name_tag = self.name_tag.clone();
|
let name_tag = command.name_tag.clone();
|
||||||
if let Ok(mut popen) = popen {
|
if let Ok(mut popen) = popen {
|
||||||
match stream_next {
|
match stream_next {
|
||||||
StreamNext::Last => {
|
StreamNext::Last => {
|
||||||
|
@ -224,38 +191,3 @@ impl Command {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub struct ExternalArg {
|
|
||||||
pub arg: String,
|
|
||||||
pub tag: Tag,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Deref for ExternalArg {
|
|
||||||
type Target = str;
|
|
||||||
|
|
||||||
fn deref(&self) -> &str {
|
|
||||||
&self.arg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub struct ExternalArgs {
|
|
||||||
pub list: Vec<ExternalArg>,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExternalArgs {
|
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &ExternalArg> {
|
|
||||||
self.list.iter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Deref for ExternalArgs {
|
|
||||||
type Target = [ExternalArg];
|
|
||||||
|
|
||||||
fn deref(&self) -> &[ExternalArg] {
|
|
||||||
&self.list
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,57 +1,37 @@
|
||||||
use crate::data::value;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use derive_new::new;
|
|
||||||
use log::{log_enabled, trace};
|
use log::{log_enabled, trace};
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_parser::hir;
|
use nu_parser::InternalCommand;
|
||||||
use nu_protocol::{CommandAction, Primitive, ReturnSuccess, UntaggedValue, Value};
|
use nu_protocol::{CommandAction, Primitive, ReturnSuccess, UntaggedValue, Value};
|
||||||
|
|
||||||
use super::ClassifiedInputStream;
|
use super::ClassifiedInputStream;
|
||||||
|
|
||||||
#[derive(new, Debug, Clone, Eq, PartialEq)]
|
pub(crate) async fn run_internal_command(
|
||||||
pub struct Command {
|
command: InternalCommand,
|
||||||
pub(crate) name: String,
|
|
||||||
pub(crate) name_tag: Tag,
|
|
||||||
pub(crate) args: hir::Call,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasSpan for Command {
|
|
||||||
fn span(&self) -> Span {
|
|
||||||
let start = self.name_tag.span;
|
|
||||||
|
|
||||||
start.until(self.args.span)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PrettyDebugWithSource for Command {
|
|
||||||
fn pretty_debug(&self, source: &str) -> DebugDocBuilder {
|
|
||||||
b::typed(
|
|
||||||
"internal command",
|
|
||||||
b::description(&self.name) + b::space() + self.args.pretty_debug(source),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command {
|
|
||||||
pub(crate) fn run(
|
|
||||||
self,
|
|
||||||
context: &mut Context,
|
context: &mut Context,
|
||||||
input: ClassifiedInputStream,
|
input: ClassifiedInputStream,
|
||||||
source: Text,
|
source: Text,
|
||||||
) -> Result<InputStream, ShellError> {
|
) -> Result<InputStream, ShellError> {
|
||||||
if log_enabled!(log::Level::Trace) {
|
if log_enabled!(log::Level::Trace) {
|
||||||
trace!(target: "nu::run::internal", "->");
|
trace!(target: "nu::run::internal", "->");
|
||||||
trace!(target: "nu::run::internal", "{}", self.name);
|
trace!(target: "nu::run::internal", "{}", command.name);
|
||||||
trace!(target: "nu::run::internal", "{}", self.args.debug(&source));
|
trace!(target: "nu::run::internal", "{}", command.args.debug(&source));
|
||||||
}
|
}
|
||||||
|
|
||||||
let objects: InputStream =
|
let objects: InputStream =
|
||||||
trace_stream!(target: "nu::trace_stream::internal", "input" = input.objects);
|
trace_stream!(target: "nu::trace_stream::internal", "input" = input.objects);
|
||||||
|
|
||||||
let command = context.expect_command(&self.name);
|
let internal_command = context.expect_command(&command.name);
|
||||||
|
|
||||||
let result =
|
let result = {
|
||||||
{ context.run_command(command, self.name_tag.clone(), self.args, &source, objects) };
|
context.run_command(
|
||||||
|
internal_command,
|
||||||
|
command.name_tag.clone(),
|
||||||
|
command.args,
|
||||||
|
&source,
|
||||||
|
objects,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let result = trace_out_stream!(target: "nu::trace_stream::internal", "output" = result);
|
let result = trace_out_stream!(target: "nu::trace_stream::internal", "output" = result);
|
||||||
let mut result = result.values;
|
let mut result = result.values;
|
||||||
|
@ -147,4 +127,3 @@ impl Command {
|
||||||
|
|
||||||
Ok(stream.to_input_stream())
|
Ok(stream.to_input_stream())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
|
use crate::data::value;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use nu_parser::{hir, TokenNode};
|
|
||||||
|
|
||||||
mod dynamic;
|
mod dynamic;
|
||||||
mod external;
|
pub(crate) mod external;
|
||||||
mod internal;
|
pub(crate) mod internal;
|
||||||
mod pipeline;
|
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
pub(crate) use dynamic::Command as DynamicCommand;
|
pub(crate) use dynamic::Command as DynamicCommand;
|
||||||
#[allow(unused_imports)]
|
|
||||||
pub(crate) use external::{Command as ExternalCommand, ExternalArg, ExternalArgs, StreamNext};
|
|
||||||
pub(crate) use internal::Command as InternalCommand;
|
|
||||||
|
|
||||||
pub(crate) struct ClassifiedInputStream {
|
pub(crate) struct ClassifiedInputStream {
|
||||||
pub(crate) objects: InputStream,
|
pub(crate) objects: InputStream,
|
||||||
|
@ -20,7 +16,7 @@ pub(crate) struct ClassifiedInputStream {
|
||||||
impl ClassifiedInputStream {
|
impl ClassifiedInputStream {
|
||||||
pub(crate) fn new() -> ClassifiedInputStream {
|
pub(crate) fn new() -> ClassifiedInputStream {
|
||||||
ClassifiedInputStream {
|
ClassifiedInputStream {
|
||||||
objects: vec![crate::data::value::nothing().into_untagged_value()].into(),
|
objects: vec![value::nothing().into_value(Tag::unknown())].into(),
|
||||||
stdin: None,
|
stdin: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,35 +35,3 @@ impl ClassifiedInputStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub enum ClassifiedCommand {
|
|
||||||
#[allow(unused)]
|
|
||||||
Expr(TokenNode),
|
|
||||||
#[allow(unused)]
|
|
||||||
Dynamic(hir::Call),
|
|
||||||
Internal(InternalCommand),
|
|
||||||
External(ExternalCommand),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PrettyDebugWithSource for ClassifiedCommand {
|
|
||||||
fn pretty_debug(&self, source: &str) -> DebugDocBuilder {
|
|
||||||
match self {
|
|
||||||
ClassifiedCommand::Expr(token) => b::typed("command", token.pretty_debug(source)),
|
|
||||||
ClassifiedCommand::Dynamic(call) => b::typed("command", call.pretty_debug(source)),
|
|
||||||
ClassifiedCommand::Internal(internal) => internal.pretty_debug(source),
|
|
||||||
ClassifiedCommand::External(external) => external.pretty_debug(source),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasSpan for ClassifiedCommand {
|
|
||||||
fn span(&self) -> Span {
|
|
||||||
match self {
|
|
||||||
ClassifiedCommand::Expr(node) => node.span(),
|
|
||||||
ClassifiedCommand::Internal(command) => command.span(),
|
|
||||||
ClassifiedCommand::Dynamic(call) => call.span,
|
|
||||||
ClassifiedCommand::External(command) => command.span(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -14,7 +14,9 @@ pub fn apply_operator(
|
||||||
| Operator::LessThan
|
| Operator::LessThan
|
||||||
| Operator::GreaterThan
|
| Operator::GreaterThan
|
||||||
| Operator::LessThanOrEqual
|
| Operator::LessThanOrEqual
|
||||||
| Operator::GreaterThanOrEqual => left.compare(op, right).map(value::boolean),
|
| Operator::GreaterThanOrEqual => {
|
||||||
|
value::compare_values(op, left, right).map(value::boolean)
|
||||||
|
}
|
||||||
Operator::Dot => Ok(value::boolean(false)),
|
Operator::Dot => Ok(value::boolean(false)),
|
||||||
Operator::Contains => contains(left, right).map(value::boolean),
|
Operator::Contains => contains(left, right).map(value::boolean),
|
||||||
Operator::NotContains => contains(left, right).map(Not::not).map(value::boolean),
|
Operator::NotContains => contains(left, right).map(Not::not).map(value::boolean),
|
||||||
|
|
Loading…
Reference in a new issue