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
)
..addOption('route',
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);
usesTargetOption();
......@@ -307,6 +312,7 @@ class RunCommand extends RunCommandBase {
hostname: featureFlags.isWebEnabled ? argResults['web-hostname'] : '',
port: featureFlags.isWebEnabled ? argResults['web-port'] : '',
browserLaunch: featureFlags.isWebEnabled ? argResults['web-browser-launch'] : null,
vmserviceOutFile: argResults['vmservice-out-file'],
);
}
}
......
......@@ -499,6 +499,7 @@ class DebuggingOptions {
this.hostname,
this.port,
this.browserLaunch = true,
this.vmserviceOutFile,
}) : debuggingEnabled = true;
DebuggingOptions.disabled(this.buildInfo, { this.initializePlatform = true, this.port, this.hostname })
......@@ -514,7 +515,8 @@ class DebuggingOptions {
dumpSkpOnShaderCompilation = false,
verboseSystemLogs = false,
observatoryPort = null,
browserLaunch = true;
browserLaunch = true,
vmserviceOutFile = null;
final bool debuggingEnabled;
......@@ -535,6 +537,8 @@ class DebuggingOptions {
final String port;
final String hostname;
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;
}
......
......@@ -643,6 +643,20 @@ abstract class ResidentRunner {
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 {
_exited = true;
await stopEchoingDeviceLog();
......
......@@ -114,6 +114,8 @@ class ColdRunner extends ResidentRunner {
appStartedCompleter?.complete();
writeVmserviceFile();
if (stayResident && !traceStartup) {
return waitForAppToFinish();
}
......
......@@ -228,6 +228,7 @@ class HotRunner extends ResidentRunner {
benchmarkOutput.writeAsStringSync(toPrettyJson(benchmarkData));
return 0;
}
writeVmserviceFile();
int result = 0;
if (stayResident) {
......
......@@ -4,6 +4,7 @@
import 'dart:async';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/file_system.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/devfs.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/resident_runner.dart';
import 'package:flutter_tools/src/run_cold.dart';
import 'package:flutter_tools/src/run_hot.dart';
import 'package:flutter_tools/src/vmservice.dart';
import 'package:json_rpc_2/json_rpc_2.dart';
......@@ -532,6 +535,70 @@ void main() {
verify(mockFlutterDevice.refreshViews()).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 {}
......@@ -550,3 +617,14 @@ class TestFlutterDevice extends FlutterDevice {
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