diff --git a/lib/core/file/file.dart b/lib/core/file/file.dart index 9acb2d24..c142732c 100644 --- a/lib/core/file/file.dart +++ b/lib/core/file/file.dart @@ -4,8 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -import 'dart:typed_data'; - import 'package:flutter/foundation.dart'; import 'package:dart_git/plumbing/git_hash.dart'; @@ -123,7 +121,7 @@ class File { static File fromProtoBuf(pb.File pbFile) { return File( repoPath: pbFile.repoPath, - oid: GitHash.fromBytes(Uint8List.fromList(pbFile.hash)), + oid: GitHash.fromBytes(pbFile.hash), filePath: pbFile.filePath, created: pbFile.created.toDateTime(), modified: pbFile.modified.toDateTime(), diff --git a/lib/core/file/file_storage_cache.dart b/lib/core/file/file_storage_cache.dart index cab1f831..3484c7d2 100644 --- a/lib/core/file/file_storage_cache.dart +++ b/lib/core/file/file_storage_cache.dart @@ -4,14 +4,13 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -import 'dart:typed_data'; - import 'package:dart_git/blob_ctime_builder.dart'; import 'package:dart_git/dart_git.dart'; import 'package:dart_git/file_mtime_builder.dart'; import 'package:dart_git/utils/date_time.dart'; import 'package:fixnum/fixnum.dart'; import 'package:path/path.dart' as p; +import 'package:tuple/tuple.dart'; import 'package:universal_io/io.dart' as io; import 'package:gitjournal/core/file/file.dart'; @@ -21,6 +20,7 @@ import 'package:gitjournal/logger/logger.dart'; class FileStorageCache { final String cacheFolderPath; + var lastProcessedHead = GitHash.zero(); FileStorageCache(this.cacheFolderPath) { assert(cacheFolderPath.startsWith(p.separator)); @@ -42,18 +42,26 @@ class FileStorageCache { } Future load(GitRepository gitRepo) async { - var blobVisitor = await _buildCTimeBuilder(); - var mTimeBuilder = await _buildMTimeBuilder(); + var blobVisitorTuple = await _buildCTimeBuilder(); + var mTimeBuilderTuple = await _buildMTimeBuilder(); + + lastProcessedHead = blobVisitorTuple.item2; + if (mTimeBuilderTuple.item2 != lastProcessedHead) { + lastProcessedHead = GitHash.zero(); + } return FileStorage( gitRepo: gitRepo, - blobCTimeBuilder: blobVisitor, - fileMTimeBuilder: mTimeBuilder, + blobCTimeBuilder: blobVisitorTuple.item1, + fileMTimeBuilder: mTimeBuilderTuple.item1, ); } Future> save(FileStorage fileStorage) async { return catchAll(() async { + var headR = await fileStorage.gitRepo.headHash(); + lastProcessedHead = headR.isFailure ? GitHash.zero() : headR.getOrThrow(); + await _saveCTime(fileStorage.blobCTimeBuilder); await _saveMTime(fileStorage.fileMTimeBuilder); return Result(null); @@ -63,12 +71,12 @@ class FileStorageCache { String get _cTimeFilePath => p.join(cacheFolderPath, 'blob_ctime_v1'); String get _mTimeFilePath => p.join(cacheFolderPath, 'file_mtime_v1'); - Future _buildCTimeBuilder() async { + Future> _buildCTimeBuilder() async { var file = io.File(_cTimeFilePath); var stat = file.statSync(); if (stat.type == io.FileSystemEntityType.notFound) { - return BlobCTimeBuilder(); + return Tuple2(BlobCTimeBuilder(), GitHash.zero()); } var size = (stat.size / 1024).toStringAsFixed(2); @@ -77,30 +85,29 @@ class FileStorageCache { var buffer = await file.readAsBytes(); var data = pb.BlobCTimeBuilderData.fromBuffer(buffer); - var commitHashes = data.commitHashes - .map((bytes) => GitHash.fromBytes(Uint8List.fromList(bytes))) - .toSet(); + var commitHashes = + data.commitHashes.map((bytes) => GitHash.fromBytes(bytes)).toSet(); - var treeHashes = data.treeHashes - .map((bytes) => GitHash.fromBytes(Uint8List.fromList(bytes))) - .toSet(); + var treeHashes = + data.treeHashes.map((bytes) => GitHash.fromBytes(bytes)).toSet(); var map = data.map .map((hashStr, pbDt) => MapEntry(GitHash(hashStr), _fromProto(pbDt))); - return BlobCTimeBuilder( + var builder = BlobCTimeBuilder( processedCommits: commitHashes, processedTrees: treeHashes, map: map, ); + return Tuple2(builder, GitHash.fromBytes(data.headHash)); } - Future _buildMTimeBuilder() async { + Future> _buildMTimeBuilder() async { var file = io.File(_mTimeFilePath); var stat = file.statSync(); if (stat.type == io.FileSystemEntityType.notFound) { - return FileMTimeBuilder(); + return Tuple2(FileMTimeBuilder(), GitHash.zero()); } var size = (stat.size / 1024).toStringAsFixed(2); @@ -109,19 +116,19 @@ class FileStorageCache { var buffer = await file.readAsBytes(); var data = pb.FileMTimeBuilderData.fromBuffer(buffer); - var commitHashes = data.commitHashes - .map((bytes) => GitHash.fromBytes(Uint8List.fromList(bytes))) - .toSet(); + var commitHashes = + data.commitHashes.map((bytes) => GitHash.fromBytes(bytes)).toSet(); var map = data.map.map((filePath, pbInfo) { - var hash = GitHash.fromBytes(Uint8List.fromList(pbInfo.hash)); + var hash = GitHash.fromBytes(pbInfo.hash); var dt = _fromProto(pbInfo.dt); var info = FileMTimeInfo(pbInfo.filePath, hash, dt); return MapEntry(filePath, info); }); - return FileMTimeBuilder(processedCommits: commitHashes, map: map); + var builder = FileMTimeBuilder(processedCommits: commitHashes, map: map); + return Tuple2(builder, GitHash.fromBytes(data.headHash)); } Future _saveCTime(BlobCTimeBuilder builder) async { @@ -136,6 +143,7 @@ class FileStorageCache { }); var data = pb.BlobCTimeBuilderData( + headHash: lastProcessedHead.bytes, commitHashes: commitHashes, treeHashes: treeHashes, map: map, @@ -162,7 +170,11 @@ class FileStorageCache { return MapEntry(filePath, info); }); - var data = pb.FileMTimeBuilderData(commitHashes: commitHashes, map: map); + var data = pb.FileMTimeBuilderData( + headHash: lastProcessedHead.bytes, + commitHashes: commitHashes, + map: map, + ); var file = io.File(_mTimeFilePath); var _ = await file.writeAsBytes(data.writeToBuffer()); diff --git a/lib/generated/builders.pb.dart b/lib/generated/builders.pb.dart index eaaa5aaa..741ed477 100644 --- a/lib/generated/builders.pb.dart +++ b/lib/generated/builders.pb.dart @@ -48,6 +48,13 @@ class BlobCTimeBuilderData extends $pb.GeneratedMessage { valueFieldType: $pb.PbFieldType.OM, valueCreator: TzDateTime.create, packageName: const $pb.PackageName('gitjournal')) + ..a<$core.List<$core.int>>( + 4, + const $core.bool.fromEnvironment('protobuf.omit_field_names') + ? '' + : 'headHash', + $pb.PbFieldType.OY, + protoName: 'headHash') ..hasRequiredFields = false; BlobCTimeBuilderData._() : super(); @@ -55,6 +62,7 @@ class BlobCTimeBuilderData extends $pb.GeneratedMessage { $core.Iterable<$core.List<$core.int>>? commitHashes, $core.Iterable<$core.List<$core.int>>? treeHashes, $core.Map<$core.String, TzDateTime>? map, + $core.List<$core.int>? headHash, }) { final _result = create(); if (commitHashes != null) { @@ -66,6 +74,9 @@ class BlobCTimeBuilderData extends $pb.GeneratedMessage { if (map != null) { _result.map.addAll(map); } + if (headHash != null) { + _result.headHash = headHash; + } return _result; } factory BlobCTimeBuilderData.fromBuffer($core.List<$core.int> i, @@ -104,6 +115,18 @@ class BlobCTimeBuilderData extends $pb.GeneratedMessage { @$pb.TagNumber(3) $core.Map<$core.String, TzDateTime> get map => $_getMap(2); + + @$pb.TagNumber(4) + $core.List<$core.int> get headHash => $_getN(3); + @$pb.TagNumber(4) + set headHash($core.List<$core.int> v) { + $_setBytes(3, v); + } + + @$pb.TagNumber(4) + $core.bool hasHeadHash() => $_has(3); + @$pb.TagNumber(4) + void clearHeadHash() => clearField(4); } class FileMTimeBuilderData extends $pb.GeneratedMessage { @@ -133,12 +156,20 @@ class FileMTimeBuilderData extends $pb.GeneratedMessage { valueFieldType: $pb.PbFieldType.OM, valueCreator: FileMTimeInfo.create, packageName: const $pb.PackageName('gitjournal')) + ..a<$core.List<$core.int>>( + 4, + const $core.bool.fromEnvironment('protobuf.omit_field_names') + ? '' + : 'headHash', + $pb.PbFieldType.OY, + protoName: 'headHash') ..hasRequiredFields = false; FileMTimeBuilderData._() : super(); factory FileMTimeBuilderData({ $core.Iterable<$core.List<$core.int>>? commitHashes, $core.Map<$core.String, FileMTimeInfo>? map, + $core.List<$core.int>? headHash, }) { final _result = create(); if (commitHashes != null) { @@ -147,6 +178,9 @@ class FileMTimeBuilderData extends $pb.GeneratedMessage { if (map != null) { _result.map.addAll(map); } + if (headHash != null) { + _result.headHash = headHash; + } return _result; } factory FileMTimeBuilderData.fromBuffer($core.List<$core.int> i, @@ -182,6 +216,18 @@ class FileMTimeBuilderData extends $pb.GeneratedMessage { @$pb.TagNumber(3) $core.Map<$core.String, FileMTimeInfo> get map => $_getMap(1); + + @$pb.TagNumber(4) + $core.List<$core.int> get headHash => $_getN(2); + @$pb.TagNumber(4) + set headHash($core.List<$core.int> v) { + $_setBytes(2, v); + } + + @$pb.TagNumber(4) + $core.bool hasHeadHash() => $_has(2); + @$pb.TagNumber(4) + void clearHeadHash() => clearField(4); } class TzDateTime extends $pb.GeneratedMessage { diff --git a/lib/generated/builders.pbjson.dart b/lib/generated/builders.pbjson.dart index d8fca2d6..fa4a88fe 100644 --- a/lib/generated/builders.pbjson.dart +++ b/lib/generated/builders.pbjson.dart @@ -27,6 +27,7 @@ const BlobCTimeBuilderData$json = const { '6': '.gitjournal.BlobCTimeBuilderData.MapEntry', '10': 'map' }, + const {'1': 'headHash', '3': 4, '4': 1, '5': 12, '10': 'headHash'}, ], '3': const [BlobCTimeBuilderData_MapEntry$json], }; @@ -50,7 +51,7 @@ const BlobCTimeBuilderData_MapEntry$json = const { /// Descriptor for `BlobCTimeBuilderData`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List blobCTimeBuilderDataDescriptor = $convert.base64Decode( - 'ChRCbG9iQ1RpbWVCdWlsZGVyRGF0YRIiCgxjb21taXRIYXNoZXMYASADKAxSDGNvbW1pdEhhc2hlcxIeCgp0cmVlSGFzaGVzGAIgAygMUgp0cmVlSGFzaGVzEjsKA21hcBgDIAMoCzIpLmdpdGpvdXJuYWwuQmxvYkNUaW1lQnVpbGRlckRhdGEuTWFwRW50cnlSA21hcBpOCghNYXBFbnRyeRIQCgNrZXkYASABKAlSA2tleRIsCgV2YWx1ZRgCIAEoCzIWLmdpdGpvdXJuYWwuVHpEYXRlVGltZVIFdmFsdWU6AjgB'); + 'ChRCbG9iQ1RpbWVCdWlsZGVyRGF0YRIiCgxjb21taXRIYXNoZXMYASADKAxSDGNvbW1pdEhhc2hlcxIeCgp0cmVlSGFzaGVzGAIgAygMUgp0cmVlSGFzaGVzEjsKA21hcBgDIAMoCzIpLmdpdGpvdXJuYWwuQmxvYkNUaW1lQnVpbGRlckRhdGEuTWFwRW50cnlSA21hcBIaCghoZWFkSGFzaBgEIAEoDFIIaGVhZEhhc2gaTgoITWFwRW50cnkSEAoDa2V5GAEgASgJUgNrZXkSLAoFdmFsdWUYAiABKAsyFi5naXRqb3VybmFsLlR6RGF0ZVRpbWVSBXZhbHVlOgI4AQ=='); @$core.Deprecated('Use fileMTimeBuilderDataDescriptor instead') const FileMTimeBuilderData$json = const { '1': 'FileMTimeBuilderData', @@ -64,6 +65,7 @@ const FileMTimeBuilderData$json = const { '6': '.gitjournal.FileMTimeBuilderData.MapEntry', '10': 'map' }, + const {'1': 'headHash', '3': 4, '4': 1, '5': 12, '10': 'headHash'}, ], '3': const [FileMTimeBuilderData_MapEntry$json], }; @@ -87,7 +89,7 @@ const FileMTimeBuilderData_MapEntry$json = const { /// Descriptor for `FileMTimeBuilderData`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List fileMTimeBuilderDataDescriptor = $convert.base64Decode( - 'ChRGaWxlTVRpbWVCdWlsZGVyRGF0YRIiCgxjb21taXRIYXNoZXMYASADKAxSDGNvbW1pdEhhc2hlcxI7CgNtYXAYAyADKAsyKS5naXRqb3VybmFsLkZpbGVNVGltZUJ1aWxkZXJEYXRhLk1hcEVudHJ5UgNtYXAaUQoITWFwRW50cnkSEAoDa2V5GAEgASgJUgNrZXkSLwoFdmFsdWUYAiABKAsyGS5naXRqb3VybmFsLkZpbGVNVGltZUluZm9SBXZhbHVlOgI4AQ=='); + 'ChRGaWxlTVRpbWVCdWlsZGVyRGF0YRIiCgxjb21taXRIYXNoZXMYASADKAxSDGNvbW1pdEhhc2hlcxI7CgNtYXAYAyADKAsyKS5naXRqb3VybmFsLkZpbGVNVGltZUJ1aWxkZXJEYXRhLk1hcEVudHJ5UgNtYXASGgoIaGVhZEhhc2gYBCABKAxSCGhlYWRIYXNoGlEKCE1hcEVudHJ5EhAKA2tleRgBIAEoCVIDa2V5Ei8KBXZhbHVlGAIgASgLMhkuZ2l0am91cm5hbC5GaWxlTVRpbWVJbmZvUgV2YWx1ZToCOAE='); @$core.Deprecated('Use tzDateTimeDescriptor instead') const TzDateTime$json = const { '1': 'TzDateTime', diff --git a/lib/repository.dart b/lib/repository.dart index 10256ef3..c90a2343 100644 --- a/lib/repository.dart +++ b/lib/repository.dart @@ -13,6 +13,7 @@ import 'package:collection/collection.dart'; import 'package:dart_git/config.dart'; import 'package:dart_git/dart_git.dart'; import 'package:dart_git/exceptions.dart'; +import 'package:dart_git/plumbing/git_hash.dart'; import 'package:git_bindings/git_bindings.dart'; import 'package:path/path.dart' as p; import 'package:sentry_flutter/sentry_flutter.dart'; @@ -78,7 +79,7 @@ class GitJournalRepo with ChangeNotifier { late NotesFolderFS notesFolder; bool remoteGitRepoConfigured = false; - bool fileStorageCacheReady = false; + late bool fileStorageCacheReady; static Future load( {required String gitBaseDir, @@ -152,6 +153,9 @@ class GitJournalRepo with ChangeNotifier { var fileStorageCache = FileStorageCache(cacheDir); var fileStorage = await fileStorageCache.load(repo); + var headR = await repo.headHash(); + var head = headR.isFailure ? GitHash.zero() : headR.getOrThrow(); + return GitJournalRepo._internal( repoPath: repoPath, gitBaseDirectory: gitBaseDir, @@ -165,6 +169,7 @@ class GitJournalRepo with ChangeNotifier { fileStorage: fileStorage, fileStorageCache: fileStorageCache, currentBranch: await repo.currentBranch().getOrThrow(), + headHash: head, ); } @@ -181,6 +186,7 @@ class GitJournalRepo with ChangeNotifier { required this.fileStorage, required this.fileStorageCache, required String? currentBranch, + required GitHash headHash, }) { _gitRepo = GitNoteRepository(gitRepoPath: repoPath, config: gitConfig); notesFolder = NotesFolderFS.root(folderConfig, fileStorage); @@ -202,6 +208,8 @@ class GitJournalRepo with ChangeNotifier { fileStorage: fileStorage, ); + fileStorageCacheReady = headHash == fileStorageCache.lastProcessedHead; + _loadFromCache(); _syncNotes(); } @@ -277,7 +285,7 @@ class GitJournalRepo with ChangeNotifier { // Notify that the cache is ready Log.i("Done building the FileStorageCache"); - fileStorageCacheReady = true; + fileStorageCacheReady = fileStorageCache.lastProcessedHead == head; notifyListeners(); } diff --git a/protos/builders.proto b/protos/builders.proto index d43f142d..f49d7803 100644 --- a/protos/builders.proto +++ b/protos/builders.proto @@ -12,11 +12,15 @@ message BlobCTimeBuilderData { repeated bytes commitHashes = 1; repeated bytes treeHashes = 2; map map = 3; + + bytes headHash = 4; } message FileMTimeBuilderData { repeated bytes commitHashes = 1; map map = 3; + + bytes headHash = 4; } message TzDateTime { diff --git a/pubspec.lock b/pubspec.lock index b722c5a2..4a2faad7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -328,7 +328,7 @@ packages: description: path: "." ref: HEAD - resolved-ref: "0369ae80dfde703b3a22ade5adf350800d649153" + resolved-ref: "6d4b7f26bc2c7b8c83ec7f608fe05eec561d6757" url: "https://github.com/GitJournal/dart-git.git" source: git version: "0.0.2"