From 480467447ed3ba590e8fdc9e22bc150fe5ca4073 Mon Sep 17 00:00:00 2001 From: Jonathan Rothberg Date: Sun, 22 Sep 2019 18:49:11 -0700 Subject: [PATCH 1/4] Initial Docker command implementation. --- Cargo.lock | 6 +- src/cli.rs | 1 + src/commands.rs | 2 + src/commands/docker.rs | 256 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 262 insertions(+), 3 deletions(-) create mode 100644 src/commands/docker.rs diff --git a/Cargo.lock b/Cargo.lock index 3fea3453ee..eee0ffe248 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1556,7 +1556,7 @@ dependencies = [ "rawkey 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "roxmltree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rusqlite 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustyline 5.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustyline 5.0.2 (git+https://github.com/kkawakam/rustyline)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", "serde-hjson 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2196,7 +2196,7 @@ dependencies = [ [[package]] name = "rustyline" version = "5.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/kkawakam/rustyline#5e68e972810133a7343b75db30addc98aea63ba0" dependencies = [ "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3216,7 +3216,7 @@ dependencies = [ "checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustyline 5.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8ee0838a6594169a1c5f4bb9af0fe692cc99691941710a8cc6576395ede804e" +"checksum rustyline 5.0.2 (git+https://github.com/kkawakam/rustyline)" = "" "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" "checksum safemem 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e133ccc4f4d1cd4f89cc8a7ff618287d56dc7f638b8e38fc32c5fdcadc339dd5" "checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" diff --git a/src/cli.rs b/src/cli.rs index 7b6f6e863e..d834468db9 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -223,6 +223,7 @@ pub async fn cli() -> Result<(), Box> { whole_stream_command(Next), whole_stream_command(Previous), whole_stream_command(Debug), + whole_stream_command(Docker), whole_stream_command(Lines), whole_stream_command(Shells), whole_stream_command(SplitColumn), diff --git a/src/commands.rs b/src/commands.rs index c6cc7b7285..c15b32e590 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -11,6 +11,7 @@ pub(crate) mod config; pub(crate) mod cp; pub(crate) mod date; pub(crate) mod debug; +pub(crate) mod docker; pub(crate) mod echo; pub(crate) mod enter; pub(crate) mod exit; @@ -76,6 +77,7 @@ pub(crate) use config::Config; pub(crate) use cp::Cpy; pub(crate) use date::Date; pub(crate) use debug::Debug; +pub(crate) use docker::Docker; pub(crate) use echo::Echo; pub(crate) use enter::Enter; pub(crate) use exit::Exit; diff --git a/src/commands/docker.rs b/src/commands/docker.rs new file mode 100644 index 0000000000..ae5d37b9d1 --- /dev/null +++ b/src/commands/docker.rs @@ -0,0 +1,256 @@ +use crate::commands::WholeStreamCommand; +use crate::data::{Dictionary, Value}; +use crate::errors::ShellError; +use crate::parser::registry::Signature; +use crate::prelude::*; +use indexmap::IndexMap; +use std::process::Command; +use std::str; + +pub struct Docker; + +#[derive(Deserialize)] +pub struct DockerArgs { + sub_command: Tagged, + rest: Vec>, +} + +impl WholeStreamCommand for Docker { + fn name(&self) -> &str { + "docker" + } + + fn signature(&self) -> Signature { + Signature::build(self.name()) + .required("sub_command", SyntaxType::Member) + .rest(SyntaxType::Member) + } + + fn usage(&self) -> &str { + "e.g. docker ps, docker images" + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + args.process(registry, docker_arg)?.run() + // docker(args, registry) + } +} +pub fn docker_arg( + DockerArgs { + sub_command, + rest: _fields, + }: DockerArgs, + RunnableContext { input: _, .. }: RunnableContext, +) -> Result { + // let mut docker_out = VecDeque::new(); + // docker_out.push_back(Value::Primitive(Primitive::String("docker command"))); + // + // println!("Sub Command: {:?}", sub_command); + // match sub_command.item() { + // Tagged { item: val, .. } => println!("Val: {}", val), + // _ => {} + // } + + match sub_command.item().as_str() { + "ps" => { + // println!("ps command") + return docker_ps(); + } + "images" => { + // println!("images command"); + return docker_images(); + } + _ => { + return Err(ShellError::labeled_error( + "Unsupported Docker command", + format!("'{}'?", sub_command.item()), + Span::unknown(), + )) + } + } + + // let stream = input + // .values + // .map(move |item| { + // let mut result = VecDeque::new(); + + // let member = vec![member.clone()]; + + // let fields = vec![&member, &fields] + // .into_iter() + // .flatten() + // .collect::>>(); + + // for field in &fields { + // match get_member(field, &item) { + // Ok(Tagged { + // item: Value::Table(l), + // .. + // }) => { + // for item in l { + // result.push_back(ReturnSuccess::value(item.clone())); + // } + // } + // Ok(x) => result.push_back(ReturnSuccess::value(x.clone())), + // Err(x) => result.push_back(Err(x)), + // } + // } + + // result + // }) + // .flatten(); + + // Ok(docker_out.to_output_stream()) + // Ok(docker_out.to_output_stream()) +} + +fn process_docker_output(cmd_output: &str) -> Result { + let mut docker_out = VecDeque::new(); + let mut columns: Vec<&str> = cmd_output.lines().collect(); + // println!("{:#?}", columns); + + let header: Vec<&str> = columns + .iter() + .take(1) + .next() + .unwrap() + .split_whitespace() + .collect(); + + // println!("{:#?}", header); + + columns.remove(0); + + // let span = args.call_info.name_span; + for line in columns { + let values: Vec<&str> = line + .trim_end() + .split(" ") // Some columns values contains spaces to split by two spaces + .filter(|s| s.trim() != "") + .collect(); + + // println!("len: {}", values.len()); + // println!("Values: {:#?}", values); + let mut indexmap = IndexMap::new(); + for (i, v) in values.iter().enumerate() { + // println!("{}", i); + // println!("{}", header[i]); + indexmap.insert( + header[i].to_string(), + Tagged::from_simple_spanned_item( + Value::Primitive(Primitive::String(v.trim().to_string())), + Span::unknown(), + ), + ); + } + + docker_out.push_back(Tagged::from_simple_spanned_item( + Value::Row(Dictionary::from(indexmap)), + Span::unknown(), + )) + } + + // let t = dict.into_tagged_value(); + + // docker_out.push_back(ReturnSuccess::value(t)); + + Ok(docker_out.to_output_stream()) +} + +pub fn docker_images() -> Result { + // let mut docker_out = VecDeque::new(); + // docker_out.push_back(Value::Primitive(Primitive::String("docker command"))); + // Ok(docker_out.to_output_stream()) + // + // let mut dict = TaggedDictBuilder::new(Tag::unknown_origin(cmd_args.call_info.name_span)); + // dict.insert("name", Value::string("test name")); + // println!("{:#?}", cmd_args.call_info); + + // let args = cmd_args.evaluate_once(registry)?; + // println!("{:#?}", args.call_info); + + // let arg = args.nth(0); + // println!("{:?}", arg); + + // match &args.nth(0) { + // Some(val) => println!("Val: {:?}", val), + // _ => {} + // } + + let output = Command::new("docker") + .arg("images") + // .arg("--format") + // .arg("table {{.ID}}\t{{.Repository}}\t{{.Tag}}\t{{.CreatedSince}}") + .output() + .expect("failed to execute process."); + + let ps_output = str::from_utf8(&output.stdout).unwrap(); + let out = process_docker_output(ps_output); + + // let mut columns: Vec<&str> = ps_output.lines().collect(); + // // println!("{:#?}", columns); + + // let header: Vec<&str> = columns + // .iter() + // .take(1) + // .next() + // .unwrap() + // .split_whitespace() + // .collect(); + + // println!("{:#?}", header); + + // columns.remove(0); + + // let span = args.call_info.name_span; + // for line in columns { + // let values: Vec<&str> = line + // .trim_end() + // .split(" ") // Some columns values contains spaces to split by two spaces + // .filter(|s| s.trim() != "") + // .collect(); + + // // println!("len: {}", values.len()); + // // println!("Values: {:#?}", values); + // let mut indexmap = IndexMap::new(); + // for (i, v) in values.iter().enumerate() { + // // println!("{}", i); + // // println!("{}", header[i]); + // indexmap.insert( + // header[i].to_string(), + // Tagged::from_simple_spanned_item( + // Value::Primitive(Primitive::String(v.trim().to_string())), + // span, + // ), + // ); + // } + + // docker_out.push_back(Tagged::from_simple_spanned_item( + // Value::Row(Dictionary::from(indexmap)), + // span, + // )) + // } + + // let t = dict.into_tagged_value(); + + // docker_out.push_back(ReturnSuccess::value(t)); + + // Ok(docker_out.to_output_stream()) + out +} + +pub fn docker_ps() -> Result { + let output = Command::new("docker") + .arg("ps") + .output() + .expect("failed to execute process."); + + let ps_output = str::from_utf8(&output.stdout).unwrap(); + let out = process_docker_output(ps_output); + + out +} From e6bdef696d923c98e653be2fa92e875c5972cfba Mon Sep 17 00:00:00 2001 From: Jonathan Rothberg Date: Sun, 22 Sep 2019 20:19:43 -0700 Subject: [PATCH 2/4] Some cleanup. --- src/commands/docker.rs | 182 +++++------------------------------------ 1 file changed, 21 insertions(+), 161 deletions(-) diff --git a/src/commands/docker.rs b/src/commands/docker.rs index ae5d37b9d1..0149b4e04d 100644 --- a/src/commands/docker.rs +++ b/src/commands/docker.rs @@ -1,5 +1,6 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Dictionary, Value}; +use crate::data::meta::Span; +use crate::data::Value; use crate::errors::ShellError; use crate::parser::registry::Signature; use crate::prelude::*; @@ -22,8 +23,8 @@ impl WholeStreamCommand for Docker { fn signature(&self) -> Signature { Signature::build(self.name()) - .required("sub_command", SyntaxType::Member) - .rest(SyntaxType::Member) + .required("sub_command", SyntaxShape::Member) + .rest(SyntaxShape::Member) } fn usage(&self) -> &str { @@ -44,74 +45,22 @@ pub fn docker_arg( sub_command, rest: _fields, }: DockerArgs, - RunnableContext { input: _, .. }: RunnableContext, + RunnableContext { input: _, name, .. }: RunnableContext, ) -> Result { - // let mut docker_out = VecDeque::new(); - // docker_out.push_back(Value::Primitive(Primitive::String("docker command"))); - // - // println!("Sub Command: {:?}", sub_command); - // match sub_command.item() { - // Tagged { item: val, .. } => println!("Val: {}", val), - // _ => {} - // } - match sub_command.item().as_str() { - "ps" => { - // println!("ps command") - return docker_ps(); - } - "images" => { - // println!("images command"); - return docker_images(); - } - _ => { - return Err(ShellError::labeled_error( - "Unsupported Docker command", - format!("'{}'?", sub_command.item()), - Span::unknown(), - )) - } + "ps" => docker_ps(name), + "images" => docker_images(name), + _ => Err(ShellError::labeled_error( + "Unsupported Docker command", + format!("'{}'?", sub_command.item()), + Span::unknown(), + )), } - - // let stream = input - // .values - // .map(move |item| { - // let mut result = VecDeque::new(); - - // let member = vec![member.clone()]; - - // let fields = vec![&member, &fields] - // .into_iter() - // .flatten() - // .collect::>>(); - - // for field in &fields { - // match get_member(field, &item) { - // Ok(Tagged { - // item: Value::Table(l), - // .. - // }) => { - // for item in l { - // result.push_back(ReturnSuccess::value(item.clone())); - // } - // } - // Ok(x) => result.push_back(ReturnSuccess::value(x.clone())), - // Err(x) => result.push_back(Err(x)), - // } - // } - - // result - // }) - // .flatten(); - - // Ok(docker_out.to_output_stream()) - // Ok(docker_out.to_output_stream()) } -fn process_docker_output(cmd_output: &str) -> Result { +fn process_docker_output(cmd_output: &str, tag: Tag) -> Result { let mut docker_out = VecDeque::new(); - let mut columns: Vec<&str> = cmd_output.lines().collect(); - // println!("{:#?}", columns); + let columns: Vec<&str> = cmd_output.lines().collect(); let header: Vec<&str> = columns .iter() @@ -121,136 +70,47 @@ fn process_docker_output(cmd_output: &str) -> Result { .split_whitespace() .collect(); - // println!("{:#?}", header); - - columns.remove(0); - - // let span = args.call_info.name_span; - for line in columns { + for line in columns.iter().skip(1) { let values: Vec<&str> = line .trim_end() .split(" ") // Some columns values contains spaces to split by two spaces .filter(|s| s.trim() != "") .collect(); - // println!("len: {}", values.len()); - // println!("Values: {:#?}", values); let mut indexmap = IndexMap::new(); for (i, v) in values.iter().enumerate() { - // println!("{}", i); - // println!("{}", header[i]); indexmap.insert( header[i].to_string(), - Tagged::from_simple_spanned_item( - Value::Primitive(Primitive::String(v.trim().to_string())), - Span::unknown(), - ), + Value::string(v.trim().to_string()).tagged(tag), ); } - docker_out.push_back(Tagged::from_simple_spanned_item( - Value::Row(Dictionary::from(indexmap)), - Span::unknown(), - )) + docker_out.push_back(Value::Row(indexmap.into()).tagged(tag)) } - // let t = dict.into_tagged_value(); - - // docker_out.push_back(ReturnSuccess::value(t)); - Ok(docker_out.to_output_stream()) } -pub fn docker_images() -> Result { - // let mut docker_out = VecDeque::new(); - // docker_out.push_back(Value::Primitive(Primitive::String("docker command"))); - // Ok(docker_out.to_output_stream()) - // - // let mut dict = TaggedDictBuilder::new(Tag::unknown_origin(cmd_args.call_info.name_span)); - // dict.insert("name", Value::string("test name")); - // println!("{:#?}", cmd_args.call_info); - - // let args = cmd_args.evaluate_once(registry)?; - // println!("{:#?}", args.call_info); - - // let arg = args.nth(0); - // println!("{:?}", arg); - - // match &args.nth(0) { - // Some(val) => println!("Val: {:?}", val), - // _ => {} - // } - +pub fn docker_images(tag: Tag) -> Result { let output = Command::new("docker") .arg("images") - // .arg("--format") - // .arg("table {{.ID}}\t{{.Repository}}\t{{.Tag}}\t{{.CreatedSince}}") .output() .expect("failed to execute process."); let ps_output = str::from_utf8(&output.stdout).unwrap(); - let out = process_docker_output(ps_output); + let out = process_docker_output(ps_output, tag); - // let mut columns: Vec<&str> = ps_output.lines().collect(); - // // println!("{:#?}", columns); - - // let header: Vec<&str> = columns - // .iter() - // .take(1) - // .next() - // .unwrap() - // .split_whitespace() - // .collect(); - - // println!("{:#?}", header); - - // columns.remove(0); - - // let span = args.call_info.name_span; - // for line in columns { - // let values: Vec<&str> = line - // .trim_end() - // .split(" ") // Some columns values contains spaces to split by two spaces - // .filter(|s| s.trim() != "") - // .collect(); - - // // println!("len: {}", values.len()); - // // println!("Values: {:#?}", values); - // let mut indexmap = IndexMap::new(); - // for (i, v) in values.iter().enumerate() { - // // println!("{}", i); - // // println!("{}", header[i]); - // indexmap.insert( - // header[i].to_string(), - // Tagged::from_simple_spanned_item( - // Value::Primitive(Primitive::String(v.trim().to_string())), - // span, - // ), - // ); - // } - - // docker_out.push_back(Tagged::from_simple_spanned_item( - // Value::Row(Dictionary::from(indexmap)), - // span, - // )) - // } - - // let t = dict.into_tagged_value(); - - // docker_out.push_back(ReturnSuccess::value(t)); - - // Ok(docker_out.to_output_stream()) out } -pub fn docker_ps() -> Result { +pub fn docker_ps(tag: Tag) -> Result { let output = Command::new("docker") .arg("ps") .output() .expect("failed to execute process."); let ps_output = str::from_utf8(&output.stdout).unwrap(); - let out = process_docker_output(ps_output); + let out = process_docker_output(ps_output, tag); out } From f0b638063d27242c3c32df4bdc3a24182938ca46 Mon Sep 17 00:00:00 2001 From: Jonathan Rothberg Date: Tue, 24 Sep 2019 20:42:18 -0700 Subject: [PATCH 3/4] Transfered Docker to a plugin instead of a Command. --- Cargo.toml | 4 ++ debian/install | 1 + src/cli.rs | 2 +- src/commands.rs | 4 +- src/commands/docker.rs | 116 --------------------------------------- src/plugins/docker.rs | 120 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 128 insertions(+), 119 deletions(-) delete mode 100644 src/commands/docker.rs create mode 100644 src/plugins/docker.rs diff --git a/Cargo.toml b/Cargo.toml index e81bc0ee69..e28674d7be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -158,6 +158,10 @@ name = "nu_plugin_textview" path = "src/plugins/textview.rs" required-features = ["textview"] +[[bin]] +name = "nu_plugin_docker" +path = "src/plugins/docker.rs" + [[bin]] name = "nu" path = "src/main.rs" diff --git a/debian/install b/debian/install index 75cf2844d9..e9ebfc1232 100644 --- a/debian/install +++ b/debian/install @@ -8,3 +8,4 @@ target/release/nu_plugin_sum usr/bin target/release/nu_plugin_sys usr/bin target/release/nu_plugin_textview usr/bin target/release/nu_plugin_tree usr/bin +target/release/nu_plugin_docker usr/bin diff --git a/src/cli.rs b/src/cli.rs index 3bef636b2c..82413ec9a6 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -248,7 +248,7 @@ pub async fn cli() -> Result<(), Box> { whole_stream_command(Next), whole_stream_command(Previous), whole_stream_command(Debug), - whole_stream_command(Docker), + // whole_stream_command(Docker), whole_stream_command(Lines), whole_stream_command(Shells), whole_stream_command(SplitColumn), diff --git a/src/commands.rs b/src/commands.rs index cc23cb7d19..5e4287c0af 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -11,7 +11,7 @@ pub(crate) mod config; pub(crate) mod cp; pub(crate) mod date; pub(crate) mod debug; -pub(crate) mod docker; +// pub(crate) mod docker; pub(crate) mod echo; pub(crate) mod enter; pub(crate) mod env; @@ -80,7 +80,7 @@ pub(crate) use config::Config; pub(crate) use cp::Cpy; pub(crate) use date::Date; pub(crate) use debug::Debug; -pub(crate) use docker::Docker; +// pub(crate) use docker::Docker; pub(crate) use echo::Echo; pub(crate) use enter::Enter; pub(crate) use env::Env; diff --git a/src/commands/docker.rs b/src/commands/docker.rs deleted file mode 100644 index 0149b4e04d..0000000000 --- a/src/commands/docker.rs +++ /dev/null @@ -1,116 +0,0 @@ -use crate::commands::WholeStreamCommand; -use crate::data::meta::Span; -use crate::data::Value; -use crate::errors::ShellError; -use crate::parser::registry::Signature; -use crate::prelude::*; -use indexmap::IndexMap; -use std::process::Command; -use std::str; - -pub struct Docker; - -#[derive(Deserialize)] -pub struct DockerArgs { - sub_command: Tagged, - rest: Vec>, -} - -impl WholeStreamCommand for Docker { - fn name(&self) -> &str { - "docker" - } - - fn signature(&self) -> Signature { - Signature::build(self.name()) - .required("sub_command", SyntaxShape::Member) - .rest(SyntaxShape::Member) - } - - fn usage(&self) -> &str { - "e.g. docker ps, docker images" - } - - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - args.process(registry, docker_arg)?.run() - // docker(args, registry) - } -} -pub fn docker_arg( - DockerArgs { - sub_command, - rest: _fields, - }: DockerArgs, - RunnableContext { input: _, name, .. }: RunnableContext, -) -> Result { - match sub_command.item().as_str() { - "ps" => docker_ps(name), - "images" => docker_images(name), - _ => Err(ShellError::labeled_error( - "Unsupported Docker command", - format!("'{}'?", sub_command.item()), - Span::unknown(), - )), - } -} - -fn process_docker_output(cmd_output: &str, tag: Tag) -> Result { - let mut docker_out = VecDeque::new(); - let columns: Vec<&str> = cmd_output.lines().collect(); - - let header: Vec<&str> = columns - .iter() - .take(1) - .next() - .unwrap() - .split_whitespace() - .collect(); - - for line in columns.iter().skip(1) { - let values: Vec<&str> = line - .trim_end() - .split(" ") // Some columns values contains spaces to split by two spaces - .filter(|s| s.trim() != "") - .collect(); - - let mut indexmap = IndexMap::new(); - for (i, v) in values.iter().enumerate() { - indexmap.insert( - header[i].to_string(), - Value::string(v.trim().to_string()).tagged(tag), - ); - } - - docker_out.push_back(Value::Row(indexmap.into()).tagged(tag)) - } - - Ok(docker_out.to_output_stream()) -} - -pub fn docker_images(tag: Tag) -> Result { - let output = Command::new("docker") - .arg("images") - .output() - .expect("failed to execute process."); - - let ps_output = str::from_utf8(&output.stdout).unwrap(); - let out = process_docker_output(ps_output, tag); - - out -} - -pub fn docker_ps(tag: Tag) -> Result { - let output = Command::new("docker") - .arg("ps") - .output() - .expect("failed to execute process."); - - let ps_output = str::from_utf8(&output.stdout).unwrap(); - let out = process_docker_output(ps_output, tag); - - out -} diff --git a/src/plugins/docker.rs b/src/plugins/docker.rs new file mode 100644 index 0000000000..9cb8a52e80 --- /dev/null +++ b/src/plugins/docker.rs @@ -0,0 +1,120 @@ +use futures::executor::block_on; +use nu::{ + serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature, + SyntaxShape, Tag, Tagged, TaggedDictBuilder, Value, +}; + +use std::process::Command; +use std::str; + +struct Docker; + +impl Docker { + fn new() -> Self { + Self + } +} + +async fn docker(sub_command: &String, name: Tag) -> Result>, ShellError> { + match sub_command.as_str() { + "ps" => docker_ps(name), + "images" => docker_images(name), + _ => Err(ShellError::labeled_error( + "Unsupported Docker command", + format!("'{}'?", sub_command), + name.span, + )), + } +} + +fn process_docker_output(cmd_output: &str, tag: Tag) -> Result>, ShellError> { + let columns: Vec<&str> = cmd_output.lines().collect(); + + let header: Vec<&str> = columns + .iter() + .take(1) + .next() + .unwrap() + .split_whitespace() + .collect(); + + let mut output = vec![]; + for line in columns.iter().skip(1) { + let values: Vec<&str> = line + .trim_end() + .split(" ") // Some columns values contains spaces to split by two spaces + .filter(|s| s.trim() != "") + .collect(); + + let mut dict = TaggedDictBuilder::new(tag); + for (i, v) in values.iter().enumerate() { + dict.insert(header[i].to_string(), Value::string(v.trim().to_string())); + } + + output.push(dict.into_tagged_value()); + } + + Ok(output) +} + +pub fn docker_images(tag: Tag) -> Result>, ShellError> { + let output = Command::new("docker") + .arg("images") + .output() + .expect("failed to execute process."); + + let ps_output = str::from_utf8(&output.stdout).unwrap(); + let out = process_docker_output(ps_output, tag); + + out +} + +pub fn docker_ps(tag: Tag) -> Result>, ShellError> { + let output = Command::new("docker") + .arg("ps") + .output() + .expect("failed to execute process."); + + let ps_output = str::from_utf8(&output.stdout).unwrap(); + let out = process_docker_output(ps_output, tag); + + out +} + +impl Plugin for Docker { + fn config(&mut self) -> Result { + Ok(Signature::build("docker") + .required("sub_command", SyntaxShape::Member) + .filter()) + } + + fn begin_filter(&mut self, callinfo: CallInfo) -> Result, ShellError> { + if let Some(args) = callinfo.args.positional { + match &args[0] { + Tagged { + item: Value::Primitive(Primitive::String(s)), + .. + } => match block_on(docker(&s, callinfo.name_tag)) { + Ok(v) => return Ok(v.into_iter().map(ReturnSuccess::value).collect()), + Err(e) => return Err(e), + }, + _ => { + return Err(ShellError::string(format!( + "Unrecognized type in params: {:?}", + args[0] + ))) + } + } + } + + Ok(vec![]) + } + + fn filter(&mut self, _: Tagged) -> Result, ShellError> { + Ok(vec![]) + } +} + +fn main() { + serve_plugin(&mut Docker::new()); +} From 4af0dbe44182a25807fc2e35f2194c409488b51c Mon Sep 17 00:00:00 2001 From: Jonathan Rothberg Date: Fri, 27 Sep 2019 20:21:30 -0700 Subject: [PATCH 4/4] Removed commented code and added feature to Cargo.toml --- Cargo.toml | 1 + src/cli.rs | 1 - src/commands.rs | 2 -- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6da254c18b..073c213df0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -161,6 +161,7 @@ required-features = ["textview"] [[bin]] name = "nu_plugin_docker" path = "src/plugins/docker.rs" +required-features = ["docker"] [[bin]] name = "nu" diff --git a/src/cli.rs b/src/cli.rs index 7b5d49751e..3db0747d01 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -248,7 +248,6 @@ pub async fn cli() -> Result<(), Box> { whole_stream_command(Next), whole_stream_command(Previous), whole_stream_command(Debug), - // whole_stream_command(Docker), whole_stream_command(Lines), whole_stream_command(Shells), whole_stream_command(SplitColumn), diff --git a/src/commands.rs b/src/commands.rs index 5e4287c0af..72c07e38e6 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -11,7 +11,6 @@ pub(crate) mod config; pub(crate) mod cp; pub(crate) mod date; pub(crate) mod debug; -// pub(crate) mod docker; pub(crate) mod echo; pub(crate) mod enter; pub(crate) mod env; @@ -80,7 +79,6 @@ pub(crate) use config::Config; pub(crate) use cp::Cpy; pub(crate) use date::Date; pub(crate) use debug::Debug; -// pub(crate) use docker::Docker; pub(crate) use echo::Echo; pub(crate) use enter::Enter; pub(crate) use env::Env;