mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 10:05:54 +02: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:
@ -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::{
|
||||
CallInfo, CallInput, PluginCall, PluginCustomValue, PluginData, PluginResponse,
|
||||
};
|
||||
@ -16,21 +16,14 @@ pub struct PluginDeclaration {
|
||||
signature: Signature,
|
||||
filename: PathBuf,
|
||||
shell: Option<PathBuf>,
|
||||
encoding: EncodingType,
|
||||
}
|
||||
|
||||
impl PluginDeclaration {
|
||||
pub fn new(
|
||||
filename: PathBuf,
|
||||
signature: Signature,
|
||||
encoding: EncodingType,
|
||||
shell: Option<PathBuf>,
|
||||
) -> Self {
|
||||
pub fn new(filename: PathBuf, signature: Signature, shell: Option<PathBuf>) -> Self {
|
||||
Self {
|
||||
name: signature.name.clone(),
|
||||
signature,
|
||||
filename,
|
||||
encoding,
|
||||
shell,
|
||||
}
|
||||
}
|
||||
@ -111,17 +104,27 @@ impl Command for PluginDeclaration {
|
||||
input,
|
||||
});
|
||||
|
||||
let response =
|
||||
call_plugin(&mut child, plugin_call, &self.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 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, &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 {
|
||||
Ok(PluginResponse::Value(value)) => {
|
||||
@ -134,7 +137,6 @@ impl Command for PluginDeclaration {
|
||||
data: plugin_data.data,
|
||||
filename: self.filename.clone(),
|
||||
shell: self.shell.clone(),
|
||||
encoding: self.encoding.clone(),
|
||||
source: engine_state.get_decl(call.decl_id).name().to_owned(),
|
||||
}),
|
||||
span: plugin_data.span,
|
||||
@ -158,7 +160,7 @@ impl Command for PluginDeclaration {
|
||||
pipeline_data
|
||||
}
|
||||
|
||||
fn is_plugin(&self) -> Option<(&PathBuf, &str, &Option<PathBuf>)> {
|
||||
Some((&self.filename, self.encoding.to_str(), &self.shell))
|
||||
fn is_plugin(&self) -> Option<(&PathBuf, &Option<PathBuf>)> {
|
||||
Some((&self.filename, &self.shell))
|
||||
}
|
||||
}
|
||||
|
@ -7,9 +7,9 @@ use crate::protocol::{CallInput, LabeledError, PluginCall, PluginData, PluginRes
|
||||
use crate::EncodingType;
|
||||
use std::env;
|
||||
use std::fmt::Write;
|
||||
use std::io::BufReader;
|
||||
use std::io::{BufReader, Read, Write as WriteTrait};
|
||||
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::{Signature, Value};
|
||||
@ -116,7 +116,6 @@ pub(crate) fn call_plugin(
|
||||
|
||||
pub fn get_signature(
|
||||
path: &Path,
|
||||
encoding: &EncodingType,
|
||||
shell: &Option<PathBuf>,
|
||||
current_envs: &HashMap<String, String>,
|
||||
) -> Result<Vec<Signature>, ShellError> {
|
||||
@ -127,32 +126,34 @@ pub fn get_signature(
|
||||
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
|
||||
// send call to plugin asking for signature
|
||||
if let Some(mut stdin_writer) = child.stdin.take() {
|
||||
let encoding_clone = encoding.clone();
|
||||
std::thread::spawn(move || {
|
||||
encoding_clone.encode_call(&PluginCall::Signature, &mut stdin_writer)
|
||||
});
|
||||
}
|
||||
let encoding_clone = encoding.clone();
|
||||
std::thread::spawn(move || {
|
||||
encoding_clone.encode_call(&PluginCall::Signature, &mut stdin_writer)
|
||||
});
|
||||
|
||||
// deserialize response from plugin to extract the signature
|
||||
let signatures = if let Some(stdout_reader) = &mut child.stdout {
|
||||
let reader = stdout_reader;
|
||||
let mut buf_read = BufReader::with_capacity(OUTPUT_BUFFER_SIZE, reader);
|
||||
let response = encoding.decode_response(&mut buf_read)?;
|
||||
let reader = stdout_reader;
|
||||
let mut buf_read = BufReader::with_capacity(OUTPUT_BUFFER_SIZE, reader);
|
||||
let response = encoding.decode_response(&mut buf_read)?;
|
||||
|
||||
match response {
|
||||
PluginResponse::Signature(sign) => Ok(sign),
|
||||
PluginResponse::Error(err) => Err(err.into()),
|
||||
_ => Err(ShellError::PluginFailedToLoad(
|
||||
"Plugin missing signature".into(),
|
||||
)),
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::PluginFailedToLoad(
|
||||
"Plugin missing stdout reader".into(),
|
||||
))
|
||||
let signatures = match response {
|
||||
PluginResponse::Signature(sign) => Ok(sign),
|
||||
PluginResponse::Error(err) => Err(err.into()),
|
||||
_ => Err(ShellError::PluginFailedToLoad(
|
||||
"Plugin missing signature".into(),
|
||||
)),
|
||||
}?;
|
||||
|
||||
match child.wait() {
|
||||
@ -196,6 +197,24 @@ pub fn serve_plugin(plugin: &mut impl Plugin, encoder: impl PluginEncoder) {
|
||||
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 plugin_call = encoder.decode_call(&mut stdin_buf);
|
||||
|
||||
@ -332,3 +351,22 @@ fn print_help(plugin: &mut impl Plugin, encoder: impl PluginEncoder) {
|
||||
|
||||
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 serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
plugin::{call_plugin, create_command},
|
||||
EncodingType,
|
||||
};
|
||||
use crate::plugin::{call_plugin, create_command, get_plugin_encoding};
|
||||
|
||||
use super::{PluginCall, PluginData, PluginResponse};
|
||||
|
||||
@ -32,8 +29,6 @@ pub struct PluginCustomValue {
|
||||
#[serde(skip)]
|
||||
pub shell: Option<PathBuf>,
|
||||
#[serde(skip)]
|
||||
pub encoding: EncodingType,
|
||||
#[serde(skip)]
|
||||
pub source: String,
|
||||
}
|
||||
|
||||
@ -72,8 +67,19 @@ impl CustomValue for PluginCustomValue {
|
||||
data: self.data.clone(),
|
||||
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(
|
||||
format!(
|
||||
"Unable to decode call for {} to get base value",
|
||||
|
@ -7,7 +7,7 @@ pub struct JsonSerializer;
|
||||
|
||||
impl PluginEncoder for JsonSerializer {
|
||||
fn name(&self) -> &str {
|
||||
"Json Serializer"
|
||||
"json"
|
||||
}
|
||||
|
||||
fn encode_call(
|
||||
|
@ -6,7 +6,7 @@ pub struct MsgPackSerializer;
|
||||
|
||||
impl PluginEncoder for MsgPackSerializer {
|
||||
fn name(&self) -> &str {
|
||||
"MsgPack Serializer"
|
||||
"msgpack"
|
||||
}
|
||||
|
||||
fn encode_call(
|
||||
@ -23,7 +23,7 @@ impl PluginEncoder for MsgPackSerializer {
|
||||
reader: &mut impl std::io::BufRead,
|
||||
) -> Result<crate::protocol::PluginCall, nu_protocol::ShellError> {
|
||||
rmp_serde::from_read(reader)
|
||||
.map_err(|err| ShellError::PluginFailedToEncode(err.to_string()))
|
||||
.map_err(|err| ShellError::PluginFailedToDecode(err.to_string()))
|
||||
}
|
||||
|
||||
fn encode_response(
|
||||
@ -40,7 +40,7 @@ impl PluginEncoder for MsgPackSerializer {
|
||||
reader: &mut impl std::io::BufRead,
|
||||
) -> Result<PluginResponse, ShellError> {
|
||||
rmp_serde::from_read(reader)
|
||||
.map_err(|err| ShellError::PluginFailedToEncode(err.to_string()))
|
||||
.map_err(|err| ShellError::PluginFailedToDecode(err.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user