| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:async'; |
| import 'dart:convert'; |
| import 'dart:io'; |
| |
| import 'package:path/path.dart' as path; |
| |
| import '../framework/framework.dart'; |
| import '../framework/running_processes.dart'; |
| import '../framework/utils.dart'; |
| |
| final Directory _editedFlutterGalleryDir = dir(path.join(Directory.systemTemp.path, 'edited_flutter_gallery')); |
| final Directory flutterGalleryDir = dir(path.join(flutterDirectory.path, 'examples/flutter_gallery')); |
| |
| TaskFunction createWebDevModeTest() { |
| return () async { |
| final List<String> options = <String>[ |
| '--hot', '-d', 'chrome', '--verbose', '--resident', '--target=lib/main.dart', |
| ]; |
| int hotRestartCount = 0; |
| String chromeProcessName; |
| if (Platform.isMacOS) { |
| chromeProcessName = 'Chrome'; |
| } else if (Platform.isLinux) { |
| chromeProcessName = 'chrome'; |
| } else if (Platform.isWindows) { |
| chromeProcessName = 'chrome.exe'; |
| } |
| final Set<String> beforeChromeProcesses = await getRunningProcesses(processName: chromeProcessName) |
| .map((RunningProcessInfo info) => info.pid) |
| .toSet(); |
| try { |
| await inDirectory<void>(flutterDirectory, () async { |
| rmTree(_editedFlutterGalleryDir); |
| mkdirs(_editedFlutterGalleryDir); |
| recursiveCopy(flutterGalleryDir, _editedFlutterGalleryDir); |
| await inDirectory<void>(_editedFlutterGalleryDir, () async { |
| { |
| final Process packagesGet = await startProcess( |
| path.join(flutterDirectory.path, 'bin', 'flutter'), |
| <String>['packages', 'get'], |
| environment: <String, String>{ |
| 'FLUTTER_WEB': 'true', |
| }, |
| ); |
| await packagesGet.exitCode; |
| final Process process = await startProcess( |
| path.join(flutterDirectory.path, 'bin', 'flutter'), |
| flutterCommandArgs('run', options), |
| environment: <String, String>{ |
| 'FLUTTER_WEB': 'true', |
| }, |
| ); |
| |
| final Completer<void> stdoutDone = Completer<void>(); |
| final Completer<void> stderrDone = Completer<void>(); |
| process.stdout |
| .transform<String>(utf8.decoder) |
| .transform<String>(const LineSplitter()) |
| .listen((String line) { |
| if (line.contains('To hot restart')) { |
| process.stdin.write('R'); |
| } |
| if (line.contains('Restarted')) { |
| if (hotRestartCount == 0) { |
| // Update the file and reload again. |
| final File appDartSource = file(path.join( |
| _editedFlutterGalleryDir.path, 'lib/gallery/app.dart', |
| )); |
| appDartSource.writeAsStringSync( |
| appDartSource.readAsStringSync().replaceFirst( |
| "'Flutter Gallery'", "'Updated Flutter Gallery'", |
| ) |
| ); |
| process.stdin.writeln('R'); |
| ++hotRestartCount; |
| } else { |
| // Quit after second hot restart. |
| process.stdin.writeln('q'); |
| } |
| } |
| print('stdout: $line'); |
| }, onDone: () { |
| stdoutDone.complete(); |
| }); |
| process.stderr |
| .transform<String>(utf8.decoder) |
| .transform<String>(const LineSplitter()) |
| .listen((String line) { |
| print('stderr: $line'); |
| }, onDone: () { |
| stderrDone.complete(); |
| }); |
| |
| await Future.wait<void>(<Future<void>>[ |
| stdoutDone.future, |
| stderrDone.future, |
| ]); |
| await process.exitCode; |
| |
| } |
| |
| // Start `flutter run` again to make sure it loads from the previous |
| // state. dev compilers loads up from previously compiled JavaScript. |
| { |
| final Process process = await startProcess( |
| path.join(flutterDirectory.path, 'bin', 'flutter'), |
| flutterCommandArgs('run', options), |
| environment: <String, String>{ |
| 'FLUTTER_WEB': 'true', |
| }, |
| ); |
| final Completer<void> stdoutDone = Completer<void>(); |
| final Completer<void> stderrDone = Completer<void>(); |
| process.stdout |
| .transform<String>(utf8.decoder) |
| .transform<String>(const LineSplitter()) |
| .listen((String line) { |
| if (line.contains('To hot restart')) { |
| process.stdin.write('R'); |
| } |
| if (line.contains('Restarted')) { |
| process.stdin.writeln('q'); |
| } |
| print('stdout: $line'); |
| }, onDone: () { |
| stdoutDone.complete(); |
| }); |
| process.stderr |
| .transform<String>(utf8.decoder) |
| .transform<String>(const LineSplitter()) |
| .listen((String line) { |
| print('stderr: $line'); |
| }, onDone: () { |
| stderrDone.complete(); |
| }); |
| |
| await Future.wait<void>(<Future<void>>[ |
| stdoutDone.future, |
| stderrDone.future, |
| ]); |
| await process.exitCode; |
| } |
| }); |
| }); |
| } finally { |
| final Set<String> afterChromeProcesses = await getRunningProcesses(processName: chromeProcessName) |
| .map((RunningProcessInfo info) => info.pid) |
| .toSet(); |
| final Set<String> newProcesses = afterChromeProcesses.difference(beforeChromeProcesses); |
| for (String processId in newProcesses) { |
| await killProcess(processId); |
| } |
| } |
| if (hotRestartCount != 1) { |
| return TaskResult.failure(null); |
| } |
| return TaskResult.success(null); |
| }; |
| } |