fix: main thread deadlock cause by calling .Result directly (#1720)

Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
leo
2025-08-12 16:03:58 +08:00
parent 20ca646307
commit bd81ccd94f
29 changed files with 475 additions and 338 deletions

View File

@@ -578,7 +578,7 @@ namespace SourceGit
{
if (!string.IsNullOrEmpty(repo) && Directory.Exists(repo))
{
var test = new Commands.QueryRepositoryRootPath(repo).GetResultAsync().Result;
var test = new Commands.QueryRepositoryRootPath(repo).GetResult();
if (test.IsSuccess && !string.IsNullOrEmpty(test.StdOut))
{
Dispatcher.UIThread.Invoke(() =>

View File

@@ -50,6 +50,28 @@ namespace SourceGit.Commands
}
}
protected Result ReadToEnd()
{
using var proc = new Process() { StartInfo = CreateGitStartInfo(true) };
try
{
proc.Start();
}
catch (Exception e)
{
return Result.Failed(e.Message);
}
var rs = new Result() { IsSuccess = true };
rs.StdOut = proc.StandardOutput.ReadToEnd();
rs.StdErr = proc.StandardError.ReadToEnd();
proc.WaitForExit();
rs.IsSuccess = proc.ExitCode == 0;
return rs;
}
public async Task<bool> ExecAsync()
{
Log?.AppendLine($"$ git {Args}\n");

View File

@@ -20,6 +20,26 @@ namespace SourceGit.Commands
}
}
public Dictionary<string, string> ReadAll()
{
Args = "config -l";
var output = ReadToEnd();
var rs = new Dictionary<string, string>();
if (output.IsSuccess)
{
var lines = output.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var parts = line.Split('=', 2);
if (parts.Length == 2)
rs[parts[0]] = parts[1];
}
}
return rs;
}
public async Task<Dictionary<string, string>> ReadAllAsync()
{
Args = "config -l";
@@ -40,6 +60,12 @@ namespace SourceGit.Commands
return rs;
}
public string Get(string key)
{
Args = $"config {key}";
return ReadToEnd().StdOut.Trim();
}
public async Task<string> GetAsync(string key)
{
Args = $"config {key}";

View File

@@ -11,6 +11,17 @@ namespace SourceGit.Commands
Args = "rev-parse --is-bare-repository";
}
public bool GetResult()
{
if (!Directory.Exists(Path.Combine(WorkingDirectory, "refs")) ||
!Directory.Exists(Path.Combine(WorkingDirectory, "objects")) ||
!File.Exists(Path.Combine(WorkingDirectory, "HEAD")))
return false;
var rs = ReadToEnd();
return rs.IsSuccess && rs.StdOut.Trim() == "true";
}
public async Task<bool> GetResultAsync()
{
if (!Directory.Exists(Path.Combine(WorkingDirectory, "refs")) ||

View File

@@ -13,6 +13,11 @@ namespace SourceGit.Commands
Args = $"diff -a --ignore-cr-at-eol --check {opt}";
}
public bool GetResult()
{
return ReadToEnd().IsSuccess;
}
public async Task<bool> GetResultAsync()
{
var rs = await ReadToEndAsync().ConfigureAwait(false);

View File

@@ -20,9 +20,19 @@ namespace SourceGit.Commands
RaiseError = false;
}
public bool GetResult()
{
return Parse(ReadToEnd());
}
public async Task<bool> GetResultAsync()
{
var rs = await ReadToEndAsync().ConfigureAwait(false);
return Parse(rs);
}
private bool Parse(Result rs)
{
return rs.IsSuccess && rs.StdOut.Contains("filter\0lfs");
}
}

View File

@@ -11,6 +11,12 @@ namespace SourceGit.Commands
Args = $"show --no-show-signature --format=%B -s {sha}";
}
public string GetResult()
{
var rs = ReadToEnd();
return rs.IsSuccess ? rs.StdOut.TrimEnd() : string.Empty;
}
public async Task<string> GetResultAsync()
{
var rs = await ReadToEndAsync().ConfigureAwait(false);

View File

@@ -11,6 +11,11 @@ namespace SourceGit.Commands
Args = "branch --show-current";
}
public string GetResult()
{
return ReadToEnd().StdOut.Trim();
}
public async Task<string> GetResultAsync()
{
var rs = await ReadToEndAsync().ConfigureAwait(false);

View File

@@ -1,5 +1,4 @@
using System.IO;
using System.Threading.Tasks;
namespace SourceGit.Commands
{
@@ -11,9 +10,9 @@ namespace SourceGit.Commands
Args = "rev-parse --git-common-dir";
}
public async Task<string> GetResultAsync()
public string GetResult()
{
var rs = await ReadToEndAsync().ConfigureAwait(false);
var rs = ReadToEnd();
if (!rs.IsSuccess)
return null;

View File

@@ -11,9 +11,19 @@ namespace SourceGit.Commands
Args = "rev-parse --git-dir";
}
public string GetResult()
{
return Parse(ReadToEnd());
}
public async Task<string> GetResultAsync()
{
var rs = await ReadToEndAsync().ConfigureAwait(false);
return Parse(rs);
}
private string Parse(Result rs)
{
if (!rs.IsSuccess)
return null;

View File

@@ -10,6 +10,11 @@ namespace SourceGit.Commands
Args = "rev-parse --show-toplevel";
}
public Result GetResult()
{
return ReadToEnd();
}
public async Task<Result> GetResultAsync()
{
return await ReadToEndAsync().ConfigureAwait(false);

View File

@@ -11,9 +11,19 @@ namespace SourceGit.Commands
Args = $"rev-parse {refname}";
}
public string GetResult()
{
return Parse(ReadToEnd());
}
public async Task<string> GetResultAsync()
{
var rs = await ReadToEndAsync().ConfigureAwait(false);
return Parse(rs);
}
private string Parse(Result rs)
{
if (rs.IsSuccess && !string.IsNullOrEmpty(rs.StdOut))
return rs.StdOut.Trim();

View File

@@ -12,31 +12,40 @@ namespace SourceGit.Commands
Args = $"show --no-show-signature --decorate=full --format=%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s -s {sha}";
}
public Models.Commit GetResult()
{
var rs = ReadToEnd();
return Parse(rs);
}
public async Task<Models.Commit> GetResultAsync()
{
var rs = await ReadToEndAsync().ConfigureAwait(false);
if (rs.IsSuccess && !string.IsNullOrEmpty(rs.StdOut))
{
var commit = new Models.Commit();
var lines = rs.StdOut.Split('\n');
if (lines.Length < 8)
return null;
return Parse(rs);
}
commit.SHA = lines[0];
if (!string.IsNullOrEmpty(lines[1]))
commit.Parents.AddRange(lines[1].Split(' ', StringSplitOptions.RemoveEmptyEntries));
if (!string.IsNullOrEmpty(lines[2]))
commit.ParseDecorators(lines[2]);
commit.Author = Models.User.FindOrAdd(lines[3]);
commit.AuthorTime = ulong.Parse(lines[4]);
commit.Committer = Models.User.FindOrAdd(lines[5]);
commit.CommitterTime = ulong.Parse(lines[6]);
commit.Subject = lines[7];
private Models.Commit Parse(Result rs)
{
if (!rs.IsSuccess || string.IsNullOrEmpty(rs.StdOut))
return null;
return commit;
}
var commit = new Models.Commit();
var lines = rs.StdOut.Split('\n');
if (lines.Length < 8)
return null;
return null;
commit.SHA = lines[0];
if (!string.IsNullOrEmpty(lines[1]))
commit.Parents.AddRange(lines[1].Split(' ', StringSplitOptions.RemoveEmptyEntries));
if (!string.IsNullOrEmpty(lines[2]))
commit.ParseDecorators(lines[2]);
commit.Author = Models.User.FindOrAdd(lines[3]);
commit.AuthorTime = ulong.Parse(lines[4]);
commit.Committer = Models.User.FindOrAdd(lines[5]);
commit.CommitterTime = ulong.Parse(lines[6]);
commit.Subject = lines[7];
return commit;
}
}
}

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace SourceGit.Commands
{
@@ -20,9 +19,9 @@ namespace SourceGit.Commands
_parent = parent;
}
public async Task<List<Models.Change>> GetResultAsync()
public List<Models.Change> GetResult()
{
var rs = await ReadToEndAsync().ConfigureAwait(false);
var rs = ReadToEnd();
if (!rs.IsSuccess)
return [];

View File

@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace SourceGit.Models
{
@@ -125,44 +124,44 @@ namespace SourceGit.Models
if (_updateTags > 0)
{
_updateTags = 0;
Task.Run(_repo.RefreshTags);
_repo.RefreshTags();
}
if (_updateSubmodules > 0 || _repo.MayHaveSubmodules())
{
_updateSubmodules = 0;
Task.Run(_repo.RefreshSubmodules);
_repo.RefreshSubmodules();
}
Task.Run(_repo.RefreshBranches);
Task.Run(_repo.RefreshCommits);
Task.Run(_repo.RefreshWorkingCopyChanges);
Task.Run(_repo.RefreshWorktrees);
_repo.RefreshBranches();
_repo.RefreshCommits();
_repo.RefreshWorkingCopyChanges();
_repo.RefreshWorktrees();
}
if (_updateWC > 0 && now > _updateWC)
{
_updateWC = 0;
Task.Run(_repo.RefreshWorkingCopyChanges);
_repo.RefreshWorkingCopyChanges();
}
if (_updateSubmodules > 0 && now > _updateSubmodules)
{
_updateSubmodules = 0;
Task.Run(_repo.RefreshSubmodules);
_repo.RefreshSubmodules();
}
if (_updateStashes > 0 && now > _updateStashes)
{
_updateStashes = 0;
Task.Run(_repo.RefreshStashes);
_repo.RefreshStashes();
}
if (_updateTags > 0 && now > _updateTags)
{
_updateTags = 0;
Task.Run(_repo.RefreshTags);
Task.Run(_repo.RefreshCommits);
_repo.RefreshTags();
_repo.RefreshCommits();
}
}

