Index: packages/glob/lib/src/list_tree.dart |
diff --git a/packages/glob/lib/src/list_tree.dart b/packages/glob/lib/src/list_tree.dart |
index 3667d63c1abbd2a1a9492af9601203717604f736..3cce642253c25b18d4593fcff67807ffd67f6be2 100644 |
--- a/packages/glob/lib/src/list_tree.dart |
+++ b/packages/glob/lib/src/list_tree.dart |
@@ -2,15 +2,13 @@ |
// for details. All rights reserved. Use of this source code is governed by a |
// BSD-style license that can be found in the LICENSE file. |
-library glob.list_tree; |
- |
import 'dart:io'; |
import 'dart:async'; |
+import 'package:async/async.dart'; |
import 'package:path/path.dart' as p; |
import 'ast.dart'; |
-import 'stream_pool.dart'; |
import 'utils.dart'; |
/// The errno for a file or directory not existing on Mac and Linux. |
@@ -99,7 +97,7 @@ class ListTree { |
} |
/// Add the glob represented by [components] to the tree under [root]. |
- void _addGlob(String root, List<AstNode> components) { |
+ void _addGlob(String root, List<SequenceNode> components) { |
// The first [parent] represents the root directory itself. It may be null |
// here if this is the first option with this particular [root]. If so, |
// we'll create it below. |
@@ -172,19 +170,19 @@ class ListTree { |
/// List all entities that match this glob beneath [root]. |
Stream<FileSystemEntity> list({String root, bool followLinks: true}) { |
if (root == null) root = '.'; |
- var pool = new StreamPool(); |
+ var group = new StreamGroup<FileSystemEntity>(); |
for (var rootDir in _trees.keys) { |
var dir = rootDir == '.' ? root : rootDir; |
- pool.add(_trees[rootDir].list(dir, followLinks: followLinks)); |
+ group.add(_trees[rootDir].list(dir, followLinks: followLinks)); |
} |
- pool.closeWhenEmpty(); |
+ group.close(); |
- if (!_canOverlap) return pool.stream; |
+ if (!_canOverlap) return group.stream; |
// TODO(nweiz): Rather than filtering here, avoid double-listing directories |
// in the first place. |
var seen = new Set(); |
- return pool.stream.where((entity) { |
+ return group.stream.where((entity) { |
if (seen.contains(entity.path)) return false; |
seen.add(entity.path); |
return true; |
@@ -195,7 +193,8 @@ class ListTree { |
List<FileSystemEntity> listSync({String root, bool followLinks: true}) { |
if (root == null) root = '.'; |
- var result = _trees.keys.expand((rootDir) { |
+ // TODO(nweiz): Remove the explicit annotation when sdk#26139 is fixed. |
+ var result = _trees.keys.expand/*<FileSystemEntity>*/((rootDir) { |
var dir = rootDir == '.' ? root : rootDir; |
return _trees[rootDir].listSync(dir, followLinks: followLinks); |
}); |
@@ -204,7 +203,7 @@ class ListTree { |
// TODO(nweiz): Rather than filtering here, avoid double-listing directories |
// in the first place. |
- var seen = new Set(); |
+ var seen = new Set<String>(); |
return result.where((entity) { |
if (seen.contains(entity.path)) return false; |
seen.add(entity.path); |
@@ -234,6 +233,13 @@ class _ListTreeNode { |
/// A recursive node has no children and is listed recursively. |
bool get isRecursive => children == null; |
+ bool get _caseSensitive { |
+ if (_validator != null) return _validator.caseSensitive; |
+ if (children == null) return true; |
+ if (children.isEmpty) return true; |
+ return children.keys.first.caseSensitive; |
+ } |
+ |
/// Whether this node doesn't itself need to be listed. |
/// |
/// If a node has no validator and all of its children are literal filenames, |
@@ -241,6 +247,7 @@ class _ListTreeNode { |
/// its children. |
bool get _isIntermediate { |
if (_validator != null) return false; |
+ if (!_caseSensitive) return false; |
return children.keys.every((sequence) => |
sequence.nodes.length == 1 && sequence.nodes.first is LiteralNode); |
} |
@@ -255,9 +262,14 @@ class _ListTreeNode { |
// If there's more than one child node and at least one of the children is |
// dynamic (that is, matches more than just a literal string), there may be |
// overlap. |
- if (children.length > 1 && children.keys.any((sequence) => |
+ if (children.length > 1) { |
+ // Case-insensitivity means that even literals may match multiple entries. |
+ if (!_caseSensitive) return true; |
+ |
+ if (children.keys.any((sequence) => |
sequence.nodes.length > 1 || sequence.nodes.single is! LiteralNode)) { |
- return true; |
+ return true; |
+ } |
} |
return children.values.any((node) => node.canOverlap); |
@@ -271,7 +283,8 @@ class _ListTreeNode { |
/// Creates a recursive node the given [validator]. |
_ListTreeNode.recursive(SequenceNode validator) |
: children = null, |
- _validator = new OptionsNode([validator]); |
+ _validator = new OptionsNode([validator], |
+ caseSensitive: validator.caseSensitive); |
/// Transforms this into recursive node, folding all its children into its |
/// validator. |
@@ -281,14 +294,15 @@ class _ListTreeNode { |
var child = children[sequence]; |
child.makeRecursive(); |
return _join([sequence, child._validator]); |
- })); |
+ }), caseSensitive: _caseSensitive); |
children = null; |
} |
/// Adds [validator] to this node's existing validator. |
void addOption(SequenceNode validator) { |
if (_validator == null) { |
- _validator = new OptionsNode([validator]); |
+ _validator = new OptionsNode([validator], |
+ caseSensitive: validator.caseSensitive); |
} else { |
_validator.options.add(validator); |
} |
@@ -301,26 +315,27 @@ class _ListTreeNode { |
Stream<FileSystemEntity> list(String dir, {bool followLinks: true}) { |
if (isRecursive) { |
return new Directory(dir).list(recursive: true, followLinks: followLinks) |
- .where((entity) => _matches(entity.path.substring(dir.length + 1))); |
+ .where((entity) => _matches(p.relative(entity.path, from: dir))); |
} |
- var resultPool = new StreamPool(); |
+ var resultGroup = new StreamGroup<FileSystemEntity>(); |
// Don't spawn extra [Directory.list] calls when we already know exactly |
// which subdirectories we're interested in. |
if (_isIntermediate) { |
children.forEach((sequence, child) { |
- resultPool.add(child.list(p.join(dir, sequence.nodes.single.text), |
+ resultGroup.add(child.list( |
+ p.join(dir, (sequence.nodes.single as LiteralNode).text), |
followLinks: followLinks)); |
}); |
- resultPool.closeWhenEmpty(); |
- return resultPool.stream; |
+ resultGroup.close(); |
+ return resultGroup.stream; |
} |
- var resultController = new StreamController(sync: true); |
- resultPool.add(resultController.stream); |
+ var resultController = new StreamController<FileSystemEntity>(sync: true); |
+ resultGroup.add(resultController.stream); |
new Directory(dir).list(followLinks: followLinks).listen((entity) { |
- var basename = entity.path.substring(dir.length + 1); |
+ var basename = p.relative(entity.path, from: dir); |
if (_matches(basename)) resultController.add(entity); |
children.forEach((sequence, child) { |
@@ -336,14 +351,16 @@ class _ListTreeNode { |
(error.osError.errorCode == _ENOENT || |
error.osError.errorCode == _ENOENT_WIN); |
}); |
- resultPool.add(stream); |
+ resultGroup.add(stream); |
}); |
}, |
onError: resultController.addError, |
- onDone: resultController.close); |
+ onDone: () { |
+ resultController.close(); |
+ resultGroup.close(); |
+ }); |
- resultPool.closeWhenEmpty(); |
- return resultPool.stream; |
+ return resultGroup.stream; |
} |
/// Synchronously lists all entities within [dir] matching this node or its |
@@ -355,7 +372,7 @@ class _ListTreeNode { |
if (isRecursive) { |
return new Directory(dir) |
.listSync(recursive: true, followLinks: followLinks) |
- .where((entity) => _matches(entity.path.substring(dir.length + 1))); |
+ .where((entity) => _matches(p.relative(entity.path, from: dir))); |
} |
// Don't spawn extra [Directory.listSync] calls when we already know exactly |
@@ -363,14 +380,15 @@ class _ListTreeNode { |
if (_isIntermediate) { |
return children.keys.expand((sequence) { |
return children[sequence].listSync( |
- p.join(dir, sequence.nodes.single.text), followLinks: followLinks); |
+ p.join(dir, (sequence.nodes.single as LiteralNode).text), |
+ followLinks: followLinks); |
}); |
} |
return new Directory(dir).listSync(followLinks: followLinks) |
.expand((entity) { |
- var entities = []; |
- var basename = entity.path.substring(dir.length + 1); |
+ var entities = <FileSystemEntity>[]; |
+ var basename = p.relative(entity.path, from: dir); |
if (_matches(basename)) entities.add(entity); |
if (entity is! Directory) return entities; |
@@ -411,10 +429,11 @@ class _ListTreeNode { |
/// a path separator. |
SequenceNode _join(Iterable<AstNode> components) { |
var componentsList = components.toList(); |
- var nodes = [componentsList.removeAt(0)]; |
+ var first = componentsList.removeAt(0); |
+ var nodes = [first]; |
for (var component in componentsList) { |
- nodes.add(new LiteralNode('/')); |
+ nodes.add(new LiteralNode('/', caseSensitive: first.caseSensitive)); |
nodes.add(component); |
} |
- return new SequenceNode(nodes); |
+ return new SequenceNode(nodes, caseSensitive: first.caseSensitive); |
} |