Fix --pid-file not working for --machine + add to attach command (#23242) * Fix --pid-file not working for --machine + add to attach Fixes #23201. * Add tests for --pid-file in run+attach
diff --git a/packages/flutter_tools/lib/src/base/utils.dart b/packages/flutter_tools/lib/src/base/utils.dart index a7fe6fa..b9cb836 100644 --- a/packages/flutter_tools/lib/src/base/utils.dart +++ b/packages/flutter_tools/lib/src/base/utils.dart
@@ -398,6 +398,13 @@ return result.join('\n'); } +void writePidFile(String pidFile) { + if (pidFile != null) { + // Write our pid to the file. + fs.file(pidFile).writeAsStringSync(io.pid.toString()); + } +} + // Used to represent a run of ANSI control sequences next to a visible // character. class _AnsiRun {
diff --git a/packages/flutter_tools/lib/src/commands/attach.dart b/packages/flutter_tools/lib/src/commands/attach.dart index 50091d8..0f1b70a 100644 --- a/packages/flutter_tools/lib/src/commands/attach.dart +++ b/packages/flutter_tools/lib/src/commands/attach.dart
@@ -7,6 +7,7 @@ import '../base/common.dart'; import '../base/file_system.dart'; import '../base/io.dart'; +import '../base/utils.dart'; import '../cache.dart'; import '../commands/daemon.dart'; import '../device.dart'; @@ -44,6 +45,10 @@ ..addOption( 'debug-port', help: 'Local port where the observatory is listening.', + )..addOption('pid-file', + help: 'Specify a file to write the process id to. ' + 'You can send SIGUSR1 to trigger a hot reload ' + 'and SIGUSR2 to trigger a hot restart.', )..addOption( 'project-root', hide: !verboseHelp, @@ -90,6 +95,8 @@ await _validateArguments(); + writePidFile(argResults['pid-file']); + final Device device = await findTargetDevice(); final int devicePort = observatoryPort;
diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index b94543e..461c4fc 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart
@@ -6,7 +6,6 @@ import '../base/common.dart'; import '../base/file_system.dart'; -import '../base/io.dart'; import '../base/utils.dart'; import '../build_info.dart'; import '../cache.dart'; @@ -276,6 +275,8 @@ // debug mode. final bool hotMode = shouldUseHotMode(); + writePidFile(argResults['pid-file']); + if (argResults['machine']) { if (devices.length > 1) throwToolExit('--machine does not support -d all.'); @@ -340,12 +341,6 @@ } } - final String pidFile = argResults['pid-file']; - if (pidFile != null) { - // Write our pid to the file. - fs.file(pidFile).writeAsStringSync(pid.toString()); - } - final List<FlutterDevice> flutterDevices = devices.map<FlutterDevice>((Device device) { return FlutterDevice( device,
diff --git a/packages/flutter_tools/test/integration/flutter_attach_test.dart b/packages/flutter_tools/test/integration/flutter_attach_test.dart index 8b5cff8..2e21ffa 100644 --- a/packages/flutter_tools/test/integration/flutter_attach_test.dart +++ b/packages/flutter_tools/test/integration/flutter_attach_test.dart
@@ -29,6 +29,15 @@ }); group('attached process', () { + test('writes pid-file', () async { + final File pidFile = tempDir.childFile('test.pid'); + await _flutterRun.run(withDebugger: true); + await _flutterAttach.attach( + _flutterRun.vmServicePort, + pidFile: pidFile, + ); + expect(pidFile.existsSync(), isTrue); + }); test('can hot reload', () async { await _flutterRun.run(withDebugger: true); await _flutterAttach.attach(_flutterRun.vmServicePort);
diff --git a/packages/flutter_tools/test/integration/flutter_run_test.dart b/packages/flutter_tools/test/integration/flutter_run_test.dart index 2f1a577..fa594cf 100644 --- a/packages/flutter_tools/test/integration/flutter_run_test.dart +++ b/packages/flutter_tools/test/integration/flutter_run_test.dart
@@ -9,21 +9,25 @@ import '../src/common.dart'; import 'test_data/basic_project.dart'; +import 'test_driver.dart'; import 'test_utils.dart'; void main() { group('flutter_run', () { Directory tempDir; final BasicProject _project = BasicProject(); + FlutterTestDriver _flutter; setUp(() async { tempDir = createResolvedTempDirectorySync(); await _project.setUpIn(tempDir); + _flutter = FlutterTestDriver(tempDir); }); tearDown(() async { tryToDelete(tempDir); }); + test('reports an error if an invalid device is supplied', () async { // This test forces flutter to check for all possible devices to catch issues // like https://github.com/flutter/flutter/issues/21418 which were skipped @@ -44,5 +48,11 @@ fail("'flutter run -d invalid-device-id' did not produce the expected error"); } }); + + test('writes pid-file', () async { + final File pidFile = tempDir.childFile('test.pid'); + await _flutter.run(pidFile: pidFile); + expect(pidFile.existsSync(), isTrue); + }); }, timeout: const Timeout.factor(6)); }
diff --git a/packages/flutter_tools/test/integration/test_driver.dart b/packages/flutter_tools/test/integration/test_driver.dart index a6f535e..c7d89c7 100644 --- a/packages/flutter_tools/test/integration/test_driver.dart +++ b/packages/flutter_tools/test/integration/test_driver.dart
@@ -56,16 +56,25 @@ return msg; } - Future<void> run({bool withDebugger = false, bool pauseOnExceptions = false}) async { + Future<void> run({ + bool withDebugger = false, + bool pauseOnExceptions = false, + File pidFile, + }) async { await _setupProcess(<String>[ 'run', '--machine', '-d', 'flutter-tester', - ], withDebugger: withDebugger, pauseOnExceptions: pauseOnExceptions); + ], withDebugger: withDebugger, pauseOnExceptions: pauseOnExceptions, pidFile: pidFile); } - Future<void> attach(int port, {bool withDebugger = false, bool pauseOnExceptions = false}) async { + Future<void> attach( + int port, { + bool withDebugger = false, + bool pauseOnExceptions = false, + File pidFile, + }) async { await _setupProcess(<String>[ 'attach', '--machine', @@ -73,20 +82,28 @@ 'flutter-tester', '--debug-port', '$port', - ], withDebugger: withDebugger, pauseOnExceptions: pauseOnExceptions); + ], withDebugger: withDebugger, pauseOnExceptions: pauseOnExceptions, pidFile: pidFile); } - Future<void> _setupProcess(List<String> args, {bool withDebugger = false, bool pauseOnExceptions = false}) async { + Future<void> _setupProcess( + List<String> args, { + bool withDebugger = false, + bool pauseOnExceptions = false, + File pidFile, + }) async { final String flutterBin = fs.path.join(getFlutterRoot(), 'bin', 'flutter'); - final List<String> flutterArgs = withDebugger - ? args.followedBy(<String>['--start-paused']).toList() - : args; - _debugPrint('Spawning flutter $flutterArgs in ${_projectFolder.path}'); + if (withDebugger) { + args.add('--start-paused'); + } + if (pidFile != null) { + args.addAll(<String>['--pid-file', pidFile.path]); + } + _debugPrint('Spawning flutter $args in ${_projectFolder.path}'); const ProcessManager _processManager = LocalProcessManager(); _proc = await _processManager.start( <String>[flutterBin] - .followedBy(flutterArgs) + .followedBy(args) .toList(), workingDirectory: _projectFolder.path, environment: <String, String>{'FLUTTER_TEST': 'true'});