mirror of
https://github.com/nushell/nushell.git
synced 2025-02-18 03:21:05 +01:00
# Description This allows plugins to report their version (and potentially other metadata in the future). The version is shown in `plugin list` and in `version`. The metadata is stored in the registry file, and reflects whatever was retrieved on `plugin add`, not necessarily the running binary. This can help you to diagnose if there's some kind of mismatch with what you expect. We could potentially use this functionality to show a warning or error if a plugin being run does not have the same version as what was in the cache file, suggesting `plugin add` be run again, but I haven't done that at this point. It is optional, and it requires the plugin author to make some code changes if they want to provide it, since I can't automatically determine the version of the calling crate or anything tricky like that to do it. Example: ``` > plugin list | select name version is_running pid ╭───┬────────────────┬─────────┬────────────┬─────╮ │ # │ name │ version │ is_running │ pid │ ├───┼────────────────┼─────────┼────────────┼─────┤ │ 0 │ example │ 0.93.1 │ false │ │ │ 1 │ gstat │ 0.93.1 │ false │ │ │ 2 │ inc │ 0.93.1 │ false │ │ │ 3 │ python_example │ 0.1.0 │ false │ │ ╰───┴────────────────┴─────────┴────────────┴─────╯ ``` cc @maxim-uvarov (he asked for it) # User-Facing Changes - `plugin list` gets a `version` column - `version` shows plugin versions when available - plugin authors *should* add `fn metadata()` to their `impl Plugin`, but don't have to # Tests + Formatting Tested the low level stuff and also the `plugin list` column. # After Submitting - [ ] update plugin guide docs - [ ] update plugin protocol docs (`Metadata` call & response) - [ ] update plugin template (`fn metadata()` should be easy) - [ ] release notes
108 lines
2.8 KiB
Rust
108 lines
2.8 KiB
Rust
use std::{
|
|
collections::BTreeMap,
|
|
sync::{atomic::AtomicU64, Mutex},
|
|
};
|
|
|
|
use handle_custom_value::HandleCustomValue;
|
|
use nu_plugin::{serve_plugin, EngineInterface, MsgPackSerializer, Plugin, PluginCommand};
|
|
|
|
mod cool_custom_value;
|
|
mod handle_custom_value;
|
|
mod second_custom_value;
|
|
|
|
mod drop_check;
|
|
mod generate;
|
|
mod generate2;
|
|
mod handle_get;
|
|
mod handle_make;
|
|
mod handle_update;
|
|
mod update;
|
|
mod update_arg;
|
|
|
|
use drop_check::{DropCheck, DropCheckValue};
|
|
use generate::Generate;
|
|
use generate2::Generate2;
|
|
use handle_get::HandleGet;
|
|
use handle_make::HandleMake;
|
|
use handle_update::HandleUpdate;
|
|
use nu_protocol::{CustomValue, LabeledError, Spanned, Value};
|
|
use update::Update;
|
|
use update_arg::UpdateArg;
|
|
|
|
#[derive(Default)]
|
|
pub struct CustomValuePlugin {
|
|
counter: AtomicU64,
|
|
handles: Mutex<BTreeMap<u64, Value>>,
|
|
}
|
|
|
|
impl CustomValuePlugin {
|
|
pub fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
}
|
|
|
|
impl Plugin for CustomValuePlugin {
|
|
fn version(&self) -> String {
|
|
env!("CARGO_PKG_VERSION").into()
|
|
}
|
|
|
|
fn commands(&self) -> Vec<Box<dyn PluginCommand<Plugin = Self>>> {
|
|
vec![
|
|
Box::new(Generate),
|
|
Box::new(Generate2),
|
|
Box::new(Update),
|
|
Box::new(UpdateArg),
|
|
Box::new(DropCheck),
|
|
Box::new(HandleGet),
|
|
Box::new(HandleMake),
|
|
Box::new(HandleUpdate),
|
|
]
|
|
}
|
|
|
|
fn custom_value_to_base_value(
|
|
&self,
|
|
_engine: &EngineInterface,
|
|
custom_value: Spanned<Box<dyn CustomValue>>,
|
|
) -> Result<Value, LabeledError> {
|
|
// HandleCustomValue depends on the plugin state to get.
|
|
if let Some(handle) = custom_value
|
|
.item
|
|
.as_any()
|
|
.downcast_ref::<HandleCustomValue>()
|
|
{
|
|
Ok(self
|
|
.handles
|
|
.lock()
|
|
.map_err(|err| LabeledError::new(err.to_string()))?
|
|
.get(&handle.0)
|
|
.cloned()
|
|
.unwrap_or_else(|| Value::nothing(custom_value.span)))
|
|
} else {
|
|
custom_value
|
|
.item
|
|
.to_base_value(custom_value.span)
|
|
.map_err(|err| err.into())
|
|
}
|
|
}
|
|
|
|
fn custom_value_dropped(
|
|
&self,
|
|
_engine: &EngineInterface,
|
|
custom_value: Box<dyn CustomValue>,
|
|
) -> Result<(), LabeledError> {
|
|
// This is how we implement our drop behavior.
|
|
if let Some(drop_check) = custom_value.as_any().downcast_ref::<DropCheckValue>() {
|
|
drop_check.notify();
|
|
} else if let Some(handle) = custom_value.as_any().downcast_ref::<HandleCustomValue>() {
|
|
if let Ok(mut handles) = self.handles.lock() {
|
|
handles.remove(&handle.0);
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
serve_plugin(&CustomValuePlugin::default(), MsgPackSerializer {})
|
|
}
|