| // 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/adb.dart'; |
| import '../framework/framework.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')); |
| |
| TaskFunction createHotModeTest({String deviceIdOverride, Map<String, String> environment}) { |
| return () async { |
| if (deviceIdOverride == null) { |
| final Device device = await devices.workingDevice; |
| await device.unlock(); |
| deviceIdOverride = device.deviceId; |
| } |
| final File benchmarkFile = file(path.join(_editedFlutterGalleryDir.path, 'hot_benchmark.json')); |
| rm(benchmarkFile); |
| final List<String> options = <String>[ |
| '--hot', '-d', deviceIdOverride, '--benchmark', '--verbose', '--resident', '--output-dill', path.join('build', 'app.dill') |
| ]; |
| int hotReloadCount = 0; |
| Map<String, dynamic> twoReloadsData; |
| Map<String, dynamic> freshRestartReloadsData; |
| await inDirectory<void>(flutterDirectory, () async { |
| rmTree(_editedFlutterGalleryDir); |
| mkdirs(_editedFlutterGalleryDir); |
| recursiveCopy(flutterGalleryDir, _editedFlutterGalleryDir); |
| await inDirectory<void>(_editedFlutterGalleryDir, () async { |
| { |
| final Process clearProcess = await startProcess( |
| path.join(flutterDirectory.path, 'bin', 'flutter'), |
| flutterCommandArgs('clean', <String>[]), |
| environment: environment, |
| ); |
| await clearProcess.exitCode; |
| |
| final Process process = await startProcess( |
| path.join(flutterDirectory.path, 'bin', 'flutter'), |
| flutterCommandArgs('run', options), |
| environment: environment, |
| ); |
| |
| 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('] Reloaded ')) { |
| if (hotReloadCount == 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'); |
| ++hotReloadCount; |
| } else { |
| // Quit after second hot reload. |
| 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; |
| |
| twoReloadsData = json.decode(benchmarkFile.readAsStringSync()) as Map<String, dynamic>; |
| } |
| benchmarkFile.deleteSync(); |
| |
| // Start `flutter run` again to make sure it loads from the previous |
| // state. Frontend loads up from previously generated kernel files. |
| { |
| final Process process = await startProcess( |
| path.join(flutterDirectory.path, 'bin', 'flutter'), |
| flutterCommandArgs('run', options), |
| environment: environment, |
| ); |
| 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('] Reloaded ')) { |
| 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; |
| |
| freshRestartReloadsData = |
| json.decode(benchmarkFile.readAsStringSync()) as Map<String, dynamic>; |
| } |
| }); |
| }); |
| |
| |
| |
| return TaskResult.success( |
| <String, dynamic> { |
| 'hotReloadInitialDevFSSyncMilliseconds': twoReloadsData['hotReloadInitialDevFSSyncMilliseconds'][0], |
| 'hotRestartMillisecondsToFrame': twoReloadsData['hotRestartMillisecondsToFrame'][0], |
| 'hotReloadMillisecondsToFrame' : twoReloadsData['hotReloadMillisecondsToFrame'][0], |
| 'hotReloadDevFSSyncMilliseconds': twoReloadsData['hotReloadDevFSSyncMilliseconds'][0], |
| 'hotReloadFlutterReassembleMilliseconds': twoReloadsData['hotReloadFlutterReassembleMilliseconds'][0], |
| 'hotReloadVMReloadMilliseconds': twoReloadsData['hotReloadVMReloadMilliseconds'][0], |
| 'hotReloadMillisecondsToFrameAfterChange' : twoReloadsData['hotReloadMillisecondsToFrame'][1], |
| 'hotReloadDevFSSyncMillisecondsAfterChange': twoReloadsData['hotReloadDevFSSyncMilliseconds'][1], |
| 'hotReloadFlutterReassembleMillisecondsAfterChange': twoReloadsData['hotReloadFlutterReassembleMilliseconds'][1], |
| 'hotReloadVMReloadMillisecondsAfterChange': twoReloadsData['hotReloadVMReloadMilliseconds'][1], |
| 'hotReloadInitialDevFSSyncAfterRelaunchMilliseconds' : freshRestartReloadsData['hotReloadInitialDevFSSyncMilliseconds'][0], |
| }, |
| benchmarkScoreKeys: <String>[ |
| 'hotReloadInitialDevFSSyncMilliseconds', |
| 'hotRestartMillisecondsToFrame', |
| 'hotReloadMillisecondsToFrame', |
| 'hotReloadDevFSSyncMilliseconds', |
| 'hotReloadFlutterReassembleMilliseconds', |
| 'hotReloadVMReloadMilliseconds', |
| 'hotReloadMillisecondsToFrameAfterChange', |
| 'hotReloadDevFSSyncMillisecondsAfterChange', |
| 'hotReloadFlutterReassembleMillisecondsAfterChange', |
| 'hotReloadVMReloadMillisecondsAfterChange', |
| 'hotReloadInitialDevFSSyncAfterRelaunchMilliseconds', |
| ], |
| ); |
| }; |
| } |