mirror of
https://github.com/nushell/nushell.git
synced 2024-11-22 00:13:21 +01:00
Add wasm support (#2199)
* Working towards a PoC for wasm * Move bson and sqlite to plugins * proof of concept now working * tests are green * Add CI test for --no-default-features * Fix some tests * Fix clippy and windows build * More fixes * Fix the windows build * Fix the windows test
This commit is contained in:
parent
dbe0effd67
commit
d8594a62c2
@ -6,6 +6,9 @@ strategy:
|
||||
linux-stable:
|
||||
image: ubuntu-18.04
|
||||
style: 'unflagged'
|
||||
linux-minimal:
|
||||
image: ubuntu-18.04
|
||||
style: 'minimal'
|
||||
macos-stable:
|
||||
image: macos-10.14
|
||||
style: 'unflagged'
|
||||
@ -58,6 +61,9 @@ steps:
|
||||
- bash: NUSHELL_ENABLE_ALL_FLAGS=1 RUSTFLAGS="-D warnings" cargo clippy --all --features=stable -- -D clippy::result_unwrap_used -D clippy::option_unwrap_used
|
||||
condition: eq(variables['style'], 'canary')
|
||||
displayName: Check clippy lints
|
||||
- bash: RUSTFLAGS="-D warnings" cargo test --all --no-default-features
|
||||
condition: eq(variables['style'], 'minimal')
|
||||
displayName: Run tests
|
||||
- bash: cargo fmt --all -- --check
|
||||
condition: eq(variables['style'], 'fmt')
|
||||
displayName: Lint
|
||||
|
66
Cargo.lock
generated
66
Cargo.lock
generated
@ -2464,6 +2464,8 @@ dependencies = [
|
||||
"nu-value-ext",
|
||||
"nu_plugin_binaryview",
|
||||
"nu_plugin_fetch",
|
||||
"nu_plugin_from_bson",
|
||||
"nu_plugin_from_sqlite",
|
||||
"nu_plugin_inc",
|
||||
"nu_plugin_match",
|
||||
"nu_plugin_post",
|
||||
@ -2471,6 +2473,8 @@ dependencies = [
|
||||
"nu_plugin_start",
|
||||
"nu_plugin_sys",
|
||||
"nu_plugin_textview",
|
||||
"nu_plugin_to_bson",
|
||||
"nu_plugin_to_sqlite",
|
||||
"nu_plugin_tree",
|
||||
"pretty_env_logger",
|
||||
"semver 0.10.0",
|
||||
@ -2501,7 +2505,6 @@ dependencies = [
|
||||
"async-trait",
|
||||
"base64 0.12.3",
|
||||
"bigdecimal",
|
||||
"bson",
|
||||
"byte-unit",
|
||||
"bytes 0.5.5",
|
||||
"calamine",
|
||||
@ -2752,6 +2755,37 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu_plugin_from_bson"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"bigdecimal",
|
||||
"bson",
|
||||
"nu-build",
|
||||
"nu-errors",
|
||||
"nu-plugin",
|
||||
"nu-protocol",
|
||||
"nu-source",
|
||||
"nu-value-ext",
|
||||
"num-traits 0.2.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu_plugin_from_sqlite"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"bigdecimal",
|
||||
"nu-build",
|
||||
"nu-errors",
|
||||
"nu-plugin",
|
||||
"nu-protocol",
|
||||
"nu-source",
|
||||
"nu-value-ext",
|
||||
"num-traits 0.2.12",
|
||||
"rusqlite",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu_plugin_inc"
|
||||
version = "0.16.1"
|
||||
@ -2857,6 +2891,36 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu_plugin_to_bson"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"bson",
|
||||
"nu-build",
|
||||
"nu-errors",
|
||||
"nu-plugin",
|
||||
"nu-protocol",
|
||||
"nu-source",
|
||||
"nu-value-ext",
|
||||
"num-traits 0.2.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu_plugin_to_sqlite"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"hex 0.4.2",
|
||||
"nu-build",
|
||||
"nu-errors",
|
||||
"nu-plugin",
|
||||
"nu-protocol",
|
||||
"nu-source",
|
||||
"nu-value-ext",
|
||||
"num-traits 0.2.12",
|
||||
"rusqlite",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu_plugin_tree"
|
||||
version = "0.16.1"
|
||||
|
31
Cargo.toml
31
Cargo.toml
@ -27,6 +27,8 @@ nu-source = {version = "0.16.1", path = "./crates/nu-source"}
|
||||
nu-value-ext = {version = "0.16.1", path = "./crates/nu-value-ext"}
|
||||
nu_plugin_binaryview = {version = "0.16.1", path = "./crates/nu_plugin_binaryview", optional = true}
|
||||
nu_plugin_fetch = {version = "0.16.1", path = "./crates/nu_plugin_fetch", optional = true}
|
||||
nu_plugin_from_bson = {version = "0.16.1", path = "./crates/nu_plugin_from_bson", optional = true}
|
||||
nu_plugin_from_sqlite = {version = "0.16.1", path = "./crates/nu_plugin_from_sqlite", optional = true}
|
||||
nu_plugin_inc = {version = "0.16.1", path = "./crates/nu_plugin_inc", optional = true}
|
||||
nu_plugin_match = {version = "0.16.1", path = "./crates/nu_plugin_match", optional = true}
|
||||
nu_plugin_post = {version = "0.16.1", path = "./crates/nu_plugin_post", optional = true}
|
||||
@ -34,6 +36,8 @@ nu_plugin_ps = {version = "0.16.1", path = "./crates/nu_plugin_ps", optional = t
|
||||
nu_plugin_start = {version = "0.16.1", path = "./crates/nu_plugin_start", optional = true}
|
||||
nu_plugin_sys = {version = "0.16.1", path = "./crates/nu_plugin_sys", optional = true}
|
||||
nu_plugin_textview = {version = "0.16.1", path = "./crates/nu_plugin_textview", optional = true}
|
||||
nu_plugin_to_bson = {version = "0.16.1", path = "./crates/nu_plugin_to_bson", optional = true}
|
||||
nu_plugin_to_sqlite = {version = "0.16.1", path = "./crates/nu_plugin_to_sqlite", optional = true}
|
||||
nu_plugin_tree = {version = "0.16.1", path = "./crates/nu_plugin_tree", optional = true}
|
||||
|
||||
crossterm = {version = "0.17.5", optional = true}
|
||||
@ -58,8 +62,20 @@ serde = {version = "1.0.110", features = ["derive"]}
|
||||
toml = "0.5.6"
|
||||
|
||||
[features]
|
||||
default = ["sys", "ps", "textview", "inc"]
|
||||
stable = ["default", "binaryview", "match", "tree", "post", "fetch", "clipboard-cli", "trash-support", "start"]
|
||||
default = [
|
||||
"sys",
|
||||
"ps",
|
||||
"textview",
|
||||
"inc",
|
||||
"git-support",
|
||||
"directories-support",
|
||||
"ctrlc-support",
|
||||
"which-support",
|
||||
"ptree-support",
|
||||
"term-support",
|
||||
"uuid-support",
|
||||
]
|
||||
stable = ["default", "binaryview", "match", "tree", "post", "fetch", "clipboard-cli", "trash-support", "start", "starship-prompt", "bson", "sqlite"]
|
||||
|
||||
# Default
|
||||
inc = ["semver", "nu_plugin_inc"]
|
||||
@ -69,16 +85,25 @@ textview = ["crossterm", "syntect", "url", "nu_plugin_textview"]
|
||||
|
||||
# Stable
|
||||
binaryview = ["nu_plugin_binaryview"]
|
||||
bson = ["nu_plugin_from_bson", "nu_plugin_to_bson"]
|
||||
fetch = ["nu_plugin_fetch"]
|
||||
match = ["nu_plugin_match"]
|
||||
post = ["nu_plugin_post"]
|
||||
sqlite = ["nu_plugin_from_sqlite", "nu_plugin_to_sqlite"]
|
||||
start = ["nu_plugin_start"]
|
||||
trace = ["nu-parser/trace"]
|
||||
tree = ["nu_plugin_tree"]
|
||||
|
||||
clipboard-cli = ["nu-cli/clipboard-cli"]
|
||||
# starship-prompt = ["nu-cli/starship-prompt"]
|
||||
ctrlc-support = ["nu-cli/ctrlc"]
|
||||
directories-support = ["nu-cli/directories", "nu-cli/dirs"]
|
||||
git-support = ["nu-cli/git2"]
|
||||
ptree-support = ["nu-cli/ptree"]
|
||||
starship-prompt = ["nu-cli/starship-prompt"]
|
||||
term-support = ["nu-cli/term"]
|
||||
trash-support = ["nu-cli/trash-support"]
|
||||
uuid-support = ["nu-cli/uuid_crate"]
|
||||
which-support = ["nu-cli/ichwh", "nu-cli/which"]
|
||||
|
||||
# Core plugins that ship with `cargo install nu` by default
|
||||
# Currently, Cargo limits us to installing only one binary
|
||||
|
@ -25,7 +25,6 @@ async-recursion = "0.3.1"
|
||||
async-trait = "0.1.36"
|
||||
base64 = "0.12.3"
|
||||
bigdecimal = {version = "0.1.2", features = ["serde"]}
|
||||
bson = {version = "0.14.1", features = ["decimal128"]}
|
||||
byte-unit = "3.1.3"
|
||||
bytes = "0.5.5"
|
||||
calamine = "0.16"
|
||||
@ -33,10 +32,10 @@ chrono = {version = "0.4.11", features = ["serde"]}
|
||||
clap = "2.33.1"
|
||||
codespan-reporting = "0.9.5"
|
||||
csv = "1.1"
|
||||
ctrlc = "3.1.4"
|
||||
ctrlc = {version = "3.1.4", optional = true}
|
||||
derive-new = "0.5.8"
|
||||
directories = "2.0.2"
|
||||
dirs = "2.0.2"
|
||||
directories = {version = "2.0.2", optional = true}
|
||||
dirs = {version = "2.0.2", optional = true}
|
||||
dunce = "1.0.1"
|
||||
eml-parser = "0.1.0"
|
||||
filesize = "0.2.0"
|
||||
@ -44,12 +43,12 @@ futures = {version = "0.3", features = ["compat", "io-compat"]}
|
||||
futures-util = "0.3.5"
|
||||
futures_codec = "0.4"
|
||||
getset = "0.1.1"
|
||||
git2 = {version = "0.13.6", default_features = false}
|
||||
git2 = {version = "0.13.6", default_features = false, optional = true}
|
||||
glob = "0.3.0"
|
||||
hex = "0.4"
|
||||
htmlescape = "0.3.1"
|
||||
ical = "0.6.*"
|
||||
ichwh = "0.3.4"
|
||||
ichwh = {version = "0.3.4", optional = true}
|
||||
indexmap = {version = "1.4.0", features = ["serde-1"]}
|
||||
itertools = "0.9.0"
|
||||
log = "0.4.8"
|
||||
@ -62,7 +61,7 @@ parking_lot = "0.11.0"
|
||||
pin-utils = "0.1.0"
|
||||
pretty-hex = "0.1.1"
|
||||
pretty_env_logger = "0.4.0"
|
||||
ptree = {version = "0.2"}
|
||||
ptree = {version = "0.2", optional = true}
|
||||
query_interface = "0.3.5"
|
||||
rand = "0.7"
|
||||
regex = "1"
|
||||
@ -79,20 +78,20 @@ sha2 = "0.9.1"
|
||||
shellexpand = "2.0.0"
|
||||
strip-ansi-escapes = "0.1.0"
|
||||
tempfile = "3.1.0"
|
||||
term = "0.5.2"
|
||||
term = {version = "0.5.2", optional = true}
|
||||
term_size = "0.3.2"
|
||||
termcolor = "1.1.0"
|
||||
toml = "0.5.6"
|
||||
typetag = "0.1.5"
|
||||
umask = "1.0.0"
|
||||
unicode-xid = "0.2.1"
|
||||
uuid_crate = {package = "uuid", version = "0.8.1", features = ["v4"]}
|
||||
which = "4.0.1"
|
||||
uuid_crate = {package = "uuid", version = "0.8.1", features = ["v4"], optional = true}
|
||||
which = {version = "4.0.1", optional = true}
|
||||
|
||||
clipboard = {version = "0.5", optional = true}
|
||||
encoding_rs = "0.8.23"
|
||||
rayon = "1.3.1"
|
||||
starship = "0.43.0"
|
||||
starship = {version = "0.43.0", optional = true}
|
||||
trash = {version = "1.0.1", optional = true}
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
@ -106,6 +105,7 @@ users = "0.10.0"
|
||||
|
||||
[dependencies.rusqlite]
|
||||
features = ["bundled", "blob"]
|
||||
optional = true
|
||||
version = "0.23.1"
|
||||
|
||||
[build-dependencies]
|
||||
@ -116,7 +116,7 @@ quickcheck = "0.9"
|
||||
quickcheck_macros = "0.9"
|
||||
|
||||
[features]
|
||||
stable = []
|
||||
# starship-prompt = ["starship"]
|
||||
clipboard-cli = ["clipboard"]
|
||||
stable = []
|
||||
starship-prompt = ["starship"]
|
||||
trash-support = ["trash"]
|
||||
|
@ -12,6 +12,8 @@ use futures_codec::FramedRead;
|
||||
use nu_errors::{ProximateShellError, ShellDiagnostic, ShellError};
|
||||
use nu_protocol::hir::{ClassifiedCommand, Expression, InternalCommand, Literal, NamedArguments};
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
||||
#[allow(unused)]
|
||||
use nu_source::Tagged;
|
||||
|
||||
use log::{debug, trace};
|
||||
use rustyline::error::ReadlineError;
|
||||
@ -374,12 +376,9 @@ pub fn create_default_context(
|
||||
whole_stream_command(MathVariance),
|
||||
// File format output
|
||||
whole_stream_command(To),
|
||||
whole_stream_command(ToBSON),
|
||||
whole_stream_command(ToCSV),
|
||||
whole_stream_command(ToHTML),
|
||||
whole_stream_command(ToJSON),
|
||||
whole_stream_command(ToSQLite),
|
||||
whole_stream_command(ToDB),
|
||||
whole_stream_command(ToMarkdown),
|
||||
whole_stream_command(ToTOML),
|
||||
whole_stream_command(ToTSV),
|
||||
@ -392,11 +391,8 @@ pub fn create_default_context(
|
||||
whole_stream_command(FromTSV),
|
||||
whole_stream_command(FromSSV),
|
||||
whole_stream_command(FromINI),
|
||||
whole_stream_command(FromBSON),
|
||||
whole_stream_command(FromJSON),
|
||||
whole_stream_command(FromODS),
|
||||
whole_stream_command(FromDB),
|
||||
whole_stream_command(FromSQLite),
|
||||
whole_stream_command(FromTOML),
|
||||
whole_stream_command(FromURL),
|
||||
whole_stream_command(FromXLSX),
|
||||
@ -411,6 +407,7 @@ pub fn create_default_context(
|
||||
whole_stream_command(Random),
|
||||
whole_stream_command(RandomBool),
|
||||
whole_stream_command(RandomDice),
|
||||
#[cfg(feature = "uuid_crate")]
|
||||
whole_stream_command(RandomUUID),
|
||||
]);
|
||||
|
||||
@ -432,15 +429,18 @@ pub async fn run_vec_of_pipelines(
|
||||
|
||||
let _ = crate::load_plugins(&mut context);
|
||||
|
||||
let cc = context.ctrl_c.clone();
|
||||
#[cfg(feature = "ctrlc")]
|
||||
{
|
||||
let cc = context.ctrl_c.clone();
|
||||
|
||||
ctrlc::set_handler(move || {
|
||||
cc.store(true, Ordering::SeqCst);
|
||||
})
|
||||
.expect("Error setting Ctrl-C handler");
|
||||
ctrlc::set_handler(move || {
|
||||
cc.store(true, Ordering::SeqCst);
|
||||
})
|
||||
.expect("Error setting Ctrl-C handler");
|
||||
|
||||
if context.ctrl_c.load(Ordering::SeqCst) {
|
||||
context.ctrl_c.store(false, Ordering::SeqCst);
|
||||
if context.ctrl_c.load(Ordering::SeqCst) {
|
||||
context.ctrl_c.store(false, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
// before we start up, let's run our startup commands
|
||||
@ -557,11 +557,15 @@ pub async fn cli(
|
||||
// we are ok if history does not exist
|
||||
let _ = rl.load_history(&History::path());
|
||||
|
||||
let cc = context.ctrl_c.clone();
|
||||
ctrlc::set_handler(move || {
|
||||
cc.store(true, Ordering::SeqCst);
|
||||
})
|
||||
.expect("Error setting Ctrl-C handler");
|
||||
#[cfg(feature = "ctrlc")]
|
||||
{
|
||||
let cc = context.ctrl_c.clone();
|
||||
|
||||
ctrlc::set_handler(move || {
|
||||
cc.store(true, Ordering::SeqCst);
|
||||
})
|
||||
.expect("Error setting Ctrl-C handler");
|
||||
}
|
||||
let mut ctrlcbreak = false;
|
||||
|
||||
// before we start up, let's run our startup commands
|
||||
@ -662,21 +666,35 @@ pub async fn cli(
|
||||
|
||||
let colored_prompt = {
|
||||
if use_starship {
|
||||
std::env::set_var("STARSHIP_SHELL", "");
|
||||
std::env::set_var("PWD", &cwd);
|
||||
let mut starship_context =
|
||||
starship::context::Context::new_with_dir(clap::ArgMatches::default(), cwd);
|
||||
#[cfg(feature = "starship")]
|
||||
{
|
||||
std::env::set_var("STARSHIP_SHELL", "");
|
||||
std::env::set_var("PWD", &cwd);
|
||||
let mut starship_context =
|
||||
starship::context::Context::new_with_dir(clap::ArgMatches::default(), cwd);
|
||||
|
||||
match starship_context.config.config {
|
||||
None => {
|
||||
starship_context.config.config = create_default_starship_config();
|
||||
}
|
||||
Some(toml::Value::Table(t)) if t.is_empty() => {
|
||||
starship_context.config.config = create_default_starship_config();
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
starship::print::get_prompt(starship_context)
|
||||
match starship_context.config.config {
|
||||
None => {
|
||||
starship_context.config.config = create_default_starship_config();
|
||||
}
|
||||
Some(toml::Value::Table(t)) if t.is_empty() => {
|
||||
starship_context.config.config = create_default_starship_config();
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
starship::print::get_prompt(starship_context)
|
||||
}
|
||||
#[cfg(not(feature = "starship"))]
|
||||
{
|
||||
format!(
|
||||
"\x1b[32m{}{}\x1b[m> ",
|
||||
cwd,
|
||||
match current_branch() {
|
||||
Some(s) => format!("({})", s),
|
||||
None => "".to_string(),
|
||||
}
|
||||
)
|
||||
}
|
||||
} else if let Some(prompt) = config.get("prompt") {
|
||||
let prompt_line = prompt.as_string()?;
|
||||
|
||||
@ -829,6 +847,7 @@ fn chomp_newline(s: &str) -> &str {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LineResult {
|
||||
Success(String),
|
||||
Error(String, ShellError),
|
||||
@ -836,6 +855,36 @@ pub enum LineResult {
|
||||
Break,
|
||||
}
|
||||
|
||||
pub async fn parse_and_eval(line: &str, ctx: &mut Context) -> Result<String, ShellError> {
|
||||
let line = if line.ends_with('\n') {
|
||||
&line[..line.len() - 1]
|
||||
} else {
|
||||
line
|
||||
};
|
||||
|
||||
let lite_result = nu_parser::lite_parse(&line, 0)?;
|
||||
|
||||
// TODO ensure the command whose examples we're testing is actually in the pipeline
|
||||
let mut classified_block = nu_parser::classify_block(&lite_result, ctx.registry());
|
||||
classified_block.block.expand_it_usage();
|
||||
|
||||
let input_stream = InputStream::empty();
|
||||
let env = ctx.get_env();
|
||||
|
||||
run_block(
|
||||
&classified_block.block,
|
||||
ctx,
|
||||
input_stream,
|
||||
&Value::nothing(),
|
||||
&IndexMap::new(),
|
||||
&env,
|
||||
)
|
||||
.await?
|
||||
.collect_string(Tag::unknown())
|
||||
.await
|
||||
.map(|x| x.item)
|
||||
}
|
||||
|
||||
/// Process the line by parsing the text to turn it into commands, classify those commands so that we understand what is being called in the pipeline, and then run this pipeline
|
||||
pub async fn process_line(
|
||||
readline: Result<String, ReadlineError>,
|
||||
@ -912,7 +961,7 @@ pub async fn process_line(
|
||||
.unwrap_or(true)
|
||||
&& canonicalize(ctx.shell_manager.path(), name).is_ok()
|
||||
&& Path::new(&name).is_dir()
|
||||
&& which::which(&name).is_err()
|
||||
&& !crate::commands::classified::external::did_find_command(&name)
|
||||
{
|
||||
// Here we work differently if we're in Windows because of the expected Windows behavior
|
||||
#[cfg(windows)]
|
||||
|
@ -40,14 +40,12 @@ pub(crate) mod exit;
|
||||
pub(crate) mod first;
|
||||
pub(crate) mod format;
|
||||
pub(crate) mod from;
|
||||
pub(crate) mod from_bson;
|
||||
pub(crate) mod from_csv;
|
||||
pub(crate) mod from_eml;
|
||||
pub(crate) mod from_ics;
|
||||
pub(crate) mod from_ini;
|
||||
pub(crate) mod from_json;
|
||||
pub(crate) mod from_ods;
|
||||
pub(crate) mod from_sqlite;
|
||||
pub(crate) mod from_ssv;
|
||||
pub(crate) mod from_toml;
|
||||
pub(crate) mod from_tsv;
|
||||
@ -104,12 +102,10 @@ pub(crate) mod str_;
|
||||
pub(crate) mod table;
|
||||
pub(crate) mod tags;
|
||||
pub(crate) mod to;
|
||||
pub(crate) mod to_bson;
|
||||
pub(crate) mod to_csv;
|
||||
pub(crate) mod to_html;
|
||||
pub(crate) mod to_json;
|
||||
pub(crate) mod to_md;
|
||||
pub(crate) mod to_sqlite;
|
||||
pub(crate) mod to_toml;
|
||||
pub(crate) mod to_tsv;
|
||||
pub(crate) mod to_url;
|
||||
@ -168,15 +164,12 @@ pub(crate) use exit::Exit;
|
||||
pub(crate) use first::First;
|
||||
pub(crate) use format::Format;
|
||||
pub(crate) use from::From;
|
||||
pub(crate) use from_bson::FromBSON;
|
||||
pub(crate) use from_csv::FromCSV;
|
||||
pub(crate) use from_eml::FromEML;
|
||||
pub(crate) use from_ics::FromIcs;
|
||||
pub(crate) use from_ini::FromINI;
|
||||
pub(crate) use from_json::FromJSON;
|
||||
pub(crate) use from_ods::FromODS;
|
||||
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;
|
||||
@ -213,7 +206,9 @@ pub(crate) use pivot::Pivot;
|
||||
pub(crate) use prepend::Prepend;
|
||||
pub(crate) use prev::Previous;
|
||||
pub(crate) use pwd::Pwd;
|
||||
pub(crate) use random::{Random, RandomBool, RandomDice, RandomUUID};
|
||||
#[cfg(feature = "uuid_crate")]
|
||||
pub(crate) use random::RandomUUID;
|
||||
pub(crate) use random::{Random, RandomBool, RandomDice};
|
||||
pub(crate) use range::Range;
|
||||
pub(crate) use reject::Reject;
|
||||
pub(crate) use rename::Rename;
|
||||
@ -236,13 +231,10 @@ pub(crate) use str_::{
|
||||
pub(crate) use table::Table;
|
||||
pub(crate) use tags::Tags;
|
||||
pub(crate) use to::To;
|
||||
pub(crate) use to_bson::ToBSON;
|
||||
pub(crate) use to_csv::ToCSV;
|
||||
pub(crate) use to_html::ToHTML;
|
||||
pub(crate) use to_json::ToJSON;
|
||||
pub(crate) use to_md::ToMarkdown;
|
||||
pub(crate) use to_sqlite::ToDB;
|
||||
pub(crate) use to_sqlite::ToSQLite;
|
||||
pub(crate) use to_toml::ToTOML;
|
||||
pub(crate) use to_tsv::ToTSV;
|
||||
pub(crate) use to_url::ToURL;
|
||||
|
@ -26,7 +26,7 @@ pub(crate) async fn run_external_command(
|
||||
) -> Result<InputStream, ShellError> {
|
||||
trace!(target: "nu::run::external", "-> {}", command.name);
|
||||
|
||||
if !did_find_command(&command.name).await {
|
||||
if !did_find_command(&command.name) {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Command not found",
|
||||
"command not found",
|
||||
@ -70,7 +70,18 @@ async fn run_with_stdin(
|
||||
let process_args = command_args
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
let arg = expand_tilde(arg.deref(), dirs::home_dir);
|
||||
let home_dir;
|
||||
|
||||
#[cfg(feature = "dirs")]
|
||||
{
|
||||
home_dir = dirs::home_dir;
|
||||
}
|
||||
#[cfg(not(feature = "dirs"))]
|
||||
{
|
||||
home_dir = || Some(std::path::PathBuf::from("/"));
|
||||
}
|
||||
|
||||
let arg = expand_tilde(arg.deref(), home_dir);
|
||||
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
@ -407,13 +418,19 @@ fn spawn(
|
||||
}
|
||||
}
|
||||
|
||||
async fn did_find_command(name: &str) -> bool {
|
||||
#[cfg(not(windows))]
|
||||
pub fn did_find_command(#[allow(unused)] name: &str) -> bool {
|
||||
#[cfg(not(feature = "which"))]
|
||||
{
|
||||
// we can't perform this check, so just assume it can be found
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "which", unix))]
|
||||
{
|
||||
which::which(name).is_ok()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[cfg(all(feature = "which", windows))]
|
||||
{
|
||||
if which::which(name).is_ok() {
|
||||
true
|
||||
@ -483,11 +500,17 @@ fn shell_os_paths() -> Vec<std::path::PathBuf> {
|
||||
mod tests {
|
||||
use super::{
|
||||
add_quotes, argument_contains_whitespace, argument_is_quoted, expand_tilde, remove_quotes,
|
||||
run_external_command, Context, InputStream,
|
||||
};
|
||||
#[cfg(feature = "which")]
|
||||
use super::{run_external_command, Context, InputStream};
|
||||
|
||||
#[cfg(feature = "which")]
|
||||
use futures::executor::block_on;
|
||||
#[cfg(feature = "which")]
|
||||
use nu_errors::ShellError;
|
||||
#[cfg(feature = "which")]
|
||||
use nu_protocol::Scope;
|
||||
#[cfg(feature = "which")]
|
||||
use nu_test_support::commands::ExternalBuilder;
|
||||
|
||||
// async fn read(mut stream: OutputStream) -> Option<Value> {
|
||||
@ -503,6 +526,7 @@ mod tests {
|
||||
// }
|
||||
// }
|
||||
|
||||
#[cfg(feature = "which")]
|
||||
async fn non_existent_run() -> Result<(), ShellError> {
|
||||
let cmd = ExternalBuilder::for_name("i_dont_exist.exe").build();
|
||||
|
||||
@ -542,6 +566,7 @@ mod tests {
|
||||
// block_on(failure_run())
|
||||
// }
|
||||
|
||||
#[cfg(feature = "which")]
|
||||
#[test]
|
||||
fn identifies_command_not_found() -> Result<(), ShellError> {
|
||||
block_on(non_existent_run())
|
||||
|
@ -2,10 +2,12 @@ pub mod command;
|
||||
|
||||
pub mod bool;
|
||||
pub mod dice;
|
||||
#[cfg(feature = "uuid_crate")]
|
||||
pub mod uuid;
|
||||
|
||||
pub use command::Command as Random;
|
||||
|
||||
pub use self::bool::SubCommand as RandomBool;
|
||||
pub use dice::SubCommand as RandomDice;
|
||||
#[cfg(feature = "uuid_crate")]
|
||||
pub use uuid::SubCommand as RandomUUID;
|
||||
|
@ -157,7 +157,7 @@ async fn maybe_autocd_dir<'a>(cmd: &ExternalCommand, ctx: &mut Context) -> Optio
|
||||
|| (cmd.args.is_empty()
|
||||
&& PathBuf::from(name).is_dir()
|
||||
&& dunce::canonicalize(name).is_ok()
|
||||
&& which::which(&name).is_err())
|
||||
&& !crate::commands::classified::external::did_find_command(&name))
|
||||
{
|
||||
Some(name)
|
||||
} else {
|
||||
|
@ -60,6 +60,7 @@ macro_rules! entry_builtin {
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! entry_path {
|
||||
($arg:expr, $path:expr, $tag:expr) => {
|
||||
entry(
|
||||
@ -99,13 +100,16 @@ async fn which(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputSt
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(paths) = ichwh::which_all(&item).await {
|
||||
for path in paths {
|
||||
output.push(ReturnSuccess::value(entry_path!(
|
||||
item,
|
||||
path.into(),
|
||||
application.tag.clone()
|
||||
)));
|
||||
#[cfg(feature = "ichwh")]
|
||||
{
|
||||
if let Ok(paths) = ichwh::which_all(&item).await {
|
||||
for path in paths {
|
||||
output.push(ReturnSuccess::value(entry_path!(
|
||||
item,
|
||||
path.into(),
|
||||
application.tag.clone()
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,7 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn basic() -> Result<Context, Box<dyn Error>> {
|
||||
pub fn basic() -> Result<Context, Box<dyn Error>> {
|
||||
let registry = CommandRegistry::new();
|
||||
|
||||
#[cfg(windows)]
|
||||
|
@ -10,7 +10,6 @@ pub(crate) use nuconfig::NuConfig;
|
||||
use crate::commands::from_toml::convert_toml_value_to_nu_value;
|
||||
use crate::commands::to_toml::value_to_toml_value;
|
||||
use crate::prelude::*;
|
||||
use directories::ProjectDirs;
|
||||
use indexmap::IndexMap;
|
||||
use log::trace;
|
||||
use nu_errors::ShellError;
|
||||
@ -20,8 +19,25 @@ use std::fs::{self, OpenOptions};
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[cfg(feature = "directories")]
|
||||
pub fn config_path() -> Result<PathBuf, ShellError> {
|
||||
app_path("config", ProjectDirs::config_dir)
|
||||
use directories::ProjectDirs;
|
||||
|
||||
let dir = ProjectDirs::from("org", "nushell", "nu")
|
||||
.ok_or_else(|| ShellError::untagged_runtime_error("Couldn't find project directory"))?;
|
||||
let path = ProjectDirs::config_dir(&dir).to_owned();
|
||||
std::fs::create_dir_all(&path).map_err(|err| {
|
||||
ShellError::untagged_runtime_error(&format!("Couldn't create {} path:\n{}", "config", err))
|
||||
})?;
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "directories"))]
|
||||
pub fn config_path() -> Result<PathBuf, ShellError> {
|
||||
// FIXME: unsure if this should be error or a simple default
|
||||
|
||||
Ok(std::path::PathBuf::from("/"))
|
||||
}
|
||||
|
||||
pub fn default_path() -> Result<PathBuf, ShellError> {
|
||||
@ -39,21 +55,30 @@ pub fn default_path_for(file: &Option<PathBuf>) -> Result<PathBuf, ShellError> {
|
||||
Ok(filename)
|
||||
}
|
||||
|
||||
#[cfg(feature = "directories")]
|
||||
pub fn user_data() -> Result<PathBuf, ShellError> {
|
||||
app_path("user data", ProjectDirs::data_local_dir)
|
||||
}
|
||||
use directories::ProjectDirs;
|
||||
|
||||
fn app_path<F: FnOnce(&ProjectDirs) -> &Path>(display: &str, f: F) -> Result<PathBuf, ShellError> {
|
||||
let dir = ProjectDirs::from("org", "nushell", "nu")
|
||||
.ok_or_else(|| ShellError::untagged_runtime_error("Couldn't find project directory"))?;
|
||||
let path = f(&dir).to_owned();
|
||||
let path = ProjectDirs::data_local_dir(&dir).to_owned();
|
||||
std::fs::create_dir_all(&path).map_err(|err| {
|
||||
ShellError::untagged_runtime_error(&format!("Couldn't create {} path:\n{}", display, err))
|
||||
ShellError::untagged_runtime_error(&format!(
|
||||
"Couldn't create {} path:\n{}",
|
||||
"user data", err
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "directories"))]
|
||||
pub fn user_data() -> Result<PathBuf, ShellError> {
|
||||
// FIXME: unsure if this should be error or a simple default
|
||||
|
||||
Ok(std::path::PathBuf::from("/"))
|
||||
}
|
||||
|
||||
pub fn read(
|
||||
tag: impl Into<Tag>,
|
||||
at: &Option<PathBuf>,
|
||||
|
56
crates/nu-cli/src/env/host.rs
vendored
56
crates/nu-cli/src/env/host.rs
vendored
@ -6,9 +6,6 @@ use std::ffi::OsString;
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub trait Host: Debug + Send {
|
||||
fn out_terminal(&self) -> Option<Box<term::StdoutTerminal>>;
|
||||
fn err_terminal(&self) -> Option<Box<term::StderrTerminal>>;
|
||||
|
||||
fn out_termcolor(&self) -> termcolor::StandardStream;
|
||||
fn err_termcolor(&self) -> termcolor::StandardStream;
|
||||
|
||||
@ -24,14 +21,6 @@ pub trait Host: Debug + Send {
|
||||
}
|
||||
|
||||
impl Host for Box<dyn Host> {
|
||||
fn out_terminal(&self) -> Option<Box<term::StdoutTerminal>> {
|
||||
(**self).out_terminal()
|
||||
}
|
||||
|
||||
fn err_terminal(&self) -> Option<Box<term::StderrTerminal>> {
|
||||
(**self).err_terminal()
|
||||
}
|
||||
|
||||
fn stdout(&mut self, out: &str) {
|
||||
(**self).stdout(out)
|
||||
}
|
||||
@ -73,14 +62,6 @@ impl Host for Box<dyn Host> {
|
||||
pub struct BasicHost;
|
||||
|
||||
impl Host for BasicHost {
|
||||
fn out_terminal(&self) -> Option<Box<term::StdoutTerminal>> {
|
||||
term::stdout()
|
||||
}
|
||||
|
||||
fn err_terminal(&self) -> Option<Box<term::StderrTerminal>> {
|
||||
term::stderr()
|
||||
}
|
||||
|
||||
fn stdout(&mut self, out: &str) {
|
||||
match out {
|
||||
"\n" => outln!(""),
|
||||
@ -96,19 +77,40 @@ impl Host for BasicHost {
|
||||
}
|
||||
|
||||
fn vars(&mut self) -> Vec<(String, String)> {
|
||||
std::env::vars().collect::<Vec<_>>()
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
std::env::vars().collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
fn env_get(&mut self, key: OsString) -> Option<OsString> {
|
||||
std::env::var_os(key)
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
std::env::var_os(key)
|
||||
}
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn env_set(&mut self, key: OsString, value: OsString) {
|
||||
std::env::set_var(key, value);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
std::env::set_var(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
fn env_rm(&mut self, key: OsString) {
|
||||
std::env::remove_var(key);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
std::env::remove_var(key);
|
||||
}
|
||||
}
|
||||
|
||||
fn out_termcolor(&self) -> termcolor::StandardStream {
|
||||
@ -145,14 +147,6 @@ impl FakeHost {
|
||||
|
||||
#[cfg(test)]
|
||||
impl Host for FakeHost {
|
||||
fn out_terminal(&self) -> Option<Box<term::StdoutTerminal>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn err_terminal(&self) -> Option<Box<term::StderrTerminal>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn stdout(&mut self, out: &str) {
|
||||
self.line_written = out.to_string();
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ pub fn nu(env: &IndexMap<String, String>, tag: impl Into<Tag>) -> Result<Value,
|
||||
let path = std::env::current_dir()?;
|
||||
nu_dict.insert_value("cwd", UntaggedValue::path(path).into_value(&tag));
|
||||
|
||||
if let Some(home) = dirs::home_dir() {
|
||||
if let Some(home) = crate::shell::filesystem_shell::homedir_if_possible() {
|
||||
nu_dict.insert_value("home-dir", UntaggedValue::path(home).into_value(&tag));
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
use crate::prelude::*;
|
||||
use git2::{Repository, RepositoryOpenFlags};
|
||||
use std::ffi::OsString;
|
||||
|
||||
pub fn current_branch() -> Option<String> {
|
||||
if let Ok(config) = crate::data::config::config(Tag::unknown()) {
|
||||
@ -13,19 +11,29 @@ pub fn current_branch() -> Option<String> {
|
||||
};
|
||||
|
||||
if !use_starship {
|
||||
let v: Vec<OsString> = vec![];
|
||||
match Repository::open_ext(".", RepositoryOpenFlags::empty(), v) {
|
||||
Ok(repo) => {
|
||||
let r = repo.head();
|
||||
match r {
|
||||
Ok(r) => match r.shorthand() {
|
||||
Some(s) => Some(s.to_string()),
|
||||
None => None,
|
||||
},
|
||||
_ => None,
|
||||
#[cfg(feature = "git2")]
|
||||
{
|
||||
use git2::{Repository, RepositoryOpenFlags};
|
||||
use std::ffi::OsString;
|
||||
|
||||
let v: Vec<OsString> = vec![];
|
||||
match Repository::open_ext(".", RepositoryOpenFlags::empty(), v) {
|
||||
Ok(repo) => {
|
||||
let r = repo.head();
|
||||
match r {
|
||||
Ok(r) => match r.shorthand() {
|
||||
Some(s) => Some(s.to_string()),
|
||||
None => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
#[cfg(not(feature = "git2"))]
|
||||
{
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
|
@ -34,14 +34,14 @@ pub mod utils;
|
||||
mod examples;
|
||||
|
||||
pub use crate::cli::{
|
||||
cli, create_default_context, load_plugins, process_line, run_pipeline_standalone,
|
||||
run_vec_of_pipelines, LineResult,
|
||||
cli, create_default_context, load_plugins, parse_and_eval, process_line,
|
||||
run_pipeline_standalone, run_vec_of_pipelines, LineResult,
|
||||
};
|
||||
pub use crate::commands::command::{
|
||||
whole_stream_command, CommandArgs, EvaluatedWholeStreamCommandArgs, WholeStreamCommand,
|
||||
};
|
||||
pub use crate::commands::help::get_help;
|
||||
pub use crate::context::CommandRegistry;
|
||||
pub use crate::context::{CommandRegistry, Context};
|
||||
pub use crate::data::config;
|
||||
pub use crate::data::dict::TaggedListBuilder;
|
||||
pub use crate::data::primitive;
|
||||
|
@ -3,8 +3,9 @@ use crate::context::CommandRegistry;
|
||||
use crate::data::config;
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
#[cfg(windows)]
|
||||
#[cfg(all(windows, feature = "ichwh"))]
|
||||
use ichwh::IchwhError;
|
||||
#[cfg(all(windows, feature = "ichwh"))]
|
||||
use ichwh::IchwhResult;
|
||||
use indexmap::set::IndexSet;
|
||||
use rustyline::completion::{Completer, FilenameCompleter};
|
||||
@ -225,35 +226,49 @@ impl NuCompleter {
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn is_executable(&self, file: &DirEntry) -> IchwhResult<bool> {
|
||||
let file_type = file.metadata()?.file_type();
|
||||
fn is_executable(&self, file: &DirEntry) -> bool {
|
||||
if let Ok(metadata) = file.metadata() {
|
||||
let file_type = metadata.file_type();
|
||||
|
||||
// If the entry isn't a file, it cannot be executable
|
||||
if !(file_type.is_file() || file_type.is_symlink()) {
|
||||
return Ok(false);
|
||||
}
|
||||
// If the entry isn't a file, it cannot be executable
|
||||
if !(file_type.is_file() || file_type.is_symlink()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(extension) = file.path().extension() {
|
||||
let exts = self.pathext()?;
|
||||
|
||||
Ok(exts
|
||||
.iter()
|
||||
.any(|ext| extension.to_string_lossy().eq_ignore_ascii_case(ext)))
|
||||
if let Some(extension) = file.path().extension() {
|
||||
if let Ok(exts) = self.pathext() {
|
||||
exts.iter()
|
||||
.any(|ext| extension.to_string_lossy().eq_ignore_ascii_case(ext))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
Ok(false)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn is_executable(&self, file: &DirEntry) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn is_executable(&self, file: &DirEntry) -> IchwhResult<bool> {
|
||||
let metadata = file.metadata()?;
|
||||
fn is_executable(&self, file: &DirEntry) -> bool {
|
||||
let metadata = file.metadata();
|
||||
|
||||
let filetype = metadata.file_type();
|
||||
let permissions = metadata.permissions();
|
||||
if let Ok(metadata) = metadata {
|
||||
let filetype = metadata.file_type();
|
||||
let permissions = metadata.permissions();
|
||||
|
||||
// The file is executable if it is a directory or a symlink and the permissions are set for
|
||||
// owner, group, or other
|
||||
Ok((filetype.is_file() || filetype.is_symlink()) && (permissions.mode() & 0o111 != 0))
|
||||
// The file is executable if it is a directory or a symlink and the permissions are set for
|
||||
// owner, group, or other
|
||||
(filetype.is_file() || filetype.is_symlink()) && (permissions.mode() & 0o111 != 0)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn find_path_executables(&self) -> Option<IndexSet<String>> {
|
||||
@ -264,7 +279,7 @@ impl NuCompleter {
|
||||
for path in paths {
|
||||
if let Ok(mut contents) = read_dir(path) {
|
||||
while let Some(Ok(item)) = contents.next() {
|
||||
if let Ok(true) = self.is_executable(&item) {
|
||||
if self.is_executable(&item) {
|
||||
if let Ok(name) = item.file_name().into_string() {
|
||||
executables.insert(name);
|
||||
}
|
||||
|
@ -61,7 +61,10 @@ impl Clone for FilesystemShell {
|
||||
|
||||
impl FilesystemShell {
|
||||
pub fn basic(commands: CommandRegistry) -> Result<FilesystemShell, Error> {
|
||||
let path = std::env::current_dir()?;
|
||||
let path = match std::env::current_dir() {
|
||||
Ok(path) => path,
|
||||
Err(_) => PathBuf::from("/"),
|
||||
};
|
||||
|
||||
Ok(FilesystemShell {
|
||||
path: path.to_string_lossy().to_string(),
|
||||
@ -69,7 +72,7 @@ impl FilesystemShell {
|
||||
completer: NuCompleter {
|
||||
file_completer: FilenameCompleter::new(),
|
||||
commands,
|
||||
homedir: dirs::home_dir(),
|
||||
homedir: homedir_if_possible(),
|
||||
},
|
||||
hinter: HistoryHinter {},
|
||||
})
|
||||
@ -89,20 +92,32 @@ impl FilesystemShell {
|
||||
completer: NuCompleter {
|
||||
file_completer: FilenameCompleter::new(),
|
||||
commands,
|
||||
homedir: dirs::home_dir(),
|
||||
homedir: homedir_if_possible(),
|
||||
},
|
||||
hinter: HistoryHinter {},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn homedir_if_possible() -> Option<PathBuf> {
|
||||
#[cfg(feature = "dirs")]
|
||||
{
|
||||
dirs::home_dir()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "dirs"))]
|
||||
{
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Shell for FilesystemShell {
|
||||
fn name(&self) -> String {
|
||||
"filesystem".to_string()
|
||||
}
|
||||
|
||||
fn homedir(&self) -> Option<PathBuf> {
|
||||
dirs::home_dir()
|
||||
homedir_if_possible()
|
||||
}
|
||||
|
||||
fn ls(
|
||||
@ -195,7 +210,7 @@ impl Shell for FilesystemShell {
|
||||
|
||||
fn cd(&self, args: CdArgs, name: Tag) -> Result<OutputStream, ShellError> {
|
||||
let path = match args.path {
|
||||
None => match dirs::home_dir() {
|
||||
None => match homedir_if_possible() {
|
||||
Some(o) => o,
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
|
@ -126,7 +126,15 @@ impl Shell for HelpShell {
|
||||
}
|
||||
|
||||
fn homedir(&self) -> Option<PathBuf> {
|
||||
dirs::home_dir()
|
||||
#[cfg(feature = "dirs")]
|
||||
{
|
||||
dirs::home_dir()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "dirs"))]
|
||||
{
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn path(&self) -> String {
|
||||
|
@ -126,9 +126,8 @@ impl InputStream {
|
||||
}
|
||||
Some(Value {
|
||||
tag: value_tag,
|
||||
value: v,
|
||||
value: _,
|
||||
}) => {
|
||||
println!("{:?}", v);
|
||||
return Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected binary from pipeline",
|
||||
"requires binary input",
|
||||
|
@ -127,6 +127,7 @@ fn filesystem_change_current_directory_to_parent_directory_after_delete_cwd() {
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "dirs")]
|
||||
#[test]
|
||||
fn filesystem_change_to_home_directory() {
|
||||
Playground::setup("cd_test_8", |dirs, _| {
|
||||
|
@ -54,6 +54,7 @@ fn parses_csv() {
|
||||
// what appears to be an issue in the bson library that is under investigation.
|
||||
//
|
||||
|
||||
#[cfg(feature = "bson")]
|
||||
#[test]
|
||||
fn parses_bson() {
|
||||
let actual = nu!(
|
||||
@ -64,6 +65,7 @@ fn parses_bson() {
|
||||
assert_eq!(actual.out, "hello");
|
||||
}
|
||||
|
||||
#[cfg(feature = "bson")]
|
||||
#[test]
|
||||
fn parses_more_bson_complexity() {
|
||||
let actual = nu!(
|
||||
@ -130,6 +132,7 @@ fn parses_more_bson_complexity() {
|
||||
// 4 │
|
||||
// ━━━┷━━━━━━
|
||||
|
||||
#[cfg(feature = "sqlite")]
|
||||
#[test]
|
||||
fn parses_sqlite() {
|
||||
let actual = nu!(
|
||||
|
@ -1,3 +1,4 @@
|
||||
mod bool;
|
||||
mod dice;
|
||||
#[cfg(feature = "uuid_crate")]
|
||||
mod uuid;
|
||||
|
@ -15,6 +15,7 @@ fn sets_the_column() {
|
||||
assert_eq!(actual.out, "0.7.0");
|
||||
}
|
||||
|
||||
#[cfg(features = "inc")]
|
||||
#[test]
|
||||
fn sets_the_column_from_a_block_run_output() {
|
||||
let actual = nu!(
|
||||
|
@ -1,4 +1,7 @@
|
||||
use nu_test_support::{nu, pipeline};
|
||||
use nu_test_support::nu;
|
||||
|
||||
#[cfg(feature = "sqlite")]
|
||||
use nu_test_support::pipeline;
|
||||
|
||||
#[test]
|
||||
fn filters_by_unit_size_comparison() {
|
||||
@ -40,6 +43,7 @@ fn where_not_in_table() {
|
||||
assert_eq!(actual.out, "4");
|
||||
}
|
||||
|
||||
#[cfg(feature = "sqlite")]
|
||||
#[test]
|
||||
fn explicit_block_condition() {
|
||||
let actual = nu!(
|
||||
@ -58,6 +62,7 @@ fn explicit_block_condition() {
|
||||
assert_eq!(actual.out, "4253");
|
||||
}
|
||||
|
||||
#[cfg(feature = "sqlite")]
|
||||
#[test]
|
||||
fn binary_operator_comparisons() {
|
||||
let actual = nu!(
|
||||
@ -136,6 +141,7 @@ fn binary_operator_comparisons() {
|
||||
assert_eq!(actual.out, "42");
|
||||
}
|
||||
|
||||
#[cfg(feature = "sqlite")]
|
||||
#[test]
|
||||
fn contains_operator() {
|
||||
let actual = nu!(
|
||||
|
@ -1,7 +1,7 @@
|
||||
use nu_test_support::{nu, pipeline};
|
||||
|
||||
#[cfg(feature = "bson")]
|
||||
#[test]
|
||||
fn table_to_bson_and_back_into_table() {
|
||||
use nu_test_support::{nu, pipeline};
|
||||
let actual = nu!(
|
||||
cwd: "tests/fixtures/formats", pipeline(
|
||||
r#"
|
||||
|
@ -1,5 +1,7 @@
|
||||
#[cfg(feature = "sqlite")]
|
||||
use nu_test_support::{nu, pipeline};
|
||||
|
||||
#[cfg(feature = "sqlite")]
|
||||
#[test]
|
||||
fn table_to_sqlite_and_back_into_table() {
|
||||
let actual = nu!(
|
||||
|
@ -95,6 +95,7 @@ impl Playground {
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub fn symlink(&mut self, from: impl AsRef<Path>, to: impl AsRef<Path>) -> &mut Self {
|
||||
let from = self.cwd.join(from);
|
||||
let to = self.cwd.join(to);
|
||||
|
23
crates/nu_plugin_from_bson/Cargo.toml
Normal file
23
crates/nu_plugin_from_bson/Cargo.toml
Normal file
@ -0,0 +1,23 @@
|
||||
[package]
|
||||
authors = ["The Nu Project Contributors"]
|
||||
description = "A converter plugin to the bson format for Nushell"
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
name = "nu_plugin_from_bson"
|
||||
version = "0.16.1"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
bigdecimal = "0.1.2"
|
||||
bson = {version = "0.14.1", features = ["decimal128"]}
|
||||
nu-errors = {path = "../nu-errors", version = "0.16.1"}
|
||||
nu-plugin = {path = "../nu-plugin", version = "0.16.1"}
|
||||
nu-protocol = {path = "../nu-protocol", version = "0.16.1"}
|
||||
nu-source = {path = "../nu-source", version = "0.16.1"}
|
||||
nu-value-ext = {path = "../nu-value-ext", version = "0.16.1"}
|
||||
num-traits = "0.2.12"
|
||||
|
||||
[build-dependencies]
|
||||
nu-build = {version = "0.16.1", path = "../nu-build"}
|
3
crates/nu_plugin_from_bson/build.rs
Normal file
3
crates/nu_plugin_from_bson/build.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
nu_build::build()
|
||||
}
|
@ -1,41 +1,22 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use bigdecimal::BigDecimal;
|
||||
use bson::{decode_document, spec::BinarySubtype, Bson};
|
||||
use nu_errors::{ExpectedRange, ShellError};
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, TaggedDictBuilder, UntaggedValue, Value};
|
||||
use nu_source::SpannedItem;
|
||||
use nu_protocol::{Primitive, ReturnSuccess, ReturnValue, TaggedDictBuilder, UntaggedValue, Value};
|
||||
use nu_source::{SpannedItem, Tag};
|
||||
use std::str::FromStr;
|
||||
|
||||
pub struct FromBSON;
|
||||
#[derive(Default)]
|
||||
pub struct FromBSON {
|
||||
pub state: Vec<u8>,
|
||||
pub name_tag: Tag,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for FromBSON {
|
||||
fn name(&self) -> &str {
|
||||
"from bson"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("from bson")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Parse binary as .bson and create table."
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
from_bson(args, registry).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Convert bson data to a table",
|
||||
example: "open file.bin | from bson",
|
||||
result: None,
|
||||
}]
|
||||
impl FromBSON {
|
||||
pub fn new() -> FromBSON {
|
||||
FromBSON {
|
||||
state: vec![],
|
||||
name_tag: Tag::unknown(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,37 +189,13 @@ pub fn from_bson_bytes_to_value(bytes: Vec<u8>, tag: impl Into<Tag>) -> Result<V
|
||||
convert_bson_value_to_nu_value(&Bson::Array(docs), tag)
|
||||
}
|
||||
|
||||
async fn from_bson(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
let args = args.evaluate_once(®istry).await?;
|
||||
let tag = args.name_tag();
|
||||
let input = args.input;
|
||||
|
||||
let bytes = input.collect_binary(tag.clone()).await?;
|
||||
|
||||
match from_bson_bytes_to_value(bytes.item, tag.clone()) {
|
||||
Ok(x) => Ok(OutputStream::one(ReturnSuccess::value(x))),
|
||||
Err(_) => Err(ShellError::labeled_error_with_secondary(
|
||||
pub fn from_bson(bytes: Vec<u8>, name_tag: Tag) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
match from_bson_bytes_to_value(bytes, name_tag.clone()) {
|
||||
Ok(x) => Ok(vec![ReturnSuccess::value(x)]),
|
||||
Err(_) => Err(ShellError::labeled_error(
|
||||
"Could not parse as BSON",
|
||||
"input cannot be parsed as BSON",
|
||||
tag.clone(),
|
||||
"value originates from here",
|
||||
bytes.tag,
|
||||
name_tag,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::FromBSON;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(FromBSON {})
|
||||
}
|
||||
}
|
4
crates/nu_plugin_from_bson/src/lib.rs
Normal file
4
crates/nu_plugin_from_bson/src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
||||
mod from_bson;
|
||||
mod nu;
|
||||
|
||||
pub use from_bson::FromBSON;
|
6
crates/nu_plugin_from_bson/src/main.rs
Normal file
6
crates/nu_plugin_from_bson/src/main.rs
Normal file
@ -0,0 +1,6 @@
|
||||
use nu_plugin::serve_plugin;
|
||||
use nu_plugin_from_bson::FromBSON;
|
||||
|
||||
fn main() {
|
||||
serve_plugin(&mut FromBSON::new())
|
||||
}
|
46
crates/nu_plugin_from_bson/src/nu/mod.rs
Normal file
46
crates/nu_plugin_from_bson/src/nu/mod.rs
Normal file
@ -0,0 +1,46 @@
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use crate::FromBSON;
|
||||
use nu_errors::ShellError;
|
||||
use nu_plugin::Plugin;
|
||||
use nu_protocol::{CallInfo, Primitive, ReturnValue, Signature, UntaggedValue, Value};
|
||||
use nu_source::Tag;
|
||||
|
||||
impl Plugin for FromBSON {
|
||||
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||
Ok(Signature::build("from bson")
|
||||
.desc("Convert from .bson binary into table")
|
||||
.filter())
|
||||
}
|
||||
|
||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
self.name_tag = call_info.name_tag;
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
fn filter(&mut self, input: Value) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
match input {
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Binary(b)),
|
||||
..
|
||||
} => {
|
||||
self.state.extend_from_slice(&b);
|
||||
}
|
||||
Value { tag, .. } => {
|
||||
return Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected binary from pipeline",
|
||||
"requires binary input",
|
||||
self.name_tag.clone(),
|
||||
"value originates from here",
|
||||
tag,
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
fn end_filter(&mut self) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
crate::from_bson::from_bson(self.state.clone(), Tag::unknown())
|
||||
}
|
||||
}
|
1
crates/nu_plugin_from_bson/src/nu/tests.rs
Normal file
1
crates/nu_plugin_from_bson/src/nu/tests.rs
Normal file
@ -0,0 +1 @@
|
||||
mod integration {}
|
27
crates/nu_plugin_from_sqlite/Cargo.toml
Normal file
27
crates/nu_plugin_from_sqlite/Cargo.toml
Normal file
@ -0,0 +1,27 @@
|
||||
[package]
|
||||
authors = ["The Nu Project Contributors"]
|
||||
description = "A converter plugin to the bson format for Nushell"
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
name = "nu_plugin_from_sqlite"
|
||||
version = "0.16.1"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
bigdecimal = "0.1.2"
|
||||
nu-errors = {path = "../nu-errors", version = "0.16.1"}
|
||||
nu-plugin = {path = "../nu-plugin", version = "0.16.1"}
|
||||
nu-protocol = {path = "../nu-protocol", version = "0.16.1"}
|
||||
nu-source = {path = "../nu-source", version = "0.16.1"}
|
||||
nu-value-ext = {path = "../nu-value-ext", version = "0.16.1"}
|
||||
num-traits = "0.2.12"
|
||||
tempfile = "3.1.0"
|
||||
|
||||
[dependencies.rusqlite]
|
||||
features = ["bundled", "blob"]
|
||||
version = "0.23.1"
|
||||
|
||||
[build-dependencies]
|
||||
nu-build = {version = "0.16.1", path = "../nu-build"}
|
3
crates/nu_plugin_from_sqlite/build.rs
Normal file
3
crates/nu_plugin_from_sqlite/build.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
nu_build::build()
|
||||
}
|
@ -1,58 +1,22 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, Signature, TaggedDictBuilder, UntaggedValue, Value};
|
||||
use nu_protocol::{Primitive, ReturnSuccess, ReturnValue, TaggedDictBuilder, UntaggedValue, Value};
|
||||
use nu_source::Tag;
|
||||
use rusqlite::{types::ValueRef, Connection, Row, NO_PARAMS};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
pub struct FromSQLite;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for FromSQLite {
|
||||
fn name(&self) -> &str {
|
||||
"from sqlite"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("from sqlite")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Parse binary data as sqlite .db and create table."
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
from_sqlite(args, registry).await
|
||||
}
|
||||
#[derive(Default)]
|
||||
pub struct FromSqlite {
|
||||
pub state: Vec<u8>,
|
||||
pub name_tag: Tag,
|
||||
}
|
||||
|
||||
pub struct FromDB;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for FromDB {
|
||||
fn name(&self) -> &str {
|
||||
"from db"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("from db")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Parse binary data as db and create table."
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
from_sqlite(args, registry).await
|
||||
impl FromSqlite {
|
||||
pub fn new() -> FromSqlite {
|
||||
FromSqlite {
|
||||
state: vec![],
|
||||
name_tag: Tag::unknown(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,47 +99,19 @@ pub fn from_sqlite_bytes_to_value(
|
||||
}
|
||||
}
|
||||
|
||||
async fn from_sqlite(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
let args = args.evaluate_once(®istry).await?;
|
||||
let tag = args.name_tag();
|
||||
let input = args.input;
|
||||
|
||||
let bytes = input.collect_binary(tag.clone()).await?;
|
||||
|
||||
match from_sqlite_bytes_to_value(bytes.item, tag.clone()) {
|
||||
pub fn from_sqlite(bytes: Vec<u8>, name_tag: Tag) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
match from_sqlite_bytes_to_value(bytes, name_tag.clone()) {
|
||||
Ok(x) => match x {
|
||||
Value {
|
||||
value: UntaggedValue::Table(list),
|
||||
..
|
||||
} => Ok(futures::stream::iter(list).to_output_stream()),
|
||||
_ => Ok(OutputStream::one(x)),
|
||||
} => Ok(list.into_iter().map(ReturnSuccess::value).collect()),
|
||||
_ => Ok(vec![ReturnSuccess::value(x)]),
|
||||
},
|
||||
Err(err) => {
|
||||
println!("{:?}", err);
|
||||
|
||||
Err(ShellError::labeled_error_with_secondary(
|
||||
"Could not parse as SQLite",
|
||||
"input cannot be parsed as SQLite",
|
||||
&tag,
|
||||
"value originates from here",
|
||||
bytes.tag,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::FromSQLite;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(FromSQLite {})
|
||||
Err(_) => Err(ShellError::labeled_error(
|
||||
"Could not parse as SQLite",
|
||||
"input cannot be parsed as SQLite",
|
||||
&name_tag,
|
||||
)),
|
||||
}
|
||||
}
|
4
crates/nu_plugin_from_sqlite/src/lib.rs
Normal file
4
crates/nu_plugin_from_sqlite/src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
||||
mod from_sqlite;
|
||||
mod nu;
|
||||
|
||||
pub use from_sqlite::FromSqlite;
|
6
crates/nu_plugin_from_sqlite/src/main.rs
Normal file
6
crates/nu_plugin_from_sqlite/src/main.rs
Normal file
@ -0,0 +1,6 @@
|
||||
use nu_plugin::serve_plugin;
|
||||
use nu_plugin_from_sqlite::FromSqlite;
|
||||
|
||||
fn main() {
|
||||
serve_plugin(&mut FromSqlite::new())
|
||||
}
|
46
crates/nu_plugin_from_sqlite/src/nu/mod.rs
Normal file
46
crates/nu_plugin_from_sqlite/src/nu/mod.rs
Normal file
@ -0,0 +1,46 @@
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use crate::FromSqlite;
|
||||
use nu_errors::ShellError;
|
||||
use nu_plugin::Plugin;
|
||||
use nu_protocol::{CallInfo, Primitive, ReturnValue, Signature, UntaggedValue, Value};
|
||||
use nu_source::Tag;
|
||||
|
||||
impl Plugin for FromSqlite {
|
||||
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||
Ok(Signature::build("from sqlite")
|
||||
.desc("Convert from sqlite binary into table")
|
||||
.filter())
|
||||
}
|
||||
|
||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
self.name_tag = call_info.name_tag;
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
fn filter(&mut self, input: Value) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
match input {
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Binary(b)),
|
||||
..
|
||||
} => {
|
||||
self.state.extend_from_slice(&b);
|
||||
}
|
||||
Value { tag, .. } => {
|
||||
return Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected binary from pipeline",
|
||||
"requires binary input",
|
||||
self.name_tag.clone(),
|
||||
"value originates from here",
|
||||
tag,
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
fn end_filter(&mut self) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
crate::from_sqlite::from_sqlite(self.state.clone(), Tag::unknown())
|
||||
}
|
||||
}
|
1
crates/nu_plugin_from_sqlite/src/nu/tests.rs
Normal file
1
crates/nu_plugin_from_sqlite/src/nu/tests.rs
Normal file
@ -0,0 +1 @@
|
||||
mod integration {}
|
22
crates/nu_plugin_to_bson/Cargo.toml
Normal file
22
crates/nu_plugin_to_bson/Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
||||
[package]
|
||||
authors = ["The Nu Project Contributors"]
|
||||
description = "A converter plugin to the bson format for Nushell"
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
name = "nu_plugin_to_bson"
|
||||
version = "0.16.1"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
bson = "0.14.1"
|
||||
nu-errors = {path = "../nu-errors", version = "0.16.1"}
|
||||
nu-plugin = {path = "../nu-plugin", version = "0.16.1"}
|
||||
nu-protocol = {path = "../nu-protocol", version = "0.16.1"}
|
||||
nu-source = {path = "../nu-source", version = "0.16.1"}
|
||||
nu-value-ext = {path = "../nu-value-ext", version = "0.16.1"}
|
||||
num-traits = "0.2.12"
|
||||
|
||||
[build-dependencies]
|
||||
nu-build = {version = "0.16.1", path = "../nu-build"}
|
3
crates/nu_plugin_to_bson/build.rs
Normal file
3
crates/nu_plugin_to_bson/build.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
nu_build::build()
|
||||
}
|
4
crates/nu_plugin_to_bson/src/lib.rs
Normal file
4
crates/nu_plugin_to_bson/src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
||||
mod nu;
|
||||
mod to_bson;
|
||||
|
||||
pub use to_bson::ToBSON;
|
6
crates/nu_plugin_to_bson/src/main.rs
Normal file
6
crates/nu_plugin_to_bson/src/main.rs
Normal file
@ -0,0 +1,6 @@
|
||||
use nu_plugin::serve_plugin;
|
||||
use nu_plugin_to_bson::ToBSON;
|
||||
|
||||
fn main() {
|
||||
serve_plugin(&mut ToBSON::new())
|
||||
}
|
25
crates/nu_plugin_to_bson/src/nu/mod.rs
Normal file
25
crates/nu_plugin_to_bson/src/nu/mod.rs
Normal file
@ -0,0 +1,25 @@
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use crate::ToBSON;
|
||||
use nu_errors::ShellError;
|
||||
use nu_plugin::Plugin;
|
||||
use nu_protocol::{ReturnValue, Signature, Value};
|
||||
use nu_source::Tag;
|
||||
|
||||
impl Plugin for ToBSON {
|
||||
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||
Ok(Signature::build("to bson")
|
||||
.desc("Convert table into .bson binary")
|
||||
.filter())
|
||||
}
|
||||
|
||||
fn filter(&mut self, input: Value) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
self.state.push(input);
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
fn end_filter(&mut self) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
Ok(crate::to_bson::to_bson(self.state.clone(), Tag::unknown()))
|
||||
}
|
||||
}
|
1
crates/nu_plugin_to_bson/src/nu/tests.rs
Normal file
1
crates/nu_plugin_to_bson/src/nu/tests.rs
Normal file
@ -0,0 +1 @@
|
||||
mod integration {}
|
@ -1,39 +1,21 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use bson::{encode_document, oid::ObjectId, spec::BinarySubtype, Bson, Document};
|
||||
use nu_errors::{CoerceInto, ShellError};
|
||||
use nu_protocol::{
|
||||
Dictionary, Primitive, ReturnSuccess, Signature, SpannedTypeName, UnspannedPathMember,
|
||||
Dictionary, Primitive, ReturnSuccess, ReturnValue, SpannedTypeName, UnspannedPathMember,
|
||||
UntaggedValue, Value,
|
||||
};
|
||||
use nu_source::{Tag, TaggedItem};
|
||||
use num_traits::ToPrimitive;
|
||||
use std::convert::TryInto;
|
||||
|
||||
pub struct ToBSON;
|
||||
#[derive(Default)]
|
||||
pub struct ToBSON {
|
||||
pub state: Vec<Value>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for ToBSON {
|
||||
fn name(&self) -> &str {
|
||||
"to bson"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("to bson")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Convert table into .bson text."
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
to_bson(args, registry).await
|
||||
}
|
||||
|
||||
fn is_binary(&self) -> bool {
|
||||
true
|
||||
impl ToBSON {
|
||||
pub fn new() -> ToBSON {
|
||||
ToBSON { state: vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,17 +243,9 @@ fn bson_value_to_bytes(bson: Bson, tag: Tag) -> Result<Vec<u8>, ShellError> {
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
async fn to_bson(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
let args = args.evaluate_once(®istry).await?;
|
||||
let name_tag = args.name_tag();
|
||||
pub fn to_bson(input: Vec<Value>, name_tag: Tag) -> Vec<ReturnValue> {
|
||||
let name_span = name_tag.span;
|
||||
|
||||
let input: Vec<Value> = args.input.collect().await;
|
||||
|
||||
let to_process_input = match input.len() {
|
||||
x if x > 1 => {
|
||||
let tag = input[0].tag.clone();
|
||||
@ -284,13 +258,14 @@ async fn to_bson(
|
||||
_ => vec![],
|
||||
};
|
||||
|
||||
Ok(futures::stream::iter(to_process_input.into_iter().map(
|
||||
move |value| match value_to_bson_value(&value) {
|
||||
to_process_input
|
||||
.into_iter()
|
||||
.map(move |value| match value_to_bson_value(&value) {
|
||||
Ok(bson_value) => {
|
||||
let value_span = value.tag.span;
|
||||
|
||||
match bson_value_to_bytes(bson_value, name_tag.clone()) {
|
||||
Ok(x) => ReturnSuccess::value(UntaggedValue::binary(x).into_value(&name_tag)),
|
||||
Ok(x) => ReturnSuccess::value(UntaggedValue::binary(x).into_value(name_span)),
|
||||
_ => Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected a table with BSON-compatible structure from pipeline",
|
||||
"requires BSON-compatible input",
|
||||
@ -305,19 +280,6 @@ async fn to_bson(
|
||||
"requires BSON-compatible input",
|
||||
&name_tag,
|
||||
)),
|
||||
},
|
||||
))
|
||||
.to_output_stream())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ToBSON;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(ToBSON {})
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
27
crates/nu_plugin_to_sqlite/Cargo.toml
Normal file
27
crates/nu_plugin_to_sqlite/Cargo.toml
Normal file
@ -0,0 +1,27 @@
|
||||
[package]
|
||||
authors = ["The Nu Project Contributors"]
|
||||
description = "A converter plugin to the bson format for Nushell"
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
name = "nu_plugin_to_sqlite"
|
||||
version = "0.16.1"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
hex = "0.4.2"
|
||||
nu-errors = {path = "../nu-errors", version = "0.16.1"}
|
||||
nu-plugin = {path = "../nu-plugin", version = "0.16.1"}
|
||||
nu-protocol = {path = "../nu-protocol", version = "0.16.1"}
|
||||
nu-source = {path = "../nu-source", version = "0.16.1"}
|
||||
nu-value-ext = {path = "../nu-value-ext", version = "0.16.1"}
|
||||
num-traits = "0.2.12"
|
||||
tempfile = "3.1.0"
|
||||
|
||||
[dependencies.rusqlite]
|
||||
features = ["bundled", "blob"]
|
||||
version = "0.23.1"
|
||||
|
||||
[build-dependencies]
|
||||
nu-build = {version = "0.16.1", path = "../nu-build"}
|
3
crates/nu_plugin_to_sqlite/build.rs
Normal file
3
crates/nu_plugin_to_sqlite/build.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
nu_build::build()
|
||||
}
|
4
crates/nu_plugin_to_sqlite/src/lib.rs
Normal file
4
crates/nu_plugin_to_sqlite/src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
||||
mod nu;
|
||||
mod to_sqlite;
|
||||
|
||||
pub use to_sqlite::ToSqlite;
|
6
crates/nu_plugin_to_sqlite/src/main.rs
Normal file
6
crates/nu_plugin_to_sqlite/src/main.rs
Normal file
@ -0,0 +1,6 @@
|
||||
use nu_plugin::serve_plugin;
|
||||
use nu_plugin_to_sqlite::ToSqlite;
|
||||
|
||||
fn main() {
|
||||
serve_plugin(&mut ToSqlite::new())
|
||||
}
|
25
crates/nu_plugin_to_sqlite/src/nu/mod.rs
Normal file
25
crates/nu_plugin_to_sqlite/src/nu/mod.rs
Normal file
@ -0,0 +1,25 @@
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use crate::ToSqlite;
|
||||
use nu_errors::ShellError;
|
||||
use nu_plugin::Plugin;
|
||||
use nu_protocol::{ReturnValue, Signature, Value};
|
||||
use nu_source::Tag;
|
||||
|
||||
impl Plugin for ToSqlite {
|
||||
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||
Ok(Signature::build("to sqlite")
|
||||
.desc("Convert table into sqlite binary")
|
||||
.filter())
|
||||
}
|
||||
|
||||
fn filter(&mut self, input: Value) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
self.state.push(input);
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
fn end_filter(&mut self) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
crate::to_sqlite::to_sqlite(self.state.clone(), Tag::unknown())
|
||||
}
|
||||
}
|
1
crates/nu_plugin_to_sqlite/src/nu/tests.rs
Normal file
1
crates/nu_plugin_to_sqlite/src/nu/tests.rs
Normal file
@ -0,0 +1 @@
|
||||
mod integration {}
|
@ -1,69 +1,20 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use hex::encode;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Dictionary, Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
||||
use nu_protocol::{Dictionary, Primitive, ReturnSuccess, ReturnValue, UntaggedValue, Value};
|
||||
use nu_source::Tag;
|
||||
use rusqlite::{Connection, NO_PARAMS};
|
||||
use std::io::Read;
|
||||
|
||||
pub struct ToSQLite;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for ToSQLite {
|
||||
fn name(&self) -> &str {
|
||||
"to sqlite"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("to sqlite")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Convert table to sqlite .db binary data"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
to_sqlite(args, registry).await
|
||||
}
|
||||
|
||||
fn is_binary(&self) -> bool {
|
||||
true
|
||||
}
|
||||
#[derive(Default)]
|
||||
pub struct ToSqlite {
|
||||
pub state: Vec<Value>,
|
||||
}
|
||||
|
||||
pub struct ToDB;
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for ToDB {
|
||||
fn name(&self) -> &str {
|
||||
"to db"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("to db")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Convert table to db data"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
to_sqlite(args, registry).await
|
||||
}
|
||||
|
||||
fn is_binary(&self) -> bool {
|
||||
true
|
||||
impl ToSqlite {
|
||||
pub fn new() -> ToSqlite {
|
||||
ToSqlite { state: vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
fn comma_concat(acc: String, current: String) -> String {
|
||||
if acc == "" {
|
||||
current
|
||||
@ -183,9 +134,6 @@ fn sqlite_input_stream_to_bytes(values: Vec<Value>) -> Result<Value, std::io::Er
|
||||
{
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
outln!("{}", create);
|
||||
outln!("{}", insert);
|
||||
outln!("{:?}", e);
|
||||
return Err(std::io::Error::new(std::io::ErrorKind::Other, e));
|
||||
}
|
||||
}
|
||||
@ -203,17 +151,9 @@ fn sqlite_input_stream_to_bytes(values: Vec<Value>) -> Result<Value, std::io::Er
|
||||
Ok(UntaggedValue::binary(out).into_value(tag))
|
||||
}
|
||||
|
||||
async fn to_sqlite(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
let args = args.evaluate_once(®istry).await?;
|
||||
let name_tag = args.name_tag();
|
||||
let input: Vec<Value> = args.input.collect().await;
|
||||
|
||||
pub fn to_sqlite(input: Vec<Value>, name_tag: Tag) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
match sqlite_input_stream_to_bytes(input) {
|
||||
Ok(out) => Ok(OutputStream::one(ReturnSuccess::value(out))),
|
||||
Ok(out) => Ok(vec![ReturnSuccess::value(out)]),
|
||||
_ => Err(ShellError::labeled_error(
|
||||
"Expected a table with SQLite-compatible structure from pipeline",
|
||||
"requires SQLite-compatible input",
|
||||
@ -221,15 +161,3 @@ async fn to_sqlite(
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ToSQLite;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(ToSQLite {})
|
||||
}
|
||||
}
|
@ -1 +1,2 @@
|
||||
#[cfg(features = "inc")]
|
||||
mod core_inc;
|
||||
|
@ -1,5 +1,6 @@
|
||||
use nu_test_support::nu;
|
||||
|
||||
#[cfg(feature = "which")]
|
||||
#[test]
|
||||
fn shows_error_for_command_not_found() {
|
||||
let actual = nu!(
|
||||
@ -10,6 +11,7 @@ fn shows_error_for_command_not_found() {
|
||||
assert!(actual.err.contains("Command not found"));
|
||||
}
|
||||
|
||||
#[cfg(feature = "which")]
|
||||
#[test]
|
||||
fn shows_error_for_command_not_found_in_pipeline() {
|
||||
let actual = nu!(
|
||||
@ -20,6 +22,7 @@ fn shows_error_for_command_not_found_in_pipeline() {
|
||||
assert!(actual.err.contains("Command not found"));
|
||||
}
|
||||
|
||||
#[cfg(feature = "which")]
|
||||
#[test]
|
||||
fn automatically_change_directory() {
|
||||
use nu_test_support::playground::Playground;
|
||||
|
@ -1,4 +1,5 @@
|
||||
use nu_test_support::fs::Stub::EmptyFile;
|
||||
#[cfg(feature = "which")]
|
||||
use nu_test_support::fs::Stub::FileWithContent;
|
||||
use nu_test_support::fs::Stub::FileWithContentToBeTrimmed;
|
||||
use nu_test_support::nu;
|
||||
@ -37,6 +38,7 @@ fn takes_rows_of_nu_value_strings_and_pipes_it_to_stdin_of_external() {
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "which")]
|
||||
#[test]
|
||||
fn autoenv() {
|
||||
Playground::setup("autoenv_test", |dirs, sandbox| {
|
||||
@ -379,6 +381,7 @@ fn string_interpolation_with_it_column_path() {
|
||||
assert_eq!(actual.out, "sammie");
|
||||
}
|
||||
|
||||
#[cfg(feature = "which")]
|
||||
#[test]
|
||||
fn argument_invocation_reports_errors() {
|
||||
let actual = nu!(
|
||||
|
Loading…
Reference in New Issue
Block a user