OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * Helper functionality to make working with IO easier. | 6 * Helper functionality to make working with IO easier. |
7 */ | 7 */ |
8 library io; | 8 library io; |
9 | 9 |
10 import 'dart:io'; | 10 import 'dart:io'; |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 * Asynchronously recursively deletes [dir], which can be a [String] or a | 238 * Asynchronously recursively deletes [dir], which can be a [String] or a |
239 * [Directory]. Returns a [Future] that completes when the deletion is done. | 239 * [Directory]. Returns a [Future] that completes when the deletion is done. |
240 */ | 240 */ |
241 Future<Directory> deleteDir(dir) { | 241 Future<Directory> deleteDir(dir) { |
242 dir = _getDirectory(dir); | 242 dir = _getDirectory(dir); |
243 | 243 |
244 return _attemptRetryable(() => log.ioAsync("delete directory ${dir.path}", | 244 return _attemptRetryable(() => log.ioAsync("delete directory ${dir.path}", |
245 dir.delete(recursive: true))); | 245 dir.delete(recursive: true))); |
246 } | 246 } |
247 | 247 |
248 /** | 248 /// Asynchronously lists the contents of [dir], which can be a [String] |
249 * Asynchronously lists the contents of [dir], which can be a [String] directory | 249 /// directory path or a [Directory]. If [recursive] is `true`, lists |
250 * path or a [Directory]. If [recursive] is `true`, lists subdirectory contents | 250 /// subdirectory contents (defaults to `false`). If [includeHiddenFiles] is |
251 * (defaults to `false`). If [includeHiddenFiles] is `true`, includes files and | 251 /// `true`, includes files and directories beginning with `.` (defaults to |
252 * directories beginning with `.` (defaults to `false`). | 252 /// `false`). |
253 */ | 253 /// |
| 254 /// If [dir] is a string, the returned paths are guaranteed to begin with it. |
254 Future<List<String>> listDir(dir, | 255 Future<List<String>> listDir(dir, |
255 {bool recursive: false, bool includeHiddenFiles: false}) { | 256 {bool recursive: false, bool includeHiddenFiles: false}) { |
256 final completer = new Completer<List<String>>(); | 257 Future<List<String>> doList(Directory dir, Set<String> listedDirectories) { |
257 final contents = <String>[]; | 258 var contents = <String>[]; |
| 259 var completer = new Completer<List<String>>(); |
258 | 260 |
259 dir = _getDirectory(dir); | 261 // Avoid recursive symlinks. |
260 log.io("Listing directory ${dir.path}."); | 262 var resolvedPath = new File(dir.path).fullPathSync(); |
261 var lister = dir.list(recursive: recursive); | 263 if (listedDirectories.contains(resolvedPath)) { |
| 264 return new Future.immediate([]); |
| 265 } |
| 266 listedDirectories = new Set<String>.from(listedDirectories); |
| 267 listedDirectories.add(resolvedPath); |
262 | 268 |
263 lister.onDone = (done) { | 269 log.io("Listing directory ${dir.path}."); |
264 // TODO(rnystrom): May need to sort here if it turns out onDir and onFile | 270 var lister = dir.list(); |
265 // aren't guaranteed to be called in a certain order. So far, they seem to. | 271 |
266 if (done) { | 272 lister.onDone = (done) { |
267 log.fine("Listed directory ${dir.path}:\n" | 273 // TODO(rnystrom): May need to sort here if it turns out onDir and onFile |
268 "${Strings.join(contents, '\n')}"); | 274 // aren't guaranteed to be called in a certain order. So far, they seem to
. |
269 completer.complete(contents); | 275 if (done) { |
| 276 log.fine("Listed directory ${dir.path}:\n" |
| 277 "${Strings.join(contents, '\n')}"); |
| 278 completer.complete(contents); |
| 279 } |
| 280 }; |
| 281 |
| 282 // TODO(nweiz): remove this when issue 4061 is fixed. |
| 283 var stackTrace; |
| 284 try { |
| 285 throw ""; |
| 286 } catch (_, localStackTrace) { |
| 287 stackTrace = localStackTrace; |
270 } | 288 } |
271 }; | |
272 | 289 |
273 // TODO(nweiz): remove this when issue 4061 is fixed. | 290 var children = []; |
274 var stackTrace; | 291 lister.onError = (error) => completer.completeException(error, stackTrace); |
275 try { | 292 lister.onDir = (file) { |
276 throw ""; | 293 if (!includeHiddenFiles && basename(file).startsWith('.')) return; |
277 } catch (_, localStackTrace) { | 294 file = join(dir, basename(file)); |
278 stackTrace = localStackTrace; | 295 contents.add(file); |
| 296 |
| 297 // TODO(nweiz): don't manually recurse once issue 7358 is fixed. |
| 298 if (recursive) { |
| 299 children.add(doList(new Directory(file), listedDirectories)); |
| 300 } |
| 301 }; |
| 302 lister.onFile = (file) { |
| 303 if (!includeHiddenFiles && basename(file).startsWith('.')) return; |
| 304 contents.add(join(dir, basename(file))); |
| 305 }; |
| 306 |
| 307 return completer.future.chain((contents) { |
| 308 return Futures.wait(children).transform((childContents) { |
| 309 contents.addAll(flatten(childContents)); |
| 310 return contents; |
| 311 }); |
| 312 }); |
279 } | 313 } |
280 | 314 |
281 lister.onError = (error) => completer.completeException(error, stackTrace); | 315 return doList(_getDirectory(dir), new Set<String>()); |
282 lister.onDir = (file) { | |
283 if (!includeHiddenFiles && basename(file).startsWith('.')) return; | |
284 contents.add(file); | |
285 }; | |
286 lister.onFile = (file) { | |
287 if (!includeHiddenFiles && basename(file).startsWith('.')) return; | |
288 contents.add(file); | |
289 }; | |
290 | |
291 return completer.future; | |
292 } | 316 } |
293 | 317 |
294 /** | 318 /** |
295 * Asynchronously determines if [dir], which can be a [String] directory path | 319 * Asynchronously determines if [dir], which can be a [String] directory path |
296 * or a [Directory], exists on the file system. Returns a [Future] that | 320 * or a [Directory], exists on the file system. Returns a [Future] that |
297 * completes with the result. | 321 * completes with the result. |
298 */ | 322 */ |
299 Future<bool> dirExists(dir) { | 323 Future<bool> dirExists(dir) { |
300 dir = _getDirectory(dir); | 324 dir = _getDirectory(dir); |
301 return log.ioAsync("Seeing if directory ${dir.path} exists.", | 325 return log.ioAsync("Seeing if directory ${dir.path} exists.", |
(...skipping 691 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
993 return new Directory(entry); | 1017 return new Directory(entry); |
994 } | 1018 } |
995 | 1019 |
996 /** | 1020 /** |
997 * Gets a [Uri] for [uri], which can either already be one, or be a [String]. | 1021 * Gets a [Uri] for [uri], which can either already be one, or be a [String]. |
998 */ | 1022 */ |
999 Uri _getUri(uri) { | 1023 Uri _getUri(uri) { |
1000 if (uri is Uri) return uri; | 1024 if (uri is Uri) return uri; |
1001 return new Uri.fromString(uri); | 1025 return new Uri.fromString(uri); |
1002 } | 1026 } |
OLD | NEW |