wip
This commit is contained in:
parent
d5e00c0d5d
commit
0da531a319
|
@ -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;
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue
Block a user