This commit is contained in:
Andy Gayton 2024-07-04 17:33:31 -04:00
parent d5e00c0d5d
commit 0da531a319
3 changed files with 0 additions and 244 deletions

View File

@ -24,6 +24,3 @@ pub use parser::{
is_math_expression_like, parse, parse_block, parse_expression, parse_external_call,
parse_unit_value, trim_quotes, trim_quotes_str, unescape_unquote_string, DURATION_UNIT_GROUPS,
};
#[cfg(feature = "plugin")]
pub use parse_keywords::parse_register;

View File

@ -82,7 +82,6 @@ pub const UNALIASABLE_PARSER_KEYWORDS: &[&[u8]] = &[
b"source-env",
b"source",
b"where",
b"register",
b"plugin use",
];
@ -3627,244 +3626,6 @@ pub fn parse_where(working_set: &mut StateWorkingSet, lite_command: &LiteCommand
}
}
/// `register` is deprecated and will be removed in 0.94. Use `plugin add` and `plugin use` instead.
#[cfg(feature = "plugin")]
pub fn parse_register(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) -> Pipeline {
use nu_plugin_engine::PluginDeclaration;
use nu_protocol::{
engine::Stack, ErrSpan, ParseWarning, PluginIdentity, PluginRegistryItem, PluginSignature,
RegisteredPlugin,
};
let spans = &lite_command.parts;
#[allow(deprecated)]
let cwd = working_set.get_cwd();
// Checking that the function is used with the correct name
// Maybe this is not necessary but it is a sanity check
if working_set.get_span_contents(spans[0]) != b"register" {
working_set.error(ParseError::UnknownState(
"internal error: Wrong call name for 'register' function".into(),
Span::concat(spans),
));
return garbage_pipeline(working_set, spans);
}
if let Some(redirection) = lite_command.redirection.as_ref() {
working_set.error(redirecting_builtin_error("register", redirection));
return garbage_pipeline(working_set, spans);
}
// Parsing the spans and checking that they match the register signature
// Using a parsed call makes more sense than checking for how many spans are in the call
// Also, by creating a call, it can be checked if it matches the declaration signature
let (call, call_span) = match working_set.find_decl(b"register") {
None => {
working_set.error(ParseError::UnknownState(
"internal error: Register declaration not found".into(),
Span::concat(spans),
));
return garbage_pipeline(working_set, spans);
}
Some(decl_id) => {
let ParsedInternalCall { call, output } =
parse_internal_call(working_set, spans[0], &spans[1..], decl_id);
let decl = working_set.get_decl(decl_id);
let call_span = Span::concat(spans);
let starting_error_count = working_set.parse_errors.len();
check_call(working_set, call_span, &decl.signature(), &call);
let Ok(is_help) = has_flag_const(working_set, &call, "help") else {
return garbage_pipeline(working_set, spans);
};
if starting_error_count != working_set.parse_errors.len() || is_help {
return Pipeline::from_vec(vec![Expression::new(
working_set,
Expr::Call(call),
call_span,
output,
)]);
}
(call, call_span)
}
};
// Now that the call is parsed, add the deprecation warning
working_set
.parse_warnings
.push(ParseWarning::DeprecatedWarning {
old_command: "register".into(),
new_suggestion: "use `plugin add` and `plugin use`".into(),
span: call.head,
url: "https://www.nushell.sh/book/plugins.html".into(),
});
// Extracting the required arguments from the call and keeping them together in a tuple
let arguments = call
.positional_nth(0)
.map(|expr| {
let val =
eval_constant(working_set, expr).map_err(|err| err.wrap(working_set, call.head))?;
let filename = val
.coerce_into_string()
.map_err(|err| err.wrap(working_set, call.head))?;
let Some(path) = find_in_dirs(&filename, working_set, &cwd, Some(PLUGIN_DIRS_VAR))
else {
return Err(ParseError::RegisteredFileNotFound(filename, expr.span));
};
if path.exists() && path.is_file() {
Ok((path, expr.span))
} else {
Err(ParseError::RegisteredFileNotFound(filename, expr.span))
}
})
.expect("required positional has being checked");
// Signature is an optional value from the call and will be used to decide if
// the plugin is called to get the signatures or to use the given signature
let signature = call.positional_nth(1).map(|expr| {
let signature = working_set.get_span_contents(expr.span);
serde_json::from_slice::<PluginSignature>(signature).map_err(|e| {
ParseError::LabeledError(
"Signature deserialization error".into(),
format!("unable to deserialize signature: {e}"),
spans[0],
)
})
});
// Shell is another optional value used as base to call shell to plugins
let shell = call.get_flag_expr("shell").map(|expr| {
let shell_expr = working_set.get_span_contents(expr.span);
String::from_utf8(shell_expr.to_vec())
.map_err(|_| ParseError::NonUtf8(expr.span))
.and_then(|name| {
canonicalize_with(&name, cwd)
.map_err(|_| ParseError::RegisteredFileNotFound(name, expr.span))
})
.and_then(|path| {
if path.exists() & path.is_file() {
Ok(path)
} else {
Err(ParseError::RegisteredFileNotFound(
format!("{path:?}"),
expr.span,
))
}
})
});
let shell = match shell {
None => None,
Some(path) => match path {
Ok(path) => Some(path),
Err(err) => {
working_set.error(err);
return Pipeline::from_vec(vec![Expression::new(
working_set,
Expr::Call(call),
call_span,
Type::Any,
)]);
}
},
};
// We need the current environment variables for `python` based plugins
// Or we'll likely have a problem when a plugin is implemented in a virtual Python environment.
let get_envs = || {
let stack = Stack::new().capture();
nu_engine::env::env_to_strings(working_set.permanent_state, &stack)
};
let error = arguments.and_then(|(path, path_span)| {
let path = path.path_buf();
// Create the plugin identity. This validates that the plugin name starts with `nu_plugin_`
let identity = PluginIdentity::new(path, shell).err_span(path_span)?;
let plugin = nu_plugin_engine::add_plugin_to_working_set(working_set, &identity)
.map_err(|err| err.wrap(working_set, call.head))?;
let signatures = signature.map_or_else(
|| {
// It's important that the plugin is restarted if we're going to get signatures
//
// The user would expect that `register` would always run the binary to get new
// signatures, in case it was replaced with an updated binary
plugin.reset().map_err(|err| {
ParseError::LabeledError(
"Failed to restart plugin to get new signatures".into(),
err.to_string(),
spans[0],
)
})?;
let metadata_and_signatures = plugin
.clone()
.get(get_envs)
.and_then(|p| {
let meta = p.get_metadata()?;
let sigs = p.get_signature()?;
Ok((meta, sigs))
})
.map_err(|err| {
log::warn!("Error getting metadata and signatures: {err:?}");
ParseError::LabeledError(
"Error getting metadata and signatures".into(),
err.to_string(),
spans[0],
)
});
match metadata_and_signatures {
Ok((meta, sigs)) => {
// Set the metadata on the plugin
plugin.set_metadata(Some(meta.clone()));
// Add the loaded plugin to the delta
working_set.update_plugin_registry(PluginRegistryItem::new(
&identity,
meta,
sigs.clone(),
));
Ok(sigs)
}
Err(err) => Err(err),
}
},
|sig| sig.map(|sig| vec![sig]),
)?;
for signature in signatures {
// create plugin command declaration (need struct impl Command)
// store declaration in working set
let plugin_decl = PluginDeclaration::new(plugin.clone(), signature);
working_set.add_decl(Box::new(plugin_decl));
}
Ok(())
});
if let Err(err) = error {
working_set.error(err);
}
Pipeline::from_vec(vec![Expression::new(
working_set,
Expr::Call(call),
call_span,
Type::Nothing,
)])
}
#[cfg(feature = "plugin")]
pub fn parse_plugin_use(working_set: &mut StateWorkingSet, call: Box<Call>) -> Pipeline {
use nu_protocol::{FromValue, PluginRegistryFile};

View File

@ -5419,8 +5419,6 @@ pub fn parse_builtin_commands(
b"export" => parse_export_in_block(working_set, lite_command),
b"hide" => parse_hide(working_set, lite_command),
b"where" => parse_where(working_set, lite_command),
#[cfg(feature = "plugin")]
b"register" => parse_register(working_set, lite_command),
// Only "plugin use" is a keyword
#[cfg(feature = "plugin")]
b"plugin"