From 480467447ed3ba590e8fdc9e22bc150fe5ca4073 Mon Sep 17 00:00:00 2001 From: Jonathan Rothberg Date: Sun, 22 Sep 2019 18:49:11 -0700 Subject: [PATCH] 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 3fea3453..eee0ffe2 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 7b6f6e86..d834468d 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 c6cc7b72..c15b32e5 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 00000000..ae5d37b9 --- /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 +}