From 4a2ff6490f9864836b2eb3349086755dc0bc3db9 Mon Sep 17 00:00:00 2001 From: Jenn Magder Date: Mon, 29 Mar 2021 20:44:05 -0700 Subject: [PATCH] Migrate file_store to null safety (#79111) --- .../lib/src/build_system/file_store.dart | 43 ++++++++++--------- .../build_system/file_store_test.dart | 13 ++++++ 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/packages/flutter_tools/lib/src/build_system/file_store.dart b/packages/flutter_tools/lib/src/build_system/file_store.dart index dab105497f5..f42f641a1b9 100644 --- a/packages/flutter_tools/lib/src/build_system/file_store.dart +++ b/packages/flutter_tools/lib/src/build_system/file_store.dart @@ -2,13 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:collection'; import 'dart:typed_data'; import 'package:crypto/crypto.dart'; -import 'package:meta/meta.dart'; import '../base/file_system.dart'; import '../base/logger.dart'; @@ -21,23 +18,26 @@ class FileStorage { FileStorage(this.version, this.files); factory FileStorage.fromBuffer(Uint8List buffer) { - final Map json = castStringKeyedMap(jsonDecode(utf8.decode(buffer))); + final Map? json = castStringKeyedMap(jsonDecode(utf8.decode(buffer))); + if (json == null) { + throw Exception('File storage format invalid'); + } final int version = json['version'] as int; final List> rawCachedFiles = (json['files'] as List).cast>(); - final List cachedFiles = [ - for (final Map rawFile in rawCachedFiles) FileHash.fromJson(rawFile), + final List<_FileHash> cachedFiles = <_FileHash>[ + for (final Map rawFile in rawCachedFiles) _FileHash._fromJson(rawFile), ]; return FileStorage(version, cachedFiles); } final int version; - final List files; + final List<_FileHash> files; List toBuffer() { final Map json = { 'version': version, 'files': [ - for (final FileHash file in files) file.toJson(), + for (final _FileHash file in files) file.toJson(), ], }; return utf8.encode(jsonEncode(json)); @@ -45,11 +45,14 @@ class FileStorage { } /// A stored file hash and path. -class FileHash { - FileHash(this.path, this.hash); +class _FileHash { + _FileHash(this.path, this.hash); - factory FileHash.fromJson(Map json) { - return FileHash(json['path'] as String, json['hash'] as String); + factory _FileHash._fromJson(Map json) { + if (!json.containsKey('path') || !json.containsKey('hash')) { + throw Exception('File storage format invalid'); + } + return _FileHash(json['path']! as String, json['hash']! as String); } final String path; @@ -88,8 +91,8 @@ enum FileStoreStrategy { /// The format of the file store is subject to change and not part of its API. class FileStore { FileStore({ - @required File cacheFile, - @required Logger logger, + required File cacheFile, + required Logger logger, FileStoreStrategy strategy = FileStoreStrategy.hash, }) : _logger = logger, _strategy = strategy, @@ -139,7 +142,7 @@ class FileStore { _cacheFile.deleteSync(); return; } - for (final FileHash fileHash in fileStorage.files) { + for (final _FileHash fileHash in fileStorage.files) { previousAssetKeys[fileHash.path] = fileHash.hash; } _logger.printTrace('Done initializing file store'); @@ -151,9 +154,9 @@ class FileStore { if (!_cacheFile.existsSync()) { _cacheFile.createSync(recursive: true); } - final List fileHashes = []; + final List<_FileHash> fileHashes = <_FileHash>[]; for (final MapEntry entry in currentAssetKeys.entries) { - fileHashes.add(FileHash(entry.key, entry.value)); + fileHashes.add(_FileHash(entry.key, entry.value)); } final FileStorage fileStorage = FileStorage( _kVersion, @@ -200,7 +203,7 @@ class FileStore { void _checkModification(File file, List dirty) { final String absolutePath = file.path; - final String previousTime = previousAssetKeys[absolutePath]; + final String? previousTime = previousAssetKeys[absolutePath]; // If the file is missing it is assumed to be dirty. if (!file.existsSync()) { @@ -221,7 +224,7 @@ class FileStore { void _hashFile(File file, List dirty) { final String absolutePath = file.path; - final String previousHash = previousAssetKeys[absolutePath]; + final String? previousHash = previousAssetKeys[absolutePath]; // If the file is missing it is assumed to be dirty. if (!file.existsSync()) { currentAssetKeys.remove(absolutePath); @@ -231,7 +234,7 @@ class FileStore { } final int fileBytes = file.lengthSync(); final Md5Hash hash = Md5Hash(); - RandomAccessFile openFile; + RandomAccessFile? openFile; try { openFile = file.openSync(mode: FileMode.read); int bytes = 0; diff --git a/packages/flutter_tools/test/general.shard/build_system/file_store_test.dart b/packages/flutter_tools/test/general.shard/build_system/file_store_test.dart index dbfdab84e2e..bd3d8505470 100644 --- a/packages/flutter_tools/test/general.shard/build_system/file_store_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/file_store_test.dart @@ -103,6 +103,19 @@ void main() { expect(fileStorage.files.single.path, file.path); }); + testWithoutContext('FileStore handles changed format', () async { + final FileSystem fileSystem = MemoryFileSystem.test(); + final File cacheFile = fileSystem.file(FileStore.kFileCache)..writeAsStringSync( + '{"version":1,"files":[{"path_old":"foo.dart","hash_old":"f95b70fdc3088560732a5ac135644506"}]}'); + final FileStore fileCache = FileStore( + cacheFile: cacheFile, + logger: BufferLogger.test(), + ); + + fileCache.initialize(); + expect(cacheFile, isNot(exists)); + }); + testWithoutContext('FileStore handles persisting with a missing build directory', () async { final FileSystem fileSystem = MemoryFileSystem.test(); final File cacheFile = fileSystem