mirror of
https://github.com/nushell/nushell.git
synced 2024-11-22 08:23:24 +01:00
Remove --encoding
argument during register plugin (#6486)
* first implement new plugin protocol core logic * fix debug body construct * fix output message from plugin * finish plugin commands calling * fix tests and adjust plugin_custom_value call * fmt code * fmt code, fix clippy * add FIXME comment * change from FIXME to TODO
This commit is contained in:
parent
80624267fd
commit
aa92141ad7
@ -21,12 +21,6 @@ impl Command for Register {
|
|||||||
SyntaxShape::Filepath,
|
SyntaxShape::Filepath,
|
||||||
"path of executable for plugin",
|
"path of executable for plugin",
|
||||||
)
|
)
|
||||||
.required_named(
|
|
||||||
"encoding",
|
|
||||||
SyntaxShape::String,
|
|
||||||
"Encoding used to communicate with plugin. Options: [json, msgpack]",
|
|
||||||
Some('e'),
|
|
||||||
)
|
|
||||||
.optional(
|
.optional(
|
||||||
"signature",
|
"signature",
|
||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
@ -64,12 +58,12 @@ impl Command for Register {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Register `nu_plugin_query` plugin from ~/.cargo/bin/ dir",
|
description: "Register `nu_plugin_query` plugin from ~/.cargo/bin/ dir",
|
||||||
example: r#"register -e json ~/.cargo/bin/nu_plugin_query"#,
|
example: r#"register ~/.cargo/bin/nu_plugin_query"#,
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Register `nu_plugin_query` plugin from `nu -c`(plugin will be available in that nu session only)",
|
description: "Register `nu_plugin_query` plugin from `nu -c`(plugin will be available in that nu session only)",
|
||||||
example: r#"let plugin = ((which nu).path.0 | path dirname | path join 'nu_plugin_query'); nu -c $'register -e json ($plugin); version'"#,
|
example: r#"let plugin = ((which nu).path.0 | path dirname | path join 'nu_plugin_query'); nu -c $'register ($plugin); version'"#,
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -3027,7 +3027,7 @@ pub fn parse_register(
|
|||||||
spans: &[Span],
|
spans: &[Span],
|
||||||
expand_aliases_denylist: &[usize],
|
expand_aliases_denylist: &[usize],
|
||||||
) -> (Pipeline, Option<ParseError>) {
|
) -> (Pipeline, Option<ParseError>) {
|
||||||
use nu_plugin::{get_signature, EncodingType, PluginDeclaration};
|
use nu_plugin::{get_signature, PluginDeclaration};
|
||||||
use nu_protocol::{engine::Stack, Signature};
|
use nu_protocol::{engine::Stack, Signature};
|
||||||
|
|
||||||
let cwd = working_set.get_cwd();
|
let cwd = working_set.get_cwd();
|
||||||
@ -3120,22 +3120,7 @@ pub fn parse_register(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.expect("required positional has being checked")
|
.expect("required positional has being checked");
|
||||||
.and_then(|path| {
|
|
||||||
call.get_flag_expr("encoding")
|
|
||||||
.map(|expr| {
|
|
||||||
EncodingType::try_from_bytes(working_set.get_span_contents(expr.span))
|
|
||||||
.ok_or_else(|| {
|
|
||||||
ParseError::IncorrectValue(
|
|
||||||
"wrong encoding".into(),
|
|
||||||
expr.span,
|
|
||||||
"Encodings available: json, and msgpack".into(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.expect("required named has being checked")
|
|
||||||
.map(|encoding| (path, encoding))
|
|
||||||
});
|
|
||||||
|
|
||||||
// Signature is an optional value from the call and will be used to decide if
|
// Signature is an optional value from the call and will be used to decide if
|
||||||
// the plugin is called to get the signatures or to use the given signature
|
// the plugin is called to get the signatures or to use the given signature
|
||||||
@ -3196,7 +3181,7 @@ pub fn parse_register(
|
|||||||
let current_envs =
|
let current_envs =
|
||||||
nu_engine::env::env_to_strings(working_set.permanent_state, &stack).unwrap_or_default();
|
nu_engine::env::env_to_strings(working_set.permanent_state, &stack).unwrap_or_default();
|
||||||
let error = match signature {
|
let error = match signature {
|
||||||
Some(signature) => arguments.and_then(|(path, encoding)| {
|
Some(signature) => arguments.and_then(|path| {
|
||||||
// restrict plugin file name starts with `nu_plugin_`
|
// restrict plugin file name starts with `nu_plugin_`
|
||||||
let f_name = path
|
let f_name = path
|
||||||
.file_name()
|
.file_name()
|
||||||
@ -3204,7 +3189,7 @@ pub fn parse_register(
|
|||||||
|
|
||||||
if let Some(true) = f_name {
|
if let Some(true) = f_name {
|
||||||
signature.map(|signature| {
|
signature.map(|signature| {
|
||||||
let plugin_decl = PluginDeclaration::new(path, signature, encoding, shell);
|
let plugin_decl = PluginDeclaration::new(path, signature, shell);
|
||||||
working_set.add_decl(Box::new(plugin_decl));
|
working_set.add_decl(Box::new(plugin_decl));
|
||||||
working_set.mark_plugins_file_dirty();
|
working_set.mark_plugins_file_dirty();
|
||||||
})
|
})
|
||||||
@ -3212,14 +3197,14 @@ pub fn parse_register(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
None => arguments.and_then(|(path, encoding)| {
|
None => arguments.and_then(|path| {
|
||||||
// restrict plugin file name starts with `nu_plugin_`
|
// restrict plugin file name starts with `nu_plugin_`
|
||||||
let f_name = path
|
let f_name = path
|
||||||
.file_name()
|
.file_name()
|
||||||
.map(|s| s.to_string_lossy().starts_with("nu_plugin_"));
|
.map(|s| s.to_string_lossy().starts_with("nu_plugin_"));
|
||||||
|
|
||||||
if let Some(true) = f_name {
|
if let Some(true) = f_name {
|
||||||
get_signature(path.as_path(), &encoding, &shell, ¤t_envs)
|
get_signature(path.as_path(), &shell, ¤t_envs)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
ParseError::LabeledError(
|
ParseError::LabeledError(
|
||||||
"Error getting signatures".into(),
|
"Error getting signatures".into(),
|
||||||
@ -3231,12 +3216,8 @@ pub fn parse_register(
|
|||||||
for signature in signatures {
|
for signature in signatures {
|
||||||
// create plugin command declaration (need struct impl Command)
|
// create plugin command declaration (need struct impl Command)
|
||||||
// store declaration in working set
|
// store declaration in working set
|
||||||
let plugin_decl = PluginDeclaration::new(
|
let plugin_decl =
|
||||||
path.clone(),
|
PluginDeclaration::new(path.clone(), signature, shell.clone());
|
||||||
signature,
|
|
||||||
encoding.clone(),
|
|
||||||
shell.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
working_set.add_decl(Box::new(plugin_decl));
|
working_set.add_decl(Box::new(plugin_decl));
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{EncodingType, EvaluatedCall};
|
use crate::EvaluatedCall;
|
||||||
|
|
||||||
use super::{call_plugin, create_command};
|
use super::{call_plugin, create_command, get_plugin_encoding};
|
||||||
use crate::protocol::{
|
use crate::protocol::{
|
||||||
CallInfo, CallInput, PluginCall, PluginCustomValue, PluginData, PluginResponse,
|
CallInfo, CallInput, PluginCall, PluginCustomValue, PluginData, PluginResponse,
|
||||||
};
|
};
|
||||||
@ -16,21 +16,14 @@ pub struct PluginDeclaration {
|
|||||||
signature: Signature,
|
signature: Signature,
|
||||||
filename: PathBuf,
|
filename: PathBuf,
|
||||||
shell: Option<PathBuf>,
|
shell: Option<PathBuf>,
|
||||||
encoding: EncodingType,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PluginDeclaration {
|
impl PluginDeclaration {
|
||||||
pub fn new(
|
pub fn new(filename: PathBuf, signature: Signature, shell: Option<PathBuf>) -> Self {
|
||||||
filename: PathBuf,
|
|
||||||
signature: Signature,
|
|
||||||
encoding: EncodingType,
|
|
||||||
shell: Option<PathBuf>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
name: signature.name.clone(),
|
name: signature.name.clone(),
|
||||||
signature,
|
signature,
|
||||||
filename,
|
filename,
|
||||||
encoding,
|
|
||||||
shell,
|
shell,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,17 +104,27 @@ impl Command for PluginDeclaration {
|
|||||||
input,
|
input,
|
||||||
});
|
});
|
||||||
|
|
||||||
let response =
|
let encoding = {
|
||||||
call_plugin(&mut child, plugin_call, &self.encoding, call.head).map_err(|err| {
|
let stdout_reader = match &mut child.stdout {
|
||||||
let decl = engine_state.get_decl(call.decl_id);
|
Some(out) => out,
|
||||||
ShellError::GenericError(
|
None => {
|
||||||
format!("Unable to decode call for {}", decl.name()),
|
return Err(ShellError::PluginFailedToLoad(
|
||||||
err.to_string(),
|
"Plugin missing stdout reader".into(),
|
||||||
Some(call.head),
|
))
|
||||||
None,
|
}
|
||||||
Vec::new(),
|
};
|
||||||
)
|
get_plugin_encoding(stdout_reader)?
|
||||||
});
|
};
|
||||||
|
let response = call_plugin(&mut child, plugin_call, &encoding, call.head).map_err(|err| {
|
||||||
|
let decl = engine_state.get_decl(call.decl_id);
|
||||||
|
ShellError::GenericError(
|
||||||
|
format!("Unable to decode call for {}", decl.name()),
|
||||||
|
err.to_string(),
|
||||||
|
Some(call.head),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
let pipeline_data = match response {
|
let pipeline_data = match response {
|
||||||
Ok(PluginResponse::Value(value)) => {
|
Ok(PluginResponse::Value(value)) => {
|
||||||
@ -134,7 +137,6 @@ impl Command for PluginDeclaration {
|
|||||||
data: plugin_data.data,
|
data: plugin_data.data,
|
||||||
filename: self.filename.clone(),
|
filename: self.filename.clone(),
|
||||||
shell: self.shell.clone(),
|
shell: self.shell.clone(),
|
||||||
encoding: self.encoding.clone(),
|
|
||||||
source: engine_state.get_decl(call.decl_id).name().to_owned(),
|
source: engine_state.get_decl(call.decl_id).name().to_owned(),
|
||||||
}),
|
}),
|
||||||
span: plugin_data.span,
|
span: plugin_data.span,
|
||||||
@ -158,7 +160,7 @@ impl Command for PluginDeclaration {
|
|||||||
pipeline_data
|
pipeline_data
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_plugin(&self) -> Option<(&PathBuf, &str, &Option<PathBuf>)> {
|
fn is_plugin(&self) -> Option<(&PathBuf, &Option<PathBuf>)> {
|
||||||
Some((&self.filename, self.encoding.to_str(), &self.shell))
|
Some((&self.filename, &self.shell))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,9 @@ use crate::protocol::{CallInput, LabeledError, PluginCall, PluginData, PluginRes
|
|||||||
use crate::EncodingType;
|
use crate::EncodingType;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::io::BufReader;
|
use std::io::{BufReader, Read, Write as WriteTrait};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::{Child, Command as CommandSys, Stdio};
|
use std::process::{Child, ChildStdout, Command as CommandSys, Stdio};
|
||||||
|
|
||||||
use nu_protocol::{CustomValue, ShellError, Span};
|
use nu_protocol::{CustomValue, ShellError, Span};
|
||||||
use nu_protocol::{Signature, Value};
|
use nu_protocol::{Signature, Value};
|
||||||
@ -116,7 +116,6 @@ pub(crate) fn call_plugin(
|
|||||||
|
|
||||||
pub fn get_signature(
|
pub fn get_signature(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
encoding: &EncodingType,
|
|
||||||
shell: &Option<PathBuf>,
|
shell: &Option<PathBuf>,
|
||||||
current_envs: &HashMap<String, String>,
|
current_envs: &HashMap<String, String>,
|
||||||
) -> Result<Vec<Signature>, ShellError> {
|
) -> Result<Vec<Signature>, ShellError> {
|
||||||
@ -127,32 +126,34 @@ pub fn get_signature(
|
|||||||
ShellError::PluginFailedToLoad(format!("Error spawning child process: {}", err))
|
ShellError::PluginFailedToLoad(format!("Error spawning child process: {}", err))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
let mut stdin_writer = child
|
||||||
|
.stdin
|
||||||
|
.take()
|
||||||
|
.ok_or_else(|| ShellError::PluginFailedToLoad("plugin missing stdin writer".into()))?;
|
||||||
|
let mut stdout_reader = child
|
||||||
|
.stdout
|
||||||
|
.take()
|
||||||
|
.ok_or_else(|| ShellError::PluginFailedToLoad("Plugin missing stdout reader".into()))?;
|
||||||
|
let encoding = get_plugin_encoding(&mut stdout_reader)?;
|
||||||
|
|
||||||
// Create message to plugin to indicate that signature is required and
|
// Create message to plugin to indicate that signature is required and
|
||||||
// send call to plugin asking for signature
|
// send call to plugin asking for signature
|
||||||
if let Some(mut stdin_writer) = child.stdin.take() {
|
let encoding_clone = encoding.clone();
|
||||||
let encoding_clone = encoding.clone();
|
std::thread::spawn(move || {
|
||||||
std::thread::spawn(move || {
|
encoding_clone.encode_call(&PluginCall::Signature, &mut stdin_writer)
|
||||||
encoding_clone.encode_call(&PluginCall::Signature, &mut stdin_writer)
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// deserialize response from plugin to extract the signature
|
// deserialize response from plugin to extract the signature
|
||||||
let signatures = if let Some(stdout_reader) = &mut child.stdout {
|
let reader = stdout_reader;
|
||||||
let reader = stdout_reader;
|
let mut buf_read = BufReader::with_capacity(OUTPUT_BUFFER_SIZE, reader);
|
||||||
let mut buf_read = BufReader::with_capacity(OUTPUT_BUFFER_SIZE, reader);
|
let response = encoding.decode_response(&mut buf_read)?;
|
||||||
let response = encoding.decode_response(&mut buf_read)?;
|
|
||||||
|
|
||||||
match response {
|
let signatures = match response {
|
||||||
PluginResponse::Signature(sign) => Ok(sign),
|
PluginResponse::Signature(sign) => Ok(sign),
|
||||||
PluginResponse::Error(err) => Err(err.into()),
|
PluginResponse::Error(err) => Err(err.into()),
|
||||||
_ => Err(ShellError::PluginFailedToLoad(
|
_ => Err(ShellError::PluginFailedToLoad(
|
||||||
"Plugin missing signature".into(),
|
"Plugin missing signature".into(),
|
||||||
)),
|
)),
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(ShellError::PluginFailedToLoad(
|
|
||||||
"Plugin missing stdout reader".into(),
|
|
||||||
))
|
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
match child.wait() {
|
match child.wait() {
|
||||||
@ -196,6 +197,24 @@ pub fn serve_plugin(plugin: &mut impl Plugin, encoder: impl PluginEncoder) {
|
|||||||
std::process::exit(0)
|
std::process::exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tell nushell encoding.
|
||||||
|
//
|
||||||
|
// 1 byte
|
||||||
|
// encoding format: | content-length | content |
|
||||||
|
{
|
||||||
|
let mut stdout = std::io::stdout();
|
||||||
|
let encoding = encoder.name();
|
||||||
|
let length = encoding.len() as u8;
|
||||||
|
let mut encoding_content: Vec<u8> = encoding.as_bytes().to_vec();
|
||||||
|
encoding_content.insert(0, length);
|
||||||
|
stdout
|
||||||
|
.write_all(&encoding_content)
|
||||||
|
.expect("Failed to tell nushell my encoding");
|
||||||
|
stdout
|
||||||
|
.flush()
|
||||||
|
.expect("Failed to tell nushell my encoding when flushing stdout");
|
||||||
|
}
|
||||||
|
|
||||||
let mut stdin_buf = BufReader::with_capacity(OUTPUT_BUFFER_SIZE, std::io::stdin());
|
let mut stdin_buf = BufReader::with_capacity(OUTPUT_BUFFER_SIZE, std::io::stdin());
|
||||||
let plugin_call = encoder.decode_call(&mut stdin_buf);
|
let plugin_call = encoder.decode_call(&mut stdin_buf);
|
||||||
|
|
||||||
@ -332,3 +351,22 @@ fn print_help(plugin: &mut impl Plugin, encoder: impl PluginEncoder) {
|
|||||||
|
|
||||||
println!("{}", help)
|
println!("{}", help)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_plugin_encoding(child_stdout: &mut ChildStdout) -> Result<EncodingType, ShellError> {
|
||||||
|
let mut length_buf = [0u8; 1];
|
||||||
|
child_stdout.read_exact(&mut length_buf).map_err(|e| {
|
||||||
|
ShellError::PluginFailedToLoad(format!("unable to get encoding from plugin: {e}"))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let mut buf = vec![0u8; length_buf[0] as usize];
|
||||||
|
child_stdout.read_exact(&mut buf).map_err(|e| {
|
||||||
|
ShellError::PluginFailedToLoad(format!("unable to get encoding from plugin: {e}"))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
EncodingType::try_from_bytes(&buf).ok_or_else(|| {
|
||||||
|
let encoding_for_debug = String::from_utf8_lossy(&buf);
|
||||||
|
ShellError::PluginFailedToLoad(format!(
|
||||||
|
"get unsupported plugin encoding: {encoding_for_debug}"
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -3,10 +3,7 @@ use std::path::PathBuf;
|
|||||||
use nu_protocol::{CustomValue, ShellError, Value};
|
use nu_protocol::{CustomValue, ShellError, Value};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::plugin::{call_plugin, create_command, get_plugin_encoding};
|
||||||
plugin::{call_plugin, create_command},
|
|
||||||
EncodingType,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{PluginCall, PluginData, PluginResponse};
|
use super::{PluginCall, PluginData, PluginResponse};
|
||||||
|
|
||||||
@ -32,8 +29,6 @@ pub struct PluginCustomValue {
|
|||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub shell: Option<PathBuf>,
|
pub shell: Option<PathBuf>,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub encoding: EncodingType,
|
|
||||||
#[serde(skip)]
|
|
||||||
pub source: String,
|
pub source: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,8 +67,19 @@ impl CustomValue for PluginCustomValue {
|
|||||||
data: self.data.clone(),
|
data: self.data.clone(),
|
||||||
span,
|
span,
|
||||||
});
|
});
|
||||||
|
let encoding = {
|
||||||
|
let stdout_reader = match &mut child.stdout {
|
||||||
|
Some(out) => out,
|
||||||
|
None => {
|
||||||
|
return Err(ShellError::PluginFailedToLoad(
|
||||||
|
"Plugin missing stdout reader".into(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
get_plugin_encoding(stdout_reader)?
|
||||||
|
};
|
||||||
|
|
||||||
let response = call_plugin(&mut child, plugin_call, &self.encoding, span).map_err(|err| {
|
let response = call_plugin(&mut child, plugin_call, &encoding, span).map_err(|err| {
|
||||||
ShellError::GenericError(
|
ShellError::GenericError(
|
||||||
format!(
|
format!(
|
||||||
"Unable to decode call for {} to get base value",
|
"Unable to decode call for {} to get base value",
|
||||||
|
@ -7,7 +7,7 @@ pub struct JsonSerializer;
|
|||||||
|
|
||||||
impl PluginEncoder for JsonSerializer {
|
impl PluginEncoder for JsonSerializer {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"Json Serializer"
|
"json"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_call(
|
fn encode_call(
|
||||||
|
@ -6,7 +6,7 @@ pub struct MsgPackSerializer;
|
|||||||
|
|
||||||
impl PluginEncoder for MsgPackSerializer {
|
impl PluginEncoder for MsgPackSerializer {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"MsgPack Serializer"
|
"msgpack"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_call(
|
fn encode_call(
|
||||||
@ -23,7 +23,7 @@ impl PluginEncoder for MsgPackSerializer {
|
|||||||
reader: &mut impl std::io::BufRead,
|
reader: &mut impl std::io::BufRead,
|
||||||
) -> Result<crate::protocol::PluginCall, nu_protocol::ShellError> {
|
) -> Result<crate::protocol::PluginCall, nu_protocol::ShellError> {
|
||||||
rmp_serde::from_read(reader)
|
rmp_serde::from_read(reader)
|
||||||
.map_err(|err| ShellError::PluginFailedToEncode(err.to_string()))
|
.map_err(|err| ShellError::PluginFailedToDecode(err.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_response(
|
fn encode_response(
|
||||||
@ -40,7 +40,7 @@ impl PluginEncoder for MsgPackSerializer {
|
|||||||
reader: &mut impl std::io::BufRead,
|
reader: &mut impl std::io::BufRead,
|
||||||
) -> Result<PluginResponse, ShellError> {
|
) -> Result<PluginResponse, ShellError> {
|
||||||
rmp_serde::from_read(reader)
|
rmp_serde::from_read(reader)
|
||||||
.map_err(|err| ShellError::PluginFailedToEncode(err.to_string()))
|
.map_err(|err| ShellError::PluginFailedToDecode(err.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,9 +57,8 @@ pub trait Command: Send + Sync + CommandClone {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is a plugin command (returns plugin's path, encoding and type of shell
|
// Is a plugin command (returns plugin's path, type of shell if the declaration is a plugin)
|
||||||
// if the declaration is a plugin)
|
fn is_plugin(&self) -> Option<(&PathBuf, &Option<PathBuf>)> {
|
||||||
fn is_plugin(&self) -> Option<(&PathBuf, &str, &Option<PathBuf>)> {
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,8 +366,7 @@ impl EngineState {
|
|||||||
self.plugin_decls().try_for_each(|decl| {
|
self.plugin_decls().try_for_each(|decl| {
|
||||||
// A successful plugin registration already includes the plugin filename
|
// A successful plugin registration already includes the plugin filename
|
||||||
// No need to check the None option
|
// No need to check the None option
|
||||||
let (path, encoding, shell) =
|
let (path, shell) = decl.is_plugin().expect("plugin should have file name");
|
||||||
decl.is_plugin().expect("plugin should have file name");
|
|
||||||
let mut file_name = path
|
let mut file_name = path
|
||||||
.to_str()
|
.to_str()
|
||||||
.expect("path was checked during registration as a str")
|
.expect("path was checked during registration as a str")
|
||||||
@ -394,14 +393,10 @@ impl EngineState {
|
|||||||
None => "".into(),
|
None => "".into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Each signature is stored in the plugin file with the required
|
// Each signature is stored in the plugin file with the shell and signature
|
||||||
// encoding, shell and signature
|
|
||||||
// This information will be used when loading the plugin
|
// This information will be used when loading the plugin
|
||||||
// information when nushell starts
|
// information when nushell starts
|
||||||
format!(
|
format!("register {} {} {}\n\n", file_name, shell_str, signature)
|
||||||
"register {} -e {} {} {}\n\n",
|
|
||||||
file_name, encoding, shell_str, signature
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.map_err(|err| ShellError::PluginFailedToLoad(err.to_string()))
|
.map_err(|err| ShellError::PluginFailedToLoad(err.to_string()))
|
||||||
.and_then(|line| {
|
.and_then(|line| {
|
||||||
|
@ -225,11 +225,11 @@ macro_rules! with_exe {
|
|||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! nu_with_plugins {
|
macro_rules! nu_with_plugins {
|
||||||
(cwd: $cwd:expr, plugins: [$(($format:expr, $plugin_name:expr)),+$(,)?], $command:expr) => {{
|
(cwd: $cwd:expr, plugins: [$(($plugin_name:expr)),+$(,)?], $command:expr) => {{
|
||||||
nu_with_plugins!($cwd, [$(($format, $plugin_name)),+], $command)
|
nu_with_plugins!($cwd, [$(("", $plugin_name)),+], $command)
|
||||||
}};
|
}};
|
||||||
(cwd: $cwd:expr, plugin: ($format:expr, $plugin_name:expr), $command:expr) => {{
|
(cwd: $cwd:expr, plugin: ($plugin_name:expr), $command:expr) => {{
|
||||||
nu_with_plugins!($cwd, [($format, $plugin_name)], $command)
|
nu_with_plugins!($cwd, [("", $plugin_name)], $command)
|
||||||
}};
|
}};
|
||||||
|
|
||||||
($cwd:expr, [$(($format:expr, $plugin_name:expr)),+$(,)?], $command:expr) => {{
|
($cwd:expr, [$(($format:expr, $plugin_name:expr)),+$(,)?], $command:expr) => {{
|
||||||
@ -254,8 +254,10 @@ macro_rules! nu_with_plugins {
|
|||||||
|
|
||||||
$($crate::commands::ensure_binary_present($plugin_name);)+
|
$($crate::commands::ensure_binary_present($plugin_name);)+
|
||||||
|
|
||||||
|
// TODO: the `$format` is a dummy empty string, but `plugin_name` is repeatable
|
||||||
|
// just keep it here for now. Need to find a way to remove it.
|
||||||
let registrations = format!(
|
let registrations = format!(
|
||||||
concat!($(concat!("register -e ", $format, " {};")),+),
|
concat!($(concat!("register ", $format, " {};")),+),
|
||||||
$(
|
$(
|
||||||
nu_path::canonicalize_with(with_exe!($plugin_name), &test_bins)
|
nu_path::canonicalize_with(with_exe!($plugin_name), &test_bins)
|
||||||
.unwrap_or_else(|e| {
|
.unwrap_or_else(|e| {
|
||||||
|
@ -6,7 +6,7 @@ use nu_test_support::playground::Playground;
|
|||||||
fn chooses_highest_increment_if_given_more_than_one() {
|
fn chooses_highest_increment_if_given_more_than_one() {
|
||||||
let actual = nu_with_plugins!(
|
let actual = nu_with_plugins!(
|
||||||
cwd: "tests/fixtures/formats",
|
cwd: "tests/fixtures/formats",
|
||||||
plugin: ("json", "nu_plugin_inc"),
|
plugin: ("nu_plugin_inc"),
|
||||||
"open cargo_sample.toml | first 1 | inc package.version --major --minor | get package.version"
|
"open cargo_sample.toml | first 1 | inc package.version --major --minor | get package.version"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ fn chooses_highest_increment_if_given_more_than_one() {
|
|||||||
|
|
||||||
let actual = nu_with_plugins!(
|
let actual = nu_with_plugins!(
|
||||||
cwd: "tests/fixtures/formats",
|
cwd: "tests/fixtures/formats",
|
||||||
plugin: ("json", "nu_plugin_inc"),
|
plugin: ("nu_plugin_inc"),
|
||||||
// Regardless of order of arguments
|
// Regardless of order of arguments
|
||||||
"open cargo_sample.toml | first 1 | inc package.version --minor --major | get package.version"
|
"open cargo_sample.toml | first 1 | inc package.version --minor --major | get package.version"
|
||||||
);
|
);
|
||||||
@ -35,7 +35,7 @@ fn by_one_with_field_passed() {
|
|||||||
|
|
||||||
let actual = nu_with_plugins!(
|
let actual = nu_with_plugins!(
|
||||||
cwd: dirs.test(),
|
cwd: dirs.test(),
|
||||||
plugin: ("json", "nu_plugin_inc"),
|
plugin: ("nu_plugin_inc"),
|
||||||
"open sample.toml | inc package.edition | get package.edition"
|
"open sample.toml | inc package.edition | get package.edition"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ fn by_one_with_no_field_passed() {
|
|||||||
|
|
||||||
let actual = nu_with_plugins!(
|
let actual = nu_with_plugins!(
|
||||||
cwd: dirs.test(),
|
cwd: dirs.test(),
|
||||||
plugin: ("json", "nu_plugin_inc"),
|
plugin: ("nu_plugin_inc"),
|
||||||
"open sample.toml | get package.contributors | inc"
|
"open sample.toml | get package.contributors | inc"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ fn semversion_major_inc() {
|
|||||||
|
|
||||||
let actual = nu_with_plugins!(
|
let actual = nu_with_plugins!(
|
||||||
cwd: dirs.test(),
|
cwd: dirs.test(),
|
||||||
plugin: ("json", "nu_plugin_inc"),
|
plugin: ("nu_plugin_inc"),
|
||||||
"open sample.toml | inc package.version -M | get package.version"
|
"open sample.toml | inc package.version -M | get package.version"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ fn semversion_minor_inc() {
|
|||||||
|
|
||||||
let actual = nu_with_plugins!(
|
let actual = nu_with_plugins!(
|
||||||
cwd: dirs.test(),
|
cwd: dirs.test(),
|
||||||
plugin: ("json", "nu_plugin_inc"),
|
plugin: ("nu_plugin_inc"),
|
||||||
"open sample.toml | inc package.version --minor | get package.version"
|
"open sample.toml | inc package.version --minor | get package.version"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ fn semversion_patch_inc() {
|
|||||||
|
|
||||||
let actual = nu_with_plugins!(
|
let actual = nu_with_plugins!(
|
||||||
cwd: dirs.test(),
|
cwd: dirs.test(),
|
||||||
plugin: ("json", "nu_plugin_inc"),
|
plugin: ("nu_plugin_inc"),
|
||||||
"open sample.toml | inc package.version --patch | get package.version"
|
"open sample.toml | inc package.version --patch | get package.version"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ fn semversion_without_passing_field() {
|
|||||||
|
|
||||||
let actual = nu_with_plugins!(
|
let actual = nu_with_plugins!(
|
||||||
cwd: dirs.test(),
|
cwd: dirs.test(),
|
||||||
plugin: ("json", "nu_plugin_inc"),
|
plugin: ("nu_plugin_inc"),
|
||||||
"open sample.toml | get package.version | inc --patch"
|
"open sample.toml | get package.version | inc --patch"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ use nu_test_support::nu_with_plugins;
|
|||||||
fn can_get_custom_value_from_plugin_and_instantly_collapse_it() {
|
fn can_get_custom_value_from_plugin_and_instantly_collapse_it() {
|
||||||
let actual = nu_with_plugins!(
|
let actual = nu_with_plugins!(
|
||||||
cwd: "tests",
|
cwd: "tests",
|
||||||
plugin: ("msgpack", "nu_plugin_custom_values"),
|
plugin: ("nu_plugin_custom_values"),
|
||||||
"custom-value generate"
|
"custom-value generate"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ fn can_get_custom_value_from_plugin_and_instantly_collapse_it() {
|
|||||||
fn can_get_custom_value_from_plugin_and_pass_it_over() {
|
fn can_get_custom_value_from_plugin_and_pass_it_over() {
|
||||||
let actual = nu_with_plugins!(
|
let actual = nu_with_plugins!(
|
||||||
cwd: "tests",
|
cwd: "tests",
|
||||||
plugin: ("msgpack", "nu_plugin_custom_values"),
|
plugin: ("nu_plugin_custom_values"),
|
||||||
"custom-value generate | custom-value update"
|
"custom-value generate | custom-value update"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ fn can_get_custom_value_from_plugin_and_pass_it_over() {
|
|||||||
fn can_generate_and_updated_multiple_types_of_custom_values() {
|
fn can_generate_and_updated_multiple_types_of_custom_values() {
|
||||||
let actual = nu_with_plugins!(
|
let actual = nu_with_plugins!(
|
||||||
cwd: "tests",
|
cwd: "tests",
|
||||||
plugin: ("msgpack", "nu_plugin_custom_values"),
|
plugin: ("nu_plugin_custom_values"),
|
||||||
"custom-value generate2 | custom-value update"
|
"custom-value generate2 | custom-value update"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ fn can_generate_and_updated_multiple_types_of_custom_values() {
|
|||||||
fn can_get_describe_plugin_custom_values() {
|
fn can_get_describe_plugin_custom_values() {
|
||||||
let actual = nu_with_plugins!(
|
let actual = nu_with_plugins!(
|
||||||
cwd: "tests",
|
cwd: "tests",
|
||||||
plugin: ("msgpack", "nu_plugin_custom_values"),
|
plugin: ("nu_plugin_custom_values"),
|
||||||
"custom-value generate | describe"
|
"custom-value generate | describe"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ fn can_get_describe_plugin_custom_values() {
|
|||||||
fn fails_if_passing_engine_custom_values_to_plugins() {
|
fn fails_if_passing_engine_custom_values_to_plugins() {
|
||||||
let actual = nu_with_plugins!(
|
let actual = nu_with_plugins!(
|
||||||
cwd: "tests/fixtures/formats",
|
cwd: "tests/fixtures/formats",
|
||||||
plugin: ("msgpack", "nu_plugin_custom_values"),
|
plugin: ("nu_plugin_custom_values"),
|
||||||
"open-db sample.db | custom-value update"
|
"open-db sample.db | custom-value update"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -72,8 +72,8 @@ fn fails_if_passing_custom_values_across_plugins() {
|
|||||||
let actual = nu_with_plugins!(
|
let actual = nu_with_plugins!(
|
||||||
cwd: "tests",
|
cwd: "tests",
|
||||||
plugins: [
|
plugins: [
|
||||||
("msgpack", "nu_plugin_custom_values"),
|
("nu_plugin_custom_values"),
|
||||||
("json", "nu_plugin_inc")
|
("nu_plugin_inc")
|
||||||
],
|
],
|
||||||
"custom-value generate | inc --major"
|
"custom-value generate | inc --major"
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user