mirror of
https://github.com/nushell/nushell.git
synced 2025-04-30 08:04:25 +02:00
# Description Close: #15083 This pr will set `pre` field of version to `Prerelease::EMPTY`, as nushell does not require this level of checking currently. # User-Facing Changes NaN # Tests + Formatting Added 1 test # After Submitting NaN
114 lines
4.3 KiB
Rust
114 lines
4.3 KiB
Rust
use nu_protocol::ShellError;
|
|
use semver::Prerelease;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// Protocol information, sent as a `Hello` message on initialization. This determines the
|
|
/// compatibility of the plugin and engine. They are considered to be compatible if the lower
|
|
/// version is semver compatible with the higher one.
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub struct ProtocolInfo {
|
|
/// The name of the protocol being implemented. Only one protocol is supported. This field
|
|
/// can be safely ignored, because not matching is a deserialization error
|
|
pub protocol: Protocol,
|
|
/// The semantic version of the protocol. This should be the version of the `nu-plugin-protocol`
|
|
/// crate
|
|
pub version: String,
|
|
/// Supported optional features. This helps to maintain semver compatibility when adding new
|
|
/// features
|
|
pub features: Vec<Feature>,
|
|
}
|
|
|
|
impl Default for ProtocolInfo {
|
|
fn default() -> ProtocolInfo {
|
|
ProtocolInfo {
|
|
protocol: Protocol::NuPlugin,
|
|
version: env!("CARGO_PKG_VERSION").into(),
|
|
features: default_features(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ProtocolInfo {
|
|
/// True if the version specified in `self` is compatible with the version specified in `other`.
|
|
pub fn is_compatible_with(&self, other: &ProtocolInfo) -> Result<bool, ShellError> {
|
|
fn parse_failed(error: semver::Error) -> ShellError {
|
|
ShellError::PluginFailedToLoad {
|
|
msg: format!("Failed to parse protocol version: {error}"),
|
|
}
|
|
}
|
|
let mut versions = [
|
|
semver::Version::parse(&self.version).map_err(parse_failed)?,
|
|
semver::Version::parse(&other.version).map_err(parse_failed)?,
|
|
];
|
|
|
|
versions.sort();
|
|
|
|
// The version may be a nightly version (1.2.3-nightly.1).
|
|
// It's good to mark the prerelease field as empty, so plugins
|
|
// can work with a nightly version of Nushell.
|
|
versions[1].pre = Prerelease::EMPTY;
|
|
versions[0].pre = Prerelease::EMPTY;
|
|
|
|
// For example, if the lower version is 1.1.0, and the higher version is 1.2.3, the
|
|
// requirement is that 1.2.3 matches ^1.1.0 (which it does)
|
|
Ok(semver::Comparator {
|
|
op: semver::Op::Caret,
|
|
major: versions[0].major,
|
|
minor: Some(versions[0].minor),
|
|
patch: Some(versions[0].patch),
|
|
pre: versions[0].pre.clone(),
|
|
}
|
|
.matches(&versions[1]))
|
|
}
|
|
|
|
/// True if the protocol info contains a feature compatible with the given feature.
|
|
pub fn supports_feature(&self, feature: &Feature) -> bool {
|
|
self.features.iter().any(|f| feature.is_compatible_with(f))
|
|
}
|
|
}
|
|
|
|
/// Indicates the protocol in use. Only one protocol is supported.
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
|
pub enum Protocol {
|
|
/// Serializes to the value `"nu-plugin"`
|
|
#[serde(rename = "nu-plugin")]
|
|
#[default]
|
|
NuPlugin,
|
|
}
|
|
|
|
/// Indicates optional protocol features. This can help to make non-breaking-change additions to
|
|
/// the protocol. Features are not restricted to plain strings and can contain additional
|
|
/// configuration data.
|
|
///
|
|
/// Optional features should not be used by the protocol if they are not present in the
|
|
/// [`ProtocolInfo`] sent by the other side.
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
#[serde(tag = "name")]
|
|
pub enum Feature {
|
|
/// The plugin supports running with a local socket passed via `--local-socket` instead of
|
|
/// stdio.
|
|
LocalSocket,
|
|
|
|
/// A feature that was not recognized on deserialization. Attempting to serialize this feature
|
|
/// is an error. Matching against it may only be used if necessary to determine whether
|
|
/// unsupported features are present.
|
|
#[serde(other, skip_serializing)]
|
|
Unknown,
|
|
}
|
|
|
|
impl Feature {
|
|
/// True if the feature is considered to be compatible with another feature.
|
|
pub fn is_compatible_with(&self, other: &Feature) -> bool {
|
|
matches!((self, other), (Feature::LocalSocket, Feature::LocalSocket))
|
|
}
|
|
}
|
|
|
|
/// Protocol features compiled into this version of `nu-plugin`.
|
|
pub fn default_features() -> Vec<Feature> {
|
|
vec![
|
|
// Only available if compiled with the `local-socket` feature flag (enabled by default).
|
|
#[cfg(feature = "local-socket")]
|
|
Feature::LocalSocket,
|
|
]
|
|
}
|