mirror of
https://github.com/nushell/nushell.git
synced 2025-06-30 22:50:14 +02:00
Revert PRs for 0.99.1 patch (#14119)
# Description Temporarily reverts PRs merged after the 0.99.1 bump.
This commit is contained in:
@ -119,7 +119,7 @@ apparent the next time `nu` is next launched with that plugin registry file.
|
||||
let metadata = interface.get_metadata()?;
|
||||
let commands = interface.get_signature()?;
|
||||
|
||||
modify_plugin_file(engine_state, stack, call.head, &custom_path, |contents| {
|
||||
modify_plugin_file(engine_state, stack, call.head, custom_path, |contents| {
|
||||
// Update the file with the received metadata and signatures
|
||||
let item = PluginRegistryItem::new(plugin.identity(), metadata, commands);
|
||||
contents.upsert_plugin(item);
|
||||
|
@ -1,8 +1,5 @@
|
||||
use itertools::{EitherOrBoth, Itertools};
|
||||
use itertools::Itertools;
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::{IntoValue, PluginRegistryItemData};
|
||||
|
||||
use crate::util::read_plugin_file;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PluginList;
|
||||
@ -20,7 +17,7 @@ impl Command for PluginList {
|
||||
[
|
||||
("name".into(), Type::String),
|
||||
("version".into(), Type::String),
|
||||
("status".into(), Type::String),
|
||||
("is_running".into(), Type::Bool),
|
||||
("pid".into(), Type::Int),
|
||||
("filename".into(), Type::String),
|
||||
("shell".into(), Type::String),
|
||||
@ -29,54 +26,11 @@ impl Command for PluginList {
|
||||
.into(),
|
||||
),
|
||||
)
|
||||
.named(
|
||||
"plugin-config",
|
||||
SyntaxShape::Filepath,
|
||||
"Use a plugin registry file other than the one set in `$nu.plugin-path`",
|
||||
None,
|
||||
)
|
||||
.switch(
|
||||
"engine",
|
||||
"Show info for plugins that are loaded into the engine only.",
|
||||
Some('e'),
|
||||
)
|
||||
.switch(
|
||||
"registry",
|
||||
"Show info for plugins from the registry file only.",
|
||||
Some('r'),
|
||||
)
|
||||
.category(Category::Plugin)
|
||||
}
|
||||
|
||||
fn description(&self) -> &str {
|
||||
"List loaded and installed plugins."
|
||||
}
|
||||
|
||||
fn extra_description(&self) -> &str {
|
||||
r#"
|
||||
The `status` column will contain one of the following values:
|
||||
|
||||
- `added`: The plugin is present in the plugin registry file, but not in
|
||||
the engine.
|
||||
- `loaded`: The plugin is present both in the plugin registry file and in
|
||||
the engine, but is not running.
|
||||
- `running`: The plugin is currently running, and the `pid` column should
|
||||
contain its process ID.
|
||||
- `modified`: The plugin state present in the plugin registry file is different
|
||||
from the state in the engine.
|
||||
- `removed`: The plugin is still loaded in the engine, but is not present in
|
||||
the plugin registry file.
|
||||
- `invalid`: The data in the plugin registry file couldn't be deserialized,
|
||||
and the plugin most likely needs to be added again.
|
||||
|
||||
`running` takes priority over any other status. Unless `--registry` is used
|
||||
or the plugin has not been loaded yet, the values of `version`, `filename`,
|
||||
`shell`, and `commands` reflect the values in the engine and not the ones in
|
||||
the plugin registry file.
|
||||
|
||||
See also: `plugin use`
|
||||
"#
|
||||
.trim()
|
||||
"List installed plugins."
|
||||
}
|
||||
|
||||
fn search_terms(&self) -> Vec<&str> {
|
||||
@ -91,7 +45,7 @@ See also: `plugin use`
|
||||
result: Some(Value::test_list(vec![Value::test_record(record! {
|
||||
"name" => Value::test_string("inc"),
|
||||
"version" => Value::test_string(env!("CARGO_PKG_VERSION")),
|
||||
"status" => Value::test_string("running"),
|
||||
"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")
|
||||
@ -113,189 +67,58 @@ See also: `plugin use`
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let custom_path = call.get_flag(engine_state, stack, "plugin-config")?;
|
||||
let engine_mode = call.has_flag(engine_state, stack, "engine")?;
|
||||
let registry_mode = call.has_flag(engine_state, stack, "registry")?;
|
||||
let head = call.head;
|
||||
|
||||
let plugins_info = match (engine_mode, registry_mode) {
|
||||
// --engine and --registry together is equivalent to the default.
|
||||
(false, false) | (true, true) => {
|
||||
if engine_state.plugin_path.is_some() || custom_path.is_some() {
|
||||
let plugins_in_engine = get_plugins_in_engine(engine_state);
|
||||
let plugins_in_registry =
|
||||
get_plugins_in_registry(engine_state, stack, call.head, &custom_path)?;
|
||||
merge_plugin_info(plugins_in_engine, plugins_in_registry)
|
||||
} else {
|
||||
// Don't produce error when running nu --no-config-file
|
||||
get_plugins_in_engine(engine_state)
|
||||
}
|
||||
}
|
||||
(true, false) => get_plugins_in_engine(engine_state),
|
||||
(false, true) => get_plugins_in_registry(engine_state, stack, call.head, &custom_path)?,
|
||||
};
|
||||
// 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")
|
||||
});
|
||||
|
||||
Ok(plugins_info.into_value(call.head).into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, IntoValue, PartialOrd, Ord, PartialEq, Eq)]
|
||||
struct PluginInfo {
|
||||
name: String,
|
||||
version: Option<String>,
|
||||
status: PluginStatus,
|
||||
pid: Option<u32>,
|
||||
filename: String,
|
||||
shell: Option<String>,
|
||||
commands: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, IntoValue, PartialOrd, Ord, PartialEq, Eq)]
|
||||
#[nu_value(rename_all = "snake_case")]
|
||||
enum PluginStatus {
|
||||
Added,
|
||||
Loaded,
|
||||
Running,
|
||||
Modified,
|
||||
Removed,
|
||||
Invalid,
|
||||
}
|
||||
|
||||
fn get_plugins_in_engine(engine_state: &EngineState) -> Vec<PluginInfo> {
|
||||
// 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
|
||||
engine_state
|
||||
.plugins()
|
||||
.iter()
|
||||
.map(|plugin| {
|
||||
// Build plugins list
|
||||
let list = engine_state.plugins().iter().map(|plugin| {
|
||||
// Find commands that belong to the plugin
|
||||
let commands = decls
|
||||
.get(plugin.identity())
|
||||
let commands = decls.get(plugin.identity())
|
||||
.into_iter()
|
||||
.flat_map(|decls| decls.iter().map(|decl| decl.name().to_owned()))
|
||||
.sorted()
|
||||
.flat_map(|decls| {
|
||||
decls.iter().map(|decl| Value::string(decl.name(), head))
|
||||
})
|
||||
.collect();
|
||||
|
||||
PluginInfo {
|
||||
name: plugin.identity().name().into(),
|
||||
version: plugin.metadata().and_then(|m| m.version),
|
||||
status: if plugin.pid().is_some() {
|
||||
PluginStatus::Running
|
||||
} else {
|
||||
PluginStatus::Loaded
|
||||
},
|
||||
pid: plugin.pid(),
|
||||
filename: plugin.identity().filename().to_string_lossy().into_owned(),
|
||||
shell: plugin
|
||||
.identity()
|
||||
.shell()
|
||||
.map(|path| path.to_string_lossy().into_owned()),
|
||||
commands,
|
||||
}
|
||||
})
|
||||
.sorted()
|
||||
.collect()
|
||||
}
|
||||
let pid = plugin
|
||||
.pid()
|
||||
.map(|p| Value::int(p as i64, head))
|
||||
.unwrap_or(Value::nothing(head));
|
||||
|
||||
fn get_plugins_in_registry(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
span: Span,
|
||||
custom_path: &Option<Spanned<String>>,
|
||||
) -> Result<Vec<PluginInfo>, ShellError> {
|
||||
let plugin_file_contents = read_plugin_file(engine_state, stack, span, custom_path)?;
|
||||
let shell = plugin
|
||||
.identity()
|
||||
.shell()
|
||||
.map(|s| Value::string(s.to_string_lossy(), head))
|
||||
.unwrap_or(Value::nothing(head));
|
||||
|
||||
let plugins_info = plugin_file_contents
|
||||
.plugins
|
||||
.into_iter()
|
||||
.map(|plugin| {
|
||||
let mut info = PluginInfo {
|
||||
name: plugin.name,
|
||||
version: None,
|
||||
status: PluginStatus::Added,
|
||||
pid: None,
|
||||
filename: plugin.filename.to_string_lossy().into_owned(),
|
||||
shell: plugin.shell.map(|path| path.to_string_lossy().into_owned()),
|
||||
commands: vec![],
|
||||
let metadata = plugin.metadata();
|
||||
let version = metadata
|
||||
.and_then(|m| m.version)
|
||||
.map(|s| Value::string(s, head))
|
||||
.unwrap_or(Value::nothing(head));
|
||||
|
||||
let record = record! {
|
||||
"name" => Value::string(plugin.identity().name(), head),
|
||||
"version" => version,
|
||||
"is_running" => Value::bool(plugin.is_running(), head),
|
||||
"pid" => pid,
|
||||
"filename" => Value::string(plugin.identity().filename().to_string_lossy(), head),
|
||||
"shell" => shell,
|
||||
"commands" => Value::list(commands, head),
|
||||
};
|
||||
|
||||
if let PluginRegistryItemData::Valid { metadata, commands } = plugin.data {
|
||||
info.version = metadata.version;
|
||||
info.commands = commands
|
||||
.into_iter()
|
||||
.map(|command| command.sig.name)
|
||||
.sorted()
|
||||
.collect();
|
||||
} else {
|
||||
info.status = PluginStatus::Invalid;
|
||||
}
|
||||
info
|
||||
})
|
||||
.sorted()
|
||||
.collect();
|
||||
Value::record(record, head)
|
||||
}).collect();
|
||||
|
||||
Ok(plugins_info)
|
||||
}
|
||||
|
||||
/// If no options are provided, the command loads from both the plugin list in the engine and what's
|
||||
/// in the registry file. We need to reconcile the two to set the proper states and make sure that
|
||||
/// new plugins that were added to the plugin registry file show up.
|
||||
fn merge_plugin_info(
|
||||
from_engine: Vec<PluginInfo>,
|
||||
from_registry: Vec<PluginInfo>,
|
||||
) -> Vec<PluginInfo> {
|
||||
from_engine
|
||||
.into_iter()
|
||||
.merge_join_by(from_registry, |info_a, info_b| {
|
||||
info_a.name.cmp(&info_b.name)
|
||||
})
|
||||
.map(|either_or_both| match either_or_both {
|
||||
// Exists in the engine, but not in the registry file
|
||||
EitherOrBoth::Left(info) => PluginInfo {
|
||||
status: match info.status {
|
||||
PluginStatus::Running => info.status,
|
||||
// The plugin is not in the registry file, so it should be marked as `removed`
|
||||
_ => PluginStatus::Removed,
|
||||
},
|
||||
..info
|
||||
},
|
||||
// Exists in the registry file, but not in the engine
|
||||
EitherOrBoth::Right(info) => info,
|
||||
// Exists in both
|
||||
EitherOrBoth::Both(info_engine, info_registry) => PluginInfo {
|
||||
status: match (info_engine.status, info_registry.status) {
|
||||
// Above all, `running` should be displayed if the plugin is running
|
||||
(PluginStatus::Running, _) => PluginStatus::Running,
|
||||
// `invalid` takes precedence over other states because the user probably wants
|
||||
// to fix it
|
||||
(_, PluginStatus::Invalid) => PluginStatus::Invalid,
|
||||
// Display `modified` if the state in the registry is different somehow
|
||||
_ if info_engine.is_modified(&info_registry) => PluginStatus::Modified,
|
||||
// Otherwise, `loaded` (it's not running)
|
||||
_ => PluginStatus::Loaded,
|
||||
},
|
||||
..info_engine
|
||||
},
|
||||
})
|
||||
.sorted()
|
||||
.collect()
|
||||
}
|
||||
|
||||
impl PluginInfo {
|
||||
/// True if the plugin info shows some kind of change (other than status/pid) relative to the
|
||||
/// other
|
||||
fn is_modified(&self, other: &PluginInfo) -> bool {
|
||||
self.name != other.name
|
||||
|| self.filename != other.filename
|
||||
|| self.shell != other.shell
|
||||
|| self.commands != other.commands
|
||||
Ok(Value::list(list, head).into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ fixed with `plugin add`.
|
||||
|
||||
let filename = canonicalize_possible_filename_arg(engine_state, stack, &name.item);
|
||||
|
||||
modify_plugin_file(engine_state, stack, call.head, &custom_path, |contents| {
|
||||
modify_plugin_file(engine_state, stack, call.head, custom_path, |contents| {
|
||||
if let Some(index) = contents
|
||||
.plugins
|
||||
.iter()
|
||||
|
@ -6,17 +6,18 @@ use std::{
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
fn get_plugin_registry_file_path(
|
||||
pub(crate) fn modify_plugin_file(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
span: Span,
|
||||
custom_path: &Option<Spanned<String>>,
|
||||
) -> Result<PathBuf, ShellError> {
|
||||
custom_path: Option<Spanned<String>>,
|
||||
operate: impl FnOnce(&mut PluginRegistryFile) -> Result<(), ShellError>,
|
||||
) -> Result<(), ShellError> {
|
||||
#[allow(deprecated)]
|
||||
let cwd = current_dir(engine_state, stack)?;
|
||||
|
||||
if let Some(ref custom_path) = custom_path {
|
||||
Ok(nu_path::expand_path_with(&custom_path.item, cwd, true))
|
||||
let plugin_registry_file_path = if let Some(ref custom_path) = custom_path {
|
||||
nu_path::expand_path_with(&custom_path.item, cwd, true)
|
||||
} else {
|
||||
engine_state
|
||||
.plugin_path
|
||||
@ -27,53 +28,8 @@ fn get_plugin_registry_file_path(
|
||||
span: Some(span),
|
||||
help: Some("you may be running `nu` with --no-config-file".into()),
|
||||
inner: vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn read_plugin_file(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
span: Span,
|
||||
custom_path: &Option<Spanned<String>>,
|
||||
) -> Result<PluginRegistryFile, ShellError> {
|
||||
let plugin_registry_file_path =
|
||||
get_plugin_registry_file_path(engine_state, stack, span, custom_path)?;
|
||||
|
||||
let file_span = custom_path.as_ref().map(|p| p.span).unwrap_or(span);
|
||||
|
||||
// Try to read the plugin file if it exists
|
||||
if fs::metadata(&plugin_registry_file_path).is_ok_and(|m| m.len() > 0) {
|
||||
PluginRegistryFile::read_from(
|
||||
File::open(&plugin_registry_file_path).map_err(|err| ShellError::IOErrorSpanned {
|
||||
msg: format!(
|
||||
"failed to read `{}`: {}",
|
||||
plugin_registry_file_path.display(),
|
||||
err
|
||||
),
|
||||
span: file_span,
|
||||
})?,
|
||||
Some(file_span),
|
||||
)
|
||||
} else if let Some(path) = custom_path {
|
||||
Err(ShellError::FileNotFound {
|
||||
file: path.item.clone(),
|
||||
span: path.span,
|
||||
})
|
||||
} else {
|
||||
Ok(PluginRegistryFile::default())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn modify_plugin_file(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
span: Span,
|
||||
custom_path: &Option<Spanned<String>>,
|
||||
operate: impl FnOnce(&mut PluginRegistryFile) -> Result<(), ShellError>,
|
||||
) -> Result<(), ShellError> {
|
||||
let plugin_registry_file_path =
|
||||
get_plugin_registry_file_path(engine_state, stack, span, custom_path)?;
|
||||
})?
|
||||
};
|
||||
|
||||
let file_span = custom_path.as_ref().map(|p| p.span).unwrap_or(span);
|
||||
|
||||
|
Reference in New Issue
Block a user