mirror of
https://github.com/nushell/nushell
synced 2024-12-26 13:03:07 +00:00
WIP move post/fetch to plugins
This commit is contained in:
parent
5622bbdd48
commit
38b7a3e32b
14 changed files with 420 additions and 357 deletions
33
Cargo.lock
generated
33
Cargo.lock
generated
|
@ -1923,6 +1923,8 @@ dependencies = [
|
||||||
"nu-protocol",
|
"nu-protocol",
|
||||||
"nu-source",
|
"nu-source",
|
||||||
"nu_plugin_binaryview",
|
"nu_plugin_binaryview",
|
||||||
|
"nu_plugin_fetch",
|
||||||
|
"nu_plugin_post",
|
||||||
"nu_plugin_ps",
|
"nu_plugin_ps",
|
||||||
"nu_plugin_sys",
|
"nu_plugin_sys",
|
||||||
"nu_plugin_textview",
|
"nu_plugin_textview",
|
||||||
|
@ -1953,7 +1955,6 @@ dependencies = [
|
||||||
"strip-ansi-escapes",
|
"strip-ansi-escapes",
|
||||||
"sublime_fuzzy",
|
"sublime_fuzzy",
|
||||||
"subprocess",
|
"subprocess",
|
||||||
"surf",
|
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"term",
|
"term",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
|
@ -1963,7 +1964,6 @@ dependencies = [
|
||||||
"typetag",
|
"typetag",
|
||||||
"umask",
|
"umask",
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
"url",
|
|
||||||
"which",
|
"which",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2090,6 +2090,35 @@ dependencies = [
|
||||||
"rawkey",
|
"rawkey",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nu_plugin_fetch"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"futures-preview",
|
||||||
|
"nu-build",
|
||||||
|
"nu-errors",
|
||||||
|
"nu-protocol",
|
||||||
|
"nu-source",
|
||||||
|
"surf",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nu_plugin_post"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.11.0",
|
||||||
|
"futures-preview",
|
||||||
|
"nu-build",
|
||||||
|
"nu-errors",
|
||||||
|
"nu-protocol",
|
||||||
|
"nu-source",
|
||||||
|
"num-traits 0.2.10",
|
||||||
|
"serde_json",
|
||||||
|
"surf",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu_plugin_ps"
|
name = "nu_plugin_ps"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
@ -18,6 +18,8 @@ members = [
|
||||||
"crates/nu-source",
|
"crates/nu-source",
|
||||||
"crates/nu_plugin_textview",
|
"crates/nu_plugin_textview",
|
||||||
"crates/nu_plugin_binaryview",
|
"crates/nu_plugin_binaryview",
|
||||||
|
"crates/nu_plugin_fetch",
|
||||||
|
"crates/nu_plugin_post",
|
||||||
"crates/nu_plugin_ps",
|
"crates/nu_plugin_ps",
|
||||||
"crates/nu_plugin_sys",
|
"crates/nu_plugin_sys",
|
||||||
"crates/nu-protocol",
|
"crates/nu-protocol",
|
||||||
|
@ -34,6 +36,8 @@ nu-errors = { version = "0.1.0", path = "./crates/nu-errors" }
|
||||||
nu-parser = { version = "0.1.0", path = "./crates/nu-parser" }
|
nu-parser = { version = "0.1.0", path = "./crates/nu-parser" }
|
||||||
nu_plugin_textview = {version = "0.1.0", path = "./crates/nu_plugin_textview", optional=true}
|
nu_plugin_textview = {version = "0.1.0", path = "./crates/nu_plugin_textview", optional=true}
|
||||||
nu_plugin_binaryview = {version = "0.1.0", path = "./crates/nu_plugin_binaryview", optional=true}
|
nu_plugin_binaryview = {version = "0.1.0", path = "./crates/nu_plugin_binaryview", optional=true}
|
||||||
|
nu_plugin_fetch = {version = "0.1.0", path = "./crates/nu_plugin_fetch", optional=true}
|
||||||
|
nu_plugin_post = {version = "0.1.0", path = "./crates/nu_plugin_post", optional=true}
|
||||||
nu_plugin_ps = {version = "0.1.0", path = "./crates/nu_plugin_ps", optional=true}
|
nu_plugin_ps = {version = "0.1.0", path = "./crates/nu_plugin_ps", optional=true}
|
||||||
nu_plugin_sys = {version = "0.1.0", path = "./crates/nu_plugin_sys", optional=true}
|
nu_plugin_sys = {version = "0.1.0", path = "./crates/nu_plugin_sys", optional=true}
|
||||||
|
|
||||||
|
@ -75,8 +79,6 @@ git2 = { version = "0.10.1", default_features = false }
|
||||||
dirs = "2.0.2"
|
dirs = "2.0.2"
|
||||||
glob = "0.3.0"
|
glob = "0.3.0"
|
||||||
ctrlc = "3.1.3"
|
ctrlc = "3.1.3"
|
||||||
surf = "1.0.3"
|
|
||||||
url = "2.1.0"
|
|
||||||
roxmltree = "0.7.2"
|
roxmltree = "0.7.2"
|
||||||
nom_locate = "1.0.0"
|
nom_locate = "1.0.0"
|
||||||
nom-tracable = "0.4.1"
|
nom-tracable = "0.4.1"
|
||||||
|
|
|
@ -9,6 +9,7 @@ pub enum CommandAction {
|
||||||
Exit,
|
Exit,
|
||||||
Error(ShellError),
|
Error(ShellError),
|
||||||
EnterShell(String),
|
EnterShell(String),
|
||||||
|
AutoConvert(Value, String),
|
||||||
EnterValueShell(Value),
|
EnterValueShell(Value),
|
||||||
EnterHelpShell(Value),
|
EnterHelpShell(Value),
|
||||||
PreviousShell,
|
PreviousShell,
|
||||||
|
@ -22,6 +23,9 @@ impl PrettyDebug for CommandAction {
|
||||||
CommandAction::ChangePath(path) => b::typed("change path", b::description(path)),
|
CommandAction::ChangePath(path) => b::typed("change path", b::description(path)),
|
||||||
CommandAction::Exit => b::description("exit"),
|
CommandAction::Exit => b::description("exit"),
|
||||||
CommandAction::Error(_) => b::error("error"),
|
CommandAction::Error(_) => b::error("error"),
|
||||||
|
CommandAction::AutoConvert(_, extension) => {
|
||||||
|
b::typed("auto convert", b::description(extension))
|
||||||
|
}
|
||||||
CommandAction::EnterShell(s) => b::typed("enter shell", b::description(s)),
|
CommandAction::EnterShell(s) => b::typed("enter shell", b::description(s)),
|
||||||
CommandAction::EnterValueShell(v) => b::typed("enter value shell", v.pretty()),
|
CommandAction::EnterValueShell(v) => b::typed("enter value shell", v.pretty()),
|
||||||
CommandAction::EnterHelpShell(v) => b::typed("enter help shell", v.pretty()),
|
CommandAction::EnterHelpShell(v) => b::typed("enter help shell", v.pretty()),
|
||||||
|
|
18
crates/nu_plugin_fetch/Cargo.toml
Normal file
18
crates/nu_plugin_fetch/Cargo.toml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
[package]
|
||||||
|
name = "nu_plugin_fetch"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Yehuda Katz <wycats@gmail.com>", "Jonathan Turner <jonathan.d.turner@gmail.com>", "Andrés N. Robalino <andres@androbtech.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
nu-protocol = { path = "../nu-protocol" }
|
||||||
|
nu-source = { path = "../nu-source" }
|
||||||
|
nu-errors = { path = "../nu-errors" }
|
||||||
|
futures-preview = { version = "=0.3.0-alpha.19", features = ["compat", "io-compat"] }
|
||||||
|
surf = "1.0.3"
|
||||||
|
url = "2.1.0"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
nu-build = { version = "0.1.0", path = "../nu-build" }
|
3
crates/nu_plugin_fetch/build.rs
Normal file
3
crates/nu_plugin_fetch/build.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
nu_build::build()
|
||||||
|
}
|
|
@ -1,128 +1,107 @@
|
||||||
use crate::commands::UnevaluatedCallInfo;
|
use futures::executor::block_on;
|
||||||
use crate::prelude::*;
|
|
||||||
use mime::Mime;
|
use mime::Mime;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{CallInfo, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
use nu_protocol::{
|
||||||
use nu_source::{AnchorLocation, Span};
|
serve_plugin, CallInfo, CommandAction, Plugin, ReturnSuccess, ReturnValue, Signature,
|
||||||
|
SyntaxShape, UntaggedValue, Value,
|
||||||
|
};
|
||||||
|
use nu_source::{AnchorLocation, Span, Tag};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use surf::mime;
|
use surf::mime;
|
||||||
|
|
||||||
pub struct Fetch;
|
struct Fetch {
|
||||||
|
path: Option<Value>,
|
||||||
|
has_raw: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl PerItemCommand for Fetch {
|
impl Fetch {
|
||||||
fn name(&self) -> &str {
|
fn new() -> Fetch {
|
||||||
"fetch"
|
Fetch {
|
||||||
|
path: None,
|
||||||
|
has_raw: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn setup(&mut self, call_info: CallInfo) -> ReturnValue {
|
||||||
Signature::build(self.name())
|
self.path = Some(
|
||||||
|
match call_info.args.nth(0).ok_or_else(|| {
|
||||||
|
ShellError::labeled_error(
|
||||||
|
"No file or directory specified",
|
||||||
|
"for command",
|
||||||
|
&call_info.name_tag,
|
||||||
|
)
|
||||||
|
})? {
|
||||||
|
file => file.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
self.has_raw = call_info.args.has("raw");
|
||||||
|
|
||||||
|
ReturnSuccess::value(UntaggedValue::nothing().into_untagged_value())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Plugin for Fetch {
|
||||||
|
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||||
|
Ok(Signature::build("fetch")
|
||||||
|
.desc("Load from a URL into a cell, convert to table if possible (avoid by appending '--raw')")
|
||||||
.required(
|
.required(
|
||||||
"path",
|
"path",
|
||||||
SyntaxShape::Path,
|
SyntaxShape::Path,
|
||||||
"the URL to fetch the contents from",
|
"the URL to fetch the contents from",
|
||||||
)
|
)
|
||||||
.switch("raw", "fetch contents as text rather than a table")
|
.switch("raw", "fetch contents as text rather than a table")
|
||||||
|
.filter())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn begin_filter(&mut self, callinfo: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
"Load from a URL into a cell, convert to table if possible (avoid by appending '--raw')"
|
Ok(vec![self.setup(callinfo)])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn filter(&mut self, value: Value) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
&self,
|
Ok(vec![block_on(fetch_helper(
|
||||||
call_info: &CallInfo,
|
&self.path.clone().unwrap(),
|
||||||
registry: &CommandRegistry,
|
self.has_raw,
|
||||||
raw_args: &RawCommandArgs,
|
value,
|
||||||
_input: Value,
|
))])
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
run(call_info, registry, raw_args)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn main() {
|
||||||
call_info: &CallInfo,
|
serve_plugin(&mut Fetch::new());
|
||||||
registry: &CommandRegistry,
|
}
|
||||||
raw_args: &RawCommandArgs,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
async fn fetch_helper(path: &Value, has_raw: bool, _row: Value) -> ReturnValue {
|
||||||
let path = match call_info.args.nth(0).ok_or_else(|| {
|
|
||||||
ShellError::labeled_error(
|
|
||||||
"No file or directory specified",
|
|
||||||
"for command",
|
|
||||||
&call_info.name_tag,
|
|
||||||
)
|
|
||||||
})? {
|
|
||||||
file => file,
|
|
||||||
};
|
|
||||||
let path_buf = path.as_path()?;
|
let path_buf = path.as_path()?;
|
||||||
let path_str = path_buf.display().to_string();
|
let path_str = path_buf.display().to_string();
|
||||||
let path_span = path.tag.span;
|
let path_span = path.tag.span;
|
||||||
let has_raw = call_info.args.has("raw");
|
|
||||||
let registry = registry.clone();
|
|
||||||
let raw_args = raw_args.clone();
|
|
||||||
|
|
||||||
let stream = async_stream! {
|
let result = fetch(&path_str, path_span).await;
|
||||||
|
|
||||||
let result = fetch(&path_str, path_span).await;
|
if let Err(e) = result {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
let (file_extension, contents, contents_tag) = result.unwrap();
|
||||||
|
|
||||||
if let Err(e) = result {
|
let file_extension = if has_raw {
|
||||||
yield Err(e);
|
None
|
||||||
return;
|
} else {
|
||||||
}
|
// If the extension could not be determined via mimetype, try to use the path
|
||||||
let (file_extension, contents, contents_tag) = result.unwrap();
|
// extension. Some file types do not declare their mimetypes (such as bson files).
|
||||||
|
file_extension.or(path_str.split('.').last().map(String::from))
|
||||||
let file_extension = if has_raw {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
// If the extension could not be determined via mimetype, try to use the path
|
|
||||||
// extension. Some file types do not declare their mimetypes (such as bson files).
|
|
||||||
file_extension.or(path_str.split('.').last().map(String::from))
|
|
||||||
};
|
|
||||||
|
|
||||||
let tagged_contents = contents.retag(&contents_tag);
|
|
||||||
|
|
||||||
if let Some(extension) = file_extension {
|
|
||||||
let command_name = format!("from-{}", extension);
|
|
||||||
if let Some(converter) = registry.get_command(&command_name) {
|
|
||||||
let new_args = RawCommandArgs {
|
|
||||||
host: raw_args.host,
|
|
||||||
ctrl_c: raw_args.ctrl_c,
|
|
||||||
shell_manager: raw_args.shell_manager,
|
|
||||||
call_info: UnevaluatedCallInfo {
|
|
||||||
args: nu_parser::hir::Call {
|
|
||||||
head: raw_args.call_info.args.head,
|
|
||||||
positional: None,
|
|
||||||
named: None,
|
|
||||||
span: Span::unknown()
|
|
||||||
},
|
|
||||||
source: raw_args.call_info.source,
|
|
||||||
name_tag: raw_args.call_info.name_tag,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut result = converter.run(new_args.with_input(vec![tagged_contents]), ®istry);
|
|
||||||
let result_vec: Vec<Result<ReturnSuccess, ShellError>> = result.drain_vec().await;
|
|
||||||
for res in result_vec {
|
|
||||||
match res {
|
|
||||||
Ok(ReturnSuccess::Value(Value { value: UntaggedValue::Table(list), ..})) => {
|
|
||||||
for l in list {
|
|
||||||
yield Ok(ReturnSuccess::Value(l));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(ReturnSuccess::Value(Value { value, .. })) => {
|
|
||||||
yield Ok(ReturnSuccess::Value(value.into_value(contents_tag.clone())));
|
|
||||||
}
|
|
||||||
x => yield x,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
yield ReturnSuccess::value(tagged_contents);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
yield ReturnSuccess::value(tagged_contents);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(stream.to_output_stream())
|
let tagged_contents = contents.retag(&contents_tag);
|
||||||
|
|
||||||
|
if let Some(extension) = file_extension {
|
||||||
|
return Ok(ReturnSuccess::Action(CommandAction::AutoConvert(
|
||||||
|
tagged_contents,
|
||||||
|
extension,
|
||||||
|
)));
|
||||||
|
} else {
|
||||||
|
return ReturnSuccess::value(tagged_contents);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn fetch(
|
pub async fn fetch(
|
21
crates/nu_plugin_post/Cargo.toml
Normal file
21
crates/nu_plugin_post/Cargo.toml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
[package]
|
||||||
|
name = "nu_plugin_post"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Yehuda Katz <wycats@gmail.com>", "Jonathan Turner <jonathan.d.turner@gmail.com>", "Andrés N. Robalino <andres@androbtech.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
nu-protocol = { path = "../nu-protocol" }
|
||||||
|
nu-source = { path = "../nu-source" }
|
||||||
|
nu-errors = { path = "../nu-errors" }
|
||||||
|
futures-preview = { version = "=0.3.0-alpha.19", features = ["compat", "io-compat"] }
|
||||||
|
surf = "1.0.3"
|
||||||
|
url = "2.1.0"
|
||||||
|
serde_json = "1.0.41"
|
||||||
|
base64 = "0.11"
|
||||||
|
num-traits = "0.2.8"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
nu-build = { version = "0.1.0", path = "../nu-build" }
|
3
crates/nu_plugin_post/build.rs
Normal file
3
crates/nu_plugin_post/build.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
nu_build::build()
|
||||||
|
}
|
|
@ -1,12 +1,13 @@
|
||||||
use crate::commands::UnevaluatedCallInfo;
|
|
||||||
use crate::prelude::*;
|
|
||||||
use base64::encode;
|
use base64::encode;
|
||||||
|
use futures::executor::block_on;
|
||||||
use mime::Mime;
|
use mime::Mime;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::{CoerceInto, ShellError};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
CallInfo, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
serve_plugin, CallInfo, CommandAction, Plugin, Primitive, ReturnSuccess, ReturnValue,
|
||||||
|
Signature, SyntaxShape, UnspannedPathMember, UntaggedValue, Value,
|
||||||
};
|
};
|
||||||
use nu_source::AnchorLocation;
|
use nu_source::{AnchorLocation, Tag, TaggedItem};
|
||||||
|
use num_traits::cast::ToPrimitive;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use surf::mime;
|
use surf::mime;
|
||||||
|
@ -16,15 +17,17 @@ pub enum HeaderKind {
|
||||||
ContentLength(String),
|
ContentLength(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Post;
|
struct Post;
|
||||||
|
impl Post {
|
||||||
impl PerItemCommand for Post {
|
fn new() -> Post {
|
||||||
fn name(&self) -> &str {
|
Post
|
||||||
"post"
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
impl Plugin for Post {
|
||||||
Signature::build(self.name())
|
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||||
|
Ok(Signature::build("post")
|
||||||
|
.desc("Post content to a url and retrieve data as a table if possible.")
|
||||||
.required("path", SyntaxShape::Any, "the URL to post to")
|
.required("path", SyntaxShape::Any, "the URL to post to")
|
||||||
.required("body", SyntaxShape::Any, "the contents of the post body")
|
.required("body", SyntaxShape::Any, "the contents of the post body")
|
||||||
.named("user", SyntaxShape::Any, "the username when authenticating")
|
.named("user", SyntaxShape::Any, "the username when authenticating")
|
||||||
|
@ -44,43 +47,38 @@ impl PerItemCommand for Post {
|
||||||
"the length of the content being posted",
|
"the length of the content being posted",
|
||||||
)
|
)
|
||||||
.switch("raw", "return values as a string instead of a table")
|
.switch("raw", "return values as a string instead of a table")
|
||||||
|
.filter())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn begin_filter(&mut self, callinfo: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
"Post content to a url and retrieve data as a table if possible."
|
Ok(vec![block_on(post_helper(callinfo))])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn filter(&mut self, _: Value) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
&self,
|
Ok(vec![])
|
||||||
call_info: &CallInfo,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
raw_args: &RawCommandArgs,
|
|
||||||
_input: Value,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
run(call_info, registry, raw_args)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn main() {
|
||||||
call_info: &CallInfo,
|
serve_plugin(&mut Post::new());
|
||||||
registry: &CommandRegistry,
|
}
|
||||||
raw_args: &RawCommandArgs,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
async fn post_helper(call_info: CallInfo) -> ReturnValue {
|
||||||
let name_tag = call_info.name_tag.clone();
|
let path = match call_info.args.nth(0).ok_or_else(|| {
|
||||||
let call_info = call_info.clone();
|
ShellError::labeled_error(
|
||||||
let path =
|
"No file or directory specified",
|
||||||
match call_info.args.nth(0).ok_or_else(|| {
|
"for command",
|
||||||
ShellError::labeled_error("No url specified", "for command", &name_tag)
|
&call_info.name_tag,
|
||||||
})? {
|
)
|
||||||
file => file.clone(),
|
})? {
|
||||||
};
|
file => file,
|
||||||
|
};
|
||||||
let path_tag = path.tag.clone();
|
let path_tag = path.tag.clone();
|
||||||
let body =
|
let body = match call_info.args.nth(1).ok_or_else(|| {
|
||||||
match call_info.args.nth(1).ok_or_else(|| {
|
ShellError::labeled_error("No body specified", "for command", &call_info.name_tag)
|
||||||
ShellError::labeled_error("No body specified", "for command", &name_tag)
|
})? {
|
||||||
})? {
|
file => file.clone(),
|
||||||
file => file.clone(),
|
};
|
||||||
};
|
|
||||||
let path_str = path.as_string()?.to_string();
|
let path_str = path.as_string()?.to_string();
|
||||||
let has_raw = call_info.args.has("raw");
|
let has_raw = call_info.args.has("raw");
|
||||||
let user = call_info
|
let user = call_info
|
||||||
|
@ -91,122 +89,32 @@ fn run(
|
||||||
.args
|
.args
|
||||||
.get("password")
|
.get("password")
|
||||||
.map(|x| x.as_string().unwrap().to_string());
|
.map(|x| x.as_string().unwrap().to_string());
|
||||||
let registry = registry.clone();
|
|
||||||
let raw_args = raw_args.clone();
|
|
||||||
|
|
||||||
let headers = get_headers(&call_info)?;
|
let headers = get_headers(&call_info)?;
|
||||||
|
|
||||||
let stream = async_stream! {
|
let (file_extension, contents, contents_tag) =
|
||||||
let (file_extension, contents, contents_tag) =
|
post(&path_str, &body, user, password, &headers, path_tag.clone())
|
||||||
post(&path_str, &body, user, password, &headers, path_tag.clone(), ®istry, &raw_args).await.unwrap();
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let file_extension = if has_raw {
|
let file_extension = if has_raw {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
// If the extension could not be determined via mimetype, try to use the path
|
// If the extension could not be determined via mimetype, try to use the path
|
||||||
// extension. Some file types do not declare their mimetypes (such as bson files).
|
// extension. Some file types do not declare their mimetypes (such as bson files).
|
||||||
file_extension.or(path_str.split('.').last().map(String::from))
|
file_extension.or(path_str.split('.').last().map(String::from))
|
||||||
};
|
|
||||||
|
|
||||||
let tagged_contents = contents.into_value(&contents_tag);
|
|
||||||
|
|
||||||
if let Some(extension) = file_extension {
|
|
||||||
let command_name = format!("from-{}", extension);
|
|
||||||
if let Some(converter) = registry.get_command(&command_name) {
|
|
||||||
let new_args = RawCommandArgs {
|
|
||||||
host: raw_args.host,
|
|
||||||
ctrl_c: raw_args.ctrl_c,
|
|
||||||
shell_manager: raw_args.shell_manager,
|
|
||||||
call_info: UnevaluatedCallInfo {
|
|
||||||
args: nu_parser::hir::Call {
|
|
||||||
head: raw_args.call_info.args.head,
|
|
||||||
positional: None,
|
|
||||||
named: None,
|
|
||||||
span: Span::unknown()
|
|
||||||
},
|
|
||||||
source: raw_args.call_info.source,
|
|
||||||
name_tag: raw_args.call_info.name_tag,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut result = converter.run(new_args.with_input(vec![tagged_contents]), ®istry);
|
|
||||||
let result_vec: Vec<Result<ReturnSuccess, ShellError>> = result.drain_vec().await;
|
|
||||||
for res in result_vec {
|
|
||||||
match res {
|
|
||||||
Ok(ReturnSuccess::Value(Value { value: UntaggedValue::Table(list), ..})) => {
|
|
||||||
for l in list {
|
|
||||||
yield Ok(ReturnSuccess::Value(l));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(ReturnSuccess::Value(Value { value, .. })) => {
|
|
||||||
yield Ok(ReturnSuccess::Value(Value { value, tag: contents_tag.clone() }));
|
|
||||||
}
|
|
||||||
x => yield x,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
yield ReturnSuccess::value(tagged_contents);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
yield ReturnSuccess::value(tagged_contents);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(stream.to_output_stream())
|
let tagged_contents = contents.into_value(&contents_tag);
|
||||||
}
|
|
||||||
|
|
||||||
fn get_headers(call_info: &CallInfo) -> Result<Vec<HeaderKind>, ShellError> {
|
if let Some(extension) = file_extension {
|
||||||
let mut headers = vec![];
|
return Ok(ReturnSuccess::Action(CommandAction::AutoConvert(
|
||||||
|
tagged_contents,
|
||||||
match extract_header_value(&call_info, "content-type") {
|
extension,
|
||||||
Ok(h) => match h {
|
)));
|
||||||
Some(ct) => headers.push(HeaderKind::ContentType(ct)),
|
} else {
|
||||||
None => {}
|
return ReturnSuccess::value(tagged_contents);
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match extract_header_value(&call_info, "content-length") {
|
|
||||||
Ok(h) => match h {
|
|
||||||
Some(cl) => headers.push(HeaderKind::ContentLength(cl)),
|
|
||||||
None => {}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extract_header_value(call_info: &CallInfo, key: &str) -> Result<Option<String>, ShellError> {
|
|
||||||
if call_info.args.has(key) {
|
|
||||||
let tagged = call_info.args.get(key);
|
|
||||||
let val = match tagged {
|
|
||||||
Some(Value {
|
|
||||||
value: UntaggedValue::Primitive(Primitive::String(s)),
|
|
||||||
..
|
|
||||||
}) => s.clone(),
|
|
||||||
Some(Value { tag, .. }) => {
|
|
||||||
return Err(ShellError::labeled_error(
|
|
||||||
format!("{} not in expected format. Expected string.", key),
|
|
||||||
"post error",
|
|
||||||
tag,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(ShellError::labeled_error(
|
|
||||||
format!("{} not in expected format. Expected string.", key),
|
|
||||||
"post error",
|
|
||||||
Tag::unknown(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return Ok(Some(val));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(None)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn post(
|
pub async fn post(
|
||||||
|
@ -216,11 +124,7 @@ pub async fn post(
|
||||||
password: Option<String>,
|
password: Option<String>,
|
||||||
headers: &Vec<HeaderKind>,
|
headers: &Vec<HeaderKind>,
|
||||||
tag: Tag,
|
tag: Tag,
|
||||||
registry: &CommandRegistry,
|
|
||||||
raw_args: &RawCommandArgs,
|
|
||||||
) -> Result<(Option<String>, UntaggedValue, Tag), ShellError> {
|
) -> Result<(Option<String>, UntaggedValue, Tag), ShellError> {
|
||||||
let registry = registry.clone();
|
|
||||||
let raw_args = raw_args.clone();
|
|
||||||
if location.starts_with("http:") || location.starts_with("https:") {
|
if location.starts_with("http:") || location.starts_with("https:") {
|
||||||
let login = match (user, password) {
|
let login = match (user, password) {
|
||||||
(Some(user), Some(password)) => Some(encode(&format!("{}:{}", user, password))),
|
(Some(user), Some(password)) => Some(encode(&format!("{}:{}", user, password))),
|
||||||
|
@ -256,59 +160,31 @@ pub async fn post(
|
||||||
s.await
|
s.await
|
||||||
}
|
}
|
||||||
Value { value, tag } => {
|
Value { value, tag } => {
|
||||||
if let Some(converter) = registry.get_command("to-json") {
|
match value_to_json_value(&value.clone().into_untagged_value()) {
|
||||||
let new_args = RawCommandArgs {
|
Ok(json_value) => match serde_json::to_string(&json_value) {
|
||||||
host: raw_args.host,
|
Ok(result_string) => {
|
||||||
ctrl_c: raw_args.ctrl_c,
|
let mut s = surf::post(location).body_string(result_string);
|
||||||
shell_manager: raw_args.shell_manager,
|
|
||||||
call_info: UnevaluatedCallInfo {
|
if let Some(login) = login {
|
||||||
args: nu_parser::hir::Call {
|
s = s.set_header("Authorization", format!("Basic {}", login));
|
||||||
head: raw_args.call_info.args.head,
|
|
||||||
positional: None,
|
|
||||||
named: None,
|
|
||||||
span: Span::unknown(),
|
|
||||||
},
|
|
||||||
source: raw_args.call_info.source,
|
|
||||||
name_tag: raw_args.call_info.name_tag,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let mut result = converter.run(
|
|
||||||
new_args.with_input(vec![value.clone().into_value(tag.clone())]),
|
|
||||||
®istry,
|
|
||||||
);
|
|
||||||
let result_vec: Vec<Result<ReturnSuccess, ShellError>> =
|
|
||||||
result.drain_vec().await;
|
|
||||||
let mut result_string = String::new();
|
|
||||||
for res in result_vec {
|
|
||||||
match res {
|
|
||||||
Ok(ReturnSuccess::Value(Value {
|
|
||||||
value: UntaggedValue::Primitive(Primitive::String(s)),
|
|
||||||
..
|
|
||||||
})) => {
|
|
||||||
result_string.push_str(&s);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(ShellError::labeled_error(
|
|
||||||
"Save could not successfully save",
|
|
||||||
"unexpected data during save",
|
|
||||||
tag,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
s.await
|
||||||
}
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"Could not automatically convert table",
|
||||||
|
"needs manual conversion",
|
||||||
|
tag,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"Could not automatically convert table",
|
||||||
|
"needs manual conversion",
|
||||||
|
tag,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut s = surf::post(location).body_string(result_string);
|
|
||||||
|
|
||||||
if let Some(login) = login {
|
|
||||||
s = s.set_header("Authorization", format!("Basic {}", login));
|
|
||||||
}
|
|
||||||
s.await
|
|
||||||
} else {
|
|
||||||
return Err(ShellError::labeled_error(
|
|
||||||
"Could not automatically convert table",
|
|
||||||
"needs manual conversion",
|
|
||||||
tag,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -458,3 +334,137 @@ pub async fn post(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME FIXME FIXME
|
||||||
|
// Ultimately, we don't want to duplicate to-json here, but we need to because there isn't an easy way to call into it, yet
|
||||||
|
pub fn value_to_json_value(v: &Value) -> Result<serde_json::Value, ShellError> {
|
||||||
|
Ok(match &v.value {
|
||||||
|
UntaggedValue::Primitive(Primitive::Boolean(b)) => serde_json::Value::Bool(*b),
|
||||||
|
UntaggedValue::Primitive(Primitive::Bytes(b)) => serde_json::Value::Number(
|
||||||
|
serde_json::Number::from(b.to_u64().expect("What about really big numbers")),
|
||||||
|
),
|
||||||
|
UntaggedValue::Primitive(Primitive::Duration(secs)) => {
|
||||||
|
serde_json::Value::Number(serde_json::Number::from(*secs))
|
||||||
|
}
|
||||||
|
UntaggedValue::Primitive(Primitive::Date(d)) => serde_json::Value::String(d.to_string()),
|
||||||
|
UntaggedValue::Primitive(Primitive::EndOfStream) => serde_json::Value::Null,
|
||||||
|
UntaggedValue::Primitive(Primitive::BeginningOfStream) => serde_json::Value::Null,
|
||||||
|
UntaggedValue::Primitive(Primitive::Decimal(f)) => serde_json::Value::Number(
|
||||||
|
serde_json::Number::from_f64(
|
||||||
|
f.to_f64().expect("TODO: What about really big decimals?"),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
UntaggedValue::Primitive(Primitive::Int(i)) => {
|
||||||
|
serde_json::Value::Number(serde_json::Number::from(CoerceInto::<i64>::coerce_into(
|
||||||
|
i.tagged(&v.tag),
|
||||||
|
"converting to JSON number",
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
UntaggedValue::Primitive(Primitive::Nothing) => serde_json::Value::Null,
|
||||||
|
UntaggedValue::Primitive(Primitive::Pattern(s)) => serde_json::Value::String(s.clone()),
|
||||||
|
UntaggedValue::Primitive(Primitive::String(s)) => serde_json::Value::String(s.clone()),
|
||||||
|
UntaggedValue::Primitive(Primitive::Line(s)) => serde_json::Value::String(s.clone()),
|
||||||
|
UntaggedValue::Primitive(Primitive::ColumnPath(path)) => serde_json::Value::Array(
|
||||||
|
path.iter()
|
||||||
|
.map(|x| match &x.unspanned {
|
||||||
|
UnspannedPathMember::String(string) => {
|
||||||
|
Ok(serde_json::Value::String(string.clone()))
|
||||||
|
}
|
||||||
|
UnspannedPathMember::Int(int) => Ok(serde_json::Value::Number(
|
||||||
|
serde_json::Number::from(CoerceInto::<i64>::coerce_into(
|
||||||
|
int.tagged(&v.tag),
|
||||||
|
"converting to JSON number",
|
||||||
|
)?),
|
||||||
|
)),
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<serde_json::Value>, ShellError>>()?,
|
||||||
|
),
|
||||||
|
UntaggedValue::Primitive(Primitive::Path(s)) => {
|
||||||
|
serde_json::Value::String(s.display().to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
UntaggedValue::Table(l) => serde_json::Value::Array(json_list(l)?),
|
||||||
|
UntaggedValue::Error(e) => return Err(e.clone()),
|
||||||
|
UntaggedValue::Block(_) => serde_json::Value::Null,
|
||||||
|
UntaggedValue::Primitive(Primitive::Binary(b)) => serde_json::Value::Array(
|
||||||
|
b.iter()
|
||||||
|
.map(|x| {
|
||||||
|
serde_json::Value::Number(serde_json::Number::from_f64(*x as f64).unwrap())
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
UntaggedValue::Row(o) => {
|
||||||
|
let mut m = serde_json::Map::new();
|
||||||
|
for (k, v) in o.entries.iter() {
|
||||||
|
m.insert(k.clone(), value_to_json_value(v)?);
|
||||||
|
}
|
||||||
|
serde_json::Value::Object(m)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn json_list(input: &Vec<Value>) -> Result<Vec<serde_json::Value>, ShellError> {
|
||||||
|
let mut out = vec![];
|
||||||
|
|
||||||
|
for value in input {
|
||||||
|
out.push(value_to_json_value(value)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_headers(call_info: &CallInfo) -> Result<Vec<HeaderKind>, ShellError> {
|
||||||
|
let mut headers = vec![];
|
||||||
|
|
||||||
|
match extract_header_value(&call_info, "content-type") {
|
||||||
|
Ok(h) => match h {
|
||||||
|
Some(ct) => headers.push(HeaderKind::ContentType(ct)),
|
||||||
|
None => {}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match extract_header_value(&call_info, "content-length") {
|
||||||
|
Ok(h) => match h {
|
||||||
|
Some(cl) => headers.push(HeaderKind::ContentLength(cl)),
|
||||||
|
None => {}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_header_value(call_info: &CallInfo, key: &str) -> Result<Option<String>, ShellError> {
|
||||||
|
if call_info.args.has(key) {
|
||||||
|
let tagged = call_info.args.get(key);
|
||||||
|
let val = match tagged {
|
||||||
|
Some(Value {
|
||||||
|
value: UntaggedValue::Primitive(Primitive::String(s)),
|
||||||
|
..
|
||||||
|
}) => s.clone(),
|
||||||
|
Some(Value { tag, .. }) => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
format!("{} not in expected format. Expected string.", key),
|
||||||
|
"post error",
|
||||||
|
tag,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
format!("{} not in expected format. Expected string.", key),
|
||||||
|
"post error",
|
||||||
|
Tag::unknown(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Ok(Some(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
|
@ -283,9 +283,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||||
whole_stream_command(Get),
|
whole_stream_command(Get),
|
||||||
whole_stream_command(Histogram),
|
whole_stream_command(Histogram),
|
||||||
per_item_command(Remove),
|
per_item_command(Remove),
|
||||||
per_item_command(Fetch),
|
|
||||||
per_item_command(Open),
|
per_item_command(Open),
|
||||||
per_item_command(Post),
|
|
||||||
per_item_command(Where),
|
per_item_command(Where),
|
||||||
per_item_command(Echo),
|
per_item_command(Echo),
|
||||||
per_item_command(Edit),
|
per_item_command(Edit),
|
||||||
|
|
|
@ -25,7 +25,6 @@ pub(crate) mod env;
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub(crate) mod evaluate_by;
|
pub(crate) mod evaluate_by;
|
||||||
pub(crate) mod exit;
|
pub(crate) mod exit;
|
||||||
pub(crate) mod fetch;
|
|
||||||
pub(crate) mod first;
|
pub(crate) mod first;
|
||||||
pub(crate) mod from_bson;
|
pub(crate) mod from_bson;
|
||||||
pub(crate) mod from_csv;
|
pub(crate) mod from_csv;
|
||||||
|
@ -58,7 +57,6 @@ pub(crate) mod open;
|
||||||
pub(crate) mod pick;
|
pub(crate) mod pick;
|
||||||
pub(crate) mod pivot;
|
pub(crate) mod pivot;
|
||||||
pub(crate) mod plugin;
|
pub(crate) mod plugin;
|
||||||
pub(crate) mod post;
|
|
||||||
pub(crate) mod prepend;
|
pub(crate) mod prepend;
|
||||||
pub(crate) mod prev;
|
pub(crate) mod prev;
|
||||||
pub(crate) mod pwd;
|
pub(crate) mod pwd;
|
||||||
|
@ -116,7 +114,6 @@ pub(crate) use env::Env;
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub(crate) use evaluate_by::EvaluateBy;
|
pub(crate) use evaluate_by::EvaluateBy;
|
||||||
pub(crate) use exit::Exit;
|
pub(crate) use exit::Exit;
|
||||||
pub(crate) use fetch::Fetch;
|
|
||||||
pub(crate) use first::First;
|
pub(crate) use first::First;
|
||||||
pub(crate) use from_bson::FromBSON;
|
pub(crate) use from_bson::FromBSON;
|
||||||
pub(crate) use from_csv::FromCSV;
|
pub(crate) use from_csv::FromCSV;
|
||||||
|
@ -150,7 +147,6 @@ pub(crate) use nth::Nth;
|
||||||
pub(crate) use open::Open;
|
pub(crate) use open::Open;
|
||||||
pub(crate) use pick::Pick;
|
pub(crate) use pick::Pick;
|
||||||
pub(crate) use pivot::Pivot;
|
pub(crate) use pivot::Pivot;
|
||||||
pub(crate) use post::Post;
|
|
||||||
pub(crate) use prepend::Prepend;
|
pub(crate) use prepend::Prepend;
|
||||||
pub(crate) use prev::Previous;
|
pub(crate) use prev::Previous;
|
||||||
pub(crate) use pwd::PWD;
|
pub(crate) use pwd::PWD;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::commands::UnevaluatedCallInfo;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use log::{log_enabled, trace};
|
use log::{log_enabled, trace};
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
|
@ -27,7 +28,7 @@ pub(crate) async fn run_internal_command(
|
||||||
context.run_command(
|
context.run_command(
|
||||||
internal_command,
|
internal_command,
|
||||||
command.name_tag.clone(),
|
command.name_tag.clone(),
|
||||||
command.args,
|
command.args.clone(),
|
||||||
&source,
|
&source,
|
||||||
objects,
|
objects,
|
||||||
)
|
)
|
||||||
|
@ -52,6 +53,44 @@ pub(crate) async fn run_internal_command(
|
||||||
context.error(err);
|
context.error(err);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
CommandAction::AutoConvert(tagged_contents, extension) => {
|
||||||
|
let contents_tag = tagged_contents.tag.clone();
|
||||||
|
let command_name = format!("from-{}", extension);
|
||||||
|
let command = command.clone();
|
||||||
|
if let Some(converter) = context.registry.get_command(&command_name) {
|
||||||
|
let new_args = RawCommandArgs {
|
||||||
|
host: context.host.clone(),
|
||||||
|
ctrl_c: context.ctrl_c.clone(),
|
||||||
|
shell_manager: context.shell_manager.clone(),
|
||||||
|
call_info: UnevaluatedCallInfo {
|
||||||
|
args: nu_parser::hir::Call {
|
||||||
|
head: command.args.head,
|
||||||
|
positional: None,
|
||||||
|
named: None,
|
||||||
|
span: Span::unknown()
|
||||||
|
},
|
||||||
|
source: source.clone(),
|
||||||
|
name_tag: command.name_tag,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut result = converter.run(new_args.with_input(vec![tagged_contents]), &context.registry);
|
||||||
|
let result_vec: Vec<Result<ReturnSuccess, ShellError>> = result.drain_vec().await;
|
||||||
|
for res in result_vec {
|
||||||
|
match res {
|
||||||
|
Ok(ReturnSuccess::Value(Value { value: UntaggedValue::Table(list), ..})) => {
|
||||||
|
for l in list {
|
||||||
|
yield Ok(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(ReturnSuccess::Value(Value { value, .. })) => {
|
||||||
|
yield Ok(value.into_value(contents_tag.clone()));
|
||||||
|
}
|
||||||
|
Err(e) => yield Err(e),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
CommandAction::EnterHelpShell(value) => {
|
CommandAction::EnterHelpShell(value) => {
|
||||||
match value {
|
match value {
|
||||||
Value {
|
Value {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use crate::commands::UnevaluatedCallInfo;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{CallInfo, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
use nu_protocol::{
|
||||||
|
CallInfo, CommandAction, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||||
|
};
|
||||||
use nu_source::{AnchorLocation, Span};
|
use nu_source::{AnchorLocation, Span};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
@ -29,19 +30,15 @@ impl PerItemCommand for Open {
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
call_info: &CallInfo,
|
call_info: &CallInfo,
|
||||||
registry: &CommandRegistry,
|
_registry: &CommandRegistry,
|
||||||
raw_args: &RawCommandArgs,
|
raw_args: &RawCommandArgs,
|
||||||
_input: Value,
|
_input: Value,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
run(call_info, registry, raw_args)
|
run(call_info, raw_args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(call_info: &CallInfo, raw_args: &RawCommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
call_info: &CallInfo,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
raw_args: &RawCommandArgs,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let shell_manager = &raw_args.shell_manager;
|
let shell_manager = &raw_args.shell_manager;
|
||||||
let cwd = PathBuf::from(shell_manager.path());
|
let cwd = PathBuf::from(shell_manager.path());
|
||||||
let full_path = PathBuf::from(cwd);
|
let full_path = PathBuf::from(cwd);
|
||||||
|
@ -58,8 +55,6 @@ fn run(
|
||||||
let path_str = path_buf.display().to_string();
|
let path_str = path_buf.display().to_string();
|
||||||
let path_span = path.tag.span;
|
let path_span = path.tag.span;
|
||||||
let has_raw = call_info.args.has("raw");
|
let has_raw = call_info.args.has("raw");
|
||||||
let registry = registry.clone();
|
|
||||||
let raw_args = raw_args.clone();
|
|
||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
|
|
||||||
|
@ -82,41 +77,7 @@ fn run(
|
||||||
let tagged_contents = contents.into_value(&contents_tag);
|
let tagged_contents = contents.into_value(&contents_tag);
|
||||||
|
|
||||||
if let Some(extension) = file_extension {
|
if let Some(extension) = file_extension {
|
||||||
let command_name = format!("from-{}", extension);
|
yield Ok(ReturnSuccess::Action(CommandAction::AutoConvert(tagged_contents, extension)))
|
||||||
if let Some(converter) = registry.get_command(&command_name) {
|
|
||||||
let new_args = RawCommandArgs {
|
|
||||||
host: raw_args.host,
|
|
||||||
ctrl_c: raw_args.ctrl_c,
|
|
||||||
shell_manager: raw_args.shell_manager,
|
|
||||||
call_info: UnevaluatedCallInfo {
|
|
||||||
args: nu_parser::hir::Call {
|
|
||||||
head: raw_args.call_info.args.head,
|
|
||||||
positional: None,
|
|
||||||
named: None,
|
|
||||||
span: Span::unknown()
|
|
||||||
},
|
|
||||||
source: raw_args.call_info.source,
|
|
||||||
name_tag: raw_args.call_info.name_tag,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut result = converter.run(new_args.with_input(vec![tagged_contents]), ®istry);
|
|
||||||
let result_vec: Vec<Result<ReturnSuccess, ShellError>> = result.drain_vec().await;
|
|
||||||
for res in result_vec {
|
|
||||||
match res {
|
|
||||||
Ok(ReturnSuccess::Value(Value { value: UntaggedValue::Table(list), ..})) => {
|
|
||||||
for l in list {
|
|
||||||
yield Ok(ReturnSuccess::Value(l));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(ReturnSuccess::Value(Value { value, .. })) => {
|
|
||||||
yield Ok(ReturnSuccess::Value(Value { value, tag: contents_tag.clone() }));
|
|
||||||
}
|
|
||||||
x => yield x,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
yield ReturnSuccess::value(tagged_contents);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
yield ReturnSuccess::value(tagged_contents);
|
yield ReturnSuccess::value(tagged_contents);
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,8 +71,8 @@ impl CommandRegistry {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
registry: CommandRegistry,
|
pub registry: CommandRegistry,
|
||||||
host: Arc<Mutex<Box<dyn Host>>>,
|
pub host: Arc<Mutex<Box<dyn Host>>>,
|
||||||
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
|
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
|
||||||
pub ctrl_c: Arc<AtomicBool>,
|
pub ctrl_c: Arc<AtomicBool>,
|
||||||
pub(crate) shell_manager: ShellManager,
|
pub(crate) shell_manager: ShellManager,
|
||||||
|
|
Loading…
Reference in a new issue