mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-05-17 12:45:58 +08:00
Upgrade to latest dart-git
Most of dart-git's operations are synchronous by default now. The async functions run on another isolate.
This commit is contained in:
@ -4,15 +4,20 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:dart_git/blob_ctime_builder.dart';
|
||||
import 'package:dart_git/dart_git.dart';
|
||||
import 'package:dart_git/exceptions.dart';
|
||||
import 'package:dart_git/file_mtime_builder.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:tuple/tuple.dart';
|
||||
import 'package:universal_io/io.dart' as io;
|
||||
|
||||
import 'package:gitjournal/error_reporting.dart';
|
||||
import 'package:gitjournal/logger/logger.dart';
|
||||
import 'file.dart';
|
||||
|
||||
@ -25,21 +30,7 @@ class FileStorage with ChangeNotifier {
|
||||
var _dateTime = DateTime.now();
|
||||
DateTime get dateTime => _dateTime;
|
||||
|
||||
TreeEntryVisitor get visitor {
|
||||
return MultiTreeEntryVisitor(
|
||||
[
|
||||
blobCTimeBuilder,
|
||||
fileMTimeBuilder,
|
||||
],
|
||||
afterCommitCallback: (commit) {
|
||||
var commitDt = commit.author.date;
|
||||
if (commitDt.isBefore(_dateTime)) {
|
||||
_dateTime = commitDt;
|
||||
}
|
||||
notifyListeners();
|
||||
},
|
||||
);
|
||||
}
|
||||
var head = GitHash.zero();
|
||||
|
||||
FileStorage({
|
||||
required String repoPath,
|
||||
@ -96,20 +87,50 @@ class FileStorage with ChangeNotifier {
|
||||
));
|
||||
}
|
||||
|
||||
Future<void> fill() async {
|
||||
var rp = ReceivePort();
|
||||
rp.listen((d) {
|
||||
if (d is DateTime) {
|
||||
_dateTime = d;
|
||||
notifyListeners();
|
||||
}
|
||||
});
|
||||
|
||||
var resp = await compute(
|
||||
_fillFileStorage,
|
||||
_FillFileStorageParams(
|
||||
rp.sendPort,
|
||||
repoPath,
|
||||
blobCTimeBuilder,
|
||||
fileMTimeBuilder,
|
||||
),
|
||||
);
|
||||
rp.close();
|
||||
|
||||
// FIXME: Handle this case of having an error!
|
||||
assert(resp != null);
|
||||
if (resp == null) return;
|
||||
|
||||
blobCTimeBuilder.update(resp.item1);
|
||||
fileMTimeBuilder.update(resp.item2);
|
||||
head = resp.item3;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
static Future<FileStorage> fake(String rootFolder) async {
|
||||
assert(rootFolder.startsWith(p.separator));
|
||||
|
||||
await GitRepository.init(rootFolder).throwOnError();
|
||||
GitRepository.init(rootFolder).throwOnError();
|
||||
|
||||
var blobVisitor = BlobCTimeBuilder();
|
||||
var mTimeBuilder = FileMTimeBuilder();
|
||||
|
||||
var repo = await GitRepository.load(rootFolder).getOrThrow();
|
||||
var result = await repo.headHash();
|
||||
var repo = GitRepository.load(rootFolder).getOrThrow();
|
||||
var result = repo.headHash();
|
||||
if (result.isSuccess) {
|
||||
var multi = MultiTreeEntryVisitor([blobVisitor, mTimeBuilder]);
|
||||
await repo
|
||||
repo
|
||||
.visitTree(fromCommitHash: result.getOrThrow(), visitor: multi)
|
||||
.throwOnError();
|
||||
}
|
||||
@ -128,17 +149,7 @@ class FileStorage with ChangeNotifier {
|
||||
|
||||
@visibleForTesting
|
||||
Future<Result<void>> reload() async {
|
||||
var gitRepo = await GitRepository.load(repoPath).getOrThrow();
|
||||
var result = await gitRepo.headHash();
|
||||
if (result.isFailure) {
|
||||
return fail(result);
|
||||
}
|
||||
var headHash = result.getOrThrow();
|
||||
|
||||
var multi = MultiTreeEntryVisitor([blobCTimeBuilder, fileMTimeBuilder]);
|
||||
await gitRepo
|
||||
.visitTree(fromCommitHash: headHash, visitor: multi)
|
||||
.throwOnError();
|
||||
await fill();
|
||||
return Result(null);
|
||||
}
|
||||
}
|
||||
@ -147,3 +158,53 @@ class FileStorageCacheIncomplete implements Exception {
|
||||
final String path;
|
||||
FileStorageCacheIncomplete(this.path);
|
||||
}
|
||||
|
||||
typedef _FillFileStorageParams
|
||||
= Tuple4<SendPort, String, BlobCTimeBuilder, FileMTimeBuilder>;
|
||||
|
||||
typedef _FillFileStorageOutput
|
||||
= Tuple3<BlobCTimeBuilder, FileMTimeBuilder, GitHash>;
|
||||
|
||||
_FillFileStorageOutput? _fillFileStorage(_FillFileStorageParams params) {
|
||||
var sendPort = params.item1;
|
||||
var repoPath = params.item2;
|
||||
var blobCTimeBuilder = params.item3;
|
||||
var fileMTimeBuilder = params.item4;
|
||||
|
||||
var dateTime = DateTime.now();
|
||||
var visitor = MultiTreeEntryVisitor(
|
||||
[blobCTimeBuilder, fileMTimeBuilder],
|
||||
afterCommitCallback: (commit) {
|
||||
var commitDt = commit.author.date;
|
||||
if (commitDt.isBefore(dateTime)) {
|
||||
dateTime = commitDt;
|
||||
sendPort.send(dateTime);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
var gitRepo = GitRepository.load(repoPath).getOrThrow();
|
||||
var headR = gitRepo.headHash();
|
||||
if (headR.isFailure) {
|
||||
if (headR.error is GitRefNotFound) {
|
||||
// No commits
|
||||
// fileStorageCacheReady = true;
|
||||
// notifyListeners();
|
||||
// FIXME: Send a signal saying its done
|
||||
return _FillFileStorageOutput(
|
||||
blobCTimeBuilder, fileMTimeBuilder, GitHash.zero());
|
||||
}
|
||||
Log.e("Failed to fetch HEAD", result: headR);
|
||||
return null;
|
||||
}
|
||||
var head = headR.getOrThrow();
|
||||
Log.d("Got HEAD: $head");
|
||||
|
||||
var result = gitRepo.visitTree(fromCommitHash: head, visitor: visitor);
|
||||
if (result.isFailure) {
|
||||
Log.e("Failed to build FileStorage cache", result: result);
|
||||
logException(result.exception!, result.stackTrace!);
|
||||
}
|
||||
|
||||
return _FillFileStorageOutput(blobCTimeBuilder, fileMTimeBuilder, head);
|
||||
}
|
||||
|
@ -66,9 +66,7 @@ class FileStorageCache {
|
||||
|
||||
Future<Result<void>> save(FileStorage fileStorage) async {
|
||||
return catchAll(() async {
|
||||
var repo = await GitRepository.load(fileStorage.repoPath).getOrThrow();
|
||||
var headR = await repo.headHash();
|
||||
lastProcessedHead = headR.isFailure ? GitHash.zero() : headR.getOrThrow();
|
||||
lastProcessedHead = fileStorage.head;
|
||||
|
||||
var blobCTimeBuilder = fileStorage.blobCTimeBuilder;
|
||||
var fileMTimeBUilder = fileStorage.fileMTimeBuilder;
|
||||
@ -83,7 +81,7 @@ class FileStorageCache {
|
||||
}
|
||||
|
||||
String get _cTimeFilePath => p.join(cacheFolderPath, 'blob_ctime_v1');
|
||||
String get _mTimeFilePath => p.join(cacheFolderPath, 'file_mtime_v1');
|
||||
String get _mTimeFilePath => p.join(cacheFolderPath, 'file_mtime_v2');
|
||||
|
||||
Future<Tuple2<BlobCTimeBuilder, GitHash>> _buildCTimeBuilder() async {
|
||||
var file = io.File(_cTimeFilePath);
|
||||
|
@ -24,6 +24,9 @@ import 'package:gitjournal/utils/git_desktop.dart';
|
||||
|
||||
bool useDartGit = false;
|
||||
|
||||
// FIXME: Remember to close all the opened repos!!
|
||||
// FIXME: Micro optimization? Avoid re-creating the GitAsyncRepository!
|
||||
|
||||
class GitNoteRepository {
|
||||
final String gitRepoPath;
|
||||
final gb.GitRepo _gitRepo;
|
||||
@ -43,7 +46,7 @@ class GitNoteRepository {
|
||||
|
||||
Future<Result<void>> _add(String pathSpec) async {
|
||||
if (useDartGit || AppConfig.instance.experimentalGitOps) {
|
||||
var repo = await GitRepository.load(gitRepoPath).getOrThrow();
|
||||
var repo = await GitAsyncRepository.load(gitRepoPath).getOrThrow();
|
||||
await repo.add(pathSpec).throwOnError();
|
||||
return Result(null);
|
||||
} else {
|
||||
@ -59,7 +62,7 @@ class GitNoteRepository {
|
||||
|
||||
Future<Result<void>> _rm(String pathSpec) async {
|
||||
if (useDartGit || AppConfig.instance.experimentalGitOps) {
|
||||
var repo = await GitRepository.load(gitRepoPath).getOrThrow();
|
||||
var repo = await GitAsyncRepository.load(gitRepoPath).getOrThrow();
|
||||
return await repo.rm(pathSpec);
|
||||
} else {
|
||||
try {
|
||||
@ -78,7 +81,7 @@ class GitNoteRepository {
|
||||
required String authorName,
|
||||
}) async {
|
||||
if (useDartGit || AppConfig.instance.experimentalGitOps) {
|
||||
var repo = await GitRepository.load(gitRepoPath).getOrThrow();
|
||||
var repo = await GitAsyncRepository.load(gitRepoPath).getOrThrow();
|
||||
var author = GitAuthor(name: authorName, email: authorEmail);
|
||||
var r = await repo.commit(message: message, author: author);
|
||||
if (r.isFailure) {
|
||||
@ -209,7 +212,7 @@ class GitNoteRepository {
|
||||
|
||||
Future<Result<void>> resetLastCommit() async {
|
||||
if (useDartGit || AppConfig.instance.experimentalGitOps) {
|
||||
var repo = await GitRepository.load(gitRepoPath).getOrThrow();
|
||||
var repo = await GitAsyncRepository.load(gitRepoPath).getOrThrow();
|
||||
var headCommitR = await repo.headCommit();
|
||||
if (headCommitR.isFailure) {
|
||||
return fail(headCommitR);
|
||||
@ -268,7 +271,7 @@ class GitNoteRepository {
|
||||
Future<Result<void>> merge() => catchAll(_merge);
|
||||
|
||||
Future<Result<void>> _merge() async {
|
||||
var repo = await GitRepository.load(gitRepoPath).getOrThrow();
|
||||
var repo = await GitAsyncRepository.load(gitRepoPath).getOrThrow();
|
||||
var branch = await repo.currentBranch().getOrThrow();
|
||||
|
||||
var branchConfig = repo.config.branch(branch);
|
||||
@ -316,7 +319,7 @@ class GitNoteRepository {
|
||||
Future<Result<void>> push() async {
|
||||
// Only push if we have something we need to push
|
||||
try {
|
||||
var repo = await GitRepository.load(gitRepoPath).getOrThrow();
|
||||
var repo = await GitAsyncRepository.load(gitRepoPath).getOrThrow();
|
||||
var canPush = await repo.canPush().getOrThrow();
|
||||
if (!canPush) {
|
||||
return Result(null);
|
||||
@ -365,7 +368,7 @@ class GitNoteRepository {
|
||||
|
||||
Future<int?> numChanges() async {
|
||||
try {
|
||||
var repo = await GitRepository.load(gitRepoPath).getOrThrow();
|
||||
var repo = await GitAsyncRepository.load(gitRepoPath).getOrThrow();
|
||||
var nResult = await repo.numChangesToPush();
|
||||
if (nResult.isSuccess) {
|
||||
return nResult.getOrThrow();
|
||||
|
@ -7,6 +7,7 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
|
||||
import 'package:dart_git/dart_git.dart';
|
||||
import 'package:dart_git/diff_commit.dart';
|
||||
@ -43,10 +44,10 @@ class _CommitDataWidgetState extends State<CommitDataWidget> {
|
||||
_initStateAsync();
|
||||
}
|
||||
|
||||
Future<void> _initStateAsync() async {
|
||||
void _initStateAsync() {
|
||||
// FIXME: Run all of this in another worker thread!
|
||||
|
||||
var r = await diffCommits(
|
||||
var r = diffCommits(
|
||||
fromCommit: widget.parentCommit,
|
||||
toCommit: widget.commit,
|
||||
objStore: widget.gitRepo.objStorage,
|
||||
@ -54,7 +55,7 @@ class _CommitDataWidgetState extends State<CommitDataWidget> {
|
||||
if (r.isFailure) {
|
||||
Log.e("Got exception in diffCommits",
|
||||
ex: r.error, stacktrace: r.stackTrace);
|
||||
return setState(() {
|
||||
setState(() {
|
||||
_exception = r.exception;
|
||||
});
|
||||
}
|
||||
@ -131,11 +132,11 @@ class __BlobLoaderState extends State<_BlobLoader> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_initStateAsync();
|
||||
SchedulerBinding.instance!.addPostFrameCallback((_) => _initStateAsync);
|
||||
}
|
||||
|
||||
Future<void> _initStateAsync() async {
|
||||
var result = await widget.gitRepo.objStorage.readBlob(widget.blobHash);
|
||||
void _initStateAsync() {
|
||||
var result = widget.gitRepo.objStorage.readBlob(widget.blobHash);
|
||||
setState(() {
|
||||
_exception = result.exception;
|
||||
_blob = result.data;
|
||||
|
@ -8,7 +8,7 @@ import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:dart_git/git.dart';
|
||||
import 'package:dart_git/dart_git.dart';
|
||||
import 'package:dart_git/plumbing/commit_iterator.dart';
|
||||
import 'package:dart_git/plumbing/objects/commit.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
@ -59,7 +59,7 @@ class _HistoryWidgetState extends State<HistoryWidget> {
|
||||
List<Result<GitCommit>> commits = [];
|
||||
List<dynamic> commitsAndSyncAttempts = [];
|
||||
|
||||
Stream<Result<GitCommit>>? _stream;
|
||||
Iterable<Result<GitCommit>>? _stream;
|
||||
|
||||
final _scrollController = ScrollController();
|
||||
final _lock = Lock();
|
||||
@ -109,7 +109,7 @@ class _HistoryWidgetState extends State<HistoryWidget> {
|
||||
var stream = _stream!;
|
||||
|
||||
var list = <Result<GitCommit>>[];
|
||||
await for (var commit in stream.take(20)) {
|
||||
for (var commit in stream.take(20)) {
|
||||
list.add(commit);
|
||||
}
|
||||
|
||||
@ -120,20 +120,19 @@ class _HistoryWidgetState extends State<HistoryWidget> {
|
||||
});
|
||||
}
|
||||
|
||||
Future<Stream<Result<GitCommit>>> _initStream() async {
|
||||
Future<Iterable<Result<GitCommit>>> _initStream() async {
|
||||
try {
|
||||
_gitRepo = await GitRepository.load(widget.repoPath).getOrThrow();
|
||||
var head = await _gitRepo!.headHash().getOrThrow();
|
||||
_gitRepo = GitRepository.load(widget.repoPath).getOrThrow();
|
||||
var head = _gitRepo!.headHash().getOrThrow();
|
||||
return commitPreOrderIterator(
|
||||
objStorage: _gitRepo!.objStorage, from: head)
|
||||
.asBroadcastStream();
|
||||
objStorage: _gitRepo!.objStorage, from: head);
|
||||
} on Exception catch (ex) {
|
||||
setState(() {
|
||||
_exception = ex;
|
||||
});
|
||||
}
|
||||
|
||||
return const Stream.empty();
|
||||
return [];
|
||||
}
|
||||
|
||||
void _rebuildCombined() {
|
||||
|
@ -135,7 +135,7 @@ class GitJournalRepo with ChangeNotifier {
|
||||
|
||||
if (!repoDir.existsSync()) {
|
||||
Log.i("Calling GitInit for ${storageConfig.folderName} at: $repoPath");
|
||||
var r = await GitRepository.init(repoPath, defaultBranch: 'main');
|
||||
var r = GitRepository.init(repoPath, defaultBranch: DEFAULT_BRANCH);
|
||||
if (r.isFailure) {
|
||||
Log.e("GitInit Failed", result: r);
|
||||
return fail(r);
|
||||
@ -144,7 +144,7 @@ class GitJournalRepo with ChangeNotifier {
|
||||
storageConfig.save();
|
||||
}
|
||||
|
||||
var valid = await GitRepository.isValidRepo(repoPath);
|
||||
var valid = GitRepository.isValidRepo(repoPath);
|
||||
if (!valid) {
|
||||
// What happened that the directory still exists but the .git folder
|
||||
// has disappeared?
|
||||
@ -154,7 +154,7 @@ class GitJournalRepo with ChangeNotifier {
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
var repoR = await GitRepository.load(repoPath);
|
||||
var repoR = await GitAsyncRepository.load(repoPath);
|
||||
if (repoR.isFailure) {
|
||||
return fail(repoR);
|
||||
}
|
||||
@ -164,6 +164,7 @@ class GitJournalRepo with ChangeNotifier {
|
||||
if (!storageConfig.storeInternally) {
|
||||
var r = await _commitUnTrackedChanges(repo, gitConfig);
|
||||
if (r.isFailure) {
|
||||
repo.close();
|
||||
return fail(r);
|
||||
}
|
||||
}
|
||||
@ -192,6 +193,8 @@ class GitJournalRepo with ChangeNotifier {
|
||||
currentBranch: await repo.currentBranch().getOrThrow(),
|
||||
headHash: head,
|
||||
);
|
||||
|
||||
repo.close();
|
||||
return Result(gjRepo);
|
||||
}
|
||||
|
||||
@ -268,7 +271,7 @@ class GitJournalRepo with ChangeNotifier {
|
||||
var r = await rootFolder.loadRecursively();
|
||||
if (r.isFailure) {
|
||||
if (r.error is FileStorageCacheIncomplete) {
|
||||
var repo = await GitRepository.load(repoPath).getOrThrow();
|
||||
var repo = await GitAsyncRepository.load(repoPath).getOrThrow();
|
||||
await _commitUnTrackedChanges(repo, gitConfig);
|
||||
await _resetFileStorage();
|
||||
return;
|
||||
@ -287,33 +290,11 @@ class GitJournalRepo with ChangeNotifier {
|
||||
}
|
||||
|
||||
Future<void> __fillFileStorageCache() async {
|
||||
var gitRepo = await GitRepository.load(repoPath).getOrThrow();
|
||||
var headR = await gitRepo.headHash();
|
||||
if (headR.isFailure) {
|
||||
if (headR.error is GitRefNotFound) {
|
||||
// No commits
|
||||
fileStorageCacheReady = true;
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
Log.e("Failed to fetch HEAD", result: headR);
|
||||
return;
|
||||
}
|
||||
var head = headR.getOrThrow();
|
||||
Log.d("Got HEAD: $head");
|
||||
|
||||
var startTime = DateTime.now();
|
||||
var result = await gitRepo.visitTree(
|
||||
fromCommitHash: head,
|
||||
visitor: fileStorage.visitor,
|
||||
);
|
||||
await fileStorage.fill();
|
||||
var endTime = DateTime.now().difference(startTime);
|
||||
|
||||
Log.i("Built Git Time Cache - $endTime");
|
||||
if (result.isFailure) {
|
||||
Log.e("Failed to build FileStorage cache", result: result);
|
||||
logException(result.exception!, result.stackTrace!);
|
||||
}
|
||||
|
||||
var r = await fileStorageCache.save(fileStorage);
|
||||
if (r.isFailure) {
|
||||
@ -321,10 +302,7 @@ class GitJournalRepo with ChangeNotifier {
|
||||
logException(r.exception!, r.stackTrace!);
|
||||
}
|
||||
|
||||
if (fileStorageCache.lastProcessedHead != head) {
|
||||
Log.e(
|
||||
"FileStorageCache Head different ${fileStorageCache.lastProcessedHead}");
|
||||
}
|
||||
assert(fileStorageCache.lastProcessedHead == fileStorage.head);
|
||||
|
||||
// Notify that the cache is ready
|
||||
fileStorageCacheReady = true;
|
||||
@ -342,7 +320,7 @@ class GitJournalRepo with ChangeNotifier {
|
||||
Future<void> syncNotes({bool doNotThrow = false}) async {
|
||||
// This is extremely slow with dart-git, can take over a second!
|
||||
if (_shouldCheckForChanges()) {
|
||||
var repoR = await GitRepository.load(repoPath);
|
||||
var repoR = await GitAsyncRepository.load(repoPath);
|
||||
if (repoR.isFailure) {
|
||||
Log.e("SyncNotes Failed to Load Repo", result: repoR);
|
||||
return;
|
||||
@ -747,7 +725,7 @@ class GitJournalRepo with ChangeNotifier {
|
||||
|
||||
Future<void> discardChanges(Note note) async {
|
||||
// FIXME: Add the checkout method to GJRepo
|
||||
var gitRepo = await GitRepository.load(repoPath).getOrThrow();
|
||||
var gitRepo = await GitAsyncRepository.load(repoPath).getOrThrow();
|
||||
await gitRepo.checkout(note.filePath).throwOnError();
|
||||
|
||||
// FIXME: Instead of this just reload that specific file
|
||||
@ -756,12 +734,12 @@ class GitJournalRepo with ChangeNotifier {
|
||||
}
|
||||
|
||||
Future<List<GitRemoteConfig>> remoteConfigs() async {
|
||||
var repo = await GitRepository.load(repoPath).getOrThrow();
|
||||
var repo = await GitAsyncRepository.load(repoPath).getOrThrow();
|
||||
return repo.config.remotes;
|
||||
}
|
||||
|
||||
Future<List<String>> branches() async {
|
||||
var repo = await GitRepository.load(repoPath).getOrThrow();
|
||||
var repo = await GitAsyncRepository.load(repoPath).getOrThrow();
|
||||
var branches = Set<String>.from(await repo.branches().getOrThrow());
|
||||
if (repo.config.remotes.isNotEmpty) {
|
||||
var remoteName = repo.config.remotes.first.name;
|
||||
@ -777,11 +755,12 @@ class GitJournalRepo with ChangeNotifier {
|
||||
|
||||
Future<String> checkoutBranch(String branchName) async {
|
||||
Log.i("Changing branch to $branchName");
|
||||
var repo = await GitRepository.load(repoPath).getOrThrow();
|
||||
var repo = await GitAsyncRepository.load(repoPath).getOrThrow();
|
||||
|
||||
try {
|
||||
var created = await createBranchIfRequired(repo, branchName);
|
||||
if (created.isEmpty) {
|
||||
repo.close();
|
||||
return "";
|
||||
}
|
||||
} catch (ex, st) {
|
||||
@ -800,12 +779,15 @@ class GitJournalRepo with ChangeNotifier {
|
||||
} catch (e, st) {
|
||||
Log.e("Checkout Branch Failed", ex: e, stacktrace: st);
|
||||
}
|
||||
|
||||
repo.close();
|
||||
return branchName;
|
||||
}
|
||||
|
||||
// FIXME: Why does this need to return a string?
|
||||
/// throws exceptions
|
||||
Future<String> createBranchIfRequired(GitRepository repo, String name) async {
|
||||
Future<String> createBranchIfRequired(
|
||||
GitAsyncRepository repo, String name) async {
|
||||
var localBranches = await repo.branches().getOrThrow();
|
||||
if (localBranches.contains(name)) {
|
||||
return name;
|
||||
@ -824,8 +806,8 @@ class GitJournalRepo with ChangeNotifier {
|
||||
return "";
|
||||
}
|
||||
|
||||
await repo.createBranch(name, hash: remoteBranchRef.hash).throwOnError();
|
||||
await repo.setBranchUpstreamTo(name, remoteConfig, name).throwOnError();
|
||||
repo.createBranch(name, hash: remoteBranchRef.hash).throwOnError();
|
||||
repo.setBranchUpstreamTo(name, remoteConfig, name).throwOnError();
|
||||
|
||||
Log.i("Created branch $name");
|
||||
return name;
|
||||
@ -840,7 +822,8 @@ class GitJournalRepo with ChangeNotifier {
|
||||
/// reset --hard the current branch to its remote branch
|
||||
Future<Result<void>> resetHard() {
|
||||
return catchAll(() async {
|
||||
var repo = await GitRepository.load(_gitRepo.gitRepoPath).getOrThrow();
|
||||
var repo =
|
||||
await GitAsyncRepository.load(_gitRepo.gitRepoPath).getOrThrow();
|
||||
var branchName = await repo.currentBranch().getOrThrow();
|
||||
var branchConfig = repo.config.branch(branchName);
|
||||
if (branchConfig == null) {
|
||||
@ -866,7 +849,8 @@ class GitJournalRepo with ChangeNotifier {
|
||||
|
||||
Future<Result<bool>> canResetHard() {
|
||||
return catchAll(() async {
|
||||
var repo = await GitRepository.load(_gitRepo.gitRepoPath).getOrThrow();
|
||||
var repo =
|
||||
await GitAsyncRepository.load(_gitRepo.gitRepoPath).getOrThrow();
|
||||
var branchName = await repo.currentBranch().getOrThrow();
|
||||
var branchConfig = repo.config.branch(branchName);
|
||||
if (branchConfig == null) {
|
||||
@ -930,7 +914,7 @@ Future<void> _ensureOneCommitInRepo({
|
||||
}
|
||||
|
||||
Future<Result<void>> _commitUnTrackedChanges(
|
||||
GitRepository repo, GitConfig gitConfig) async {
|
||||
GitAsyncRepository repo, GitConfig gitConfig) async {
|
||||
var timer = Stopwatch()..start();
|
||||
//
|
||||
// Check for un-committed files and save them
|
||||
|
@ -23,6 +23,8 @@ const SETTINGS_VERSION = 3;
|
||||
const DEFAULT_LIGHT_THEME_NAME = "LightDefault";
|
||||
const DEFAULT_DARK_THEME_NAME = "DarkDefault";
|
||||
|
||||
const DEFAULT_BRANCH = 'main';
|
||||
|
||||
class Settings extends ChangeNotifier with SettingsSharedPref {
|
||||
Settings(this.id, this.pref);
|
||||
|
||||
|
@ -246,7 +246,7 @@ class _GitRemoteSettingsScreenState extends State<GitRemoteSettingsScreen> {
|
||||
while (true) {
|
||||
var repoFolderPath = p.join(gitDir, "$repoFolderName$num");
|
||||
if (!Directory(repoFolderPath).existsSync()) {
|
||||
var r = await GitRepository.init(repoFolderPath, defaultBranch: 'main');
|
||||
var r = GitRepository.init(repoFolderPath, defaultBranch: 'main');
|
||||
showResultError(context, r);
|
||||
break;
|
||||
}
|
||||
|
@ -13,9 +13,10 @@ import 'package:path/path.dart' as p;
|
||||
import 'package:universal_io/io.dart' show Directory;
|
||||
|
||||
import 'package:gitjournal/logger/logger.dart';
|
||||
import 'package:gitjournal/settings/settings.dart';
|
||||
import 'git_transfer_progress.dart';
|
||||
|
||||
const DefaultBranchName = 'main';
|
||||
const DefaultBranchName = DEFAULT_BRANCH;
|
||||
|
||||
typedef GitFetchFunction = Future<Result<void>> Function(
|
||||
String repoPath,
|
||||
@ -56,7 +57,7 @@ Future<Result<void>> cloneRemotePluggable({
|
||||
required GitDefaultBranchFunction defaultBranchFn,
|
||||
required GitMergeFn gitMergeFn,
|
||||
}) async {
|
||||
var repo = await GitRepository.load(repoPath).getOrThrow();
|
||||
var repo = await GitAsyncRepository.load(repoPath).getOrThrow();
|
||||
var remote = await repo.addOrUpdateRemote(remoteName, cloneUrl).getOrThrow();
|
||||
|
||||
var statusFile = p.join(Directory.systemTemp.path, 'gj');
|
||||
@ -73,12 +74,14 @@ Future<Result<void>> cloneRemotePluggable({
|
||||
timer.cancel();
|
||||
if (fetchR.isFailure) {
|
||||
// FIXME: Give a better error?
|
||||
repo.close();
|
||||
return fail(fetchR);
|
||||
}
|
||||
|
||||
var branchNameR = await defaultBranchFn(
|
||||
repoPath, remoteName, sshPublicKey, sshPrivateKey, sshPassword);
|
||||
if (branchNameR.isFailure) {
|
||||
repo.close();
|
||||
return fail(branchNameR);
|
||||
}
|
||||
var remoteBranchName = branchNameR.getOrThrow();
|
||||
@ -101,6 +104,7 @@ Future<Result<void>> cloneRemotePluggable({
|
||||
var remoteBranchR = await repo.remoteBranch(remoteName, remoteBranchName);
|
||||
if (remoteBranchR.isFailure) {
|
||||
if (remoteBranchR.error is! GitNotFound) {
|
||||
repo.close();
|
||||
return fail(remoteBranchR);
|
||||
}
|
||||
|
||||
@ -144,6 +148,7 @@ Future<Result<void>> cloneRemotePluggable({
|
||||
var r = await gitMergeFn(
|
||||
repoPath, remoteName, remoteBranchName, authorName, authorEmail);
|
||||
if (r.isFailure) {
|
||||
repo.close();
|
||||
return fail(r);
|
||||
}
|
||||
}
|
||||
@ -159,6 +164,7 @@ Future<Result<void>> cloneRemotePluggable({
|
||||
var r = await gitMergeFn(
|
||||
repoPath, remoteName, remoteBranchName, authorName, authorEmail);
|
||||
if (r.isFailure) {
|
||||
repo.close();
|
||||
return fail(r);
|
||||
}
|
||||
}
|
||||
@ -173,10 +179,12 @@ Future<Result<void>> cloneRemotePluggable({
|
||||
if (!skipCheckout) {
|
||||
var r = await repo.checkout(".");
|
||||
if (r.isFailure) {
|
||||
repo.close();
|
||||
return fail(r);
|
||||
}
|
||||
}
|
||||
|
||||
repo.close();
|
||||
return Result(null);
|
||||
}
|
||||
|
||||
|
@ -81,9 +81,9 @@ Future<Result<void>> _merge(
|
||||
String authorEmail,
|
||||
) {
|
||||
return catchAll(() async {
|
||||
var repo = await GitRepository.load(repoPath).getOrThrow();
|
||||
var repo = GitRepository.load(repoPath).getOrThrow();
|
||||
var author = GitAuthor(name: authorName, email: authorEmail);
|
||||
await repo.mergeCurrentTrackingBranch(author: author).throwOnError();
|
||||
repo.mergeCurrentTrackingBranch(author: author).throwOnError();
|
||||
return Result(null);
|
||||
});
|
||||
}
|
||||
|
@ -89,8 +89,8 @@ Future<Result<String>> _defaultBranch(
|
||||
Log.w("Could not fetch git Default Branch", ex: ex);
|
||||
}
|
||||
|
||||
var repo = await GitRepository.load(repoPath).getOrThrow();
|
||||
var remoteBranch = await repo.guessRemoteHead(remoteName);
|
||||
var repo = GitRepository.load(repoPath).getOrThrow();
|
||||
var remoteBranch = repo.guessRemoteHead(remoteName);
|
||||
if (remoteBranch == null) {
|
||||
return Result(null);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:dart_git/git.dart';
|
||||
import 'package:dart_git/dart_git.dart';
|
||||
import 'package:dots_indicator/dots_indicator.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:function_types/function_types.dart';
|
||||
@ -426,20 +426,20 @@ class GitHostSetupScreenState extends State<GitHostSetupScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _removeRemote() async {
|
||||
void _removeRemote() {
|
||||
var repo = context.read<GitJournalRepo>();
|
||||
var basePath = repo.gitBaseDirectory;
|
||||
|
||||
var repoPath = p.join(basePath, widget.repoFolderName);
|
||||
|
||||
try {
|
||||
if (!await GitRepository.isValidRepo(repoPath)) {
|
||||
var r = await GitRepository.init(repoPath, defaultBranch: 'main');
|
||||
if (!GitRepository.isValidRepo(repoPath)) {
|
||||
var r = GitRepository.init(repoPath, defaultBranch: 'main');
|
||||
showResultError(context, r);
|
||||
}
|
||||
var repo = await GitRepository.load(repoPath).getOrThrow();
|
||||
var repo = GitRepository.load(repoPath).getOrThrow();
|
||||
if (repo.config.remote(widget.remoteName) != null) {
|
||||
await repo.removeRemote(widget.remoteName).throwOnError();
|
||||
repo.removeRemote(widget.remoteName).throwOnError();
|
||||
}
|
||||
} catch (e, stacktrace) {
|
||||
Log.e("Failed to remove remote", ex: e, stacktrace: stacktrace);
|
||||
@ -571,7 +571,7 @@ class GitHostSetupScreenState extends State<GitHostSetupScreen> {
|
||||
if (cloneR.isFailure) {
|
||||
Log.e("Failed to clone", ex: cloneR.error, stacktrace: cloneR.stackTrace);
|
||||
var error = cloneR.error.toString();
|
||||
await _removeRemote();
|
||||
_removeRemote();
|
||||
|
||||
setState(() {
|
||||
logEvent(Event.GitHostSetupGitCloneError, parameters: {
|
||||
|
@ -13,6 +13,7 @@ import 'package:dart_git/utils/result.dart';
|
||||
import 'package:universal_io/io.dart';
|
||||
|
||||
import 'package:gitjournal/logger/logger.dart';
|
||||
import 'package:gitjournal/settings/settings.dart';
|
||||
|
||||
Future<Result<void>> gitFetchViaExecutable({
|
||||
required String repoPath,
|
||||
@ -60,7 +61,7 @@ Future<Result<void>> _gitCommandViaExecutable({
|
||||
var dir = Directory.systemTemp.createTempSync();
|
||||
var temp = File("${dir.path}/key");
|
||||
_ = await temp.writeAsString(privateKey);
|
||||
await temp.chmod(int.parse('0600', radix: 8));
|
||||
temp.chmodSync(int.parse('0600', radix: 8));
|
||||
|
||||
Log.i("Running git $command $remoteName");
|
||||
var process = await Process.start(
|
||||
@ -113,7 +114,7 @@ Future<Result<String>> gitDefaultBranchViaExecutable({
|
||||
var dir = Directory.systemTemp.createTempSync();
|
||||
var temp = File("${dir.path}/key");
|
||||
_ = await temp.writeAsString(privateKey);
|
||||
await temp.chmod(int.parse('0600', radix: 8));
|
||||
temp.chmodSync(int.parse('0600', radix: 8));
|
||||
|
||||
var process = await Process.start(
|
||||
'git',
|
||||
@ -147,9 +148,8 @@ Future<Result<String>> gitDefaultBranchViaExecutable({
|
||||
for (var line in LineSplitter.split(stdout)) {
|
||||
if (line.contains('HEAD branch:')) {
|
||||
var branch = line.split(':')[1].trim();
|
||||
// Everyone seems to default to 'main' these days
|
||||
if (branch == '(unknown)') {
|
||||
return Result('main');
|
||||
return Result(DEFAULT_BRANCH);
|
||||
}
|
||||
return Result(branch);
|
||||
}
|
||||
|
@ -346,7 +346,7 @@ packages:
|
||||
description:
|
||||
path: "."
|
||||
ref: HEAD
|
||||
resolved-ref: f1cb3b0376a2f3222a84b034906f156b237766d3
|
||||
resolved-ref: d02e1ea8712a31d1e51211091de7b56e6f2158b8
|
||||
url: "https://github.com/GitJournal/dart-git.git"
|
||||
source: git
|
||||
version: "0.0.2"
|
||||
|
@ -58,7 +58,7 @@ void main() {
|
||||
var tempDir = await io.Directory.systemTemp.createTemp('__fnft__');
|
||||
var repoPath = tempDir.path;
|
||||
|
||||
await GitRepository.init(repoPath).throwOnError();
|
||||
GitRepository.init(repoPath).throwOnError();
|
||||
|
||||
var fileStorage = FileStorage(
|
||||
repoPath: repoPath,
|
||||
@ -74,12 +74,19 @@ void main() {
|
||||
|
||||
var deepEq = const DeepCollectionEquality().equals;
|
||||
expect(
|
||||
deepEq(fileStorage2.blobCTimeBuilder.processedCommits, commits), true);
|
||||
expect(deepEq(fileStorage2.blobCTimeBuilder.processedTrees, trees), true);
|
||||
deepEq(fileStorage2.blobCTimeBuilder.processedCommits.set, commits),
|
||||
true,
|
||||
);
|
||||
expect(
|
||||
deepEq(fileStorage2.blobCTimeBuilder.processedTrees.set, trees),
|
||||
true,
|
||||
);
|
||||
expect(deepEq(fileStorage2.blobCTimeBuilder.map, cMap), true);
|
||||
|
||||
expect(
|
||||
deepEq(fileStorage2.fileMTimeBuilder.processedCommits, commits), true);
|
||||
deepEq(fileStorage2.fileMTimeBuilder.processedCommits.set, commits),
|
||||
true,
|
||||
);
|
||||
expect(deepEq(fileStorage2.fileMTimeBuilder.map, mMap), true);
|
||||
});
|
||||
}
|
||||
|
@ -108,8 +108,8 @@ void main() {
|
||||
await storage.save(note).throwOnError();
|
||||
}
|
||||
|
||||
var repo = await GitRepository.load(repoPath).getOrThrow();
|
||||
await repo
|
||||
var repo = GitRepository.load(repoPath).getOrThrow();
|
||||
repo
|
||||
.commit(
|
||||
message: "Prepare Test Env",
|
||||
author: GitAuthor(name: 'Name', email: "name@example.com"),
|
||||
|
@ -42,8 +42,8 @@ void main() {
|
||||
await _writeRandomNote(random, repoPath, config, fileStorage);
|
||||
}
|
||||
|
||||
var repo = await GitRepository.load(repoPath).getOrThrow();
|
||||
await repo
|
||||
var repo = GitRepository.load(repoPath).getOrThrow();
|
||||
repo
|
||||
.commit(
|
||||
message: "Prepare Test Env",
|
||||
author: GitAuthor(name: 'Name', email: "name@example.com"),
|
||||
@ -72,8 +72,8 @@ void main() {
|
||||
var newFileStorage = await FileStorage.fake(newRepoPath);
|
||||
await _writeRandomNote(Random(), newRepoPath, config, newFileStorage);
|
||||
|
||||
var repo = await GitRepository.load(newRepoPath).getOrThrow();
|
||||
await repo
|
||||
var repo = GitRepository.load(newRepoPath).getOrThrow();
|
||||
repo
|
||||
.commit(
|
||||
message: "Prepare Test Env",
|
||||
author: GitAuthor(name: 'Name', email: "name@example.com"),
|
||||
|
@ -109,8 +109,8 @@ void main() {
|
||||
await storage.save(note).throwOnError();
|
||||
}
|
||||
|
||||
var repo = await GitRepository.load(repoPath).getOrThrow();
|
||||
await repo
|
||||
var repo = GitRepository.load(repoPath).getOrThrow();
|
||||
repo
|
||||
.commit(
|
||||
message: "Prepare Test Env",
|
||||
author: GitAuthor(name: 'Name', email: "name@example.com"),
|
||||
|
@ -46,8 +46,8 @@ void main() {
|
||||
await generateNote(repoPath, "zeplin.txt");
|
||||
await generateNote(repoPath, "Goat Sim.md");
|
||||
|
||||
var repo = await GitRepository.load(repoPath).getOrThrow();
|
||||
await repo
|
||||
var repo = GitRepository.load(repoPath).getOrThrow();
|
||||
repo
|
||||
.commit(
|
||||
message: "Prepare Test Env",
|
||||
author: GitAuthor(name: 'Name', email: "name@example.com"),
|
||||
|
@ -67,8 +67,8 @@ void main() {
|
||||
|
||||
notes = [n1, n2];
|
||||
|
||||
var repo = await GitRepository.load(tempDir.path).getOrThrow();
|
||||
await repo
|
||||
var repo = GitRepository.load(tempDir.path).getOrThrow();
|
||||
repo
|
||||
.commit(
|
||||
message: "Prepare Test Env",
|
||||
author: GitAuthor(name: 'Name', email: "name@example.com"),
|
||||
|
@ -28,7 +28,7 @@ Future<void> populateWithData(SharedPreferences pref) async {
|
||||
var dir = await getApplicationDocumentsDirectory();
|
||||
|
||||
var repoPath = p.join(dir.path, "journal_local");
|
||||
await GitRepository.init(repoPath);
|
||||
GitRepository.init(repoPath);
|
||||
|
||||
stderr.writeln("Filling fake data in $repoPath");
|
||||
|
||||
|
Reference in New Issue
Block a user