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:
Devyn Cairns
2024-04-21 05:36:26 -07:00
committed by GitHub
parent 6cba7c6b40
commit 2595f31541
45 changed files with 1462 additions and 211 deletions

View File

@ -340,7 +340,7 @@ impl Command for Nu {
signature = signature.named(
"plugin-config",
SyntaxShape::String,
"start with an alternate plugin signature file",
"start with an alternate plugin cache file",
None,
);
}

View File

@ -214,7 +214,7 @@ pub(crate) fn setup_config(
);
let result = catch_unwind(AssertUnwindSafe(|| {
#[cfg(feature = "plugin")]
read_plugin_file(engine_state, stack, plugin_file, NUSHELL_FOLDER);
read_plugin_file(engine_state, plugin_file, NUSHELL_FOLDER);
read_config_file(engine_state, stack, env_file, true);
read_config_file(engine_state, stack, config_file, false);

View File

@ -43,6 +43,8 @@ use std::{
fn get_engine_state() -> EngineState {
let engine_state = nu_cmd_lang::create_default_context();
#[cfg(feature = "plugin")]
let engine_state = nu_cmd_plugin::add_plugin_command_context(engine_state);
let engine_state = nu_command::add_shell_command_context(engine_state);
let engine_state = nu_cmd_extra::add_extra_command_context(engine_state);
#[cfg(feature = "dataframe")]

View File

@ -30,12 +30,7 @@ pub(crate) fn run_commands(
// if the --no-config-file(-n) flag is passed, do not load plugin, env, or config files
if parsed_nu_cli_args.no_config_file.is_none() {
#[cfg(feature = "plugin")]
read_plugin_file(
engine_state,
&mut stack,
parsed_nu_cli_args.plugin_file,
NUSHELL_FOLDER,
);
read_plugin_file(engine_state, parsed_nu_cli_args.plugin_file, NUSHELL_FOLDER);
perf(
"read plugins",
@ -155,12 +150,7 @@ pub(crate) fn run_file(
if parsed_nu_cli_args.no_config_file.is_none() {
let start_time = std::time::Instant::now();
#[cfg(feature = "plugin")]
read_plugin_file(
engine_state,
&mut stack,
parsed_nu_cli_args.plugin_file,
NUSHELL_FOLDER,
);
read_plugin_file(engine_state, parsed_nu_cli_args.plugin_file, NUSHELL_FOLDER);
perf(
"read plugins",
start_time,

View File

@ -117,7 +117,7 @@ fn test_config_path_helper(playground: &mut Playground, config_dir_nushell: Path
#[cfg(feature = "plugin")]
{
let plugin_path = config_dir_nushell.join("plugin.nu");
let plugin_path = config_dir_nushell.join("plugin.msgpackz");
let canon_plugin_path =
adjust_canonicalization(std::fs::canonicalize(&plugin_path).unwrap_or(plugin_path));
let actual = run(playground, "$nu.plugin-path");
@ -161,7 +161,7 @@ fn test_default_symlink_config_path_broken_symlink_config_files() {
"history.txt",
"history.sqlite3",
"login.nu",
"plugin.nu",
"plugin.msgpackz",
] {
let fake_file = fake_dir.join(config_file);
File::create(playground.cwd().join(&fake_file)).unwrap();
@ -194,7 +194,7 @@ fn test_default_config_path_symlinked_config_files() {
"history.txt",
"history.sqlite3",
"login.nu",
"plugin.nu",
"plugin.msgpackz",
] {
let empty_file = playground.cwd().join(format!("empty-{config_file}"));
File::create(&empty_file).unwrap();