mirror of
https://github.com/nushell/nushell.git
synced 2025-06-30 22:50:14 +02:00
Fix scoped overlay use
not finding a module (#6474)
* Add source-env test for dynamic path * Use correct module ID for env overlay imports * Remove parser check from "overlay list" It would cause unnecessary errors from some inner scope if some overlay module was also defined in some inner scope. * Restore Cargo.lock back * Remove comments
This commit is contained in:
@ -4,8 +4,6 @@ use nu_protocol::{
|
||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Value,
|
||||
};
|
||||
|
||||
use log::trace;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct OverlayList;
|
||||
|
||||
@ -28,41 +26,17 @@ impl Command for OverlayList {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
_engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let active_overlays_parser: Vec<Value> = engine_state
|
||||
.active_overlay_names(&[])
|
||||
.iter()
|
||||
.map(|s| Value::string(String::from_utf8_lossy(s), call.head))
|
||||
.collect();
|
||||
|
||||
let active_overlays_engine: Vec<Value> = stack
|
||||
.active_overlays
|
||||
.iter()
|
||||
.map(|s| Value::string(s, call.head))
|
||||
.collect();
|
||||
|
||||
// Check if the overlays in the engine match the overlays in the parser
|
||||
if (active_overlays_parser.len() != active_overlays_engine.len())
|
||||
|| active_overlays_parser
|
||||
.iter()
|
||||
.zip(active_overlays_engine.iter())
|
||||
.any(|(op, oe)| op != oe)
|
||||
{
|
||||
trace!("parser overlays: {:?}", active_overlays_parser);
|
||||
trace!("engine overlays: {:?}", active_overlays_engine);
|
||||
|
||||
return Err(ShellError::NushellFailedSpannedHelp(
|
||||
"Overlay mismatch".into(),
|
||||
"Active overlays do not match between the engine and the parser.".into(),
|
||||
call.head,
|
||||
"Run Nushell with --log-level=trace to see what went wrong.".into(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Value::List {
|
||||
vals: active_overlays_engine,
|
||||
span: call.head,
|
||||
|
@ -1,5 +1,5 @@
|
||||
use nu_engine::{eval_block, find_in_dirs_env, redirect_env, CallExt};
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::ast::{Call, Expr};
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Value,
|
||||
@ -57,12 +57,29 @@ impl Command for OverlayUse {
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let name_arg: Spanned<String> = call.req(engine_state, caller_stack, 0)?;
|
||||
|
||||
let (overlay_name, overlay_name_span) = if let Some(kw_expression) = call.positional_nth(1)
|
||||
{
|
||||
let origin_module_id = if let Some(overlay_expr) = call.positional_nth(0) {
|
||||
if let Expr::Overlay(module_id) = overlay_expr.expr {
|
||||
module_id
|
||||
} else {
|
||||
return Err(ShellError::NushellFailedSpanned(
|
||||
"Not an overlay".to_string(),
|
||||
"requires an overlay (path or a string)".to_string(),
|
||||
overlay_expr.span,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return Err(ShellError::NushellFailedSpanned(
|
||||
"Missing positional".to_string(),
|
||||
"missing required overlay".to_string(),
|
||||
call.head,
|
||||
));
|
||||
};
|
||||
|
||||
let overlay_name = if let Some(kw_expression) = call.positional_nth(1) {
|
||||
// If renamed via the 'as' keyword, use the new name as the overlay name
|
||||
if let Some(new_name_expression) = kw_expression.as_keyword() {
|
||||
if let Some(new_name) = new_name_expression.as_string() {
|
||||
(new_name, new_name_expression.span)
|
||||
new_name
|
||||
} else {
|
||||
return Err(ShellError::NushellFailedSpanned(
|
||||
"Wrong keyword type".to_string(),
|
||||
@ -81,10 +98,10 @@ impl Command for OverlayUse {
|
||||
.find_overlay(name_arg.item.as_bytes())
|
||||
.is_some()
|
||||
{
|
||||
(name_arg.item.clone(), name_arg.span)
|
||||
name_arg.item.clone()
|
||||
} else if let Some(os_str) = Path::new(&name_arg.item).file_stem() {
|
||||
if let Some(name) = os_str.to_str() {
|
||||
(name.to_string(), name_arg.span)
|
||||
name.to_string()
|
||||
} else {
|
||||
return Err(ShellError::NonUtf8(name_arg.span));
|
||||
}
|
||||
@ -95,87 +112,73 @@ impl Command for OverlayUse {
|
||||
));
|
||||
};
|
||||
|
||||
if let Some(overlay_id) = engine_state.find_overlay(overlay_name.as_bytes()) {
|
||||
let old_module_id = engine_state.get_overlay(overlay_id).origin;
|
||||
caller_stack.add_overlay(overlay_name);
|
||||
|
||||
caller_stack.add_overlay(overlay_name.clone());
|
||||
if let Some(module_id) = origin_module_id {
|
||||
// Add environment variables only if:
|
||||
// a) adding a new overlay
|
||||
// b) refreshing an active overlay (the origin module changed)
|
||||
let module = engine_state.get_module(module_id);
|
||||
|
||||
if let Some(new_module_id) = engine_state.find_module(overlay_name.as_bytes(), &[]) {
|
||||
if !caller_stack.has_env_overlay(&overlay_name, engine_state)
|
||||
|| (old_module_id != new_module_id)
|
||||
{
|
||||
// Add environment variables only if:
|
||||
// a) adding a new overlay
|
||||
// b) refreshing an active overlay (the origin module changed)
|
||||
let module = engine_state.get_module(new_module_id);
|
||||
for (name, block_id) in module.env_vars() {
|
||||
let name = if let Ok(s) = String::from_utf8(name.clone()) {
|
||||
s
|
||||
} else {
|
||||
return Err(ShellError::NonUtf8(call.head));
|
||||
};
|
||||
|
||||
for (name, block_id) in module.env_vars() {
|
||||
let name = if let Ok(s) = String::from_utf8(name.clone()) {
|
||||
s
|
||||
} else {
|
||||
return Err(ShellError::NonUtf8(call.head));
|
||||
};
|
||||
let block = engine_state.get_block(block_id);
|
||||
|
||||
let block = engine_state.get_block(block_id);
|
||||
let val = eval_block(
|
||||
engine_state,
|
||||
caller_stack,
|
||||
block,
|
||||
PipelineData::new(call.head),
|
||||
false,
|
||||
true,
|
||||
)?
|
||||
.into_value(call.head);
|
||||
|
||||
let val = eval_block(
|
||||
engine_state,
|
||||
caller_stack,
|
||||
block,
|
||||
PipelineData::new(call.head),
|
||||
false,
|
||||
true,
|
||||
)?
|
||||
.into_value(call.head);
|
||||
caller_stack.add_env_var(name, val);
|
||||
}
|
||||
|
||||
caller_stack.add_env_var(name, val);
|
||||
}
|
||||
// Evaluate the export-env block (if any) and keep its environment
|
||||
if let Some(block_id) = module.env_block {
|
||||
let maybe_path = find_in_dirs_env(&name_arg.item, engine_state, caller_stack)?;
|
||||
|
||||
// Evaluate the export-env block (if any) and keep its environment
|
||||
if let Some(block_id) = module.env_block {
|
||||
let maybe_path =
|
||||
find_in_dirs_env(&name_arg.item, engine_state, caller_stack)?;
|
||||
if let Some(path) = &maybe_path {
|
||||
// Set the currently evaluated directory, if the argument is a valid path
|
||||
let mut parent = path.clone();
|
||||
parent.pop();
|
||||
|
||||
if let Some(path) = &maybe_path {
|
||||
// Set the currently evaluated directory, if the argument is a valid path
|
||||
let mut parent = path.clone();
|
||||
parent.pop();
|
||||
let file_pwd = Value::String {
|
||||
val: parent.to_string_lossy().to_string(),
|
||||
span: call.head,
|
||||
};
|
||||
|
||||
let file_pwd = Value::String {
|
||||
val: parent.to_string_lossy().to_string(),
|
||||
span: call.head,
|
||||
};
|
||||
caller_stack.add_env_var("FILE_PWD".to_string(), file_pwd);
|
||||
}
|
||||
|
||||
caller_stack.add_env_var("FILE_PWD".to_string(), file_pwd);
|
||||
}
|
||||
let block = engine_state.get_block(block_id);
|
||||
let mut callee_stack = caller_stack.gather_captures(&block.captures);
|
||||
|
||||
let block = engine_state.get_block(block_id);
|
||||
let mut callee_stack = caller_stack.gather_captures(&block.captures);
|
||||
let _ = eval_block(
|
||||
engine_state,
|
||||
&mut callee_stack,
|
||||
block,
|
||||
input,
|
||||
call.redirect_stdout,
|
||||
call.redirect_stderr,
|
||||
);
|
||||
|
||||
let _ = eval_block(
|
||||
engine_state,
|
||||
&mut callee_stack,
|
||||
block,
|
||||
input,
|
||||
call.redirect_stdout,
|
||||
call.redirect_stderr,
|
||||
);
|
||||
// Merge the block's environment to the current stack
|
||||
redirect_env(engine_state, caller_stack, &callee_stack);
|
||||
|
||||
// Merge the block's environment to the current stack
|
||||
redirect_env(engine_state, caller_stack, &callee_stack);
|
||||
|
||||
if maybe_path.is_some() {
|
||||
// Remove the file-relative PWD, if the argument is a valid path
|
||||
caller_stack.remove_env_var(engine_state, "FILE_PWD");
|
||||
}
|
||||
}
|
||||
if maybe_path.is_some() {
|
||||
// Remove the file-relative PWD, if the argument is a valid path
|
||||
caller_stack.remove_env_var(engine_state, "FILE_PWD");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(ShellError::OverlayNotFoundAtRuntime(
|
||||
overlay_name,
|
||||
overlay_name_span,
|
||||
));
|
||||
}
|
||||
|
||||
Ok(PipelineData::new(call.head))
|
||||
|
@ -265,6 +265,12 @@ fn convert_to_value(
|
||||
"imports not supported in nuon".into(),
|
||||
expr.span,
|
||||
)),
|
||||
Expr::Overlay(..) => Err(ShellError::OutsideSpannedLabeledError(
|
||||
original_text.to_string(),
|
||||
"Error when loading".into(),
|
||||
"overlays not supported in nuon".into(),
|
||||
expr.span,
|
||||
)),
|
||||
Expr::Int(val) => Ok(Value::Int { val, span }),
|
||||
Expr::Keyword(kw, ..) => Err(ShellError::OutsideSpannedLabeledError(
|
||||
original_text.to_string(),
|
||||
|
Reference in New Issue
Block a user