-
Notifications
You must be signed in to change notification settings - Fork 632
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
Deprecating "exists" because of some use cases ignores legitimate use cases #2594
Comments
If the check is for a file (not dir), and |
@kt3k That assumes:
These feel like very complex, cumbersome, and non-intuitive proposals to a potential problem that isn't quantified nor experienced in the wild in many contexts, and especially not in my use cases. I will never experience the stated threat in the use cases for the tooling I build with deno (CLI tools, build tools, automation). |
Related: #2125. Perhaps, this is a matter that requires more thorough documentation. |
@kt3k, I think it's worth:
I'm happy to work on this. What do you think? |
@iuioiua I think this is a good solution. |
I feel like the use cases I put forward are not understood. All the suggestions are assuming that you want to write to the file, or create it if it doesn't exist, rather than take an unrelated action if the file exists. None of the suggestions work in this case, since I don't want to create the file or directory, just to check if it exists. I suppose we'll have to create a third-party module to cover this basic use-case. |
It'd be worth pointing out that If |
There's types of usages like |
Do these use cases provide sufficient reasoning to undo the deprecation of |
@iuioiua My recent research shows that this code would throw an unhandled exception on Windows, when the backup file exists, but is not readable. If you'd use Your code sample shows me that What are your thoughts? |
I agree with @martin-braun's analysis here. I would suggest that we deprecate (and eventually remove) I, personally, have run into a very similar problem as @dionjwa where I needed to do something (not a file write), if something did not exist and would really like a non-deprecated solution. |
@lino-levan See also #2785 . I believe it's the latest version of the proposal. |
@kt3k Which is probably stale. I could maybe move forward when #2791 gets fixed, but I seriously question if the permission part should be included, or not. Unfortunately, my last comment in this issue got no response. Maybe you could look into it, please? My concern is, that there are use-cases in which On the other hand, not having a Third option would be to simply implement |
@martin-braun BTW I feel it's a little verbose to have both |
@kt3k The primary goal was to undo the deprecation while improving the situation to reduce the potential for TOCTOU scenarios. Including permission checks was an idea and I was motivated to get consistent behavior between the platforms, thus making So instead, I'm playing with the thought to just re-implement
The first point is crucial for me. People want The second point is important for better consistency between the platforms. In regards of introducing The bottom line is: Both paths fail to be consistent between platforms, both cannot catch all basic use-cases, I'm neither happy with my draft (which is blocked by unstable implementations), nor with the old |
We can throw TypeError for wrong usages. I still don't see what's wrong about returning |
In case of
Ok sure, we can do that. So you think the best is to ignore the issue I just mentioned and simply re-implement |
I feel like there's some amount of miscommunication going on here. I'm kind of on a fence here, but I think we should push for I do get @martin-braun's point here which is, sometimes I really do want to check if a file exists and not just that it's readable by me (I think the examples they've provided show enough usecases for that). If we do decide to remove the current implementation and create another one:
Regardless of which route we take, I think that the JSDocs for (both of) them should still recommend "just do the operation directly and catch errors" for the vast majority of things. |
@lino-levan Now I'm actually interested in changing my PR to implement One last thing though: I think that the 3 arguments rule holds usually, but having to define two arguments when a folder is checked ( isReadable({
folder: true
}) Thanks. |
@martin-braun denoland/deno#16424 just landed in |
@lino-levan No worries, I'm aware of this and I'm going to tackle this soon, since the path is graded, now. |
Idea for further improvement: const isReadable = await fs.exists("path/to/file.txt", {
isFile: true,
isReadable: true // also require file to be readable
}); The idea is to not just combine the path type check, but also the permission check, into one function. It's not very pretensive against bad programming styles that might lead to race conditions (similarly to the former
I'm curious if you agree or not. |
Double thumbs on this one, I feel like the syntax is a lot clearer. I do want to really make sure the documentation is on point if we are essentially un-deprecating exists. Also bumping this:
|
There is also an option to opt-in for another function name and have |
I think a sensible solution would be to add a second optional Outside of that, I think The documentation recommends not using it and provides examples of how to do so. Also, there appears to be enough evidence of valid use cases. For this reason, I think the deprecation should be undone, and the codebase should steer away from using it internally where reasonable. Frankly, but respectfully, I think the amount of time and effort surrounding this function has been overplayed. It'd be nice for a sensible agreement to be met and move on. |
@iuioiua I agree. My PR is almost ready, but I need denoland/deno#15576 to be addressed first. Let me explain:
// ...
} catch (error) {
if (error instanceof Deno.errors.NotFound) {
return false;
}
if (error instanceof Deno.errors.PermissionDenied) {
if (
(await Deno.permissions.query({ name: "read", path })).state ===
"granted"
) { // --allow-read not missing
return !options?.isReadable; // PermissionDenied was raised by file system
}
}
throw error;
}
} For I came to awareness after re-implementing the cc @lino-levan |
|
The |
@iuioiua If I'm understanding @martin-braun's logic, I think you're missing the point. We need to query the Now that I say that out loud, is there even value in differentiating between these two @martin-braun? |
Yes, I understand. However, my statement still stands:
I think that's a good question. Perhaps, a simple boolean option could set whether the function throws or ignores a permission error might do the trick. What do we think? |
This is absolutely correct, @lino-levan.
Yes there is. If
@iuioiua Please revisit my code snippet, I'm trying to query the permissions in the catch-block and I cannot just return This is the reason why I cannot throw an error from
I have hard times to imagine how this would solve the situation. Why would A suitable alternative to my approach would be to let Deno raise different errors for these scenarios. |
I think we should just have an I feel pretty strongly that we should not add more options to this API. |
Yeah, my suggestion of adding options came from hearing about people's edge cases from previous discussions. But again, they're edge cases. Thinking about it further, I agree. I think the best solution is to just add sufficient documentation to explain these edge cases and move on, rather than having a function that's needlessly over-engineered. |
That is very unfortunate, given that the implementation is almost ready to be reviewed ( I get that enhancing a function which concept is not perceived in a positive manner feels counter-intuitive, but the proposed enhancements would improve the situation by covering all the possible pitfalls that would occur when using A simple undo of the deprecation of For me, simply using I believe it is irresponsible to offer only a plain |
Fair points. |
This can be closed now, since #2785 landed. |
Latest docs: https://deno.land/[email protected]/fs/mod.ts?s=exists
"Checking the state of a file before using it causes a race condition. Perform the actual operation directly instead."
So it's saying instead of:
instead do
Rather than that flow, I have this flow:
This doesn't fit into "Perform the actual operation directly instead." scenario. I don't want to perform the operation if the directory or file exists. But I need to check that state beforehand. I have this pattern in many places.
What would the alternative be?
I can understand the documented scenario is an anti-pattern, but this feels like deprecating crucial functionality without a clear pattern for legitimate use cases.
The text was updated successfully, but these errors were encountered: