Index: sdk/lib/_internal/pub/lib/src/io.dart |
diff --git a/sdk/lib/_internal/pub/lib/src/io.dart b/sdk/lib/_internal/pub/lib/src/io.dart |
index f93f34c6d2eccfb801e5519acf96d8044b2edbfc..7483a5a17b76a65ef0e1be1be7869cf597044bb8 100644 |
--- a/sdk/lib/_internal/pub/lib/src/io.dart |
+++ b/sdk/lib/_internal/pub/lib/src/io.dart |
@@ -270,49 +270,57 @@ List<String> listDir(String dir, {bool recursive: false, |
/// a symlink only if that symlink is unbroken and points to a directory. |
bool dirExists(String dir) => new Directory(dir).existsSync(); |
-/// Deletes whatever's at [path], whether it's a file, directory, or symlink. If |
-/// it's a directory, it will be deleted recursively. |
-void deleteEntry(String path) { |
- tryDeleteEntry() { |
- if (linkExists(path)) { |
- log.io("Deleting link $path."); |
- new Link(path).deleteSync(); |
- } else if (dirExists(path)) { |
- log.io("Deleting directory $path."); |
- new Directory(path).deleteSync(recursive: true); |
- } else if (fileExists(path)) { |
- log.io("Deleting file $path."); |
- new File(path).deleteSync(); |
- } |
- } |
- |
+/// Try to resiliently perform [operation]. |
+/// |
+/// Some file system operations can intermittently fail on Windows because |
+/// other processes are locking a file. We've seen this with virus scanners |
+/// when we try to delete or move something while it's being scanned. To |
+/// mitigate that, on Windows, this will retry the operation a few times if it |
+/// fails. |
+void _attempt(String description, void operation()) { |
if (Platform.operatingSystem != 'windows') { |
- tryDeleteEntry(); |
+ operation(); |
return; |
} |
- // On Windows, we can fail to delete an entry if it's in use by another |
- // process. The only case where we know this to cause a problem is when |
- // testing "pub serve", since it can poll a file at the same time we try to |
- // delete it in the test process (issue 16129). |
- // |
- // TODO(nweiz): Once issue 14428 is fixed for Windows, remove this special |
- // handling. |
for (var i = 0; i < 2; i++) { |
try { |
- tryDeleteEntry(); |
+ operation(); |
+ return; |
} on FileSystemException catch (error) { |
- // Errno 32 indicates that the deletion failed because the file was in |
- // use. |
- if (error.osError.errorCode != 32) rethrow; |
+ var reason; |
+ if (error.osError.errorCode == 5) { |
+ reason = "access was denied"; |
+ } else if (error.osError.errorCode == 32) { |
+ reason = "it was in use by another process"; |
+ } else { |
+ rethrow; |
+ } |
- log.io("Failed to delete entry because it was in use by another process. " |
+ log.io("Failed to $description because $reason. " |
"Retrying in 50ms."); |
sleep(new Duration(milliseconds: 50)); |
} |
} |
- tryDeleteEntry(); |
+ operation(); |
nweiz
2014/06/16 20:02:14
It might be nice to catch the error here as well a
Bob Nystrom
2014/06/17 21:30:29
Done.
|
+} |
+ |
+/// Deletes whatever's at [path], whether it's a file, directory, or symlink. If |
+/// it's a directory, it will be deleted recursively. |
+void deleteEntry(String path) { |
+ _attempt("delete entry", () { |
+ if (linkExists(path)) { |
+ log.io("Deleting link $path."); |
+ new Link(path).deleteSync(); |
+ } else if (dirExists(path)) { |
+ log.io("Deleting directory $path."); |
+ new Directory(path).deleteSync(recursive: true); |
+ } else if (fileExists(path)) { |
+ log.io("Deleting file $path."); |
+ new File(path).deleteSync(); |
+ } |
+ }); |
} |
/// "Cleans" [dir]. If that directory already exists, it will be deleted. Then a |
@@ -324,14 +332,16 @@ void cleanDir(String dir) { |
/// Renames (i.e. moves) the directory [from] to [to]. |
void renameDir(String from, String to) { |
- log.io("Renaming directory $from to $to."); |
- try { |
- new Directory(from).renameSync(to); |
- } on IOException catch (error) { |
- // Ensure that [to] isn't left in an inconsistent state. See issue 12436. |
- if (entryExists(to)) deleteEntry(to); |
- rethrow; |
- } |
+ _attempt("rename directory", () { |
+ log.io("Renaming directory $from to $to."); |
+ try { |
+ new Directory(from).renameSync(to); |
+ } on IOException catch (error) { |
+ // Ensure that [to] isn't left in an inconsistent state. See issue 12436. |
+ if (entryExists(to)) deleteEntry(to); |
+ rethrow; |
+ } |
+ }); |
} |
/// Creates a new symlink at path [symlink] that points to [target]. Returns a |