[flutter_tools] handle case where file is deleted by other program or running on read only volume #66708
Conversation
| @@ -17,6 +17,40 @@ import 'signals.dart'; | |||
| // the tool is killed by a signal. | |||
| export 'package:file/file.dart'; | |||
|
|
|||
| extension FileUtils on File { | |||
jonahwilliams
Sep 28, 2020
Author
Member
Not in love with the extension method, but I don't want to re-type everything as ErrorHandling file.
Maybe just a static helper method?
Not in love with the extension method, but I don't want to re-type everything as ErrorHandling file.
Maybe just a static helper method?
jonahwilliams
Oct 1, 2020
Author
Member
Update to static method on ErrorHandlingFileSystem
Update to static method on ErrorHandlingFileSystem
|
Extension methods are a bit scary. Not saying it's the not the right thing here, but it looks like we need to be careful with them. |
| @@ -17,6 +17,40 @@ import 'signals.dart'; | |||
| // the tool is killed by a signal. | |||
| export 'package:file/file.dart'; | |||
|
|
|||
| extension FileUtils on File { | |||
zanderso
Sep 29, 2020
Member
Does this extension apply to every class that extends or implements File, or does it apply only to exactly File? Either way, it is probably worth a comment here.
Does this extension apply to every class that extends or implements File, or does it apply only to exactly File? Either way, it is probably worth a comment here.
jonahwilliams
Oct 1, 2020
Author
Member
Moved to ErrorHandlingFileSystem
Moved to ErrorHandlingFileSystem
| @@ -57,6 +58,44 @@ void main() { | |||
| }); | |||
| }); | |||
|
|
|||
| testWithoutContext('deleteIfExists does not delete if file does not exist', () { | |||
zanderso
Sep 29, 2020
Member
If the extension method applies to any implementation of File, then we need test coverage of how it applies to them.
If the extension method applies to any implementation of File, then we need test coverage of how it applies to them.
| } | ||
| try { | ||
| deleteSync(recursive: recursive); | ||
| } on FileSystemException catch (err) { |
zanderso
Sep 29, 2020
Member
If File is an ErrorHandlingFile, then you could get either a ToolExit or an Exception here depending on whether you're under a noExitOnFailure.
If File is an ErrorHandlingFile, then you could get either a ToolExit or an Exception here depending on whether you're under a noExitOnFailure.
jonahwilliams
Sep 29, 2020
Author
Member
The goal with this catch is to only intercept error code 2, which we don't catch with error handling io because it normally seems to indicate a tool error.
Any other exception types should pass through as is, though I will add support for the existing error ignoring logic
The goal with this catch is to only intercept error code 2, which we don't catch with error handling io because it normally seems to indicate a tool error.
Any other exception types should pass through as is, though I will add support for the existing error ignoring logic
| rethrow; | ||
| } | ||
| if (existsSync()) { | ||
| throwToolExit( |
zanderso
Sep 29, 2020
Member
This would subvert a noExitOnFailure.
This would subvert a noExitOnFailure.
jonahwilliams
Sep 29, 2020
Author
Member
Thats true - this should probably become a static method on error handling file system - then that can be taken into account.
Thats true - this should probably become a static method on error handling file system - then that can be taken into account.
jonahwilliams
Oct 1, 2020
Author
Member
Updated to support noExitOnFailure
Updated to support noExitOnFailure
|
Friendly ping @zanderso |
|
Sorry for the delay. |
| // been deleted by a different program while the tool was running. | ||
| // if it still exists, the file likely exists on a read-only volume. | ||
| // This error code is the same across linux, windows, and macOS. | ||
| const int kSystemCannotFindFile = 2; |
zanderso
Oct 5, 2020
Member
Wouldn't this be different on different OS's?
Wouldn't this be different on different OS's?
jonahwilliams
Oct 5, 2020
Author
Member
For files it is the same, windows 2 is ERROR_FILE_NOT_FOUND, and 2 on linux/macOS 2 is ENOENT is No such file or directory. I can check if deleting a directory that does not exist uses the same error code on windows
For files it is the same, windows 2 is ERROR_FILE_NOT_FOUND, and 2 on linux/macOS 2 is ENOENT is No such file or directory. I can check if deleting a directory that does not exist uses the same error code on windows
zanderso
Oct 5, 2020
Member
kk. This would be good to have as a comment in the code here.
kk. This would be good to have as a comment in the code here.
jonahwilliams
Oct 5, 2020
Author
Member
Made the comment more specific
Made the comment more specific
| /// This method should be prefered to checking if it exists and | ||
| /// then deleting, because it handles the edge case where the file is | ||
| /// deleted by a different program between the two calls. | ||
| static bool deleteFileIfExists(File file, {bool recursive = false}) { |
zanderso
Oct 5, 2020
Member
How about:
static bool deleteIfExists(FileSystemEntity entity, ...) { ... }
Then it can handle directories and links as well.
How about:
static bool deleteIfExists(FileSystemEntity entity, ...) { ... }Then it can handle directories and links as well.
jonahwilliams
Oct 5, 2020
Author
Member
Will check if these have the same error code on windows
Will check if these have the same error code on windows
jonahwilliams
Oct 5, 2020
Author
Member
same error code for directories
same error code for directories
| @@ -241,9 +242,7 @@ flutter_project:lib/ | |||
| toolExit: true, | |||
| ); | |||
| } finally { | |||
| if (optionsFile.existsSync()) { | |||
zanderso
Oct 5, 2020
Member
How about replacing https://github.com/flutter/flutter/blob/master/packages/flutter_tools/test/src/common.dart#L34 and using that not just for directories but also for files?
How about replacing https://github.com/flutter/flutter/blob/master/packages/flutter_tools/test/src/common.dart#L34 and using that not just for directories but also for files?
jonahwilliams
Oct 5, 2020
Author
Member
That probably needs to be fixed too, but it is more for file lock issues on windows than read-only problems
That probably needs to be fixed too, but it is more for file lock issues on windows than read-only problems
zanderso
Oct 5, 2020
Member
So, the difference would be a different error code? The same code structure could handle the situation apart from that, though, right? Maybe not for this PR, but it would be nice to have a single way for the tool to try to delete something.
So, the difference would be a different error code? The same code structure could handle the situation apart from that, though, right? Maybe not for this PR, but it would be nice to have a single way for the tool to try to delete something.
jonahwilliams
Oct 5, 2020
Author
Member
I think we would prefer if the tests shut down cleanly, and this was added as more of a stopgap
I think we would prefer if the tests shut down cleanly, and this was added as more of a stopgap
zanderso
Oct 5, 2020
Member
Ah, yeah. Good point.
Ah, yeah. Good point.
|
lgtm |
| @@ -241,9 +242,7 @@ flutter_project:lib/ | |||
| toolExit: true, | |||
| ); | |||
| } finally { | |||
| if (optionsFile.existsSync()) { | |||
zanderso
Oct 5, 2020
Member
Ah, yeah. Good point.
Ah, yeah. Good point.
c8466d0
into
flutter:master
Description
I've seen some odd bugs in crash reporting where the tool fails to delete a file that it just checked does exist. It could be that a different program was deleting the file and the timing was just right. Be defensive to this and test on an OSError of 2 if it still exists. If it does, then it is probably pointing at a read-only volume
Fixes #57950