diff --git a/crates/nu_plugin_fetch/src/main.rs b/crates/nu_plugin_fetch/src/main.rs index 830043dfe..6192b18bd 100644 --- a/crates/nu_plugin_fetch/src/main.rs +++ b/crates/nu_plugin_fetch/src/main.rs @@ -56,7 +56,8 @@ impl Plugin for Fetch { } fn begin_filter(&mut self, callinfo: CallInfo) -> Result, ShellError> { - Ok(vec![self.setup(callinfo)]) + self.setup(callinfo)?; + Ok(vec![]) } fn filter(&mut self, value: Value) -> Result, ShellError> { @@ -72,9 +73,18 @@ fn main() { serve_plugin(&mut Fetch::new()); } -async fn fetch_helper(path: &Value, has_raw: bool, _row: Value) -> ReturnValue { +async fn fetch_helper(path: &Value, has_raw: bool, row: Value) -> ReturnValue { let path_buf = path.as_path()?; let path_str = path_buf.display().to_string(); + + //FIXME: this is a workaround because plugins don't yet support per-item iteration + let path_str = if path_str == "$it" { + let path_buf = row.as_path()?; + path_buf.display().to_string() + } else { + path_str + }; + let path_span = path.tag.span; let result = fetch(&path_str, path_span).await; diff --git a/crates/nu_plugin_post/src/main.rs b/crates/nu_plugin_post/src/main.rs index ebb0bf17c..4b379db0d 100644 --- a/crates/nu_plugin_post/src/main.rs +++ b/crates/nu_plugin_post/src/main.rs @@ -12,15 +12,67 @@ use std::path::PathBuf; use std::str::FromStr; use surf::mime; +#[derive(Clone)] pub enum HeaderKind { ContentType(String), ContentLength(String), } -struct Post; +struct Post { + path: Option, + has_raw: bool, + body: Option, + user: Option, + password: Option, + headers: Vec, +} + impl Post { fn new() -> Post { - Post + Post { + path: None, + has_raw: false, + body: None, + user: None, + password: None, + headers: vec![], + } + } + + fn setup(&mut self, call_info: CallInfo) -> ReturnValue { + 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"); + + self.body = match call_info.args.nth(1).ok_or_else(|| { + ShellError::labeled_error("No body specified", "for command", &call_info.name_tag) + })? { + file => Some(file.clone()), + }; + + self.user = call_info + .args + .get("user") + .map(|x| x.as_string().unwrap().to_string()); + + self.password = call_info + .args + .get("password") + .map(|x| x.as_string().unwrap().to_string()); + + self.headers = get_headers(&call_info)?; + + ReturnSuccess::value(UntaggedValue::nothing().into_untagged_value()) } } @@ -50,12 +102,21 @@ impl Plugin for Post { .filter()) } - fn begin_filter(&mut self, callinfo: CallInfo) -> Result, ShellError> { - Ok(vec![block_on(post_helper(callinfo))]) + fn begin_filter(&mut self, call_info: CallInfo) -> Result, ShellError> { + self.setup(call_info)?; + Ok(vec![]) } - fn filter(&mut self, _: Value) -> Result, ShellError> { - Ok(vec![]) + fn filter(&mut self, row: Value) -> Result, ShellError> { + Ok(vec![block_on(post_helper( + &self.path.clone().unwrap(), + self.has_raw, + &self.body.clone().unwrap(), + self.user.clone(), + self.password.clone(), + &self.headers.clone(), + row, + ))]) } } @@ -63,7 +124,16 @@ fn main() { serve_plugin(&mut Post::new()); } -async fn post_helper(call_info: CallInfo) -> ReturnValue { +async fn post_helper( + path: &Value, + has_raw: bool, + body: &Value, + user: Option, + password: Option, + headers: &[HeaderKind], + row: Value, +) -> ReturnValue { + /* let path = match call_info.args.nth(0).ok_or_else(|| { ShellError::labeled_error( "No file or directory specified", @@ -80,6 +150,7 @@ async fn post_helper(call_info: CallInfo) -> ReturnValue { file => file.clone(), }; let path_str = path.as_string()?.to_string(); + let has_raw = call_info.args.has("raw"); let user = call_info .args @@ -91,6 +162,28 @@ async fn post_helper(call_info: CallInfo) -> ReturnValue { .map(|x| x.as_string().unwrap().to_string()); let headers = get_headers(&call_info)?; + */ + let path_tag = path.tag.clone(); + let path_str = path.as_string()?.to_string(); + + //FIXME: this is a workaround because plugins don't yet support per-item iteration + let path_str = if path_str == "$it" { + let path_buf = row.as_path()?; + path_buf.display().to_string() + } else { + path_str + }; + + //FIXME: this is a workaround because plugins don't yet support per-item iteration + let body = if let Ok(x) = body.as_string() { + if x == "$it" { + &row + } else { + body + } + } else { + body + }; let (file_extension, contents, contents_tag) = post(&path_str, &body, user, password, &headers, path_tag.clone()) diff --git a/src/commands/command.rs b/src/commands/command.rs index 691a90bf1..ef5443a3e 100644 --- a/src/commands/command.rs +++ b/src/commands/command.rs @@ -117,6 +117,26 @@ impl CommandArgs { )) } + pub fn evaluate_once_with_scope( + self, + registry: &CommandRegistry, + scope: &Scope, + ) -> Result { + let host = self.host.clone(); + let ctrl_c = self.ctrl_c.clone(); + let shell_manager = self.shell_manager.clone(); + let input = self.input; + let call_info = self.call_info.evaluate(registry, scope)?; + + Ok(EvaluatedWholeStreamCommandArgs::new( + host, + ctrl_c, + shell_manager, + call_info, + input, + )) + } + pub fn source(&self) -> Text { self.call_info.source.clone() } diff --git a/src/commands/plugin.rs b/src/commands/plugin.rs index c0051731f..9bb693bd0 100644 --- a/src/commands/plugin.rs +++ b/src/commands/plugin.rs @@ -3,7 +3,7 @@ use crate::prelude::*; use derive_new::new; use log::trace; use nu_errors::ShellError; -use nu_protocol::{Primitive, ReturnSuccess, ReturnValue, Signature, UntaggedValue, Value}; +use nu_protocol::{Primitive, ReturnSuccess, ReturnValue, Scope, Signature, UntaggedValue, Value}; use serde::{self, Deserialize, Serialize}; use std::io::prelude::*; use std::io::BufReader; @@ -71,7 +71,10 @@ pub fn filter_plugin( ) -> Result { trace!("filter_plugin :: {}", path); - let args = args.evaluate_once(registry)?; + let args = args.evaluate_once_with_scope( + registry, + &Scope::it_value(UntaggedValue::string("$it").into_untagged_value()), + )?; let mut child = std::process::Command::new(path) .stdin(std::process::Stdio::piped())