-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add fs::exists
function
#3375
Add fs::exists
function
#3375
Conversation
I don't see an |
Its under |
TBH, I believe that this API (and the API in |
Returning |
|
I mean, are you should people will do Regarding std, it cannot be fixed in std because of backwards compatibility. Waiting for std to change it is just a roundabout way to say "don't add the method at all". Of course, there's still an argument in following what std does. I wonder if this was discussed when it was added to std. |
@hamza1311 in your example you assume broken error handling is preferable, which I don't find convincing. A more reasonable comparison: fs::exists(&path).await? instead of: use std::io::ErrorKind;
fs::metadata(&path)
.await
.map(|_| true)
.or_else(|error| if error.kind() == ErrorKind::NotFound { Ok(false) } else { Err(error) })? |
That is a valid point. How about naming the current implementation as |
Changing the return-type but keeping the name |
I believe another touch /tmp/foo
chmod 000 /tmp/foo
An interesting thing is that I created a thread in internals suggesting deprecating |
What are the use-cases where this matters, and the code isn't broken already? For example, a code like this:
is vulnerable to race conditions. So maybe the lack of |
My real-world use case for scanning FS before actually using it. Basic sanity checks at the start of the program. It's better to report corrupted installation/configuration sooner than it's actually needed and disable the corrupted part (other parts may still work fine!). Yes this is vulnerable to race conditions, but I find it acceptable as I do the error checking in the code that actually uses the files too and find edge cases unlikely to bother implementing any more safety measures. This all being said, I don't use |
It is only racy in terms of the actual creation of the file, but if you are predicating other logic based off the existence or lack thereof of a file, then this is useful. e.g. detect if an application is installed based off the existence of a file or binary (yes, the application could be installed that second, but you'll account for that by allowing the process to be restarted or something.). Or you need a file to be at a certain location if it isn't already, but generating the file is expensive so you check if it exists before you generate the content to be written (in a non-racy way via, for example, There are lots of use cases. It's somewhat hubris for an API to presume to know better than the developer about things external to it. |
@mqudsi exactly, I actually do this in one project. Running Anyway, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add the test in the tokio/tests/async_send_sync.rs
file.
async_assert_fn!(tokio::fs::exists(&str): Send & Sync & !Unpin);
use std::path::Path; | ||
|
||
/// Returns `true` if the path points at an existing entity. | ||
/// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// | |
/// This is an async version of [`std::path::Path::exists`][std] |
/// | ||
/// This function will traverse symbolic links to query information about the | ||
/// destination file. | ||
/// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// | |
/// [std]: std::path::Path::exists |
/// ```rust,no_run | ||
/// # use tokio::fs; | ||
/// | ||
/// # #[tokio::main] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The example in src/fs/metadata.rs
does not hide these lines. Maybe we should be consistent and show these lines?
/// This method returns false in case of errors thus ignoring them. Use [`fs::metadata`][super::metadata()] | ||
/// if you want to check for errors. | ||
pub async fn exists(path: impl AsRef<Path>) -> bool { | ||
super::metadata(&path).await.is_ok() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
super::metadata(&path).await.is_ok() | |
let path = path.as_ref().to_owned(); | |
asyncify(|| path.exists()).await |
Why not directly use the exists
method from std
?
Is the intention to change this implementation to match the experimental You can find the implementation and see that it's pretty straightforward at the moment: pub fn try_exists(path: &Path) -> io::Result<bool> {
match fs::metadata(path) {
Ok(_) => Ok(true),
Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false),
Err(error) => Err(error),
}
} What I'm doing with tokio is pretty much the same with the async version: match tokio::fs::metadata(path).await {
Ok(_) => Ok(true),
Err(x) if x.kind() == io::ErrorKind::NotFound => Ok(false),
Err(x) => Err(x),
} |
I don't mind implementing, if that's what should be done. I don't think we need to provide an abstraction for |
I'm going to close this since #4299 was merged. I'm sorry that this discussion stalled. |
Motivation
The std lib implements
exists
while there's no tokio equivalent. This is possible withmetadata
function but a wrapper is nice to have.Solution
Add
fs::exists
function.Fixes: #3373