Unverified Commit e22d4aa1 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Add debugging option to write vmservice address to file after starting (#41583)

parent 428d7d7f
...@@ -43,6 +43,11 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment ...@@ -43,6 +43,11 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
) )
..addOption('route', ..addOption('route',
help: 'Which route to load when running the app.', help: 'Which route to load when running the app.',
)
..addOption('vmservice-out-file',
help: 'A file to write the attached vmservice uri to after an'
' application is started.',
valueHelp: 'project/example/out.txt'
); );
usesWebOptions(hide: !verboseHelp); usesWebOptions(hide: !verboseHelp);
usesTargetOption(); usesTargetOption();
...@@ -307,6 +312,7 @@ class RunCommand extends RunCommandBase { ...@@ -307,6 +312,7 @@ class RunCommand extends RunCommandBase {
hostname: featureFlags.isWebEnabled ? argResults['web-hostname'] : '', hostname: featureFlags.isWebEnabled ? argResults['web-hostname'] : '',
port: featureFlags.isWebEnabled ? argResults['web-port'] : '', port: featureFlags.isWebEnabled ? argResults['web-port'] : '',
browserLaunch: featureFlags.isWebEnabled ? argResults['web-browser-launch'] : null, browserLaunch: featureFlags.isWebEnabled ? argResults['web-browser-launch'] : null,
vmserviceOutFile: argResults['vmservice-out-file'],
); );
} }
} }
......
...@@ -499,6 +499,7 @@ class DebuggingOptions { ...@@ -499,6 +499,7 @@ class DebuggingOptions {
this.hostname, this.hostname,
this.port, this.port,
this.browserLaunch = true, this.browserLaunch = true,
this.vmserviceOutFile,
}) : debuggingEnabled = true; }) : debuggingEnabled = true;
DebuggingOptions.disabled(this.buildInfo, { this.initializePlatform = true, this.port, this.hostname }) DebuggingOptions.disabled(this.buildInfo, { this.initializePlatform = true, this.port, this.hostname })
...@@ -514,7 +515,8 @@ class DebuggingOptions { ...@@ -514,7 +515,8 @@ class DebuggingOptions {
dumpSkpOnShaderCompilation = false, dumpSkpOnShaderCompilation = false,
verboseSystemLogs = false, verboseSystemLogs = false,
observatoryPort = null, observatoryPort = null,
browserLaunch = true; browserLaunch = true,
vmserviceOutFile = null;
final bool debuggingEnabled; final bool debuggingEnabled;
...@@ -535,6 +537,8 @@ class DebuggingOptions { ...@@ -535,6 +537,8 @@ class DebuggingOptions {
final String port; final String port;
final String hostname; final String hostname;
final bool browserLaunch; final bool browserLaunch;
/// A file where the vmservice uri should be written after the application is started.
final String vmserviceOutFile;
bool get hasObservatoryPort => observatoryPort != null; bool get hasObservatoryPort => observatoryPort != null;
} }
......
...@@ -643,6 +643,20 @@ abstract class ResidentRunner { ...@@ -643,6 +643,20 @@ abstract class ResidentRunner {
throw '${fullRestart ? 'Restart' : 'Reload'} is not supported in $mode mode'; throw '${fullRestart ? 'Restart' : 'Reload'} is not supported in $mode mode';
} }
@protected
void writeVmserviceFile() {
if (debuggingOptions.vmserviceOutFile != null) {
try {
final String address = flutterDevices.first.vmServices.first.wsAddress.toString();
final File vmserviceOutFile = fs.file(debuggingOptions.vmserviceOutFile);
vmserviceOutFile.createSync(recursive: true);
vmserviceOutFile.writeAsStringSync(address);
} on FileSystemException {
printError('Failed to write vmservice-out-file at ${debuggingOptions.vmserviceOutFile}');
}
}
}
Future<void> exit() async { Future<void> exit() async {
_exited = true; _exited = true;
await stopEchoingDeviceLog(); await stopEchoingDeviceLog();
......
...@@ -114,6 +114,8 @@ class ColdRunner extends ResidentRunner { ...@@ -114,6 +114,8 @@ class ColdRunner extends ResidentRunner {
appStartedCompleter?.complete(); appStartedCompleter?.complete();
writeVmserviceFile();
if (stayResident && !traceStartup) { if (stayResident && !traceStartup) {
return waitForAppToFinish(); return waitForAppToFinish();
} }
......
...@@ -228,6 +228,7 @@ class HotRunner extends ResidentRunner { ...@@ -228,6 +228,7 @@ class HotRunner extends ResidentRunner {
benchmarkOutput.writeAsStringSync(toPrettyJson(benchmarkData)); benchmarkOutput.writeAsStringSync(toPrettyJson(benchmarkData));
return 0; return 0;
} }
writeVmserviceFile();
int result = 0; int result = 0;
if (stayResident) { if (stayResident) {
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'dart:async'; import 'dart:async';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/context.dart'; import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
...@@ -11,8 +12,10 @@ import 'package:flutter_tools/src/base/logger.dart'; ...@@ -11,8 +12,10 @@ import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/devfs.dart'; import 'package:flutter_tools/src/devfs.dart';
import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/globals.dart';
import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/resident_runner.dart'; import 'package:flutter_tools/src/resident_runner.dart';
import 'package:flutter_tools/src/run_cold.dart';
import 'package:flutter_tools/src/run_hot.dart'; import 'package:flutter_tools/src/run_hot.dart';
import 'package:flutter_tools/src/vmservice.dart'; import 'package:flutter_tools/src/vmservice.dart';
import 'package:json_rpc_2/json_rpc_2.dart'; import 'package:json_rpc_2/json_rpc_2.dart';
...@@ -532,6 +535,70 @@ void main() { ...@@ -532,6 +535,70 @@ void main() {
verify(mockFlutterDevice.refreshViews()).called(1); verify(mockFlutterDevice.refreshViews()).called(1);
verify(mockFlutterDevice.toggleProfileWidgetBuilds()).called(1); verify(mockFlutterDevice.toggleProfileWidgetBuilds()).called(1);
})); }));
test('HotRunner writes vm service file when providing debugging option', () => testbed.run(() async {
fs.file(fs.path.join('lib', 'main.dart')).createSync(recursive: true);
residentRunner = HotRunner(
<FlutterDevice>[
mockFlutterDevice,
],
stayResident: false,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug, vmserviceOutFile: 'foo'),
);
when(mockFlutterDevice.runHot(
hotRunner: anyNamed('hotRunner'),
route: anyNamed('route'),
)).thenAnswer((Invocation invocation) async {
return 0;
});
await residentRunner.run();
expect(await fs.file('foo').readAsString(), testUri.toString());
}));
test('HotRunner handles failure to write vmservice file', () => testbed.run(() async {
final BufferLogger bufferLogger = logger;
fs.file(fs.path.join('lib', 'main.dart')).createSync(recursive: true);
residentRunner = HotRunner(
<FlutterDevice>[
mockFlutterDevice,
],
stayResident: false,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug, vmserviceOutFile: 'foo'),
);
when(mockFlutterDevice.runHot(
hotRunner: anyNamed('hotRunner'),
route: anyNamed('route'),
)).thenAnswer((Invocation invocation) async {
return 0;
});
await residentRunner.run();
expect(bufferLogger.errorText, contains('Failed to write vmservice-out-file at foo'));
}, overrides: <Type, Generator>{
FileSystem: () => ThrowingForwardingFileSystem(MemoryFileSystem()),
}));
test('ColdRunner writes vm service file when providing debugging option', () => testbed.run(() async {
fs.file(fs.path.join('lib', 'main.dart')).createSync(recursive: true);
residentRunner = ColdRunner(
<FlutterDevice>[
mockFlutterDevice,
],
stayResident: false,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.profile, vmserviceOutFile: 'foo'),
);
when(mockFlutterDevice.runCold(
coldRunner: anyNamed('coldRunner'),
route: anyNamed('route'),
)).thenAnswer((Invocation invocation) async {
return 0;
});
await residentRunner.run();
expect(await fs.file('foo').readAsString(), testUri.toString());
}));
} }
class MockFlutterDevice extends Mock implements FlutterDevice {} class MockFlutterDevice extends Mock implements FlutterDevice {}
...@@ -550,3 +617,14 @@ class TestFlutterDevice extends FlutterDevice { ...@@ -550,3 +617,14 @@ class TestFlutterDevice extends FlutterDevice {
final List<FlutterView> views; final List<FlutterView> views;
} }
class ThrowingForwardingFileSystem extends ForwardingFileSystem {
ThrowingForwardingFileSystem(FileSystem delegate) : super(delegate);
@override
File file(dynamic path) {
if (path == 'foo') {
throw const FileSystemException();
}
return delegate.file(path);
}
}
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