Coder Social home page Coder Social logo

fs-err's People

Contributors

andrewhickman avatar brooksprumo avatar emerentius avatar hniksic avatar lpghatguy avatar mathstuf avatar notgull avatar nukesor avatar schneems avatar sfleener avatar shellixyz avatar veetaha avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

fs-err's Issues

Marketing/public docs

This crate fills an important hole in the ecosystem and that a lot of people would use it if they knew about it and its benefits.

I'd like to help draft an expanded README along with crate-level documentation and examples. I want to make sure my understanding of fs-err's role matches yours, though.

Key points would be:

  • fs-err is a (mostly) drop-in replacement for std::fs, so it could be used like use fs_err as fs to get existing code working
  • We should have clear comparisons of error messages between std::fs and fs-err
  • The crate's scope is the same as std::fs, plus methods to expose paths where we've added them
  • There might be a path for merging some of the work in this crate back into std (?)

fs::remove APIs

This would cover remove_file, remove_dir, and remove_dir_all.

path type different than std::fs::File

std::fs::File uses AsRef<Path> as the type for passing paths while fs_err uses Into<PathBuf>

This makes fs_err not be a "drop in replacement": When I pass an AsRef<Path> to fs_err::File::open, it does not compile

Use wrapper around std::io::Error instead of custom error type?

Hello!

I created a similar wrapper to fs-err, but I took a slightly different approach. When using a custom error type, code that uses those I/O functions has return types that don't compose well with the io trait ecosystem like io::Write.

If we use io::Error's ability to hold other arbitrary error types though, we can still return io::Error but attach custom information with no loss of error handling ability.

Here's an implementation I did recently: https://github.com/rojo-rbx/foreman/blob/4cca3ba84025ef42eb458f2a8184f93a42915c15/src/fs.rs

I was going to make a crate for this last week, but then found fs-err! Do you think this strategy would work better, and if so, can I help move fs-err to that pattern?

More comprehensive rustdocs

The docs of the fs-err wrappers currently just say "Wrapper for ". While that's true and easy to maintain, it is also a bit underwhelming for IDE users who rely on hovering over a function to see what it does.

For example, if I hover over a call to fs_err::OpenOptions::create_new() I just get "Wrapper for OpenOptions::create_new". If I instead hover over std::fs::OpenOptions::create_new(), I get a description such as "Sets the option to create a new file, failing if it already exists. [...]". While the shown docs is technically 100% true, it's less useful, and means that swapping std::fs for fs_err makes the code less convenient to browse in IDE.

Could we make a compromise between maintainability and usefulness by copying the first sentence of the upstream docs? Something like "Sets the option to create a new file, failing if it already exists. Wrapper for OpenOptions::create_new, which see for details."

fs::create_dir and fs::create_dir_all

Similarly to read_to_string, we may want to reimplement the guts of create_dir_all inside this crate so that we can report more accurate paths than just the top-level path in the event of an error.

Missing functions

Looking at std::fs, for the functions I was using in my project, I was missing hard_link, soft_link, rename. Could these be added?

Provide a `fn file_mut(&mut self) -> &mut std::fs::File`

Currently there is no API that allows mutable access to some of those files or conversion to the inner std::fs::File. As such one has to go via the os-specific {FromInto}RawFd to gain access to the underlying file.

This is required for i.e. the tar crate.

Changelog

It would be useful to keep track of a changelog of releases, and have people filing PRs (oops) append to an 'unreleased' section.

I like the rough structure of Keep a Changelog, but am not really tied any specific organization.

Add support for `tokio::fs`

The project is very cool for applications that can tolerate synchronous filesystem interaction!
However, if one needs async io, fs_err can't help with this too much.
As a workaround some operations could be wrapped in tokio::task::spawn_blocking(), but it would be better to have a native wrapper for tokio::fs module.

It may be reasonable to have this with a tokio cargo feature.

Add support for path associated functions such as `try_exist`

Thank you for your work. My team works with the file system heavily, and we need good error messages that include the path being referenced, and your library is helpful in providing this out of the box.

One thing we've found is that while checking if a file exists or not on the path, it can be confusing to raise an error that says "This file {} does not exist" when the end user can see it on the path but Path::exists() returned false because there was an error with permissions (or something else).

Currently, I have some code like this:

    if path
        .try_exists()
        .map_err(|error| CustomError::CannotRead(path.clone(), error))?
    {
        Ok(path)
    } else {
        Err(CustomError::DoesNotExist(path))
    }

If fs-err supported these operations, then this would be simplified to just path.try_exists()?.

The challenge is how to present this as an API. Maybe something like FsErrPath::try_exists(&path)?

