mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 09:45:50 +02:00
Overhaul the plugin cache file with a new msgpack+brotli format (#12579)
# Description - Plugin signatures are now saved to `plugin.msgpackz`, which is brotli-compressed MessagePack. - The file is updated incrementally, rather than writing all plugin commands in the engine every time. - The file always contains the result of the `Signature` call to the plugin, even if commands were removed. - Invalid data for a particular plugin just causes an error to be reported, but the rest of the plugins can still be parsed # User-Facing Changes - The plugin file has a different filename, and it's not a nushell script. - The default `plugin.nu` file will be automatically migrated the first time, but not other plugin config files. - We don't currently provide any utilities that could help edit this file, beyond `plugin add` and `plugin rm` - `from msgpackz`, `to msgpackz` could also help - New commands: `plugin add`, `plugin rm` # Tests + Formatting Tests added for the format and for the invalid handling. - 🟢 `toolkit fmt` - 🟢 `toolkit clippy` - 🟢 `toolkit test` - 🟢 `toolkit test stdlib` # After Submitting - [ ] Check for documentation changes - [ ] Definitely needs release notes
This commit is contained in:
@ -71,13 +71,3 @@ pub use try_::Try;
|
||||
pub use use_::Use;
|
||||
pub use version::Version;
|
||||
pub use while_::While;
|
||||
|
||||
mod plugin;
|
||||
mod plugin_list;
|
||||
mod plugin_stop;
|
||||
mod register;
|
||||
|
||||
pub use plugin::PluginCommand;
|
||||
pub use plugin_list::PluginList;
|
||||
pub use plugin_stop::PluginStop;
|
||||
pub use register::Register;
|
||||
|
@ -1,59 +0,0 @@
|
||||
use nu_engine::{command_prelude::*, get_full_help};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PluginCommand;
|
||||
|
||||
impl Command for PluginCommand {
|
||||
fn name(&self) -> &str {
|
||||
"plugin"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("plugin")
|
||||
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
|
||||
.category(Category::Core)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Commands for managing plugins."
|
||||
}
|
||||
|
||||
fn extra_usage(&self) -> &str {
|
||||
"To load a plugin, see `register`."
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
Ok(Value::string(
|
||||
get_full_help(
|
||||
&PluginCommand.signature(),
|
||||
&PluginCommand.examples(),
|
||||
engine_state,
|
||||
stack,
|
||||
self.is_parser_keyword(),
|
||||
),
|
||||
call.head,
|
||||
)
|
||||
.into_pipeline_data())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
example: "plugin list",
|
||||
description: "List installed plugins",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
example: "plugin stop inc",
|
||||
description: "Stop the plugin named `inc`.",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
use itertools::Itertools;
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PluginList;
|
||||
|
||||
impl Command for PluginList {
|
||||
fn name(&self) -> &str {
|
||||
"plugin list"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("plugin list")
|
||||
.input_output_type(
|
||||
Type::Nothing,
|
||||
Type::Table(vec![
|
||||
("name".into(), Type::String),
|
||||
("is_running".into(), Type::Bool),
|
||||
("pid".into(), Type::Int),
|
||||
("filename".into(), Type::String),
|
||||
("shell".into(), Type::String),
|
||||
("commands".into(), Type::List(Type::String.into())),
|
||||
]),
|
||||
)
|
||||
.category(Category::Core)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"List installed plugins."
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<nu_protocol::Example> {
|
||||
vec![
|
||||
Example {
|
||||
example: "plugin list",
|
||||
description: "List installed plugins.",
|
||||
result: Some(Value::test_list(vec![Value::test_record(record! {
|
||||
"name" => Value::test_string("inc"),
|
||||
"is_running" => Value::test_bool(true),
|
||||
"pid" => Value::test_int(106480),
|
||||
"filename" => if cfg!(windows) {
|
||||
Value::test_string(r"C:\nu\plugins\nu_plugin_inc.exe")
|
||||
} else {
|
||||
Value::test_string("/opt/nu/plugins/nu_plugin_inc")
|
||||
},
|
||||
"shell" => Value::test_nothing(),
|
||||
"commands" => Value::test_list(vec![Value::test_string("inc")]),
|
||||
})])),
|
||||
},
|
||||
Example {
|
||||
example: "ps | where pid in (plugin list).pid",
|
||||
description: "Get process information for running plugins.",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let span = call.span();
|
||||
// Group plugin decls by plugin identity
|
||||
let decls = engine_state.plugin_decls().into_group_map_by(|decl| {
|
||||
decl.plugin_identity()
|
||||
.expect("plugin decl should have identity")
|
||||
});
|
||||
// Build plugins list
|
||||
let list = engine_state.plugins().iter().map(|plugin| {
|
||||
// Find commands that belong to the plugin
|
||||
let commands = decls.get(plugin.identity())
|
||||
.into_iter()
|
||||
.flat_map(|decls| {
|
||||
decls.iter().map(|decl| Value::string(decl.name(), span))
|
||||
})
|
||||
.collect();
|
||||
|
||||
Value::record(record! {
|
||||
"name" => Value::string(plugin.identity().name(), span),
|
||||
"is_running" => Value::bool(plugin.is_running(), span),
|
||||
"pid" => plugin.pid()
|
||||
.map(|p| Value::int(p as i64, span))
|
||||
.unwrap_or(Value::nothing(span)),
|
||||
"filename" => Value::string(plugin.identity().filename().to_string_lossy(), span),
|
||||
"shell" => plugin.identity().shell()
|
||||
.map(|s| Value::string(s.to_string_lossy(), span))
|
||||
.unwrap_or(Value::nothing(span)),
|
||||
"commands" => Value::list(commands, span),
|
||||
}, span)
|
||||
}).collect::<Vec<Value>>();
|
||||
Ok(list.into_pipeline_data(engine_state.ctrlc.clone()))
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PluginStop;
|
||||
|
||||
impl Command for PluginStop {
|
||||
fn name(&self) -> &str {
|
||||
"plugin stop"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("plugin stop")
|
||||
.input_output_type(Type::Nothing, Type::Nothing)
|
||||
.required(
|
||||
"name",
|
||||
SyntaxShape::String,
|
||||
"The name of the plugin to stop.",
|
||||
)
|
||||
.category(Category::Core)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Stop an installed plugin if it was running."
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<nu_protocol::Example> {
|
||||
vec![
|
||||
Example {
|
||||
example: "plugin stop inc",
|
||||
description: "Stop the plugin named `inc`.",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
example: "plugin list | each { |p| plugin stop $p.name }",
|
||||
description: "Stop all plugins.",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let name: Spanned<String> = call.req(engine_state, stack, 0)?;
|
||||
|
||||
let mut found = false;
|
||||
for plugin in engine_state.plugins() {
|
||||
if plugin.identity().name() == name.item {
|
||||
plugin.stop()?;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
Ok(PipelineData::Empty)
|
||||
} else {
|
||||
Err(ShellError::GenericError {
|
||||
error: format!("Failed to stop the `{}` plugin", name.item),
|
||||
msg: "couldn't find a plugin with this name".into(),
|
||||
span: Some(name.span),
|
||||
help: Some("you may need to `register` the plugin first".into()),
|
||||
inner: vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Register;
|
||||
|
||||
impl Command for Register {
|
||||
fn name(&self) -> &str {
|
||||
"register"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Register a plugin."
|
||||
}
|
||||
|
||||
fn signature(&self) -> nu_protocol::Signature {
|
||||
Signature::build("register")
|
||||
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
|
||||
.required(
|
||||
"plugin",
|
||||
SyntaxShape::Filepath,
|
||||
"Path of executable for plugin.",
|
||||
)
|
||||
.optional(
|
||||
"signature",
|
||||
SyntaxShape::Any,
|
||||
"Block with signature description as json object.",
|
||||
)
|
||||
.named(
|
||||
"shell",
|
||||
SyntaxShape::Filepath,
|
||||
"path of shell used to run plugin (cmd, sh, python, etc)",
|
||||
Some('s'),
|
||||
)
|
||||
.category(Category::Core)
|
||||
}
|
||||
|
||||
fn extra_usage(&self) -> &str {
|
||||
r#"This command is a parser keyword. For details, check:
|
||||
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||
}
|
||||
|
||||
fn is_parser_keyword(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
_call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Register `nu_plugin_query` plugin from ~/.cargo/bin/ dir",
|
||||
example: r#"register ~/.cargo/bin/nu_plugin_query"#,
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Register `nu_plugin_query` plugin from `nu -c` (writes/updates $nu.plugin-path)",
|
||||
example: r#"let plugin = ((which nu).path.0 | path dirname | path join 'nu_plugin_query'); nu -c $'register ($plugin); version'"#,
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
@ -63,9 +63,6 @@ pub fn create_default_context() -> EngineState {
|
||||
While,
|
||||
};
|
||||
|
||||
//#[cfg(feature = "plugin")]
|
||||
bind_command!(PluginCommand, PluginList, PluginStop, Register,);
|
||||
|
||||
working_set.render()
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user