View File

@@ -63,10 +63,7 @@ namespace SourceGit.ViewModels
if (_commitMessages.TryGetValue(sha, out var msg))
return msg;
msg = new Commands.QueryCommitFullMessage(_repo, sha)
.GetResultAsync()
.Result;
msg = new Commands.QueryCommitFullMessage(_repo, sha).GetResult();
_commitMessages[sha] = msg;
return msg;
}

View File

@@ -20,7 +20,7 @@ namespace SourceGit.ViewModels
{
Name = branch.Name;
Head = branch.Head;
Revision = new Commands.QuerySingleCommit(repo.FullPath, branch.Head).GetResultAsync().Result ?? new Models.Commit() { SHA = branch.Head };
Revision = new Commands.QuerySingleCommit(repo.FullPath, branch.Head).GetResult() ?? new Models.Commit() { SHA = branch.Head };
}
}
@@ -69,7 +69,7 @@ namespace SourceGit.ViewModels
if (!isSubmodule && (_change.ConflictReason is Models.ConflictReason.BothAdded or Models.ConflictReason.BothModified))
{
CanUseExternalMergeTool = true;
IsResolved = new Commands.IsConflictResolved(repo.FullPath, change).GetResultAsync().Result;
IsResolved = new Commands.IsConflictResolved(repo.FullPath, change).GetResult();
}
switch (wc.InProgressContext)

View File

@@ -51,7 +51,7 @@ namespace SourceGit.ViewModels
_basedOn = branch.Head;
BasedOn = branch;
SignTag = new Commands.Config(repo.FullPath).GetAsync("tag.gpgsign").Result.Equals("true", StringComparison.OrdinalIgnoreCase);
SignTag = new Commands.Config(repo.FullPath).Get("tag.gpgsign").Equals("true", StringComparison.OrdinalIgnoreCase);
}
public CreateTag(Repository repo, Models.Commit commit)
@@ -60,7 +60,7 @@ namespace SourceGit.ViewModels
_basedOn = commit.SHA;
BasedOn = commit;
SignTag = new Commands.Config(repo.FullPath).GetAsync("tag.gpgsign").Result.Equals("true", StringComparison.OrdinalIgnoreCase);
SignTag = new Commands.Config(repo.FullPath).Get("tag.gpgsign").Equals("true", StringComparison.OrdinalIgnoreCase);
}
public static ValidationResult ValidateTagName(string name, ValidationContext ctx)

