Unverified Commit 86613d19 authored by Danny Tuppeny's avatar Danny Tuppeny Committed by GitHub

[flutter_tool] [dap] Forward Flutter progress events to DAP client (#142524)

Builds can be slow and the legacy debug adapter would handle Flutter's `app.progress` events to update the toast notification during builds. This was lost in the new adapters - we should only a single "Launching.." notification for the whole progress.

This change listens to `app.progress` events and forwards those with `finished=false` to the client if the launch progress is still active.

Fixes https://github.com/Dart-Code/Dart-Code/issues/4938

https://github.com/flutter/flutter/assets/1078012/8c60cf08-e034-4a72-b31e-9c61dca388bf
parent 7082ae15
...@@ -420,6 +420,19 @@ class FlutterDebugAdapter extends FlutterBaseDebugAdapter with VmServiceInfoFile ...@@ -420,6 +420,19 @@ class FlutterDebugAdapter extends FlutterBaseDebugAdapter with VmServiceInfoFile
); );
} }
/// Handles any app.progress event from Flutter.
void _handleAppProgress(Map<String, Object?> params) {
// If this is a new progress starting (and we're still launching), update
// the progress notification.
//
// We ignore finished status because we have a limited API - the next
// item will replace it (or the launch progress will be completed by
// _handleAppStarted).
if (params case {'message': final String message, 'finished': false}) {
launchProgress?.update(message: message);
}
}
/// Handles the app.started event from Flutter. /// Handles the app.started event from Flutter.
Future<void> _handleAppStarted() async { Future<void> _handleAppStarted() async {
launchProgress?.end(); launchProgress?.end();
...@@ -481,6 +494,8 @@ class FlutterDebugAdapter extends FlutterBaseDebugAdapter with VmServiceInfoFile ...@@ -481,6 +494,8 @@ class FlutterDebugAdapter extends FlutterBaseDebugAdapter with VmServiceInfoFile
_handleDebugPort(params); _handleDebugPort(params);
case 'app.start': case 'app.start':
_handleAppStart(params); _handleAppStart(params);
case 'app.progress':
_handleAppProgress(params);
case 'app.started': case 'app.started':
_handleAppStarted(); _handleAppStarted();
} }
......
...@@ -210,6 +210,45 @@ void main() { ...@@ -210,6 +210,45 @@ void main() {
expect(adapter.dapToFlutterRequests, isNot(contains('app.restart'))); expect(adapter.dapToFlutterRequests, isNot(contains('app.restart')));
}); });
test('includes build progress updates', () async {
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
fileSystem: MemoryFileSystem.test(style: fsStyle),
platform: platform,
);
final Completer<void> responseCompleter = Completer<void>();
final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments(
cwd: '.',
program: 'foo.dart',
);
// Begin listening for progress events up until `progressEnd` (but don't await yet).
final Future<List<List<Object?>>> progressEventsFuture =
adapter.dapToClientProgressEvents
.takeWhile((Map<String, Object?> message) => message['event'] != 'progressEnd')
.map((Map<String, Object?> message) => <Object?>[message['event'], (message['body']! as Map<String, Object?>)['message']])
.toList();
// Initialize with progress support.
await adapter.initializeRequest(
MockRequest(),
InitializeRequestArguments(adapterID: 'test', supportsProgressReporting: true, ),
(_) {},
);
await adapter.configurationDoneRequest(MockRequest(), null, () {});
await adapter.launchRequest(MockRequest(), args, responseCompleter.complete);
await responseCompleter.future;
// Ensure we got the expected events prior to the progressEnd.
final List<List<Object?>> progressEvents = await progressEventsFuture;
expect(progressEvents, containsAllInOrder(<List<String?>>[
<String?>['progressStart', 'Launching…'],
<String?>['progressUpdate', 'Step 1…'],
<String?>['progressUpdate', 'Step 2…'],
// progressEnd isn't included because we used takeWhile to stop when it arrived above.
]));
});
test('includes Dart Debug extension progress update', () async { test('includes Dart Debug extension progress update', () async {
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter( final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
fileSystem: MemoryFileSystem.test(style: fsStyle), fileSystem: MemoryFileSystem.test(style: fsStyle),
...@@ -242,7 +281,7 @@ void main() { ...@@ -242,7 +281,7 @@ void main() {
await adapter.launchRequest(MockRequest(), args, responseCompleter.complete); await adapter.launchRequest(MockRequest(), args, responseCompleter.complete);
await responseCompleter.future; await responseCompleter.future;
// Ensure we got the expected events prior to the // Ensure we got the expected events prior to the progressEnd.
final List<List<Object?>> progressEvents = await progressEventsFuture; final List<List<Object?>> progressEvents = await progressEventsFuture;
expect(progressEvents, containsAllInOrder(<List<String>>[ expect(progressEvents, containsAllInOrder(<List<String>>[
<String>['progressStart', 'Launching…'], <String>['progressStart', 'Launching…'],
......
...@@ -104,9 +104,22 @@ class MockFlutterDebugAdapter extends FlutterDebugAdapter { ...@@ -104,9 +104,22 @@ class MockFlutterDebugAdapter extends FlutterDebugAdapter {
await preAppStart?.call(this); await preAppStart?.call(this);
void sendLaunchProgress({required bool finished, String? message}) {
assert(finished == (message == null));
simulateStdoutMessage(<String, Object?>{
'event': 'app.progress',
'params': <String, Object?>{
'id': 'launch',
'message': message,
'finished': finished,
}
});
}
// Simulate the app starting by triggering handling of events that Flutter // Simulate the app starting by triggering handling of events that Flutter
// would usually write to stdout. // would usually write to stdout.
if (simulateAppStarted) { if (simulateAppStarted) {
sendLaunchProgress(message: 'Step 1…', finished: false);
simulateStdoutMessage(<String, Object?>{ simulateStdoutMessage(<String, Object?>{
'event': 'app.start', 'event': 'app.start',
'params': <String, Object?>{ 'params': <String, Object?>{
...@@ -116,6 +129,8 @@ class MockFlutterDebugAdapter extends FlutterDebugAdapter { ...@@ -116,6 +129,8 @@ class MockFlutterDebugAdapter extends FlutterDebugAdapter {
'mode': 'debug', 'mode': 'debug',
} }
}); });
sendLaunchProgress(message: 'Step 2…', finished: false);
sendLaunchProgress(finished: true);
simulateStdoutMessage(<String, Object?>{ simulateStdoutMessage(<String, Object?>{
'event': 'app.started', 'event': 'app.started',
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment