Skip to content

Commit 31f4f2b

Browse files
Add a --print-dtd flag to print the DTD address served by DevTools server (#144272)
1 parent dbdcead commit 31f4f2b

12 files changed

+324
-189
lines changed

packages/flutter_tools/lib/executable.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// found in the LICENSE file.
44

55
import 'runner.dart' as runner;
6-
import 'src/artifacts.dart';
76
import 'src/base/context.dart';
87
import 'src/base/io.dart';
98
import 'src/base/logger.dart';
@@ -110,7 +109,7 @@ Future<void> main(List<String> args) async {
110109
// devtools source code.
111110
DevtoolsLauncher: () => DevtoolsServerLauncher(
112111
processManager: globals.processManager,
113-
dartExecutable: globals.artifacts!.getArtifactPath(Artifact.engineDartBinary),
112+
artifacts: globals.artifacts!,
114113
logger: globals.logger,
115114
botDetector: globals.botDetector,
116115
),

packages/flutter_tools/lib/src/context_runner.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ Future<T> runInContext<T>(
218218
),
219219
DevtoolsLauncher: () => DevtoolsServerLauncher(
220220
processManager: globals.processManager,
221-
dartExecutable: globals.artifacts!.getArtifactPath(Artifact.engineDartBinary),
221+
artifacts: globals.artifacts!,
222222
logger: globals.logger,
223223
botDetector: globals.botDetector,
224224
),

packages/flutter_tools/lib/src/devtools_launcher.dart

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,35 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
6-
75
import 'dart:async';
86

97
import 'package:meta/meta.dart';
108
import 'package:process/process.dart';
119

10+
import 'artifacts.dart';
1211
import 'base/bot_detector.dart';
1312
import 'base/common.dart';
1413
import 'base/io.dart' as io;
1514
import 'base/logger.dart';
1615
import 'convert.dart';
1716
import 'resident_runner.dart';
1817

19-
/// An implementation of the devtools launcher that uses `pub global activate` to
20-
/// start a server instance.
18+
/// An implementation of the devtools launcher that uses `dart devtools` to
19+
/// start a DevTools server instance.
2120
class DevtoolsServerLauncher extends DevtoolsLauncher {
2221
DevtoolsServerLauncher({
2322
required ProcessManager processManager,
24-
required String dartExecutable,
2523
required Logger logger,
2624
required BotDetector botDetector,
25+
required Artifacts artifacts,
2726
}) : _processManager = processManager,
28-
_dartExecutable = dartExecutable,
2927
_logger = logger,
30-
_botDetector = botDetector;
28+
_botDetector = botDetector,
29+
_artifacts = artifacts;
3130

3231
final ProcessManager _processManager;
33-
final String _dartExecutable;
32+
final Artifacts _artifacts;
33+
late final String _dartExecutable = _artifacts.getArtifactPath(Artifact.engineDartBinary);
3434
final Logger _logger;
3535
final BotDetector _botDetector;
3636
final Completer<void> _processStartCompleter = Completer<void>();
@@ -42,6 +42,8 @@ class DevtoolsServerLauncher extends DevtoolsLauncher {
4242

4343
static final RegExp _serveDevToolsPattern =
4444
RegExp(r'Serving DevTools at ((http|//)[a-zA-Z0-9:/=_\-\.\[\]]+?)\.?$');
45+
static final RegExp _serveDtdPattern =
46+
RegExp(r'Serving the Dart Tooling Daemon at (ws:\/\/[a-zA-Z0-9:/=_\-\.\[\]]+?)\.?$');
4547

4648
@override
4749
Future<void> get processStart => _processStartCompleter.future;
@@ -55,21 +57,28 @@ class DevtoolsServerLauncher extends DevtoolsLauncher {
5557
_dartExecutable,
5658
'devtools',
5759
'--no-launch-browser',
60+
if (printDtdUri) '--print-dtd',
5861
if (vmServiceUri != null) '--vm-uri=$vmServiceUri',
5962
...?additionalArguments,
6063
]);
6164
_processStartCompleter.complete();
62-
final Completer<Uri> completer = Completer<Uri>();
65+
66+
final Completer<Uri> devToolsCompleter = Completer<Uri>();
6367
_devToolsProcess!.stdout
6468
.transform(utf8.decoder)
6569
.transform(const LineSplitter())
6670
.listen((String line) {
67-
final Match? match = _serveDevToolsPattern.firstMatch(line);
68-
if (match != null) {
69-
final String url = match[1]!;
70-
completer.complete(Uri.parse(url));
71-
}
72-
});
71+
final Match? dtdMatch = _serveDtdPattern.firstMatch(line);
72+
if (dtdMatch != null) {
73+
final String uri = dtdMatch[1]!;
74+
dtdUri = Uri.parse(uri);
75+
}
76+
final Match? devToolsMatch = _serveDevToolsPattern.firstMatch(line);
77+
if (devToolsMatch != null) {
78+
final String url = devToolsMatch[1]!;
79+
devToolsCompleter.complete(Uri.parse(url));
80+
}
81+
});
7382
_devToolsProcess!.stderr
7483
.transform(utf8.decoder)
7584
.transform(const LineSplitter())
@@ -84,7 +93,11 @@ class DevtoolsServerLauncher extends DevtoolsLauncher {
8493
}
8594
);
8695

