diff --git a/pkg/dds/CHANGELOG.md b/pkg/dds/CHANGELOG.md index 13597fe7542..eea03378ea6 100644 --- a/pkg/dds/CHANGELOG.md +++ b/pkg/dds/CHANGELOG.md @@ -1,3 +1,8 @@ +# 5.3.0 + +- Add `--app-name` option to `dart development-service`. This is a short, user + focused name to describe the application being debugged. + # 5.2.0 - [DAP] `Stopped(reason: 'entry')` events will no longer be lost if an isolate has not yet reached the `PauseStart` state when connecting to the VM. diff --git a/pkg/dds/lib/dds.dart b/pkg/dds/lib/dds.dart index 3ad37da4c81..bac6cdf9db2 100644 --- a/pkg/dds/lib/dds.dart +++ b/pkg/dds/lib/dds.dart @@ -44,8 +44,13 @@ abstract class DartDevelopmentService { /// /// If [enablesServicePortFallback] is enabled, DDS will attempt to bind to any /// available port if the specified port is unavailable. + /// + /// [appName] is a short description of the application that is being served + /// by the vm service, and will be sent as the `name` when registering the vm + /// service with the Dart Tooling Daemon. static Future startDartDevelopmentService( Uri remoteVmServiceUri, { + String? appName, Uri? serviceUri, bool enableAuthCodes = true, bool ipv6 = false, @@ -98,6 +103,7 @@ abstract class DartDevelopmentService { logRequests, enableServicePortFallback, uriConverter, + appName, ); await service.startService(); return service; @@ -115,6 +121,10 @@ abstract class DartDevelopmentService { /// Throws a [StateError] if DevTools is already being served by DDS. void setExternalDevToolsUri(Uri uri); + /// The name of the application that is being served by the vm service if + /// provided. + String? get appName; + /// Set to `true` if this instance of [DartDevelopmentService] requires an /// authentication code to connect. bool get authCodesEnabled; diff --git a/pkg/dds/lib/dds_launcher.dart b/pkg/dds/lib/dds_launcher.dart index 9215d065c87..1333ac7cd31 100644 --- a/pkg/dds/lib/dds_launcher.dart +++ b/pkg/dds/lib/dds_launcher.dart @@ -45,9 +45,13 @@ import 'src/dds_impl.dart'; /// If provided, [dartExecutable] is the path to the 'dart' executable that /// should be used to spawn the DDS instance. By default, `Platform.executable` /// is used. +/// +/// If provided, [appName] is a short user focused description of the +/// application, used to help identify it. class DartDevelopmentServiceLauncher { static Future start({ required Uri remoteVmServiceUri, + String? appName, Uri? serviceUri, bool enableAuthCodes = true, bool serveDevTools = false, @@ -72,6 +76,8 @@ class DartDevelopmentServiceLauncher { '--${DartDevelopmentServiceOptions.enableServicePortFallbackFlag}', if (google3WorkspaceRoot != null) '--${DartDevelopmentServiceOptions.google3WorkspaceRootOption}=$google3WorkspaceRoot', + if (appName != null) + '--${DartDevelopmentServiceOptions.appNameOption}=$appName', ]; late String executable; if (dartExecutable == null) { @@ -80,7 +86,8 @@ class DartDevelopmentServiceLauncher { // then invoke it directly as it would avoid the additional hop // of going through the dart CLI process to invoke dds. executable = Platform.executable; - var sdkPath = path.absolute(path.dirname(path.dirname(executable)), 'bin'); + var sdkPath = + path.absolute(path.dirname(path.dirname(executable)), 'bin'); var snapshotsDir = path.join(sdkPath, 'snapshots'); final type = FileSystemEntity.typeSync(snapshotsDir); if (type != FileSystemEntityType.directory && @@ -91,12 +98,12 @@ class DartDevelopmentServiceLauncher { sdkPath = path.absolute(path.dirname(executable)); snapshotsDir = sdkPath; } - final dartAotRuntime = path.absolute( - sdkPath, Platform.isWindows ? 'dartaotruntime.exe' : 'dartaotruntime'); + final dartAotRuntime = path.absolute(sdkPath, + Platform.isWindows ? 'dartaotruntime.exe' : 'dartaotruntime'); final ddsAotSnapshot = path.absolute(snapshotsDir, 'dds_aot.dart.snapshot'); - if (File(dartAotRuntime).existsSync() - && File(ddsAotSnapshot).existsSync()) { + if (File(dartAotRuntime).existsSync() && + File(ddsAotSnapshot).existsSync()) { executable = dartAotRuntime; args = [ddsAotSnapshot, ...args]; } else { @@ -132,6 +139,7 @@ class DartDevelopmentServiceLauncher { uri: ddsUri, devToolsUri: devToolsUri, dtdUri: dtdUri, + appName: appName, ), ); } else if (result @@ -159,10 +167,15 @@ class DartDevelopmentServiceLauncher { required this.uri, required this.devToolsUri, required this.dtdUri, + required this.appName, }) : _ddsInstance = process; final Process _ddsInstance; + /// A short, user focused description of the application that DDS will + /// connect to. + final String? appName; + /// The [Uri] VM service clients can use to communicate with this /// DDS instance via HTTP. final Uri uri; diff --git a/pkg/dds/lib/src/arg_parser.dart b/pkg/dds/lib/src/arg_parser.dart index 116d446ba54..e917588f116 100644 --- a/pkg/dds/lib/src/arg_parser.dart +++ b/pkg/dds/lib/src/arg_parser.dart @@ -17,6 +17,7 @@ abstract class DartDevelopmentServiceOptions { static const cachedUserTagsOption = 'cached-user-tags'; static const devToolsServerAddressOption = 'devtools-server-address'; static const google3WorkspaceRootOption = 'google3-workspace-root'; + static const appNameOption = 'app-name'; static ArgParser createArgParser({ int? usageLineLength, @@ -84,6 +85,11 @@ abstract class DartDevelopmentServiceOptions { help: 'Sets the Google3 workspace root used for google3:// URI ' 'resolution.', hide: !verbose, + ) + ..addOption( + appNameOption, + help: 'A short, user focused description of the application that DDS ' + 'will connect to.', ); if (includeHelp) { argParser.addFlag('help', negatable: false); diff --git a/pkg/dds/lib/src/dds_cli_entrypoint.dart b/pkg/dds/lib/src/dds_cli_entrypoint.dart index e3622f8cf94..198b4808df3 100644 --- a/pkg/dds/lib/src/dds_cli_entrypoint.dart +++ b/pkg/dds/lib/src/dds_cli_entrypoint.dart @@ -141,6 +141,7 @@ ${argParser.usage} : null, enableServicePortFallback: enableServicePortFallback, uriConverter: uriConverter, + appName: argResults[DartDevelopmentServiceOptions.appNameOption], ); final dtdInfo = dds.hostedDartToolingDaemon; stderr.write(json.encode({ @@ -153,6 +154,7 @@ ${argParser.usage} // is no mechanism for exposing URIs. 'uri': dtdInfo.localUri.toString(), }, + 'name': dds.appName, })); } catch (e, st) { writeErrorResponse(e, st); diff --git a/pkg/dds/lib/src/dds_impl.dart b/pkg/dds/lib/src/dds_impl.dart index cdd38bbfc34..59807db49d9 100644 --- a/pkg/dds/lib/src/dds_impl.dart +++ b/pkg/dds/lib/src/dds_impl.dart @@ -65,6 +65,7 @@ class DartDevelopmentServiceImpl implements DartDevelopmentService { this.shouldLogRequests, this._enableServicePortFallback, this.uriConverter, + this.appName, ) { _clientManager = ClientManager(this); _expressionEvaluator = ExpressionEvaluator(this); @@ -281,6 +282,7 @@ class DartDevelopmentServiceImpl implements DartDevelopmentService { await dtdClient.registerVmService( uri: wsUri!.toString(), secret: hostedDtd.secret!, + name: appName, ); // Immediately close this client after registering the VM service. The // VM service will be automatically unregistered from DTD when the VM @@ -562,6 +564,9 @@ class DartDevelopmentServiceImpl implements DartDevelopmentService { bool _initializationComplete = false; bool _shuttingDown = false; + @override + final String? appName; + UriConverter? uriConverter; PackageUriConverter get packageUriConverter => _packageUriConverter; late PackageUriConverter _packageUriConverter; diff --git a/pkg/dds/lib/src/devtools/dtd.dart b/pkg/dds/lib/src/devtools/dtd.dart index aad01af208a..0855417bca8 100644 --- a/pkg/dds/lib/src/devtools/dtd.dart +++ b/pkg/dds/lib/src/devtools/dtd.dart @@ -69,21 +69,15 @@ Future startDtd({ required bool printDtdUri, }) async { final snapshotDir = getDTDSnapshotDir(); - final dtdAotSnapshot = path.absolute( + final dtdAotSnapshot = path.absolute( snapshotDir, 'dart_tooling_daemon_aot.dart.snapshot', ); final completer = Completer(); - void completeForError() => completer.complete(null); + void completeForError([_]) => completer.complete(null); - final exitPort = ReceivePort() - ..listen((_) { - completeForError(); - }); - final errorPort = ReceivePort() - ..listen((_) { - completeForError(); - }); + final exitPort = ReceivePort()..listen(completeForError); + final errorPort = ReceivePort()..listen(completeForError); final receivePort = ReceivePort() ..listen((message) { try { @@ -122,10 +116,10 @@ Future startDtd({ onExit: exitPort.sendPort, onError: errorPort.sendPort, ); - } catch (_, __) { + } catch (_) { // Spawning an isolate using the AOT snapshot of the tooling daemon failed, // try again using the JIT snapshot of the tooling daemon. - final dtdSnapshot = path.absolute( + final dtdSnapshot = path.absolute( snapshotDir, 'dart_tooling_daemon.dart.snapshot', ); @@ -137,7 +131,7 @@ Future startDtd({ onExit: exitPort.sendPort, onError: errorPort.sendPort, ); - } catch (_, __) { + } catch (_) { completeForError(); } } diff --git a/pkg/dds/pubspec.yaml b/pkg/dds/pubspec.yaml index 7e6cb2b7d57..301c96b8c80 100644 --- a/pkg/dds/pubspec.yaml +++ b/pkg/dds/pubspec.yaml @@ -1,5 +1,5 @@ name: dds -version: 5.2.0 +version: 5.3.0 description: >- A library used to spawn the Dart Developer Service, used to communicate with a Dart VM Service instance. diff --git a/pkg/dds/test/dap/mocks.dart b/pkg/dds/test/dap/mocks.dart index 7a4c3a707ab..38d380cc0c5 100644 --- a/pkg/dds/test/dap/mocks.dart +++ b/pkg/dds/test/dap/mocks.dart @@ -270,6 +270,9 @@ class MockDartDevelopmentServiceLauncher implements DartDevelopmentServiceLauncher { MockDartDevelopmentServiceLauncher(); + @override + String? get appName => throw UnimplementedError(); + @override Uri? get devToolsUri => throw UnimplementedError(); diff --git a/pkg/dds/test/launcher_smoke_test.dart b/pkg/dds/test/launcher_smoke_test.dart index 66c612fc0bd..e2222347ad4 100644 --- a/pkg/dds/test/launcher_smoke_test.dart +++ b/pkg/dds/test/launcher_smoke_test.dart @@ -6,6 +6,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:dds/dds_launcher.dart'; +import 'package:dtd/dtd.dart'; import 'package:test/test.dart'; import 'package:vm_service/vm_service_io.dart'; @@ -67,7 +68,7 @@ void main() { } test( - 'External DevTools address is reported correctly', + 'External DevTools address and appName are reported correctly', () async { final fakeDevToolsUri = Uri.parse('http://localhost:12345/my_devtools/'); @@ -75,10 +76,25 @@ void main() { remoteVmServiceUri: remoteVmServiceUri, serveDevTools: true, devToolsServerAddress: fakeDevToolsUri, + appName: 'my-app', ); expect(dds.devToolsUri, fakeDevToolsUri.replace(query: 'uri=${dds.wsUri.toString()}')); + + expect(dds.appName, 'my-app'); + final dtdUri = dds.dtdUri; + expect(dtdUri, isNotNull); + + final dtdClient = await DartToolingDaemon.connect(dtdUri!); + try { + final response = await dtdClient.getVmServices(); + final vmServiceInfo = response.vmServicesInfos + .firstWhere((info) => info.name == 'my-app'); + expect(vmServiceInfo.uri, dds.wsUri.toString()); + } finally { + await dtdClient.close(); + } }, ); diff --git a/utils/dds/BUILD.gn b/utils/dds/BUILD.gn index 48643d00033..cf037837692 100644 --- a/utils/dds/BUILD.gn +++ b/utils/dds/BUILD.gn @@ -10,6 +10,7 @@ group("dds_aot") { public_deps = [ ":dds_aot_product_snapshot", ":dds_aot_snapshot", + "../dtd:dtd_aot_snapshot", ] } @@ -32,7 +33,10 @@ aot_snapshot("dds_aot_product_snapshot") { } group("dds") { - public_deps = [ ":copy_dds_snapshot" ] + public_deps = [ + ":copy_dds_snapshot", + "../dtd", + ] } copy("copy_dds_snapshot") {