From 70fe6f4c232111d61187ea5c2b511bc4ebb339ca Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Tue, 15 Aug 2017 17:53:58 -0700 Subject: [PATCH] Rollback patch that broke microbenchmarks (#11616) * Revert "Extract snapshotting logic to Snapshotter class (#11591)" This reverts commit 309a2d78fbcd735b7594e3f65df809f52d46b23e. * Revert "Minor whitespace formatting fix (#11590)" This reverts commit bf69c3c69bde95779252e0deb3e288c8120aa1ec. * Revert "Avoid rebuilding snapshots if no change to source (#11551)" This reverts commit 74835db563b7c31b4c883eeea15e689a1bdbd303. --- .../flutter_tools/lib/src/base/build.dart | 168 ------------- .../lib/src/commands/build_aot.dart | 78 ++---- packages/flutter_tools/lib/src/flx.dart | 93 +++++++- .../flutter_tools/test/base/build_test.dart | 222 ------------------ 4 files changed, 107 insertions(+), 454 deletions(-) diff --git a/packages/flutter_tools/lib/src/base/build.dart b/packages/flutter_tools/lib/src/base/build.dart index f5f7f8a5c47..6b48ea64552 100644 --- a/packages/flutter_tools/lib/src/base/build.dart +++ b/packages/flutter_tools/lib/src/base/build.dart @@ -2,48 +2,11 @@ // 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' show JSON; import 'package:crypto/crypto.dart' show md5; -import 'package:meta/meta.dart'; -import '../artifacts.dart'; -import '../build_info.dart'; -import '../globals.dart'; -import 'context.dart'; import 'file_system.dart'; -import 'process.dart'; - -GenSnapshot get genSnapshot => context.putIfAbsent(GenSnapshot, () => const GenSnapshot()); - -class GenSnapshot { - const GenSnapshot(); - - Future run({ - @required TargetPlatform targetPlatform, - @required BuildMode buildMode, - @required String packagesPath, - @required String depfilePath, - Iterable additionalArgs: const [], - }) { - final String vmSnapshotData = artifacts.getArtifactPath(Artifact.vmSnapshotData); - final String isolateSnapshotData = artifacts.getArtifactPath(Artifact.isolateSnapshotData); - final List args = [ - '--assert_initializer', - '--await_is_keyword', - '--causal_async_stacks', - '--vm_snapshot_data=$vmSnapshotData', - '--isolate_snapshot_data=$isolateSnapshotData', - '--packages=$packagesPath', - '--dependencies=$depfilePath', - '--print_snapshot_sizes', - ]..addAll(additionalArgs); - - final String snapshotterPath = artifacts.getArtifactPath(Artifact.genSnapshot, targetPlatform, buildMode); - return runCommandAndStreamOutput([snapshotterPath]..addAll(args)); - } -} /// A collection of checksums for a set of input files. /// @@ -79,134 +42,3 @@ class Checksum { @override int get hashCode => _checksums.hashCode; } - -final RegExp _separatorExpr = new RegExp(r'([^\\]) '); -final RegExp _escapeExpr = new RegExp(r'\\(.)'); - -/// Parses a VM snapshot dependency file. -/// -/// Snapshot dependency files are a single line mapping the output snapshot to a -/// space-separated list of input files used to generate that output. Spaces and -/// backslashes are escaped with a backslash. e.g, -/// -/// outfile : file1.dart fil\\e2.dart fil\ e3.dart -/// -/// will return a set containing: 'file1.dart', 'fil\e2.dart', 'fil e3.dart'. -Future> readDepfile(String depfilePath) async { - // Depfile format: - // outfile1 outfile2 : file1.dart file2.dart file3.dart - final String contents = await fs.file(depfilePath).readAsString(); - final String dependencies = contents.split(': ')[1]; - return dependencies - .replaceAllMapped(_separatorExpr, (Match match) => '${match.group(1)}\n') - .split('\n') - .map((String path) => path.replaceAllMapped(_escapeExpr, (Match match) => match.group(1)).trim()) - .where((String path) => path.isNotEmpty) - .toSet(); -} - -/// Dart snapshot builder. -/// -/// Builds Dart snapshots in one of three modes: -/// * Script snapshot: architecture-independent snapshot of a Dart script core -/// libraries. -/// * AOT snapshot: architecture-specific ahead-of-time compiled snapshot -/// suitable for loading with `mmap`. -/// * Assembly AOT snapshot: architecture-specific ahead-of-time compile to -/// assembly suitable for compilation as a static or dynamic library. -class Snapshotter { - /// Builds an architecture-independent snapshot of the specified script. - Future buildScriptSnapshot({ - @required String mainPath, - @required String snapshotPath, - @required String depfilePath, - @required String packagesPath - }) async { - final List args = [ - '--snapshot_kind=script', - '--script_snapshot=$snapshotPath', - mainPath, - ]; - - final String checksumsPath = '$depfilePath.checksums'; - final int exitCode = await _build( - outputSnapshotPath: snapshotPath, - packagesPath: packagesPath, - snapshotArgs: args, - depfilePath: depfilePath, - mainPath: mainPath, - checksumsPath: checksumsPath, - ); - if (exitCode != 0) - return exitCode; - await _writeChecksum(snapshotPath, depfilePath, mainPath, checksumsPath); - return exitCode; - } - - /// Builds an architecture-specific ahead-of-time compiled snapshot of the specified script. - Future buildAotSnapshot() async { - throw new UnimplementedError('AOT snapshotting not yet implemented'); - } - - Future _build({ - @required List snapshotArgs, - @required String outputSnapshotPath, - @required String packagesPath, - @required String depfilePath, - @required String mainPath, - @required String checksumsPath, - }) async { - if (!await _isBuildRequired(outputSnapshotPath, depfilePath, mainPath, checksumsPath)) { - printTrace('Skipping snapshot build. Checksums match.'); - return 0; - } - - // Build the snapshot. - final int exitCode = await genSnapshot.run( - targetPlatform: null, - buildMode: BuildMode.debug, - packagesPath: packagesPath, - depfilePath: depfilePath, - additionalArgs: snapshotArgs, - ); - if (exitCode != 0) - return exitCode; - - _writeChecksum(outputSnapshotPath, depfilePath, mainPath, checksumsPath); - return 0; - } - - Future _isBuildRequired(String outputSnapshotPath, String depfilePath, String mainPath, String checksumsPath) async { - final File checksumFile = fs.file(checksumsPath); - final File outputSnapshotFile = fs.file(outputSnapshotPath); - final File depfile = fs.file(depfilePath); - if (!outputSnapshotFile.existsSync() || !depfile.existsSync() || !checksumFile.existsSync()) - return true; - - try { - if (checksumFile.existsSync()) { - final Checksum oldChecksum = new Checksum.fromJson(await checksumFile.readAsString()); - final Set checksumPaths = await readDepfile(depfilePath) - ..addAll([outputSnapshotPath, mainPath]); - final Checksum newChecksum = new Checksum.fromFiles(checksumPaths); - return oldChecksum != newChecksum; - } - } catch (e, s) { - // Log exception and continue, this step is a performance improvement only. - printTrace('Error during snapshot checksum output: $e\n$s'); - } - return true; - } - - Future _writeChecksum(String outputSnapshotPath, String depfilePath, String mainPath, String checksumsPath) async { - try { - final Set checksumPaths = await readDepfile(depfilePath) - ..addAll([outputSnapshotPath, mainPath]); - final Checksum checksum = new Checksum.fromFiles(checksumPaths); - await fs.file(checksumsPath).writeAsString(checksum.toJson()); - } catch (e, s) { - // Log exception and continue, this step is a performance improvement only. - print('Error during snapshot checksum output: $e\n$s'); - } - } -} diff --git a/packages/flutter_tools/lib/src/commands/build_aot.dart b/packages/flutter_tools/lib/src/commands/build_aot.dart index 9414cf0d55b..f042441d6ff 100644 --- a/packages/flutter_tools/lib/src/commands/build_aot.dart +++ b/packages/flutter_tools/lib/src/commands/build_aot.dart @@ -5,7 +5,6 @@ import 'dart:async'; import '../artifacts.dart'; -import '../base/build.dart'; import '../base/common.dart'; import '../base/file_system.dart'; import '../base/logger.dart'; @@ -150,16 +149,13 @@ Future _buildAotSnapshot( final String uiPath = fs.path.join(skyEnginePkg, 'lib', 'ui', 'ui.dart'); final String vmServicePath = fs.path.join(skyEnginePkg, 'sdk_ext', 'vmservice_io.dart'); - final List inputPaths = [ + final List filePaths = [ vmEntryPoints, ioEntryPoints, uiPath, vmServicePath, - mainPath, ]; - final Set outputPaths = new Set(); - // These paths are used only on iOS. String snapshotDartIOS; String assembly; @@ -168,15 +164,13 @@ Future _buildAotSnapshot( case TargetPlatform.android_arm: case TargetPlatform.android_x64: case TargetPlatform.android_x86: - outputPaths.addAll([ - vmSnapshotData, - isolateSnapshotData, - ]); break; case TargetPlatform.ios: snapshotDartIOS = artifacts.getArtifactPath(Artifact.snapshotDart, platform, buildMode); assembly = fs.path.join(outputDir.path, 'snapshot_assembly.S'); - inputPaths.add(snapshotDartIOS); + filePaths.addAll([ + snapshotDartIOS, + ]); break; case TargetPlatform.darwin_x64: case TargetPlatform.linux_x64: @@ -185,9 +179,9 @@ Future _buildAotSnapshot( assert(false); } - final Iterable missingInputs = inputPaths.where((String p) => !fs.isFileSync(p)); - if (missingInputs.isNotEmpty) { - printError('Missing input files: $missingInputs'); + final List missingFiles = filePaths.where((String p) => !fs.isFileSync(p)).toList(); + if (missingFiles.isNotEmpty) { + printError('Missing files: $missingFiles'); return null; } if (!processManager.canRun(genSnapshot)) { @@ -214,17 +208,6 @@ Future _buildAotSnapshot( genSnapshotCmd.add('--embedder_entry_points_manifest=$ioEntryPoints'); } - // iOS symbols used to load snapshot data in the engine. - const String kVmSnapshotData = 'kDartVmSnapshotData'; - const String kIsolateSnapshotData = 'kDartIsolateSnapshotData'; - - // iOS snapshot generated files, compiled object files. - final String kVmSnapshotDataC = fs.path.join(outputDir.path, '$kVmSnapshotData.c'); - final String kIsolateSnapshotDataC = fs.path.join(outputDir.path, '$kIsolateSnapshotData.c'); - final String kVmSnapshotDataO = fs.path.join(outputDir.path, '$kVmSnapshotData.o'); - final String kIsolateSnapshotDataO = fs.path.join(outputDir.path, '$kIsolateSnapshotData.o'); - final String assemblyO = fs.path.join(outputDir.path, 'snapshot_assembly.o'); - switch (platform) { case TargetPlatform.android_arm: case TargetPlatform.android_x64: @@ -241,14 +224,9 @@ Future _buildAotSnapshot( if (interpreter) { genSnapshotCmd.add('--snapshot_kind=core'); genSnapshotCmd.add(snapshotDartIOS); - outputPaths.addAll([ - kVmSnapshotDataO, - kIsolateSnapshotDataO, - ]); } else { genSnapshotCmd.add('--snapshot_kind=app-aot-assembly'); genSnapshotCmd.add('--assembly=$assembly'); - outputPaths.add(assemblyO); } break; case TargetPlatform.darwin_x64: @@ -267,27 +245,6 @@ Future _buildAotSnapshot( genSnapshotCmd.add(mainPath); - final File checksumFile = fs.file('$dependencies.checksum'); - final List checksumFiles = [checksumFile, fs.file(dependencies)] - ..addAll(inputPaths.map(fs.file)) - ..addAll(outputPaths.map(fs.file)); - if (checksumFiles.every((File file) => file.existsSync())) { - try { - final String json = await checksumFile.readAsString(); - final Checksum oldChecksum = new Checksum.fromJson(json); - final Set snapshotInputPaths = await readDepfile(dependencies); - snapshotInputPaths.addAll(outputPaths); - final Checksum newChecksum = new Checksum.fromFiles(snapshotInputPaths); - if (oldChecksum == newChecksum) { - printTrace('Skipping AOT snapshot build. Checksums match.'); - return outputPath; - } - } catch (e, s) { - // Log exception and continue, this step is a performance improvement only. - printTrace('Error during AOT snapshot checksum check: $e\n$s'); - } - } - final RunResult results = await runAsync(genSnapshotCmd); if (results.exitCode != 0) { printError('Dart snapshot generator failed with exit code ${results.exitCode}'); @@ -304,6 +261,16 @@ Future _buildAotSnapshot( if (platform == TargetPlatform.ios) { printStatus('Building App.framework...'); + // These names are known to from the engine. + const String kVmSnapshotData = 'kDartVmSnapshotData'; + const String kIsolateSnapshotData = 'kDartIsolateSnapshotData'; + + final String kVmSnapshotDataC = fs.path.join(outputDir.path, '$kVmSnapshotData.c'); + final String kIsolateSnapshotDataC = fs.path.join(outputDir.path, '$kIsolateSnapshotData.c'); + final String kVmSnapshotDataO = fs.path.join(outputDir.path, '$kVmSnapshotData.o'); + final String kIsolateSnapshotDataO = fs.path.join(outputDir.path, '$kIsolateSnapshotData.o'); + final String assemblyO = fs.path.join(outputDir.path, 'snapshot_assembly.o'); + final List commonBuildOptions = ['-arch', 'arm64', '-miphoneos-version-min=8.0']; if (interpreter) { @@ -350,16 +317,5 @@ Future _buildAotSnapshot( await runCheckedAsync(linkCommand); } - // Compute and record checksums. - try { - final Set snapshotInputPaths = await readDepfile(dependencies); - snapshotInputPaths..addAll(outputPaths); - final Checksum checksum = new Checksum.fromFiles(snapshotInputPaths); - await checksumFile.writeAsString(checksum.toJson()); - } catch (e, s) { - // Log exception and continue, this step is a performance improvement only. - printTrace('Error during AOT snapshot checksum output: $e\n$s'); - } - return outputPath; } diff --git a/packages/flutter_tools/lib/src/flx.dart b/packages/flutter_tools/lib/src/flx.dart index 2d9abf22295..996b3023401 100644 --- a/packages/flutter_tools/lib/src/flx.dart +++ b/packages/flutter_tools/lib/src/flx.dart @@ -4,10 +4,14 @@ import 'dart:async'; +import 'package:meta/meta.dart' show required; + +import 'artifacts.dart'; import 'asset.dart'; import 'base/build.dart'; import 'base/common.dart'; import 'base/file_system.dart'; +import 'base/process.dart'; import 'build_info.dart'; import 'dart/package_map.dart'; import 'devfs.dart'; @@ -26,6 +30,90 @@ const String _kKernelKey = 'kernel_blob.bin'; const String _kSnapshotKey = 'snapshot_blob.bin'; const String _kDylibKey = 'libapp.so'; +Future _createSnapshot({ + @required String mainPath, + @required String snapshotPath, + @required String depfilePath, + @required String packages +}) async { + assert(mainPath != null); + assert(snapshotPath != null); + assert(depfilePath != null); + assert(packages != null); + final String snapshotterPath = artifacts.getArtifactPath(Artifact.genSnapshot, null, BuildMode.debug); + final String vmSnapshotData = artifacts.getArtifactPath(Artifact.vmSnapshotData); + final String isolateSnapshotData = artifacts.getArtifactPath(Artifact.isolateSnapshotData); + + final List args = [ + snapshotterPath, + '--snapshot_kind=script', + '--vm_snapshot_data=$vmSnapshotData', + '--isolate_snapshot_data=$isolateSnapshotData', + '--packages=$packages', + '--script_snapshot=$snapshotPath', + '--dependencies=$depfilePath', + mainPath, + ]; + + // Write the depfile path to disk. + fs.file(depfilePath).parent.childFile('gen_snapshot.d').writeAsString('$depfilePath: $snapshotterPath\n'); + + final File checksumFile = fs.file('$depfilePath.checksums'); + final File snapshotFile = fs.file(snapshotPath); + final File depfile = fs.file(depfilePath); + if (snapshotFile.existsSync() && depfile.existsSync() && checksumFile.existsSync()) { + try { + final String json = await checksumFile.readAsString(); + final Checksum oldChecksum = new Checksum.fromJson(json); + final Set inputPaths = await _readDepfile(depfilePath); + inputPaths.add(snapshotPath); + final Checksum newChecksum = new Checksum.fromFiles(inputPaths); + if (oldChecksum == newChecksum) { + printTrace('Skipping snapshot build. Checksums match.'); + return 0; + } + } catch (e, s) { + // Log exception and continue, this step is a performance improvement only. + printTrace('Error during snapshot checksum check: $e\n$s'); + } + } + + // Build the snapshot. + final int exitCode = await runCommandAndStreamOutput(args); + if (exitCode != 0) + return exitCode; + + // Compute and record input file checksums. + try { + final Set inputPaths = await _readDepfile(depfilePath); + inputPaths.add(snapshotPath); + final Checksum checksum = new Checksum.fromFiles(inputPaths); + await checksumFile.writeAsString(checksum.toJson()); + } catch (e, s) { + // Log exception and continue, this step is a performance improvement only. + printTrace('Error during snapshot checksum output: $e\n$s'); + } + return 0; +} + +/// Parses a VM snapshot dependency file. +/// +/// Snapshot dependency files are a single line mapping the output snapshot to a +/// space-separated list of input files used to generate that output. e.g, +/// +/// outfile : file1.dart file2.dart file3.dart +Future> _readDepfile(String depfilePath) async { + // Depfile format: + // outfile : file1.dart file2.dart file3.dart + final String contents = await fs.file(depfilePath).readAsString(); + final String dependencies = contents.split(': ')[1]; + return dependencies + .split(' ') + .map((String path) => path.trim()) + .where((String path) => path.isNotEmpty) + .toSet(); +} + Future build({ String mainPath: defaultMainPath, String manifestPath: defaultManifestPath, @@ -51,12 +139,11 @@ Future build({ // In a precompiled snapshot, the instruction buffer contains script // content equivalents - final Snapshotter snapshotter = new Snapshotter(); - final int result = await snapshotter.buildScriptSnapshot( + final int result = await _createSnapshot( mainPath: mainPath, snapshotPath: snapshotPath, depfilePath: depfilePath, - packagesPath: packagesPath, + packages: packagesPath ); if (result != 0) throwToolExit('Failed to run the Flutter compiler. Exit code: $result', exitCode: result); diff --git a/packages/flutter_tools/test/base/build_test.dart b/packages/flutter_tools/test/base/build_test.dart index c80a8697d8c..ae1682ad062 100644 --- a/packages/flutter_tools/test/base/build_test.dart +++ b/packages/flutter_tools/test/base/build_test.dart @@ -2,54 +2,13 @@ // 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' show JSON; - import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/build.dart'; -import 'package:flutter_tools/src/base/context.dart'; import 'package:flutter_tools/src/base/file_system.dart'; -import 'package:flutter_tools/src/build_info.dart'; import 'package:test/test.dart'; import '../src/context.dart'; -class _FakeGenSnapshot implements GenSnapshot { - _FakeGenSnapshot({ - this.succeed: true, - this.snapshotPath: 'output.snapshot', - this.snapshotContent: '', - this.depfilePath: 'output.snapshot.d', - this.depfileContent: 'output.snapshot.d : main.dart', - }); - - final bool succeed; - final String snapshotPath; - final String snapshotContent; - final String depfilePath; - final String depfileContent; - int _callCount = 0; - - int get callCount => _callCount; - - @override - Future run({ - TargetPlatform targetPlatform, - BuildMode buildMode, - String packagesPath, - String depfilePath, - Iterable additionalArgs, - }) async { - _callCount += 1; - - if (!succeed) - return 1; - await fs.file(snapshotPath).writeAsString(snapshotContent); - await fs.file(depfilePath).writeAsString(depfileContent); - return 0; - } -} - void main() { group('Checksum', () { group('fromFiles', () { @@ -105,185 +64,4 @@ void main() { }); }); }); - - group('readDepfile', () { - MemoryFileSystem fs; - - setUp(() { - fs = new MemoryFileSystem(); - }); - - testUsingContext('returns one file if only one is listed', () async { - await fs.file('a.d').writeAsString('snapshot.d: /foo/a.dart'); - expect(await readDepfile('a.d'), unorderedEquals(['/foo/a.dart'])); - }, overrides: { FileSystem: () => fs }); - - testUsingContext('returns multiple files', () async { - await fs.file('a.d').writeAsString('snapshot.d: /foo/a.dart /foo/b.dart'); - expect(await readDepfile('a.d'), unorderedEquals([ - '/foo/a.dart', - '/foo/b.dart', - ])); - }, overrides: { FileSystem: () => fs}); - - testUsingContext('trims extra spaces between files', () async { - await fs.file('a.d').writeAsString('snapshot.d: /foo/a.dart /foo/b.dart /foo/c.dart'); - expect(await readDepfile('a.d'), unorderedEquals([ - '/foo/a.dart', - '/foo/b.dart', - '/foo/c.dart', - ])); - }, overrides: { FileSystem: () => fs }); - - testUsingContext('returns files with spaces and backslashes', () async { - await fs.file('a.d').writeAsString(r'snapshot.d: /foo/a\ a.dart /foo/b\\b.dart /foo/c\\ c.dart'); - expect(await readDepfile('a.d'), unorderedEquals([ - r'/foo/a a.dart', - r'/foo/b\b.dart', - r'/foo/c\ c.dart', - ])); - }, overrides: { FileSystem: () => fs }); - }); - - group('Snapshotter', () { - _FakeGenSnapshot genSnapshot; - MemoryFileSystem fs; - Snapshotter snapshotter; - - setUp(() { - fs = new MemoryFileSystem(); - genSnapshot = new _FakeGenSnapshot(); - snapshotter = new Snapshotter(); - }); - - testUsingContext('builds snapshot and checksums when no checksums are present', () async { - await fs.file('main.dart').writeAsString('void main() {}'); - await fs.file('output.snapshot').create(); - await fs.file('output.snapshot.d').writeAsString('snapshot : main.dart'); - await snapshotter.buildScriptSnapshot( - mainPath: 'main.dart', - snapshotPath: 'output.snapshot', - depfilePath: 'output.snapshot.d', - packagesPath: '.packages', - ); - - expect(genSnapshot.callCount, 1); - - final Map json = JSON.decode(await fs.file('output.snapshot.d.checksums').readAsString()); - expect(json, hasLength(2)); - expect(json['main.dart'], '27f5ebf0f8c559b2af9419d190299a5e'); - expect(json['output.snapshot'], 'd41d8cd98f00b204e9800998ecf8427e'); - }, overrides: { - FileSystem: () => fs, - GenSnapshot: () => genSnapshot, - }); - - testUsingContext('builds snapshot and checksums when checksums differ', () async { - await fs.file('main.dart').writeAsString('void main() {}'); - await fs.file('output.snapshot').create(); - await fs.file('output.snapshot.d').writeAsString('output.snapshot : main.dart'); - await fs.file('output.snapshot.d.checksums').writeAsString(JSON.encode({ - 'main.dart': '27f5ebf0f8c559b2af9419d190299a5e', - 'output.snapshot': 'deadbeef01234567890abcdef0123456', - })); - await snapshotter.buildScriptSnapshot( - mainPath: 'main.dart', - snapshotPath: 'output.snapshot', - depfilePath: 'output.snapshot.d', - packagesPath: '.packages', - ); - - expect(genSnapshot.callCount, 1); - - final Map json = JSON.decode(await fs.file('output.snapshot.d.checksums').readAsString()); - expect(json, hasLength(2)); - expect(json['main.dart'], '27f5ebf0f8c559b2af9419d190299a5e'); - expect(json['output.snapshot'], 'd41d8cd98f00b204e9800998ecf8427e'); - }, overrides: { - FileSystem: () => fs, - GenSnapshot: () => genSnapshot, - }); - - testUsingContext('builds snapshot and checksums when checksums match but previous snapshot not present', () async { - await fs.file('main.dart').writeAsString('void main() {}'); - await fs.file('output.snapshot.d').writeAsString('output.snapshot : main.dart'); - await fs.file('output.snapshot.d.checksums').writeAsString(JSON.encode({ - 'main.dart': '27f5ebf0f8c559b2af9419d190299a5e', - 'output.snapshot': 'd41d8cd98f00b204e9800998ecf8427e', - })); - await snapshotter.buildScriptSnapshot( - mainPath: 'main.dart', - snapshotPath: 'output.snapshot', - depfilePath: 'output.snapshot.d', - packagesPath: '.packages', - ); - - expect(genSnapshot.callCount, 1); - - final Map json = JSON.decode(await fs.file('output.snapshot.d.checksums').readAsString()); - expect(json, hasLength(2)); - expect(json['main.dart'], '27f5ebf0f8c559b2af9419d190299a5e'); - expect(json['output.snapshot'], 'd41d8cd98f00b204e9800998ecf8427e'); - }, overrides: { - FileSystem: () => fs, - GenSnapshot: () => genSnapshot, - }); - - testUsingContext('builds snapshot and checksums when main entry point changes', () async { - final _FakeGenSnapshot genSnapshot = new _FakeGenSnapshot( - snapshotPath: 'output.snapshot', - depfilePath: 'output.snapshot.d', - depfileContent: 'output.snapshot : other.dart', - ); - context.setVariable(GenSnapshot, genSnapshot); - - await fs.file('main.dart').writeAsString('void main() {}'); - await fs.file('other.dart').writeAsString('void main() { print("Kanpai ima kimi wa jinsei no ookina ookina butai ni tachi"); }'); - await fs.file('output.snapshot.d').writeAsString('output.snapshot : main.dart'); - await fs.file('output.snapshot.d.checksums').writeAsString(JSON.encode({ - 'main.dart': '27f5ebf0f8c559b2af9419d190299a5e', - 'output.snapshot': 'd41d8cd98f00b204e9800998ecf8427e', - })); - await snapshotter.buildScriptSnapshot( - mainPath: 'other.dart', - snapshotPath: 'output.snapshot', - depfilePath: 'output.snapshot.d', - packagesPath: '.packages', - ); - - expect(genSnapshot.callCount, 1); - final Map json = JSON.decode(await fs.file('output.snapshot.d.checksums').readAsString()); - expect(json, hasLength(2)); - expect(json['other.dart'], '3238d0ae341339b1731d3c2e195ad177'); - expect(json['output.snapshot'], 'd41d8cd98f00b204e9800998ecf8427e'); - }, overrides: { - FileSystem: () => fs, - }); - - testUsingContext('skips snapshot when checksums match and previous snapshot is present', () async { - await fs.file('main.dart').writeAsString('void main() {}'); - await fs.file('output.snapshot').create(); - await fs.file('output.snapshot.d').writeAsString('output.snapshot : main.dart'); - await fs.file('output.snapshot.d.checksums').writeAsString(JSON.encode({ - 'main.dart': '27f5ebf0f8c559b2af9419d190299a5e', - 'output.snapshot': 'd41d8cd98f00b204e9800998ecf8427e', - })); - await snapshotter.buildScriptSnapshot( - mainPath: 'main.dart', - snapshotPath: 'output.snapshot', - depfilePath: 'output.snapshot.d', - packagesPath: '.packages', - ); - - expect(genSnapshot.callCount, 0); - - final Map json = JSON.decode(await fs.file('output.snapshot.d.checksums').readAsString()); - expect(json, hasLength(2)); - expect(json['main.dart'], '27f5ebf0f8c559b2af9419d190299a5e'); - expect(json['output.snapshot'], 'd41d8cd98f00b204e9800998ecf8427e'); - }, overrides: { - FileSystem: () => fs, - GenSnapshot: () => genSnapshot, - }); - }); }