87-
devToolsUrl = await completer.future;
96+
// We do not need to wait for a [Completer] holding the DTD URI because
97+
// the DTD URI will be output to stdout before the DevTools URI. Awaiting
98+
// a [Completer] for the DevTools URI ensures both values will be
99+
// populated before returning.
100+
devToolsUrl = await devToolsCompleter.future;
88101
} on Exception catch (e, st) {
89102
_logger.printError('Failed to launch DevTools: $e', stackTrace: st);
90103
}

packages/flutter_tools/lib/src/resident_devtools_handler.dart

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,19 @@ abstract class ResidentDevtoolsHandler {
2424
/// The current devtools server, or null if one is not running.
2525
DevToolsServerAddress? get activeDevToolsServer;
2626

27+
/// The Dart Tooling Daemon (DTD) URI for the DTD instance being hosted by
28+
/// DevTools server.
29+
///
30+
/// This will be null if the DevTools server is not served through Flutter
31+
/// tools (e.g. if it is served from an IDE).
32+
Uri? get dtdUri;
33+
34+
/// Whether to print the Dart Tooling Daemon URI.
35+
///
36+
/// This will always return false when there is not a DTD instance being
37+
/// served from the DevTools server.
38+
bool get printDtdUri;
39+
2740
/// Whether it's ok to announce the [activeDevToolsServer].
2841
///
2942
/// This should only return true once all the devices have been notified
@@ -63,6 +76,12 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler {
6376
return _devToolsLauncher?.activeDevToolsServer;
6477
}
6578

79+
@override
80+
Uri? get dtdUri => _devToolsLauncher?.dtdUri;
81+
82+
@override
83+
bool get printDtdUri => _devToolsLauncher?.printDtdUri ?? false;
84+
6685
@override
6786
bool get readyToAnnounce => _readyToAnnounce;
6887
bool _readyToAnnounce = false;
@@ -337,6 +356,12 @@ class NoOpDevtoolsHandler implements ResidentDevtoolsHandler {
337356
wasShutdown = true;
338357
return;
339358
}
359+
360+
@override
361+
Uri? get dtdUri => null;
362+
363+
@override
364+
bool get printDtdUri => false;
340365
}
341366

342367
/// Convert a [URI] with query parameters into a display format instead

packages/flutter_tools/lib/src/resident_runner.dart

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,6 +1526,12 @@ abstract class ResidentRunner extends ResidentHandlers {
15261526
);
15271527
}
15281528
if (includeDevtools) {
1529+
if (_residentDevtoolsHandler!.printDtdUri) {
1530+
final Uri? dtdUri = residentDevtoolsHandler!.dtdUri;
1531+
if (dtdUri != null) {
1532+
globals.printStatus('The Dart Tooling Daemon is available at: $dtdUri\n');
1533+
}
1534+
}
15291535
final Uri? uri = devToolsServerAddress!.uri?.replace(
15301536
queryParameters: <String, dynamic>{'uri': '${device.vmService!.httpAddress}'},
15311537
);
@@ -1945,6 +1951,26 @@ abstract class DevtoolsLauncher {
19451951
}
19461952
}
19471953

1954+
/// The Dart Tooling Daemon (DTD) URI for the DTD instance being hosted by
1955+
/// DevTools server.
1956+
///
1957+
/// This will be null if the DevTools server is not served through Flutter
1958+
/// tools (e.g. if it is served from an IDE).
1959+
Uri? get dtdUri => _dtdUri;
1960+
Uri? _dtdUri;
1961+
@protected
1962+
set dtdUri(Uri? value) => _dtdUri = value;
1963+
1964+
/// Whether to print the Dart Tooling Daemon URI.
1965+
///
1966+
/// This will always return false when there is not a DTD instance being
1967+
/// served from the DevTools server.
1968+
bool get printDtdUri => _printDtdUri ?? false;
1969+
bool? _printDtdUri;
1970+
set printDtdUri(bool value) {
1971+
_printDtdUri = value;
1972+
}
1973+
19481974
/// The URL of the current DevTools server.
19491975
///
19501976
/// Returns null if [ready] is not complete.

