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...) 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, |
257 Set<String> _listedDirectories}) { | |
Bob Nystrom
2012/12/17 23:42:33
Instead of making this an optional parameter, how
nweiz
2012/12/18 18:38:43
Done.
| |
256 final completer = new Completer<List<String>>(); | 258 final completer = new Completer<List<String>>(); |
257 final contents = <String>[]; | 259 final contents = <String>[]; |
258 | 260 |
261 // Avoid recursive symlinks. | |
262 if (_listedDirectories == null) _listedDirectories = new Set<String>(); | |
263 var resolvedPath = new File(dir).fullPathSync(); | |
264 if (_listedDirectories.contains(resolvedPath)) { | |
265 return new Future.immediate([]); | |
266 } | |
267 _listedDirectories = new Set<String>.from(_listedDirectories); | |
268 _listedDirectories.add(resolvedPath); | |
269 | |
259 dir = _getDirectory(dir); | 270 dir = _getDirectory(dir); |
260 log.io("Listing directory ${dir.path}."); | 271 log.io("Listing directory ${dir.path}."); |
261 var lister = dir.list(recursive: recursive); | 272 var lister = dir.list(); |
262 | 273 |
263 lister.onDone = (done) { | 274 lister.onDone = (done) { |
264 // TODO(rnystrom): May need to sort here if it turns out onDir and onFile | 275 // TODO(rnystrom): May need to sort here if it turns out onDir and onFile |
265 // aren't guaranteed to be called in a certain order. So far, they seem to. | 276 // aren't guaranteed to be called in a certain order. So far, they seem to. |
266 if (done) { | 277 if (done) { |
267 log.fine("Listed directory ${dir.path}:\n" | 278 log.fine("Listed directory ${dir.path}:\n" |
268 "${Strings.join(contents, '\n')}"); | 279 "${Strings.join(contents, '\n')}"); |
269 completer.complete(contents); | 280 completer.complete(contents); |
270 } | 281 } |
271 }; | 282 }; |
272 | 283 |
273 // TODO(nweiz): remove this when issue 4061 is fixed. | 284 // TODO(nweiz): remove this when issue 4061 is fixed. |
274 var stackTrace; | 285 var stackTrace; |
275 try { | 286 try { |
276 throw ""; | 287 throw ""; |
277 } catch (_, localStackTrace) { | 288 } catch (_, localStackTrace) { |
278 stackTrace = localStackTrace; | 289 stackTrace = localStackTrace; |
279 } | 290 } |
280 | 291 |
292 var children = []; | |
281 lister.onError = (error) => completer.completeException(error, stackTrace); | 293 lister.onError = (error) => completer.completeException(error, stackTrace); |
282 lister.onDir = (file) { | 294 lister.onDir = (file) { |
283 if (!includeHiddenFiles && basename(file).startsWith('.')) return; | 295 if (!includeHiddenFiles && basename(file).startsWith('.')) return; |
296 file = join(dir, basename(file)); | |
284 contents.add(file); | 297 contents.add(file); |
298 | |
299 // TODO(nweiz): don't manually recurse once issue 7358 is fixed. | |
300 if (recursive) { | |
301 children.add(listDir(file, | |
302 recursive: true, | |
303 includeHiddenFiles: includeHiddenFiles, | |
304 _listedDirectories: _listedDirectories)); | |
305 } | |
285 }; | 306 }; |
286 lister.onFile = (file) { | 307 lister.onFile = (file) { |
287 if (!includeHiddenFiles && basename(file).startsWith('.')) return; | 308 if (!includeHiddenFiles && basename(file).startsWith('.')) return; |
288 contents.add(file); | 309 contents.add(join(dir, basename(file))); |
289 }; | 310 }; |
290 | 311 |
291 return completer.future; | 312 return completer.future.chain((contents) { |
313 return Futures.wait(children).transform((childContents) { | |
314 contents.addAll(flatten(childContents)); | |
315 return contents; | |
316 }); | |
317 }); | |
292 } | 318 } |
293 | 319 |
294 /** | 320 /** |
295 * Asynchronously determines if [dir], which can be a [String] directory path | 321 * Asynchronously determines if [dir], which can be a [String] directory path |
296 * or a [Directory], exists on the file system. Returns a [Future] that | 322 * or a [Directory], exists on the file system. Returns a [Future] that |
297 * completes with the result. | 323 * completes with the result. |
298 */ | 324 */ |
299 Future<bool> dirExists(dir) { | 325 Future<bool> dirExists(dir) { |
300 dir = _getDirectory(dir); | 326 dir = _getDirectory(dir); |
301 return log.ioAsync("Seeing if directory ${dir.path} exists.", | 327 return log.ioAsync("Seeing if directory ${dir.path} exists.", |
(...skipping 765 matching lines...) Loading... | |
1067 return new Directory(entry); | 1093 return new Directory(entry); |
1068 } | 1094 } |
1069 | 1095 |
1070 /** | 1096 /** |
1071 * Gets a [Uri] for [uri], which can either already be one, or be a [String]. | 1097 * Gets a [Uri] for [uri], which can either already be one, or be a [String]. |
1072 */ | 1098 */ |
1073 Uri _getUri(uri) { | 1099 Uri _getUri(uri) { |
1074 if (uri is Uri) return uri; | 1100 if (uri is Uri) return uri; |
1075 return new Uri.fromString(uri); | 1101 return new Uri.fromString(uri); |
1076 } | 1102 } |
OLD | NEW |