Deny std::fs functions
Your crate provide a very useful error message, and I thank you for that 👍
But I find it is easy to forget to use it and still use the original std::fs function.
I would like to ensure that I always use the fs_err replacement function when available.
I created a clippy.toml that list the functions I would like not to use
disallowed-methods = [
# Do not use the `std::fs` method below, use their `fs_err` equivalent
# The `std::fs` methods fail with 'No such file or directory' if the path does not exist, but do not print the problematic path
# See: https://docs.rs/fs-err/latest/fs_err/
"std::fs::canonicalize",
"std::fs::copy",
"std::fs::create_dir",
"std::fs::create_dir_all",
"std::fs::hard_link",
"std::fs::metadata",
"std::fs::read",
"std::fs::read_dir",
"std::fs::read_link",
"std::fs::read_to_string",
"std::fs::remove_dir",
"std::fs::remove_dir_all",
"std::fs::remove_file",
"std::fs::rename",
"std::fs::set_permissions",
"std::fs::soft_link",
"std::fs::symlink_metadata",
"std::fs::write",
"std::path::Path::canonicalize", # Use fs_err::canonicalize instead
]
And it works well. But it is not complete: I need to add std::fs::File::open, create, ...
It tried to disallow all std::fs::File::*, but clippy does not seem to support globing
Do you know how I can easily complete the list ? And keep it updated ? Can I add to this file to the repo so that people can easily add it to their project ?
First off, I didn't know you could do this, and love the idea. I've been wondering how to write a custom linter rule for this exact same purpose, and disallowing the methods makes more sense.
As a starting point, we could add a section to the README that suggests using disallowed-methods and documents them all. It wouldn't be automated, but it would let people know about the technique and provide a centralized source of information.
If you wanted something more automated, what if: fs-err maintained that list in it's codebase, and had a function that takes a vec and returns a diff of any methods that it knows about that weren't in the vec. Then a codebase could call that function in a test. Something like:
// pseudo rust code
let clippy = toml::Toml::from_str(include_str("../clippy.toml")).unwrap().get("disallowed-methods").unwrap();
let diff = fs_err::clippy::disallowed_diff(clippy);
assert_eq!(diff, Vec::empty())
If you missed one that fs-err knows about, then it would error and that would let you know which to add.
I applied this to my repo and specified replacements for most. Commit is here: https://github.com/heroku/docker-heroku-ruby-builder/pull/92.
disallowed-methods = [
# Use fs_errr functions, so the filename is available in the error message
{ path = "std::fs::canonicalize", replacement = "fs_err::canonicalize" },
{ path = "std::fs::copy", replacement = "fs_err::copy" },
{ path = "std::fs::create_dir", replacement = "fs_err::create_dir" },
{ path = "std::fs::create_dir_all", replacement = "fs_err::create_dir_all" },
{ path = "std::fs::exists", replacement = "fs_err::exists" },
{ path = "std::fs::hard_link", replacement = "fs_err::hard_link" },
{ path = "std::fs::metadata", replacement = "fs_err::metadata" },
{ path = "std::fs::read", replacement = "fs_err::read" },
{ path = "std::fs::read_dir", replacement = "fs_err::read_dir" },
{ path = "std::fs::read_link", replacement = "fs_err::read_link" },
{ path = "std::fs::read_to_string", replacement = "fs_err::read_to_string" },
{ path = "std::fs::remove_dir", replacement = "fs_err::remove_dir" },
{ path = "std::fs::remove_dir_all", replacement = "fs_err::remove_dir_all" },
{ path = "std::fs::remove_file", replacement = "fs_err::remove_file" },
{ path = "std::fs::rename", replacement = "fs_err::rename" },
{ path = "std::fs::set_permissions", replacement = "fs_err::set_permissions" },
{ path = "std::fs::soft_link", replacement = "fs_err::soft_link" },
{ path = "std::fs::symlink_metadata", replacement = "fs_err::symlink_metadata" },
{ path = "std::fs::write", replacement = "fs_err::write" },
# Use fs_err::path::PathExt methods, so the filename is available in the error message
{ path = "std::path::Path::try_exists", reason = "Use fs_err::path::PathExt methods" },
{ path = "std::path::Path::metadata", reason = "Use fs_err::path::PathExt methods" },
{ path = "std::path::Path::symlink_metadata", reason = "Use fs_err::path::PathExt methods" },
{ path = "std::path::Path::canonicalize", reason = "Use fs_err::path::PathExt methods" },
{ path = "std::path::Path::read_link", reason = "Use fs_err::path::PathExt methods" },
{ path = "std::path::Path::read_dir", reason = "Use fs_err::path::PathExt methods" },
]