packages/flutter_tools/lib/src/runner/flutter_command_runner.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import '../base/utils.dart';
1717
import '../cache.dart';
1818
import '../convert.dart';
1919
import '../globals.dart' as globals;
20+
import '../resident_runner.dart';
2021
import '../tester/flutter_tester.dart';
2122
import '../version.dart';
2223
import '../web/web_device.dart';
@@ -35,6 +36,7 @@ abstract final class FlutterGlobalOptions {
3536
static const String kMachineFlag = 'machine';
3637
static const String kPackagesOption = 'packages';
3738
static const String kPrefixedErrorsFlag = 'prefixed-errors';
39+
static const String kPrintDtd = 'print-dtd';
3840
static const String kQuietFlag = 'quiet';
3941
static const String kShowTestDeviceFlag = 'show-test-device';
4042
static const String kShowWebServerDeviceFlag = 'show-web-server-device';
@@ -116,6 +118,12 @@ class FlutterCommandRunner extends CommandRunner<void> {
116118
argParser.addOption(FlutterGlobalOptions.kPackagesOption,
117119
hide: !verboseHelp,
118120
help: 'Path to your "package_config.json" file.');
121+
argParser.addFlag(
122+
FlutterGlobalOptions.kPrintDtd,
123+
negatable: false,
124+
help: 'Print the address of the Dart Tooling Daemon, if one is hosted by the Flutter CLI.',
125+
hide: !verboseHelp,
126+
);
119127
if (verboseHelp) {
120128
argParser.addSeparator('Local build selection options (not normally required):');
121129
}
@@ -357,6 +365,10 @@ class FlutterCommandRunner extends CommandRunner<void> {
357365
if (machineFlag && topLevelResults.command?.name != 'analyze') {
358366
throwToolExit('The "--machine" flag is only valid with the "--version" flag or the "analyze --suggestions" command.', exitCode: 2);
359367
}
368+
369+
final bool shouldPrintDtdUri = topLevelResults[FlutterGlobalOptions.kPrintDtd] as bool? ?? false;
370+
DevtoolsLauncher.instance!.printDtdUri = shouldPrintDtdUri;
371+
360372
await super.runCommand(topLevelResults);
361373
},
362374
);

packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,7 @@ void main() {
824824
expect(result['host'], '127.0.0.1');
825825
expect(result['port'], 1234);
826826
}, overrides: <Type, Generator>{
827-
DevtoolsLauncher: () => FakeDevtoolsLauncher(DevToolsServerAddress('127.0.0.1', 1234)),
827+
DevtoolsLauncher: () => FakeDevtoolsLauncher(serverAddress: DevToolsServerAddress('127.0.0.1', 1234)),
828828
});
829829

830830
testUsingContext('devtools.serve command should return null fields if null returned', () async {
@@ -840,7 +840,7 @@ void main() {
840840
expect(result['host'], null);
841841
expect(result['port'], null);
842842
}, overrides: <Type, Generator>{
843-
DevtoolsLauncher: () => FakeDevtoolsLauncher(null),
843+
DevtoolsLauncher: () => FakeDevtoolsLauncher(),
844844
});
845845

846846
testUsingContext('proxy.connect tries to connect to an ipv4 address and proxies the connection correctly', () async {
@@ -1286,18 +1286,6 @@ class FakeDeviceLogReader implements DeviceLogReader {
12861286

12871287
}
12881288

1289-
class FakeDevtoolsLauncher extends Fake implements DevtoolsLauncher {
1290-
FakeDevtoolsLauncher(this._serverAddress);
1291-
1292-
final DevToolsServerAddress? _serverAddress;
1293-
1294-
@override
1295-
Future<DevToolsServerAddress?> serve() async => _serverAddress;
1296-
1297-
@override
1298-
Future<void> close() async {}
1299-
}
1300-
13011289
class FakeApplicationPackageFactory implements ApplicationPackageFactory {
13021290
TargetPlatform? platformRequested;
13031291
File? applicationBinaryRequested;

0 commit comments

Comments
 (0)