OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library glob.list_tree; | 5 library glob.list_tree; |
6 | 6 |
7 import 'dart:io'; | 7 import 'dart:io'; |
8 import 'dart:async'; | 8 import 'dart:async'; |
9 | 9 |
10 import 'package:path/path.dart' as p; | 10 import 'package:path/path.dart' as p; |
11 | 11 |
12 import 'ast.dart'; | 12 import 'ast.dart'; |
13 import 'stream_pool.dart'; | 13 import 'stream_pool.dart'; |
14 import 'utils.dart'; | 14 import 'utils.dart'; |
15 | 15 |
16 /// The errno for a file or directory not existing. | 16 /// The errno for a file or directory not existing on Mac and Linux. |
17 /// | |
18 /// This is consistent across platforms. | |
19 const _ENOENT = 2; | 17 const _ENOENT = 2; |
20 | 18 |
| 19 /// Another errno we see on Windows when trying to list a non-existent |
| 20 /// directory. |
| 21 const _ENOENT_WIN = 3; |
| 22 |
21 /// A structure built from a glob that efficiently lists filesystem entities | 23 /// A structure built from a glob that efficiently lists filesystem entities |
22 /// that match that glob. | 24 /// that match that glob. |
23 /// | 25 /// |
24 /// This structure is designed to list the minimal number of physical | 26 /// This structure is designed to list the minimal number of physical |
25 /// directories necessary to find everything that matches the glob. For example, | 27 /// directories necessary to find everything that matches the glob. For example, |
26 /// for the glob `foo/{bar,baz}/*`, there's no need to list the working | 28 /// for the glob `foo/{bar,baz}/*`, there's no need to list the working |
27 /// directory or even `foo/`; only `foo/bar` and `foo/baz` should be listed. | 29 /// directory or even `foo/`; only `foo/bar` and `foo/baz` should be listed. |
28 /// | 30 /// |
29 /// This works by creating a tree of [_ListTreeNode]s, each of which corresponds | 31 /// This works by creating a tree of [_ListTreeNode]s, each of which corresponds |
30 /// to a single of directory nesting in the source glob. Each node has child | 32 /// to a single of directory nesting in the source glob. Each node has child |
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 children.forEach((sequence, child) { | 326 children.forEach((sequence, child) { |
325 if (entity is! Directory) return; | 327 if (entity is! Directory) return; |
326 if (!sequence.matches(basename)) return; | 328 if (!sequence.matches(basename)) return; |
327 var stream = child.list(p.join(dir, basename), followLinks: followLinks) | 329 var stream = child.list(p.join(dir, basename), followLinks: followLinks) |
328 .handleError((_) {}, test: (error) { | 330 .handleError((_) {}, test: (error) { |
329 // Ignore errors from directories not existing. We do this here so | 331 // Ignore errors from directories not existing. We do this here so |
330 // that we only ignore warnings below wild cards. For example, the | 332 // that we only ignore warnings below wild cards. For example, the |
331 // glob "foo/bar/*/baz" should fail if "foo/bar" doesn't exist but | 333 // glob "foo/bar/*/baz" should fail if "foo/bar" doesn't exist but |
332 // succeed if "foo/bar/qux/baz" doesn't exist. | 334 // succeed if "foo/bar/qux/baz" doesn't exist. |
333 return error is FileSystemException && | 335 return error is FileSystemException && |
334 error.osError.errorCode == _ENOENT; | 336 (error.osError.errorCode == _ENOENT || |
| 337 error.osError.errorCode == _ENOENT_WIN); |
335 }); | 338 }); |
336 resultPool.add(stream); | 339 resultPool.add(stream); |
337 }); | 340 }); |
338 }, | 341 }, |
339 onError: resultController.addError, | 342 onError: resultController.addError, |
340 onDone: resultController.close); | 343 onDone: resultController.close); |
341 | 344 |
342 resultPool.closeWhenEmpty(); | 345 resultPool.closeWhenEmpty(); |
343 return resultPool.stream; | 346 return resultPool.stream; |
344 } | 347 } |
(...skipping 30 matching lines...) Expand all Loading... |
375 .where((sequence) => sequence.matches(basename)) | 378 .where((sequence) => sequence.matches(basename)) |
376 .expand((sequence) { | 379 .expand((sequence) { |
377 try { | 380 try { |
378 return children[sequence].listSync( | 381 return children[sequence].listSync( |
379 p.join(dir, basename), followLinks: followLinks).toList(); | 382 p.join(dir, basename), followLinks: followLinks).toList(); |
380 } on FileSystemException catch (error) { | 383 } on FileSystemException catch (error) { |
381 // Ignore errors from directories not existing. We do this here so | 384 // Ignore errors from directories not existing. We do this here so |
382 // that we only ignore warnings below wild cards. For example, the | 385 // that we only ignore warnings below wild cards. For example, the |
383 // glob "foo/bar/*/baz" should fail if "foo/bar" doesn't exist but | 386 // glob "foo/bar/*/baz" should fail if "foo/bar" doesn't exist but |
384 // succeed if "foo/bar/qux/baz" doesn't exist. | 387 // succeed if "foo/bar/qux/baz" doesn't exist. |
385 if (error.osError.errorCode == _ENOENT) { | 388 if (error.osError.errorCode == _ENOENT || |
| 389 error.osError.errorCode == _ENOENT_WIN) { |
386 return const []; | 390 return const []; |
387 } else { | 391 } else { |
388 rethrow; | 392 rethrow; |
389 } | 393 } |
390 } | 394 } |
391 })); | 395 })); |
392 | 396 |
393 return entities; | 397 return entities; |
394 }); | 398 }); |
395 } | 399 } |
(...skipping 11 matching lines...) Expand all Loading... |
407 /// a path separator. | 411 /// a path separator. |
408 SequenceNode _join(Iterable<AstNode> components) { | 412 SequenceNode _join(Iterable<AstNode> components) { |
409 var componentsList = components.toList(); | 413 var componentsList = components.toList(); |
410 var nodes = [componentsList.removeAt(0)]; | 414 var nodes = [componentsList.removeAt(0)]; |
411 for (var component in componentsList) { | 415 for (var component in componentsList) { |
412 nodes.add(new LiteralNode('/')); | 416 nodes.add(new LiteralNode('/')); |
413 nodes.add(component); | 417 nodes.add(component); |
414 } | 418 } |
415 return new SequenceNode(nodes); | 419 return new SequenceNode(nodes); |
416 } | 420 } |
OLD | NEW |