diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart index 0c07e559986..896ed748cab 100644 --- a/packages/flutter_tools/lib/src/run_hot.dart +++ b/packages/flutter_tools/lib/src/run_hot.dart @@ -27,6 +27,11 @@ class HotRunnerConfig { bool computeDartDependencies = true; /// Should the hot runner assume that the minimal Dart dependencies do not change? bool stableDartDependencies = false; + /// A hook for implementations to perform any necessary initialization prior + /// to a hot restart. Should return true if the hot restart should continue. + Future setupHotRestart() async { + return true; + } } HotRunnerConfig get hotRunnerConfig => context[HotRunnerConfig]; @@ -477,6 +482,10 @@ class HotRunner extends ResidentRunner { ); try { final Stopwatch timer = new Stopwatch()..start(); + if (!(await hotRunnerConfig.setupHotRestart())) { + status.cancel(); + return new OperationResult(1, 'setupHotRestart failed'); + } await _restartFromSources(); timer.stop(); status.cancel(); diff --git a/packages/flutter_tools/test/hot_test.dart b/packages/flutter_tools/test/hot_test.dart index 73f7fd816d2..760c460ed59 100644 --- a/packages/flutter_tools/test/hot_test.dart +++ b/packages/flutter_tools/test/hot_test.dart @@ -2,7 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:async'; + +import 'package:flutter_tools/src/device.dart'; +import 'package:flutter_tools/src/resident_runner.dart'; import 'package:flutter_tools/src/run_hot.dart'; +import 'package:meta/meta.dart'; +import 'package:mockito/mockito.dart'; import 'package:test/test.dart'; import 'src/context.dart'; @@ -83,4 +89,49 @@ void main() { }), true); }); }); + + group('hotRestart', () { + final List devices = []; + + setUp(() { + devices.add(new FlutterDevice(new MockDevice(), + previewDart2: false, trackWidgetCreation: false)); + }); + + testUsingContext('no setup', () async { + expect((await new HotRunner(devices).restart(fullRestart: true)).isOk, + true); + }); + + testUsingContext('setup function succeeds', () async { + expect((await new HotRunner(devices).restart(fullRestart: true)).isOk, + true); + }, overrides: { + HotRunnerConfig: () => new TestHotRunnerConfig(successfulSetup: true), + }); + + testUsingContext('setup function fails', () async { + expect((await new HotRunner(devices).restart(fullRestart: true)).isOk, + false); + }, overrides: { + HotRunnerConfig: () => new TestHotRunnerConfig(successfulSetup: false), + }); + }); +} + +class MockDevice extends Mock implements Device { + MockDevice() { + when(isSupported()).thenReturn(true); + } +} + +class TestHotRunnerConfig extends HotRunnerConfig { + bool successfulSetup; + + TestHotRunnerConfig({@required this.successfulSetup}); + + @override + Future setupHotRestart() async { + return successfulSetup; + } }