@@ -11,10 +11,12 @@ import '../asset/id.dart';
1111import '../asset/writer.dart' ;
1212import '../asset_graph/graph.dart' ;
1313import '../asset_graph/node.dart' ;
14+ import '../logging/logging.dart' ;
1415import '../package_graph/package_graph.dart' ;
1516import 'build_impl.dart' ;
1617import 'build_result.dart' ;
1718import 'directory_watcher_factory.dart' ;
19+ import 'exceptions.dart' ;
1820import 'options.dart' ;
1921import 'phase.dart' ;
2022
@@ -46,8 +48,8 @@ class WatchImpl {
4648 final AssetWriter _writer;
4749
4850 /// A future that completes when the current build is done.
49- Future _currentBuild;
50- Future get currentBuild => _currentBuild;
51+ Future < BuildResult > _currentBuild;
52+ Future < BuildResult > get currentBuild => _currentBuild;
5153
5254 /// Whether or not another build is scheduled.
5355 bool _nextBuildScheduled;
@@ -61,6 +63,9 @@ class WatchImpl {
6163 /// Whether we are in the process of terminating.
6264 bool _terminating = false ;
6365
66+ Completer _onTerminatedCompleter = new Completer ();
67+ Future get onTerminated => _onTerminatedCompleter.future;
68+
6469 WatchImpl (BuildOptions options, PhaseGroup phaseGroup)
6570 : _directoryWatcherFactory = options.directoryWatcherFactory,
6671 _debounceDelay = options.debounceDelay,
@@ -71,7 +76,10 @@ class WatchImpl {
7176 /// Completes after the current build is done, and stops further builds from
7277 /// happening.
7378 Future terminate () async {
74- if (_terminating) throw new StateError ('Already terminating.' );
79+ if (_terminating) {
80+ _logger.warning ('Already terminating.' );
81+ return ;
82+ }
7583 if (_resultStreamController == null ) {
7684 throw new StateError ('`terminate` called before `runWatch`' );
7785 }
@@ -93,6 +101,7 @@ class WatchImpl {
93101 }
94102 _terminating = false ;
95103 _logger.info ('Build watching terminated, safe to exit.\n ' );
104+ _onTerminatedCompleter.complete ();
96105 }
97106
98107 /// Runs a build any time relevant files change.
@@ -140,11 +149,17 @@ class WatchImpl {
140149 return ;
141150 }
142151
143- _logger.info ('Preparing for next build' );
144- _logger.info ('Starting build' );
152+ _logger.info ('Starting next build' );
145153 _currentBuild =
146154 _buildImpl.runBuild (validAsOf: validAsOf, updates: updatedInputsCopy);
147155 _currentBuild.then ((result) {
156+ // Terminate the watcher if the build script is updated, there is no
157+ // need to continue listening.
158+ if (result.status == BuildStatus .Failure &&
159+ result.exception is BuildScriptUpdatedException ) {
160+ terminate ();
161+ }
162+
148163 if (_resultStreamController.hasListener) {
149164 _resultStreamController.add (result);
150165 }
@@ -162,46 +177,48 @@ class WatchImpl {
162177 buildTimer = new Timer (_debounceDelay, doBuild);
163178 }
164179
165- final watchers = < DirectoryWatcher > [];
166- _logger. info ( 'Setting up file watchers' ) ;
180+ logWithTime (_logger, 'Setting up file watchers' , () {
181+ final watchers = < DirectoryWatcher > [] ;
167182
168- // Collect absolute file paths for all the packages. This needs to happen
169- // before setting up the watchers.
170- final absolutePackagePaths = < PackageNode , String > {};
171- for (var package in _packageGraph.allPackages.values) {
172- absolutePackagePaths[package] =
173- path.normalize (path.absolute (package.location.toFilePath ()));
174- }
183+ // Collect absolute file paths for all the packages. This needs to happen
184+ // before setting up the watchers.
185+ final absolutePackagePaths = < PackageNode , String > {};
186+ for (var package in _packageGraph.allPackages.values) {
187+ absolutePackagePaths[package] =
188+ path.normalize (path.absolute (package.location.toFilePath ()));
189+ }
175190
176- // Set up watchers for all the packages
177- for (var package in _packageGraph.allPackages.values) {
178- var absolutePackagePath = absolutePackagePaths[package];
179- _logger.fine ('Setting up watcher at $absolutePackagePath ' );
180-
181- // Ignore all subfolders which are other packages.
182- var pathsToIgnore = absolutePackagePaths.values.where ((path) =>
183- path != absolutePackagePath && path.startsWith (absolutePackagePath));
184-
185- var watcher = _directoryWatcherFactory (absolutePackagePath);
186- watchers.add (watcher);
187- _allListeners.add (watcher.events.listen ((WatchEvent e) {
188- // Check for ignored paths and immediately bail.
189- if (pathsToIgnore.any ((path) => e.path.startsWith (path))) return ;
190-
191- var relativePath = path.relative (e.path, from: absolutePackagePath);
192- _logger.finest (
193- 'Got ${e .type } event for path $relativePath from ${watcher .path }' );
194- var id = new AssetId (package.name, relativePath);
195- var node = _assetGraph.get (id);
196- // Short circuit for deletes of nodes that aren't in the graph.
197- if (e.type == ChangeType .REMOVE && node == null ) return ;
198-
199- updatedInputs[id] = e.type;
200- scheduleBuild ();
201- }));
202- }
191+ // Set up watchers for all the packages
192+ for (var package in _packageGraph.allPackages.values) {
193+ var absolutePackagePath = absolutePackagePaths[package];
194+ _logger.fine ('Setting up watcher at $absolutePackagePath ' );
195+
196+ // Ignore all subfolders which are other packages.
197+ var pathsToIgnore = absolutePackagePaths.values.where ((path) =>
198+ path != absolutePackagePath &&
199+ path.startsWith (absolutePackagePath));
200+
201+ var watcher = _directoryWatcherFactory (absolutePackagePath);
202+ watchers.add (watcher);
203+ _allListeners.add (watcher.events.listen ((WatchEvent e) {
204+ // Check for ignored paths and immediately bail.
205+ if (pathsToIgnore.any ((path) => e.path.startsWith (path))) return ;
206+
207+ var relativePath = path.relative (e.path, from: absolutePackagePath);
208+ _logger.finest (
209+ 'Got ${e .type } event for path $relativePath from ${watcher .path }' );
210+ var id = new AssetId (package.name, relativePath);
211+ var node = _assetGraph.get (id);
212+ // Short circuit for deletes of nodes that aren't in the graph.
213+ if (e.type == ChangeType .REMOVE && node == null ) return ;
214+
215+ updatedInputs[id] = e.type;
216+ scheduleBuild ();
217+ }));
218+ }
203219
204- Future .wait (watchers.map ((w) => w.ready)).then ((_) {
220+ return Future .wait (watchers.map ((w) => w.ready));
221+ }).then ((_) {
205222 // Schedule the first build!
206223 doBuild (true );
207224 });
0 commit comments