Provide more detailed I/O errors
The UIoError only contains an std::io::Error and some context and both aren't really accessible. For people that use uucore as a library that makes it very hard to build good errors from that. It would be really nice if that error type could expose the std::io::Error, a path that failed if it happened at some path and maybe even an index for commands that take multiple paths like cp or mv. I think restructuring UIoErrors in that direction would also harmonize error messages across the different binaries and you maybe don't need to use as many custom contexts anymore.
Hi! I'm just chipping in because I wrote the UError stuff. What you're saying is correct and it is a pain. However, I think the problem isn't really with the error types but with the standard library (and libc). The error itself cannot find the paths and other necessary context. Instead we'd have to wrap standard functions with versions that have more elaborate error types. Kind of similar to this: https://docs.rs/fs-err/latest/fs_err/.
If you have a better idea to be smarter about this, I'd love to hear it though!
I recently refactored the I/O errors in nushell#14927 to provide exactly this necessary information. And yeah, we also had to extend the std::io::Error with our own IoError to store everything needed. I think most often the function that actually produces the std::io::Errors know about the context (e.g. the save command). In our case I added some constructors for our IoError to take this information and went through the code to call this constructor everywhere, which was kinda painful but now we have nicer errors.
Just now with the direction to replace our filesystem commands with the uutils ones, we lose that information again. :/
Sounds good! Feel free to ping me if you want to discuss changes you'd like to make.
I think similar to the Nushell IoError, the UIoError could look like this:
pub struct UIoError {
// hold the inner io error to extract further data from it later on
inner: std::io::Error,
// reference a path that caused the error
path: Option<std::path::PathBuf>,
// an index to which path failed, `cp` or `mv` need two paths
path_index: usize,
// additional context if that is useful
additional_context: Option<String>,
}
But I'm not really sure about the path_index here. For Nushell we provide a span, but I don't think that is necessary here. But somehow we should track which of the paths we had caused an issue.
@tertsdiepraam I need some guidance about the path_index field of my proposed UIoError it doesn't feel completely right but I think we need something.
Hey @tertsdiepraam, how is it going? I just wanted to ask before I throw myself onto this issue.
Ah sorry! Let me try to understand. Would this index refer to the arguments of the tool (e.g. mv) or the arguments of the function (e.g. File::open)? And what is it used for in nushell?
It would be for the arguments of the tool. The File::open obviously has only one file it concerns about but in the wider context of the mv command you give two paths and I want to figure out which one of these caused the issue. Then in nushell we could apply the correct span to show the user which given path had the issue.
I don't know if a path_index would be the best approach here but anything that lets you know which path caused the issue would be great. It could also be an enum with something like From and To but this is less flexible, considering we may have more than two given paths.
Right, I suppose that would be interesting to track, though also might complicate the code a bit. I don't think we can do this in general though, it needs to be Option<usize> because sometimes is a subpath or some other thing. It could also be an argument to an option somewhere, so that complicates things.