fix(tvix): distinguish search- and relative path resolution errors
Failures to resolve a nix search path lookup in angle brackets can be caught using tryEval (if it reaches the runtime). Resolving relative paths (either to the current directory or the current user's home) can never be caught, even if they happen inside a thunk at runtime (which is currently the case for home-relative paths). Change-Id: I7f73221df66d82a381dd4063358906257826995a Reviewed-on: https://cl.tvl.fyi/c/depot/+/7025 Autosubmit: sterni <sternenseemann@systemli.org> Reviewed-by: Adam Joseph <adam@westernsemico.com> Tested-by: BuildkiteCI Reviewed-by: grfn <grfn@gws.fyi>
This commit is contained in:
parent
5753fc14f5
commit
64bb501de1
4 changed files with 19 additions and 11 deletions
|
@ -115,7 +115,7 @@ impl<'observer> Compiler<'observer> {
|
||||||
Some(dir) if cfg!(target_arch = "wasm32") || dir.is_absolute() => Ok(dir),
|
Some(dir) if cfg!(target_arch = "wasm32") || dir.is_absolute() => Ok(dir),
|
||||||
_ => {
|
_ => {
|
||||||
let current_dir = std::env::current_dir().map_err(|e| Error {
|
let current_dir = std::env::current_dir().map_err(|e| Error {
|
||||||
kind: ErrorKind::PathResolution(format!(
|
kind: ErrorKind::RelativePathResolution(format!(
|
||||||
"could not determine current directory: {}",
|
"could not determine current directory: {}",
|
||||||
e
|
e
|
||||||
)),
|
)),
|
||||||
|
@ -290,7 +290,7 @@ impl Compiler<'_> {
|
||||||
if raw_path.len() == 2 {
|
if raw_path.len() == 2 {
|
||||||
return self.emit_error(
|
return self.emit_error(
|
||||||
node,
|
node,
|
||||||
ErrorKind::PathResolution("Empty <> path not allowed".into()),
|
ErrorKind::NixPathResolution("Empty <> path not allowed".into()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let path = &raw_path[1..(raw_path.len() - 1)];
|
let path = &raw_path[1..(raw_path.len() - 1)];
|
||||||
|
|
|
@ -50,8 +50,11 @@ pub enum ErrorKind {
|
||||||
rhs: &'static str,
|
rhs: &'static str,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Resolving a user-supplied path literal failed in some way.
|
/// Resolving a user-supplied angle brackets path literal failed in some way.
|
||||||
PathResolution(String),
|
NixPathResolution(String),
|
||||||
|
|
||||||
|
/// Resolving a user-supplied relative or home-relative path literal failed in some way.
|
||||||
|
RelativePathResolution(String),
|
||||||
|
|
||||||
/// Dynamic keys are not allowed in some scopes.
|
/// Dynamic keys are not allowed in some scopes.
|
||||||
DynamicKeyInScope(&'static str),
|
DynamicKeyInScope(&'static str),
|
||||||
|
@ -178,7 +181,7 @@ impl ErrorKind {
|
||||||
/// Returns `true` if this error can be caught by `builtins.tryEval`
|
/// Returns `true` if this error can be caught by `builtins.tryEval`
|
||||||
pub fn is_catchable(&self) -> bool {
|
pub fn is_catchable(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Throw(_) | Self::AssertionFailed | Self::PathResolution(_) => true,
|
Self::Throw(_) | Self::AssertionFailed | Self::NixPathResolution(_) => true,
|
||||||
Self::ThunkForce(err) => err.kind.is_catchable(),
|
Self::ThunkForce(err) => err.kind.is_catchable(),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
@ -238,7 +241,9 @@ impl Display for Error {
|
||||||
write!(f, "can not compare a {} with a {}", lhs, rhs)
|
write!(f, "can not compare a {} with a {}", lhs, rhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorKind::PathResolution(err) => write!(f, "could not resolve path: {}", err),
|
ErrorKind::NixPathResolution(err) | ErrorKind::RelativePathResolution(err) => {
|
||||||
|
write!(f, "could not resolve path: {}", err)
|
||||||
|
}
|
||||||
|
|
||||||
ErrorKind::DynamicKeyInScope(scope) => {
|
ErrorKind::DynamicKeyInScope(scope) => {
|
||||||
write!(f, "dynamically evaluated keys are not allowed in {}", scope)
|
write!(f, "dynamically evaluated keys are not allowed in {}", scope)
|
||||||
|
@ -619,7 +624,9 @@ impl Error {
|
||||||
let label = match &self.kind {
|
let label = match &self.kind {
|
||||||
ErrorKind::DuplicateAttrsKey { .. } => "in this attribute set",
|
ErrorKind::DuplicateAttrsKey { .. } => "in this attribute set",
|
||||||
ErrorKind::InvalidAttributeName(_) => "in this attribute set",
|
ErrorKind::InvalidAttributeName(_) => "in this attribute set",
|
||||||
ErrorKind::PathResolution(_) => "in this path literal",
|
ErrorKind::NixPathResolution(_) | ErrorKind::RelativePathResolution(_) => {
|
||||||
|
"in this path literal"
|
||||||
|
}
|
||||||
ErrorKind::UnexpectedArgument { .. } => "in this function call",
|
ErrorKind::UnexpectedArgument { .. } => "in this function call",
|
||||||
|
|
||||||
// The spans for some errors don't have any more descriptive stuff
|
// The spans for some errors don't have any more descriptive stuff
|
||||||
|
@ -668,7 +675,7 @@ impl Error {
|
||||||
ErrorKind::AttributeNotFound { .. } => "E005",
|
ErrorKind::AttributeNotFound { .. } => "E005",
|
||||||
ErrorKind::TypeError { .. } => "E006",
|
ErrorKind::TypeError { .. } => "E006",
|
||||||
ErrorKind::Incomparable { .. } => "E007",
|
ErrorKind::Incomparable { .. } => "E007",
|
||||||
ErrorKind::PathResolution(_) => "E008",
|
ErrorKind::NixPathResolution(_) => "E008",
|
||||||
ErrorKind::DynamicKeyInScope(_) => "E009",
|
ErrorKind::DynamicKeyInScope(_) => "E009",
|
||||||
ErrorKind::UnknownStaticVariable => "E010",
|
ErrorKind::UnknownStaticVariable => "E010",
|
||||||
ErrorKind::UnknownDynamicVariable(_) => "E011",
|
ErrorKind::UnknownDynamicVariable(_) => "E011",
|
||||||
|
@ -691,6 +698,7 @@ impl Error {
|
||||||
ErrorKind::IO { .. } => "E029",
|
ErrorKind::IO { .. } => "E029",
|
||||||
ErrorKind::FromJsonError { .. } => "E030",
|
ErrorKind::FromJsonError { .. } => "E030",
|
||||||
ErrorKind::UnexpectedArgument { .. } => "E031",
|
ErrorKind::UnexpectedArgument { .. } => "E031",
|
||||||
|
ErrorKind::RelativePathResolution(_) => "E032",
|
||||||
|
|
||||||
// Placeholder error while Tvix is under construction.
|
// Placeholder error while Tvix is under construction.
|
||||||
ErrorKind::NotImplemented(_) => "E999",
|
ErrorKind::NotImplemented(_) => "E999",
|
||||||
|
|
|
@ -103,7 +103,7 @@ impl NixSearchPath {
|
||||||
return Ok(p);
|
return Ok(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(ErrorKind::PathResolution(format!(
|
Err(ErrorKind::NixPathResolution(format!(
|
||||||
"path '{}' was not found in the Nix search path",
|
"path '{}' was not found in the Nix search path",
|
||||||
path.display()
|
path.display()
|
||||||
)))
|
)))
|
||||||
|
@ -178,7 +178,7 @@ mod tests {
|
||||||
let nix_search_path = NixSearchPath::from_str("./.").unwrap();
|
let nix_search_path = NixSearchPath::from_str("./.").unwrap();
|
||||||
let err = nix_search_path.resolve("nope").unwrap_err();
|
let err = nix_search_path.resolve("nope").unwrap_err();
|
||||||
assert!(
|
assert!(
|
||||||
matches!(err, ErrorKind::PathResolution(..)),
|
matches!(err, ErrorKind::NixPathResolution(..)),
|
||||||
"err = {err:?}"
|
"err = {err:?}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -555,7 +555,7 @@ impl<'o> VM<'o> {
|
||||||
Value::UnresolvedPath(path) => {
|
Value::UnresolvedPath(path) => {
|
||||||
match dirs::home_dir() {
|
match dirs::home_dir() {
|
||||||
None => {
|
None => {
|
||||||
return Err(self.error(ErrorKind::PathResolution(
|
return Err(self.error(ErrorKind::RelativePathResolution(
|
||||||
"failed to determine home directory".into(),
|
"failed to determine home directory".into(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue