Unverified Commit 4a2ff649 authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Migrate file_store to null safety (#79111)

parent 6dcaeb3d
...@@ -2,13 +2,10 @@ ...@@ -2,13 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:collection'; import 'dart:collection';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:crypto/crypto.dart'; import 'package:crypto/crypto.dart';
import 'package:meta/meta.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/logger.dart'; import '../base/logger.dart';
...@@ -21,23 +18,26 @@ class FileStorage { ...@@ -21,23 +18,26 @@ class FileStorage {
FileStorage(this.version, this.files); FileStorage(this.version, this.files);
factory FileStorage.fromBuffer(Uint8List buffer) { factory FileStorage.fromBuffer(Uint8List buffer) {
final Map<String, dynamic> json = castStringKeyedMap(jsonDecode(utf8.decode(buffer))); final Map<String, dynamic>? json = castStringKeyedMap(jsonDecode(utf8.decode(buffer)));
if (json == null) {
throw Exception('File storage format invalid');
}
final int version = json['version'] as int; final int version = json['version'] as int;
final List<Map<String, Object>> rawCachedFiles = (json['files'] as List<dynamic>).cast<Map<String, Object>>(); final List<Map<String, Object>> rawCachedFiles = (json['files'] as List<dynamic>).cast<Map<String, Object>>();
final List<FileHash> cachedFiles = <FileHash>[ final List<_FileHash> cachedFiles = <_FileHash>[
for (final Map<String, Object> rawFile in rawCachedFiles) FileHash.fromJson(rawFile), for (final Map<String, Object> rawFile in rawCachedFiles) _FileHash._fromJson(rawFile),
]; ];
return FileStorage(version, cachedFiles); return FileStorage(version, cachedFiles);
} }
final int version; final int version;
final List<FileHash> files; final List<_FileHash> files;
List<int> toBuffer() { List<int> toBuffer() {
final Map<String, Object> json = <String, Object>{ final Map<String, Object> json = <String, Object>{
'version': version, 'version': version,
'files': <Object>[ 'files': <Object>[
for (final FileHash file in files) file.toJson(), for (final _FileHash file in files) file.toJson(),
], ],
}; };
return utf8.encode(jsonEncode(json)); return utf8.encode(jsonEncode(json));
...@@ -45,11 +45,14 @@ class FileStorage { ...@@ -45,11 +45,14 @@ class FileStorage {
} }
/// A stored file hash and path. /// A stored file hash and path.
class FileHash { class _FileHash {
FileHash(this.path, this.hash); _FileHash(this.path, this.hash);
factory FileHash.fromJson(Map<String, Object> json) { factory _FileHash._fromJson(Map<String, Object> json) {
return FileHash(json['path'] as String, json['hash'] as String); 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; final String path;
...@@ -88,8 +91,8 @@ enum FileStoreStrategy { ...@@ -88,8 +91,8 @@ enum FileStoreStrategy {
/// The format of the file store is subject to change and not part of its API. /// The format of the file store is subject to change and not part of its API.
class FileStore { class FileStore {
FileStore({ FileStore({
@required File cacheFile, required File cacheFile,
@required Logger logger, required Logger logger,
FileStoreStrategy strategy = FileStoreStrategy.hash, FileStoreStrategy strategy = FileStoreStrategy.hash,
}) : _logger = logger, }) : _logger = logger,
_strategy = strategy, _strategy = strategy,
...@@ -139,7 +142,7 @@ class FileStore { ...@@ -139,7 +142,7 @@ class FileStore {
_cacheFile.deleteSync(); _cacheFile.deleteSync();
return; return;
} }
for (final FileHash fileHash in fileStorage.files) { for (final _FileHash fileHash in fileStorage.files) {
previousAssetKeys[fileHash.path] = fileHash.hash; previousAssetKeys[fileHash.path] = fileHash.hash;
} }
_logger.printTrace('Done initializing file store'); _logger.printTrace('Done initializing file store');
...@@ -151,9 +154,9 @@ class FileStore { ...@@ -151,9 +154,9 @@ class FileStore {
if (!_cacheFile.existsSync()) { if (!_cacheFile.existsSync()) {
_cacheFile.createSync(recursive: true); _cacheFile.createSync(recursive: true);
} }
final List<FileHash> fileHashes = <FileHash>[]; final List<_FileHash> fileHashes = <_FileHash>[];
for (final MapEntry<String, String> entry in currentAssetKeys.entries) { for (final MapEntry<String, String> entry in currentAssetKeys.entries) {
fileHashes.add(FileHash(entry.key, entry.value)); fileHashes.add(_FileHash(entry.key, entry.value));
} }
final FileStorage fileStorage = FileStorage( final FileStorage fileStorage = FileStorage(
_kVersion, _kVersion,
...@@ -200,7 +203,7 @@ class FileStore { ...@@ -200,7 +203,7 @@ class FileStore {
void _checkModification(File file, List<File> dirty) { void _checkModification(File file, List<File> dirty) {
final String absolutePath = file.path; 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 the file is missing it is assumed to be dirty.
if (!file.existsSync()) { if (!file.existsSync()) {
...@@ -221,7 +224,7 @@ class FileStore { ...@@ -221,7 +224,7 @@ class FileStore {
void _hashFile(File file, List<File> dirty) { void _hashFile(File file, List<File> dirty) {
final String absolutePath = file.path; 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 the file is missing it is assumed to be dirty.
if (!file.existsSync()) { if (!file.existsSync()) {
currentAssetKeys.remove(absolutePath); currentAssetKeys.remove(absolutePath);
...@@ -231,7 +234,7 @@ class FileStore { ...@@ -231,7 +234,7 @@ class FileStore {
} }
final int fileBytes = file.lengthSync(); final int fileBytes = file.lengthSync();
final Md5Hash hash = Md5Hash(); final Md5Hash hash = Md5Hash();
RandomAccessFile openFile; RandomAccessFile? openFile;
try { try {
openFile = file.openSync(mode: FileMode.read); openFile = file.openSync(mode: FileMode.read);
int bytes = 0; int bytes = 0;
......
...@@ -103,6 +103,19 @@ void main() { ...@@ -103,6 +103,19 @@ void main() {
expect(fileStorage.files.single.path, file.path); 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 { testWithoutContext('FileStore handles persisting with a missing build directory', () async {
final FileSystem fileSystem = MemoryFileSystem.test(); final FileSystem fileSystem = MemoryFileSystem.test();
final File cacheFile = fileSystem final File cacheFile = fileSystem
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment