@@ -38,9 +38,9 @@ String getDevFSLoaderScript() {
38
38
'loader_app.dart' ));
39
39
}
40
40
41
- class StartupDependencySetBuilder {
42
- StartupDependencySetBuilder (this .mainScriptPath,
43
- this .projectRootPath);
41
+ class DartDependencySetBuilder {
42
+ DartDependencySetBuilder (this .mainScriptPath,
43
+ this .projectRootPath);
44
44
45
45
final String mainScriptPath;
46
46
final String projectRootPath;
@@ -56,12 +56,7 @@ class StartupDependencySetBuilder {
56
56
mainScriptPath
57
57
];
58
58
59
- String output;
60
- try {
61
- output = runCheckedSync (args, hideStdout: true );
62
- } catch (e) {
63
- return null ;
64
- }
59
+ String output = runSyncAndThrowStdErrOnError (args);
65
60
66
61
final List <String > lines = LineSplitter .split (output).toList ();
67
62
final Set <String > minimalDependencies = new Set <String >();
@@ -135,7 +130,7 @@ class HotRunner extends ResidentRunner {
135
130
ApplicationPackage _package;
136
131
String _mainPath;
137
132
String _projectRootPath;
138
- Set <String > _startupDependencies ;
133
+ Set <String > _dartDependencies ;
139
134
int _observatoryPort;
140
135
final AssetBundle bundle = new AssetBundle ();
141
136
final bool benchmarkMode;
@@ -159,6 +154,23 @@ class HotRunner extends ResidentRunner {
159
154
});
160
155
}
161
156
157
+ bool _refreshDartDependencies () {
158
+ if (_dartDependencies != null ) {
159
+ // Already computed.
160
+ return true ;
161
+ }
162
+ DartDependencySetBuilder dartDependencySetBuilder =
163
+ new DartDependencySetBuilder (_mainPath, _projectRootPath);
164
+ try {
165
+ _dartDependencies = dartDependencySetBuilder.build ();
166
+ } catch (error) {
167
+ printStatus ('Error detected in application source code:' , emphasis: true );
168
+ printError (error);
169
+ return false ;
170
+ }
171
+ return true ;
172
+ }
173
+
162
174
Future <int > _run ({
163
175
Completer <DebugConnectionInfo > connectionInfoCompleter,
164
176
String route,
@@ -184,6 +196,12 @@ class HotRunner extends ResidentRunner {
184
196
return 1 ;
185
197
}
186
198
199
+ // Determine the Dart dependencies eagerly.
200
+ if (! _refreshDartDependencies ()) {
201
+ // Some kind of source level error or missing file in the Dart code.
202
+ return 1 ;
203
+ }
204
+
187
205
// TODO(devoncarew): We shouldn't have to do type checks here.
188
206
if (shouldBuild && device is AndroidDevice ) {
189
207
printTrace ('Running build command.' );
@@ -231,15 +249,6 @@ class HotRunner extends ResidentRunner {
231
249
route: route
232
250
);
233
251
234
- // In parallel, compute the minimal dependency set.
235
- StartupDependencySetBuilder startupDependencySetBuilder =
236
- new StartupDependencySetBuilder (_mainPath, _projectRootPath);
237
- _startupDependencies = startupDependencySetBuilder.build ();
238
- if (_startupDependencies == null ) {
239
- printError ('Error determining the set of Dart sources necessary to start '
240
- 'the application. Initial file upload may take a long time.' );
241
- }
242
-
243
252
LaunchResult result = await futureResult;
244
253
245
254
if (! result.started) {
@@ -295,10 +304,6 @@ class HotRunner extends ResidentRunner {
295
304
296
305
registerSignalHandlers ();
297
306
298
- printTrace ('Finishing file synchronization' );
299
- // Finish the file sync now.
300
- await _updateDevFS ();
301
-
302
307
if (benchmarkMode) {
303
308
// We are running in benchmark mode.
304
309
printStatus ('Running in benchmark mode.' );
@@ -325,13 +330,19 @@ class HotRunner extends ResidentRunner {
325
330
Future <Null > handleTerminalCommand (String code) async {
326
331
final String lower = code.toLowerCase ();
327
332
if ((lower == 'r' ) || (code == AnsiTerminal .KEY_F5 )) {
333
+ OperationResult result = OperationResult .ok;
328
334
// F5, restart
329
335
if ((code == 'r' ) || (code == AnsiTerminal .KEY_F5 )) {
330
336
// lower-case 'r'
331
- await _reloadSources ();
337
+ result = await _reloadSources ();
332
338
} else {
333
339
// upper-case 'R'.
334
- await _restartFromSources ();
340
+ result = await _restartFromSources ();
341
+ }
342
+ if (! result.isOk) {
343
+ // TODO(johnmccutchan): Attempt to determine the number of errors that
344
+ // occurred and tighten this message.
345
+ printStatus ('Try again after fixing the above error(s).' , emphasis: true );
335
346
}
336
347
}
337
348
}
@@ -362,6 +373,10 @@ class HotRunner extends ResidentRunner {
362
373
}
363
374
364
375
Future <bool > _updateDevFS ({ DevFSProgressReporter progressReporter }) async {
376
+ if (! _refreshDartDependencies ()) {
377
+ // Did not update DevFS because of a Dart source error.
378
+ return false ;
379
+ }
365
380
Status devFSStatus = logger.startProgress ('Syncing files to device...' );
366
381
final bool rebuildBundle = bundle.needsBuild ();
367
382
if (rebuildBundle) {
@@ -371,10 +386,10 @@ class HotRunner extends ResidentRunner {
371
386
await _devFS.update (progressReporter: progressReporter,
372
387
bundle: bundle,
373
388
bundleDirty: rebuildBundle,
374
- fileFilter: _startupDependencies );
389
+ fileFilter: _dartDependencies );
375
390
devFSStatus.stop (showElapsedTime: true );
376
- // Clear the minimal set after the first sync.
377
- _startupDependencies = null ;
391
+ // Clear the set after the sync.
392
+ _dartDependencies = null ;
378
393
printTrace ('Synced ${getSizeAsMB (_devFS .bytes )}.' );
379
394
return true ;
380
395
}
@@ -422,10 +437,12 @@ class HotRunner extends ResidentRunner {
422
437
deviceAssetsDirectoryPath);
423
438
}
424
439
425
- Future <Null > _restartFromSources () async {
440
+ Future <OperationResult > _restartFromSources () async {
426
441
FirstFrameTimer firstFrameTimer = new FirstFrameTimer (vmService);
427
442
firstFrameTimer.start ();
428
- await _updateDevFS ();
443
+ bool updatedDevFS = await _updateDevFS ();
444
+ if (! updatedDevFS)
445
+ return new OperationResult (1 , 'Dart Source Error' );
429
446
await _launchFromDevFS (_package, _mainPath);
430
447
bool waitForFrame =
431
448
await currentView.uiIsolate.flutterFrameworkPresent ();
@@ -446,6 +463,7 @@ class HotRunner extends ResidentRunner {
446
463
flutterUsage.sendTiming ('hot' , 'restart' , firstFrameTimer.elapsed);
447
464
}
448
465
flutterUsage.sendEvent ('hot' , 'restart' );
466
+ return OperationResult .ok;
449
467
}
450
468
451
469
/// Returns [true] if the reload was successful.
@@ -465,8 +483,7 @@ class HotRunner extends ResidentRunner {
465
483
@override
466
484
Future <OperationResult > restart ({ bool fullRestart: false , bool pauseAfterRestart: false }) async {
467
485
if (fullRestart) {
468
- await _restartFromSources ();
469
- return OperationResult .ok;
486
+ return _restartFromSources ();
470
487
} else {
471
488
return _reloadSources (pause: pauseAfterRestart);
472
489
}
@@ -477,8 +494,11 @@ class HotRunner extends ResidentRunner {
477
494
throw 'Application isolate not found' ;
478
495
FirstFrameTimer firstFrameTimer = new FirstFrameTimer (vmService);
479
496
firstFrameTimer.start ();
480
- if (_devFS != null )
481
- await _updateDevFS ();
497
+ if (_devFS != null ) {
498
+ bool updatedDevFS = await _updateDevFS ();
499
+ if (! updatedDevFS)
500
+ return new OperationResult (1 , 'Dart Source Error' );
501
+ }
482
502
Status reloadStatus = logger.startProgress ('Performing hot reload...' );
483
503
try {
484
504
Map <String , dynamic > reloadReport =
0 commit comments