View File

@@ -87,7 +87,7 @@ namespace SourceGit.ViewModels
if (_cachedCommitFullMessage.TryGetValue(sha, out var msg))
return msg;
msg = new Commands.QueryCommitFullMessage(_repo.FullPath, sha).GetResultAsync().Result;
msg = new Commands.QueryCommitFullMessage(_repo.FullPath, sha).GetResult();
_cachedCommitFullMessage[sha] = msg;
return msg;
}

View File

@@ -74,89 +74,83 @@ namespace SourceGit.ViewModels
private void RefreshViewContent()
{
if (_isDiffMode)
SetViewContentAsDiff();
else
SetViewContentAsRevisionFile();
}
private void SetViewContentAsRevisionFile()
{
var objs = new Commands.QueryRevisionObjects(_repo.FullPath, _revision.SHA, _file).GetResultAsync().Result;
if (objs.Count == 0)
{
ViewContent = new FileHistoriesRevisionFile(_file);
SetViewContentAsDiff();
return;
}
var obj = objs[0];
switch (obj.Type)
Task.Run(async () =>
{
case Models.ObjectType.Blob:
Task.Run(async () =>
var objs = await new Commands.QueryRevisionObjects(_repo.FullPath, _revision.SHA, _file)
.GetResultAsync()
.ConfigureAwait(false);
if (objs.Count == 0)
{
Dispatcher.UIThread.Post(() => ViewContent = new FileHistoriesRevisionFile(_file));
return;
}
var revisionContent = await GetRevisionFileContentAsync(objs[0]).ConfigureAwait(false);
Dispatcher.UIThread.Post(() => ViewContent = revisionContent);
});
}
private async Task<object> GetRevisionFileContentAsync(Models.Object obj)
{
if (obj.Type == Models.ObjectType.Blob)
{
var isBinary = await new Commands.IsBinary(_repo.FullPath, _revision.SHA, _file).GetResultAsync().ConfigureAwait(false);
if (isBinary)
{
var imgDecoder = ImageSource.GetDecoder(_file);
if (imgDecoder != Models.ImageDecoder.None)
{
var isBinary = await new Commands.IsBinary(_repo.FullPath, _revision.SHA, _file).GetResultAsync().ConfigureAwait(false);
if (isBinary)
{
var imgDecoder = ImageSource.GetDecoder(_file);
if (imgDecoder != Models.ImageDecoder.None)
{
var source = await ImageSource.FromRevisionAsync(_repo.FullPath, _revision.SHA, _file, imgDecoder).ConfigureAwait(false);
var image = new Models.RevisionImageFile(_file, source.Bitmap, source.Size);
Dispatcher.UIThread.Post(() => ViewContent = new FileHistoriesRevisionFile(_file, image, true));
}
else
{
var size = await new Commands.QueryFileSize(_repo.FullPath, _file, _revision.SHA).GetResultAsync().ConfigureAwait(false);
var binaryFile = new Models.RevisionBinaryFile() { Size = size };
Dispatcher.UIThread.Post(() => ViewContent = new FileHistoriesRevisionFile(_file, binaryFile, true));
}
var source = await ImageSource.FromRevisionAsync(_repo.FullPath, _revision.SHA, _file, imgDecoder).ConfigureAwait(false);
var image = new Models.RevisionImageFile(_file, source.Bitmap, source.Size);
return new FileHistoriesRevisionFile(_file, image, true);
}
return;
}
var size = await new Commands.QueryFileSize(_repo.FullPath, _file, _revision.SHA).GetResultAsync().ConfigureAwait(false);
var binaryFile = new Models.RevisionBinaryFile() { Size = size };
return new FileHistoriesRevisionFile(_file, binaryFile, true);
}
var contentStream = await Commands.QueryFileContent.RunAsync(_repo.FullPath, _revision.SHA, _file).ConfigureAwait(false);
var content = await new StreamReader(contentStream).ReadToEndAsync();
var lfs = Models.LFSObject.Parse(content);
if (lfs != null)
{
var imgDecoder = ImageSource.GetDecoder(_file);
if (imgDecoder != Models.ImageDecoder.None)
{
var combined = new RevisionLFSImage(_repo.FullPath, _file, lfs, imgDecoder);
Dispatcher.UIThread.Post(() => ViewContent = new FileHistoriesRevisionFile(_file, combined, true));
}
else
{
var rlfs = new Models.RevisionLFSObject() { Object = lfs };
Dispatcher.UIThread.Post(() => ViewContent = new FileHistoriesRevisionFile(_file, rlfs, true));
}
}
else
{
var txt = new Models.RevisionTextFile() { FileName = obj.Path, Content = content };
Dispatcher.UIThread.Post(() => ViewContent = new FileHistoriesRevisionFile(_file, txt, true));
}
});
break;
case Models.ObjectType.Commit:
Task.Run(async () =>
var contentStream = await Commands.QueryFileContent.RunAsync(_repo.FullPath, _revision.SHA, _file).ConfigureAwait(false);
var content = await new StreamReader(contentStream).ReadToEndAsync();
var lfs = Models.LFSObject.Parse(content);
if (lfs != null)
{
var imgDecoder = ImageSource.GetDecoder(_file);
if (imgDecoder != Models.ImageDecoder.None)
{
var submoduleRoot = Path.Combine(_repo.FullPath, _file);
var commit = await new Commands.QuerySingleCommit(submoduleRoot, obj.SHA).GetResultAsync().ConfigureAwait(false);
var message = commit != null ? await new Commands.QueryCommitFullMessage(submoduleRoot, obj.SHA).GetResultAsync().ConfigureAwait(false) : null;
var module = new Models.RevisionSubmodule()
{
Commit = commit ?? new Models.Commit() { SHA = obj.SHA },
FullMessage = new Models.CommitFullMessage { Message = message }
};
var combined = new RevisionLFSImage(_repo.FullPath, _file, lfs, imgDecoder);
return new FileHistoriesRevisionFile(_file, combined, true);
}
Dispatcher.UIThread.Post(() => ViewContent = new FileHistoriesRevisionFile(_file, module));
});
break;
default:
ViewContent = new FileHistoriesRevisionFile(_file);
break;
var rlfs = new Models.RevisionLFSObject() { Object = lfs };
return new FileHistoriesRevisionFile(_file, rlfs, true);
}
var txt = new Models.RevisionTextFile() { FileName = obj.Path, Content = content };
return new FileHistoriesRevisionFile(_file, txt, true);
}
if (obj.Type == Models.ObjectType.Commit)
{
var submoduleRoot = Path.Combine(_repo.FullPath, _file);
var commit = await new Commands.QuerySingleCommit(submoduleRoot, obj.SHA).GetResultAsync().ConfigureAwait(false);
var message = commit != null ? await new Commands.QueryCommitFullMessage(submoduleRoot, obj.SHA).GetResultAsync().ConfigureAwait(false) : null;
var module = new Models.RevisionSubmodule()
{
Commit = commit ?? new Models.Commit() { SHA = obj.SHA },
FullMessage = new Models.CommitFullMessage { Message = message }
};
return new FileHistoriesRevisionFile(_file, module);
}
return new FileHistoriesRevisionFile(_file);
}
private void SetViewContentAsDiff()
@@ -326,7 +320,7 @@ namespace SourceGit.ViewModels
if (_fullCommitMessages.TryGetValue(sha, out var msg))
return msg;
msg = new Commands.QueryCommitFullMessage(_repo.FullPath, sha).GetResultAsync().Result;
msg = new Commands.QueryCommitFullMessage(_repo.FullPath, sha).GetResult();
_fullCommitMessages[sha] = msg;
return msg;
}