I would like to make "doing the right thing" for error ergonomics as easy as possible. What you've got is a great start. Would you consider adding some additional io operations to your library?

Missing structs

There exist several structs in std::fs which don't appear in fs_err

  • DirBuilder
  • Metadata
  • FileType
  • Permissions

Of these, the first 2 have methods returning io::Result<_> which would benefit from wrappers.
The last 2 don't have any fallible methods. If fs-err re-exported them, it would add to the "drop-in" quality of the crate. The downside is that if std ever adds fallible methods later, they'd need to be replaced with wrappers in a breaking change.

In the case of Metadata, there already are several APIs which return std::fs::Metadata. When Metadata is wrapped, these should be switched to return the wrapper (breaking change).

THANK YOU!!!

THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!
THANK YOU!!!

You have no idea how amazing it is to see which file was not found!

fs::copy API

The format for errors from fs::copy are a little different because there are two paths involved. I solved this in my FS abstraction crate by having a new internal error type, CopyError.

I can PR this; I'll need it to port some projects over to use fs-err!

fs::read_dir API

It would be useful to expose the read_dir function, along with the associated structs ReadDir (an iterator) and DirEntry.

I have implementations of these in my old FS abstraction (that was the source of #2) that I can tidy up and PR for this crate!

Display does not include source

When printing out the errors generated by fs-err with Display, the message does not contain the source. This often means we know what happened, but not why an error happened.

For example, I encountered this when a call to fs_err::hard_link() failed. I have an error hierarchy that wraps the error from the hard link call. Printing the error with Display shows my custom text, then the text from fs-err, but not the text from the source/underlying std::io::Error.

Here's an example in the Playground (please pardon the unpolished nature of the code):
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=a5e0844e243ec0807372b01227419b50

The Display1 shows wrapping a normal std::io::Error. We can see the output does not include the path. So this has the why, but no what.

In Display2, which is what fs-err does, we have the path, but not the underlying source io::Error included in the output. This is having the what without the why

And Display3 is what I was hoping that fs-err did: it prints the what followed by the why.

By adding the source at the end of the Display, this automatically keeps printing more and more inner source errors at the end; providing more and more information/context.

For fs-err, this can be accomplished by changing the implementation of Display from here:

fs-err/src/errors.rs

Lines 65 to 101 in ba98887

fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
use ErrorKind::*;
let path = self.path.display();
match self.kind {
OpenFile => write!(formatter, "failed to open file `{}`", path),
CreateFile => write!(formatter, "failed to create file `{}`", path),
CreateDir => write!(formatter, "failed to create directory `{}`", path),
SyncFile => write!(formatter, "failed to sync file `{}`", path),
SetLen => write!(formatter, "failed to set length of file `{}`", path),
Metadata => write!(formatter, "failed to query metadata of file `{}`", path),
Clone => write!(formatter, "failed to clone handle for file `{}`", path),
SetPermissions => write!(formatter, "failed to set permissions for file `{}`", path),
Read => write!(formatter, "failed to read from file `{}`", path),
Seek => write!(formatter, "failed to seek in file `{}`", path),
Write => write!(formatter, "failed to write to file `{}`", path),
Flush => write!(formatter, "failed to flush file `{}`", path),
ReadDir => write!(formatter, "failed to read directory `{}`", path),
RemoveFile => write!(formatter, "failed to remove file `{}`", path),
RemoveDir => write!(formatter, "failed to remove directory `{}`", path),
Canonicalize => write!(formatter, "failed to canonicalize path `{}`", path),
ReadLink => write!(formatter, "failed to read symbolic link `{}`", path),
SymlinkMetadata => write!(formatter, "failed to query metadata of symlink `{}`", path),
FileExists => write!(formatter, "failed to check file existance `{}`", path),
#[cfg(windows)]
SeekRead => write!(formatter, "failed to seek and read from `{}`", path),
#[cfg(windows)]
SeekWrite => write!(formatter, "failed to seek and write to `{}`", path),
#[cfg(unix)]
ReadAt => write!(formatter, "failed to read with offset from `{}`", path),
#[cfg(unix)]
WriteAt => write!(formatter, "failed to write with offset to `{}`", path),
}
}

To something like:

    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        use ErrorKind::*;

        let path = self.path.display();

        match self.kind {
-            OpenFile => write!(formatter, "failed to open file `{}`", path),
+            OpenFile => write!(formatter, "failed to open file `{}`: {}", path, self.source),
            // and the same thing for the subsequent arms

I can create a PR for this; just wanted to check if this would be well-received first. Please also let me know if there is more information that would be helpful.

Edit: I created a PR since it was quite quick: #53

fs::metadata

This is a fairly common API and one I need for a couple of my projects.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.