Unverified Commit dc4541fa authored by Danny Tuppeny's avatar Danny Tuppeny Committed by GitHub

[flutter_tools] Add support for vmServiceFileInfo when attaching (#128503)

When building the new SDK DAPs, this functionality was missed from the Flutter adapter (but added to the Dart CLI adapter).

As well as passing a VM Service URI directly, we support passing a file that can be polled for it.

This uses the same mechanism we use to obtain the VM Service URI from a Dart debug session (we run `dart --write-service-info=foo.json my_file.dart` and then poll that file which the VM will write) and is useful for users that have their own mechanism for launching an app (for example using custom Flutter embedders - see https://github.com/Dart-Code/Dart-Code/issues/3353) to provide a VM Service URI once the app is up and running.

Fixes https://github.com/Dart-Code/Dart-Code/issues/4577.
parent 7214cb28
......@@ -40,7 +40,10 @@ Arguments specific to `launchRequest` are:
Arguments specific to `attachRequest` are:
- `String? vmServiceUri` - the VM Service URI to attach to (if not supplied, Flutter will try to discover it from the device)
- `String? vmServiceInfoFile` - the file to read the VM Service info from \*
- `String? vmServiceUri` - the VM Service URI to attach to \*
\* Only one of `vmServiceInfoFile` or `vmServiceUri` may be supplied. If neither are supplied, Flutter will try to discover it from the device.
## Custom Requests
......
......@@ -11,11 +11,12 @@ import 'package:vm_service/vm_service.dart' as vm;
import '../base/io.dart';
import '../cache.dart';
import '../convert.dart';
import '../globals.dart' as globals show fs;
import 'flutter_adapter_args.dart';
import 'flutter_base_adapter.dart';
/// A DAP Debug Adapter for running and debugging Flutter applications.
class FlutterDebugAdapter extends FlutterBaseDebugAdapter {
class FlutterDebugAdapter extends FlutterBaseDebugAdapter with VmServiceInfoFileUtils {
FlutterDebugAdapter(
super.channel, {
required super.fileSystem,
......@@ -120,6 +121,16 @@ class FlutterDebugAdapter extends FlutterBaseDebugAdapter {
@override
Future<void> attachImpl() async {
final FlutterAttachRequestArguments args = this.args as FlutterAttachRequestArguments;
String? vmServiceUri = args.vmServiceUri;
final String? vmServiceInfoFile = args.vmServiceInfoFile;
if (vmServiceUri != null && vmServiceInfoFile != null) {
sendConsoleOutput(
'To attach, provide only one (or neither) of vmServiceUri/vmServiceInfoFile',
);
handleSessionTerminate();
return;
}
launchProgress = startProgressNotification(
'launch',
......@@ -127,7 +138,11 @@ class FlutterDebugAdapter extends FlutterBaseDebugAdapter {
message: 'Attaching…',
);
final String? vmServiceUri = args.vmServiceUri;
if (vmServiceUri == null && vmServiceInfoFile != null) {
final Uri uriFromFile = await waitForVmServiceInfoFile(logger, globals.fs.file(vmServiceInfoFile));
vmServiceUri = uriFromFile.toString();
}
final List<String> toolArgs = <String>[
'attach',
'--machine',
......
......@@ -17,6 +17,7 @@ class FlutterAttachRequestArguments
this.customTool,
this.customToolReplacesArgs,
this.vmServiceUri,
this.vmServiceInfoFile,
this.program,
super.restart,
super.name,
......@@ -36,6 +37,7 @@ class FlutterAttachRequestArguments
customTool = obj['customTool'] as String?,
customToolReplacesArgs = obj['customToolReplacesArgs'] as int?,
vmServiceUri = obj['vmServiceUri'] as String?,
vmServiceInfoFile = obj['vmServiceInfoFile'] as String?,
program = obj['program'] as String?,
super.fromMap();
......@@ -64,8 +66,15 @@ class FlutterAttachRequestArguments
final int? customToolReplacesArgs;
/// The VM Service URI of the running Flutter app to connect to.
///
/// Only one of this or [vmServiceInfoFile] (or neither) can be supplied.
final String? vmServiceUri;
/// The VM Service info file to extract the VM Service URI from to attach to.
///
/// Only one of this or [vmServiceUri] (or neither) can be supplied.
final String? vmServiceInfoFile;
/// The program/Flutter app to be run.
final String? program;
......
......@@ -11,7 +11,7 @@ import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/debug_adapters/flutter_adapter.dart';
import 'package:flutter_tools/src/debug_adapters/flutter_adapter_args.dart';
import 'package:flutter_tools/src/globals.dart' as globals show platform;
import 'package:flutter_tools/src/globals.dart' as globals show fs, platform;
import 'package:test/fake.dart';
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';
......@@ -299,6 +299,107 @@ void main() {
]));
});
test('runs "flutter attach" with --debug-uri if vmServiceUri is passed', () async {
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
fileSystem: MemoryFileSystem.test(style: fsStyle),
platform: platform,
);
final Completer<void> responseCompleter = Completer<void>();
final FlutterAttachRequestArguments args =
FlutterAttachRequestArguments(
cwd: '/project',
program: 'program/main.dart',
vmServiceUri: 'ws://1.2.3.4/ws'
);
await adapter.configurationDoneRequest(MockRequest(), null, () {});
await adapter.attachRequest(
MockRequest(), args, responseCompleter.complete);
await responseCompleter.future;
expect(
adapter.processArgs,
containsAllInOrder(<String>[
'attach',
'--machine',
'--debug-uri',
'ws://1.2.3.4/ws',
'--target',
'program/main.dart',
]));
});
test('runs "flutter attach" with --debug-uri if vmServiceInfoFile exists', () async {
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
fileSystem: MemoryFileSystem.test(style: fsStyle),
platform: platform,
);
final Completer<void> responseCompleter = Completer<void>();
final File serviceInfoFile = globals.fs.systemTempDirectory.createTempSync('dap_flutter_attach_vmServiceInfoFile').childFile('vmServiceInfo.json');
final FlutterAttachRequestArguments args =
FlutterAttachRequestArguments(
cwd: '/project',
program: 'program/main.dart',
vmServiceInfoFile: serviceInfoFile.path,
);
// Write the service info file before trying to attach:
serviceInfoFile.writeAsStringSync('{ "uri": "ws://1.2.3.4/ws" }');
await adapter.configurationDoneRequest(MockRequest(), null, () {});
await adapter.attachRequest(MockRequest(), args, responseCompleter.complete);
await responseCompleter.future;
expect(
adapter.processArgs,
containsAllInOrder(<String>[
'attach',
'--machine',
'--debug-uri',
'ws://1.2.3.4/ws',
'--target',
'program/main.dart',
]));
});
test('runs "flutter attach" with --debug-uri if vmServiceInfoFile is created later', () async {
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
fileSystem: MemoryFileSystem.test(style: fsStyle),
platform: platform,
);
final Completer<void> responseCompleter = Completer<void>();
final File serviceInfoFile = globals.fs.systemTempDirectory.createTempSync('dap_flutter_attach_vmServiceInfoFile').childFile('vmServiceInfo.json');
final FlutterAttachRequestArguments args =
FlutterAttachRequestArguments(
cwd: '/project',
program: 'program/main.dart',
vmServiceInfoFile: serviceInfoFile.path,
);
await adapter.configurationDoneRequest(MockRequest(), null, () {});
final Future<void> attachResponseFuture = adapter.attachRequest(MockRequest(), args, responseCompleter.complete);
// Write the service info file a little later to ensure we detect it:
await pumpEventQueue(times:5000);
serviceInfoFile.writeAsStringSync('{ "uri": "ws://1.2.3.4/ws" }');
await attachResponseFuture;
await responseCompleter.future;
expect(
adapter.processArgs,
containsAllInOrder(<String>[
'attach',
'--machine',
'--debug-uri',
'ws://1.2.3.4/ws',
'--target',
'program/main.dart',
]));
});
test('does not record the VMs PID for terminating', () async {
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
fileSystem: MemoryFileSystem.test(style: fsStyle),
......
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