View File

@@ -11,9 +11,9 @@ namespace SourceGit.ViewModels
_cmd = cmd;
}
public Task<bool> AbortAsync()
public async Task<bool> AbortAsync()
{
return new Commands.Command()
return await new Commands.Command()
{
WorkingDirectory = _repo,
Context = _repo,
@@ -21,9 +21,9 @@ namespace SourceGit.ViewModels
}.ExecAsync();
}
public virtual Task<bool> SkipAsync()
public virtual async Task<bool> SkipAsync()
{
return new Commands.Command()
return await new Commands.Command()
{
WorkingDirectory = _repo,
Context = _repo,
@@ -31,9 +31,9 @@ namespace SourceGit.ViewModels
}.ExecAsync();
}
public virtual Task<bool> ContinueAsync()
public virtual async Task<bool> ContinueAsync()
{
return new Commands.Command()
return await new Commands.Command()
{
WorkingDirectory = _repo,
Context = _repo,
@@ -61,7 +61,7 @@ namespace SourceGit.ViewModels
public CherryPickInProgress(Repository repo) : base(repo.FullPath, "cherry-pick")
{
var headSHA = File.ReadAllText(Path.Combine(repo.GitDir, "CHERRY_PICK_HEAD")).Trim();
Head = new Commands.QuerySingleCommit(repo.FullPath, headSHA).GetResultAsync().Result ?? new Models.Commit() { SHA = headSHA };
Head = new Commands.QuerySingleCommit(repo.FullPath, headSHA).GetResult() ?? new Models.Commit() { SHA = headSHA };
HeadName = Head.GetFriendlyName();
}
}
@@ -99,19 +99,19 @@ namespace SourceGit.ViewModels
var stoppedSHAPath = Path.Combine(repo.GitDir, "rebase-merge", "stopped-sha");
var stoppedSHA = File.Exists(stoppedSHAPath)
? File.ReadAllText(stoppedSHAPath).Trim()
: new Commands.QueryRevisionByRefName(repo.FullPath, HeadName).GetResultAsync().Result;
: new Commands.QueryRevisionByRefName(repo.FullPath, HeadName).GetResult();
if (!string.IsNullOrEmpty(stoppedSHA))
StoppedAt = new Commands.QuerySingleCommit(repo.FullPath, stoppedSHA).GetResultAsync().Result ?? new Models.Commit() { SHA = stoppedSHA };
StoppedAt = new Commands.QuerySingleCommit(repo.FullPath, stoppedSHA).GetResult() ?? new Models.Commit() { SHA = stoppedSHA };
var ontoSHA = File.ReadAllText(Path.Combine(repo.GitDir, "rebase-merge", "onto")).Trim();
Onto = new Commands.QuerySingleCommit(repo.FullPath, ontoSHA).GetResultAsync().Result ?? new Models.Commit() { SHA = ontoSHA };
Onto = new Commands.QuerySingleCommit(repo.FullPath, ontoSHA).GetResult() ?? new Models.Commit() { SHA = ontoSHA };
BaseName = Onto.GetFriendlyName();
}
public override Task<bool> ContinueAsync()
public override async Task<bool> ContinueAsync()
{
return new Commands.Command()
return await new Commands.Command()
{
WorkingDirectory = _repo,
Context = _repo,
@@ -131,7 +131,7 @@ namespace SourceGit.ViewModels
public RevertInProgress(Repository repo) : base(repo.FullPath, "revert")
{
var headSHA = File.ReadAllText(Path.Combine(repo.GitDir, "REVERT_HEAD")).Trim();
Head = new Commands.QuerySingleCommit(repo.FullPath, headSHA).GetResultAsync().Result ?? new Models.Commit() { SHA = headSHA };
Head = new Commands.QuerySingleCommit(repo.FullPath, headSHA).GetResult() ?? new Models.Commit() { SHA = headSHA };
}
}
@@ -154,16 +154,16 @@ namespace SourceGit.ViewModels
public MergeInProgress(Repository repo) : base(repo.FullPath, "merge")
{
Current = new Commands.QueryCurrentBranch(repo.FullPath).GetResultAsync().Result;
Current = new Commands.QueryCurrentBranch(repo.FullPath).GetResult();
var sourceSHA = File.ReadAllText(Path.Combine(repo.GitDir, "MERGE_HEAD")).Trim();
Source = new Commands.QuerySingleCommit(repo.FullPath, sourceSHA).GetResultAsync().Result ?? new Models.Commit() { SHA = sourceSHA };
Source = new Commands.QuerySingleCommit(repo.FullPath, sourceSHA).GetResult() ?? new Models.Commit() { SHA = sourceSHA };
SourceName = Source.GetFriendlyName();
}
public override Task<bool> SkipAsync()
public override async Task<bool> SkipAsync()
{
return Task.FromResult(true);
return await Task.FromResult(true);
}
}
}

