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:
Jason Gedge 2019-11-24 17:19:12 -05:00 committed by Yehuda Katz
parent 8f9dd6516e
commit 4e9afd6698
6 changed files with 232 additions and 355 deletions

View file

@ -1,6 +1,6 @@
use crate::commands::classified::{
run_external_command, run_internal_command, ClassifiedInputStream, StreamNext,
};
use crate::commands::classified::external::{run_external_command, StreamNext};
use crate::commands::classified::internal::run_internal_command;
use crate::commands::classified::ClassifiedInputStream;
use crate::commands::plugin::JsonRpc;
use crate::commands::plugin::{PluginCommand, PluginSink};
use crate::commands::whole_stream_command;

View file

@ -1,15 +1,16 @@
use super::ClassifiedInputStream;
use crate::data::value;
use crate::prelude::*;
use bytes::{BufMut, BytesMut};
use futures::stream::StreamExt;
use futures_codec::{Decoder, Encoder, Framed};
use log::trace;
use nu_errors::ShellError;
use nu_parser::ExternalCommand;
use nu_protocol::Value;
use std::io::{Error, ErrorKind};
use subprocess::Exec;
use super::ClassifiedInputStream;
/// A simple `Codec` implementation that splits up data into lines.
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)]
pub(crate) enum StreamNext {
Last,
@ -83,25 +54,24 @@ pub(crate) enum StreamNext {
Internal,
}
impl Command {
pub(crate) async fn run(
self,
pub(crate) async fn run_external_command(
command: ExternalCommand,
context: &mut Context,
input: ClassifiedInputStream,
stream_next: StreamNext,
) -> Result<ClassifiedInputStream, ShellError> {
) -> Result<ClassifiedInputStream, ShellError> {
let stdin = input.stdin;
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);
let mut arg_string = format!("{}", self.name);
for arg in &self.args.list {
let mut arg_string = format!("{}", command.name);
for arg in command.args.iter() {
arg_string.push_str(&arg);
}
trace!(target: "nu::run::external", "command = {:?}", self.name);
trace!(target: "nu::run::external", "command = {:?}", command.name);
let mut process;
if arg_string.contains("$it") {
@ -109,7 +79,7 @@ impl Command {
.iter()
.map(|i| {
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 {
ShellError::labeled_error(
"External $it needs string data",
@ -120,7 +90,7 @@ impl Command {
ShellError::labeled_error(
"$it needs string data",
"given something else",
self.name_tag.clone(),
command.name_tag.clone(),
)
}
})
@ -128,7 +98,7 @@ impl Command {
.collect::<Result<Vec<String>, ShellError>>()?;
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()) {
None
} 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, " && "))
} else {
process = Exec::cmd(&self.name);
for arg in &self.args.list {
process = Exec::cmd(&command.name);
for arg in command.args.iter() {
let arg_chars: Vec<_> = arg.chars().collect();
if arg_chars.len() > 1
&& arg_chars[0] == '"'
&& arg_chars[arg_chars.len() - 1] == '"'
{
if arg_chars.len() > 1 && arg_chars[0] == '"' && arg_chars[arg_chars.len() - 1] == '"' {
// quoted string
let new_arg: String = arg_chars[1..arg_chars.len() - 1].iter().collect();
process = process.arg(new_arg);
@ -181,7 +148,7 @@ impl Command {
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 {
match stream_next {
StreamNext::Last => {
@ -223,39 +190,4 @@ impl Command {
name_tag,
));
}
}
}
#[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
}
}

View file

@ -1,57 +1,37 @@
use crate::data::value;
use crate::prelude::*;
use derive_new::new;
use log::{log_enabled, trace};
use nu_errors::ShellError;
use nu_parser::hir;
use nu_parser::InternalCommand;
use nu_protocol::{CommandAction, Primitive, ReturnSuccess, UntaggedValue, Value};
use super::ClassifiedInputStream;
#[derive(new, Debug, Clone, Eq, PartialEq)]
pub struct Command {
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,
pub(crate) async fn run_internal_command(
command: InternalCommand,
context: &mut Context,
input: ClassifiedInputStream,
source: Text,
) -> Result<InputStream, ShellError> {
) -> Result<InputStream, ShellError> {
if log_enabled!(log::Level::Trace) {
trace!(target: "nu::run::internal", "->");
trace!(target: "nu::run::internal", "{}", self.name);
trace!(target: "nu::run::internal", "{}", self.args.debug(&source));
trace!(target: "nu::run::internal", "{}", command.name);
trace!(target: "nu::run::internal", "{}", command.args.debug(&source));
}
let objects: InputStream =
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 =
{ context.run_command(command, self.name_tag.clone(), self.args, &source, objects) };
let result = {
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 mut result = result.values;
@ -146,5 +126,4 @@ impl Command {
};
Ok(stream.to_input_stream())
}
}

View file

@ -1,16 +1,12 @@
use crate::data::value;
use crate::prelude::*;
use nu_parser::{hir, TokenNode};
mod dynamic;
mod external;
mod internal;
mod pipeline;
pub(crate) mod external;
pub(crate) mod internal;
#[allow(unused_imports)]
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) objects: InputStream,
@ -20,7 +16,7 @@ pub(crate) struct ClassifiedInputStream {
impl ClassifiedInputStream {
pub(crate) fn new() -> ClassifiedInputStream {
ClassifiedInputStream {
objects: vec![crate::data::value::nothing().into_untagged_value()].into(),
objects: vec![value::nothing().into_value(Tag::unknown())].into(),
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(),
}
}
}

View file

@ -14,7 +14,9 @@ pub fn apply_operator(
| Operator::LessThan
| Operator::GreaterThan
| 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::Contains => contains(left, right).map(value::boolean),
Operator::NotContains => contains(left, right).map(Not::not).map(value::boolean),