| // Copyright 2014 The Flutter 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/task_result.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, 'dev/integration_tests/flutter_gallery')); |
| |
| const String kInitialStartupTime = 'InitialStartupTime'; |
| const String kFirstRestartTime = 'FistRestartTime'; |
| const String kFirstRecompileTime = 'FirstRecompileTime'; |
| const String kSecondStartupTime = 'SecondStartupTime'; |
| const String kSecondRestartTime = 'SecondRestartTime'; |
| |
| abstract class WebDevice { |
| static const String chrome = 'chrome'; |
| static const String webServer = 'web-server'; |
| } |
| |
| TaskFunction createWebDevModeTest(String webDevice, bool enableIncrementalCompiler) { |
| return () async { |
| final List<String> options = <String>[ |
| '--hot', '-d', webDevice, '--verbose', '--resident', '--target=lib/main.dart', |
| ]; |
| int hotRestartCount = 0; |
| final String expectedMessage = webDevice == WebDevice.webServer |
| ? 'Recompile complete' |
| : 'Reloaded application'; |
| final Map<String, int> measurements = <String, int>{}; |
| await inDirectory<void>(flutterDirectory, () async { |
| rmTree(_editedFlutterGalleryDir); |
| mkdirs(_editedFlutterGalleryDir); |
| recursiveCopy(flutterGalleryDir, _editedFlutterGalleryDir); |
| await inDirectory<void>(_editedFlutterGalleryDir, () async { |
| { |
| await exec( |
| path.join(flutterDirectory.path, 'bin', 'flutter'), |
| <String>['packages', 'get'], |
| ); |
| final Process process = await startProcess( |
| path.join(flutterDirectory.path, 'bin', 'flutter'), |
| flutterCommandArgs('run', options), |
| ); |
| |
| final Completer<void> stdoutDone = Completer<void>(); |
| final Completer<void> stderrDone = Completer<void>(); |
| final Stopwatch sw = Stopwatch()..start(); |
| bool restarted = false; |
| process.stdout |
| .transform<String>(utf8.decoder) |
| .transform<String>(const LineSplitter()) |
| .listen((String line) { |
| // non-dwds builds do not know when the browser is loaded so keep trying |
| // until this succeeds. |
| if (line.contains('Ignoring terminal input')) { |
| Future<void>.delayed(const Duration(seconds: 1)).then((void _) { |
| process.stdin.write(restarted ? 'q' : 'r'); |
| }); |
| return; |
| } |
| if (line.contains('To hot restart')) { |
| // measure clean start-up time. |
| sw.stop(); |
| measurements[kInitialStartupTime] = sw.elapsedMilliseconds; |
| sw |
| ..reset() |
| ..start(); |
| process.stdin.write('r'); |
| return; |
| } |
| if (line.contains(expectedMessage)) { |
| if (hotRestartCount == 0) { |
| measurements[kFirstRestartTime] = sw.elapsedMilliseconds; |
| // 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'", |
| ) |
| ); |
| sw |
| ..reset() |
| ..start(); |
| process.stdin.writeln('r'); |
| ++hotRestartCount; |
| } else { |
| restarted = true; |
| measurements[kFirstRecompileTime] = sw.elapsedMilliseconds; |
| // 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 Stopwatch sw = Stopwatch()..start(); |
| final Process process = await startProcess( |
| path.join(flutterDirectory.path, 'bin', 'flutter'), |
| flutterCommandArgs('run', options), |
| ); |
| final Completer<void> stdoutDone = Completer<void>(); |
| final Completer<void> stderrDone = Completer<void>(); |
| bool restarted = false; |
| process.stdout |
| .transform<String>(utf8.decoder) |
| .transform<String>(const LineSplitter()) |
| .listen((String line) { |
| // non-dwds builds do not know when the browser is loaded so keep trying |
| // until this succeeds. |
| if (line.contains('Ignoring terminal input')) { |
| Future<void>.delayed(const Duration(seconds: 1)).then((void _) { |
| process.stdin.write(restarted ? 'q' : 'r'); |
| }); |
| return; |
| } |
| if (line.contains('To hot restart')) { |
| measurements[kSecondStartupTime] = sw.elapsedMilliseconds; |
| sw |
| ..reset() |
| ..start(); |
| process.stdin.write('r'); |
| return; |
| } |
| if (line.contains(expectedMessage)) { |
| restarted = true; |
| measurements[kSecondRestartTime] = sw.elapsedMilliseconds; |
| 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; |
| } |
| }); |
| }); |
| if (hotRestartCount != 1) { |
| return TaskResult.failure(null); |
| } |
| return TaskResult.success(measurements, benchmarkScoreKeys: <String>[ |
| kInitialStartupTime, |
| kFirstRestartTime, |
| kFirstRecompileTime, |
| kSecondStartupTime, |
| kSecondRestartTime, |
| ]); |
| }; |
| } |