View File

@@ -94,7 +94,7 @@ namespace SourceGit.ViewModels
foreach (var w in pref.Workspaces)
w.IsActive = false;
var test = new Commands.QueryRepositoryRootPath(startupRepo).GetResultAsync().Result;
var test = new Commands.QueryRepositoryRootPath(startupRepo).GetResult();
if (!test.IsSuccess || string.IsNullOrEmpty(test.StdOut))
{
Pages[0].Notifications.Add(new Models.Notification
@@ -344,7 +344,7 @@ namespace SourceGit.ViewModels
return;
}
var isBare = new Commands.IsBareRepository(node.Id).GetResultAsync().Result;
var isBare = new Commands.IsBareRepository(node.Id).GetResult();
var gitDir = isBare ? node.Id : GetRepositoryGitDir(node.Id);
if (string.IsNullOrEmpty(gitDir))
{
@@ -446,7 +446,7 @@ namespace SourceGit.ViewModels
return null;
}
return new Commands.QueryGitDir(repo).GetResultAsync().Result;
return new Commands.QueryGitDir(repo).GetResult();
}
private void CloseRepositoryInTab(LauncherPage page, bool removeFromWorkspace = true)

View File

@@ -79,7 +79,7 @@ namespace SourceGit.ViewModels
private Models.MergeMode AutoSelectMergeMode()
{
var config = new Commands.Config(_repo.FullPath).GetAsync($"branch.{Into}.mergeoptions").Result;
var config = new Commands.Config(_repo.FullPath).Get($"branch.{Into}.mergeoptions");
var mode = config switch
{
"--ff-only" => Models.MergeMode.FastForward,

View File

@@ -96,7 +96,7 @@ namespace SourceGit.ViewModels
if (value != _settings.EnableTopoOrderInHistories)
{
_settings.EnableTopoOrderInHistories = value;
Task.Run(RefreshCommits);
RefreshCommits();
}
}
}
@@ -109,7 +109,7 @@ namespace SourceGit.ViewModels
if (value != _settings.HistoryShowFlags)
{
_settings.HistoryShowFlags = value;
Task.Run(RefreshCommits);
RefreshCommits();
}
}
}
@@ -266,7 +266,7 @@ namespace SourceGit.ViewModels
{
_settings.IncludeUntrackedInLocalChanges = value;
OnPropertyChanged();
Task.Run(RefreshWorkingCopyChanges);
RefreshWorkingCopyChanges();
}
}
}
@@ -536,7 +536,7 @@ namespace SourceGit.ViewModels
var gitDirForWatcher = _gitDir;
if (_gitDir.Replace('\\', '/').IndexOf("/worktrees/", StringComparison.Ordinal) > 0)
{
var commonDir = new Commands.QueryGitCommonDir(_fullpath).GetResultAsync().Result;
var commonDir = new Commands.QueryGitCommonDir(_fullpath).GetResult();
if (!string.IsNullOrEmpty(commonDir))
gitDirForWatcher = commonDir;
}
@@ -762,13 +762,13 @@ namespace SourceGit.ViewModels
public void RefreshAll()
{
Task.Run(RefreshCommits);
Task.Run(RefreshBranches);
Task.Run(RefreshTags);
Task.Run(RefreshSubmodules);
Task.Run(RefreshWorktrees);
Task.Run(RefreshWorkingCopyChanges);
Task.Run(RefreshStashes);
RefreshCommits();
RefreshBranches();
RefreshTags();
RefreshSubmodules();
RefreshWorktrees();
RefreshWorkingCopyChanges();
RefreshStashes();
Task.Run(async () =>
{
@@ -959,10 +959,10 @@ namespace SourceGit.ViewModels
{
if (_watcher == null)
{
Task.Run(RefreshBranches);
Task.Run(RefreshCommits);
Task.Run(RefreshWorkingCopyChanges);
Task.Run(RefreshWorktrees);
RefreshBranches();
RefreshCommits();
RefreshWorkingCopyChanges();
RefreshWorktrees();
}
else
{
@@ -974,8 +974,8 @@ namespace SourceGit.ViewModels
{
if (_watcher == null)
{
Task.Run(RefreshTags);
Task.Run(RefreshCommits);
RefreshTags();
RefreshCommits();
}
else
{
@@ -986,7 +986,7 @@ namespace SourceGit.ViewModels
public void MarkWorkingCopyDirtyManually()
{
if (_watcher == null)
Task.Run(RefreshWorkingCopyChanges);
RefreshWorkingCopyChanges();
else
_watcher.MarkWorkingCopyDirtyManually();
}
@@ -1028,7 +1028,7 @@ namespace SourceGit.ViewModels
ResetBranchTreeFilterMode(LocalBranchTrees);
ResetBranchTreeFilterMode(RemoteBranchTrees);
ResetTagFilterMode();
Task.Run(RefreshCommits);
RefreshCommits();
}
public void RemoveHistoriesFilter(Models.Filter filter)
@@ -1186,74 +1186,83 @@ namespace SourceGit.ViewModels
public void RefreshBranches()
{
var branches = new Commands.QueryBranches(_fullpath).GetResultAsync().Result;
var remotes = new Commands.QueryRemotes(_fullpath).GetResultAsync().Result;
var builder = BuildBranchTree(branches, remotes);
Dispatcher.UIThread.Invoke(() =>
Task.Run(async () =>
{
lock (_lockRemotes)
Remotes = remotes;
var branches = await new Commands.QueryBranches(_fullpath).GetResultAsync().ConfigureAwait(false);
var remotes = await new Commands.QueryRemotes(_fullpath).GetResultAsync().ConfigureAwait(false);
var builder = BuildBranchTree(branches, remotes);
Branches = branches;
CurrentBranch = branches.Find(x => x.IsCurrent);
LocalBranchTrees = builder.Locals;
RemoteBranchTrees = builder.Remotes;
var localBranchesCount = 0;
foreach (var b in branches)
Dispatcher.UIThread.Invoke(() =>
{
if (b.IsLocal && !b.IsDetachedHead)
localBranchesCount++;
}
LocalBranchesCount = localBranchesCount;
lock (_lockRemotes)
Remotes = remotes;
if (_workingCopy != null)
_workingCopy.HasRemotes = remotes.Count > 0;
Branches = branches;
CurrentBranch = branches.Find(x => x.IsCurrent);
LocalBranchTrees = builder.Locals;
RemoteBranchTrees = builder.Remotes;
var hasPendingPullOrPush = CurrentBranch?.TrackStatus.IsVisible ?? false;
GetOwnerPage()?.ChangeDirtyState(Models.DirtyState.HasPendingPullOrPush, !hasPendingPullOrPush);
var localBranchesCount = 0;
foreach (var b in branches)
{
if (b.IsLocal && !b.IsDetachedHead)
localBranchesCount++;
}
LocalBranchesCount = localBranchesCount;
if (_workingCopy != null)
_workingCopy.HasRemotes = remotes.Count > 0;
var hasPendingPullOrPush = CurrentBranch?.TrackStatus.IsVisible ?? false;
GetOwnerPage()?.ChangeDirtyState(Models.DirtyState.HasPendingPullOrPush, !hasPendingPullOrPush);
});
});
}
public void RefreshWorktrees()
{
var worktrees = new Commands.Worktree(_fullpath).ReadAllAsync().Result;
if (worktrees.Count > 0)
Task.Run(async () =>
{
var cleaned = new List<Models.Worktree>();
var normalizedGitDir = _gitDir.Replace('\\', '/');
foreach (var worktree in worktrees)
var worktrees = await new Commands.Worktree(_fullpath).ReadAllAsync().ConfigureAwait(false);
if (worktrees.Count > 0)
{
if (worktree.FullPath.Equals(_fullpath, StringComparison.Ordinal) ||
worktree.FullPath.Equals(normalizedGitDir, StringComparison.Ordinal))
continue;
var cleaned = new List<Models.Worktree>();
var normalizedGitDir = _gitDir.Replace('\\', '/');
cleaned.Add(worktree);
foreach (var worktree in worktrees)
{
if (worktree.FullPath.Equals(_fullpath, StringComparison.Ordinal) ||
worktree.FullPath.Equals(normalizedGitDir, StringComparison.Ordinal))
continue;
cleaned.Add(worktree);
}
Dispatcher.UIThread.Invoke(() =>
{
Worktrees = cleaned;
});
}
Dispatcher.UIThread.Invoke(() =>
else
{
Worktrees = cleaned;
});
}
else
{
Dispatcher.UIThread.Invoke(() =>
{
Worktrees = worktrees;
});
}
Dispatcher.UIThread.Invoke(() =>
{
Worktrees = worktrees;
});
}
});
}
public void RefreshTags()
{
var tags = new Commands.QueryTags(_fullpath).GetResultAsync().Result;
Dispatcher.UIThread.Invoke(() =>
Task.Run(async () =>
{
Tags = tags;
VisibleTags = BuildVisibleTags();
var tags = await new Commands.QueryTags(_fullpath).GetResultAsync().ConfigureAwait(false);
Dispatcher.UIThread.Invoke(() =>
{
Tags = tags;
VisibleTags = BuildVisibleTags();
});
});
}
@@ -1261,47 +1270,50 @@ namespace SourceGit.ViewModels
{
Dispatcher.UIThread.Invoke(() => _histories.IsLoading = true);
var builder = new StringBuilder();
builder.Append($"-{Preferences.Instance.MaxHistoryCommits} ");
if (_settings.EnableTopoOrderInHistories)
builder.Append("--topo-order ");
else
builder.Append("--date-order ");
if (_settings.HistoryShowFlags.HasFlag(Models.HistoryShowFlags.Reflog))
builder.Append("--reflog ");
if (_settings.HistoryShowFlags.HasFlag(Models.HistoryShowFlags.FirstParentOnly))
builder.Append("--first-parent ");
if (_settings.HistoryShowFlags.HasFlag(Models.HistoryShowFlags.SimplifyByDecoration))
builder.Append("--simplify-by-decoration ");
var filters = _settings.BuildHistoriesFilter();
if (string.IsNullOrEmpty(filters))
builder.Append("--branches --remotes --tags HEAD");
else
builder.Append(filters);
var commits = new Commands.QueryCommits(_fullpath, builder.ToString()).GetResultAsync().Result;
var graph = Models.CommitGraph.Parse(commits, _settings.HistoryShowFlags.HasFlag(Models.HistoryShowFlags.FirstParentOnly));
Dispatcher.UIThread.Invoke(() =>
Task.Run(async () =>
{
if (_histories != null)
var builder = new StringBuilder();
builder.Append($"-{Preferences.Instance.MaxHistoryCommits} ");
if (_settings.EnableTopoOrderInHistories)
builder.Append("--topo-order ");
else
builder.Append("--date-order ");
if (_settings.HistoryShowFlags.HasFlag(Models.HistoryShowFlags.Reflog))
builder.Append("--reflog ");
if (_settings.HistoryShowFlags.HasFlag(Models.HistoryShowFlags.FirstParentOnly))
builder.Append("--first-parent ");
if (_settings.HistoryShowFlags.HasFlag(Models.HistoryShowFlags.SimplifyByDecoration))
builder.Append("--simplify-by-decoration ");
var filters = _settings.BuildHistoriesFilter();
if (string.IsNullOrEmpty(filters))
builder.Append("--branches --remotes --tags HEAD");
else
builder.Append(filters);
var commits = await new Commands.QueryCommits(_fullpath, builder.ToString()).GetResultAsync().ConfigureAwait(false);
var graph = Models.CommitGraph.Parse(commits, _settings.HistoryShowFlags.HasFlag(Models.HistoryShowFlags.FirstParentOnly));
Dispatcher.UIThread.Invoke(() =>
{
_histories.IsLoading = false;
_histories.Commits = commits;
_histories.Graph = graph;
if (_histories != null)
{
_histories.IsLoading = false;
_histories.Commits = commits;
_histories.Graph = graph;
BisectState = _histories.UpdateBisectInfo();
BisectState = _histories.UpdateBisectInfo();
if (!string.IsNullOrEmpty(_navigateToCommitDelayed))
NavigateToCommit(_navigateToCommitDelayed);
}
if (!string.IsNullOrEmpty(_navigateToCommitDelayed))
NavigateToCommit(_navigateToCommitDelayed);
}
_navigateToCommitDelayed = string.Empty;
_navigateToCommitDelayed = string.Empty;
});
});
}
@@ -1321,41 +1333,44 @@ namespace SourceGit.ViewModels
return;
}
var submodules = new Commands.QuerySubmodules(_fullpath).GetResultAsync().Result;
_watcher?.SetSubmodules(submodules);
Dispatcher.UIThread.Invoke(() =>
Task.Run(async () =>
{
bool hasChanged = _submodules.Count != submodules.Count;
if (!hasChanged)
{
var old = new Dictionary<string, Models.Submodule>();
foreach (var module in _submodules)
old.Add(module.Path, module);
var submodules = await new Commands.QuerySubmodules(_fullpath).GetResultAsync().ConfigureAwait(false);
_watcher?.SetSubmodules(submodules);
foreach (var module in submodules)
Dispatcher.UIThread.Invoke(() =>
{
bool hasChanged = _submodules.Count != submodules.Count;
if (!hasChanged)
{
if (!old.TryGetValue(module.Path, out var exist))
var old = new Dictionary<string, Models.Submodule>();
foreach (var module in _submodules)
old.Add(module.Path, module);
foreach (var module in submodules)
{
hasChanged = true;
break;
if (!old.TryGetValue(module.Path, out var exist))
{
hasChanged = true;
break;
}
hasChanged = !exist.SHA.Equals(module.SHA, StringComparison.Ordinal) ||
!exist.Branch.Equals(module.Branch, StringComparison.Ordinal) ||
!exist.URL.Equals(module.URL, StringComparison.Ordinal) ||
exist.Status != module.Status;
if (hasChanged)
break;
}
hasChanged = !exist.SHA.Equals(module.SHA, StringComparison.Ordinal) ||
!exist.Branch.Equals(module.Branch, StringComparison.Ordinal) ||
!exist.URL.Equals(module.URL, StringComparison.Ordinal) ||
exist.Status != module.Status;
if (hasChanged)
break;
}
}
if (hasChanged)
{
Submodules = submodules;
VisibleSubmodules = BuildVisibleSubmodules();
}
if (hasChanged)
{
Submodules = submodules;
VisibleSubmodules = BuildVisibleSubmodules();
}
});
});
}
@@ -1364,18 +1379,24 @@ namespace SourceGit.ViewModels
if (IsBare)
return;
var changes = new Commands.QueryLocalChanges(_fullpath, _settings.IncludeUntrackedInLocalChanges).GetResultAsync().Result;
if (_workingCopy == null)
return;
changes.Sort((l, r) => Models.NumericSort.Compare(l.Path, r.Path));
_workingCopy.SetData(changes);
Dispatcher.UIThread.Invoke(() =>
Task.Run(async () =>
{
LocalChangesCount = changes.Count;
OnPropertyChanged(nameof(InProgressContext));
GetOwnerPage()?.ChangeDirtyState(Models.DirtyState.HasLocalChanges, changes.Count == 0);
var changes = await new Commands.QueryLocalChanges(_fullpath, _settings.IncludeUntrackedInLocalChanges)
.GetResultAsync()
.ConfigureAwait(false);
if (_workingCopy == null)
return;
changes.Sort((l, r) => Models.NumericSort.Compare(l.Path, r.Path));
_workingCopy.SetData(changes);
Dispatcher.UIThread.Invoke(() =>
{
LocalChangesCount = changes.Count;
OnPropertyChanged(nameof(InProgressContext));
GetOwnerPage()?.ChangeDirtyState(Models.DirtyState.HasLocalChanges, changes.Count == 0);
});
});
}
@@ -1384,13 +1405,16 @@ namespace SourceGit.ViewModels
if (IsBare)
return;
var stashes = new Commands.QueryStashes(_fullpath).GetResultAsync().Result;
Dispatcher.UIThread.Invoke(() =>
Task.Run(async () =>
{
if (_stashesPage != null)
_stashesPage.Stashes = stashes;
var stashes = await new Commands.QueryStashes(_fullpath).GetResultAsync().ConfigureAwait(false);
Dispatcher.UIThread.Invoke(() =>
{
if (_stashesPage != null)
_stashesPage.Stashes = stashes;
StashesCount = stashes.Count;
StashesCount = stashes.Count;
});
});
}
@@ -1806,8 +1830,7 @@ namespace SourceGit.ViewModels
UpdateBranchTreeFilterMode(LocalBranchTrees, filters);
UpdateBranchTreeFilterMode(RemoteBranchTrees, filters);
UpdateTagFilterMode(filters);
Task.Run(RefreshCommits);
RefreshCommits();
}
private void UpdateBranchTreeFilterMode(List<BranchTreeNode> nodes, Dictionary<string, Models.FilterMode> filters)

View File

@@ -161,7 +161,7 @@ namespace SourceGit.ViewModels
if (!AvailableOpenAIServices.Contains(PreferredOpenAIService))
PreferredOpenAIService = "---";
_cached = new Commands.Config(repo.FullPath).ReadAllAsync().Result;
_cached = new Commands.Config(repo.FullPath).ReadAll();
if (_cached.TryGetValue("user.name", out var name))
UserName = name;
if (_cached.TryGetValue("user.email", out var email))

View File

@@ -81,8 +81,7 @@ namespace SourceGit.ViewModels
_startPoint = (object)startPoint ?? new Models.Null();
_endPoint = (object)endPoint ?? new Models.Null();
CanSaveAsPatch = startPoint != null && endPoint != null;
Task.Run(Refresh);
Refresh();
}
public void Dispose()
@@ -125,7 +124,7 @@ namespace SourceGit.ViewModels
VisibleChanges = [];
SelectedChanges = [];
IsLoading = true;
Task.Run(Refresh);
Refresh();
}
public void SaveAsPatch(string saveTo)
@@ -167,28 +166,33 @@ namespace SourceGit.ViewModels
private void Refresh()
{
_changes = new Commands.CompareRevisions(_repo, GetSHA(_startPoint), GetSHA(_endPoint)).ReadAsync().Result;
var visible = _changes;
if (!string.IsNullOrWhiteSpace(_searchFilter))
Task.Run(async () =>
{
visible = [];
foreach (var c in _changes)
_changes = await new Commands.CompareRevisions(_repo, GetSHA(_startPoint), GetSHA(_endPoint))
.ReadAsync()
.ConfigureAwait(false);
var visible = _changes;
if (!string.IsNullOrWhiteSpace(_searchFilter))
{
if (c.Path.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase))
visible.Add(c);
visible = [];
foreach (var c in _changes)
{
if (c.Path.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase))
visible.Add(c);
}
}
}
Dispatcher.UIThread.Post(() =>
{
VisibleChanges = visible;
IsLoading = false;
Dispatcher.UIThread.Post(() =>
{
VisibleChanges = visible;
IsLoading = false;
if (VisibleChanges.Count > 0)
SelectedChanges = [VisibleChanges[0]];
else
SelectedChanges = [];
if (VisibleChanges.Count > 0)
SelectedChanges = [VisibleChanges[0]];
else
SelectedChanges = [];
});
});
}

