forked from extern/nushell
Merge pull request #1073 from jonathandturner/docker_wrap
Remove partial docker plugin. Embed->wrap
This commit is contained in:
commit
c9d9eec7f8
@ -147,10 +147,6 @@ path = "src/plugins/sum.rs"
|
||||
name = "nu_plugin_average"
|
||||
path = "src/plugins/average.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_embed"
|
||||
path = "src/plugins/embed.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_str"
|
||||
path = "src/plugins/str.rs"
|
||||
@ -168,11 +164,6 @@ name = "nu_plugin_tree"
|
||||
path = "src/plugins/tree.rs"
|
||||
required-features = ["tree"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_docker"
|
||||
path = "src/plugins/docker.rs"
|
||||
required-features = ["docker"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu"
|
||||
path = "src/main.rs"
|
||||
|
@ -310,6 +310,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||
whole_stream_command(Which),
|
||||
whole_stream_command(Debug),
|
||||
whole_stream_command(Range),
|
||||
whole_stream_command(Wrap),
|
||||
]);
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
|
@ -93,6 +93,7 @@ pub(crate) mod version;
|
||||
pub(crate) mod what;
|
||||
pub(crate) mod where_;
|
||||
pub(crate) mod which_;
|
||||
pub(crate) mod wrap;
|
||||
|
||||
pub(crate) use autoview::Autoview;
|
||||
pub(crate) use cd::CD;
|
||||
@ -186,3 +187,4 @@ pub(crate) use version::Version;
|
||||
pub(crate) use what::What;
|
||||
pub(crate) use where_::Where;
|
||||
pub(crate) use which_::Which;
|
||||
pub(crate) use wrap::Wrap;
|
||||
|
102
src/commands/wrap.rs
Normal file
102
src/commands/wrap.rs
Normal file
@ -0,0 +1,102 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
use indexmap::IndexMap;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
|
||||
pub struct Wrap;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct WrapArgs {
|
||||
column: Option<Tagged<String>>,
|
||||
}
|
||||
|
||||
impl WholeStreamCommand for Wrap {
|
||||
fn name(&self) -> &str {
|
||||
"wrap"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("wrap").optional(
|
||||
"column",
|
||||
SyntaxShape::String,
|
||||
"the name of the new column",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Wraps the given data in a table."
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
args.process(registry, wrap)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
fn wrap(
|
||||
WrapArgs { column }: WrapArgs,
|
||||
context: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let mut input = context.input;
|
||||
|
||||
let stream = async_stream! {
|
||||
let mut result_table = vec![];
|
||||
let mut are_all_rows = true;
|
||||
|
||||
while let Some(value) = input.next().await {
|
||||
match value {
|
||||
Value {
|
||||
value: UntaggedValue::Row(_),
|
||||
..
|
||||
} => {
|
||||
result_table.push(value);
|
||||
}
|
||||
_ => {
|
||||
are_all_rows = false;
|
||||
|
||||
let mut index_map = IndexMap::new();
|
||||
index_map.insert(
|
||||
match &column {
|
||||
Some(key) => key.item.clone(),
|
||||
None => "Column".into(),
|
||||
},
|
||||
value,
|
||||
);
|
||||
|
||||
result_table.push(UntaggedValue::row(index_map).into_value(Tag::unknown()));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if are_all_rows {
|
||||
let mut index_map = IndexMap::new();
|
||||
index_map.insert(
|
||||
match &column {
|
||||
Some(key) => key.item.clone(),
|
||||
None => "Column".into(),
|
||||
},
|
||||
UntaggedValue::table(&result_table).into_value(Tag::unknown()),
|
||||
);
|
||||
|
||||
let row = UntaggedValue::row(index_map).into_untagged_value();
|
||||
|
||||
yield ReturnSuccess::value(row);
|
||||
} else {
|
||||
for item in result_table
|
||||
.iter()
|
||||
.map(|row| ReturnSuccess::value(row.clone())) {
|
||||
|
||||
yield item;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
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<Vec<Value>, ShellError> {
|
||||
match sub_command.as_str() {
|
||||
"ps" => docker_ps(name),
|
||||
"images" => docker_images(name),
|
||||
_ => Err(ShellError::labeled_error(
|
||||
"Unsupported Docker command",
|
||||
"unknown docker command",
|
||||
name,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn process_docker_output(cmd_output: &str, tag: Tag) -> Result<Vec<Value>, 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_value());
|
||||
}
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
pub fn docker_images(tag: Tag) -> Result<Vec<Value>, 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<Vec<Value>, 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<Signature, ShellError> {
|
||||
Ok(Signature::build("docker")
|
||||
.required("sub_command", SyntaxShape::Member)
|
||||
.filter())
|
||||
}
|
||||
|
||||
fn begin_filter(&mut self, callinfo: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
if let Some(args) = callinfo.args.positional {
|
||||
match &args[0] {
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::String(command)),
|
||||
..
|
||||
} => match block_on(docker(&command, args[0].tag())) {
|
||||
Ok(v) => return Ok(v.into_iter().map(ReturnSuccess::value).collect()),
|
||||
Err(e) => return Err(e),
|
||||
},
|
||||
_ => return Err(ShellError::type_error("string", args[0].tagged_type_name())),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
fn filter(&mut self, _: Value) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
serve_plugin(&mut Docker::new());
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
#[macro_use]
|
||||
extern crate indexmap;
|
||||
|
||||
use nu::{serve_plugin, Plugin};
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
CallInfo, Primitive, ReturnSuccess, ReturnValue, Signature, SpannedTypeName, SyntaxShape,
|
||||
UntaggedValue, Value,
|
||||
};
|
||||
use nu_source::Tag;
|
||||
|
||||
struct Embed {
|
||||
field: Option<String>,
|
||||
are_all_rows: bool,
|
||||
values: Vec<Value>,
|
||||
}
|
||||
impl Embed {
|
||||
fn new() -> Embed {
|
||||
Embed {
|
||||
field: None,
|
||||
are_all_rows: true,
|
||||
values: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn embed(&mut self, value: Value) -> Result<(), ShellError> {
|
||||
match &value {
|
||||
Value {
|
||||
value: UntaggedValue::Row(_),
|
||||
..
|
||||
} => {
|
||||
self.values.push(value);
|
||||
}
|
||||
_ => {
|
||||
self.are_all_rows = false;
|
||||
|
||||
self.values.push(
|
||||
UntaggedValue::row(indexmap! {
|
||||
match &self.field {
|
||||
Some(key) => key.clone(),
|
||||
None => "Column".into()
|
||||
} => value
|
||||
})
|
||||
.into_value(Tag::unknown()),
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Plugin for Embed {
|
||||
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||
Ok(Signature::build("embed")
|
||||
.desc("Embeds a new field to the table.")
|
||||
.optional("field", SyntaxShape::String, "the name of the new column")
|
||||
.filter())
|
||||
}
|
||||
|
||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
if let Some(args) = call_info.args.positional {
|
||||
match &args[0] {
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::String(s)),
|
||||
..
|
||||
} => {
|
||||
self.field = Some(s.clone());
|
||||
self.values = Vec::new();
|
||||
}
|
||||
value => return Err(ShellError::type_error("string", value.spanned_type_name())),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
fn filter(&mut self, input: Value) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
self.embed(input)?;
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
fn end_filter(&mut self) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
if self.are_all_rows {
|
||||
let row = UntaggedValue::row(indexmap! {
|
||||
match &self.field {
|
||||
Some(key) => key.clone(),
|
||||
None => "Column".into(),
|
||||
} => UntaggedValue::table(&self.values).into_value(Tag::unknown()),
|
||||
})
|
||||
.into_untagged_value();
|
||||
|
||||
Ok(vec![ReturnSuccess::value(row)])
|
||||
} else {
|
||||
Ok(self
|
||||
.values
|
||||
.iter()
|
||||
.map(|row| ReturnSuccess::value(row.clone()))
|
||||
.collect::<Vec<_>>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
serve_plugin(&mut Embed::new());
|
||||
}
|
@ -729,7 +729,7 @@ fn can_get_reverse_first() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn embed_rows_into_a_row() {
|
||||
fn wrap_rows_into_a_row() {
|
||||
Playground::setup("embed_test_1", |dirs, sandbox| {
|
||||
sandbox.with_files(vec![FileWithContentToBeTrimmed(
|
||||
"los_tres_caballeros.txt",
|
||||
@ -746,7 +746,7 @@ fn embed_rows_into_a_row() {
|
||||
r#"
|
||||
open los_tres_caballeros.txt
|
||||
| from-csv
|
||||
| embed caballeros
|
||||
| wrap caballeros
|
||||
| get caballeros
|
||||
| nth 0
|
||||
| get last_name
|
||||
@ -759,7 +759,7 @@ fn embed_rows_into_a_row() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn embed_rows_into_a_table() {
|
||||
fn wrap_rows_into_a_table() {
|
||||
Playground::setup("embed_test_2", |dirs, sandbox| {
|
||||
sandbox.with_files(vec![FileWithContentToBeTrimmed(
|
||||
"los_tres_caballeros.txt",
|
||||
@ -777,7 +777,7 @@ fn embed_rows_into_a_table() {
|
||||
open los_tres_caballeros.txt
|
||||
| from-csv
|
||||
| get last_name
|
||||
| embed caballero
|
||||
| wrap caballero
|
||||
| nth 2
|
||||
| get caballero
|
||||
| echo $it
|
||||
|
Loading…
Reference in New Issue
Block a user