Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(282)

Side by Side Diff: pkg/watcher/lib/src/path_set.dart

Issue 66163002: Wrap Directory.watch on Mac OS for the watcher package. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
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.
4
5 library watcher.path_dart;
6
7 import 'dart:collection';
8
9 import 'package:path/path.dart' as p;
10
11 /// A set of paths, organized into a directory hierarchy.
12 ///
13 /// When a path is [add]ed, it creates an implicit directory structure above
14 /// that path. Directories can be inspected using [containsDir] and removed
15 /// using [remove]. If they're removed, their contents are removed as well.
16 ///
17 /// The paths in the set are normalized so that they all begin with [root].
18 class PathSet {
19 /// The root path, which all paths in the set must be under.
20 final String root;
21
22 /// The path set's directory hierarchy.
23 ///
24 /// Each level of this hierarchy has the same structure: a map from strings to
25 /// other maps, which are further levels of the hierarchy. A map with no
26 /// elements indicates a path that was added to the set that has no paths
27 /// beneath it. Such a path should not be treated as a directory by
28 /// [containsDir].
29 final _entries = new Map<String, Map>();
30
31 /// The set of paths that were explicitly added to this set.
32 ///
33 /// This is needed to disambiguate a directory that was explicitly added to
34 /// the set from a directory that was implicitly added by adding a path
35 /// beneath it.
36 final _paths = new Set<String>();
37
38 PathSet(this.root);
39
40 /// Adds [path] to the set.
41 void add(String path) {
42 path = _normalize(path);
43 _paths.add(path);
44
45 var parts = _split(path);
46 var dir = _entries;
47 for (var i = 0; i < parts.length; i++) {
Bob Nystrom 2013/11/09 00:42:57 Use a for-in loop here?
nweiz 2013/11/09 02:19:26 Done. This used to be structured differently.
48 dir = dir.putIfAbsent(parts[i], () => {});
49 }
50 }
51
52 /// Removes [path] and any paths beneath it from the set and returns the
53 /// removed paths.
54 ///
55 /// Even if [path] itself isn't in the set, if it's a directory containing
56 /// paths that are in the set those paths will be removed and returned.
57 ///
58 /// If neither [path] nor any paths beneath it are in the set, returns an
59 /// empty set.
60 Set<String> remove(String path) {
61 path = _normalize(path);
62 var parts = new Queue.from(_split(path));
63
Bob Nystrom 2013/11/09 00:42:57 This could definitely use some more docs.
nweiz 2013/11/09 02:19:26 Done.
64 recurse(dir, partialPath) {
65 if (parts.length > 1) {
66 var part = parts.removeFirst();
67 var entry = dir[part];
68 if (entry.isEmpty) return new Set();
69
70 partialPath = p.join(partialPath, part);
71 var paths = recurse(entry, partialPath);
72 if (entry.isEmpty && !_paths.contains(partialPath)) dir.remove(part);
Bob Nystrom 2013/11/09 00:42:57 // If after removing the children, there is nothin
nweiz 2013/11/09 02:19:26 Done.
73 return paths;
74 }
75
76 var entry = dir.remove(parts.first);
77 if (entry == null) return new Set();
78
79 if (entry.isEmpty) {
80 _paths.remove(path);
81 return new Set.from([path]);
82 }
83
84 var set = _removePathsIn(entry, path);
85 if (_paths.contains(path)) {
86 _paths.remove(path);
87 set.add(path);
88 }
89 return set;
90 }
91
92 return recurse(_entries, root);
93 }
94
95 /// Recursively removes and returns all paths in [dir].
96 ///
97 /// [root] should be the path to [dir].
98 Set<String> _removePathsIn(Map dir, String root) {
99 var removedPaths = new Set();
100 recurse(dir, path) {
101 dir.forEach((name, entry) {
102 var entryPath = p.join(path, name);
103 if (_paths.remove(entryPath)) removedPaths.add(entryPath);
104 recurse(entry, entryPath);
105 });
106 }
107
108 recurse(dir, root);
109 return removedPaths;
110 }
111
112 /// Returns whether [this] contains [path].
113 ///
114 /// This only returns true for paths explicitly added to [this].
115 /// Implicitly-added directories can be inspected using [containsDir].
116 bool contains(String path) => _paths.contains(_normalize(path));
117
118 /// Returns whether [this] contains paths beneath [path].
119 bool containsDir(String path) {
120 path = _normalize(path);
121 var dir = _entries;
122
123 for (var part in _split(path)) {
124 dir = dir[part];
125 if (dir == null) return false;
126 }
127
128 return !dir.isEmpty;
129 }
130
131 /// Returns a [Set] of all paths in [this].
132 Set<String> toSet() => _paths.toSet();
133
134 /// Removes all paths from [this].
135 void clear() {
136 _paths.clear();
137 _entries.clear();
138 }
139
140 String toString() => _paths.toString();
141
142 /// Returns a normalized version of [path].
143 ///
144 /// This removes any extra ".." or "."s and ensure that the returned path
145 /// begins with [root]. It's an error if [path] isn't within [root].
146 String _normalize(String path) {
147 var relative = p.relative(p.normalize(path), from: root);
148 var parts = p.split(relative);
149 if (!p.isRelative(relative) || parts.first == '..' || parts.first == '.') {
Bob Nystrom 2013/11/09 00:42:57 We should really add isWithin() to pkg/path.
nweiz 2013/11/09 02:19:26 Filed a bug and referenced it here.
150 throw new ArgumentError('Path "$path" is not inside "$root".');
151 }
152 return p.join(root, relative);
153 }
154
155 /// Returns the segments of [path] beneath [root].
156 List<String> _split(String path) => p.split(p.relative(path, from: root));
157 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698