View File

@@ -88,9 +88,7 @@ namespace SourceGit.ViewModels
return;
}
CommitMessage = new Commands.QueryCommitFullMessage(_repo.FullPath, currentBranch.Head)
.GetResultAsync()
.Result;
CommitMessage = new Commands.QueryCommitFullMessage(_repo.FullPath, currentBranch.Head).GetResult();
}
else
{
@@ -670,13 +668,8 @@ namespace SourceGit.ViewModels
{
if (_useAmend)
{
var head = new Commands.QuerySingleCommit(_repo.FullPath, "HEAD")
.GetResultAsync()
.Result;
return new Commands.QueryStagedChangesWithAmend(_repo.FullPath, head.Parents.Count == 0 ? Models.Commit.EmptyTreeSHA1 : $"{head.SHA}^")
.GetResultAsync()
.Result;
var head = new Commands.QuerySingleCommit(_repo.FullPath, "HEAD").GetResult();
return new Commands.QueryStagedChangesWithAmend(_repo.FullPath, head.Parents.Count == 0 ? Models.Commit.EmptyTreeSHA1 : $"{head.SHA}^").GetResult();
}
var rs = new List<Models.Change>();
@@ -722,7 +715,7 @@ namespace SourceGit.ViewModels
if (File.Exists(rebaseMsgFile))
CommitMessage = File.ReadAllText(rebaseMsgFile);
else if (rebasing.StoppedAt != null)
CommitMessage = new Commands.QueryCommitFullMessage(_repo.FullPath, rebasing.StoppedAt.SHA).GetResultAsync().Result;
CommitMessage = new Commands.QueryCommitFullMessage(_repo.FullPath, rebasing.StoppedAt.SHA).GetResult();
}
}
else if (File.Exists(Path.Combine(_repo.GitDir, "REVERT_HEAD")))
@@ -809,26 +802,14 @@ namespace SourceGit.ViewModels
log.Complete();
Dispatcher.UIThread.Post(async () =>
Dispatcher.UIThread.Post(() =>
{
if (succ)
{
CommitMessage = string.Empty;
UseAmend = false;
if (autoPush && _repo.Remotes.Count > 0)
{
if (_repo.CurrentBranch == null)
{
var currentBranchName = await new Commands.QueryCurrentBranch(_repo.FullPath).GetResultAsync();
var tmp = new Models.Branch() { Name = currentBranchName };
_repo.ShowAndStartPopup(new Push(_repo, tmp));
}
else
{
_repo.ShowAndStartPopup(new Push(_repo, null));
}
}
PushAfterCommit();
}
_repo.MarkBranchesDirtyManually();
@@ -838,6 +819,28 @@ namespace SourceGit.ViewModels
});
}
private void PushAfterCommit()
{
if (_repo.CurrentBranch == null)
{
Task.Run(async () =>
{
var currentBranchName = await new Commands.QueryCurrentBranch(_repo.FullPath).GetResultAsync();
var tmp = new Models.Branch() { Name = currentBranchName };
Dispatcher.UIThread.Post(() =>
{
if (_repo.CanCreatePopup())
_repo.ShowAndStartPopup(new Push(_repo, tmp));
});
});
}
else if (_repo.CanCreatePopup())
{
_repo.ShowAndStartPopup(new Push(_repo, null));
}
}
private bool IsChanged(List<Models.Change> old, List<Models.Change> cur)
{
if (old.Count != cur.Count)

View File

@@ -121,7 +121,7 @@ namespace SourceGit.Views
if (pref.IsGitConfigured())
{
var config = new Commands.Config(null).ReadAllAsync().Result;
var config = new Commands.Config(null).ReadAll();
if (config.TryGetValue("user.name", out var name))
DefaultUser = name;

View File

@@ -457,7 +457,7 @@ namespace SourceGit.Views
lfs.Header = App.Text("GitLFS");
lfs.Icon = App.CreateMenuIcon("Icons.LFS");
var isLFSFiltered = new Commands.IsLFSFiltered(repo.FullPath, change.Path).GetResultAsync().Result;
var isLFSFiltered = new Commands.IsLFSFiltered(repo.FullPath, change.Path).GetResult();
if (!isLFSFiltered)
{
var filename = Path.GetFileName(change.Path);