From d2eb6f6646195b6c95b09c9ed141a811709b5502 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 10 Oct 2019 21:23:12 +0200 Subject: [PATCH 01/20] Adds .envrc and shell.nix --- .envrc | 1 + shell.nix | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 .envrc create mode 100644 shell.nix diff --git a/.envrc b/.envrc new file mode 100644 index 000000000..65326bb6d --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use nix \ No newline at end of file diff --git a/shell.nix b/shell.nix new file mode 100644 index 000000000..e6062b2cb --- /dev/null +++ b/shell.nix @@ -0,0 +1,10 @@ +let + moz_overlay = import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz); + nixpkgs = import { overlays = [ moz_overlay ]; }; + nightly = ((nixpkgs.rustChannelOf { date = "2019-09-01"; channel = "nightly"; }).rust.override { extensions = [ "rust-src" "rls-preview" "clippy-preview" "rust-analysis" "rustfmt-preview" ];}); +in +with nixpkgs; +stdenv.mkDerivation { + name = "nushell-rust"; + buildInputs = [ nightly openssl_1_1 pkg-config ]; +} From f0ca0312f3ef0061033c888b56de2a64fa530365 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 11 Oct 2019 19:06:24 +0200 Subject: [PATCH 02/20] Adds racer, formats shell.nix --- shell.nix | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/shell.nix b/shell.nix index e6062b2cb..2b2bbca07 100644 --- a/shell.nix +++ b/shell.nix @@ -1,10 +1,25 @@ let - moz_overlay = import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz); + moz_overlay = import (builtins.fetchTarball + "https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz"); + nixpkgs = import { overlays = [ moz_overlay ]; }; - nightly = ((nixpkgs.rustChannelOf { date = "2019-09-01"; channel = "nightly"; }).rust.override { extensions = [ "rust-src" "rls-preview" "clippy-preview" "rust-analysis" "rustfmt-preview" ];}); -in -with nixpkgs; + + nightly = ((nixpkgs.rustChannelOf { + date = "2019-09-01"; + channel = "nightly"; + }).rust.override { + extensions = [ + "rust-src" + "rls-preview" + "clippy-preview" + "rust-analysis" + "rustfmt-preview" + ]; + }); + +in with nixpkgs; stdenv.mkDerivation { name = "nushell-rust"; - buildInputs = [ nightly openssl_1_1 pkg-config ]; + buildInputs = [ nightly openssl_1_1 pkg-config rustracer ]; + RUST_SRC_PATH = "${nightly}/lib/rustlib/src/rust/src"; } From af2ec609804d4890bd2c507941c7d273b92474dc Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 11 Oct 2019 21:13:00 +0200 Subject: [PATCH 03/20] Shell.nix cleanup. --- shell.nix | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/shell.nix b/shell.nix index 2b2bbca07..9e7cbe972 100644 --- a/shell.nix +++ b/shell.nix @@ -1,25 +1,32 @@ +{ pkgs ? import { + overlays = [ + (import (builtins.fetchTarball + "https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz")) + ]; +} }: +with pkgs; let - moz_overlay = import (builtins.fetchTarball - "https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz"); - nixpkgs = import { overlays = [ moz_overlay ]; }; - - nightly = ((nixpkgs.rustChannelOf { + nightly = ((pkgs.rustChannelOf { date = "2019-09-01"; channel = "nightly"; }).rust.override { extensions = [ - "rust-src" - "rls-preview" "clippy-preview" + "rls-preview" "rust-analysis" + "rust-src" "rustfmt-preview" ]; }); -in with nixpkgs; -stdenv.mkDerivation { + nu-deps = [ openssl_1_1 pkg-config x11 python3 ]; + + rust = [ nightly rustracer cargo-watch ]; + +in stdenv.mkDerivation { name = "nushell-rust"; - buildInputs = [ nightly openssl_1_1 pkg-config rustracer ]; + buildInputs = nu-deps ++ rust; RUST_SRC_PATH = "${nightly}/lib/rustlib/src/rust/src"; + SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt"; } From 5ec6bac7d99e7e2e3c4aa503f17efbc9e95608cf Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 11 Oct 2019 21:39:11 +0200 Subject: [PATCH 04/20] Removes redundant parens. --- shell.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell.nix b/shell.nix index 9e7cbe972..f5c61ac0a 100644 --- a/shell.nix +++ b/shell.nix @@ -7,7 +7,7 @@ with pkgs; let - nightly = ((pkgs.rustChannelOf { + nightly = (pkgs.rustChannelOf { date = "2019-09-01"; channel = "nightly"; }).rust.override { @@ -18,7 +18,7 @@ let "rust-src" "rustfmt-preview" ]; - }); + }; nu-deps = [ openssl_1_1 pkg-config x11 python3 ]; From 648d4865b18786ecfb1b31eefc5786632e9fe9bb Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Sun, 13 Oct 2019 21:15:30 +0200 Subject: [PATCH 05/20] Adds unimplemented module, tests. --- src/commands.rs | 2 ++ src/commands/from_ssv.rs | 43 ++++++++++++++++++++++++++++++ tests/filters_test.rs | 56 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 src/commands/from_ssv.rs diff --git a/src/commands.rs b/src/commands.rs index 72c07e38e..93729aef6 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -22,6 +22,7 @@ pub(crate) mod from_csv; pub(crate) mod from_ini; pub(crate) mod from_json; pub(crate) mod from_sqlite; +pub(crate) mod from_ssv; pub(crate) mod from_toml; pub(crate) mod from_tsv; pub(crate) mod from_url; @@ -91,6 +92,7 @@ pub(crate) use from_ini::FromINI; pub(crate) use from_json::FromJSON; pub(crate) use from_sqlite::FromDB; pub(crate) use from_sqlite::FromSQLite; +pub(crate) use from_ssv::FromSSV; pub(crate) use from_toml::FromTOML; pub(crate) use from_tsv::FromTSV; pub(crate) use from_url::FromURL; diff --git a/src/commands/from_ssv.rs b/src/commands/from_ssv.rs new file mode 100644 index 000000000..0da2b6f56 --- /dev/null +++ b/src/commands/from_ssv.rs @@ -0,0 +1,43 @@ +use crate::commands::WholeStreamCommand; +use crate::data::{Primitive, TaggedDictBuilder, Value}; +use crate::prelude::*; + +pub struct FromSSV; + +#[derive(Deserialize)] +pub struct FromSSVArgs { + headerless: bool, +} + +const STRING_REPRESENTATION: &str = "from-ssv"; + +impl WholeStreamCommand for FromSSV { + fn name(&self) -> &str { + STRING_REPRESENTATION + } + + fn signature(&self) -> Signature { + Signature::build(STRING_REPRESENTATION).switch("headerless") + } + + fn usage(&self) -> &str { + "Parse text as .ssv and create a table." + } + + fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + args.process(registry, from_ssv)?.run() + } +} + +fn from_ssv( + FromSSVArgs { + headerless: headerless, + }: FromSSVArgs, + RunnableContext { input, name, .. }: RunnableContext, +) -> Result { + unimplemented!() +} diff --git a/tests/filters_test.rs b/tests/filters_test.rs index f994fa449..70fd75296 100644 --- a/tests/filters_test.rs +++ b/tests/filters_test.rs @@ -355,6 +355,62 @@ fn converts_from_tsv_text_skipping_headers_to_structured_table() { }) } +#[test] +fn converts_from_ssv_text_to_structured_table() { + Playground::setup("filter_from_ssv_test_1", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "oc_get_svc.ssv", + r#" + NAME LABELS SELECTOR IP PORT(S) + docker-registry docker-registry=default docker-registry=default 172.30.78.158 5000/TCP + kubernetes component=apiserver,provider=kubernetes 172.30.0.2 443/TCP + kubernetes-ro component=apiserver,provider=kubernetes 172.30.0.1 80/TCP + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), h::pipeline( + r#" + open oc_get_svc.ssv + | from-ssv + | nth 0 + | get NAME + | echo $it + "# + )); + + assert_eq!(actual, "docker-registry"); + }) +} + +#[test] +fn converts_from_ssv_text_skipping_headers_to_structured_table() { + Playground::setup("filter_from_ssv_test_2", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "oc_get_svc.ssv", + r#" + NAME LABELS SELECTOR IP PORT(S) + docker-registry docker-registry=default docker-registry=default 172.30.78.158 5000/TCP + kubernetes component=apiserver,provider=kubernetes 172.30.0.2 443/TCP + kubernetes-ro component=apiserver,provider=kubernetes 172.30.0.1 80/TCP + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), h::pipeline( + r#" + open oc_get_svc.ssv + | from-ssv --headerless + | nth 2 + | get Column2 + | echo $it + "# + )); + + assert_eq!(actual, "component=apiserver,provider=kubernetes"); + }) +} + #[test] fn can_convert_table_to_bson_and_back_into_table() { let actual = nu!( From de1c4e6c8894915825d6bd67cc7ed85d26b25be6 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Sun, 13 Oct 2019 22:50:45 +0200 Subject: [PATCH 06/20] Implements from-ssv --- src/cli.rs | 1 + src/commands/from_ssv.rs | 88 ++++++++++++++++++++++++++++++++++++++-- tests/filters_test.rs | 12 +++--- 3 files changed, 91 insertions(+), 10 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 38e2474fa..5bfd7ff68 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -272,6 +272,7 @@ pub async fn cli() -> Result<(), Box> { whole_stream_command(Env), whole_stream_command(FromCSV), whole_stream_command(FromTSV), + whole_stream_command(FromSSV), whole_stream_command(FromINI), whole_stream_command(FromBSON), whole_stream_command(FromJSON), diff --git a/src/commands/from_ssv.rs b/src/commands/from_ssv.rs index 0da2b6f56..59ba2f2f8 100644 --- a/src/commands/from_ssv.rs +++ b/src/commands/from_ssv.rs @@ -33,11 +33,91 @@ impl WholeStreamCommand for FromSSV { } } +fn from_ssv_string_to_value( + s: &str, + headerless: bool, + tag: impl Into, +) -> Result, &str> { + let mut lines = s.lines(); + let tag = tag.into(); + + let headers = lines + .next() + .expect("No content.") + .split_whitespace() + .map(|s| s.to_owned()) + .collect::>(); + + let header_row = if headerless { + (0..headers.len()) + .map(|i| format!("Column{}", i + 1)) + .collect::>() + } else { + headers + }; + + let rows = lines + .map(|l| { + let mut row = TaggedDictBuilder::new(tag); + for (column, value) in header_row.iter().zip(l.split_whitespace()) { + row.insert_tagged( + column.to_owned(), + Value::Primitive(Primitive::String(String::from(value))).tagged(tag), + ) + } + row.into_tagged_value() + }) + .collect(); + + Ok(Tagged::from_item(Value::Table(rows), tag)) +} + fn from_ssv( - FromSSVArgs { - headerless: headerless, - }: FromSSVArgs, + FromSSVArgs { headerless }: FromSSVArgs, RunnableContext { input, name, .. }: RunnableContext, ) -> Result { - unimplemented!() + let stream = async_stream! { + let values: Vec> = input.values.collect().await; + let mut concat_string = String::new(); + let mut latest_tag: Option = None; + + for value in values { + let value_tag = value.tag(); + latest_tag = Some(value_tag); + match value.item { + Value::Primitive(Primitive::String(s)) => { + concat_string.push_str(&s); + concat_string.push_str("\n"); + + } + _ => yield Err(ShellError::labeled_error_with_secondary ( + "Expected a string from pipeline", + "requires string input", + name, + "value originates from here", + value_tag + )), + } + } + + match from_ssv_string_to_value(&concat_string, headerless, name) { + Ok(x) => match x { + Tagged { item: Value::Table(list), ..} => { + for l in list { yield ReturnSuccess::value(l) } + } + x => yield ReturnSuccess::value(x) + }, + Err(_) => if let Some(last_tag) = latest_tag { + yield Err(ShellError::labeled_error_with_secondary( + "Could not parse as SSV", + "input cannot be parsed ssv", + name, + "value originates from here", + last_tag, + )) + } + } + }; + + Ok(stream.to_output_stream()) } diff --git a/tests/filters_test.rs b/tests/filters_test.rs index 70fd75296..ed841af4c 100644 --- a/tests/filters_test.rs +++ b/tests/filters_test.rs @@ -359,7 +359,7 @@ fn converts_from_tsv_text_skipping_headers_to_structured_table() { fn converts_from_ssv_text_to_structured_table() { Playground::setup("filter_from_ssv_test_1", |dirs, sandbox| { sandbox.with_files(vec![FileWithContentToBeTrimmed( - "oc_get_svc.ssv", + "oc_get_svc.txt", r#" NAME LABELS SELECTOR IP PORT(S) docker-registry docker-registry=default docker-registry=default 172.30.78.158 5000/TCP @@ -371,15 +371,15 @@ fn converts_from_ssv_text_to_structured_table() { let actual = nu!( cwd: dirs.test(), h::pipeline( r#" - open oc_get_svc.ssv + open oc_get_svc.txt | from-ssv | nth 0 - | get NAME + | get IP | echo $it "# )); - assert_eq!(actual, "docker-registry"); + assert_eq!(actual, "172.30.78.158"); }) } @@ -387,7 +387,7 @@ fn converts_from_ssv_text_to_structured_table() { fn converts_from_ssv_text_skipping_headers_to_structured_table() { Playground::setup("filter_from_ssv_test_2", |dirs, sandbox| { sandbox.with_files(vec![FileWithContentToBeTrimmed( - "oc_get_svc.ssv", + "oc_get_svc.txt", r#" NAME LABELS SELECTOR IP PORT(S) docker-registry docker-registry=default docker-registry=default 172.30.78.158 5000/TCP @@ -399,7 +399,7 @@ fn converts_from_ssv_text_skipping_headers_to_structured_table() { let actual = nu!( cwd: dirs.test(), h::pipeline( r#" - open oc_get_svc.ssv + open oc_get_svc.txt | from-ssv --headerless | nth 2 | get Column2 From 8422d40e2c36edc31bf42f8d38b8305abdfbe19c Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Sun, 13 Oct 2019 23:09:10 +0200 Subject: [PATCH 07/20] Add from-ssv to readme. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7df2c92ec..45867f1da 100644 --- a/README.md +++ b/README.md @@ -284,6 +284,7 @@ Nu adheres closely to a set of goals that make up its design philosophy. As feat | from-ini | Parse text as .ini and create table | | from-json | Parse text as .json and create table | | from-sqlite | Parse binary data as sqlite .db and create table | +| from-ssv | Parse text as whitespace-separated values and create table| | from-toml | Parse text as .toml and create table | | from-tsv | Parse text as .tsv and create table | | from-url | Parse urlencoded string and create a table | From 38b5979881ed974824f4c94e07403d089ea8b424 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Sun, 13 Oct 2019 23:09:24 +0200 Subject: [PATCH 08/20] Make usage string clearer. --- src/commands/from_ssv.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/from_ssv.rs b/src/commands/from_ssv.rs index 59ba2f2f8..ede06da2d 100644 --- a/src/commands/from_ssv.rs +++ b/src/commands/from_ssv.rs @@ -21,7 +21,7 @@ impl WholeStreamCommand for FromSSV { } fn usage(&self) -> &str { - "Parse text as .ssv and create a table." + "Parse text as whitespace-separated values and create a table." } fn run( From 20e891db6e59c02e00ae5f0fbfa61c7f843a4295 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Sun, 13 Oct 2019 23:09:40 +0200 Subject: [PATCH 09/20] Move variable assignment to clarify use. --- src/commands/from_ssv.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/from_ssv.rs b/src/commands/from_ssv.rs index ede06da2d..2f3f574fb 100644 --- a/src/commands/from_ssv.rs +++ b/src/commands/from_ssv.rs @@ -39,7 +39,6 @@ fn from_ssv_string_to_value( tag: impl Into, ) -> Result, &str> { let mut lines = s.lines(); - let tag = tag.into(); let headers = lines .next() @@ -56,6 +55,7 @@ fn from_ssv_string_to_value( headers }; + let tag = tag.into(); let rows = lines .map(|l| { let mut row = TaggedDictBuilder::new(tag); From 63039666b0aa36f40b15b8bdd740154e7bdf6d51 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 14 Oct 2019 07:37:34 +0200 Subject: [PATCH 10/20] Changes from_ssv_to_string_value to return an Option. --- src/commands/from_ssv.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/commands/from_ssv.rs b/src/commands/from_ssv.rs index 2f3f574fb..3232fd1e3 100644 --- a/src/commands/from_ssv.rs +++ b/src/commands/from_ssv.rs @@ -37,12 +37,11 @@ fn from_ssv_string_to_value( s: &str, headerless: bool, tag: impl Into, -) -> Result, &str> { +) -> Option> { let mut lines = s.lines(); let headers = lines - .next() - .expect("No content.") + .next()? .split_whitespace() .map(|s| s.to_owned()) .collect::>(); @@ -69,7 +68,7 @@ fn from_ssv_string_to_value( }) .collect(); - Ok(Tagged::from_item(Value::Table(rows), tag)) + Some(Tagged::from_item(Value::Table(rows), tag)) } fn from_ssv( @@ -101,13 +100,13 @@ fn from_ssv( } match from_ssv_string_to_value(&concat_string, headerless, name) { - Ok(x) => match x { + Some(x) => match x { Tagged { item: Value::Table(list), ..} => { for l in list { yield ReturnSuccess::value(l) } } x => yield ReturnSuccess::value(x) }, - Err(_) => if let Some(last_tag) = latest_tag { + None => if let Some(last_tag) = latest_tag { yield Err(ShellError::labeled_error_with_secondary( "Could not parse as SSV", "input cannot be parsed ssv", @@ -115,7 +114,7 @@ fn from_ssv( "value originates from here", last_tag, )) - } + }, } }; From 38225d0dbadd2e8af530085e0a137d98fbf1d37e Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 14 Oct 2019 07:48:10 +0200 Subject: [PATCH 11/20] Removes extra newline --- src/commands/from_ssv.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/commands/from_ssv.rs b/src/commands/from_ssv.rs index 3232fd1e3..a47a8662f 100644 --- a/src/commands/from_ssv.rs +++ b/src/commands/from_ssv.rs @@ -86,8 +86,6 @@ fn from_ssv( match value.item { Value::Primitive(Primitive::String(s)) => { concat_string.push_str(&s); - concat_string.push_str("\n"); - } _ => yield Err(ShellError::labeled_error_with_secondary ( "Expected a string from pipeline", From 0b210ce5bf55b91ce88a8706724deeb844953634 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 14 Oct 2019 07:48:19 +0200 Subject: [PATCH 12/20] Filters out empty lines before table creation. --- src/commands/from_ssv.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/from_ssv.rs b/src/commands/from_ssv.rs index a47a8662f..41a611f8c 100644 --- a/src/commands/from_ssv.rs +++ b/src/commands/from_ssv.rs @@ -38,7 +38,7 @@ fn from_ssv_string_to_value( headerless: bool, tag: impl Into, ) -> Option> { - let mut lines = s.lines(); + let mut lines = s.lines().filter(|l| !l.is_empty()); let headers = lines .next()? From a9293f62a8fd9565a67e5b01ada5d120bf5ff37e Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 14 Oct 2019 09:43:54 +0200 Subject: [PATCH 13/20] Adds some initial ideas for refactoring. --- src/commands/from_ssv.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/commands/from_ssv.rs b/src/commands/from_ssv.rs index 41a611f8c..354d2cb2d 100644 --- a/src/commands/from_ssv.rs +++ b/src/commands/from_ssv.rs @@ -33,6 +33,27 @@ impl WholeStreamCommand for FromSSV { } } +fn string_to_table(s: &str, headerless: bool) -> std::iter::Map> { + let mut lines = s.lines().filter(|l| !l.trim().is_empty()); + + let headers = lines + .next() + .unwrap() + .split_whitespace() + .map(|s| s.to_owned()) + .collect::>(); + + let header_row = if headerless { + (0..headers.len()) + .map(|i| format!("Column{}", i + 1)) + .collect::>() + } else { + headers + }; + + lines.map(|l| header_row.iter().zip(l.split_whitespace())) +} + fn from_ssv_string_to_value( s: &str, headerless: bool, @@ -118,3 +139,22 @@ fn from_ssv( Ok(stream.to_output_stream()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_trims_empty_and_whitespace_only_lines() { + let input = r#" + + a b + + 1 2 + + 3 4 + "#; + + let +} +} \ No newline at end of file From 104b7824f58631d8dcfef96493827d9375ea7937 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 14 Oct 2019 16:34:06 +0200 Subject: [PATCH 14/20] Updates return types. --- src/commands/from_ssv.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/from_ssv.rs b/src/commands/from_ssv.rs index 354d2cb2d..5f88147af 100644 --- a/src/commands/from_ssv.rs +++ b/src/commands/from_ssv.rs @@ -33,7 +33,7 @@ impl WholeStreamCommand for FromSSV { } } -fn string_to_table(s: &str, headerless: bool) -> std::iter::Map> { +fn string_to_table(s: &str, headerless: bool) -> Vec> { let mut lines = s.lines().filter(|l| !l.trim().is_empty()); let headers = lines @@ -51,7 +51,7 @@ fn string_to_table(s: &str, headerless: bool) -> std::iter::Map Date: Mon, 14 Oct 2019 22:00:25 +0200 Subject: [PATCH 15/20] Adds conversion test for leading whitespace. Refactors string parsing into a separate function. --- src/commands/from_ssv.rs | 81 +++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/src/commands/from_ssv.rs b/src/commands/from_ssv.rs index 5f88147af..56a3f1086 100644 --- a/src/commands/from_ssv.rs +++ b/src/commands/from_ssv.rs @@ -44,14 +44,22 @@ fn string_to_table(s: &str, headerless: bool) -> Vec> { .collect::>(); let header_row = if headerless { - (0..headers.len()) - .map(|i| format!("Column{}", i + 1)) + (1..=headers.len()) + .map(|i| format!("Column{}", i)) .collect::>() } else { headers }; - lines.map(|l| header_row.iter().zip(l.split_whitespace())).collect() + lines + .map(|l| { + header_row + .iter() + .zip(l.split_whitespace()) + .map(|(a, b)| (String::from(a), String::from(b))) + .collect() + }) + .collect() } fn from_ssv_string_to_value( @@ -59,33 +67,18 @@ fn from_ssv_string_to_value( headerless: bool, tag: impl Into, ) -> Option> { - let mut lines = s.lines().filter(|l| !l.is_empty()); - - let headers = lines - .next()? - .split_whitespace() - .map(|s| s.to_owned()) - .collect::>(); - - let header_row = if headerless { - (0..headers.len()) - .map(|i| format!("Column{}", i + 1)) - .collect::>() - } else { - headers - }; - let tag = tag.into(); - let rows = lines - .map(|l| { - let mut row = TaggedDictBuilder::new(tag); - for (column, value) in header_row.iter().zip(l.split_whitespace()) { - row.insert_tagged( - column.to_owned(), - Value::Primitive(Primitive::String(String::from(value))).tagged(tag), + let rows = string_to_table(s, headerless) + .iter() + .map(|row| { + let mut tagged_dict = TaggedDictBuilder::new(tag); + for (col, entry) in row { + tagged_dict.insert_tagged( + col, + Value::Primitive(Primitive::String(String::from(entry))).tagged(tag), ) } - row.into_tagged_value() + tagged_dict.into_tagged_value() }) .collect(); @@ -143,18 +136,44 @@ fn from_ssv( #[cfg(test)] mod tests { use super::*; + fn owned(x: &str, y: &str) -> (String, String) { + (String::from(x), String::from(y)) + } #[test] fn it_trims_empty_and_whitespace_only_lines() { let input = r#" - a b + a b - 1 2 + 1 2 3 4 "#; + let result = string_to_table(input, false); + assert_eq!( + result, + vec![ + vec![owned("a", "1"), owned("b", "2")], + vec![owned("a", "3"), owned("b", "4")] + ] + ); + } - let + #[test] + fn it_ignores_headers_when_headerless() { + let input = r#" + a b + 1 2 + 3 4 + "#; + let result = string_to_table(input, true); + assert_eq!( + result, + vec![ + vec![owned("Column1", "1"), owned("Column2", "2")], + vec![owned("Column1", "3"), owned("Column2", "4")] + ] + ); + } } -} \ No newline at end of file From 43ead45db6755cfdcc2e65dc367c7de2ba6f611c Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 14 Oct 2019 22:03:17 +0200 Subject: [PATCH 16/20] Removes rust_src_path and ssl_cert_file vars. --- shell.nix | 2 -- 1 file changed, 2 deletions(-) diff --git a/shell.nix b/shell.nix index f5c61ac0a..d528cf849 100644 --- a/shell.nix +++ b/shell.nix @@ -27,6 +27,4 @@ let in stdenv.mkDerivation { name = "nushell-rust"; buildInputs = nu-deps ++ rust; - RUST_SRC_PATH = "${nightly}/lib/rustlib/src/rust/src"; - SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt"; } From b2c53a09672f86f6f6e35001f05a4aa6f8fd8a1e Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 14 Oct 2019 23:14:45 +0200 Subject: [PATCH 17/20] Updates commands to work after tag is no longer copy. --- src/commands/from_ssv.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/commands/from_ssv.rs b/src/commands/from_ssv.rs index 56a3f1086..782fb531f 100644 --- a/src/commands/from_ssv.rs +++ b/src/commands/from_ssv.rs @@ -71,18 +71,18 @@ fn from_ssv_string_to_value( let rows = string_to_table(s, headerless) .iter() .map(|row| { - let mut tagged_dict = TaggedDictBuilder::new(tag); + let mut tagged_dict = TaggedDictBuilder::new(&tag); for (col, entry) in row { tagged_dict.insert_tagged( col, - Value::Primitive(Primitive::String(String::from(entry))).tagged(tag), + Value::Primitive(Primitive::String(String::from(entry))).tagged(&tag), ) } tagged_dict.into_tagged_value() }) .collect(); - Some(Tagged::from_item(Value::Table(rows), tag)) + Some(Value::Table(rows).tagged(&tag)) } fn from_ssv( @@ -96,7 +96,7 @@ fn from_ssv( for value in values { let value_tag = value.tag(); - latest_tag = Some(value_tag); + latest_tag = Some(value_tag.clone()); match value.item { Value::Primitive(Primitive::String(s)) => { concat_string.push_str(&s); @@ -104,27 +104,27 @@ fn from_ssv( _ => yield Err(ShellError::labeled_error_with_secondary ( "Expected a string from pipeline", "requires string input", - name, + &name, "value originates from here", - value_tag + &value_tag )), } } - match from_ssv_string_to_value(&concat_string, headerless, name) { + match from_ssv_string_to_value(&concat_string, headerless, name.clone()) { Some(x) => match x { Tagged { item: Value::Table(list), ..} => { for l in list { yield ReturnSuccess::value(l) } } x => yield ReturnSuccess::value(x) }, - None => if let Some(last_tag) = latest_tag { + None => if let Some(tag) = latest_tag { yield Err(ShellError::labeled_error_with_secondary( "Could not parse as SSV", "input cannot be parsed ssv", - name, + &name, "value originates from here", - last_tag, + &tag, )) }, } From de12393eaf497286288d95c23431104fbc87fa16 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 14 Oct 2019 23:25:52 +0200 Subject: [PATCH 18/20] Updates shell.nix. --- shell.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shell.nix b/shell.nix index d528cf849..4e287ab11 100644 --- a/shell.nix +++ b/shell.nix @@ -8,7 +8,7 @@ with pkgs; let nightly = (pkgs.rustChannelOf { - date = "2019-09-01"; + date = "2019-10-14"; channel = "nightly"; }).rust.override { extensions = [ @@ -27,4 +27,5 @@ let in stdenv.mkDerivation { name = "nushell-rust"; buildInputs = nu-deps ++ rust; + SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt"; } From d21389d549109324a4487d59a2b9d114df38d326 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 15 Oct 2019 00:24:32 +0200 Subject: [PATCH 19/20] Removes unwrap. A rogue unwrap had been left in the code, but has now been replaced by an option. --- src/commands/from_ssv.rs | 42 ++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/src/commands/from_ssv.rs b/src/commands/from_ssv.rs index 782fb531f..1be9b4567 100644 --- a/src/commands/from_ssv.rs +++ b/src/commands/from_ssv.rs @@ -33,12 +33,11 @@ impl WholeStreamCommand for FromSSV { } } -fn string_to_table(s: &str, headerless: bool) -> Vec> { +fn string_to_table(s: &str, headerless: bool) -> Option>> { let mut lines = s.lines().filter(|l| !l.trim().is_empty()); let headers = lines - .next() - .unwrap() + .next()? .split_whitespace() .map(|s| s.to_owned()) .collect::>(); @@ -51,15 +50,17 @@ fn string_to_table(s: &str, headerless: bool) -> Vec> { headers }; - lines - .map(|l| { - header_row - .iter() - .zip(l.split_whitespace()) - .map(|(a, b)| (String::from(a), String::from(b))) - .collect() - }) - .collect() + Some( + lines + .map(|l| { + header_row + .iter() + .zip(l.split_whitespace()) + .map(|(a, b)| (String::from(a), String::from(b))) + .collect() + }) + .collect(), + ) } fn from_ssv_string_to_value( @@ -68,7 +69,7 @@ fn from_ssv_string_to_value( tag: impl Into, ) -> Option> { let tag = tag.into(); - let rows = string_to_table(s, headerless) + let rows = string_to_table(s, headerless)? .iter() .map(|row| { let mut tagged_dict = TaggedDictBuilder::new(&tag); @@ -153,10 +154,10 @@ mod tests { let result = string_to_table(input, false); assert_eq!( result, - vec![ + Some(vec![ vec![owned("a", "1"), owned("b", "2")], vec![owned("a", "3"), owned("b", "4")] - ] + ]) ); } @@ -170,10 +171,17 @@ mod tests { let result = string_to_table(input, true); assert_eq!( result, - vec![ + Some(vec![ vec![owned("Column1", "1"), owned("Column2", "2")], vec![owned("Column1", "3"), owned("Column2", "4")] - ] + ]) ); } + + #[test] + fn it_returns_none_given_an_empty_string() { + let input = ""; + let result = string_to_table(input, true); + assert_eq!(result, None); + } } From 65008bb912076f288d0c0dbf8ba0ae9f3641d374 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 14 Oct 2019 23:46:19 +0200 Subject: [PATCH 20/20] Deletes nix-specific configuration. --- .envrc | 1 - shell.nix | 31 ------------------------------- 2 files changed, 32 deletions(-) delete mode 100644 .envrc delete mode 100644 shell.nix diff --git a/.envrc b/.envrc deleted file mode 100644 index 65326bb6d..000000000 --- a/.envrc +++ /dev/null @@ -1 +0,0 @@ -use nix \ No newline at end of file diff --git a/shell.nix b/shell.nix deleted file mode 100644 index 4e287ab11..000000000 --- a/shell.nix +++ /dev/null @@ -1,31 +0,0 @@ -{ pkgs ? import { - overlays = [ - (import (builtins.fetchTarball - "https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz")) - ]; -} }: -with pkgs; -let - - nightly = (pkgs.rustChannelOf { - date = "2019-10-14"; - channel = "nightly"; - }).rust.override { - extensions = [ - "clippy-preview" - "rls-preview" - "rust-analysis" - "rust-src" - "rustfmt-preview" - ]; - }; - - nu-deps = [ openssl_1_1 pkg-config x11 python3 ]; - - rust = [ nightly rustracer cargo-watch ]; - -in stdenv.mkDerivation { - name = "nushell-rust"; - buildInputs = nu-deps ++ rust; - SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt"; -}