mirror of
https://github.com/nushell/nushell.git
synced 2024-11-24 17:34:00 +01:00
Make pipeline metadata available to plugins (#13495)
# Description Fixes an issue with pipeline metadata not being passed to plugins.
This commit is contained in:
parent
ca8eb856e8
commit
d081e3386f
@ -177,16 +177,19 @@ pub trait InterfaceManager {
|
|||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
self.prepare_pipeline_data(match header {
|
self.prepare_pipeline_data(match header {
|
||||||
PipelineDataHeader::Empty => PipelineData::Empty,
|
PipelineDataHeader::Empty => PipelineData::Empty,
|
||||||
PipelineDataHeader::Value(value) => PipelineData::Value(value, None),
|
PipelineDataHeader::Value(value, metadata) => PipelineData::Value(value, metadata),
|
||||||
PipelineDataHeader::ListStream(info) => {
|
PipelineDataHeader::ListStream(info) => {
|
||||||
let handle = self.stream_manager().get_handle();
|
let handle = self.stream_manager().get_handle();
|
||||||
let reader = handle.read_stream(info.id, self.get_interface())?;
|
let reader = handle.read_stream(info.id, self.get_interface())?;
|
||||||
ListStream::new(reader, info.span, signals.clone()).into()
|
let ls = ListStream::new(reader, info.span, signals.clone());
|
||||||
|
PipelineData::ListStream(ls, info.metadata)
|
||||||
}
|
}
|
||||||
PipelineDataHeader::ByteStream(info) => {
|
PipelineDataHeader::ByteStream(info) => {
|
||||||
let handle = self.stream_manager().get_handle();
|
let handle = self.stream_manager().get_handle();
|
||||||
let reader = handle.read_stream(info.id, self.get_interface())?;
|
let reader = handle.read_stream(info.id, self.get_interface())?;
|
||||||
ByteStream::from_result_iter(reader, info.span, signals.clone(), info.type_).into()
|
let bs =
|
||||||
|
ByteStream::from_result_iter(reader, info.span, signals.clone(), info.type_);
|
||||||
|
PipelineData::ByteStream(bs, info.metadata)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -248,26 +251,33 @@ pub trait Interface: Clone + Send {
|
|||||||
Ok::<_, ShellError>((id, writer))
|
Ok::<_, ShellError>((id, writer))
|
||||||
};
|
};
|
||||||
match self.prepare_pipeline_data(data, context)? {
|
match self.prepare_pipeline_data(data, context)? {
|
||||||
PipelineData::Value(value, ..) => {
|
PipelineData::Value(value, metadata) => Ok((
|
||||||
Ok((PipelineDataHeader::Value(value), PipelineDataWriter::None))
|
PipelineDataHeader::Value(value, metadata),
|
||||||
}
|
PipelineDataWriter::None,
|
||||||
|
)),
|
||||||
PipelineData::Empty => Ok((PipelineDataHeader::Empty, PipelineDataWriter::None)),
|
PipelineData::Empty => Ok((PipelineDataHeader::Empty, PipelineDataWriter::None)),
|
||||||
PipelineData::ListStream(stream, ..) => {
|
PipelineData::ListStream(stream, metadata) => {
|
||||||
let (id, writer) = new_stream(LIST_STREAM_HIGH_PRESSURE)?;
|
let (id, writer) = new_stream(LIST_STREAM_HIGH_PRESSURE)?;
|
||||||
Ok((
|
Ok((
|
||||||
PipelineDataHeader::ListStream(ListStreamInfo {
|
PipelineDataHeader::ListStream(ListStreamInfo {
|
||||||
id,
|
id,
|
||||||
span: stream.span(),
|
span: stream.span(),
|
||||||
|
metadata,
|
||||||
}),
|
}),
|
||||||
PipelineDataWriter::ListStream(writer, stream),
|
PipelineDataWriter::ListStream(writer, stream),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
PipelineData::ByteStream(stream, ..) => {
|
PipelineData::ByteStream(stream, metadata) => {
|
||||||
let span = stream.span();
|
let span = stream.span();
|
||||||
let type_ = stream.type_();
|
let type_ = stream.type_();
|
||||||
if let Some(reader) = stream.reader() {
|
if let Some(reader) = stream.reader() {
|
||||||
let (id, writer) = new_stream(RAW_STREAM_HIGH_PRESSURE)?;
|
let (id, writer) = new_stream(RAW_STREAM_HIGH_PRESSURE)?;
|
||||||
let header = PipelineDataHeader::ByteStream(ByteStreamInfo { id, span, type_ });
|
let header = PipelineDataHeader::ByteStream(ByteStreamInfo {
|
||||||
|
id,
|
||||||
|
span,
|
||||||
|
type_,
|
||||||
|
metadata,
|
||||||
|
});
|
||||||
Ok((header, PipelineDataWriter::ByteStream(writer, reader)))
|
Ok((header, PipelineDataWriter::ByteStream(writer, reader)))
|
||||||
} else {
|
} else {
|
||||||
Ok((PipelineDataHeader::Empty, PipelineDataWriter::None))
|
Ok((PipelineDataHeader::Empty, PipelineDataWriter::None))
|
||||||
|
@ -137,10 +137,16 @@ fn read_pipeline_data_empty() -> Result<(), ShellError> {
|
|||||||
fn read_pipeline_data_value() -> Result<(), ShellError> {
|
fn read_pipeline_data_value() -> Result<(), ShellError> {
|
||||||
let manager = TestInterfaceManager::new(&TestCase::new());
|
let manager = TestInterfaceManager::new(&TestCase::new());
|
||||||
let value = Value::test_int(4);
|
let value = Value::test_int(4);
|
||||||
let header = PipelineDataHeader::Value(value.clone());
|
let metadata = Some(PipelineMetadata {
|
||||||
|
data_source: DataSource::FilePath("/test/path".into()),
|
||||||
|
content_type: None,
|
||||||
|
});
|
||||||
|
let header = PipelineDataHeader::Value(value.clone(), metadata.clone());
|
||||||
match manager.read_pipeline_data(header, &Signals::empty())? {
|
match manager.read_pipeline_data(header, &Signals::empty())? {
|
||||||
PipelineData::Value(read_value, ..) => assert_eq!(value, read_value),
|
PipelineData::Value(read_value, read_metadata) => {
|
||||||
|
assert_eq!(value, read_value);
|
||||||
|
assert_eq!(metadata, read_metadata);
|
||||||
|
}
|
||||||
PipelineData::ListStream(..) => panic!("unexpected ListStream"),
|
PipelineData::ListStream(..) => panic!("unexpected ListStream"),
|
||||||
PipelineData::ByteStream(..) => panic!("unexpected ByteStream"),
|
PipelineData::ByteStream(..) => panic!("unexpected ByteStream"),
|
||||||
PipelineData::Empty => panic!("unexpected Empty"),
|
PipelineData::Empty => panic!("unexpected Empty"),
|
||||||
@ -161,9 +167,15 @@ fn read_pipeline_data_list_stream() -> Result<(), ShellError> {
|
|||||||
}
|
}
|
||||||
test.add(StreamMessage::End(7));
|
test.add(StreamMessage::End(7));
|
||||||
|
|
||||||
|
let metadata = Some(PipelineMetadata {
|
||||||
|
data_source: DataSource::None,
|
||||||
|
content_type: Some("foobar".into()),
|
||||||
|
});
|
||||||
|
|
||||||
let header = PipelineDataHeader::ListStream(ListStreamInfo {
|
let header = PipelineDataHeader::ListStream(ListStreamInfo {
|
||||||
id: 7,
|
id: 7,
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
|
metadata,
|
||||||
});
|
});
|
||||||
|
|
||||||
let pipe = manager.read_pipeline_data(header, &Signals::empty())?;
|
let pipe = manager.read_pipeline_data(header, &Signals::empty())?;
|
||||||
@ -204,10 +216,17 @@ fn read_pipeline_data_byte_stream() -> Result<(), ShellError> {
|
|||||||
test.add(StreamMessage::End(12));
|
test.add(StreamMessage::End(12));
|
||||||
|
|
||||||
let test_span = Span::new(10, 13);
|
let test_span = Span::new(10, 13);
|
||||||
|
|
||||||
|
let metadata = Some(PipelineMetadata {
|
||||||
|
data_source: DataSource::None,
|
||||||
|
content_type: Some("foobar".into()),
|
||||||
|
});
|
||||||
|
|
||||||
let header = PipelineDataHeader::ByteStream(ByteStreamInfo {
|
let header = PipelineDataHeader::ByteStream(ByteStreamInfo {
|
||||||
id: 12,
|
id: 12,
|
||||||
span: test_span,
|
span: test_span,
|
||||||
type_: ByteStreamType::Unknown,
|
type_: ByteStreamType::Unknown,
|
||||||
|
metadata,
|
||||||
});
|
});
|
||||||
|
|
||||||
let pipe = manager.read_pipeline_data(header, &Signals::empty())?;
|
let pipe = manager.read_pipeline_data(header, &Signals::empty())?;
|
||||||
@ -251,9 +270,15 @@ fn read_pipeline_data_byte_stream() -> Result<(), ShellError> {
|
|||||||
#[test]
|
#[test]
|
||||||
fn read_pipeline_data_prepared_properly() -> Result<(), ShellError> {
|
fn read_pipeline_data_prepared_properly() -> Result<(), ShellError> {
|
||||||
let manager = TestInterfaceManager::new(&TestCase::new());
|
let manager = TestInterfaceManager::new(&TestCase::new());
|
||||||
|
let metadata = Some(PipelineMetadata {
|
||||||
|
data_source: DataSource::None,
|
||||||
|
content_type: Some("foobar".into()),
|
||||||
|
});
|
||||||
|
|
||||||
let header = PipelineDataHeader::ListStream(ListStreamInfo {
|
let header = PipelineDataHeader::ListStream(ListStreamInfo {
|
||||||
id: 0,
|
id: 0,
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
|
metadata,
|
||||||
});
|
});
|
||||||
match manager.read_pipeline_data(header, &Signals::empty())? {
|
match manager.read_pipeline_data(header, &Signals::empty())? {
|
||||||
PipelineData::ListStream(_, meta) => match meta {
|
PipelineData::ListStream(_, meta) => match meta {
|
||||||
@ -301,7 +326,7 @@ fn write_pipeline_data_value() -> Result<(), ShellError> {
|
|||||||
interface.init_write_pipeline_data(PipelineData::Value(value.clone(), None), &())?;
|
interface.init_write_pipeline_data(PipelineData::Value(value.clone(), None), &())?;
|
||||||
|
|
||||||
match header {
|
match header {
|
||||||
PipelineDataHeader::Value(read_value) => assert_eq!(value, read_value),
|
PipelineDataHeader::Value(read_value, _) => assert_eq!(value, read_value),
|
||||||
_ => panic!("unexpected header: {header:?}"),
|
_ => panic!("unexpected header: {header:?}"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,8 @@ macro_rules! generate_tests {
|
|||||||
StreamData,
|
StreamData,
|
||||||
};
|
};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
LabeledError, PluginSignature, Signature, Span, Spanned, SyntaxShape, Value,
|
DataSource, LabeledError, PipelineMetadata, PluginSignature, Signature, Span, Spanned,
|
||||||
|
SyntaxShape, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -123,10 +124,15 @@ macro_rules! generate_tests {
|
|||||||
)],
|
)],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let metadata = Some(PipelineMetadata {
|
||||||
|
data_source: DataSource::None,
|
||||||
|
content_type: Some("foobar".into()),
|
||||||
|
});
|
||||||
|
|
||||||
let plugin_call = PluginCall::Run(CallInfo {
|
let plugin_call = PluginCall::Run(CallInfo {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
call: call.clone(),
|
call: call.clone(),
|
||||||
input: PipelineDataHeader::Value(input.clone()),
|
input: PipelineDataHeader::Value(input.clone(), metadata.clone()),
|
||||||
});
|
});
|
||||||
|
|
||||||
let plugin_input = PluginInput::Call(1, plugin_call);
|
let plugin_input = PluginInput::Call(1, plugin_call);
|
||||||
@ -144,7 +150,7 @@ macro_rules! generate_tests {
|
|||||||
match returned {
|
match returned {
|
||||||
PluginInput::Call(1, PluginCall::Run(call_info)) => {
|
PluginInput::Call(1, PluginCall::Run(call_info)) => {
|
||||||
assert_eq!(name, call_info.name);
|
assert_eq!(name, call_info.name);
|
||||||
assert_eq!(PipelineDataHeader::Value(input), call_info.input);
|
assert_eq!(PipelineDataHeader::Value(input, metadata), call_info.input);
|
||||||
assert_eq!(call.head, call_info.call.head);
|
assert_eq!(call.head, call_info.call.head);
|
||||||
assert_eq!(call.positional.len(), call_info.call.positional.len());
|
assert_eq!(call.positional.len(), call_info.call.positional.len());
|
||||||
|
|
||||||
@ -305,7 +311,7 @@ macro_rules! generate_tests {
|
|||||||
match returned {
|
match returned {
|
||||||
PluginOutput::CallResponse(
|
PluginOutput::CallResponse(
|
||||||
4,
|
4,
|
||||||
PluginCallResponse::PipelineData(PipelineDataHeader::Value(returned_value)),
|
PluginCallResponse::PipelineData(PipelineDataHeader::Value(returned_value, _)),
|
||||||
) => {
|
) => {
|
||||||
assert_eq!(value, returned_value)
|
assert_eq!(value, returned_value)
|
||||||
}
|
}
|
||||||
@ -325,7 +331,7 @@ macro_rules! generate_tests {
|
|||||||
span,
|
span,
|
||||||
);
|
);
|
||||||
|
|
||||||
let response = PluginCallResponse::PipelineData(PipelineDataHeader::Value(value));
|
let response = PluginCallResponse::PipelineData(PipelineDataHeader::value(value));
|
||||||
let output = PluginOutput::CallResponse(5, response);
|
let output = PluginOutput::CallResponse(5, response);
|
||||||
|
|
||||||
let encoder = $encoder;
|
let encoder = $encoder;
|
||||||
@ -341,7 +347,7 @@ macro_rules! generate_tests {
|
|||||||
match returned {
|
match returned {
|
||||||
PluginOutput::CallResponse(
|
PluginOutput::CallResponse(
|
||||||
5,
|
5,
|
||||||
PluginCallResponse::PipelineData(PipelineDataHeader::Value(returned_value)),
|
PluginCallResponse::PipelineData(PipelineDataHeader::Value(returned_value, _)),
|
||||||
) => {
|
) => {
|
||||||
assert_eq!(span, returned_value.span());
|
assert_eq!(span, returned_value.span());
|
||||||
|
|
||||||
|
@ -17,8 +17,9 @@ use nu_plugin_protocol::{
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Math, Operator},
|
ast::{Math, Operator},
|
||||||
engine::Closure,
|
engine::Closure,
|
||||||
ByteStreamType, CustomValue, IntoInterruptiblePipelineData, IntoSpanned, PipelineData,
|
ByteStreamType, CustomValue, DataSource, IntoInterruptiblePipelineData, IntoSpanned,
|
||||||
PluginMetadata, PluginSignature, ShellError, Signals, Span, Spanned, Value,
|
PipelineData, PipelineMetadata, PluginMetadata, PluginSignature, ShellError, Signals, Span,
|
||||||
|
Spanned, Value,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
@ -52,10 +53,7 @@ fn manager_consume_all_exits_after_streams_and_interfaces_are_dropped() -> Resul
|
|||||||
|
|
||||||
// Create a stream...
|
// Create a stream...
|
||||||
let stream = manager.read_pipeline_data(
|
let stream = manager.read_pipeline_data(
|
||||||
PipelineDataHeader::ListStream(ListStreamInfo {
|
PipelineDataHeader::list_stream(ListStreamInfo::new(0, Span::test_data())),
|
||||||
id: 0,
|
|
||||||
span: Span::test_data(),
|
|
||||||
}),
|
|
||||||
&Signals::empty(),
|
&Signals::empty(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -108,10 +106,7 @@ fn manager_consume_all_propagates_io_error_to_readers() -> Result<(), ShellError
|
|||||||
test.set_read_error(test_io_error());
|
test.set_read_error(test_io_error());
|
||||||
|
|
||||||
let stream = manager.read_pipeline_data(
|
let stream = manager.read_pipeline_data(
|
||||||
PipelineDataHeader::ListStream(ListStreamInfo {
|
PipelineDataHeader::list_stream(ListStreamInfo::new(0, Span::test_data())),
|
||||||
id: 0,
|
|
||||||
span: Span::test_data(),
|
|
||||||
}),
|
|
||||||
&Signals::empty(),
|
&Signals::empty(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -154,11 +149,11 @@ fn manager_consume_all_propagates_message_error_to_readers() -> Result<(), Shell
|
|||||||
test.add(invalid_output());
|
test.add(invalid_output());
|
||||||
|
|
||||||
let stream = manager.read_pipeline_data(
|
let stream = manager.read_pipeline_data(
|
||||||
PipelineDataHeader::ByteStream(ByteStreamInfo {
|
PipelineDataHeader::byte_stream(ByteStreamInfo::new(
|
||||||
id: 0,
|
0,
|
||||||
span: Span::test_data(),
|
Span::test_data(),
|
||||||
type_: ByteStreamType::Unknown,
|
ByteStreamType::Unknown,
|
||||||
}),
|
)),
|
||||||
&Signals::empty(),
|
&Signals::empty(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -331,10 +326,10 @@ fn manager_consume_call_response_forwards_to_subscriber_with_pipeline_data(
|
|||||||
|
|
||||||
manager.consume(PluginOutput::CallResponse(
|
manager.consume(PluginOutput::CallResponse(
|
||||||
0,
|
0,
|
||||||
PluginCallResponse::PipelineData(PipelineDataHeader::ListStream(ListStreamInfo {
|
PluginCallResponse::PipelineData(PipelineDataHeader::list_stream(ListStreamInfo::new(
|
||||||
id: 0,
|
0,
|
||||||
span: Span::test_data(),
|
Span::test_data(),
|
||||||
})),
|
))),
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
for i in 0..2 {
|
for i in 0..2 {
|
||||||
@ -375,18 +370,18 @@ fn manager_consume_call_response_registers_streams() -> Result<(), ShellError> {
|
|||||||
// Check list streams, byte streams
|
// Check list streams, byte streams
|
||||||
manager.consume(PluginOutput::CallResponse(
|
manager.consume(PluginOutput::CallResponse(
|
||||||
0,
|
0,
|
||||||
PluginCallResponse::PipelineData(PipelineDataHeader::ListStream(ListStreamInfo {
|
PluginCallResponse::PipelineData(PipelineDataHeader::list_stream(ListStreamInfo::new(
|
||||||
id: 0,
|
0,
|
||||||
span: Span::test_data(),
|
Span::test_data(),
|
||||||
})),
|
))),
|
||||||
))?;
|
))?;
|
||||||
manager.consume(PluginOutput::CallResponse(
|
manager.consume(PluginOutput::CallResponse(
|
||||||
1,
|
1,
|
||||||
PluginCallResponse::PipelineData(PipelineDataHeader::ByteStream(ByteStreamInfo {
|
PluginCallResponse::PipelineData(PipelineDataHeader::byte_stream(ByteStreamInfo::new(
|
||||||
id: 1,
|
1,
|
||||||
span: Span::test_data(),
|
Span::test_data(),
|
||||||
type_: ByteStreamType::Unknown,
|
ByteStreamType::Unknown,
|
||||||
})),
|
))),
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
// ListStream should have one
|
// ListStream should have one
|
||||||
@ -442,10 +437,7 @@ fn manager_consume_engine_call_forwards_to_subscriber_with_pipeline_data() -> Re
|
|||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
positional: vec![],
|
positional: vec![],
|
||||||
input: PipelineDataHeader::ListStream(ListStreamInfo {
|
input: PipelineDataHeader::list_stream(ListStreamInfo::new(2, Span::test_data())),
|
||||||
id: 2,
|
|
||||||
span: Span::test_data(),
|
|
||||||
}),
|
|
||||||
redirect_stdout: false,
|
redirect_stdout: false,
|
||||||
redirect_stderr: false,
|
redirect_stderr: false,
|
||||||
},
|
},
|
||||||
@ -806,6 +798,11 @@ fn interface_write_plugin_call_writes_run_with_value_input() -> Result<(), Shell
|
|||||||
let manager = test.plugin("test");
|
let manager = test.plugin("test");
|
||||||
let interface = manager.get_interface();
|
let interface = manager.get_interface();
|
||||||
|
|
||||||
|
let metadata0 = PipelineMetadata {
|
||||||
|
data_source: DataSource::None,
|
||||||
|
content_type: Some("baz".into()),
|
||||||
|
};
|
||||||
|
|
||||||
let result = interface.write_plugin_call(
|
let result = interface.write_plugin_call(
|
||||||
PluginCall::Run(CallInfo {
|
PluginCall::Run(CallInfo {
|
||||||
name: "foo".into(),
|
name: "foo".into(),
|
||||||
@ -814,7 +811,7 @@ fn interface_write_plugin_call_writes_run_with_value_input() -> Result<(), Shell
|
|||||||
positional: vec![],
|
positional: vec![],
|
||||||
named: vec![],
|
named: vec![],
|
||||||
},
|
},
|
||||||
input: PipelineData::Value(Value::test_int(-1), None),
|
input: PipelineData::Value(Value::test_int(-1), Some(metadata0.clone())),
|
||||||
}),
|
}),
|
||||||
None,
|
None,
|
||||||
)?;
|
)?;
|
||||||
@ -826,7 +823,10 @@ fn interface_write_plugin_call_writes_run_with_value_input() -> Result<(), Shell
|
|||||||
PluginCall::Run(CallInfo { name, input, .. }) => {
|
PluginCall::Run(CallInfo { name, input, .. }) => {
|
||||||
assert_eq!("foo", name);
|
assert_eq!("foo", name);
|
||||||
match input {
|
match input {
|
||||||
PipelineDataHeader::Value(value) => assert_eq!(-1, value.as_int()?),
|
PipelineDataHeader::Value(value, metadata) => {
|
||||||
|
assert_eq!(-1, value.as_int()?);
|
||||||
|
assert_eq!(metadata0, metadata.expect("there should be metadata"));
|
||||||
|
}
|
||||||
_ => panic!("unexpected input header: {input:?}"),
|
_ => panic!("unexpected input header: {input:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ pub mod test_util;
|
|||||||
|
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::Operator, engine::Closure, ByteStreamType, Config, DeclId, LabeledError, PipelineData,
|
ast::Operator, engine::Closure, ByteStreamType, Config, DeclId, LabeledError, PipelineData,
|
||||||
PluginMetadata, PluginSignature, ShellError, Span, Spanned, Value,
|
PipelineMetadata, PluginMetadata, PluginSignature, ShellError, Span, Spanned, Value,
|
||||||
};
|
};
|
||||||
use nu_utils::SharedCow;
|
use nu_utils::SharedCow;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -78,7 +78,7 @@ pub enum PipelineDataHeader {
|
|||||||
/// No input
|
/// No input
|
||||||
Empty,
|
Empty,
|
||||||
/// A single value
|
/// A single value
|
||||||
Value(Value),
|
Value(Value, Option<PipelineMetadata>),
|
||||||
/// Initiate [`nu_protocol::PipelineData::ListStream`].
|
/// Initiate [`nu_protocol::PipelineData::ListStream`].
|
||||||
///
|
///
|
||||||
/// Items are sent via [`StreamData`]
|
/// Items are sent via [`StreamData`]
|
||||||
@ -94,11 +94,23 @@ impl PipelineDataHeader {
|
|||||||
pub fn stream_id(&self) -> Option<StreamId> {
|
pub fn stream_id(&self) -> Option<StreamId> {
|
||||||
match self {
|
match self {
|
||||||
PipelineDataHeader::Empty => None,
|
PipelineDataHeader::Empty => None,
|
||||||
PipelineDataHeader::Value(_) => None,
|
PipelineDataHeader::Value(_, _) => None,
|
||||||
PipelineDataHeader::ListStream(info) => Some(info.id),
|
PipelineDataHeader::ListStream(info) => Some(info.id),
|
||||||
PipelineDataHeader::ByteStream(info) => Some(info.id),
|
PipelineDataHeader::ByteStream(info) => Some(info.id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn value(value: Value) -> Self {
|
||||||
|
PipelineDataHeader::Value(value, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list_stream(info: ListStreamInfo) -> Self {
|
||||||
|
PipelineDataHeader::ListStream(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn byte_stream(info: ByteStreamInfo) -> Self {
|
||||||
|
PipelineDataHeader::ByteStream(info)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Additional information about list (value) streams
|
/// Additional information about list (value) streams
|
||||||
@ -106,6 +118,18 @@ impl PipelineDataHeader {
|
|||||||
pub struct ListStreamInfo {
|
pub struct ListStreamInfo {
|
||||||
pub id: StreamId,
|
pub id: StreamId,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
pub metadata: Option<PipelineMetadata>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ListStreamInfo {
|
||||||
|
/// Create a new `ListStreamInfo` with a unique ID
|
||||||
|
pub fn new(id: StreamId, span: Span) -> Self {
|
||||||
|
ListStreamInfo {
|
||||||
|
id,
|
||||||
|
span,
|
||||||
|
metadata: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Additional information about byte streams
|
/// Additional information about byte streams
|
||||||
@ -115,6 +139,19 @@ pub struct ByteStreamInfo {
|
|||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub type_: ByteStreamType,
|
pub type_: ByteStreamType,
|
||||||
|
pub metadata: Option<PipelineMetadata>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ByteStreamInfo {
|
||||||
|
/// Create a new `ByteStreamInfo` with a unique ID
|
||||||
|
pub fn new(id: StreamId, span: Span, type_: ByteStreamType) -> Self {
|
||||||
|
ByteStreamInfo {
|
||||||
|
id,
|
||||||
|
span,
|
||||||
|
type_,
|
||||||
|
metadata: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calls that a plugin can execute. The type parameter determines the input type.
|
/// Calls that a plugin can execute. The type parameter determines the input type.
|
||||||
@ -344,7 +381,7 @@ impl PluginCallResponse<PipelineDataHeader> {
|
|||||||
if value.is_nothing() {
|
if value.is_nothing() {
|
||||||
PluginCallResponse::PipelineData(PipelineDataHeader::Empty)
|
PluginCallResponse::PipelineData(PipelineDataHeader::Empty)
|
||||||
} else {
|
} else {
|
||||||
PluginCallResponse::PipelineData(PipelineDataHeader::Value(value))
|
PluginCallResponse::PipelineData(PipelineDataHeader::value(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,10 +55,7 @@ fn manager_consume_all_exits_after_streams_and_interfaces_are_dropped() -> Resul
|
|||||||
|
|
||||||
// Create a stream...
|
// Create a stream...
|
||||||
let stream = manager.read_pipeline_data(
|
let stream = manager.read_pipeline_data(
|
||||||
PipelineDataHeader::ListStream(ListStreamInfo {
|
PipelineDataHeader::list_stream(ListStreamInfo::new(0, Span::test_data())),
|
||||||
id: 0,
|
|
||||||
span: Span::test_data(),
|
|
||||||
}),
|
|
||||||
&Signals::empty(),
|
&Signals::empty(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -111,10 +108,7 @@ fn manager_consume_all_propagates_io_error_to_readers() -> Result<(), ShellError
|
|||||||
test.set_read_error(test_io_error());
|
test.set_read_error(test_io_error());
|
||||||
|
|
||||||
let stream = manager.read_pipeline_data(
|
let stream = manager.read_pipeline_data(
|
||||||
PipelineDataHeader::ListStream(ListStreamInfo {
|
PipelineDataHeader::list_stream(ListStreamInfo::new(0, Span::test_data())),
|
||||||
id: 0,
|
|
||||||
span: Span::test_data(),
|
|
||||||
}),
|
|
||||||
&Signals::empty(),
|
&Signals::empty(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -157,11 +151,11 @@ fn manager_consume_all_propagates_message_error_to_readers() -> Result<(), Shell
|
|||||||
test.add(invalid_input());
|
test.add(invalid_input());
|
||||||
|
|
||||||
let stream = manager.read_pipeline_data(
|
let stream = manager.read_pipeline_data(
|
||||||
PipelineDataHeader::ByteStream(ByteStreamInfo {
|
PipelineDataHeader::byte_stream(ByteStreamInfo::new(
|
||||||
id: 0,
|
0,
|
||||||
span: Span::test_data(),
|
Span::test_data(),
|
||||||
type_: ByteStreamType::Unknown,
|
ByteStreamType::Unknown,
|
||||||
}),
|
)),
|
||||||
&Signals::empty(),
|
&Signals::empty(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -414,10 +408,7 @@ fn manager_consume_call_run_forwards_to_receiver_with_pipeline_data() -> Result<
|
|||||||
positional: vec![],
|
positional: vec![],
|
||||||
named: vec![],
|
named: vec![],
|
||||||
},
|
},
|
||||||
input: PipelineDataHeader::ListStream(ListStreamInfo {
|
input: PipelineDataHeader::list_stream(ListStreamInfo::new(6, Span::test_data())),
|
||||||
id: 6,
|
|
||||||
span: Span::test_data(),
|
|
||||||
}),
|
|
||||||
}),
|
}),
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
@ -556,10 +547,10 @@ fn manager_consume_engine_call_response_forwards_to_subscriber_with_pipeline_dat
|
|||||||
|
|
||||||
manager.consume(PluginInput::EngineCallResponse(
|
manager.consume(PluginInput::EngineCallResponse(
|
||||||
0,
|
0,
|
||||||
EngineCallResponse::PipelineData(PipelineDataHeader::ListStream(ListStreamInfo {
|
EngineCallResponse::PipelineData(PipelineDataHeader::list_stream(ListStreamInfo::new(
|
||||||
id: 0,
|
0,
|
||||||
span: Span::test_data(),
|
Span::test_data(),
|
||||||
})),
|
))),
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
for i in 0..2 {
|
for i in 0..2 {
|
||||||
@ -707,7 +698,7 @@ fn interface_write_response_with_value() -> Result<(), ShellError> {
|
|||||||
assert_eq!(33, id, "id");
|
assert_eq!(33, id, "id");
|
||||||
match response {
|
match response {
|
||||||
PluginCallResponse::PipelineData(header) => match header {
|
PluginCallResponse::PipelineData(header) => match header {
|
||||||
PipelineDataHeader::Value(value) => assert_eq!(6, value.as_int()?),
|
PipelineDataHeader::Value(value, _) => assert_eq!(6, value.as_int()?),
|
||||||
_ => panic!("unexpected pipeline data header: {header:?}"),
|
_ => panic!("unexpected pipeline data header: {header:?}"),
|
||||||
},
|
},
|
||||||
_ => panic!("unexpected response: {response:?}"),
|
_ => panic!("unexpected response: {response:?}"),
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Metadata that is valid for the whole [`PipelineData`](crate::PipelineData)
|
/// Metadata that is valid for the whole [`PipelineData`](crate::PipelineData)
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
|
||||||
pub struct PipelineMetadata {
|
pub struct PipelineMetadata {
|
||||||
pub data_source: DataSource,
|
pub data_source: DataSource,
|
||||||
pub content_type: Option<String>,
|
pub content_type: Option<String>,
|
||||||
@ -27,7 +29,7 @@ impl PipelineMetadata {
|
|||||||
///
|
///
|
||||||
/// This can either be a particular family of commands (useful so downstream commands can adjust
|
/// This can either be a particular family of commands (useful so downstream commands can adjust
|
||||||
/// the presentation e.g. `Ls`) or the opened file to protect against overwrite-attempts properly.
|
/// the presentation e.g. `Ls`) or the opened file to protect against overwrite-attempts properly.
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
|
||||||
pub enum DataSource {
|
pub enum DataSource {
|
||||||
Ls,
|
Ls,
|
||||||
HtmlThemes,
|
HtmlThemes,
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
# language without adding any extra dependencies to our tests.
|
# language without adding any extra dependencies to our tests.
|
||||||
|
|
||||||
const NUSHELL_VERSION = "0.96.2"
|
const NUSHELL_VERSION = "0.96.2"
|
||||||
const PLUGIN_VERSION = "0.1.0" # bump if you change commands!
|
const PLUGIN_VERSION = "0.1.1" # bump if you change commands!
|
||||||
|
|
||||||
def main [--stdio] {
|
def main [--stdio] {
|
||||||
if ($stdio) {
|
if ($stdio) {
|
||||||
@ -133,7 +133,7 @@ def process_call [
|
|||||||
|
|
||||||
# Create a Value of type List that will be encoded and sent to Nushell
|
# Create a Value of type List that will be encoded and sent to Nushell
|
||||||
let value = {
|
let value = {
|
||||||
Value: {
|
Value: [{
|
||||||
List: {
|
List: {
|
||||||
vals: (0..9 | each { |x|
|
vals: (0..9 | each { |x|
|
||||||
{
|
{
|
||||||
@ -157,7 +157,7 @@ def process_call [
|
|||||||
}),
|
}),
|
||||||
span: $span
|
span: $span
|
||||||
}
|
}
|
||||||
}
|
}, null]
|
||||||
}
|
}
|
||||||
|
|
||||||
write_response $id { PipelineData: $value }
|
write_response $id { PipelineData: $value }
|
||||||
|
@ -28,7 +28,7 @@ import json
|
|||||||
|
|
||||||
|
|
||||||
NUSHELL_VERSION = "0.96.2"
|
NUSHELL_VERSION = "0.96.2"
|
||||||
PLUGIN_VERSION = "0.1.0" # bump if you change commands!
|
PLUGIN_VERSION = "0.1.1" # bump if you change commands!
|
||||||
|
|
||||||
|
|
||||||
def signatures():
|
def signatures():
|
||||||
@ -125,15 +125,12 @@ def process_call(id, plugin_call):
|
|||||||
span = plugin_call["call"]["head"]
|
span = plugin_call["call"]["head"]
|
||||||
|
|
||||||
# Creates a Value of type List that will be encoded and sent to Nushell
|
# Creates a Value of type List that will be encoded and sent to Nushell
|
||||||
def f(x, y): return {
|
def f(x, y):
|
||||||
"Int": {
|
return {"Int": {"val": x * y, "span": span}}
|
||||||
"val": x * y,
|
|
||||||
"span": span
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
value = {
|
value = {
|
||||||
"Value": {
|
"Value": [
|
||||||
|
{
|
||||||
"List": {
|
"List": {
|
||||||
"vals": [
|
"vals": [
|
||||||
{
|
{
|
||||||
@ -143,13 +140,16 @@ def process_call(id, plugin_call):
|
|||||||
"two": f(x, 1),
|
"two": f(x, 1),
|
||||||
"three": f(x, 2),
|
"three": f(x, 2),
|
||||||
},
|
},
|
||||||
"span": span
|
"span": span,
|
||||||
}
|
}
|
||||||
} for x in range(0, 10)
|
}
|
||||||
|
for x in range(0, 10)
|
||||||
],
|
],
|
||||||
"span": span
|
"span": span,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
write_response(id, {"PipelineData": value})
|
write_response(id, {"PipelineData": value})
|
||||||
@ -172,7 +172,7 @@ def tell_nushell_hello():
|
|||||||
"Hello": {
|
"Hello": {
|
||||||
"protocol": "nu-plugin", # always this value
|
"protocol": "nu-plugin", # always this value
|
||||||
"version": NUSHELL_VERSION,
|
"version": NUSHELL_VERSION,
|
||||||
"features": []
|
"features": [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sys.stdout.write(json.dumps(hello))
|
sys.stdout.write(json.dumps(hello))
|
||||||
@ -200,7 +200,8 @@ def write_error(id, text, span=None):
|
|||||||
Use this error format to send errors to nushell in response to a plugin call. The ID of the
|
Use this error format to send errors to nushell in response to a plugin call. The ID of the
|
||||||
plugin call is required.
|
plugin call is required.
|
||||||
"""
|
"""
|
||||||
error = {
|
error = (
|
||||||
|
{
|
||||||
"Error": {
|
"Error": {
|
||||||
"msg": "ERROR from plugin",
|
"msg": "ERROR from plugin",
|
||||||
"labels": [
|
"labels": [
|
||||||
@ -210,12 +211,15 @@ def write_error(id, text, span=None):
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
} if span is not None else {
|
}
|
||||||
|
if span is not None
|
||||||
|
else {
|
||||||
"Error": {
|
"Error": {
|
||||||
"msg": "ERROR from plugin",
|
"msg": "ERROR from plugin",
|
||||||
"help": text,
|
"help": text,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
)
|
||||||
write_response(id, error)
|
write_response(id, error)
|
||||||
|
|
||||||
|
|
||||||
@ -230,11 +234,14 @@ def handle_input(input):
|
|||||||
elif "Call" in input:
|
elif "Call" in input:
|
||||||
[id, plugin_call] = input["Call"]
|
[id, plugin_call] = input["Call"]
|
||||||
if plugin_call == "Metadata":
|
if plugin_call == "Metadata":
|
||||||
write_response(id, {
|
write_response(
|
||||||
|
id,
|
||||||
|
{
|
||||||
"Metadata": {
|
"Metadata": {
|
||||||
"version": PLUGIN_VERSION,
|
"version": PLUGIN_VERSION,
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
)
|
||||||
elif plugin_call == "Signature":
|
elif plugin_call == "Signature":
|
||||||
write_response(id, signatures())
|
write_response(id, signatures())
|
||||||
elif "Run" in plugin_call:
|
elif "Run" in plugin_call:
|
||||||
|
@ -178,7 +178,7 @@ fn handle_message(
|
|||||||
id,
|
id,
|
||||||
{
|
{
|
||||||
"PipelineData": {
|
"PipelineData": {
|
||||||
"Value": return_value
|
"Value": [return_value, null]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user