mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Send progress notifications to clients during hot reload / hot restart (#112455)
This commit is contained in:
parent
a11bef9688
commit
5655225cd7
@ -140,6 +140,13 @@ class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments
|
|||||||
Future<void> attachImpl() async {
|
Future<void> attachImpl() async {
|
||||||
final FlutterAttachRequestArguments args = this.args as FlutterAttachRequestArguments;
|
final FlutterAttachRequestArguments args = this.args as FlutterAttachRequestArguments;
|
||||||
|
|
||||||
|
final DapProgressReporter progress = startProgressNotification(
|
||||||
|
'launch',
|
||||||
|
'Flutter',
|
||||||
|
message: 'Attaching…',
|
||||||
|
);
|
||||||
|
unawaited(appStartedCompleter.future.then((_) => progress.end()));
|
||||||
|
|
||||||
final String? vmServiceUri = args.vmServiceUri;
|
final String? vmServiceUri = args.vmServiceUri;
|
||||||
final List<String> toolArgs = <String>[
|
final List<String> toolArgs = <String>[
|
||||||
'attach',
|
'attach',
|
||||||
@ -255,6 +262,13 @@ class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments
|
|||||||
Future<void> launchImpl() async {
|
Future<void> launchImpl() async {
|
||||||
final FlutterLaunchRequestArguments args = this.args as FlutterLaunchRequestArguments;
|
final FlutterLaunchRequestArguments args = this.args as FlutterLaunchRequestArguments;
|
||||||
|
|
||||||
|
final DapProgressReporter progress = startProgressNotification(
|
||||||
|
'launch',
|
||||||
|
'Flutter',
|
||||||
|
message: 'Launching…',
|
||||||
|
);
|
||||||
|
unawaited(appStartedCompleter.future.then((_) => progress.end()));
|
||||||
|
|
||||||
final List<String> toolArgs = <String>[
|
final List<String> toolArgs = <String>[
|
||||||
'run',
|
'run',
|
||||||
'--machine',
|
'--machine',
|
||||||
@ -593,6 +607,14 @@ class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments
|
|||||||
bool fullRestart, [
|
bool fullRestart, [
|
||||||
String? reason,
|
String? reason,
|
||||||
]) async {
|
]) async {
|
||||||
|
final String progressId = fullRestart ? 'hotRestart' : 'hotReload';
|
||||||
|
final String progressMessage = fullRestart ? 'Hot restarting…' : 'Hot reloading…';
|
||||||
|
final DapProgressReporter progress = startProgressNotification(
|
||||||
|
progressId,
|
||||||
|
'Flutter',
|
||||||
|
message: progressMessage,
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await sendFlutterRequest('app.restart', <String, Object?>{
|
await sendFlutterRequest('app.restart', <String, Object?>{
|
||||||
'appId': appId,
|
'appId': appId,
|
||||||
@ -605,6 +627,9 @@ class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments
|
|||||||
final String action = fullRestart ? 'Hot Restart' : 'Hot Reload';
|
final String action = fullRestart ? 'Hot Restart' : 'Hot Reload';
|
||||||
sendOutput('console', 'Failed to $action: $error');
|
sendOutput('console', 'Failed to $action: $error');
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
progress.end();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _sendServiceExtensionStateChanged(vm.ExtensionData? extensionData) {
|
void _sendServiceExtensionStateChanged(vm.ExtensionData? extensionData) {
|
||||||
|
@ -27,6 +27,7 @@ class FlutterAttachRequestArguments
|
|||||||
super.evaluateGettersInDebugViews,
|
super.evaluateGettersInDebugViews,
|
||||||
super.evaluateToStringInDebugViews,
|
super.evaluateToStringInDebugViews,
|
||||||
super.sendLogsToClient,
|
super.sendLogsToClient,
|
||||||
|
super.sendCustomProgressEvents,
|
||||||
});
|
});
|
||||||
|
|
||||||
FlutterAttachRequestArguments.fromMap(super.obj)
|
FlutterAttachRequestArguments.fromMap(super.obj)
|
||||||
@ -99,6 +100,7 @@ class FlutterLaunchRequestArguments
|
|||||||
super.evaluateGettersInDebugViews,
|
super.evaluateGettersInDebugViews,
|
||||||
super.evaluateToStringInDebugViews,
|
super.evaluateToStringInDebugViews,
|
||||||
super.sendLogsToClient,
|
super.sendLogsToClient,
|
||||||
|
super.sendCustomProgressEvents,
|
||||||
});
|
});
|
||||||
|
|
||||||
FlutterLaunchRequestArguments.fromMap(super.obj)
|
FlutterLaunchRequestArguments.fromMap(super.obj)
|
||||||
|
@ -218,6 +218,43 @@ void main() {
|
|||||||
await dap.client.terminate();
|
await dap.client.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWithoutContext('sends progress notifications during hot reload', () async {
|
||||||
|
final BasicProject project = BasicProject();
|
||||||
|
await project.setUpIn(tempDir);
|
||||||
|
|
||||||
|
// Launch the app and wait for it to print "topLevelFunction".
|
||||||
|
await Future.wait(<Future<void>>[
|
||||||
|
dap.client.stdoutOutput.firstWhere((String output) => output.startsWith('topLevelFunction')),
|
||||||
|
dap.client.initialize(supportsProgressReporting: true),
|
||||||
|
dap.client.launch(
|
||||||
|
cwd: project.dir.path,
|
||||||
|
noDebug: true,
|
||||||
|
toolArgs: <String>['-d', 'flutter-tester'],
|
||||||
|
),
|
||||||
|
], eagerError: true);
|
||||||
|
|
||||||
|
// Capture progress events during a reload.
|
||||||
|
final Future<List<Event>> progressEventsFuture = dap.client.progressEvents().toList();
|
||||||
|
await dap.client.hotReload();
|
||||||
|
await dap.client.terminate();
|
||||||
|
|
||||||
|
// Verify the progress events.
|
||||||
|
final List<Event> progressEvents = await progressEventsFuture;
|
||||||
|
expect(progressEvents, hasLength(2));
|
||||||
|
|
||||||
|
final List<String> eventKinds = progressEvents.map((Event event) => event.event).toList();
|
||||||
|
expect(eventKinds, <String>['progressStart', 'progressEnd']);
|
||||||
|
|
||||||
|
final List<Map<String, Object?>> eventBodies = progressEvents.map((Event event) => event.body).cast<Map<String, Object?>>().toList();
|
||||||
|
final ProgressStartEventBody start = ProgressStartEventBody.fromMap(eventBodies[0]);
|
||||||
|
final ProgressEndEventBody end = ProgressEndEventBody.fromMap(eventBodies[1]);
|
||||||
|
expect(start.progressId, isNotNull);
|
||||||
|
expect(start.title, 'Flutter');
|
||||||
|
expect(start.message, 'Hot reloading…');
|
||||||
|
expect(end.progressId, start.progressId);
|
||||||
|
expect(end.message, isNull);
|
||||||
|
});
|
||||||
|
|
||||||
testWithoutContext('can hot restart', () async {
|
testWithoutContext('can hot restart', () async {
|
||||||
final BasicProject project = BasicProject();
|
final BasicProject project = BasicProject();
|
||||||
await project.setUpIn(tempDir);
|
await project.setUpIn(tempDir);
|
||||||
@ -255,6 +292,43 @@ void main() {
|
|||||||
await dap.client.terminate();
|
await dap.client.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWithoutContext('sends progress notifications during hot restart', () async {
|
||||||
|
final BasicProject project = BasicProject();
|
||||||
|
await project.setUpIn(tempDir);
|
||||||
|
|
||||||
|
// Launch the app and wait for it to print "topLevelFunction".
|
||||||
|
await Future.wait(<Future<void>>[
|
||||||
|
dap.client.stdoutOutput.firstWhere((String output) => output.startsWith('topLevelFunction')),
|
||||||
|
dap.client.initialize(supportsProgressReporting: true),
|
||||||
|
dap.client.launch(
|
||||||
|
cwd: project.dir.path,
|
||||||
|
noDebug: true,
|
||||||
|
toolArgs: <String>['-d', 'flutter-tester'],
|
||||||
|
),
|
||||||
|
], eagerError: true);
|
||||||
|
|
||||||
|
// Capture progress events during a restart.
|
||||||
|
final Future<List<Event>> progressEventsFuture = dap.client.progressEvents().toList();
|
||||||
|
await dap.client.hotRestart();
|
||||||
|
await dap.client.terminate();
|
||||||
|
|
||||||
|
// Verify the progress events.
|
||||||
|
final List<Event> progressEvents = await progressEventsFuture;
|
||||||
|
expect(progressEvents, hasLength(2));
|
||||||
|
|
||||||
|
final List<String> eventKinds = progressEvents.map((Event event) => event.event).toList();
|
||||||
|
expect(eventKinds, <String>['progressStart', 'progressEnd']);
|
||||||
|
|
||||||
|
final List<Map<String, Object?>> eventBodies = progressEvents.map((Event event) => event.body).cast<Map<String, Object?>>().toList();
|
||||||
|
final ProgressStartEventBody start = ProgressStartEventBody.fromMap(eventBodies[0]);
|
||||||
|
final ProgressEndEventBody end = ProgressEndEventBody.fromMap(eventBodies[1]);
|
||||||
|
expect(start.progressId, isNotNull);
|
||||||
|
expect(start.title, 'Flutter');
|
||||||
|
expect(start.message, 'Hot restarting…');
|
||||||
|
expect(end.progressId, start.progressId);
|
||||||
|
expect(end.message, isNull);
|
||||||
|
});
|
||||||
|
|
||||||
testWithoutContext('can hot restart when exceptions occur on outgoing isolates', () async {
|
testWithoutContext('can hot restart when exceptions occur on outgoing isolates', () async {
|
||||||
final BasicProjectThatThrows project = BasicProjectThatThrows();
|
final BasicProjectThatThrows project = BasicProjectThatThrows();
|
||||||
await project.setUpIn(tempDir);
|
await project.setUpIn(tempDir);
|
||||||
|
@ -83,6 +83,12 @@ class DapTestClient {
|
|||||||
return _eventController.stream.where((Event e) => e.event == event);
|
return _eventController.stream.where((Event e) => e.event == event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a stream of progress events.
|
||||||
|
Stream<Event> progressEvents() {
|
||||||
|
const Set<String> progressEvents = <String>{'progressStart', 'progressUpdate', 'progressEnd'};
|
||||||
|
return _eventController.stream.where((Event e) => progressEvents.contains(e.event));
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a stream of custom 'dart.serviceExtensionAdded' events.
|
/// Returns a stream of custom 'dart.serviceExtensionAdded' events.
|
||||||
Stream<Map<String, Object?>> get serviceExtensionAddedEvents =>
|
Stream<Map<String, Object?>> get serviceExtensionAddedEvents =>
|
||||||
events('dart.serviceExtensionAdded')
|
events('dart.serviceExtensionAdded')
|
||||||
@ -116,12 +122,14 @@ class DapTestClient {
|
|||||||
Future<Response> initialize({
|
Future<Response> initialize({
|
||||||
String exceptionPauseMode = 'None',
|
String exceptionPauseMode = 'None',
|
||||||
bool? supportsRunInTerminalRequest,
|
bool? supportsRunInTerminalRequest,
|
||||||
|
bool? supportsProgressReporting,
|
||||||
}) async {
|
}) async {
|
||||||
final List<ProtocolMessage> responses = await Future.wait(<Future<ProtocolMessage>>[
|
final List<ProtocolMessage> responses = await Future.wait(<Future<ProtocolMessage>>[
|
||||||
event('initialized'),
|
event('initialized'),
|
||||||
sendRequest(InitializeRequestArguments(
|
sendRequest(InitializeRequestArguments(
|
||||||
adapterID: 'test',
|
adapterID: 'test',
|
||||||
supportsRunInTerminalRequest: supportsRunInTerminalRequest,
|
supportsRunInTerminalRequest: supportsRunInTerminalRequest,
|
||||||
|
supportsProgressReporting: supportsProgressReporting,
|
||||||
)),
|
)),
|
||||||
sendRequest(
|
sendRequest(
|
||||||
SetExceptionBreakpointsArguments(
|
SetExceptionBreakpointsArguments(
|
||||||
|
Loading…
Reference in New Issue
Block a user