diff --git a/src/Commands/Blame.cs b/src/Commands/Blame.cs index 1fc51fa40..7613cd52e 100644 --- a/src/Commands/Blame.cs +++ b/src/Commands/Blame.cs @@ -1,6 +1,7 @@ using System; using System.Text; using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -19,9 +20,9 @@ public Blame(string repo, string file, string revision) _result.File = file; } - public Models.BlameData Result() + public async Task ResultAsync() { - var rs = ReadToEnd(); + var rs = await ReadToEndAsync(); if (!rs.IsSuccess) return _result; diff --git a/src/Commands/Branch.cs b/src/Commands/Branch.cs index f207e976e..e920413fe 100644 --- a/src/Commands/Branch.cs +++ b/src/Commands/Branch.cs @@ -1,4 +1,5 @@ using System.Text; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -13,7 +14,16 @@ public static string ShowCurrent(string repo) return cmd.ReadToEnd().StdOut.Trim(); } - public static bool Create(string repo, string name, string basedOn, bool force, Models.ICommandLog log) + public static async Task ShowCurrentAsync(string repo) + { + var cmd = new Command(); + cmd.WorkingDirectory = repo; + cmd.Context = repo; + cmd.Args = "branch --show-current"; + return (await cmd.ReadToEndAsync()).StdOut.Trim(); + } + + public static async Task CreateAsync(string repo, string name, string basedOn, bool force, Models.ICommandLog log) { var builder = new StringBuilder(); builder.Append("branch "); @@ -28,20 +38,20 @@ public static bool Create(string repo, string name, string basedOn, bool force, cmd.Context = repo; cmd.Args = builder.ToString(); cmd.Log = log; - return cmd.Exec(); + return await cmd.ExecAsync(); } - public static bool Rename(string repo, string name, string to, Models.ICommandLog log) + public static async Task RenameAsync(string repo, string name, string to, Models.ICommandLog log) { var cmd = new Command(); cmd.WorkingDirectory = repo; cmd.Context = repo; cmd.Args = $"branch -M {name} {to}"; cmd.Log = log; - return cmd.Exec(); + return await cmd.ExecAsync(); } - public static bool SetUpstream(string repo, string name, string upstream, Models.ICommandLog log) + public static async Task SetUpstreamAsync(string repo, string name, string upstream, Models.ICommandLog log) { var cmd = new Command(); cmd.WorkingDirectory = repo; @@ -53,31 +63,31 @@ public static bool SetUpstream(string repo, string name, string upstream, Models else cmd.Args = $"branch {name} -u {upstream}"; - return cmd.Exec(); + return await cmd.ExecAsync(); } - public static bool DeleteLocal(string repo, string name, Models.ICommandLog log) + public static async Task DeleteLocalAsync(string repo, string name, Models.ICommandLog log) { var cmd = new Command(); cmd.WorkingDirectory = repo; cmd.Context = repo; cmd.Args = $"branch -D {name}"; cmd.Log = log; - return cmd.Exec(); + return await cmd.ExecAsync(); } - public static bool DeleteRemote(string repo, string remote, string name, Models.ICommandLog log) + public static async Task DeleteRemoteAsync(string repo, string remote, string name, Models.ICommandLog log) { - bool exists = new Remote(repo).HasBranch(remote, name); + bool exists = await new Remote(repo).HasBranchAsync(remote, name); if (exists) - return new Push(repo, remote, $"refs/heads/{name}", true) { Log = log }.Exec(); + return await new Push(repo, remote, $"refs/heads/{name}", true) { Log = log }.ExecAsync(); var cmd = new Command(); cmd.WorkingDirectory = repo; cmd.Context = repo; cmd.Args = $"branch -D -r {remote}/{name}"; cmd.Log = log; - return cmd.Exec(); + return await cmd.ExecAsync(); } } } diff --git a/src/Commands/Checkout.cs b/src/Commands/Checkout.cs index d2876740f..87186b740 100644 --- a/src/Commands/Checkout.cs +++ b/src/Commands/Checkout.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Text; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -11,7 +12,7 @@ public Checkout(string repo) Context = repo; } - public bool Branch(string branch, bool force) + public async Task BranchAsync(string branch, bool force) { var builder = new StringBuilder(); builder.Append("checkout --progress "); @@ -20,10 +21,10 @@ public bool Branch(string branch, bool force) builder.Append(branch); Args = builder.ToString(); - return Exec(); + return await ExecAsync(); } - public bool Branch(string branch, string basedOn, bool force, bool allowOverwrite) + public async Task BranchAsync(string branch, string basedOn, bool force, bool allowOverwrite) { var builder = new StringBuilder(); builder.Append("checkout --progress "); @@ -35,17 +36,17 @@ public bool Branch(string branch, string basedOn, bool force, bool allowOverwrit builder.Append(basedOn); Args = builder.ToString(); - return Exec(); + return await ExecAsync(); } - public bool Commit(string commitId, bool force) + public async Task CommitAsync(string commitId, bool force) { var option = force ? "--force" : string.Empty; Args = $"checkout {option} --detach --progress {commitId}"; - return Exec(); + return await ExecAsync(); } - public bool UseTheirs(List files) + public async Task UseTheirsAsync(List files) { var builder = new StringBuilder(); builder.Append("checkout --theirs --"); @@ -56,10 +57,10 @@ public bool UseTheirs(List files) builder.Append("\""); } Args = builder.ToString(); - return Exec(); + return await ExecAsync(); } - public bool UseMine(List files) + public async Task UseMineAsync(List files) { var builder = new StringBuilder(); builder.Append("checkout --ours --"); @@ -69,14 +70,15 @@ public bool UseMine(List files) builder.Append(f); builder.Append("\""); } + Args = builder.ToString(); - return Exec(); + return await ExecAsync(); } - public bool FileWithRevision(string file, string revision) + public async Task FileWithRevisionAsync(string file, string revision) { Args = $"checkout --no-overlay {revision} -- \"{file}\""; - return Exec(); + return await ExecAsync(); } } } diff --git a/src/Commands/Command.cs b/src/Commands/Command.cs index caf5d0a48..03d4a8d03 100644 --- a/src/Commands/Command.cs +++ b/src/Commands/Command.cs @@ -4,6 +4,7 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -32,7 +33,39 @@ public enum EditorType public bool RaiseError { get; set; } = true; public Models.ICommandLog Log { get; set; } = null; - public bool Exec() + public ReadToEndResult ReadToEnd() + { + var start = CreateGitStartInfo(); + var proc = new Process() { StartInfo = start }; + + try + { + proc.Start(); + } + catch (Exception e) + { + return new ReadToEndResult() + { + IsSuccess = false, + StdOut = string.Empty, + StdErr = e.Message, + }; + } + + var rs = new ReadToEndResult() + { + StdOut = proc.StandardOutput.ReadToEnd(), + StdErr = proc.StandardError.ReadToEnd(), + }; + + proc.WaitForExit(); + rs.IsSuccess = proc.ExitCode == 0; + proc.Close(); + + return rs; + } + + public async Task ExecAsync() { Log?.AppendLine($"$ git {Args}\n"); @@ -74,7 +107,7 @@ public bool Exec() proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); - proc.WaitForExit(); + await proc.WaitForExitAsync(CancellationToken); if (dummy != null) { @@ -103,7 +136,7 @@ public bool Exec() return true; } - public ReadToEndResult ReadToEnd() + public async Task ReadToEndAsync() { var start = CreateGitStartInfo(); var proc = new Process() { StartInfo = start }; @@ -124,11 +157,11 @@ public ReadToEndResult ReadToEnd() var rs = new ReadToEndResult() { - StdOut = proc.StandardOutput.ReadToEnd(), - StdErr = proc.StandardError.ReadToEnd(), + StdOut = await proc.StandardOutput.ReadToEndAsync(CancellationToken), + StdErr = await proc.StandardError.ReadToEndAsync(CancellationToken), }; - proc.WaitForExit(); + await proc.WaitForExitAsync(CancellationToken); rs.IsSuccess = proc.ExitCode == 0; proc.Close(); diff --git a/src/Commands/Commit.cs b/src/Commands/Commit.cs index 1585e7e3c..453afbc8f 100644 --- a/src/Commands/Commit.cs +++ b/src/Commands/Commit.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -18,9 +19,9 @@ public Commit(string repo, string message, bool signOff, bool amend, bool resetA Args += resetAuthor ? " --amend --reset-author --no-edit" : " --amend --no-edit"; } - public bool Run() + public async Task RunAsync() { - var succ = Exec(); + var succ = await ExecAsync(); try { diff --git a/src/Commands/CompareRevisions.cs b/src/Commands/CompareRevisions.cs index c88e087ae..5530b919e 100644 --- a/src/Commands/CompareRevisions.cs +++ b/src/Commands/CompareRevisions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -43,6 +44,20 @@ public CompareRevisions(string repo, string start, string end, string path) return _changes; } + public async Task> ResultAsync() + { + var rs = await ReadToEndAsync(); + if (!rs.IsSuccess) + return _changes; + + var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); + foreach (var line in lines) + ParseLine(line); + + _changes.Sort((l, r) => Models.NumericSort.Compare(l.Path, r.Path)); + return _changes; + } + private void ParseLine(string line) { var match = REG_FORMAT().Match(line); diff --git a/src/Commands/Config.cs b/src/Commands/Config.cs index 49e8fcb7e..3e0516c53 100644 --- a/src/Commands/Config.cs +++ b/src/Commands/Config.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -51,7 +52,37 @@ public string Get(string key) return ReadToEnd().StdOut.Trim(); } - public bool Set(string key, string value, bool allowEmpty = false) + public async Task> ListAllAsync() + { + Args = "config -l"; + + var output = await ReadToEndAsync(); + var rs = new Dictionary(); + if (output.IsSuccess) + { + var lines = output.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); + foreach (var line in lines) + { + var idx = line.IndexOf('=', StringComparison.Ordinal); + if (idx != -1) + { + var key = line.Substring(0, idx).Trim(); + var val = line.Substring(idx + 1).Trim(); + rs[key] = val; + } + } + } + + return rs; + } + + public async Task GetAsync(string key) + { + Args = $"config {key}"; + return (await ReadToEndAsync()).StdOut.Trim(); + } + + public async Task SetAsync(string key, string value, bool allowEmpty = false) { var scope = _isLocal ? "--local" : "--global"; @@ -60,7 +91,7 @@ public bool Set(string key, string value, bool allowEmpty = false) else Args = $"config {scope} {key} \"{value}\""; - return Exec(); + return await ExecAsync(); } private bool _isLocal = false; diff --git a/src/Commands/CountLocalChangesWithoutUntracked.cs b/src/Commands/CountLocalChangesWithoutUntracked.cs index a704f313e..b59368bf7 100644 --- a/src/Commands/CountLocalChangesWithoutUntracked.cs +++ b/src/Commands/CountLocalChangesWithoutUntracked.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -11,9 +12,9 @@ public CountLocalChangesWithoutUntracked(string repo) Args = "--no-optional-locks status -uno --ignore-submodules=all --porcelain"; } - public int Result() + public async Task ResultAsync() { - var rs = ReadToEnd(); + var rs = await ReadToEndAsync(); if (rs.IsSuccess) { var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); diff --git a/src/Commands/Diff.cs b/src/Commands/Diff.cs index 6af0a3cc6..d56e21bdb 100644 --- a/src/Commands/Diff.cs +++ b/src/Commands/Diff.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -35,9 +36,9 @@ public Diff(string repo, Models.DiffOption opt, int unified, bool ignoreWhitespa Args = $"diff --no-ext-diff --patch --unified={unified} {opt}"; } - public Models.DiffResult Result() + public async Task ResultAsync() { - var rs = ReadToEnd(); + var rs = await ReadToEndAsync(); var start = 0; var end = rs.StdOut.IndexOf('\n', start); while (end > 0) diff --git a/src/Commands/Discard.cs b/src/Commands/Discard.cs index 6f076bb10..6f5a1eb7f 100644 --- a/src/Commands/Discard.cs +++ b/src/Commands/Discard.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -12,9 +13,9 @@ public static class Discard /// /// /// - public static void All(string repo, bool includeIgnored, Models.ICommandLog log) + public static async Task AllAsync(string repo, bool includeIgnored, Models.ICommandLog log) { - var changes = new QueryLocalChanges(repo).Result(); + var changes = await new QueryLocalChanges(repo).ResultAsync(); try { foreach (var c in changes) @@ -37,10 +38,10 @@ public static void All(string repo, bool includeIgnored, Models.ICommandLog log) App.RaiseException(repo, $"Failed to discard changes. Reason: {e.Message}"); } - new Reset(repo, "HEAD", "--hard") { Log = log }.Exec(); + await new Reset(repo, "HEAD", "--hard") { Log = log }.ExecAsync(); if (includeIgnored) - new Clean(repo) { Log = log }.Exec(); + await new Clean(repo) { Log = log }.ExecAsync(); } /// @@ -49,7 +50,7 @@ public static void All(string repo, bool includeIgnored, Models.ICommandLog log) /// /// /// - public static void Changes(string repo, List changes, Models.ICommandLog log) + public static async Task ChangesAsync(string repo, List changes, Models.ICommandLog log) { var restores = new List(); @@ -79,8 +80,8 @@ public static void Changes(string repo, List changes, Models.ICom if (restores.Count > 0) { var pathSpecFile = Path.GetTempFileName(); - File.WriteAllLines(pathSpecFile, restores); - new Restore(repo, pathSpecFile, false) { Log = log }.Exec(); + await File.WriteAllLinesAsync(pathSpecFile, restores); + await new Restore(repo, pathSpecFile, false) { Log = log }.ExecAsync(); File.Delete(pathSpecFile); } } diff --git a/src/Commands/GenerateCommitMessage.cs b/src/Commands/GenerateCommitMessage.cs index 7b486abd1..2292a56a7 100644 --- a/src/Commands/GenerateCommitMessage.cs +++ b/src/Commands/GenerateCommitMessage.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Text; using System.Threading; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -29,7 +30,7 @@ public GenerateCommitMessage(Models.OpenAIService service, string repo, List InitAsync(string repo, string master, string develop, string feature, string release, string hotfix, string version, Models.ICommandLog log) { var config = new Config(repo); - config.Set("gitflow.branch.master", master); - config.Set("gitflow.branch.develop", develop); - config.Set("gitflow.prefix.feature", feature); - config.Set("gitflow.prefix.bugfix", "bugfix/"); - config.Set("gitflow.prefix.release", release); - config.Set("gitflow.prefix.hotfix", hotfix); - config.Set("gitflow.prefix.support", "support/"); - config.Set("gitflow.prefix.versiontag", version, true); + await config.SetAsync("gitflow.branch.master", master); + await config.SetAsync("gitflow.branch.develop", develop); + await config.SetAsync("gitflow.prefix.feature", feature); + await config.SetAsync("gitflow.prefix.bugfix", "bugfix/"); + await config.SetAsync("gitflow.prefix.release", release); + await config.SetAsync("gitflow.prefix.hotfix", hotfix); + await config.SetAsync("gitflow.prefix.support", "support/"); + await config.SetAsync("gitflow.prefix.versiontag", version, true); var init = new Command(); init.WorkingDirectory = repo; init.Context = repo; init.Args = "flow init -d"; init.Log = log; - return init.Exec(); + return await init.ExecAsync(); } - public static bool Start(string repo, Models.GitFlowBranchType type, string name, Models.ICommandLog log) + public static async Task StartAsync(string repo, Models.GitFlowBranchType type, string name, Models.ICommandLog log) { var start = new Command(); start.WorkingDirectory = repo; @@ -47,10 +48,10 @@ public static bool Start(string repo, Models.GitFlowBranchType type, string name } start.Log = log; - return start.Exec(); + return await start.ExecAsync(); } - public static bool Finish(string repo, Models.GitFlowBranchType type, string name, bool squash, bool push, bool keepBranch, Models.ICommandLog log) + public static async Task FinishAsync(string repo, Models.GitFlowBranchType type, string name, bool squash, bool push, bool keepBranch, Models.ICommandLog log) { var builder = new StringBuilder(); builder.Append("flow "); @@ -85,7 +86,7 @@ public static bool Finish(string repo, Models.GitFlowBranchType type, string nam finish.Context = repo; finish.Args = builder.ToString(); finish.Log = log; - return finish.Exec(); + return await finish.ExecAsync(); } } } diff --git a/src/Commands/IsBareRepository.cs b/src/Commands/IsBareRepository.cs index f92d0888f..2b67a5e3f 100644 --- a/src/Commands/IsBareRepository.cs +++ b/src/Commands/IsBareRepository.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -20,5 +21,16 @@ public bool Result() var rs = ReadToEnd(); return rs.IsSuccess && rs.StdOut.Trim() == "true"; } + + public async Task ResultAsync() + { + if (!Directory.Exists(Path.Combine(WorkingDirectory, "refs")) || + !Directory.Exists(Path.Combine(WorkingDirectory, "objects")) || + !File.Exists(Path.Combine(WorkingDirectory, "HEAD"))) + return false; + + var rs = await ReadToEndAsync(); + return rs.IsSuccess && rs.StdOut.Trim() == "true"; + } } } diff --git a/src/Commands/IsBinary.cs b/src/Commands/IsBinary.cs index af8f54bbb..f540a71ad 100644 --- a/src/Commands/IsBinary.cs +++ b/src/Commands/IsBinary.cs @@ -1,4 +1,5 @@ using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -15,9 +16,9 @@ public IsBinary(string repo, string commit, string path) RaiseError = false; } - public bool Result() + public async Task ResultAsync() { - return REG_TEST().IsMatch(ReadToEnd().StdOut); + return REG_TEST().IsMatch((await ReadToEndAsync()).StdOut); } } } diff --git a/src/Commands/IsCommitSHA.cs b/src/Commands/IsCommitSHA.cs index 1b0c50e3b..5ebba6cbd 100644 --- a/src/Commands/IsCommitSHA.cs +++ b/src/Commands/IsCommitSHA.cs @@ -1,4 +1,6 @@ -namespace SourceGit.Commands +using System.Threading.Tasks; + +namespace SourceGit.Commands { public class IsCommitSHA : Command { @@ -8,9 +10,9 @@ public IsCommitSHA(string repo, string hash) Args = $"cat-file -t {hash}"; } - public bool Result() + public async Task ResultAsync() { - var rs = ReadToEnd(); + var rs = await ReadToEndAsync(); return rs.IsSuccess && rs.StdOut.Trim().Equals("commit"); } } diff --git a/src/Commands/IsConflictResolved.cs b/src/Commands/IsConflictResolved.cs index 9b2434515..f986c3250 100644 --- a/src/Commands/IsConflictResolved.cs +++ b/src/Commands/IsConflictResolved.cs @@ -1,4 +1,6 @@ -namespace SourceGit.Commands +using System.Threading.Tasks; + +namespace SourceGit.Commands { public class IsConflictResolved : Command { @@ -15,5 +17,10 @@ public bool Result() { return ReadToEnd().IsSuccess; } + + public async Task ResultAsync() + { + return (await ReadToEndAsync()).IsSuccess; + } } } diff --git a/src/Commands/IsLFSFiltered.cs b/src/Commands/IsLFSFiltered.cs index 2a7234bbb..171f6e9b3 100644 --- a/src/Commands/IsLFSFiltered.cs +++ b/src/Commands/IsLFSFiltered.cs @@ -1,4 +1,6 @@ -namespace SourceGit.Commands +using System.Threading.Tasks; + +namespace SourceGit.Commands { public class IsLFSFiltered : Command { @@ -23,5 +25,11 @@ public bool Result() var rs = ReadToEnd(); return rs.IsSuccess && rs.StdOut.Contains("filter\0lfs"); } + + public async Task ResultAsync() + { + var rs = await ReadToEndAsync(); + return rs.IsSuccess && rs.StdOut.Contains("filter\0lfs"); + } } } diff --git a/src/Commands/LFS.cs b/src/Commands/LFS.cs index 18d2ba934..b168a1e44 100644 --- a/src/Commands/LFS.cs +++ b/src/Commands/LFS.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -36,42 +37,42 @@ public bool IsEnabled() return content.Contains("git lfs pre-push"); } - public bool Install(Models.ICommandLog log) + public async Task InstallAsync(Models.ICommandLog log) { - return new SubCmd(_repo, "lfs install --local", log).Exec(); + return await new SubCmd(_repo, "lfs install --local", log).ExecAsync(); } - public bool Track(string pattern, bool isFilenameMode, Models.ICommandLog log) + public async Task TrackAsync(string pattern, bool isFilenameMode, Models.ICommandLog log) { var opt = isFilenameMode ? "--filename" : ""; - return new SubCmd(_repo, $"lfs track {opt} \"{pattern}\"", log).Exec(); + return await new SubCmd(_repo, $"lfs track {opt} \"{pattern}\"", log).ExecAsync(); } - public void Fetch(string remote, Models.ICommandLog log) + public async Task FetchAsync(string remote, Models.ICommandLog log) { - new SubCmd(_repo, $"lfs fetch {remote}", log).Exec(); + await new SubCmd(_repo, $"lfs fetch {remote}", log).ExecAsync(); } - public void Pull(string remote, Models.ICommandLog log) + public async Task PullAsync(string remote, Models.ICommandLog log) { - new SubCmd(_repo, $"lfs pull {remote}", log).Exec(); + await new SubCmd(_repo, $"lfs pull {remote}", log).ExecAsync(); } - public void Push(string remote, Models.ICommandLog log) + public async Task PushAsync(string remote, Models.ICommandLog log) { - new SubCmd(_repo, $"lfs push {remote}", log).Exec(); + await new SubCmd(_repo, $"lfs push {remote}", log).ExecAsync(); } - public void Prune(Models.ICommandLog log) + public async Task PruneAsync(Models.ICommandLog log) { - new SubCmd(_repo, "lfs prune", log).Exec(); + await new SubCmd(_repo, "lfs prune", log).ExecAsync(); } - public List Locks(string remote) + public async Task> LocksAsync(string remote) { var locks = new List(); var cmd = new SubCmd(_repo, $"lfs locks --remote={remote}", null); - var rs = cmd.ReadToEnd(); + var rs = await cmd.ReadToEndAsync(); if (rs.IsSuccess) { var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); @@ -93,21 +94,21 @@ public void Prune(Models.ICommandLog log) return locks; } - public bool Lock(string remote, string file, Models.ICommandLog log) + public async Task LockAsync(string remote, string file, Models.ICommandLog log) { - return new SubCmd(_repo, $"lfs lock --remote={remote} \"{file}\"", log).Exec(); + return await new SubCmd(_repo, $"lfs lock --remote={remote} \"{file}\"", log).ExecAsync(); } - public bool Unlock(string remote, string file, bool force, Models.ICommandLog log) + public async Task UnlockAsync(string remote, string file, bool force, Models.ICommandLog log) { var opt = force ? "-f" : ""; - return new SubCmd(_repo, $"lfs unlock --remote={remote} {opt} \"{file}\"", log).Exec(); + return await new SubCmd(_repo, $"lfs unlock --remote={remote} {opt} \"{file}\"", log).ExecAsync(); } - public bool Unlock(string remote, long id, bool force, Models.ICommandLog log) + public async Task UnlockAsync(string remote, long id, bool force, Models.ICommandLog log) { var opt = force ? "-f" : ""; - return new SubCmd(_repo, $"lfs unlock --remote={remote} {opt} --id={id}", log).Exec(); + return await new SubCmd(_repo, $"lfs unlock --remote={remote} {opt} --id={id}", log).ExecAsync(); } private readonly string _repo; diff --git a/src/Commands/MergeTool.cs b/src/Commands/MergeTool.cs index bdc948813..806178856 100644 --- a/src/Commands/MergeTool.cs +++ b/src/Commands/MergeTool.cs @@ -1,10 +1,11 @@ using System.IO; +using System.Threading.Tasks; namespace SourceGit.Commands { public static class MergeTool { - public static bool OpenForMerge(string repo, int toolType, string toolPath, string file) + public static async Task OpenForMergeAsync(string repo, int toolType, string toolPath, string file) { var cmd = new Command(); cmd.WorkingDirectory = repo; @@ -17,7 +18,7 @@ public static bool OpenForMerge(string repo, int toolType, string toolPath, stri if (toolType == 0) { cmd.Args = $"mergetool {fileArg}"; - return cmd.Exec(); + return await cmd.ExecAsync(); } if (!File.Exists(toolPath)) @@ -34,10 +35,10 @@ public static bool OpenForMerge(string repo, int toolType, string toolPath, stri } cmd.Args = $"-c mergetool.sourcegit.cmd=\"\\\"{toolPath}\\\" {supported.Cmd}\" -c mergetool.writeToTemp=true -c mergetool.keepBackup=false -c mergetool.trustExitCode=true mergetool --tool=sourcegit {fileArg}"; - return cmd.Exec(); + return await cmd.ExecAsync(); } - public static bool OpenForDiff(string repo, int toolType, string toolPath, Models.DiffOption option) + public static async Task OpenForDiffAsync(string repo, int toolType, string toolPath, Models.DiffOption option) { var cmd = new Command(); cmd.WorkingDirectory = repo; @@ -47,7 +48,7 @@ public static bool OpenForDiff(string repo, int toolType, string toolPath, Model if (toolType == 0) { cmd.Args = $"difftool -g --no-prompt {option}"; - return cmd.Exec(); + return await cmd.ExecAsync(); } if (!File.Exists(toolPath)) @@ -64,7 +65,7 @@ public static bool OpenForDiff(string repo, int toolType, string toolPath, Model } cmd.Args = $"-c difftool.sourcegit.cmd=\"\\\"{toolPath}\\\" {supported.DiffCmd}\" difftool --tool=sourcegit --no-prompt {option}"; - return cmd.Exec(); + return await cmd.ExecAsync(); } } } diff --git a/src/Commands/QueryAssumeUnchangedFiles.cs b/src/Commands/QueryAssumeUnchangedFiles.cs index b5c23b0b0..0d13e51a0 100644 --- a/src/Commands/QueryAssumeUnchangedFiles.cs +++ b/src/Commands/QueryAssumeUnchangedFiles.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -16,10 +17,10 @@ public QueryAssumeUnchangedFiles(string repo) RaiseError = false; } - public List Result() + public async Task> ResultAsync() { var outs = new List(); - var rs = ReadToEnd(); + var rs = await ReadToEndAsync(); var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) { diff --git a/src/Commands/QueryBranches.cs b/src/Commands/QueryBranches.cs index f268d7092..653d1cc8b 100644 --- a/src/Commands/QueryBranches.cs +++ b/src/Commands/QueryBranches.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -61,6 +62,46 @@ public QueryBranches(string repo) return branches; } + public async Task> ResultAsync() + { + var branches = new List(); + var rs = await ReadToEndAsync(); + if (!rs.IsSuccess) + return branches; + + var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); + var remoteHeads = new Dictionary(); + foreach (var line in lines) + { + var b = ParseLine(line); + if (b != null) + { + branches.Add(b); + if (!b.IsLocal) + remoteHeads.Add(b.FullName, b.Head); + } + } + + foreach (var b in branches) + { + if (b.IsLocal && !string.IsNullOrEmpty(b.Upstream)) + { + if (remoteHeads.TryGetValue(b.Upstream, out var upstreamHead)) + { + b.IsUpstreamGone = false; + b.TrackStatus ??= await new QueryTrackStatus(WorkingDirectory, b.Head, upstreamHead).ResultAsync(); + } + else + { + b.IsUpstreamGone = true; + b.TrackStatus ??= new Models.BranchTrackStatus(); + } + } + } + + return branches; + } + private Models.Branch ParseLine(string line) { var parts = line.Split('\0'); diff --git a/src/Commands/QueryCommitChildren.cs b/src/Commands/QueryCommitChildren.cs index 4e99ce7a5..f4b049962 100644 --- a/src/Commands/QueryCommitChildren.cs +++ b/src/Commands/QueryCommitChildren.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -13,9 +14,9 @@ public QueryCommitChildren(string repo, string commit, int max) Args = $"rev-list -{max} --parents --branches --remotes --ancestry-path ^{commit}"; } - public List Result() + public async Task> ResultAsync() { - var rs = ReadToEnd(); + var rs = await ReadToEndAsync(); var outs = new List(); if (rs.IsSuccess) { diff --git a/src/Commands/QueryCommitFullMessage.cs b/src/Commands/QueryCommitFullMessage.cs index 36b6d1c7c..f0788c1fd 100644 --- a/src/Commands/QueryCommitFullMessage.cs +++ b/src/Commands/QueryCommitFullMessage.cs @@ -1,3 +1,5 @@ +using System.Threading.Tasks; + namespace SourceGit.Commands { public class QueryCommitFullMessage : Command @@ -16,5 +18,13 @@ public string Result() return rs.StdOut.TrimEnd(); return string.Empty; } + + public async Task ResultAsync() + { + var rs = await ReadToEndAsync(); + if (rs.IsSuccess) + return rs.StdOut.TrimEnd(); + return string.Empty; + } } } diff --git a/src/Commands/QueryCommitSignInfo.cs b/src/Commands/QueryCommitSignInfo.cs index 133949af2..312e9e1dc 100644 --- a/src/Commands/QueryCommitSignInfo.cs +++ b/src/Commands/QueryCommitSignInfo.cs @@ -1,4 +1,6 @@ -namespace SourceGit.Commands +using System.Threading.Tasks; + +namespace SourceGit.Commands { public class QueryCommitSignInfo : Command { @@ -12,9 +14,9 @@ public QueryCommitSignInfo(string repo, string sha, bool useFakeSignersFile) Args = $"{(useFakeSignersFile ? fakeSignersFileArg : string.Empty)} {baseArgs} {sha}"; } - public Models.CommitSignInfo Result() + public async Task ResultAsync() { - var rs = ReadToEnd(); + var rs = await ReadToEndAsync(); if (!rs.IsSuccess) return null; diff --git a/src/Commands/QueryCommits.cs b/src/Commands/QueryCommits.cs index 8ac9cbc5e..b386f5115 100644 --- a/src/Commands/QueryCommits.cs +++ b/src/Commands/QueryCommits.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -146,6 +147,88 @@ private void MarkFirstMerged() } } + public async Task> ResultAsync() + { + var rs = await ReadToEndAsync(); + if (!rs.IsSuccess) + return _commits; + + var nextPartIdx = 0; + var start = 0; + var end = rs.StdOut.IndexOf('\n', start); + while (end > 0) + { + var line = rs.StdOut.Substring(start, end - start); + switch (nextPartIdx) + { + case 0: + _current = new Models.Commit() { SHA = line }; + _commits.Add(_current); + break; + case 1: + ParseParent(line); + break; + case 2: + _current.ParseDecorators(line); + if (_current.IsMerged && !_isHeadFounded) + _isHeadFounded = true; + break; + case 3: + _current.Author = Models.User.FindOrAdd(line); + break; + case 4: + _current.AuthorTime = ulong.Parse(line); + break; + case 5: + _current.Committer = Models.User.FindOrAdd(line); + break; + case 6: + _current.CommitterTime = ulong.Parse(line); + break; + case 7: + _current.Subject = line; + nextPartIdx = -1; + break; + } + + nextPartIdx++; + + start = end + 1; + end = rs.StdOut.IndexOf('\n', start); + } + + if (start < rs.StdOut.Length) + _current.Subject = rs.StdOut.Substring(start); + + if (_findFirstMerged && !_isHeadFounded && _commits.Count > 0) + await MarkFirstMergedAsync(); + + return _commits; + } + + private async Task MarkFirstMergedAsync() + { + Args = $"log --since=\"{_commits[^1].CommitterTimeStr}\" --format=\"%H\""; + + var rs = await ReadToEndAsync(); + var shas = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); + if (shas.Length == 0) + return; + + var set = new HashSet(); + foreach (var sha in shas) + set.Add(sha); + + foreach (var c in _commits) + { + if (set.Contains(c.SHA)) + { + c.IsMerged = true; + break; + } + } + } + private List _commits = new List(); private Models.Commit _current = null; private bool _findFirstMerged = false; diff --git a/src/Commands/QueryCommitsForInteractiveRebase.cs b/src/Commands/QueryCommitsForInteractiveRebase.cs index 9f2383198..273a6bcfb 100644 --- a/src/Commands/QueryCommitsForInteractiveRebase.cs +++ b/src/Commands/QueryCommitsForInteractiveRebase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -14,9 +15,9 @@ public QueryCommitsForInteractiveRebase(string repo, string on) Args = $"log --date-order --no-show-signature --decorate=full --format=\"%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%B%n{_boundary}\" {on}..HEAD"; } - public List Result() + public async Task> ResultAsync() { - var rs = ReadToEnd(); + var rs = await ReadToEndAsync(); if (!rs.IsSuccess) return _commits; diff --git a/src/Commands/QueryFileContent.cs b/src/Commands/QueryFileContent.cs index 648b90582..78fe20606 100644 --- a/src/Commands/QueryFileContent.cs +++ b/src/Commands/QueryFileContent.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.IO; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -69,5 +70,69 @@ public static Stream FromLFS(string repo, string oid, long size) return stream; } + + public static async Task RunAsync(string repo, string revision, string file) + { + var starter = new ProcessStartInfo(); + starter.WorkingDirectory = repo; + starter.FileName = Native.OS.GitExecutable; + starter.Arguments = $"show {revision}:\"{file}\""; + starter.UseShellExecute = false; + starter.CreateNoWindow = true; + starter.WindowStyle = ProcessWindowStyle.Hidden; + starter.RedirectStandardOutput = true; + + var stream = new MemoryStream(); + try + { + var proc = new Process() { StartInfo = starter }; + proc.Start(); + await proc.StandardOutput.BaseStream.CopyToAsync(stream); + await proc.WaitForExitAsync(); + proc.Close(); + + stream.Position = 0; + } + catch (Exception e) + { + App.RaiseException(repo, $"Failed to query file content: {e}"); + } + + return stream; + } + + public static async Task FromLFSAsync(string repo, string oid, long size) + { + var starter = new ProcessStartInfo(); + starter.WorkingDirectory = repo; + starter.FileName = Native.OS.GitExecutable; + starter.Arguments = "lfs smudge"; + starter.UseShellExecute = false; + starter.CreateNoWindow = true; + starter.WindowStyle = ProcessWindowStyle.Hidden; + starter.RedirectStandardInput = true; + starter.RedirectStandardOutput = true; + + var stream = new MemoryStream(); + try + { + var proc = new Process() { StartInfo = starter }; + proc.Start(); + await proc.StandardInput.WriteLineAsync("version https://git-lfs.github.com/spec/v1"); + await proc.StandardInput.WriteLineAsync($"oid sha256:{oid}"); + await proc.StandardInput.WriteLineAsync($"size {size}"); + await proc.StandardOutput.BaseStream.CopyToAsync(stream); + await proc.WaitForExitAsync(); + proc.Close(); + + stream.Position = 0; + } + catch (Exception e) + { + App.RaiseException(repo, $"Failed to query file content: {e}"); + } + + return stream; + } } } diff --git a/src/Commands/QueryFileSize.cs b/src/Commands/QueryFileSize.cs index 30af77151..b30b0a245 100644 --- a/src/Commands/QueryFileSize.cs +++ b/src/Commands/QueryFileSize.cs @@ -1,4 +1,5 @@ using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -14,9 +15,9 @@ public QueryFileSize(string repo, string file, string revision) Args = $"ls-tree {revision} -l -- \"{file}\""; } - public long Result() + public async Task ResultAsync() { - var rs = ReadToEnd(); + var rs = await ReadToEndAsync(); if (rs.IsSuccess) { var match = REG_FORMAT().Match(rs.StdOut); diff --git a/src/Commands/QueryGitCommonDir.cs b/src/Commands/QueryGitCommonDir.cs index 1076243e7..875a88df0 100644 --- a/src/Commands/QueryGitCommonDir.cs +++ b/src/Commands/QueryGitCommonDir.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -22,5 +23,17 @@ public string Result() return rs; return Path.GetFullPath(Path.Combine(WorkingDirectory, rs)); } + + public async Task ResultAsync() + { + var rs = (await ReadToEndAsync()).StdOut; + if (string.IsNullOrEmpty(rs)) + return null; + + rs = rs.Trim(); + if (Path.IsPathRooted(rs)) + return rs; + return Path.GetFullPath(Path.Combine(WorkingDirectory, rs)); + } } } diff --git a/src/Commands/QueryGitDir.cs b/src/Commands/QueryGitDir.cs index e3a94baf6..3c2831d11 100644 --- a/src/Commands/QueryGitDir.cs +++ b/src/Commands/QueryGitDir.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -22,5 +23,17 @@ public string Result() return rs; return Path.GetFullPath(Path.Combine(WorkingDirectory, rs)); } + + public async Task ResultAsync() + { + var rs = (await ReadToEndAsync()).StdOut; + if (string.IsNullOrEmpty(rs)) + return null; + + rs = rs.Trim(); + if (Path.IsPathRooted(rs)) + return rs; + return Path.GetFullPath(Path.Combine(WorkingDirectory, rs)); + } } } diff --git a/src/Commands/QueryLocalChanges.cs b/src/Commands/QueryLocalChanges.cs index bf331e93e..e27162a30 100644 --- a/src/Commands/QueryLocalChanges.cs +++ b/src/Commands/QueryLocalChanges.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -159,5 +160,148 @@ public QueryLocalChanges(string repo, bool includeUntracked = true) return outs; } + + public async Task> ResultAsync() + { + var outs = new List(); + var rs = await ReadToEndAsync(); + if (!rs.IsSuccess) + { + App.RaiseException(Context, rs.StdErr); + return outs; + } + + var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); + foreach (var line in lines) + { + var match = REG_FORMAT().Match(line); + if (!match.Success) + continue; + + var change = new Models.Change() { Path = match.Groups[2].Value }; + var status = match.Groups[1].Value; + + switch (status) + { + case " M": + change.Set(Models.ChangeState.None, Models.ChangeState.Modified); + break; + case " T": + change.Set(Models.ChangeState.None, Models.ChangeState.TypeChanged); + break; + case " A": + change.Set(Models.ChangeState.None, Models.ChangeState.Added); + break; + case " D": + change.Set(Models.ChangeState.None, Models.ChangeState.Deleted); + break; + case " R": + change.Set(Models.ChangeState.None, Models.ChangeState.Renamed); + break; + case " C": + change.Set(Models.ChangeState.None, Models.ChangeState.Copied); + break; + case "M": + change.Set(Models.ChangeState.Modified); + break; + case "MM": + change.Set(Models.ChangeState.Modified, Models.ChangeState.Modified); + break; + case "MT": + change.Set(Models.ChangeState.Modified, Models.ChangeState.TypeChanged); + break; + case "MD": + change.Set(Models.ChangeState.Modified, Models.ChangeState.Deleted); + break; + case "T": + change.Set(Models.ChangeState.TypeChanged); + break; + case "TM": + change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.Modified); + break; + case "TT": + change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.TypeChanged); + break; + case "TD": + change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.Deleted); + break; + case "A": + change.Set(Models.ChangeState.Added); + break; + case "AM": + change.Set(Models.ChangeState.Added, Models.ChangeState.Modified); + break; + case "AT": + change.Set(Models.ChangeState.Added, Models.ChangeState.TypeChanged); + break; + case "AD": + change.Set(Models.ChangeState.Added, Models.ChangeState.Deleted); + break; + case "D": + change.Set(Models.ChangeState.Deleted); + break; + case "R": + change.Set(Models.ChangeState.Renamed); + break; + case "RM": + change.Set(Models.ChangeState.Renamed, Models.ChangeState.Modified); + break; + case "RT": + change.Set(Models.ChangeState.Renamed, Models.ChangeState.TypeChanged); + break; + case "RD": + change.Set(Models.ChangeState.Renamed, Models.ChangeState.Deleted); + break; + case "C": + change.Set(Models.ChangeState.Copied); + break; + case "CM": + change.Set(Models.ChangeState.Copied, Models.ChangeState.Modified); + break; + case "CT": + change.Set(Models.ChangeState.Copied, Models.ChangeState.TypeChanged); + break; + case "CD": + change.Set(Models.ChangeState.Copied, Models.ChangeState.Deleted); + break; + case "DD": + change.ConflictReason = Models.ConflictReason.BothDeleted; + change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted); + break; + case "AU": + change.ConflictReason = Models.ConflictReason.AddedByUs; + change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted); + break; + case "UD": + change.ConflictReason = Models.ConflictReason.DeletedByThem; + change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted); + break; + case "UA": + change.ConflictReason = Models.ConflictReason.AddedByThem; + change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted); + break; + case "DU": + change.ConflictReason = Models.ConflictReason.DeletedByUs; + change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted); + break; + case "AA": + change.ConflictReason = Models.ConflictReason.BothAdded; + change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted); + break; + case "UU": + change.ConflictReason = Models.ConflictReason.BothModified; + change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted); + break; + case "??": + change.Set(Models.ChangeState.None, Models.ChangeState.Untracked); + break; + } + + if (change.Index != Models.ChangeState.None || change.WorkTree != Models.ChangeState.None) + outs.Add(change); + } + + return outs; + } } } diff --git a/src/Commands/QueryRefsContainsCommit.cs b/src/Commands/QueryRefsContainsCommit.cs index cabe1b504..8e4cf8715 100644 --- a/src/Commands/QueryRefsContainsCommit.cs +++ b/src/Commands/QueryRefsContainsCommit.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -36,5 +37,30 @@ public QueryRefsContainsCommit(string repo, string commit) return rs; } + + public async Task> ResultAsync() + { + var rs = new List(); + + var output = await ReadToEndAsync(); + if (!output.IsSuccess) + return rs; + + var lines = output.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); + foreach (var line in lines) + { + if (line.EndsWith("/HEAD", StringComparison.Ordinal)) + continue; + + if (line.StartsWith("refs/heads/", StringComparison.Ordinal)) + rs.Add(new() { Name = line.Substring("refs/heads/".Length), Type = Models.DecoratorType.LocalBranchHead }); + else if (line.StartsWith("refs/remotes/", StringComparison.Ordinal)) + rs.Add(new() { Name = line.Substring("refs/remotes/".Length), Type = Models.DecoratorType.RemoteBranchHead }); + else if (line.StartsWith("refs/tags/", StringComparison.Ordinal)) + rs.Add(new() { Name = line.Substring("refs/tags/".Length), Type = Models.DecoratorType.Tag }); + } + + return rs; + } } } diff --git a/src/Commands/QueryRemotes.cs b/src/Commands/QueryRemotes.cs index 7afec74dc..c91b658be 100644 --- a/src/Commands/QueryRemotes.cs +++ b/src/Commands/QueryRemotes.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -44,5 +45,34 @@ public QueryRemotes(string repo) return outs; } + + public async Task> ResultAsync() + { + var outs = new List(); + var rs = await ReadToEndAsync(); + if (!rs.IsSuccess) + return outs; + + var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); + foreach (var line in lines) + { + var match = REG_REMOTE().Match(line); + if (!match.Success) + continue; + + var remote = new Models.Remote() + { + Name = match.Groups[1].Value, + URL = match.Groups[2].Value, + }; + + if (outs.Find(x => x.Name == remote.Name) != null) + continue; + + outs.Add(remote); + } + + return outs; + } } } diff --git a/src/Commands/QueryRevisionByRefName.cs b/src/Commands/QueryRevisionByRefName.cs index 7fb4ecfa4..ef0240d47 100644 --- a/src/Commands/QueryRevisionByRefName.cs +++ b/src/Commands/QueryRevisionByRefName.cs @@ -1,4 +1,6 @@ -namespace SourceGit.Commands +using System.Threading.Tasks; + +namespace SourceGit.Commands { public class QueryRevisionByRefName : Command { @@ -17,5 +19,14 @@ public string Result() return null; } + + public async Task ResultAsync() + { + var rs = await ReadToEndAsync(); + if (rs.IsSuccess && !string.IsNullOrEmpty(rs.StdOut)) + return rs.StdOut.Trim(); + + return null; + } } } diff --git a/src/Commands/QueryRevisionFileNames.cs b/src/Commands/QueryRevisionFileNames.cs index c6fd73735..6a1c5462c 100644 --- a/src/Commands/QueryRevisionFileNames.cs +++ b/src/Commands/QueryRevisionFileNames.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -11,9 +12,9 @@ public QueryRevisionFileNames(string repo, string revision) Args = $"ls-tree -r -z --name-only {revision}"; } - public List Result() + public async Task> ResultAsync() { - var rs = ReadToEnd(); + var rs = await ReadToEndAsync(); if (!rs.IsSuccess) return []; diff --git a/src/Commands/QueryRevisionObjects.cs b/src/Commands/QueryRevisionObjects.cs index 5c582dcce..40fc55b1e 100644 --- a/src/Commands/QueryRevisionObjects.cs +++ b/src/Commands/QueryRevisionObjects.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -40,6 +41,28 @@ public QueryRevisionObjects(string repo, string sha, string parentFolder) return _objects; } + public async Task> ResultAsync() + { + var rs = await ReadToEndAsync(); + if (rs.IsSuccess) + { + var start = 0; + var end = rs.StdOut.IndexOf('\0', start); + while (end > 0) + { + var line = rs.StdOut.Substring(start, end - start); + Parse(line); + start = end + 1; + end = rs.StdOut.IndexOf('\0', start); + } + + if (start < rs.StdOut.Length) + Parse(rs.StdOut.Substring(start)); + } + + return _objects; + } + private void Parse(string line) { var match = REG_FORMAT().Match(line); diff --git a/src/Commands/QuerySingleCommit.cs b/src/Commands/QuerySingleCommit.cs index 35289ec58..e35df36aa 100644 --- a/src/Commands/QuerySingleCommit.cs +++ b/src/Commands/QuerySingleCommit.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -37,5 +38,32 @@ public Models.Commit Result() return null; } + + public async Task ResultAsync() + { + var rs = await ReadToEndAsync(); + if (rs.IsSuccess && !string.IsNullOrEmpty(rs.StdOut)) + { + var commit = new Models.Commit(); + var lines = rs.StdOut.Split('\n'); + if (lines.Length < 8) + 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; + } + + return null; + } } } diff --git a/src/Commands/QueryStagedChangesWithAmend.cs b/src/Commands/QueryStagedChangesWithAmend.cs index 789804016..0c3e0df10 100644 --- a/src/Commands/QueryStagedChangesWithAmend.cs +++ b/src/Commands/QueryStagedChangesWithAmend.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -87,6 +88,74 @@ public QueryStagedChangesWithAmend(string repo, string parent) return changes; } + public async Task> ResultAsync() + { + var rs = await ReadToEndAsync(); + if (!rs.IsSuccess) + return []; + + var changes = new List(); + var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); + foreach (var line in lines) + { + var match = REG_FORMAT2().Match(line); + if (match.Success) + { + var change = new Models.Change() + { + Path = match.Groups[3].Value, + DataForAmend = new Models.ChangeDataForAmend() + { + FileMode = match.Groups[1].Value, + ObjectHash = match.Groups[2].Value, + ParentSHA = _parent, + }, + }; + change.Set(Models.ChangeState.Renamed); + changes.Add(change); + continue; + } + + match = REG_FORMAT1().Match(line); + if (match.Success) + { + var change = new Models.Change() + { + Path = match.Groups[4].Value, + DataForAmend = new Models.ChangeDataForAmend() + { + FileMode = match.Groups[1].Value, + ObjectHash = match.Groups[2].Value, + ParentSHA = _parent, + }, + }; + + var type = match.Groups[3].Value; + switch (type) + { + case "A": + change.Set(Models.ChangeState.Added); + break; + case "C": + change.Set(Models.ChangeState.Copied); + break; + case "D": + change.Set(Models.ChangeState.Deleted); + break; + case "M": + change.Set(Models.ChangeState.Modified); + break; + case "T": + change.Set(Models.ChangeState.TypeChanged); + break; + } + changes.Add(change); + } + } + + return changes; + } + private readonly string _parent; } } diff --git a/src/Commands/QueryStagedFileBlobGuid.cs b/src/Commands/QueryStagedFileBlobGuid.cs index 3f52a5f2d..20aad002c 100644 --- a/src/Commands/QueryStagedFileBlobGuid.cs +++ b/src/Commands/QueryStagedFileBlobGuid.cs @@ -1,4 +1,5 @@ using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -14,9 +15,9 @@ public QueryStagedFileBlobGuid(string repo, string file) Args = $"ls-files -s -- \"{file}\""; } - public string Result() + public async Task ResultAsync() { - var rs = ReadToEnd(); + var rs = await ReadToEndAsync(); var match = REG_FORMAT().Match(rs.StdOut.Trim()); if (match.Success) { diff --git a/src/Commands/QueryStashes.cs b/src/Commands/QueryStashes.cs index 2a84b34af..5b007bdae 100644 --- a/src/Commands/QueryStashes.cs +++ b/src/Commands/QueryStashes.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -64,5 +65,58 @@ public QueryStashes(string repo) } return outs; } + + public async Task> ResultAsync() + { + var outs = new List(); + var rs = await ReadToEndAsync(); + if (!rs.IsSuccess) + return outs; + + var items = rs.StdOut.Split('\0', StringSplitOptions.RemoveEmptyEntries); + foreach (var item in items) + { + var current = new Models.Stash(); + + var nextPartIdx = 0; + var start = 0; + var end = item.IndexOf('\n', start); + while (end > 0 && nextPartIdx < 4) + { + var line = item.Substring(start, end - start); + + switch (nextPartIdx) + { + case 0: + current.SHA = line; + break; + case 1: + if (line.Length > 6) + current.Parents.AddRange(line.Split(' ', StringSplitOptions.RemoveEmptyEntries)); + break; + case 2: + current.Time = ulong.Parse(line); + break; + case 3: + current.Name = line; + break; + } + + nextPartIdx++; + + start = end + 1; + if (start >= item.Length - 1) + break; + + end = item.IndexOf('\n', start); + } + + if (start < item.Length) + current.Message = item.Substring(start); + + outs.Add(current); + } + return outs; + } } } diff --git a/src/Commands/QuerySubmodules.cs b/src/Commands/QuerySubmodules.cs index 663c0ea0d..ecb072f7f 100644 --- a/src/Commands/QuerySubmodules.cs +++ b/src/Commands/QuerySubmodules.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -133,6 +134,118 @@ public QuerySubmodules(string repo) return submodules; } + public async Task> ResultAsync() + { + var submodules = new List(); + var rs = await ReadToEndAsync(); + + var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); + var map = new Dictionary(); + var needCheckLocalChanges = false; + foreach (var line in lines) + { + var match = REG_FORMAT_STATUS().Match(line); + if (match.Success) + { + var stat = match.Groups[1].Value; + var sha = match.Groups[2].Value; + var path = match.Groups[3].Value; + + var module = new Models.Submodule() { Path = path, SHA = sha }; + switch (stat[0]) + { + case '-': + module.Status = Models.SubmoduleStatus.NotInited; + break; + case '+': + module.Status = Models.SubmoduleStatus.RevisionChanged; + break; + case 'U': + module.Status = Models.SubmoduleStatus.Unmerged; + break; + default: + module.Status = Models.SubmoduleStatus.Normal; + needCheckLocalChanges = true; + break; + } + + map.Add(path, module); + submodules.Add(module); + } + } + + if (submodules.Count > 0) + { + Args = "config --file .gitmodules --list"; + rs = await ReadToEndAsync(); + if (rs.IsSuccess) + { + var modules = new Dictionary(); + lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); + foreach (var line in lines) + { + var match = REG_FORMAT_MODULE_INFO().Match(line); + if (match.Success) + { + var name = match.Groups[1].Value; + var key = match.Groups[2].Value; + var val = match.Groups[3].Value; + + if (!modules.TryGetValue(name, out var m)) + { + m = new ModuleInfo(); + modules.Add(name, m); + } + + if (key.Equals("path", StringComparison.Ordinal)) + m.Path = val; + else if (key.Equals("url", StringComparison.Ordinal)) + m.URL = val; + } + } + + foreach (var kv in modules) + { + if (map.TryGetValue(kv.Value.Path, out var m)) + m.URL = kv.Value.URL; + } + } + } + + if (needCheckLocalChanges) + { + var builder = new StringBuilder(); + foreach (var kv in map) + { + if (kv.Value.Status == Models.SubmoduleStatus.Normal) + { + builder.Append('"'); + builder.Append(kv.Key); + builder.Append("\" "); + } + } + + Args = $"--no-optional-locks status --porcelain -- {builder}"; + rs = await ReadToEndAsync(); + if (!rs.IsSuccess) + return submodules; + + lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); + foreach (var line in lines) + { + var match = REG_FORMAT_DIRTY().Match(line); + if (match.Success) + { + var path = match.Groups[1].Value; + if (map.TryGetValue(path, out var m)) + m.Status = Models.SubmoduleStatus.Modified; + } + } + } + + return submodules; + } + private class ModuleInfo { public string Path { get; set; } = string.Empty; diff --git a/src/Commands/QueryTags.cs b/src/Commands/QueryTags.cs index 896d555e2..32ccca48a 100644 --- a/src/Commands/QueryTags.cs +++ b/src/Commands/QueryTags.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -46,6 +47,38 @@ public QueryTags(string repo) return tags; } + public async Task> ResultAsync() + { + var tags = new List(); + var rs = await ReadToEndAsync(); + if (!rs.IsSuccess) + return tags; + + var records = rs.StdOut.Split(_boundary, StringSplitOptions.RemoveEmptyEntries); + foreach (var record in records) + { + var subs = record.Split('\0'); + if (subs.Length != 6) + continue; + + var name = subs[0].Substring(10); + var message = subs[5].Trim(); + if (!string.IsNullOrEmpty(message) && message.Equals(name, StringComparison.Ordinal)) + message = null; + + tags.Add(new Models.Tag() + { + Name = name, + IsAnnotated = subs[1].Equals("tag", StringComparison.Ordinal), + SHA = string.IsNullOrEmpty(subs[3]) ? subs[2] : subs[3], + CreatorDate = ulong.Parse(subs[4]), + Message = message, + }); + } + + return tags; + } + private string _boundary = string.Empty; } } diff --git a/src/Commands/QueryTrackStatus.cs b/src/Commands/QueryTrackStatus.cs index e7e1f1c95..c807451ee 100644 --- a/src/Commands/QueryTrackStatus.cs +++ b/src/Commands/QueryTrackStatus.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -30,5 +31,25 @@ public Models.BranchTrackStatus Result() return status; } + + public async Task ResultAsync() + { + var status = new Models.BranchTrackStatus(); + + var rs = await ReadToEndAsync(); + if (!rs.IsSuccess) + return status; + + var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); + foreach (var line in lines) + { + if (line[0] == '>') + status.Behind.Add(line.Substring(1)); + else + status.Ahead.Add(line.Substring(1)); + } + + return status; + } } } diff --git a/src/Commands/QueryUpdatableSubmodules.cs b/src/Commands/QueryUpdatableSubmodules.cs index 03f4a24d2..5d89ea2ef 100644 --- a/src/Commands/QueryUpdatableSubmodules.cs +++ b/src/Commands/QueryUpdatableSubmodules.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -16,10 +17,10 @@ public QueryUpdatableSubmodules(string repo) Args = "submodule status"; } - public List Result() + public async Task> ResultAsync() { var submodules = new List(); - var rs = ReadToEnd(); + var rs = await ReadToEndAsync(); var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) diff --git a/src/Commands/Remote.cs b/src/Commands/Remote.cs index beaf412b0..6a1503774 100644 --- a/src/Commands/Remote.cs +++ b/src/Commands/Remote.cs @@ -1,4 +1,6 @@ -namespace SourceGit.Commands +using System.Threading.Tasks; + +namespace SourceGit.Commands { public class Remote : Command { @@ -8,50 +10,50 @@ public Remote(string repo) Context = repo; } - public bool Add(string name, string url) + public async Task AddAsync(string name, string url) { Args = $"remote add {name} {url}"; - return Exec(); + return await ExecAsync(); } - public bool Delete(string name) + public async Task DeleteAsync(string name) { Args = $"remote remove {name}"; - return Exec(); + return await ExecAsync(); } - public bool Rename(string name, string to) + public async Task RenameAsync(string name, string to) { Args = $"remote rename {name} {to}"; - return Exec(); + return await ExecAsync(); } - public bool Prune(string name) + public async Task PruneAsync(string name) { Args = $"remote prune {name}"; - return Exec(); + return await ExecAsync(); } - public string GetURL(string name, bool isPush) + public async Task GetURLAsync(string name, bool isPush) { Args = "remote get-url" + (isPush ? " --push " : " ") + name; - var rs = ReadToEnd(); + var rs = await ReadToEndAsync(); return rs.IsSuccess ? rs.StdOut.Trim() : string.Empty; } - public bool SetURL(string name, string url, bool isPush) + public async Task SetURLAsync(string name, string url, bool isPush) { Args = "remote set-url" + (isPush ? " --push " : " ") + $"{name} {url}"; - return Exec(); + return await ExecAsync(); } - public bool HasBranch(string remote, string branch) + public async Task HasBranchAsync(string remote, string branch) { - SSHKey = new Config(WorkingDirectory).Get($"remote.{remote}.sshkey"); + SSHKey = await new Config(WorkingDirectory).GetAsync($"remote.{remote}.sshkey"); Args = $"ls-remote {remote} {branch}"; - var rs = ReadToEnd(); + var rs = await ReadToEndAsync(); return rs.IsSuccess && rs.StdOut.Trim().Length > 0; } } diff --git a/src/Commands/SaveChangesAsPatch.cs b/src/Commands/SaveChangesAsPatch.cs index 329cf823d..173456fdc 100644 --- a/src/Commands/SaveChangesAsPatch.cs +++ b/src/Commands/SaveChangesAsPatch.cs @@ -2,18 +2,19 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Threading.Tasks; namespace SourceGit.Commands { public static class SaveChangesAsPatch { - public static bool ProcessLocalChanges(string repo, List changes, bool isUnstaged, string saveTo) + public static async Task ProcessLocalChangesAsync(string repo, List changes, bool isUnstaged, string saveTo) { - using (var sw = File.Create(saveTo)) + await using (var sw = File.Create(saveTo)) { foreach (var change in changes) { - if (!ProcessSingleChange(repo, new Models.DiffOption(change, isUnstaged), sw)) + if (!await ProcessSingleChangeAsync(repo, new Models.DiffOption(change, isUnstaged), sw)) return false; } } @@ -21,13 +22,13 @@ public static bool ProcessLocalChanges(string repo, List changes, return true; } - public static bool ProcessRevisionCompareChanges(string repo, List changes, string baseRevision, string targetRevision, string saveTo) + public static async Task ProcessRevisionCompareChangesAsync(string repo, List changes, string baseRevision, string targetRevision, string saveTo) { - using (var sw = File.Create(saveTo)) + await using (var sw = File.Create(saveTo)) { foreach (var change in changes) { - if (!ProcessSingleChange(repo, new Models.DiffOption(baseRevision, targetRevision, change), sw)) + if (!await ProcessSingleChangeAsync(repo, new Models.DiffOption(baseRevision, targetRevision, change), sw)) return false; } } @@ -35,20 +36,20 @@ public static bool ProcessRevisionCompareChanges(string repo, List opts, string saveTo) + public static async Task ProcessStashChangesAsync(string repo, List opts, string saveTo) { - using (var sw = File.Create(saveTo)) + await using (var sw = File.Create(saveTo)) { foreach (var opt in opts) { - if (!ProcessSingleChange(repo, opt, sw)) + if (!await ProcessSingleChangeAsync(repo, opt, sw)) return false; } } return true; } - private static bool ProcessSingleChange(string repo, Models.DiffOption opt, FileStream writer) + private static async Task ProcessSingleChangeAsync(string repo, Models.DiffOption opt, FileStream writer) { var starter = new ProcessStartInfo(); starter.WorkingDirectory = repo; @@ -63,8 +64,8 @@ private static bool ProcessSingleChange(string repo, Models.DiffOption opt, File { var proc = new Process() { StartInfo = starter }; proc.Start(); - proc.StandardOutput.BaseStream.CopyTo(writer); - proc.WaitForExit(); + await proc.StandardOutput.BaseStream.CopyToAsync(writer); + await proc.WaitForExitAsync(); var rs = proc.ExitCode == 0; proc.Close(); diff --git a/src/Commands/SaveRevisionFile.cs b/src/Commands/SaveRevisionFile.cs index db0b99dcf..386eccbac 100644 --- a/src/Commands/SaveRevisionFile.cs +++ b/src/Commands/SaveRevisionFile.cs @@ -1,30 +1,31 @@ using System; using System.Diagnostics; using System.IO; +using System.Threading.Tasks; namespace SourceGit.Commands { public static class SaveRevisionFile { - public static void Run(string repo, string revision, string file, string saveTo) + public static async Task RunAsync(string repo, string revision, string file, string saveTo) { var dir = Path.GetDirectoryName(saveTo); if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); - var isLFSFiltered = new IsLFSFiltered(repo, revision, file).Result(); + var isLFSFiltered = await new IsLFSFiltered(repo, revision, file).ResultAsync(); if (isLFSFiltered) { - var pointerStream = QueryFileContent.Run(repo, revision, file); - ExecCmd(repo, "lfs smudge", saveTo, pointerStream); + var pointerStream = await QueryFileContent.RunAsync(repo, revision, file); + await ExecCmdAsync(repo, "lfs smudge", saveTo, pointerStream); } else { - ExecCmd(repo, $"show {revision}:\"{file}\"", saveTo); + await ExecCmdAsync(repo, $"show {revision}:\"{file}\"", saveTo); } } - private static void ExecCmd(string repo, string args, string outputFile, Stream input = null) + private static async Task ExecCmdAsync(string repo, string args, string outputFile, Stream input = null) { var starter = new ProcessStartInfo(); starter.WorkingDirectory = repo; @@ -37,16 +38,16 @@ private static void ExecCmd(string repo, string args, string outputFile, Stream starter.RedirectStandardOutput = true; starter.RedirectStandardError = true; - using (var sw = File.OpenWrite(outputFile)) + await using (var sw = File.OpenWrite(outputFile)) { try { var proc = new Process() { StartInfo = starter }; proc.Start(); if (input != null) - proc.StandardInput.Write(new StreamReader(input).ReadToEnd()); - proc.StandardOutput.BaseStream.CopyTo(sw); - proc.WaitForExit(); + await proc.StandardInput.WriteAsync(await new StreamReader(input).ReadToEndAsync()); + await proc.StandardOutput.BaseStream.CopyToAsync(sw); + await proc.WaitForExitAsync(); proc.Close(); } catch (Exception e) diff --git a/src/Commands/Stash.cs b/src/Commands/Stash.cs index 7d1a269bb..b2f86b95d 100644 --- a/src/Commands/Stash.cs +++ b/src/Commands/Stash.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Text; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -11,7 +12,7 @@ public Stash(string repo) Context = repo; } - public bool Push(string message, bool includeUntracked = true, bool keepIndex = false) + public async Task PushAsync(string message, bool includeUntracked = true, bool keepIndex = false) { var builder = new StringBuilder(); builder.Append("stash push "); @@ -24,10 +25,10 @@ public bool Push(string message, bool includeUntracked = true, bool keepIndex = builder.Append("\""); Args = builder.ToString(); - return Exec(); + return await ExecAsync(); } - public bool Push(string message, List changes, bool keepIndex) + public async Task PushAsync(string message, List changes, bool keepIndex) { var builder = new StringBuilder(); builder.Append("stash push --include-untracked "); @@ -41,10 +42,10 @@ public bool Push(string message, List changes, bool keepIndex) builder.Append($"\"{c.Path}\" "); Args = builder.ToString(); - return Exec(); + return await ExecAsync(); } - public bool Push(string message, string pathspecFromFile, bool keepIndex) + public async Task PushAsync(string message, string pathspecFromFile, bool keepIndex) { var builder = new StringBuilder(); builder.Append("stash push --include-untracked --pathspec-from-file=\""); @@ -57,10 +58,10 @@ public bool Push(string message, string pathspecFromFile, bool keepIndex) builder.Append("\""); Args = builder.ToString(); - return Exec(); + return await ExecAsync(); } - public bool PushOnlyStaged(string message, bool keepIndex) + public async Task PushOnlyStagedAsync(string message, bool keepIndex) { var builder = new StringBuilder(); builder.Append("stash push --staged "); @@ -70,32 +71,32 @@ public bool PushOnlyStaged(string message, bool keepIndex) builder.Append(message); builder.Append("\""); Args = builder.ToString(); - return Exec(); + return await ExecAsync(); } - public bool Apply(string name, bool restoreIndex) + public async Task ApplyAsync(string name, bool restoreIndex) { var opts = restoreIndex ? "--index" : string.Empty; Args = $"stash apply -q {opts} \"{name}\""; - return Exec(); + return await ExecAsync(); } - public bool Pop(string name) + public async Task PopAsync(string name) { Args = $"stash pop -q --index \"{name}\""; - return Exec(); + return await ExecAsync(); } - public bool Drop(string name) + public async Task DropAsync(string name) { Args = $"stash drop -q \"{name}\""; - return Exec(); + return await ExecAsync(); } - public bool Clear() + public async Task ClearAsync() { Args = "stash clear"; - return Exec(); + return await ExecAsync(); } } } diff --git a/src/Commands/Statistics.cs b/src/Commands/Statistics.cs index e11c17406..64ebda60f 100644 --- a/src/Commands/Statistics.cs +++ b/src/Commands/Statistics.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -11,10 +12,10 @@ public Statistics(string repo, int max) Args = $"log --date-order --branches --remotes -{max} --format=%ct$%aN±%aE"; } - public Models.Statistics Result() + public async Task ResultAsync() { var statistics = new Models.Statistics(); - var rs = ReadToEnd(); + var rs = await ReadToEndAsync(); if (!rs.IsSuccess) return statistics; diff --git a/src/Commands/Submodule.cs b/src/Commands/Submodule.cs index 025d035ae..29fd17e64 100644 --- a/src/Commands/Submodule.cs +++ b/src/Commands/Submodule.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Text; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -11,16 +12,16 @@ public Submodule(string repo) Context = repo; } - public bool Add(string url, string relativePath, bool recursive) + public async Task AddAsync(string url, string relativePath, bool recursive) { Args = $"-c protocol.file.allow=always submodule add \"{url}\" \"{relativePath}\""; - if (!Exec()) + if (!await ExecAsync()) return false; if (recursive) { Args = $"submodule update --init --recursive -- \"{relativePath}\""; - return Exec(); + return await ExecAsync(); } else { @@ -29,7 +30,7 @@ public bool Add(string url, string relativePath, bool recursive) } } - public bool Update(List modules, bool init, bool recursive, bool useRemote = false) + public async Task UpdateAsync(List modules, bool init, bool recursive, bool useRemote = false) { var builder = new StringBuilder(); builder.Append("submodule update"); @@ -48,19 +49,19 @@ public bool Update(List modules, bool init, bool recursive, bool useRemo } Args = builder.ToString(); - return Exec(); + return await ExecAsync(); } - public bool Deinit(string module, bool force) + public async Task DeinitAsync(string module, bool force) { Args = force ? $"submodule deinit -f -- \"{module}\"" : $"submodule deinit -- \"{module}\""; - return Exec(); + return await ExecAsync(); } - public bool Delete(string module) + public async Task DeleteAsync(string module) { Args = $"rm -rf \"{module}\""; - return Exec(); + return await ExecAsync(); } } } diff --git a/src/Commands/Tag.cs b/src/Commands/Tag.cs index 017afea0b..e7e9f5ee0 100644 --- a/src/Commands/Tag.cs +++ b/src/Commands/Tag.cs @@ -1,20 +1,21 @@ using System.IO; +using System.Threading.Tasks; namespace SourceGit.Commands { public static class Tag { - public static bool Add(string repo, string name, string basedOn, Models.ICommandLog log) + public static async Task AddAsync(string repo, string name, string basedOn, Models.ICommandLog log) { var cmd = new Command(); cmd.WorkingDirectory = repo; cmd.Context = repo; cmd.Args = $"tag --no-sign {name} {basedOn}"; cmd.Log = log; - return cmd.Exec(); + return await cmd.ExecAsync(); } - public static bool Add(string repo, string name, string basedOn, string message, bool sign, Models.ICommandLog log) + public static async Task AddAsync(string repo, string name, string basedOn, string message, bool sign, Models.ICommandLog log) { var param = sign ? "--sign -a" : "--no-sign -a"; var cmd = new Command(); @@ -26,26 +27,26 @@ public static bool Add(string repo, string name, string basedOn, string message, if (!string.IsNullOrEmpty(message)) { string tmp = Path.GetTempFileName(); - File.WriteAllText(tmp, message); + await File.WriteAllTextAsync(tmp, message); cmd.Args += $"-F \"{tmp}\""; - var succ = cmd.Exec(); + var succ = await cmd.ExecAsync(); File.Delete(tmp); return succ; } cmd.Args += $"-m {name}"; - return cmd.Exec(); + return await cmd.ExecAsync(); } - public static bool Delete(string repo, string name, Models.ICommandLog log) + public static async Task DeleteAsync(string repo, string name, Models.ICommandLog log) { var cmd = new Command(); cmd.WorkingDirectory = repo; cmd.Context = repo; cmd.Args = $"tag --delete {name}"; cmd.Log = log; - return cmd.Exec(); + return await cmd.ExecAsync(); } } } diff --git a/src/Commands/UnstageChangesForAmend.cs b/src/Commands/UnstageChangesForAmend.cs index 06a718521..6d2fe2b34 100644 --- a/src/Commands/UnstageChangesForAmend.cs +++ b/src/Commands/UnstageChangesForAmend.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Text; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -84,6 +85,43 @@ public bool Exec() } } + public async Task ExecAsync() + { + var starter = new ProcessStartInfo(); + starter.WorkingDirectory = _repo; + starter.FileName = Native.OS.GitExecutable; + starter.Arguments = "-c core.editor=true update-index --index-info"; + starter.UseShellExecute = false; + starter.CreateNoWindow = true; + starter.WindowStyle = ProcessWindowStyle.Hidden; + starter.RedirectStandardInput = true; + starter.RedirectStandardOutput = false; + starter.RedirectStandardError = true; + + try + { + var proc = new Process() { StartInfo = starter }; + proc.Start(); + await proc.StandardInput.WriteAsync(_patchBuilder.ToString()); + proc.StandardInput.Close(); + + var err = await proc.StandardError.ReadToEndAsync(); + await proc.WaitForExitAsync(); + var rs = proc.ExitCode == 0; + proc.Close(); + + if (!rs) + App.RaiseException(_repo, err); + + return rs; + } + catch (Exception e) + { + App.RaiseException(_repo, "Failed to unstage changes: " + e.Message); + return false; + } + } + private string _repo = ""; private StringBuilder _patchBuilder = new StringBuilder(); } diff --git a/src/Commands/Worktree.cs b/src/Commands/Worktree.cs index 1198a4430..700e441d7 100644 --- a/src/Commands/Worktree.cs +++ b/src/Commands/Worktree.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Threading.Tasks; namespace SourceGit.Commands { @@ -56,7 +57,7 @@ public Worktree(string repo) return worktrees; } - public bool Add(string fullpath, string name, bool createNew, string tracking) + public async Task AddAsync(string fullpath, string name, bool createNew, string tracking) { Args = "worktree add "; @@ -78,35 +79,35 @@ public bool Add(string fullpath, string name, bool createNew, string tracking) else if (!string.IsNullOrEmpty(name) && !createNew) Args += name; - return Exec(); + return await ExecAsync(); } - public bool Prune() + public async Task PruneAsync() { Args = "worktree prune -v"; - return Exec(); + return await ExecAsync(); } - public bool Lock(string fullpath) + public async Task LockAsync(string fullpath) { Args = $"worktree lock \"{fullpath}\""; - return Exec(); + return await ExecAsync(); } - public bool Unlock(string fullpath) + public async Task UnlockAsync(string fullpath) { Args = $"worktree unlock \"{fullpath}\""; - return Exec(); + return await ExecAsync(); } - public bool Remove(string fullpath, bool force) + public async Task RemoveAsync(string fullpath, bool force) { if (force) Args = $"worktree remove -f \"{fullpath}\""; else Args = $"worktree remove \"{fullpath}\""; - return Exec(); + return await ExecAsync(); } } } diff --git a/src/Models/OpenAI.cs b/src/Models/OpenAI.cs index ab2a92b3e..9ca3506ed 100644 --- a/src/Models/OpenAI.cs +++ b/src/Models/OpenAI.cs @@ -4,6 +4,7 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading; +using System.Threading.Tasks; using Azure.AI.OpenAI; using CommunityToolkit.Mvvm.ComponentModel; using OpenAI; @@ -173,7 +174,7 @@ Your only goal is to retrieve a single commit message. """; } - public void Chat(string prompt, string question, CancellationToken cancellation, Action onUpdate) + public async Task ChatAsync(string prompt, string question, CancellationToken cancellation, Action onUpdate) { var server = new Uri(_server); var key = new ApiKeyCredential(_apiKey); @@ -191,9 +192,9 @@ public void Chat(string prompt, string question, CancellationToken cancellation, if (_streaming) { - var updates = client.CompleteChatStreaming(messages, null, cancellation); + var updates = client.CompleteChatStreamingAsync(messages, null, cancellation); - foreach (var update in updates) + await foreach (var update in updates) { if (update.ContentUpdate.Count > 0) rsp.Append(update.ContentUpdate[0].Text); @@ -201,7 +202,7 @@ public void Chat(string prompt, string question, CancellationToken cancellation, } else { - var completion = client.CompleteChat(messages, null, cancellation); + var completion = await client.CompleteChatAsync(messages, null, cancellation); if (completion.Value.Content.Count > 0) rsp.Append(completion.Value.Content[0].Text); diff --git a/src/ViewModels/AIAssistant.cs b/src/ViewModels/AIAssistant.cs index 8756a30b0..87bc26a0e 100644 --- a/src/ViewModels/AIAssistant.cs +++ b/src/ViewModels/AIAssistant.cs @@ -58,14 +58,14 @@ private void Gen() IsGenerating = true; _cancel = new CancellationTokenSource(); - Task.Run(() => + Task.Run(async () => { - new Commands.GenerateCommitMessage(_service, _repo.FullPath, _changes, _cancel.Token, message => + await new Commands.GenerateCommitMessage(_service, _repo.FullPath, _changes, _cancel.Token, message => { Dispatcher.UIThread.Invoke(() => Text = message); - }).Exec(); + }).ExecAsync(); - Dispatcher.UIThread.Invoke(() => IsGenerating = false); + await Dispatcher.UIThread.InvokeAsync(() => IsGenerating = false); }, _cancel.Token); } diff --git a/src/ViewModels/AddRemote.cs b/src/ViewModels/AddRemote.cs index 37bbc43a3..7520c3f17 100644 --- a/src/ViewModels/AddRemote.cs +++ b/src/ViewModels/AddRemote.cs @@ -87,7 +87,7 @@ public static ValidationResult ValidateSSHKey(string sshkey, ValidationContext c return ValidationResult.Success; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Adding remote ..."; @@ -95,24 +95,21 @@ public override Task Sure() var log = _repo.CreateLog("Add Remote"); Use(log); - return Task.Run(() => + var succ = await new Commands.Remote(_repo.FullPath).Use(log).AddAsync(_name, _url); + if (succ) { - var succ = new Commands.Remote(_repo.FullPath).Use(log).Add(_name, _url); - if (succ) - { - new Commands.Config(_repo.FullPath).Use(log).Set($"remote.{_name}.sshkey", _useSSH ? SSHKey : null); - new Commands.Fetch(_repo.FullPath, _name, false, false).Use(log).Exec(); - } - - log.Complete(); - CallUIThread(() => - { - _repo.MarkFetched(); - _repo.MarkBranchesDirtyManually(); - _repo.SetWatcherEnabled(true); - }); - return succ; + await new Commands.Config(_repo.FullPath).Use(log).SetAsync($"remote.{_name}.sshkey", _useSSH ? SSHKey : null); + await new Commands.Fetch(_repo.FullPath, _name, false, false).Use(log).ExecAsync(); + } + + log.Complete(); + await CallUIThreadAsync(() => + { + _repo.MarkFetched(); + _repo.MarkBranchesDirtyManually(); + _repo.SetWatcherEnabled(true); }); + return succ; } private readonly Repository _repo = null; diff --git a/src/ViewModels/AddSubmodule.cs b/src/ViewModels/AddSubmodule.cs index 82a1f62ac..304f60160 100644 --- a/src/ViewModels/AddSubmodule.cs +++ b/src/ViewModels/AddSubmodule.cs @@ -40,7 +40,7 @@ public static ValidationResult ValidateURL(string url, ValidationContext ctx) return ValidationResult.Success; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Adding submodule..."; @@ -59,14 +59,11 @@ public override Task Sure() relativePath = Path.GetFileName(_url); } - return Task.Run(() => - { - var succ = new Commands.Submodule(_repo.FullPath).Use(log).Add(_url, relativePath, Recursive); - log.Complete(); + var succ = await new Commands.Submodule(_repo.FullPath).Use(log).AddAsync(_url, relativePath, Recursive); + log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private readonly Repository _repo = null; diff --git a/src/ViewModels/AddToIgnore.cs b/src/ViewModels/AddToIgnore.cs index 74f7e3eca..11989ae1d 100644 --- a/src/ViewModels/AddToIgnore.cs +++ b/src/ViewModels/AddToIgnore.cs @@ -27,35 +27,32 @@ public AddToIgnore(Repository repo, string pattern) StorageFile = Models.GitIgnoreFile.Supported[0]; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Adding Ignored File(s) ..."; - return Task.Run(() => + var file = StorageFile.GetFullPath(_repo.FullPath, _repo.GitDir); + if (!File.Exists(file)) { - var file = StorageFile.GetFullPath(_repo.FullPath, _repo.GitDir); - if (!File.Exists(file)) - { - File.WriteAllLines(file, [_pattern]); - } + await File.WriteAllLinesAsync(file, [_pattern]); + } + else + { + var org = await File.ReadAllTextAsync(file); + if (!org.EndsWith('\n')) + await File.AppendAllLinesAsync(file, ["", _pattern]); else - { - var org = File.ReadAllText(file); - if (!org.EndsWith('\n')) - File.AppendAllLines(file, ["", _pattern]); - else - File.AppendAllLines(file, [_pattern]); - } - - CallUIThread(() => - { - _repo.MarkWorkingCopyDirtyManually(); - _repo.SetWatcherEnabled(true); - }); + await File.AppendAllLinesAsync(file, [_pattern]); + } - return true; + await CallUIThreadAsync(() => + { + _repo.MarkWorkingCopyDirtyManually(); + _repo.SetWatcherEnabled(true); }); + + return true; } private readonly Repository _repo; diff --git a/src/ViewModels/AddWorktree.cs b/src/ViewModels/AddWorktree.cs index a089a3912..b77147cf2 100644 --- a/src/ViewModels/AddWorktree.cs +++ b/src/ViewModels/AddWorktree.cs @@ -105,7 +105,7 @@ public static ValidationResult ValidateWorktreePath(string path, ValidationConte return ValidationResult.Success; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Adding worktree ..."; @@ -116,14 +116,11 @@ public override Task Sure() Use(log); - return Task.Run(() => - { - var succ = new Commands.Worktree(_repo.FullPath).Use(log).Add(_path, branchName, _createNewBranch, tracking); - log.Complete(); + var succ = await new Commands.Worktree(_repo.FullPath).Use(log).AddAsync(_path, branchName, _createNewBranch, tracking); + log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private Repository _repo = null; diff --git a/src/ViewModels/Apply.cs b/src/ViewModels/Apply.cs index c7f3c1853..d6d73e87d 100644 --- a/src/ViewModels/Apply.cs +++ b/src/ViewModels/Apply.cs @@ -41,20 +41,17 @@ public static ValidationResult ValidatePatchFile(string file, ValidationContext return new ValidationResult($"File '{file}' can NOT be found!!!"); } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Apply patch..."; var log = _repo.CreateLog("Apply Patch"); - return Task.Run(() => - { - var succ = new Commands.Apply(_repo.FullPath, _patchFile, _ignoreWhiteSpace, SelectedWhiteSpaceMode.Arg, null).Use(log).Exec(); - log.Complete(); + var succ = await new Commands.Apply(_repo.FullPath, _patchFile, _ignoreWhiteSpace, SelectedWhiteSpaceMode.Arg, null).Use(log).ExecAsync(); + log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private readonly Repository _repo = null; diff --git a/src/ViewModels/ApplyStash.cs b/src/ViewModels/ApplyStash.cs index e7cd64e91..4343a8bc0 100644 --- a/src/ViewModels/ApplyStash.cs +++ b/src/ViewModels/ApplyStash.cs @@ -28,20 +28,17 @@ public ApplyStash(Repository repo, Models.Stash stash) Stash = stash; } - public override Task Sure() + public override async Task Sure() { ProgressDescription = $"Applying stash: {Stash.Name}"; var log = _repo.CreateLog("Apply Stash"); - return Task.Run(() => - { - var succ = new Commands.Stash(_repo.FullPath).Use(log).Apply(Stash.Name, RestoreIndex); - if (succ && DropAfterApply) - new Commands.Stash(_repo.FullPath).Use(log).Drop(Stash.Name); - - log.Complete(); - return true; - }); + var succ = await new Commands.Stash(_repo.FullPath).Use(log).ApplyAsync(Stash.Name, RestoreIndex); + if (succ && DropAfterApply) + await new Commands.Stash(_repo.FullPath).Use(log).DropAsync(Stash.Name); + + log.Complete(); + return true; } private readonly Repository _repo; diff --git a/src/ViewModels/Archive.cs b/src/ViewModels/Archive.cs index a4a4f6eb8..30cded3e1 100644 --- a/src/ViewModels/Archive.cs +++ b/src/ViewModels/Archive.cs @@ -44,7 +44,7 @@ public Archive(Repository repo, Models.Tag tag) BasedOn = tag; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Archiving ..."; @@ -52,20 +52,17 @@ public override Task Sure() var log = _repo.CreateLog("Archive"); Use(log); - return Task.Run(() => - { - var succ = new Commands.Archive(_repo.FullPath, _revision, _saveFile).Use(log).Exec(); - log.Complete(); - - CallUIThread(() => - { - _repo.SetWatcherEnabled(true); - if (succ) - App.SendNotification(_repo.FullPath, $"Save archive to : {_saveFile}"); - }); + var succ = await new Commands.Archive(_repo.FullPath, _revision, _saveFile).Use(log).ExecAsync(); + log.Complete(); - return succ; + await CallUIThreadAsync(() => + { + _repo.SetWatcherEnabled(true); + if (succ) + App.SendNotification(_repo.FullPath, $"Save archive to : {_saveFile}"); }); + + return succ; } private readonly Repository _repo = null; diff --git a/src/ViewModels/AssumeUnchangedManager.cs b/src/ViewModels/AssumeUnchangedManager.cs index 681514483..d5e523c9c 100644 --- a/src/ViewModels/AssumeUnchangedManager.cs +++ b/src/ViewModels/AssumeUnchangedManager.cs @@ -14,19 +14,19 @@ public AssumeUnchangedManager(Repository repo) _repo = repo; Files = new AvaloniaList(); - Task.Run(() => + Task.Run(async () => { - var collect = new Commands.QueryAssumeUnchangedFiles(_repo.FullPath).Result(); - Dispatcher.UIThread.Invoke(() => Files.AddRange(collect)); + var collect = await new Commands.QueryAssumeUnchangedFiles(_repo.FullPath).ResultAsync(); + await Dispatcher.UIThread.InvokeAsync(() => Files.AddRange(collect)); }); } - public void Remove(string file) + public async Task RemoveAsync(string file) { if (!string.IsNullOrEmpty(file)) { var log = _repo.CreateLog("Remove Assume Unchanged File"); - new Commands.AssumeUnchanged(_repo.FullPath, file, false).Use(log).Exec(); + await new Commands.AssumeUnchanged(_repo.FullPath, file, false).Use(log).ExecAsync(); log.Complete(); Files.Remove(file); } diff --git a/src/ViewModels/Blame.cs b/src/ViewModels/Blame.cs index a189215a1..3f6f8354d 100644 --- a/src/ViewModels/Blame.cs +++ b/src/ViewModels/Blame.cs @@ -132,11 +132,11 @@ private void SetBlameData(string commitSHA) } else { - Task.Run(() => + Task.Run(async () => { - var result = new Commands.QuerySingleCommit(_repo, commitSHA).Result(); + var result = await new Commands.QuerySingleCommit(_repo, commitSHA).ResultAsync(); - Dispatcher.UIThread.Invoke(() => + await Dispatcher.UIThread.InvokeAsync(() => { if (!token.IsCancellationRequested) { @@ -147,11 +147,11 @@ private void SetBlameData(string commitSHA) }, token); } - Task.Run(() => + Task.Run(async () => { - var result = new Commands.Blame(_repo, FilePath, commitSHA).Result(); + var result = await new Commands.Blame(_repo, FilePath, commitSHA).ResultAsync(); - Dispatcher.UIThread.Invoke(() => + await Dispatcher.UIThread.InvokeAsync(() => { if (!token.IsCancellationRequested) Data = result; diff --git a/src/ViewModels/BranchCompare.cs b/src/ViewModels/BranchCompare.cs index 64ceea1c7..a78df0351 100644 --- a/src/ViewModels/BranchCompare.cs +++ b/src/ViewModels/BranchCompare.cs @@ -133,7 +133,7 @@ public ContextMenu CreateChangeContextMenu() var toolPath = Preferences.Instance.ExternalMergeToolPath; var opt = new Models.DiffOption(_based.Head, _to.Head, change); - Task.Run(() => Commands.MergeTool.OpenForDiff(_repo, toolType, toolPath, opt)); + Task.Run(() => Commands.MergeTool.OpenForDiffAsync(_repo, toolType, toolPath, opt)); ev.Handled = true; }; menu.Items.Add(diffWithMerger); @@ -178,20 +178,20 @@ public ContextMenu CreateChangeContextMenu() private void Refresh() { - Task.Run(() => + Task.Run(async () => { if (_baseHead == null) { - var baseHead = new Commands.QuerySingleCommit(_repo, _based.Head).Result(); - var toHead = new Commands.QuerySingleCommit(_repo, _to.Head).Result(); - Dispatcher.UIThread.Invoke(() => + var baseHead = await new Commands.QuerySingleCommit(_repo, _based.Head).ResultAsync(); + var toHead = await new Commands.QuerySingleCommit(_repo, _to.Head).ResultAsync(); + await Dispatcher.UIThread.InvokeAsync(() => { BaseHead = baseHead; ToHead = toHead; }); } - _changes = new Commands.CompareRevisions(_repo, _based.Head, _to.Head).Result(); + _changes = await new Commands.CompareRevisions(_repo, _based.Head, _to.Head).ResultAsync(); var visible = _changes; if (!string.IsNullOrWhiteSpace(_searchFilter)) @@ -204,7 +204,7 @@ private void Refresh() } } - Dispatcher.UIThread.Invoke(() => VisibleChanges = visible); + await Dispatcher.UIThread.InvokeAsync(() => VisibleChanges = visible); }); } diff --git a/src/ViewModels/Checkout.cs b/src/ViewModels/Checkout.cs index 45dcd9a4a..83b9592fa 100644 --- a/src/ViewModels/Checkout.cs +++ b/src/ViewModels/Checkout.cs @@ -33,7 +33,7 @@ public Checkout(Repository repo, string branch) DiscardLocalChanges = false; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = $"Checkout '{Branch}' ..."; @@ -42,70 +42,67 @@ public override Task Sure() Use(log); var updateSubmodules = IsRecurseSubmoduleVisible && RecurseSubmodules; - return Task.Run(() => - { - bool succ; - var needPopStash = false; + bool succ; + var needPopStash = false; - if (!_repo.ConfirmCheckoutBranch()) - { - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return true; - } + if (!_repo.ConfirmCheckoutBranch()) + { + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return true; + } - if (DiscardLocalChanges) - { - succ = new Commands.Checkout(_repo.FullPath).Use(log).Branch(Branch, true); - } - else + if (DiscardLocalChanges) + { + succ = await new Commands.Checkout(_repo.FullPath).Use(log).BranchAsync(Branch, true); + } + else + { + var changes = await new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).ResultAsync(); + if (changes > 0) { - var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result(); - if (changes > 0) + succ = await new Commands.Stash(_repo.FullPath).Use(log).PushAsync("CHECKOUT_AUTO_STASH"); + if (!succ) { - succ = new Commands.Stash(_repo.FullPath).Use(log).Push("CHECKOUT_AUTO_STASH"); - if (!succ) - { - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return false; - } - - needPopStash = true; + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return false; } - succ = new Commands.Checkout(_repo.FullPath).Use(log).Branch(Branch, false); + needPopStash = true; } - if (succ) - { - if (updateSubmodules) - { - var submodules = new Commands.QueryUpdatableSubmodules(_repo.FullPath).Result(); - if (submodules.Count > 0) - new Commands.Submodule(_repo.FullPath).Use(log).Update(submodules, true, true); - } + succ = await new Commands.Checkout(_repo.FullPath).Use(log).BranchAsync(Branch, false); + } - if (needPopStash) - new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}"); + if (succ) + { + if (updateSubmodules) + { + var submodules = await new Commands.QueryUpdatableSubmodules(_repo.FullPath).ResultAsync(); + if (submodules.Count > 0) + await new Commands.Submodule(_repo.FullPath).Use(log).UpdateAsync(submodules, true, true); } - log.Complete(); + if (needPopStash) + await new Commands.Stash(_repo.FullPath).Use(log).PopAsync("stash@{0}"); + } - CallUIThread(() => - { - ProgressDescription = "Waiting for branch updated..."; + log.Complete(); - var b = _repo.Branches.Find(x => x.IsLocal && x.Name == Branch); - if (b != null && _repo.HistoriesFilterMode == Models.FilterMode.Included) - _repo.SetBranchFilterMode(b, Models.FilterMode.Included, true, false); + await CallUIThreadAsync(() => + { + ProgressDescription = "Waiting for branch updated..."; - _repo.MarkBranchesDirtyManually(); - _repo.SetWatcherEnabled(true); - }); + var b = _repo.Branches.Find(x => x.IsLocal && x.Name == Branch); + if (b != null && _repo.HistoriesFilterMode == Models.FilterMode.Included) + _repo.SetBranchFilterMode(b, Models.FilterMode.Included, true, false); - Task.Delay(400).Wait(); - return succ; + _repo.MarkBranchesDirtyManually(); + _repo.SetWatcherEnabled(true); }); + + Task.Delay(400).Wait(); + return succ; } private readonly Repository _repo = null; diff --git a/src/ViewModels/CheckoutAndFastForward.cs b/src/ViewModels/CheckoutAndFastForward.cs index 9ae931fee..559acc34e 100644 --- a/src/ViewModels/CheckoutAndFastForward.cs +++ b/src/ViewModels/CheckoutAndFastForward.cs @@ -38,7 +38,7 @@ public CheckoutAndFastForward(Repository repo, Models.Branch localBranch, Models RemoteBranch = remoteBranch; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = $"Checkout and Fast-Forward '{LocalBranch.Name}' ..."; @@ -47,69 +47,66 @@ public override Task Sure() Use(log); var updateSubmodules = IsRecurseSubmoduleVisible && RecurseSubmodules; - return Task.Run(() => - { - var succ = false; - var needPopStash = false; + var succ = false; + var needPopStash = false; - if (!_repo.ConfirmCheckoutBranch()) - { - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return true; - } + if (!_repo.ConfirmCheckoutBranch()) + { + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return true; + } - if (DiscardLocalChanges) - { - succ = new Commands.Checkout(_repo.FullPath).Use(log).Branch(LocalBranch.Name, RemoteBranch.Head, true, true); - } - else + if (DiscardLocalChanges) + { + succ = await new Commands.Checkout(_repo.FullPath).Use(log).BranchAsync(LocalBranch.Name, RemoteBranch.Head, true, true); + } + else + { + var changes = await new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).ResultAsync(); + if (changes > 0) { - var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result(); - if (changes > 0) + succ = await new Commands.Stash(_repo.FullPath).Use(log).PushAsync("CHECKOUT_AND_FASTFORWARD_AUTO_STASH"); + if (!succ) { - succ = new Commands.Stash(_repo.FullPath).Use(log).Push("CHECKOUT_AND_FASTFORWARD_AUTO_STASH"); - if (!succ) - { - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return false; - } - - needPopStash = true; + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return false; } - succ = new Commands.Checkout(_repo.FullPath).Use(log).Branch(LocalBranch.Name, RemoteBranch.Head, false, true); + needPopStash = true; } - if (succ) - { - if (updateSubmodules) - { - var submodules = new Commands.QueryUpdatableSubmodules(_repo.FullPath).Result(); - if (submodules.Count > 0) - new Commands.Submodule(_repo.FullPath).Use(log).Update(submodules, true, true); - } + succ = await new Commands.Checkout(_repo.FullPath).Use(log).BranchAsync(LocalBranch.Name, RemoteBranch.Head, false, true); + } - if (needPopStash) - new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}"); + if (succ) + { + if (updateSubmodules) + { + var submodules = await new Commands.QueryUpdatableSubmodules(_repo.FullPath).ResultAsync(); + if (submodules.Count > 0) + await new Commands.Submodule(_repo.FullPath).Use(log).UpdateAsync(submodules, true, true); } - log.Complete(); + if (needPopStash) + await new Commands.Stash(_repo.FullPath).Use(log).PopAsync("stash@{0}"); + } - CallUIThread(() => - { - ProgressDescription = "Waiting for branch updated..."; + log.Complete(); - if (_repo.HistoriesFilterMode == Models.FilterMode.Included) - _repo.SetBranchFilterMode(LocalBranch, Models.FilterMode.Included, true, false); + await CallUIThreadAsync(() => + { + ProgressDescription = "Waiting for branch updated..."; - _repo.MarkBranchesDirtyManually(); - _repo.SetWatcherEnabled(true); - }); + if (_repo.HistoriesFilterMode == Models.FilterMode.Included) + _repo.SetBranchFilterMode(LocalBranch, Models.FilterMode.Included, true, false); - Task.Delay(400).Wait(); - return succ; + _repo.MarkBranchesDirtyManually(); + _repo.SetWatcherEnabled(true); }); + + Task.Delay(400).Wait(); + return succ; } private Repository _repo; diff --git a/src/ViewModels/CheckoutCommit.cs b/src/ViewModels/CheckoutCommit.cs index f477538d8..b95829ff0 100644 --- a/src/ViewModels/CheckoutCommit.cs +++ b/src/ViewModels/CheckoutCommit.cs @@ -33,7 +33,7 @@ public CheckoutCommit(Repository repo, Models.Commit commit) DiscardLocalChanges = false; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = $"Checkout Commit '{Commit.SHA}' ..."; @@ -42,57 +42,54 @@ public override Task Sure() Use(log); var updateSubmodules = IsRecurseSubmoduleVisible && RecurseSubmodules; - return Task.Run(() => - { - bool succ; - var needPop = false; + bool succ; + var needPop = false; - if (!_repo.ConfirmCheckoutBranch()) - { - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return true; - } + if (!_repo.ConfirmCheckoutBranch()) + { + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return true; + } - if (DiscardLocalChanges) - { - succ = new Commands.Checkout(_repo.FullPath).Use(log).Commit(Commit.SHA, true); - } - else + if (DiscardLocalChanges) + { + succ = await new Commands.Checkout(_repo.FullPath).Use(log).CommitAsync(Commit.SHA, true); + } + else + { + var changes = await new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).ResultAsync(); + if (changes > 0) { - var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result(); - if (changes > 0) + succ = await new Commands.Stash(_repo.FullPath).Use(log).PushAsync("CHECKOUT_AUTO_STASH"); + if (!succ) { - succ = new Commands.Stash(_repo.FullPath).Use(log).Push("CHECKOUT_AUTO_STASH"); - if (!succ) - { - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return false; - } - - needPop = true; + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return false; } - succ = new Commands.Checkout(_repo.FullPath).Use(log).Commit(Commit.SHA, false); + needPop = true; } - if (succ) - { - if (updateSubmodules) - { - var submodules = new Commands.QueryUpdatableSubmodules(_repo.FullPath).Result(); - if (submodules.Count > 0) - new Commands.Submodule(_repo.FullPath).Use(log).Update(submodules, true, true); - } + succ = await new Commands.Checkout(_repo.FullPath).Use(log).CommitAsync(Commit.SHA, false); + } - if (needPop) - new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}"); + if (succ) + { + if (updateSubmodules) + { + var submodules = await new Commands.QueryUpdatableSubmodules(_repo.FullPath).ResultAsync(); + if (submodules.Count > 0) + await new Commands.Submodule(_repo.FullPath).Use(log).UpdateAsync(submodules, true, true); } - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + if (needPop) + await new Commands.Stash(_repo.FullPath).Use(log).PopAsync("stash@{0}"); + } + + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private readonly Repository _repo = null; diff --git a/src/ViewModels/CherryPick.cs b/src/ViewModels/CherryPick.cs index 2d929f3a9..66961b203 100644 --- a/src/ViewModels/CherryPick.cs +++ b/src/ViewModels/CherryPick.cs @@ -63,7 +63,7 @@ public CherryPick(Repository repo, Models.Commit merge, List pare AutoCommit = true; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); _repo.ClearCommitMessage(); @@ -72,31 +72,28 @@ public override Task Sure() var log = _repo.CreateLog("Cherry-Pick"); Use(log); - return Task.Run(() => + if (IsMergeCommit) { - if (IsMergeCommit) - { - new Commands.CherryPick( - _repo.FullPath, - Targets[0].SHA, - !AutoCommit, - AppendSourceToMessage, - $"-m {MainlineForMergeCommit + 1}").Use(log).Exec(); - } - else - { - new Commands.CherryPick( - _repo.FullPath, - string.Join(' ', Targets.ConvertAll(c => c.SHA)), - !AutoCommit, - AppendSourceToMessage, - string.Empty).Use(log).Exec(); - } + await new Commands.CherryPick( + _repo.FullPath, + Targets[0].SHA, + !AutoCommit, + AppendSourceToMessage, + $"-m {MainlineForMergeCommit + 1}").Use(log).ExecAsync(); + } + else + { + await new Commands.CherryPick( + _repo.FullPath, + string.Join(' ', Targets.ConvertAll(c => c.SHA)), + !AutoCommit, + AppendSourceToMessage, + string.Empty).Use(log).ExecAsync(); + } - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return true; - }); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return true; } private readonly Repository _repo = null; diff --git a/src/ViewModels/Cleanup.cs b/src/ViewModels/Cleanup.cs index 1fc39cb5e..458405e0a 100644 --- a/src/ViewModels/Cleanup.cs +++ b/src/ViewModels/Cleanup.cs @@ -9,7 +9,7 @@ public Cleanup(Repository repo) _repo = repo; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Cleanup (GC & prune) ..."; @@ -17,13 +17,10 @@ public override Task Sure() var log = _repo.CreateLog("Cleanup (GC & prune)"); Use(log); - return Task.Run(() => - { - new Commands.GC(_repo.FullPath).Use(log).Exec(); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return true; - }); + await new Commands.GC(_repo.FullPath).Use(log).ExecAsync(); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return true; } private readonly Repository _repo = null; diff --git a/src/ViewModels/ClearStashes.cs b/src/ViewModels/ClearStashes.cs index d71bab312..02c23f281 100644 --- a/src/ViewModels/ClearStashes.cs +++ b/src/ViewModels/ClearStashes.cs @@ -9,7 +9,7 @@ public ClearStashes(Repository repo) _repo = repo; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Clear all stashes..."; @@ -17,13 +17,10 @@ public override Task Sure() var log = _repo.CreateLog("Clear Stashes"); Use(log); - return Task.Run(() => - { - new Commands.Stash(_repo.FullPath).Use(log).Clear(); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return true; - }); + await new Commands.Stash(_repo.FullPath).Use(log).ClearAsync(); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return true; } private readonly Repository _repo = null; diff --git a/src/ViewModels/Clone.cs b/src/ViewModels/Clone.cs index bc742b37f..76545c19a 100644 --- a/src/ViewModels/Clone.cs +++ b/src/ViewModels/Clone.cs @@ -74,7 +74,7 @@ public Clone(string pageId) { var text = await App.GetClipboardTextAsync(); if (Models.Remote.IsValidURL(text)) - Dispatcher.UIThread.Invoke(() => Remote = text); + await Dispatcher.UIThread.InvokeAsync(() => Remote = text); } catch { @@ -97,76 +97,73 @@ public static ValidationResult ValidateParentFolder(string folder, ValidationCon return ValidationResult.Success; } - public override Task Sure() + public override async Task Sure() { ProgressDescription = "Clone ..."; var log = new CommandLog("Clone"); Use(log); - return Task.Run(() => - { - var cmd = new Commands.Clone(_pageId, _parentFolder, _remote, _local, _useSSH ? _sshKey : "", _extraArgs).Use(log); - if (!cmd.Exec()) - return false; + var cmd = new Commands.Clone(_pageId, _parentFolder, _remote, _local, _useSSH ? _sshKey : "", _extraArgs).Use(log); + if (!await cmd.ExecAsync()) + return false; - var path = _parentFolder; - if (!string.IsNullOrEmpty(_local)) - { - path = Path.GetFullPath(Path.Combine(path, _local)); - } - else - { - var name = Path.GetFileName(_remote)!; - if (name.EndsWith(".git", StringComparison.Ordinal)) - name = name.Substring(0, name.Length - 4); - else if (name.EndsWith(".bundle", StringComparison.Ordinal)) - name = name.Substring(0, name.Length - 7); + var path = _parentFolder; + if (!string.IsNullOrEmpty(_local)) + { + path = Path.GetFullPath(Path.Combine(path, _local)); + } + else + { + var name = Path.GetFileName(_remote)!; + if (name.EndsWith(".git", StringComparison.Ordinal)) + name = name.Substring(0, name.Length - 4); + else if (name.EndsWith(".bundle", StringComparison.Ordinal)) + name = name.Substring(0, name.Length - 7); - path = Path.GetFullPath(Path.Combine(path, name)); - } + path = Path.GetFullPath(Path.Combine(path, name)); + } - if (!Directory.Exists(path)) - { - App.RaiseException(_pageId, $"Folder '{path}' can NOT be found"); - return false; - } + if (!Directory.Exists(path)) + { + App.RaiseException(_pageId, $"Folder '{path}' can NOT be found"); + return false; + } - if (_useSSH && !string.IsNullOrEmpty(_sshKey)) - { - var config = new Commands.Config(path); - config.Set("remote.origin.sshkey", _sshKey); - } + if (_useSSH && !string.IsNullOrEmpty(_sshKey)) + { + var config = new Commands.Config(path); + await config.SetAsync("remote.origin.sshkey", _sshKey); + } - if (InitAndUpdateSubmodules) - { - var submodules = new Commands.QueryUpdatableSubmodules(path).Result(); - if (submodules.Count > 0) - new Commands.Submodule(path).Use(log).Update(submodules, true, true); - } + if (InitAndUpdateSubmodules) + { + var submodules = await new Commands.QueryUpdatableSubmodules(path).ResultAsync(); + if (submodules.Count > 0) + await new Commands.Submodule(path).Use(log).UpdateAsync(submodules, true, true); + } - log.Complete(); + log.Complete(); - CallUIThread(() => + await CallUIThreadAsync(() => + { + var node = Preferences.Instance.FindOrAddNodeByRepositoryPath(path, null, true); + var launcher = App.GetLauncher(); + var page = null as LauncherPage; + foreach (var one in launcher.Pages) { - var node = Preferences.Instance.FindOrAddNodeByRepositoryPath(path, null, true); - var launcher = App.GetLauncher(); - var page = null as LauncherPage; - foreach (var one in launcher.Pages) + if (one.Node.Id == _pageId) { - if (one.Node.Id == _pageId) - { - page = one; - break; - } + page = one; + break; } + } - Welcome.Instance.Refresh(); - launcher.OpenRepositoryInTab(node, page); - }); - - return true; + Welcome.Instance.Refresh(); + launcher.OpenRepositoryInTab(node, page); }); + + return true; } private string _pageId = string.Empty; diff --git a/src/ViewModels/CommitDetail.cs b/src/ViewModels/CommitDetail.cs index df687cfd0..d6ffdf794 100644 --- a/src/ViewModels/CommitDetail.cs +++ b/src/ViewModels/CommitDetail.cs @@ -215,9 +215,9 @@ public void ViewRevisionFile(Models.Object file) { case Models.ObjectType.Blob: CanOpenRevisionFileWithDefaultEditor = true; - Task.Run(() => + Task.Run(async () => { - var isBinary = new Commands.IsBinary(_repo.FullPath, _commit.SHA, file.Path).Result(); + var isBinary = await new Commands.IsBinary(_repo.FullPath, _commit.SHA, file.Path).ResultAsync(); if (isBinary) { var imgDecoder = ImageSource.GetDecoder(file.Path); @@ -225,20 +225,20 @@ public void ViewRevisionFile(Models.Object file) { var source = ImageSource.FromRevision(_repo.FullPath, _commit.SHA, file.Path, imgDecoder); var image = new Models.RevisionImageFile(file.Path, source.Bitmap, source.Size); - Dispatcher.UIThread.Invoke(() => ViewRevisionFileContent = image); + await Dispatcher.UIThread.InvokeAsync(() => ViewRevisionFileContent = image); } else { - var size = new Commands.QueryFileSize(_repo.FullPath, file.Path, _commit.SHA).Result(); + var size = await new Commands.QueryFileSize(_repo.FullPath, file.Path, _commit.SHA).ResultAsync(); var binary = new Models.RevisionBinaryFile() { Size = size }; - Dispatcher.UIThread.Invoke(() => ViewRevisionFileContent = binary); + await Dispatcher.UIThread.InvokeAsync(() => ViewRevisionFileContent = binary); } return; } - var contentStream = Commands.QueryFileContent.Run(_repo.FullPath, _commit.SHA, file.Path); - var content = new StreamReader(contentStream).ReadToEnd(); + var contentStream = await Commands.QueryFileContent.RunAsync(_repo.FullPath, _commit.SHA, file.Path); + var content = await new StreamReader(contentStream).ReadToEndAsync(); var lfs = Models.LFSObject.Parse(content); if (lfs != null) { @@ -246,35 +246,35 @@ public void ViewRevisionFile(Models.Object file) if (imgDecoder != Models.ImageDecoder.None) { var combined = new RevisionLFSImage(_repo.FullPath, file.Path, lfs, imgDecoder); - Dispatcher.UIThread.Invoke(() => ViewRevisionFileContent = combined); + await Dispatcher.UIThread.InvokeAsync(() => ViewRevisionFileContent = combined); } else { var rlfs = new Models.RevisionLFSObject() { Object = lfs }; - Dispatcher.UIThread.Invoke(() => ViewRevisionFileContent = rlfs); + await Dispatcher.UIThread.InvokeAsync(() => ViewRevisionFileContent = rlfs); } } else { var txt = new Models.RevisionTextFile() { FileName = file.Path, Content = content }; - Dispatcher.UIThread.Invoke(() => ViewRevisionFileContent = txt); + await Dispatcher.UIThread.InvokeAsync(() => ViewRevisionFileContent = txt); } }); break; case Models.ObjectType.Commit: CanOpenRevisionFileWithDefaultEditor = false; - Task.Run(() => + Task.Run(async () => { var submoduleRoot = Path.Combine(_repo.FullPath, file.Path).Replace('\\', '/').Trim('/'); - var commit = new Commands.QuerySingleCommit(submoduleRoot, file.SHA).Result(); - var message = commit != null ? new Commands.QueryCommitFullMessage(submoduleRoot, file.SHA).Result() : null; + var commit = await new Commands.QuerySingleCommit(submoduleRoot, file.SHA).ResultAsync(); + var message = commit != null ? await new Commands.QueryCommitFullMessage(submoduleRoot, file.SHA).ResultAsync() : null; var module = new Models.RevisionSubmodule() { Commit = commit ?? new Models.Commit() { SHA = _commit.SHA }, FullMessage = new Models.CommitFullMessage { Message = message } }; - Dispatcher.UIThread.Invoke(() => ViewRevisionFileContent = module); + await Dispatcher.UIThread.InvokeAsync(() => ViewRevisionFileContent = module); }); break; default: @@ -284,18 +284,17 @@ public void ViewRevisionFile(Models.Object file) } } - public Task OpenRevisionFileWithDefaultEditor(string file) + public async Task OpenRevisionFileWithDefaultEditor(string file) { - return Task.Run(() => { var fullPath = Native.OS.GetAbsPath(_repo.FullPath, file); var fileName = Path.GetFileNameWithoutExtension(fullPath) ?? ""; var fileExt = Path.GetExtension(fullPath) ?? ""; var tmpFile = Path.Combine(Path.GetTempPath(), $"{fileName}~{_commit.SHA.Substring(0, 10)}{fileExt}"); - Commands.SaveRevisionFile.Run(_repo.FullPath, _commit.SHA, file, tmpFile); + await Commands.SaveRevisionFile.RunAsync(_repo.FullPath, _commit.SHA, file, tmpFile); Native.OS.OpenWithDefaultEditor(tmpFile); - }); + } } public ContextMenu CreateChangeContextMenuByFolder(ChangeTreeNode node, List changes) @@ -339,7 +338,7 @@ public ContextMenu CreateChangeContextMenuByFolder(ChangeTreeNode node, List Commands.SaveChangesAsPatch.ProcessRevisionCompareChanges(_repo.FullPath, changes, baseRevision, _commit.SHA, saveTo)); + var succ = await Commands.SaveChangesAsPatch.ProcessRevisionCompareChangesAsync(_repo.FullPath, changes, baseRevision, _commit.SHA, saveTo); if (succ) App.SendNotification(_repo.FullPath, App.Text("SaveAsPatchSuccess")); } @@ -388,7 +387,7 @@ public ContextMenu CreateChangeContextMenu(Models.Change change) var toolPath = Preferences.Instance.ExternalMergeToolPath; var opt = new Models.DiffOption(_commit, change); - Task.Run(() => Commands.MergeTool.OpenForDiff(_repo.FullPath, toolType, toolPath, opt)); + Task.Run(() => Commands.MergeTool.OpenForDiffAsync(_repo.FullPath, toolType, toolPath, opt)); ev.Handled = true; }; @@ -441,7 +440,7 @@ public ContextMenu CreateChangeContextMenu(Models.Change change) if (storageFile != null) { var saveTo = storageFile.Path.LocalPath; - var succ = await Task.Run(() => Commands.SaveChangesAsPatch.ProcessRevisionCompareChanges(_repo.FullPath, [change], baseRevision, _commit.SHA, saveTo)); + var succ = await Commands.SaveChangesAsPatch.ProcessRevisionCompareChangesAsync(_repo.FullPath, [change], baseRevision, _commit.SHA, saveTo); if (succ) App.SendNotification(_repo.FullPath, App.Text("SaveAsPatchSuccess")); } @@ -605,7 +604,7 @@ public ContextMenu CreateRevisionFileContextMenu(Models.Object file) var folder = selected[0]; var folderPath = folder is { Path: { IsAbsoluteUri: true } path } ? path.LocalPath : folder.Path.ToString(); var saveTo = Path.Combine(folderPath, Path.GetFileName(file.Path)!); - await Task.Run(() => Commands.SaveRevisionFile.Run(_repo.FullPath, _commit.SHA, file.Path, saveTo)); + await Commands.SaveRevisionFile.RunAsync(_repo.FullPath, _commit.SHA, file.Path, saveTo); } } catch (Exception e) @@ -719,39 +718,39 @@ private void Refresh() _cancellationSource = new CancellationTokenSource(); var token = _cancellationSource.Token; - Task.Run(() => + Task.Run(async () => { - var message = new Commands.QueryCommitFullMessage(_repo.FullPath, _commit.SHA).Result(); - var inlines = ParseInlinesInMessage(message); + var message = await new Commands.QueryCommitFullMessage(_repo.FullPath, _commit.SHA).ResultAsync(); + var inlines = await ParseInlinesInMessageAsync(message); if (!token.IsCancellationRequested) - Dispatcher.UIThread.Invoke(() => FullMessage = new Models.CommitFullMessage { Message = message, Inlines = inlines }); + await Dispatcher.UIThread.InvokeAsync(() => FullMessage = new Models.CommitFullMessage { Message = message, Inlines = inlines }); }, token); - Task.Run(() => + Task.Run(async () => { - var signInfo = new Commands.QueryCommitSignInfo(_repo.FullPath, _commit.SHA, !_repo.HasAllowedSignersFile).Result(); + var signInfo = await new Commands.QueryCommitSignInfo(_repo.FullPath, _commit.SHA, !_repo.HasAllowedSignersFile).ResultAsync(); if (!token.IsCancellationRequested) - Dispatcher.UIThread.Invoke(() => SignInfo = signInfo); + await Dispatcher.UIThread.InvokeAsync(() => SignInfo = signInfo); }, token); if (Preferences.Instance.ShowChildren) { - Task.Run(() => + Task.Run(async () => { var max = Preferences.Instance.MaxHistoryCommits; var cmd = new Commands.QueryCommitChildren(_repo.FullPath, _commit.SHA, max) { CancellationToken = token }; - var children = cmd.Result(); + var children = await cmd.ResultAsync(); if (!token.IsCancellationRequested) Dispatcher.UIThread.Post(() => Children = children); }, token); } - Task.Run(() => + Task.Run(async () => { var parent = _commit.Parents.Count == 0 ? Models.Commit.EmptyTreeSHA1 : _commit.Parents[0]; var cmd = new Commands.CompareRevisions(_repo.FullPath, parent, _commit.SHA) { CancellationToken = token }; - var changes = cmd.Result(); + var changes = await cmd.ResultAsync(); var visible = changes; if (!string.IsNullOrWhiteSpace(_searchChangeFilter)) { @@ -777,7 +776,7 @@ private void Refresh() }, token); } - private Models.InlineElementCollector ParseInlinesInMessage(string message) + private async Task ParseInlinesInMessageAsync(string message) { var inlines = new Models.InlineElementCollector(); if (_repo.Settings.IssueTrackerRules is { Count: > 0 } rules) @@ -816,7 +815,7 @@ private Models.InlineElementCollector ParseInlinesInMessage(string message) continue; var sha = match.Groups[1].Value; - var isCommitSHA = new Commands.IsCommitSHA(_repo.FullPath, sha).Result(); + var isCommitSHA = await new Commands.IsCommitSHA(_repo.FullPath, sha).ResultAsync(); if (isCommitSHA) inlines.Add(new Models.InlineElement(Models.InlineElementType.CommitSHA, start, len, sha)); } @@ -868,7 +867,7 @@ private void TryToAddContextMenuItemsForGitLFS(ContextMenu menu, string fullPath lfsLock.Click += async (_, e) => { var log = _repo.CreateLog("Lock LFS file"); - var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Lock(_repo.Remotes[0].Name, path, log)); + var succ = await new Commands.LFS(_repo.FullPath).LockAsync(_repo.Remotes[0].Name, path, log); if (succ) App.SendNotification(_repo.FullPath, $"Lock file \"{path}\" successfully!"); @@ -886,7 +885,7 @@ private void TryToAddContextMenuItemsForGitLFS(ContextMenu menu, string fullPath lockRemote.Click += async (_, e) => { var log = _repo.CreateLog("Lock LFS file"); - var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Lock(remoteName, path, log)); + var succ = await new Commands.LFS(_repo.FullPath).LockAsync(remoteName, path, log); if (succ) App.SendNotification(_repo.FullPath, $"Lock file \"{path}\" successfully!"); @@ -906,7 +905,7 @@ private void TryToAddContextMenuItemsForGitLFS(ContextMenu menu, string fullPath lfsUnlock.Click += async (_, e) => { var log = _repo.CreateLog("Unlock LFS file"); - var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Unlock(_repo.Remotes[0].Name, path, false, log)); + var succ = await new Commands.LFS(_repo.FullPath).UnlockAsync(_repo.Remotes[0].Name, path, false, log); if (succ) App.SendNotification(_repo.FullPath, $"Unlock file \"{path}\" successfully!"); @@ -924,7 +923,7 @@ private void TryToAddContextMenuItemsForGitLFS(ContextMenu menu, string fullPath unlockRemote.Click += async (_, e) => { var log = _repo.CreateLog("Unlock LFS file"); - var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Unlock(remoteName, path, false, log)); + var succ = await new Commands.LFS(_repo.FullPath).UnlockAsync(remoteName, path, false, log); if (succ) App.SendNotification(_repo.FullPath, $"Unlock file \"{path}\" successfully!"); @@ -952,10 +951,10 @@ private void RefreshRevisionSearchSuggestion() var sha = Commit.SHA; _requestingRevisionFiles = true; - Task.Run(() => + Task.Run(async () => { - var files = new Commands.QueryRevisionFileNames(_repo.FullPath, sha).Result(); - Dispatcher.UIThread.Invoke(() => + var files = await new Commands.QueryRevisionFileNames(_repo.FullPath, sha).ResultAsync(); + await Dispatcher.UIThread.InvokeAsync(() => { if (sha == Commit.SHA && _requestingRevisionFiles) { @@ -996,29 +995,23 @@ private void CalcRevisionFileSearchSuggestion() RevisionFileSearchSuggestion = suggestion; } - private Task ResetToThisRevision(string path) + private async Task ResetToThisRevision(string path) { var log = _repo.CreateLog($"Reset File to '{_commit.SHA}'"); - return Task.Run(() => - { - new Commands.Checkout(_repo.FullPath).Use(log).FileWithRevision(path, $"{_commit.SHA}"); - log.Complete(); - }); + await new Commands.Checkout(_repo.FullPath).Use(log).FileWithRevisionAsync(path, $"{_commit.SHA}"); + log.Complete(); } - private Task ResetToParentRevision(Models.Change change) + private async Task ResetToParentRevision(Models.Change change) { var log = _repo.CreateLog($"Reset File to '{_commit.SHA}~1'"); - return Task.Run(() => - { - if (change.Index == Models.ChangeState.Renamed) - new Commands.Checkout(_repo.FullPath).Use(log).FileWithRevision(change.OriginalPath, $"{_commit.SHA}~1"); + if (change.Index == Models.ChangeState.Renamed) + await new Commands.Checkout(_repo.FullPath).Use(log).FileWithRevisionAsync(change.OriginalPath, $"{_commit.SHA}~1"); - new Commands.Checkout(_repo.FullPath).Use(log).FileWithRevision(change.Path, $"{_commit.SHA}~1"); - log.Complete(); - }); + await new Commands.Checkout(_repo.FullPath).Use(log).FileWithRevisionAsync(change.Path, $"{_commit.SHA}~1"); + log.Complete(); } [GeneratedRegex(@"\b(https?://|ftp://)[\w\d\._/\-~%@()+:?&=#!]*[\w\d/]")] diff --git a/src/ViewModels/CreateBranch.cs b/src/ViewModels/CreateBranch.cs index 6e01eb398..e999f5e04 100644 --- a/src/ViewModels/CreateBranch.cs +++ b/src/ViewModels/CreateBranch.cs @@ -118,7 +118,7 @@ public static ValidationResult ValidateBranchName(string name, ValidationContext } } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); @@ -127,89 +127,86 @@ public override Task Sure() Use(log); var updateSubmodules = IsRecurseSubmoduleVisible && RecurseSubmodules; - return Task.Run(() => + bool succ; + + if (CheckoutAfterCreated && !_repo.ConfirmCheckoutBranch()) { - bool succ; + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return true; + } - if (CheckoutAfterCreated && !_repo.ConfirmCheckoutBranch()) + if (CheckoutAfterCreated && !_repo.IsBare) + { + var needPopStash = false; + if (DiscardLocalChanges) { - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return true; + succ = await new Commands.Checkout(_repo.FullPath).Use(log).BranchAsync(fixedName, _baseOnRevision, true, _allowOverwrite); } - - if (CheckoutAfterCreated && !_repo.IsBare) + else { - var needPopStash = false; - if (DiscardLocalChanges) - { - succ = new Commands.Checkout(_repo.FullPath).Use(log).Branch(fixedName, _baseOnRevision, true, _allowOverwrite); - } - else + var changes = await new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).ResultAsync(); + if (changes > 0) { - var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result(); - if (changes > 0) + succ = await new Commands.Stash(_repo.FullPath).Use(log).PushAsync("CREATE_BRANCH_AUTO_STASH"); + if (!succ) { - succ = new Commands.Stash(_repo.FullPath).Use(log).Push("CREATE_BRANCH_AUTO_STASH"); - if (!succ) - { - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return false; - } - - needPopStash = true; + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return false; } - succ = new Commands.Checkout(_repo.FullPath).Use(log).Branch(fixedName, _baseOnRevision, false, _allowOverwrite); + needPopStash = true; } - if (succ) - { - if (updateSubmodules) - { - var submodules = new Commands.QueryUpdatableSubmodules(_repo.FullPath).Result(); - if (submodules.Count > 0) - new Commands.Submodule(_repo.FullPath).Use(log).Update(submodules, true, true); - } - - if (needPopStash) - new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}"); - } + succ = await new Commands.Checkout(_repo.FullPath).Use(log).BranchAsync(fixedName, _baseOnRevision, false, _allowOverwrite); } - else + + if (succ) { - succ = Commands.Branch.Create(_repo.FullPath, fixedName, _baseOnRevision, _allowOverwrite, log); + if (updateSubmodules) + { + var submodules = await new Commands.QueryUpdatableSubmodules(_repo.FullPath).ResultAsync(); + if (submodules.Count > 0) + await new Commands.Submodule(_repo.FullPath).Use(log).UpdateAsync(submodules, true, true); + } + + if (needPopStash) + await new Commands.Stash(_repo.FullPath).Use(log).PopAsync("stash@{0}"); } + } + else + { + succ = await Commands.Branch.CreateAsync(_repo.FullPath, fixedName, _baseOnRevision, _allowOverwrite, log); + } - log.Complete(); + log.Complete(); - CallUIThread(() => + await CallUIThreadAsync(() => + { + if (succ && CheckoutAfterCreated) { - if (succ && CheckoutAfterCreated) - { - var fake = new Models.Branch() { IsLocal = true, FullName = $"refs/heads/{fixedName}" }; - if (BasedOn is Models.Branch based && !based.IsLocal) - fake.Upstream = based.FullName; + var fake = new Models.Branch() { IsLocal = true, FullName = $"refs/heads/{fixedName}" }; + if (BasedOn is Models.Branch based && !based.IsLocal) + fake.Upstream = based.FullName; - var folderEndIdx = fake.FullName.LastIndexOf('/'); - if (folderEndIdx > 10) - _repo.Settings.ExpandedBranchNodesInSideBar.Add(fake.FullName.Substring(0, folderEndIdx)); + var folderEndIdx = fake.FullName.LastIndexOf('/'); + if (folderEndIdx > 10) + _repo.Settings.ExpandedBranchNodesInSideBar.Add(fake.FullName.Substring(0, folderEndIdx)); - if (_repo.HistoriesFilterMode == Models.FilterMode.Included) - _repo.SetBranchFilterMode(fake, Models.FilterMode.Included, true, false); + if (_repo.HistoriesFilterMode == Models.FilterMode.Included) + _repo.SetBranchFilterMode(fake, Models.FilterMode.Included, true, false); - ProgressDescription = "Waiting for branch updated..."; - } + ProgressDescription = "Waiting for branch updated..."; + } - _repo.MarkBranchesDirtyManually(); - _repo.SetWatcherEnabled(true); - }); + _repo.MarkBranchesDirtyManually(); + _repo.SetWatcherEnabled(true); + }); - if (CheckoutAfterCreated) - Task.Delay(400).Wait(); + if (CheckoutAfterCreated) + Task.Delay(400).Wait(); - return true; - }); + return true; } private string FixName(string name) diff --git a/src/ViewModels/CreateTag.cs b/src/ViewModels/CreateTag.cs index d3cd512bc..b6683a8fa 100644 --- a/src/ViewModels/CreateTag.cs +++ b/src/ViewModels/CreateTag.cs @@ -74,7 +74,7 @@ public static ValidationResult ValidateTagName(string name, ValidationContext ct return ValidationResult.Success; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Create tag..."; @@ -83,24 +83,21 @@ public override Task Sure() var log = _repo.CreateLog("Create Tag"); Use(log); - return Task.Run(() => + bool succ; + if (_annotated) + succ = await Commands.Tag.AddAsync(_repo.FullPath, _tagName, _basedOn, Message, SignTag, log); + else + succ = await Commands.Tag.AddAsync(_repo.FullPath, _tagName, _basedOn, log); + + if (succ && remotes != null) { - bool succ; - if (_annotated) - succ = Commands.Tag.Add(_repo.FullPath, _tagName, _basedOn, Message, SignTag, log); - else - succ = Commands.Tag.Add(_repo.FullPath, _tagName, _basedOn, log); - - if (succ && remotes != null) - { - foreach (var remote in remotes) - new Commands.Push(_repo.FullPath, remote.Name, $"refs/tags/{_tagName}", false).Use(log).Exec(); - } - - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + foreach (var remote in remotes) + await new Commands.Push(_repo.FullPath, remote.Name, $"refs/tags/{_tagName}", false).Use(log).ExecAsync(); + } + + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private readonly Repository _repo = null; diff --git a/src/ViewModels/DeinitSubmodule.cs b/src/ViewModels/DeinitSubmodule.cs index a96a65d01..0fa26acbc 100644 --- a/src/ViewModels/DeinitSubmodule.cs +++ b/src/ViewModels/DeinitSubmodule.cs @@ -23,7 +23,7 @@ public DeinitSubmodule(Repository repo, string submodule) Force = false; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "De-initialize Submodule"; @@ -31,13 +31,10 @@ public override Task Sure() var log = _repo.CreateLog("De-initialize Submodule"); Use(log); - return Task.Run(() => - { - var succ = new Commands.Submodule(_repo.FullPath).Use(log).Deinit(Submodule, false); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + var succ = await new Commands.Submodule(_repo.FullPath).Use(log).DeinitAsync(Submodule, false); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private Repository _repo; diff --git a/src/ViewModels/DeleteBranch.cs b/src/ViewModels/DeleteBranch.cs index 4decdb40c..48109eab8 100644 --- a/src/ViewModels/DeleteBranch.cs +++ b/src/ViewModels/DeleteBranch.cs @@ -39,7 +39,7 @@ public DeleteBranch(Repository repo, Models.Branch branch) } } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Deleting branch..."; @@ -47,29 +47,26 @@ public override Task Sure() var log = _repo.CreateLog("Delete Branch"); Use(log); - return Task.Run(() => + if (Target.IsLocal) { - if (Target.IsLocal) - { - Commands.Branch.DeleteLocal(_repo.FullPath, Target.Name, log); + await Commands.Branch.DeleteLocalAsync(_repo.FullPath, Target.Name, log); - if (_alsoDeleteTrackingRemote && TrackingRemoteBranch != null) - Commands.Branch.DeleteRemote(_repo.FullPath, TrackingRemoteBranch.Remote, TrackingRemoteBranch.Name, log); - } - else - { - Commands.Branch.DeleteRemote(_repo.FullPath, Target.Remote, Target.Name, log); - } + if (_alsoDeleteTrackingRemote && TrackingRemoteBranch != null) + await Commands.Branch.DeleteRemoteAsync(_repo.FullPath, TrackingRemoteBranch.Remote, TrackingRemoteBranch.Name, log); + } + else + { + await Commands.Branch.DeleteRemoteAsync(_repo.FullPath, Target.Remote, Target.Name, log); + } - log.Complete(); + log.Complete(); - CallUIThread(() => - { - _repo.MarkBranchesDirtyManually(); - _repo.SetWatcherEnabled(true); - }); - return true; + await CallUIThreadAsync(() => + { + _repo.MarkBranchesDirtyManually(); + _repo.SetWatcherEnabled(true); }); + return true; } private readonly Repository _repo = null; diff --git a/src/ViewModels/DeleteMultipleBranches.cs b/src/ViewModels/DeleteMultipleBranches.cs index b40ff223b..57ac06dc7 100644 --- a/src/ViewModels/DeleteMultipleBranches.cs +++ b/src/ViewModels/DeleteMultipleBranches.cs @@ -17,7 +17,7 @@ public DeleteMultipleBranches(Repository repo, List branches, boo Targets = branches; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Deleting multiple branches..."; @@ -25,29 +25,26 @@ public override Task Sure() var log = _repo.CreateLog("Delete Multiple Branches"); Use(log); - return Task.Run(() => + if (_isLocal) { - if (_isLocal) - { - foreach (var target in Targets) - Commands.Branch.DeleteLocal(_repo.FullPath, target.Name, log); - } - else - { - foreach (var target in Targets) - Commands.Branch.DeleteRemote(_repo.FullPath, target.Remote, target.Name, log); - } - - log.Complete(); - - CallUIThread(() => - { - _repo.MarkBranchesDirtyManually(); - _repo.SetWatcherEnabled(true); - }); - - return true; + foreach (var target in Targets) + await Commands.Branch.DeleteLocalAsync(_repo.FullPath, target.Name, log); + } + else + { + foreach (var target in Targets) + await Commands.Branch.DeleteRemoteAsync(_repo.FullPath, target.Remote, target.Name, log); + } + + log.Complete(); + + await CallUIThreadAsync(() => + { + _repo.MarkBranchesDirtyManually(); + _repo.SetWatcherEnabled(true); }); + + return true; } private Repository _repo = null; diff --git a/src/ViewModels/DeleteRemote.cs b/src/ViewModels/DeleteRemote.cs index faf7c8a98..90d7e2056 100644 --- a/src/ViewModels/DeleteRemote.cs +++ b/src/ViewModels/DeleteRemote.cs @@ -16,7 +16,7 @@ public DeleteRemote(Repository repo, Models.Remote remote) Remote = remote; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Deleting remote ..."; @@ -24,18 +24,15 @@ public override Task Sure() var log = _repo.CreateLog("Delete Remote"); Use(log); - return Task.Run(() => - { - var succ = new Commands.Remote(_repo.FullPath).Use(log).Delete(Remote.Name); - log.Complete(); + var succ = await new Commands.Remote(_repo.FullPath).Use(log).DeleteAsync(Remote.Name); + log.Complete(); - CallUIThread(() => - { - _repo.MarkBranchesDirtyManually(); - _repo.SetWatcherEnabled(true); - }); - return succ; + await CallUIThreadAsync(() => + { + _repo.MarkBranchesDirtyManually(); + _repo.SetWatcherEnabled(true); }); + return succ; } private readonly Repository _repo = null; diff --git a/src/ViewModels/DeleteSubmodule.cs b/src/ViewModels/DeleteSubmodule.cs index 239c7d315..930009de9 100644 --- a/src/ViewModels/DeleteSubmodule.cs +++ b/src/ViewModels/DeleteSubmodule.cs @@ -16,7 +16,7 @@ public DeleteSubmodule(Repository repo, string submodule) Submodule = submodule; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Deleting submodule ..."; @@ -24,13 +24,10 @@ public override Task Sure() var log = _repo.CreateLog("Delete Submodule"); Use(log); - return Task.Run(() => - { - var succ = new Commands.Submodule(_repo.FullPath).Use(log).Delete(Submodule); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + var succ = await new Commands.Submodule(_repo.FullPath).Use(log).DeleteAsync(Submodule); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private readonly Repository _repo = null; diff --git a/src/ViewModels/DeleteTag.cs b/src/ViewModels/DeleteTag.cs index f7de63416..bcc37ee79 100644 --- a/src/ViewModels/DeleteTag.cs +++ b/src/ViewModels/DeleteTag.cs @@ -22,7 +22,7 @@ public DeleteTag(Repository repo, Models.Tag tag) Target = tag; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = $"Deleting tag '{Target.Name}' ..."; @@ -31,24 +31,21 @@ public override Task Sure() var log = _repo.CreateLog("Delete Tag"); Use(log); - return Task.Run(() => + var succ = await Commands.Tag.DeleteAsync(_repo.FullPath, Target.Name, log); + if (succ) { - var succ = Commands.Tag.Delete(_repo.FullPath, Target.Name, log); - if (succ) - { - foreach (var r in remotes) - new Commands.Push(_repo.FullPath, r.Name, $"refs/tags/{Target.Name}", true).Use(log).Exec(); - } - - log.Complete(); - - CallUIThread(() => - { - _repo.MarkTagsDirtyManually(); - _repo.SetWatcherEnabled(true); - }); - return succ; + foreach (var r in remotes) + await new Commands.Push(_repo.FullPath, r.Name, $"refs/tags/{Target.Name}", true).Use(log).ExecAsync(); + } + + log.Complete(); + + await CallUIThreadAsync(() => + { + _repo.MarkTagsDirtyManually(); + _repo.SetWatcherEnabled(true); }); + return succ; } private readonly Repository _repo = null; diff --git a/src/ViewModels/DiffContext.cs b/src/ViewModels/DiffContext.cs index 9bb3c7107..7246085dc 100644 --- a/src/ViewModels/DiffContext.cs +++ b/src/ViewModels/DiffContext.cs @@ -97,7 +97,7 @@ public void OpenExternalMergeTool() { var toolType = Preferences.Instance.ExternalMergeToolType; var toolPath = Preferences.Instance.ExternalMergeToolPath; - Task.Run(() => Commands.MergeTool.OpenForDiff(_repo, toolType, toolPath, _option)); + Task.Run(() => Commands.MergeTool.OpenForDiffAsync(_repo, toolType, toolPath, _option)); } private void LoadDiffContent() @@ -109,11 +109,11 @@ private void LoadDiffContent() return; } - Task.Run(() => + Task.Run(async () => { var numLines = Preferences.Instance.UseFullTextDiff ? 999999999 : _unifiedLines; var ignoreWhitespace = Preferences.Instance.IgnoreWhitespaceChangesInDiff; - var latest = new Commands.Diff(_repo, _option, numLines, ignoreWhitespace).Result(); + var latest = await new Commands.Diff(_repo, _option, numLines, ignoreWhitespace).ResultAsync(); var info = new Info(_option, numLines, ignoreWhitespace, latest); if (_info != null && info.IsSame(_info)) return; @@ -199,13 +199,13 @@ private void LoadDiffContent() var binaryDiff = new Models.BinaryDiff(); if (_option.Revisions.Count == 2) { - binaryDiff.OldSize = new Commands.QueryFileSize(_repo, oldPath, _option.Revisions[0]).Result(); - binaryDiff.NewSize = new Commands.QueryFileSize(_repo, _option.Path, _option.Revisions[1]).Result(); + binaryDiff.OldSize = await new Commands.QueryFileSize(_repo, oldPath, _option.Revisions[0]).ResultAsync(); + binaryDiff.NewSize = await new Commands.QueryFileSize(_repo, _option.Path, _option.Revisions[1]).ResultAsync(); } else { var fullPath = Path.Combine(_repo, _option.Path); - binaryDiff.OldSize = new Commands.QueryFileSize(_repo, oldPath, "HEAD").Result(); + binaryDiff.OldSize = await new Commands.QueryFileSize(_repo, oldPath, "HEAD").ResultAsync(); binaryDiff.NewSize = File.Exists(fullPath) ? new FileInfo(fullPath).Length : 0; } rs = binaryDiff; diff --git a/src/ViewModels/DirHistories.cs b/src/ViewModels/DirHistories.cs index 3b3853afb..0fbecb25c 100644 --- a/src/ViewModels/DirHistories.cs +++ b/src/ViewModels/DirHistories.cs @@ -51,10 +51,10 @@ public DirHistories(Repository repo, string dir, string revision = null) _detail = new CommitDetail(repo, false); _detail.SearchChangeFilter = dir; - Task.Run(() => + Task.Run(async () => { - var commits = new Commands.QueryCommits(_repo.FullPath, $"--date-order -n 10000 {revision ?? string.Empty} -- \"{dir}\"", false).Result(); - Dispatcher.UIThread.Invoke(() => + var commits = await new Commands.QueryCommits(_repo.FullPath, $"--date-order -n 10000 {revision ?? string.Empty} -- \"{dir}\"", false).ResultAsync(); + await Dispatcher.UIThread.InvokeAsync(() => { Commits = commits; IsLoading = false; diff --git a/src/ViewModels/Discard.cs b/src/ViewModels/Discard.cs index 7619635c1..6433ca9d0 100644 --- a/src/ViewModels/Discard.cs +++ b/src/ViewModels/Discard.cs @@ -56,7 +56,7 @@ public Discard(Repository repo, List changes) Mode = new DiscardMultipleFiles() { Count = _changes.Count }; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = _changes == null ? "Discard all local changes ..." : $"Discard total {_changes.Count} changes ..."; @@ -64,23 +64,20 @@ public override Task Sure() var log = _repo.CreateLog("Discard all"); Use(log); - return Task.Run(() => - { - if (Mode is DiscardAllMode all) - Commands.Discard.All(_repo.FullPath, all.IncludeIgnored, log); - else - Commands.Discard.Changes(_repo.FullPath, _changes, log); - - log.Complete(); + if (Mode is DiscardAllMode all) + await Commands.Discard.AllAsync(_repo.FullPath, all.IncludeIgnored, log); + else + await Commands.Discard.ChangesAsync(_repo.FullPath, _changes, log); - CallUIThread(() => - { - _repo.MarkWorkingCopyDirtyManually(); - _repo.SetWatcherEnabled(true); - }); + log.Complete(); - return true; + await CallUIThreadAsync(() => + { + _repo.MarkWorkingCopyDirtyManually(); + _repo.SetWatcherEnabled(true); }); + + return true; } private readonly Repository _repo = null; diff --git a/src/ViewModels/DropStash.cs b/src/ViewModels/DropStash.cs index 545da0106..1c2ca6ea6 100644 --- a/src/ViewModels/DropStash.cs +++ b/src/ViewModels/DropStash.cs @@ -12,19 +12,16 @@ public DropStash(Repository repo, Models.Stash stash) Stash = stash; } - public override Task Sure() + public override async Task Sure() { ProgressDescription = $"Dropping stash: {Stash.Name}"; var log = _repo.CreateLog("Drop Stash"); Use(log); - return Task.Run(() => - { - new Commands.Stash(_repo.FullPath).Use(log).Drop(Stash.Name); - log.Complete(); - return true; - }); + await new Commands.Stash(_repo.FullPath).Use(log).DropAsync(Stash.Name); + log.Complete(); + return true; } private readonly Repository _repo; diff --git a/src/ViewModels/EditRemote.cs b/src/ViewModels/EditRemote.cs index 763c8ce1e..09833205d 100644 --- a/src/ViewModels/EditRemote.cs +++ b/src/ViewModels/EditRemote.cs @@ -100,36 +100,33 @@ public static ValidationResult ValidateSSHKey(string sshkey, ValidationContext c return ValidationResult.Success; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = $"Editing remote '{_remote.Name}' ..."; - return Task.Run(() => + if (_remote.Name != _name) { - if (_remote.Name != _name) - { - var succ = new Commands.Remote(_repo.FullPath).Rename(_remote.Name, _name); - if (succ) - _remote.Name = _name; - } + var succ = await new Commands.Remote(_repo.FullPath).RenameAsync(_remote.Name, _name); + if (succ) + _remote.Name = _name; + } - if (_remote.URL != _url) - { - var succ = new Commands.Remote(_repo.FullPath).SetURL(_name, _url, false); - if (succ) - _remote.URL = _url; - } + if (_remote.URL != _url) + { + var succ = await new Commands.Remote(_repo.FullPath).SetURLAsync(_name, _url, false); + if (succ) + _remote.URL = _url; + } - var pushURL = new Commands.Remote(_repo.FullPath).GetURL(_name, true); - if (pushURL != _url) - new Commands.Remote(_repo.FullPath).SetURL(_name, _url, true); + var pushURL = await new Commands.Remote(_repo.FullPath).GetURLAsync(_name, true); + if (pushURL != _url) + await new Commands.Remote(_repo.FullPath).SetURLAsync(_name, _url, true); - new Commands.Config(_repo.FullPath).Set($"remote.{_name}.sshkey", _useSSH ? SSHKey : null); + await new Commands.Config(_repo.FullPath).SetAsync($"remote.{_name}.sshkey", _useSSH ? SSHKey : null); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return true; - }); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return true; } private readonly Repository _repo = null; diff --git a/src/ViewModels/ExecuteCustomAction.cs b/src/ViewModels/ExecuteCustomAction.cs index fa734ed5f..915ef1799 100644 --- a/src/ViewModels/ExecuteCustomAction.cs +++ b/src/ViewModels/ExecuteCustomAction.cs @@ -151,7 +151,7 @@ public ExecuteCustomAction(Repository repo, Models.CustomAction action, Models.T PrepareControlParameters(); } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Run custom action ..."; @@ -166,19 +166,16 @@ public override Task Sure() var log = _repo.CreateLog(CustomAction.Name); Use(log); - return Task.Run(() => - { - log.AppendLine($"$ {CustomAction.Executable} {cmdline}\n"); + log.AppendLine($"$ {CustomAction.Executable} {cmdline}\n"); - if (CustomAction.WaitForExit) - RunAndWait(cmdline, log); - else - Run(cmdline); + if (CustomAction.WaitForExit) + RunAndWait(cmdline, log); + else + Run(cmdline); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return true; - }); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return true; } private void PrepareControlParameters() diff --git a/src/ViewModels/Fetch.cs b/src/ViewModels/Fetch.cs index 3225f9e22..00b3de5e8 100644 --- a/src/ViewModels/Fetch.cs +++ b/src/ViewModels/Fetch.cs @@ -54,7 +54,7 @@ public Fetch(Repository repo, Models.Remote preferredRemote = null) } } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); @@ -63,36 +63,33 @@ public override Task Sure() var log = _repo.CreateLog("Fetch"); Use(log); - return Task.Run(() => + if (FetchAllRemotes) { - if (FetchAllRemotes) - { - foreach (var remote in _repo.Remotes) - new Commands.Fetch(_repo.FullPath, remote.Name, notags, force).Use(log).Exec(); - } - else - { - new Commands.Fetch(_repo.FullPath, SelectedRemote.Name, notags, force).Use(log).Exec(); - } - - log.Complete(); - - var upstream = _repo.CurrentBranch?.Upstream; - var upstreamHead = string.Empty; - if (!string.IsNullOrEmpty(upstream)) - upstreamHead = new Commands.QueryRevisionByRefName(_repo.FullPath, upstream.Substring(13)).Result(); - - CallUIThread(() => - { - if (!string.IsNullOrEmpty(upstreamHead)) - _repo.NavigateToCommit(upstreamHead, true); - - _repo.MarkFetched(); - _repo.SetWatcherEnabled(true); - }); - - return true; + foreach (var remote in _repo.Remotes) + await new Commands.Fetch(_repo.FullPath, remote.Name, notags, force).Use(log).ExecAsync(); + } + else + { + await new Commands.Fetch(_repo.FullPath, SelectedRemote.Name, notags, force).Use(log).ExecAsync(); + } + + log.Complete(); + + var upstream = _repo.CurrentBranch?.Upstream; + var upstreamHead = string.Empty; + if (!string.IsNullOrEmpty(upstream)) + upstreamHead = await new Commands.QueryRevisionByRefName(_repo.FullPath, upstream.Substring(13)).ResultAsync(); + + await CallUIThreadAsync(() => + { + if (!string.IsNullOrEmpty(upstreamHead)) + _repo.NavigateToCommit(upstreamHead, true); + + _repo.MarkFetched(); + _repo.SetWatcherEnabled(true); }); + + return true; } private readonly Repository _repo = null; diff --git a/src/ViewModels/FetchInto.cs b/src/ViewModels/FetchInto.cs index c681b6375..89fad2a1d 100644 --- a/src/ViewModels/FetchInto.cs +++ b/src/ViewModels/FetchInto.cs @@ -21,7 +21,7 @@ public FetchInto(Repository repo, Models.Branch local, Models.Branch upstream) Upstream = upstream; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Fast-Forward ..."; @@ -29,20 +29,17 @@ public override Task Sure() var log = _repo.CreateLog($"Fetch Into '{Local.FriendlyName}'"); Use(log); - return Task.Run(() => - { - new Commands.Fetch(_repo.FullPath, Local, Upstream).Use(log).Exec(); - log.Complete(); - - var changedLocalBranchHead = new Commands.QueryRevisionByRefName(_repo.FullPath, Local.Name).Result(); - CallUIThread(() => - { - _repo.NavigateToCommit(changedLocalBranchHead, true); - _repo.SetWatcherEnabled(true); - }); + await new Commands.Fetch(_repo.FullPath, Local, Upstream).Use(log).ExecAsync(); + log.Complete(); - return true; + var changedLocalBranchHead = await new Commands.QueryRevisionByRefName(_repo.FullPath, Local.Name).ResultAsync(); + await CallUIThreadAsync(() => + { + _repo.NavigateToCommit(changedLocalBranchHead, true); + _repo.SetWatcherEnabled(true); }); + + return true; } private readonly Repository _repo = null; diff --git a/src/ViewModels/FileHistories.cs b/src/ViewModels/FileHistories.cs index f7a295dcb..051414dcf 100644 --- a/src/ViewModels/FileHistories.cs +++ b/src/ViewModels/FileHistories.cs @@ -45,26 +45,23 @@ public FileHistoriesSingleRevision(Repository repo, string file, Models.Commit r RefreshViewContent(); } - public Task ResetToSelectedRevision() + public async Task ResetToSelectedRevision() { - return Task.Run(() => new Commands.Checkout(_repo.FullPath).FileWithRevision(_file, $"{_revision.SHA}")); + return await new Commands.Checkout(_repo.FullPath).FileWithRevisionAsync(_file, $"{_revision.SHA}"); } - public Task OpenWithDefaultEditor() + public async Task OpenWithDefaultEditor() { if (_viewContent is not FileHistoriesRevisionFile { CanOpenWithDefaultEditor: true }) - return null; + return; - return Task.Run(() => - { - var fullPath = Native.OS.GetAbsPath(_repo.FullPath, _file); - var fileName = Path.GetFileNameWithoutExtension(fullPath) ?? ""; - var fileExt = Path.GetExtension(fullPath) ?? ""; - var tmpFile = Path.Combine(Path.GetTempPath(), $"{fileName}~{_revision.SHA.Substring(0, 10)}{fileExt}"); + var fullPath = Native.OS.GetAbsPath(_repo.FullPath, _file); + var fileName = Path.GetFileNameWithoutExtension(fullPath) ?? ""; + var fileExt = Path.GetExtension(fullPath) ?? ""; + var tmpFile = Path.Combine(Path.GetTempPath(), $"{fileName}~{_revision.SHA.Substring(0, 10)}{fileExt}"); - Commands.SaveRevisionFile.Run(_repo.FullPath, _revision.SHA, _file, tmpFile); - Native.OS.OpenWithDefaultEditor(tmpFile); - }); + await Commands.SaveRevisionFile.RunAsync(_repo.FullPath, _revision.SHA, _file, tmpFile); + Native.OS.OpenWithDefaultEditor(tmpFile); } private void RefreshViewContent() @@ -88,9 +85,9 @@ private void SetViewContentAsRevisionFile() switch (obj.Type) { case Models.ObjectType.Blob: - Task.Run(() => + Task.Run(async () => { - var isBinary = new Commands.IsBinary(_repo.FullPath, _revision.SHA, _file).Result(); + var isBinary = await new Commands.IsBinary(_repo.FullPath, _revision.SHA, _file).ResultAsync(); if (isBinary) { var imgDecoder = ImageSource.GetDecoder(_file); @@ -98,20 +95,20 @@ private void SetViewContentAsRevisionFile() { var source = ImageSource.FromRevision(_repo.FullPath, _revision.SHA, _file, imgDecoder); var image = new Models.RevisionImageFile(_file, source.Bitmap, source.Size); - Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, image, true)); + await Dispatcher.UIThread.InvokeAsync(() => ViewContent = new FileHistoriesRevisionFile(_file, image, true)); } else { - var size = new Commands.QueryFileSize(_repo.FullPath, _file, _revision.SHA).Result(); + var size = await new Commands.QueryFileSize(_repo.FullPath, _file, _revision.SHA).ResultAsync(); var binaryFile = new Models.RevisionBinaryFile() { Size = size }; - Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, binaryFile, true)); + await Dispatcher.UIThread.InvokeAsync(() => ViewContent = new FileHistoriesRevisionFile(_file, binaryFile, true)); } return; } - var contentStream = Commands.QueryFileContent.Run(_repo.FullPath, _revision.SHA, _file); - var content = new StreamReader(contentStream).ReadToEnd(); + var contentStream = await Commands.QueryFileContent.RunAsync(_repo.FullPath, _revision.SHA, _file); + var content = await new StreamReader(contentStream).ReadToEndAsync(); var lfs = Models.LFSObject.Parse(content); if (lfs != null) { @@ -119,34 +116,34 @@ private void SetViewContentAsRevisionFile() if (imgDecoder != Models.ImageDecoder.None) { var combined = new RevisionLFSImage(_repo.FullPath, _file, lfs, imgDecoder); - Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, combined, true)); + await Dispatcher.UIThread.InvokeAsync(() => ViewContent = new FileHistoriesRevisionFile(_file, combined, true)); } else { var rlfs = new Models.RevisionLFSObject() { Object = lfs }; - Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, rlfs, true)); + await Dispatcher.UIThread.InvokeAsync(() => ViewContent = new FileHistoriesRevisionFile(_file, rlfs, true)); } } else { var txt = new Models.RevisionTextFile() { FileName = obj.Path, Content = content }; - Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, txt, true)); + await Dispatcher.UIThread.InvokeAsync(() => ViewContent = new FileHistoriesRevisionFile(_file, txt, true)); } }); break; case Models.ObjectType.Commit: - Task.Run(() => + Task.Run(async () => { var submoduleRoot = Path.Combine(_repo.FullPath, _file); - var commit = new Commands.QuerySingleCommit(submoduleRoot, obj.SHA).Result(); - var message = commit != null ? new Commands.QueryCommitFullMessage(submoduleRoot, obj.SHA).Result() : null; + var commit = await new Commands.QuerySingleCommit(submoduleRoot, obj.SHA).ResultAsync(); + var message = commit != null ? await new Commands.QueryCommitFullMessage(submoduleRoot, obj.SHA).ResultAsync() : null; var module = new Models.RevisionSubmodule() { Commit = commit ?? new Models.Commit() { SHA = obj.SHA }, FullMessage = new Models.CommitFullMessage { Message = message } }; - Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, module)); + await Dispatcher.UIThread.InvokeAsync(() => ViewContent = new FileHistoriesRevisionFile(_file, module)); }); break; default: @@ -203,28 +200,27 @@ public void Swap() RefreshViewContent(); } - public Task SaveAsPatch(string saveTo) + public async Task SaveAsPatch(string saveTo) { - return Task.Run(() => { - Commands.SaveChangesAsPatch.ProcessRevisionCompareChanges(_repo.FullPath, _changes, _startPoint.SHA, _endPoint.SHA, saveTo); + await Commands.SaveChangesAsPatch.ProcessRevisionCompareChangesAsync(_repo.FullPath, _changes, _startPoint.SHA, _endPoint.SHA, saveTo); return true; - }); + } } private void RefreshViewContent() { - Task.Run(() => + Task.Run(async () => { - _changes = new Commands.CompareRevisions(_repo.FullPath, _startPoint.SHA, _endPoint.SHA, _file).Result(); + _changes = await new Commands.CompareRevisions(_repo.FullPath, _startPoint.SHA, _endPoint.SHA, _file).ResultAsync(); if (_changes.Count == 0) { - Dispatcher.UIThread.Invoke(() => ViewContent = null); + await Dispatcher.UIThread.InvokeAsync(() => ViewContent = null); return; } var option = new Models.DiffOption(_startPoint.SHA, _endPoint.SHA, _changes[0]); - Dispatcher.UIThread.Invoke(() => ViewContent = new DiffContext(_repo.FullPath, option, _viewContent)); + await Dispatcher.UIThread.InvokeAsync(() => ViewContent = new DiffContext(_repo.FullPath, option, _viewContent)); }); } @@ -276,11 +272,11 @@ public FileHistories(Repository repo, string file, string commit = null) _repo = repo; - Task.Run(() => + Task.Run(async () => { var based = commit ?? string.Empty; - var commits = new Commands.QueryCommits(_repo.FullPath, $"--date-order -n 10000 {based} -- \"{file}\"", false).Result(); - Dispatcher.UIThread.Invoke(() => + var commits = await new Commands.QueryCommits(_repo.FullPath, $"--date-order -n 10000 {based} -- \"{file}\"", false).ResultAsync(); + await Dispatcher.UIThread.InvokeAsync(() => { IsLoading = false; Commits = commits; diff --git a/src/ViewModels/GitFlowFinish.cs b/src/ViewModels/GitFlowFinish.cs index bef4c2d99..7ae3deaa2 100644 --- a/src/ViewModels/GitFlowFinish.cs +++ b/src/ViewModels/GitFlowFinish.cs @@ -40,7 +40,7 @@ public GitFlowFinish(Repository repo, Models.Branch branch, Models.GitFlowBranch Type = type; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = $"Git Flow - Finish {Branch.Name} ..."; @@ -51,13 +51,10 @@ public override Task Sure() var prefix = _repo.GitFlow.GetPrefix(Type); var name = Branch.Name.StartsWith(prefix) ? Branch.Name.Substring(prefix.Length) : Branch.Name; - return Task.Run(() => - { - var succ = Commands.GitFlow.Finish(_repo.FullPath, Type, name, Squash, AutoPush, KeepBranch, log); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + var succ = await Commands.GitFlow.FinishAsync(_repo.FullPath, Type, name, Squash, AutoPush, KeepBranch, log); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private readonly Repository _repo; diff --git a/src/ViewModels/GitFlowStart.cs b/src/ViewModels/GitFlowStart.cs index 3ecba883a..29110c8c0 100644 --- a/src/ViewModels/GitFlowStart.cs +++ b/src/ViewModels/GitFlowStart.cs @@ -49,7 +49,7 @@ public static ValidationResult ValidateBranchName(string name, ValidationContext return ValidationResult.Success; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = $"Git Flow - Start {Prefix}{_name} ..."; @@ -57,13 +57,10 @@ public override Task Sure() var log = _repo.CreateLog("GitFlow - Start"); Use(log); - return Task.Run(() => - { - var succ = Commands.GitFlow.Start(_repo.FullPath, Type, _name, log); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + var succ = await Commands.GitFlow.StartAsync(_repo.FullPath, Type, _name, log); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private readonly Repository _repo; diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs index 8d159419e..4dc970275 100644 --- a/src/ViewModels/Histories.cs +++ b/src/ViewModels/Histories.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO; using System.Text; -using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Platform.Storage; @@ -393,7 +392,7 @@ public ContextMenu MakeContextMenu(DataGrid list) for (var i = 0; i < selected.Count; i++) { var saveTo = GetPatchFileName(folderPath, selected[i], i); - succ = await Task.Run(() => new Commands.FormatPatch(_repo.FullPath, selected[i].SHA, saveTo).Use(log).Exec()); + succ = await new Commands.FormatPatch(_repo.FullPath, selected[i].SHA, saveTo).Use(log).ExecAsync(); if (!succ) break; } @@ -588,7 +587,7 @@ public ContextMenu MakeContextMenu(DataGrid list) var cherryPick = new MenuItem(); cherryPick.Header = App.Text("CommitCM.CherryPick"); cherryPick.Icon = App.CreateMenuIcon("Icons.CherryPick"); - cherryPick.Click += (_, e) => + cherryPick.Click += async (_, e) => { if (_repo.CanCreatePopup()) { @@ -601,7 +600,7 @@ public ContextMenu MakeContextMenu(DataGrid list) var parents = new List(); foreach (var sha in commit.Parents) { - var parent = _commits.Find(x => x.SHA == sha) ?? new Commands.QuerySingleCommit(_repo.FullPath, sha).Result(); + var parent = _commits.Find(x => x.SHA == sha) ?? await new Commands.QuerySingleCommit(_repo.FullPath, sha).ResultAsync(); if (parent != null) parents.Add(parent); @@ -685,13 +684,13 @@ public ContextMenu MakeContextMenu(DataGrid list) var compareWithHead = new MenuItem(); compareWithHead.Header = App.Text("CommitCM.CompareWithHead"); compareWithHead.Icon = App.CreateMenuIcon("Icons.Compare"); - compareWithHead.Click += (_, e) => + compareWithHead.Click += async (_, e) => { var head = _commits.Find(x => x.SHA == current.Head); if (head == null) { _repo.SelectedSearchedCommit = null; - head = new Commands.QuerySingleCommit(_repo.FullPath, current.Head).Result(); + head = await new Commands.QuerySingleCommit(_repo.FullPath, current.Head).ResultAsync(); if (head != null) DetailContext = new RevisionCompare(_repo.FullPath, commit, head); } @@ -764,7 +763,7 @@ public ContextMenu MakeContextMenu(DataGrid list) var folder = selected[0]; var folderPath = folder is { Path: { IsAbsoluteUri: true } path } ? path.LocalPath : folder.Path.ToString(); var saveTo = GetPatchFileName(folderPath, commit); - var succ = await Task.Run(() => new Commands.FormatPatch(_repo.FullPath, commit.SHA, saveTo).Use(log).Exec()); + var succ = await new Commands.FormatPatch(_repo.FullPath, commit.SHA, saveTo).Use(log).ExecAsync(); if (succ) App.SendNotification(_repo.FullPath, App.Text("SaveAsPatchSuccess")); } diff --git a/src/ViewModels/InProgressContexts.cs b/src/ViewModels/InProgressContexts.cs index d26e50c97..922ad997d 100644 --- a/src/ViewModels/InProgressContexts.cs +++ b/src/ViewModels/InProgressContexts.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Threading.Tasks; namespace SourceGit.ViewModels { @@ -10,27 +11,27 @@ protected InProgressContext(string repo, string cmd) _cmd = cmd; } - public bool Abort() + public Task AbortAsync() { return new Commands.Command() { WorkingDirectory = _repo, Context = _repo, Args = $"{_cmd} --abort", - }.Exec(); + }.ExecAsync(); } - public virtual bool Skip() + public virtual Task SkipAsync() { return new Commands.Command() { WorkingDirectory = _repo, Context = _repo, Args = $"{_cmd} --skip", - }.Exec(); + }.ExecAsync(); } - public virtual bool Continue() + public virtual Task ContinueAsync() { return new Commands.Command() { @@ -38,7 +39,7 @@ public virtual bool Continue() Context = _repo, Editor = Commands.Command.EditorType.None, Args = $"{_cmd} --continue", - }.Exec(); + }.ExecAsync(); } protected string GetFriendlyNameOfCommit(Models.Commit commit) @@ -123,7 +124,7 @@ public RebaseInProgress(Repository repo) : base(repo.FullPath, "rebase") Onto = new Commands.QuerySingleCommit(repo.FullPath, ontoSHA).Result() ?? new Models.Commit() { SHA = ontoSHA }; } - public override bool Continue() + public override Task ContinueAsync() { return new Commands.Command() { @@ -131,7 +132,7 @@ public override bool Continue() Context = _repo, Editor = Commands.Command.EditorType.RebaseEditor, Args = "rebase --continue", - }.Exec(); + }.ExecAsync(); } } @@ -177,9 +178,9 @@ public MergeInProgress(Repository repo) : base(repo.FullPath, "merge") Source = new Commands.QuerySingleCommit(repo.FullPath, sourceSHA).Result() ?? new Models.Commit() { SHA = sourceSHA }; } - public override bool Skip() + public override Task SkipAsync() { - return true; + return Task.FromResult(true); } } } diff --git a/src/ViewModels/Init.cs b/src/ViewModels/Init.cs index b47ba6636..7a5ebbbdb 100644 --- a/src/ViewModels/Init.cs +++ b/src/ViewModels/Init.cs @@ -24,29 +24,26 @@ public Init(string pageId, string path, RepositoryNode parent, string reason) Reason = string.IsNullOrEmpty(reason) ? "Invalid repository detected!" : reason; } - public override Task Sure() + public override async Task Sure() { ProgressDescription = $"Initialize git repository at: '{_targetPath}'"; var log = new CommandLog("Initialize"); Use(log); - return Task.Run(() => - { - var succ = new Commands.Init(_pageId, _targetPath).Use(log).Exec(); - log.Complete(); + var succ = await new Commands.Init(_pageId, _targetPath).Use(log).ExecAsync(); + log.Complete(); - if (succ) + if (succ) + { + await CallUIThreadAsync(() => { - CallUIThread(() => - { - Preferences.Instance.FindOrAddNodeByRepositoryPath(_targetPath, _parentNode, true); - Welcome.Instance.Refresh(); - }); - } - - return succ; - }); + Preferences.Instance.FindOrAddNodeByRepositoryPath(_targetPath, _parentNode, true); + Welcome.Instance.Refresh(); + }); + } + + return succ; } private readonly string _pageId = null; diff --git a/src/ViewModels/InitGitFlow.cs b/src/ViewModels/InitGitFlow.cs index c5aeceec0..95084e614 100644 --- a/src/ViewModels/InitGitFlow.cs +++ b/src/ViewModels/InitGitFlow.cs @@ -100,7 +100,7 @@ public static ValidationResult ValidateTagPrefix(string tagPrefix, ValidationCon return ValidationResult.Success; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Init git-flow ..."; @@ -108,65 +108,62 @@ public override Task Sure() var log = _repo.CreateLog("Gitflow - Init"); Use(log); - return Task.Run(() => - { - bool succ; - var current = _repo.CurrentBranch; + bool succ; + var current = _repo.CurrentBranch; - var masterBranch = _repo.Branches.Find(x => x.IsLocal && x.Name.Equals(_master, StringComparison.Ordinal)); - if (masterBranch == null) + var masterBranch = _repo.Branches.Find(x => x.IsLocal && x.Name.Equals(_master, StringComparison.Ordinal)); + if (masterBranch == null) + { + succ = await Commands.Branch.CreateAsync(_repo.FullPath, _master, current.Head, true, log); + if (!succ) { - succ = Commands.Branch.Create(_repo.FullPath, _master, current.Head, true, log); - if (!succ) - { - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return false; - } + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return false; } + } - var developBranch = _repo.Branches.Find(x => x.IsLocal && x.Name.Equals(_develop, StringComparison.Ordinal)); - if (developBranch == null) + var developBranch = _repo.Branches.Find(x => x.IsLocal && x.Name.Equals(_develop, StringComparison.Ordinal)); + if (developBranch == null) + { + succ = await Commands.Branch.CreateAsync(_repo.FullPath, _develop, current.Head, true, log); + if (!succ) { - succ = Commands.Branch.Create(_repo.FullPath, _develop, current.Head, true, log); - if (!succ) - { - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return false; - } + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return false; } + } - succ = Commands.GitFlow.Init( - _repo.FullPath, - _master, - _develop, - _featurePrefix, - _releasePrefix, - _hotfixPrefix, - _tagPrefix, - log); + succ = await Commands.GitFlow.InitAsync( + _repo.FullPath, + _master, + _develop, + _featurePrefix, + _releasePrefix, + _hotfixPrefix, + _tagPrefix, + log); - log.Complete(); + log.Complete(); - CallUIThread(() => + await CallUIThreadAsync(() => + { + if (succ) { - if (succ) - { - var gitflow = new Models.GitFlow(); - gitflow.Master = _master; - gitflow.Develop = _develop; - gitflow.FeaturePrefix = _featurePrefix; - gitflow.ReleasePrefix = _releasePrefix; - gitflow.HotfixPrefix = _hotfixPrefix; - _repo.GitFlow = gitflow; - } - - _repo.SetWatcherEnabled(true); - }); - - return succ; + var gitflow = new Models.GitFlow(); + gitflow.Master = _master; + gitflow.Develop = _develop; + gitflow.FeaturePrefix = _featurePrefix; + gitflow.ReleasePrefix = _releasePrefix; + gitflow.HotfixPrefix = _hotfixPrefix; + _repo.GitFlow = gitflow; + } + + _repo.SetWatcherEnabled(true); }); + + return succ; } private readonly Repository _repo; diff --git a/src/ViewModels/InteractiveRebase.cs b/src/ViewModels/InteractiveRebase.cs index 40b2dcc3b..b59e2c3af 100644 --- a/src/ViewModels/InteractiveRebase.cs +++ b/src/ViewModels/InteractiveRebase.cs @@ -131,9 +131,9 @@ public InteractiveRebase(Repository repo, Models.Branch current, Models.Commit o IsLoading = true; DetailContext = new CommitDetail(repo, false); - Task.Run(() => + Task.Run(async () => { - var commits = new Commands.QueryCommitsForInteractiveRebase(repoPath, on.SHA).Result(); + var commits = await new Commands.QueryCommitsForInteractiveRebase(repoPath, on.SHA).ResultAsync(); var list = new List(); for (var i = 0; i < commits.Count; i++) @@ -142,7 +142,7 @@ public InteractiveRebase(Repository repo, Models.Branch current, Models.Commit o list.Add(new InteractiveRebaseItem(c.Commit, c.Message, i < commits.Count - 1)); } - Dispatcher.UIThread.Invoke(() => + await Dispatcher.UIThread.InvokeAsync(() => { Items.AddRange(list); IsLoading = false; @@ -188,7 +188,7 @@ public void ChangeAction(InteractiveRebaseItem item, Models.InteractiveRebaseAct UpdateItems(); } - public Task Start() + public async Task Start() { _repo.SetWatcherEnabled(false); @@ -206,19 +206,16 @@ public Task Start() Message = item.FullMessage, }); } - using (var stream = File.Create(saveFile)) + await using (var stream = File.Create(saveFile)) { - JsonSerializer.Serialize(stream, collection, JsonCodeGen.Default.InteractiveRebaseJobCollection); + await JsonSerializer.SerializeAsync(stream, collection, JsonCodeGen.Default.InteractiveRebaseJobCollection); } var log = _repo.CreateLog("Interactive Rebase"); - return Task.Run(() => - { - var succ = new Commands.InteractiveRebase(_repo.FullPath, On.SHA).Use(log).Exec(); - log.Complete(); - Dispatcher.UIThread.Invoke(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + var succ = await new Commands.InteractiveRebase(_repo.FullPath, On.SHA).Use(log).ExecAsync(); + log.Complete(); + await Dispatcher.UIThread.InvokeAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private void UpdateItems() diff --git a/src/ViewModels/LFSFetch.cs b/src/ViewModels/LFSFetch.cs index 99d9babb7..4456070b0 100644 --- a/src/ViewModels/LFSFetch.cs +++ b/src/ViewModels/LFSFetch.cs @@ -19,7 +19,7 @@ public LFSFetch(Repository repo) SelectedRemote = _repo.Remotes[0]; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Fetching LFS objects from remote ..."; @@ -27,13 +27,10 @@ public override Task Sure() var log = _repo.CreateLog("LFS Fetch"); Use(log); - return Task.Run(() => - { - new Commands.LFS(_repo.FullPath).Fetch(SelectedRemote.Name, log); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return true; - }); + await new Commands.LFS(_repo.FullPath).FetchAsync(SelectedRemote.Name, log); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return true; } private readonly Repository _repo = null; diff --git a/src/ViewModels/LFSLocks.cs b/src/ViewModels/LFSLocks.cs index 0ee149d06..19bf70547 100644 --- a/src/ViewModels/LFSLocks.cs +++ b/src/ViewModels/LFSLocks.cs @@ -45,10 +45,10 @@ public LFSLocks(Repository repo, string remote) HasValidUserName = !string.IsNullOrEmpty(_userName); - Task.Run(() => + Task.Run(async () => { - _cachedLocks = new Commands.LFS(_repo.FullPath).Locks(_remote); - Dispatcher.UIThread.Invoke(() => + _cachedLocks = await new Commands.LFS(_repo.FullPath).LocksAsync(_remote); + await Dispatcher.UIThread.InvokeAsync(() => { UpdateVisibleLocks(); IsLoading = false; @@ -64,12 +64,12 @@ public void Unlock(Models.LFSLock lfsLock, bool force) IsLoading = true; var log = _repo.CreateLog("Unlock LFS File"); - Task.Run(() => + Task.Run(async () => { - var succ = new Commands.LFS(_repo.FullPath).Unlock(_remote, lfsLock.ID, force, log); + var succ = await new Commands.LFS(_repo.FullPath).UnlockAsync(_remote, lfsLock.ID, force, log); log.Complete(); - Dispatcher.UIThread.Invoke(() => + await Dispatcher.UIThread.InvokeAsync(() => { if (succ) { diff --git a/src/ViewModels/LFSPrune.cs b/src/ViewModels/LFSPrune.cs index 9a6bd8a79..780a7f852 100644 --- a/src/ViewModels/LFSPrune.cs +++ b/src/ViewModels/LFSPrune.cs @@ -9,7 +9,7 @@ public LFSPrune(Repository repo) _repo = repo; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "LFS prune ..."; @@ -17,13 +17,10 @@ public override Task Sure() var log = _repo.CreateLog("LFS Prune"); Use(log); - return Task.Run(() => - { - new Commands.LFS(_repo.FullPath).Prune(log); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return true; - }); + await new Commands.LFS(_repo.FullPath).PruneAsync(log); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return true; } private readonly Repository _repo = null; diff --git a/src/ViewModels/LFSPull.cs b/src/ViewModels/LFSPull.cs index 1943c02e5..c4dde9f77 100644 --- a/src/ViewModels/LFSPull.cs +++ b/src/ViewModels/LFSPull.cs @@ -19,7 +19,7 @@ public LFSPull(Repository repo) SelectedRemote = _repo.Remotes[0]; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Pull LFS objects from remote ..."; @@ -27,13 +27,10 @@ public override Task Sure() var log = _repo.CreateLog("LFS Pull"); Use(log); - return Task.Run(() => - { - new Commands.LFS(_repo.FullPath).Pull(SelectedRemote.Name, log); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return true; - }); + await new Commands.LFS(_repo.FullPath).PullAsync(SelectedRemote.Name, log); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return true; } private readonly Repository _repo = null; diff --git a/src/ViewModels/LFSPush.cs b/src/ViewModels/LFSPush.cs index ea111effd..33de0a9ed 100644 --- a/src/ViewModels/LFSPush.cs +++ b/src/ViewModels/LFSPush.cs @@ -19,7 +19,7 @@ public LFSPush(Repository repo) SelectedRemote = _repo.Remotes[0]; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Push LFS objects to remote ..."; @@ -27,13 +27,10 @@ public override Task Sure() var log = _repo.CreateLog("LFS Push"); Use(log); - return Task.Run(() => - { - new Commands.LFS(_repo.FullPath).Push(SelectedRemote.Name, log); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return true; - }); + await new Commands.LFS(_repo.FullPath).PushAsync(SelectedRemote.Name, log); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return true; } private readonly Repository _repo = null; diff --git a/src/ViewModels/LFSTrackCustomPattern.cs b/src/ViewModels/LFSTrackCustomPattern.cs index b69733e82..f43af2ec5 100644 --- a/src/ViewModels/LFSTrackCustomPattern.cs +++ b/src/ViewModels/LFSTrackCustomPattern.cs @@ -23,7 +23,7 @@ public LFSTrackCustomPattern(Repository repo) _repo = repo; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Adding custom LFS tracking pattern ..."; @@ -31,13 +31,10 @@ public override Task Sure() var log = _repo.CreateLog("LFS Add Custom Pattern"); Use(log); - return Task.Run(() => - { - var succ = new Commands.LFS(_repo.FullPath).Track(_pattern, IsFilename, log); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + var succ = await new Commands.LFS(_repo.FullPath).TrackAsync(_pattern, IsFilename, log); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private readonly Repository _repo = null; diff --git a/src/ViewModels/Merge.cs b/src/ViewModels/Merge.cs index d7b6a29c3..d11e75dab 100644 --- a/src/ViewModels/Merge.cs +++ b/src/ViewModels/Merge.cs @@ -57,7 +57,7 @@ public Merge(Repository repo, Models.Tag source, string into) Mode = AutoSelectMergeMode(); } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); _repo.ClearCommitMessage(); @@ -66,19 +66,16 @@ public override Task Sure() var log = _repo.CreateLog($"Merging '{_sourceName}' into '{Into}'"); Use(log); - return Task.Run(() => + await new Commands.Merge(_repo.FullPath, _sourceName, Mode.Arg, Edit).Use(log).ExecAsync(); + log.Complete(); + + var head = await new Commands.QueryRevisionByRefName(_repo.FullPath, "HEAD").ResultAsync(); + await CallUIThreadAsync(() => { - new Commands.Merge(_repo.FullPath, _sourceName, Mode.Arg, Edit).Use(log).Exec(); - log.Complete(); - - var head = new Commands.QueryRevisionByRefName(_repo.FullPath, "HEAD").Result(); - CallUIThread(() => - { - _repo.NavigateToCommit(head, true); - _repo.SetWatcherEnabled(true); - }); - return true; + _repo.NavigateToCommit(head, true); + _repo.SetWatcherEnabled(true); }); + return true; } private Models.MergeMode AutoSelectMergeMode() diff --git a/src/ViewModels/MergeMultiple.cs b/src/ViewModels/MergeMultiple.cs index aaa21cce5..c54afffe5 100644 --- a/src/ViewModels/MergeMultiple.cs +++ b/src/ViewModels/MergeMultiple.cs @@ -38,7 +38,7 @@ public MergeMultiple(Repository repo, List branches) Strategy = Models.MergeStrategy.ForMultiple[0]; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); _repo.ClearCommitMessage(); @@ -47,18 +47,15 @@ public override Task Sure() var log = _repo.CreateLog("Merge Multiple Heads"); Use(log); - return Task.Run(() => - { - new Commands.Merge( - _repo.FullPath, - ConvertTargetToMergeSources(), - AutoCommit, - Strategy.Arg).Use(log).Exec(); + await new Commands.Merge( + _repo.FullPath, + ConvertTargetToMergeSources(), + AutoCommit, + Strategy.Arg).Use(log).ExecAsync(); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return true; - }); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return true; } private List ConvertTargetToMergeSources() diff --git a/src/ViewModels/Popup.cs b/src/ViewModels/Popup.cs index b3fe7e230..f93996682 100644 --- a/src/ViewModels/Popup.cs +++ b/src/ViewModels/Popup.cs @@ -46,6 +46,11 @@ protected void CallUIThread(Action action) Dispatcher.UIThread.Invoke(action); } + protected async Task CallUIThreadAsync(Action action) + { + await Dispatcher.UIThread.InvokeAsync(action); + } + protected void Use(CommandLog log) { log.Register(SetDescription); diff --git a/src/ViewModels/PruneRemote.cs b/src/ViewModels/PruneRemote.cs index 007bcab81..d9e57a71a 100644 --- a/src/ViewModels/PruneRemote.cs +++ b/src/ViewModels/PruneRemote.cs @@ -15,7 +15,7 @@ public PruneRemote(Repository repo, Models.Remote remote) Remote = remote; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Run `prune` on remote ..."; @@ -23,13 +23,10 @@ public override Task Sure() var log = _repo.CreateLog($"Prune Remote '{Remote.Name}'"); Use(log); - return Task.Run(() => - { - var succ = new Commands.Remote(_repo.FullPath).Use(log).Prune(Remote.Name); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + var succ = await new Commands.Remote(_repo.FullPath).Use(log).PruneAsync(Remote.Name); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private readonly Repository _repo = null; diff --git a/src/ViewModels/PruneWorktrees.cs b/src/ViewModels/PruneWorktrees.cs index 3cb884dc5..53096e950 100644 --- a/src/ViewModels/PruneWorktrees.cs +++ b/src/ViewModels/PruneWorktrees.cs @@ -9,7 +9,7 @@ public PruneWorktrees(Repository repo) _repo = repo; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Prune worktrees ..."; @@ -17,13 +17,10 @@ public override Task Sure() var log = _repo.CreateLog("Prune Worktrees"); Use(log); - return Task.Run(() => - { - new Commands.Worktree(_repo.FullPath).Use(log).Prune(); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return true; - }); + await new Commands.Worktree(_repo.FullPath).Use(log).PruneAsync(); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return true; } private readonly Repository _repo = null; diff --git a/src/ViewModels/Pull.cs b/src/ViewModels/Pull.cs index 1ddd6d999..7b3182ff9 100644 --- a/src/ViewModels/Pull.cs +++ b/src/ViewModels/Pull.cs @@ -111,7 +111,7 @@ public Pull(Repository repo, Models.Branch specifiedRemoteBranch) } } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); @@ -119,60 +119,57 @@ public override Task Sure() Use(log); var updateSubmodules = IsRecurseSubmoduleVisible && RecurseSubmodules; - return Task.Run(() => + var changes = await new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).ResultAsync(); + var needPopStash = false; + if (changes > 0) { - var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result(); - var needPopStash = false; - if (changes > 0) + if (DiscardLocalChanges) { - if (DiscardLocalChanges) - { - Commands.Discard.All(_repo.FullPath, false, log); - } - else - { - var succ = new Commands.Stash(_repo.FullPath).Use(log).Push("PULL_AUTO_STASH"); - if (!succ) - { - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return false; - } - - needPopStash = true; - } + await Commands.Discard.AllAsync(_repo.FullPath, false, log); } - - bool rs = new Commands.Pull( - _repo.FullPath, - _selectedRemote.Name, - !string.IsNullOrEmpty(Current.Upstream) && Current.Upstream.Equals(_selectedBranch.FullName) ? string.Empty : _selectedBranch.Name, - UseRebase).Use(log).Exec(); - - if (rs) + else { - if (updateSubmodules) + var succ = await new Commands.Stash(_repo.FullPath).Use(log).PushAsync("PULL_AUTO_STASH"); + if (!succ) { - var submodules = new Commands.QueryUpdatableSubmodules(_repo.FullPath).Result(); - if (submodules.Count > 0) - new Commands.Submodule(_repo.FullPath).Use(log).Update(submodules, true, true); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return false; } - if (needPopStash) - new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}"); + needPopStash = true; } + } - log.Complete(); + bool rs = await new Commands.Pull( + _repo.FullPath, + _selectedRemote.Name, + !string.IsNullOrEmpty(Current.Upstream) && Current.Upstream.Equals(_selectedBranch.FullName) ? string.Empty : _selectedBranch.Name, + UseRebase).Use(log).ExecAsync(); - var head = new Commands.QueryRevisionByRefName(_repo.FullPath, "HEAD").Result(); - CallUIThread(() => + if (rs) + { + if (updateSubmodules) { - _repo.NavigateToCommit(head, true); - _repo.SetWatcherEnabled(true); - }); + var submodules = await new Commands.QueryUpdatableSubmodules(_repo.FullPath).ResultAsync(); + if (submodules.Count > 0) + await new Commands.Submodule(_repo.FullPath).Use(log).UpdateAsync(submodules, true, true); + } + + if (needPopStash) + await new Commands.Stash(_repo.FullPath).Use(log).PopAsync("stash@{0}"); + } - return rs; + log.Complete(); + + var head = await new Commands.QueryRevisionByRefName(_repo.FullPath, "HEAD").ResultAsync(); + await CallUIThreadAsync(() => + { + _repo.NavigateToCommit(head, true); + _repo.SetWatcherEnabled(true); }); + + return rs; } private void PostRemoteSelected() diff --git a/src/ViewModels/Push.cs b/src/ViewModels/Push.cs index 917935b04..41d76d9c7 100644 --- a/src/ViewModels/Push.cs +++ b/src/ViewModels/Push.cs @@ -158,7 +158,7 @@ public override bool CanStartDirectly() return !string.IsNullOrEmpty(_selectedRemoteBranch?.Head); } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); @@ -168,22 +168,19 @@ public override Task Sure() var log = _repo.CreateLog("Push"); Use(log); - return Task.Run(() => - { - var succ = new Commands.Push( - _repo.FullPath, - _selectedLocalBranch.Name, - _selectedRemote.Name, - remoteBranchName, - PushAllTags, - _repo.Submodules.Count > 0 && CheckSubmodules, - _isSetTrackOptionVisible && Tracking, - ForcePush).Use(log).Exec(); - - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + var succ = await new Commands.Push( + _repo.FullPath, + _selectedLocalBranch.Name, + _selectedRemote.Name, + remoteBranchName, + PushAllTags, + _repo.Submodules.Count > 0 && CheckSubmodules, + _isSetTrackOptionVisible && Tracking, + ForcePush).Use(log).ExecAsync(); + + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private void AutoSelectBranchByRemote() diff --git a/src/ViewModels/PushRevision.cs b/src/ViewModels/PushRevision.cs index 9322db2cb..5d361b1e7 100644 --- a/src/ViewModels/PushRevision.cs +++ b/src/ViewModels/PushRevision.cs @@ -28,7 +28,7 @@ public PushRevision(Repository repo, Models.Commit revision, Models.Branch remot Force = false; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = $"Push {Revision.SHA.Substring(0, 10)} -> {RemoteBranch.FriendlyName} ..."; @@ -36,22 +36,19 @@ public override Task Sure() var log = _repo.CreateLog("Push Revision"); Use(log); - return Task.Run(() => - { - var succ = new Commands.Push( - _repo.FullPath, - Revision.SHA, - RemoteBranch.Remote, - RemoteBranch.Name, - false, - false, - false, - Force).Use(log).Exec(); - - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + var succ = await new Commands.Push( + _repo.FullPath, + Revision.SHA, + RemoteBranch.Remote, + RemoteBranch.Name, + false, + false, + false, + Force).Use(log).ExecAsync(); + + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private readonly Repository _repo; diff --git a/src/ViewModels/PushTag.cs b/src/ViewModels/PushTag.cs index 82a3af00d..7ce621e66 100644 --- a/src/ViewModels/PushTag.cs +++ b/src/ViewModels/PushTag.cs @@ -34,7 +34,7 @@ public PushTag(Repository repo, Models.Tag target) SelectedRemote = _repo.Remotes[0]; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Pushing tag ..."; @@ -42,28 +42,25 @@ public override Task Sure() var log = _repo.CreateLog("Push Tag"); Use(log); - return Task.Run(() => + var succ = true; + var tag = $"refs/tags/{Target.Name}"; + if (_pushAllRemotes) { - var succ = true; - var tag = $"refs/tags/{Target.Name}"; - if (_pushAllRemotes) + foreach (var remote in _repo.Remotes) { - foreach (var remote in _repo.Remotes) - { - succ = new Commands.Push(_repo.FullPath, remote.Name, tag, false).Use(log).Exec(); - if (!succ) - break; - } - } - else - { - succ = new Commands.Push(_repo.FullPath, SelectedRemote.Name, tag, false).Use(log).Exec(); + succ = await new Commands.Push(_repo.FullPath, remote.Name, tag, false).Use(log).ExecAsync(); + if (!succ) + break; } + } + else + { + succ = await new Commands.Push(_repo.FullPath, SelectedRemote.Name, tag, false).Use(log).ExecAsync(); + } - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private readonly Repository _repo = null; diff --git a/src/ViewModels/Rebase.cs b/src/ViewModels/Rebase.cs index 0fc8ec898..8616c7458 100644 --- a/src/ViewModels/Rebase.cs +++ b/src/ViewModels/Rebase.cs @@ -40,7 +40,7 @@ public Rebase(Repository repo, Models.Branch current, Models.Commit on) AutoStash = true; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); _repo.ClearCommitMessage(); @@ -49,13 +49,10 @@ public override Task Sure() var log = _repo.CreateLog("Rebase"); Use(log); - return Task.Run(() => - { - new Commands.Rebase(_repo.FullPath, _revision, AutoStash).Use(log).Exec(); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return true; - }); + await new Commands.Rebase(_repo.FullPath, _revision, AutoStash).Use(log).ExecAsync(); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return true; } private readonly Repository _repo; diff --git a/src/ViewModels/RemoveWorktree.cs b/src/ViewModels/RemoveWorktree.cs index d5de8533d..aace0b642 100644 --- a/src/ViewModels/RemoveWorktree.cs +++ b/src/ViewModels/RemoveWorktree.cs @@ -21,7 +21,7 @@ public RemoveWorktree(Repository repo, Models.Worktree target) Target = target; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Remove worktree ..."; @@ -29,13 +29,10 @@ public override Task Sure() var log = _repo.CreateLog("Remove worktree"); Use(log); - return Task.Run(() => - { - var succ = new Commands.Worktree(_repo.FullPath).Use(log).Remove(Target.FullPath, Force); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + var succ = await new Commands.Worktree(_repo.FullPath).Use(log).RemoveAsync(Target.FullPath, Force); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private readonly Repository _repo = null; diff --git a/src/ViewModels/RenameBranch.cs b/src/ViewModels/RenameBranch.cs index 22cd2688b..9b2f239c0 100644 --- a/src/ViewModels/RenameBranch.cs +++ b/src/ViewModels/RenameBranch.cs @@ -44,11 +44,11 @@ public static ValidationResult ValidateBranchName(string name, ValidationContext return ValidationResult.Success; } - public override Task Sure() + public override async Task Sure() { var fixedName = FixName(_name); if (fixedName == Target.Name) - return null; + return true; _repo.SetWatcherEnabled(false); ProgressDescription = $"Rename '{Target.Name}'"; @@ -56,39 +56,36 @@ public override Task Sure() var log = _repo.CreateLog($"Rename Branch '{Target.Name}'"); Use(log); - return Task.Run(() => + var isCurrent = Target.IsCurrent; + var oldName = Target.FullName; + var succ = await Commands.Branch.RenameAsync(_repo.FullPath, Target.Name, fixedName, log); + log.Complete(); + + await CallUIThreadAsync(() => { - var isCurrent = Target.IsCurrent; - var oldName = Target.FullName; - var succ = Commands.Branch.Rename(_repo.FullPath, Target.Name, fixedName, log); - log.Complete(); + ProgressDescription = "Waiting for branch updated..."; - CallUIThread(() => + if (succ) { - ProgressDescription = "Waiting for branch updated..."; - - if (succ) + foreach (var filter in _repo.Settings.HistoriesFilters) { - foreach (var filter in _repo.Settings.HistoriesFilters) + if (filter.Type == Models.FilterType.LocalBranch && + filter.Pattern.Equals(oldName, StringComparison.Ordinal)) { - if (filter.Type == Models.FilterType.LocalBranch && - filter.Pattern.Equals(oldName, StringComparison.Ordinal)) - { - filter.Pattern = $"refs/heads/{fixedName}"; - break; - } + filter.Pattern = $"refs/heads/{fixedName}"; + break; } } + } - _repo.MarkBranchesDirtyManually(); - _repo.SetWatcherEnabled(true); - }); + _repo.MarkBranchesDirtyManually(); + _repo.SetWatcherEnabled(true); + }); - if (isCurrent) - Task.Delay(400).Wait(); + if (isCurrent) + Task.Delay(400).Wait(); - return succ; - }); + return succ; } private string FixName(string name) diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index 8dbf7012b..86b542ab3 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -649,9 +649,9 @@ public void RefreshAll() Task.Run(RefreshWorkingCopyChanges); Task.Run(RefreshStashes); - Task.Run(() => + Task.Run(async () => { - var config = new Commands.Config(_fullpath).ListAll(); + var config = await new Commands.Config(_fullpath).ListAllAsync(); _hasAllowedSignersFile = config.TryGetValue("gpg.ssh.allowedSignersFile", out var allowedSignersFile) && !string.IsNullOrEmpty(allowedSignersFile); if (config.TryGetValue("gitflow.branch.master", out var masterName)) @@ -869,26 +869,26 @@ public void StartSearchCommits() SelectedSearchedCommit = null; MatchedFilesForSearching = null; - Task.Run(() => + Task.Run(async () => { var visible = new List(); var method = (Models.CommitSearchMethod)_searchCommitFilterType; if (method == Models.CommitSearchMethod.BySHA) { - var isCommitSHA = new Commands.IsCommitSHA(_fullpath, _searchCommitFilter).Result(); + var isCommitSHA = await new Commands.IsCommitSHA(_fullpath, _searchCommitFilter).ResultAsync(); if (isCommitSHA) { - var commit = new Commands.QuerySingleCommit(_fullpath, _searchCommitFilter).Result(); + var commit = await new Commands.QuerySingleCommit(_fullpath, _searchCommitFilter).ResultAsync(); visible.Add(commit); } } else { - visible = new Commands.QueryCommits(_fullpath, _searchCommitFilter, method, _onlySearchCommitsInCurrentBranch).Result(); + visible = await new Commands.QueryCommits(_fullpath, _searchCommitFilter, method, _onlySearchCommitsInCurrentBranch).ResultAsync(); } - Dispatcher.UIThread.Invoke(() => + await Dispatcher.UIThread.InvokeAsync(() => { SearchedCommits = visible; IsSearchLoadingVisible = false; @@ -1102,13 +1102,13 @@ public void Bisect(string subcmd) SetWatcherEnabled(false); var log = CreateLog($"Bisect({subcmd})"); - Task.Run(() => + Task.Run(async () => { - var succ = new Commands.Bisect(_fullpath, subcmd).Use(log).Exec(); + var succ = await new Commands.Bisect(_fullpath, subcmd).Use(log).ExecAsync(); log.Complete(); - var head = new Commands.QueryRevisionByRefName(_fullpath, "HEAD").Result(); - Dispatcher.UIThread.Invoke(() => + var head = await new Commands.QueryRevisionByRefName(_fullpath, "HEAD").ResultAsync(); + await Dispatcher.UIThread.InvokeAsync(() => { if (!succ) App.RaiseException(_fullpath, log.Content.Substring(log.Content.IndexOf('\n')).Trim()); @@ -1722,10 +1722,10 @@ public ContextMenu CreateContextMenuForGitLFS() var install = new MenuItem(); install.Header = App.Text("GitLFS.Install"); install.Icon = App.CreateMenuIcon("Icons.Init"); - install.Click += (_, e) => + install.Click += async (_, e) => { var log = CreateLog("Install LFS"); - var succ = new Commands.LFS(_fullpath).Install(log); + var succ = await new Commands.LFS(_fullpath).InstallAsync(log); if (succ) App.SendNotification(_fullpath, "LFS enabled successfully!"); @@ -2020,13 +2020,13 @@ public ContextMenu CreateContextMenuForLocalBranch(Models.Branch branch) var compareWithWorktree = new MenuItem(); compareWithWorktree.Header = App.Text("BranchCM.CompareWithWorktree"); compareWithWorktree.Icon = App.CreateMenuIcon("Icons.Compare"); - compareWithWorktree.Click += (_, _) => + compareWithWorktree.Click += async (_, _) => { SelectedSearchedCommit = null; if (_histories != null) { - var target = new Commands.QuerySingleCommit(_fullpath, branch.Head).Result(); + var target = await new Commands.QuerySingleCommit(_fullpath, branch.Head).ResultAsync(); _histories.AutoSelectedCommit = null; _histories.DetailContext = new RevisionCompare(_fullpath, target, null); } @@ -2299,13 +2299,13 @@ public ContextMenu CreateContextMenuForRemoteBranch(Models.Branch branch) var compareWithWorktree = new MenuItem(); compareWithWorktree.Header = App.Text("BranchCM.CompareWithWorktree"); compareWithWorktree.Icon = App.CreateMenuIcon("Icons.Compare"); - compareWithWorktree.Click += (_, _) => + compareWithWorktree.Click += async (_, _) => { SelectedSearchedCommit = null; if (_histories != null) { - var target = new Commands.QuerySingleCommit(_fullpath, branch.Head).Result(); + var target = await new Commands.QuerySingleCommit(_fullpath, branch.Head).ResultAsync(); _histories.AutoSelectedCommit = null; _histories.DetailContext = new RevisionCompare(_fullpath, target, null); } @@ -2631,11 +2631,11 @@ public ContextMenu CreateContextMenuForWorktree(Models.Worktree worktree) var unlock = new MenuItem(); unlock.Header = App.Text("Worktree.Unlock"); unlock.Icon = App.CreateMenuIcon("Icons.Unlock"); - unlock.Click += (_, ev) => + unlock.Click += async (_, ev) => { SetWatcherEnabled(false); var log = CreateLog("Unlock Worktree"); - var succ = new Commands.Worktree(_fullpath).Use(log).Unlock(worktree.FullPath); + var succ = await new Commands.Worktree(_fullpath).Use(log).UnlockAsync(worktree.FullPath); if (succ) worktree.IsLocked = false; log.Complete(); @@ -2649,11 +2649,11 @@ public ContextMenu CreateContextMenuForWorktree(Models.Worktree worktree) var loc = new MenuItem(); loc.Header = App.Text("Worktree.Lock"); loc.Icon = App.CreateMenuIcon("Icons.Lock"); - loc.Click += (_, ev) => + loc.Click += async (_, ev) => { SetWatcherEnabled(false); var log = CreateLog("Lock Worktree"); - var succ = new Commands.Worktree(_fullpath).Use(log).Lock(worktree.FullPath); + var succ = await new Commands.Worktree(_fullpath).Use(log).LockAsync(worktree.FullPath); if (succ) worktree.IsLocked = true; log.Complete(); @@ -2910,10 +2910,10 @@ private void CalcWorktreeFilesForSearching() _requestingWorktreeFiles = true; - Task.Run(() => + Task.Run(async () => { - _worktreeFiles = new Commands.QueryRevisionFileNames(_fullpath, "HEAD").Result(); - Dispatcher.UIThread.Invoke(() => + _worktreeFiles = await new Commands.QueryRevisionFileNames(_fullpath, "HEAD").ResultAsync(); + await Dispatcher.UIThread.InvokeAsync(() => { if (IsSearchingCommitsByFilePath() && _requestingWorktreeFiles) CalcMatchedFilesForSearching(); @@ -2945,7 +2945,7 @@ private void CalcMatchedFilesForSearching() MatchedFilesForSearching = matched; } - private void AutoFetchImpl(object sender) + private async void AutoFetchImpl(object sender) { try { @@ -2970,7 +2970,7 @@ private void AutoFetchImpl(object sender) Dispatcher.UIThread.Invoke(() => IsAutoFetching = true); foreach (var remote in remotes) - new Commands.Fetch(_fullpath, remote, false, false) { RaiseError = false }.Exec(); + await new Commands.Fetch(_fullpath, remote, false, false) { RaiseError = false }.ExecAsync(); _lastFetchTime = DateTime.Now; Dispatcher.UIThread.Invoke(() => IsAutoFetching = false); } diff --git a/src/ViewModels/RepositoryConfigure.cs b/src/ViewModels/RepositoryConfigure.cs index d69ff711c..1a6a21d88 100644 --- a/src/ViewModels/RepositoryConfigure.cs +++ b/src/ViewModels/RepositoryConfigure.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.Threading.Tasks; + using Avalonia.Collections; using CommunityToolkit.Mvvm.ComponentModel; @@ -316,18 +318,18 @@ public void MoveSelectedCustomActionDown() _repo.Settings.MoveCustomActionDown(_selectedCustomAction); } - public void Save() + public async Task SaveAsync() { - SetIfChanged("user.name", UserName, ""); - SetIfChanged("user.email", UserEmail, ""); - SetIfChanged("commit.gpgsign", GPGCommitSigningEnabled ? "true" : "false", "false"); - SetIfChanged("tag.gpgsign", GPGTagSigningEnabled ? "true" : "false", "false"); - SetIfChanged("user.signingkey", GPGUserSigningKey, ""); - SetIfChanged("http.proxy", HttpProxy, ""); - SetIfChanged("fetch.prune", EnablePruneOnFetch ? "true" : "false", "false"); + await SetIfChangedAsync("user.name", UserName, ""); + await SetIfChangedAsync("user.email", UserEmail, ""); + await SetIfChangedAsync("commit.gpgsign", GPGCommitSigningEnabled ? "true" : "false", "false"); + await SetIfChangedAsync("tag.gpgsign", GPGTagSigningEnabled ? "true" : "false", "false"); + await SetIfChangedAsync("user.signingkey", GPGUserSigningKey, ""); + await SetIfChangedAsync("http.proxy", HttpProxy, ""); + await SetIfChangedAsync("fetch.prune", EnablePruneOnFetch ? "true" : "false", "false"); } - private void SetIfChanged(string key, string value, string defValue) + private async Task SetIfChangedAsync(string key, string value, string defValue) { bool changed = false; if (_cached.TryGetValue(key, out var old)) @@ -341,7 +343,7 @@ private void SetIfChanged(string key, string value, string defValue) if (changed) { - new Commands.Config(_repo.FullPath).Set(key, value); + await new Commands.Config(_repo.FullPath).SetAsync(key, value); } } diff --git a/src/ViewModels/Reset.cs b/src/ViewModels/Reset.cs index d3377a999..784fd0602 100644 --- a/src/ViewModels/Reset.cs +++ b/src/ViewModels/Reset.cs @@ -28,7 +28,7 @@ public Reset(Repository repo, Models.Branch current, Models.Commit to) SelectedMode = Models.ResetMode.Supported[1]; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = $"Reset current branch to {To.SHA} ..."; @@ -36,13 +36,10 @@ public override Task Sure() var log = _repo.CreateLog($"Reset HEAD to '{To.SHA}'"); Use(log); - return Task.Run(() => - { - var succ = new Commands.Reset(_repo.FullPath, To.SHA, SelectedMode.Arg).Use(log).Exec(); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + var succ = await new Commands.Reset(_repo.FullPath, To.SHA, SelectedMode.Arg).Use(log).ExecAsync(); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private readonly Repository _repo = null; diff --git a/src/ViewModels/ResetWithoutCheckout.cs b/src/ViewModels/ResetWithoutCheckout.cs index 9ec3f6b32..0c9a5fd61 100644 --- a/src/ViewModels/ResetWithoutCheckout.cs +++ b/src/ViewModels/ResetWithoutCheckout.cs @@ -30,7 +30,7 @@ public ResetWithoutCheckout(Repository repo, Models.Branch target, Models.Commit To = to; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = $"Reset {Target.Name} to {_revision} ..."; @@ -38,13 +38,10 @@ public override Task Sure() var log = _repo.CreateLog($"Reset '{Target.Name}' to '{_revision}'"); Use(log); - return Task.Run(() => - { - var succ = Commands.Branch.Create(_repo.FullPath, Target.Name, _revision, true, log); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + var succ = await Commands.Branch.CreateAsync(_repo.FullPath, Target.Name, _revision, true, log); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private readonly Repository _repo = null; diff --git a/src/ViewModels/Revert.cs b/src/ViewModels/Revert.cs index bb07e2ff3..7665eef1f 100644 --- a/src/ViewModels/Revert.cs +++ b/src/ViewModels/Revert.cs @@ -22,7 +22,7 @@ public Revert(Repository repo, Models.Commit target) AutoCommit = true; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); _repo.ClearCommitMessage(); @@ -31,13 +31,10 @@ public override Task Sure() var log = _repo.CreateLog($"Revert '{Target.SHA}'"); Use(log); - return Task.Run(() => - { - new Commands.Revert(_repo.FullPath, Target.SHA, AutoCommit).Use(log).Exec(); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return true; - }); + await new Commands.Revert(_repo.FullPath, Target.SHA, AutoCommit).Use(log).ExecAsync(); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return true; } private readonly Repository _repo = null; diff --git a/src/ViewModels/RevisionCompare.cs b/src/ViewModels/RevisionCompare.cs index 0af66a309..9586a92c4 100644 --- a/src/ViewModels/RevisionCompare.cs +++ b/src/ViewModels/RevisionCompare.cs @@ -120,9 +120,9 @@ public void Swap() public void SaveAsPatch(string saveTo) { - Task.Run(() => + Task.Run(async () => { - var succ = Commands.SaveChangesAsPatch.ProcessRevisionCompareChanges(_repo, _changes, GetSHA(_startPoint), GetSHA(_endPoint), saveTo); + var succ = await Commands.SaveChangesAsPatch.ProcessRevisionCompareChangesAsync(_repo, _changes, GetSHA(_startPoint), GetSHA(_endPoint), saveTo); if (succ) App.SendNotification(_repo, App.Text("SaveAsPatchSuccess")); }); @@ -150,7 +150,7 @@ public ContextMenu CreateChangeContextMenu() var toolType = Preferences.Instance.ExternalMergeToolType; var toolPath = Preferences.Instance.ExternalMergeToolPath; - Task.Run(() => Commands.MergeTool.OpenForDiff(_repo, toolType, toolPath, opt)); + Task.Run(() => Commands.MergeTool.OpenForDiffAsync(_repo, toolType, toolPath, opt)); ev.Handled = true; }; menu.Items.Add(diffWithMerger); diff --git a/src/ViewModels/Reword.cs b/src/ViewModels/Reword.cs index 8517c1bff..6a9d36887 100644 --- a/src/ViewModels/Reword.cs +++ b/src/ViewModels/Reword.cs @@ -26,10 +26,10 @@ public Reword(Repository repo, Models.Commit head) Head = head; } - public override Task Sure() + public override async Task Sure() { if (string.Compare(_message, _oldMessage, StringComparison.Ordinal) == 0) - return null; + return true; _repo.SetWatcherEnabled(false); ProgressDescription = "Editing head commit message ..."; @@ -38,14 +38,11 @@ public override Task Sure() Use(log); var signOff = _repo.Settings.EnableSignOffForCommit; - return Task.Run(() => - { - // For reword (only changes the commit message), disable `--reset-author` - var succ = new Commands.Commit(_repo.FullPath, _message, signOff, true, false).Use(log).Run(); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + // For reword (only changes the commit message), disable `--reset-author` + var succ = await new Commands.Commit(_repo.FullPath, _message, signOff, true, false).Use(log).RunAsync(); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private readonly Repository _repo; diff --git a/src/ViewModels/ScanRepositories.cs b/src/ViewModels/ScanRepositories.cs index 6df2843ba..2f5614821 100644 --- a/src/ViewModels/ScanRepositories.cs +++ b/src/ViewModels/ScanRepositories.cs @@ -40,56 +40,53 @@ public ScanRepositories() GetManagedRepositories(Preferences.Instance.RepositoryNodes, _managed); } - public override Task Sure() + public override async Task Sure() { ProgressDescription = $"Scan repositories under '{_selected.Path}' ..."; - return Task.Run(() => + var watch = new Stopwatch(); + watch.Start(); + + var rootDir = new DirectoryInfo(_selected.Path); + var found = new List(); + GetUnmanagedRepositories(rootDir, found, new EnumerationOptions() { - var watch = new Stopwatch(); - watch.Start(); + AttributesToSkip = FileAttributes.Hidden | FileAttributes.System, + IgnoreInaccessible = true, + }); - var rootDir = new DirectoryInfo(_selected.Path); - var found = new List(); - GetUnmanagedRepositories(rootDir, found, new EnumerationOptions() - { - AttributesToSkip = FileAttributes.Hidden | FileAttributes.System, - IgnoreInaccessible = true, - }); + // Make sure this task takes at least 0.5s to avoid that the popup panel do not disappear very quickly. + var remain = 500 - (int)watch.Elapsed.TotalMilliseconds; + watch.Stop(); + if (remain > 0) + Task.Delay(remain).Wait(); - // Make sure this task takes at least 0.5s to avoid that the popup panel do not disappear very quickly. - var remain = 500 - (int)watch.Elapsed.TotalMilliseconds; - watch.Stop(); - if (remain > 0) - Task.Delay(remain).Wait(); + await Dispatcher.UIThread.InvokeAsync(() => + { + var normalizedRoot = rootDir.FullName.Replace('\\', '/').TrimEnd('/'); - Dispatcher.UIThread.Invoke(() => + foreach (var f in found) { - var normalizedRoot = rootDir.FullName.Replace('\\', '/').TrimEnd('/'); - - foreach (var f in found) + var parent = new DirectoryInfo(f).Parent!.FullName.Replace('\\', '/').TrimEnd('/'); + if (parent.Equals(normalizedRoot, StringComparison.Ordinal)) { - var parent = new DirectoryInfo(f).Parent!.FullName.Replace('\\', '/').TrimEnd('/'); - if (parent.Equals(normalizedRoot, StringComparison.Ordinal)) - { - Preferences.Instance.FindOrAddNodeByRepositoryPath(f, null, false, false); - } - else if (parent.StartsWith(normalizedRoot, StringComparison.Ordinal)) - { - var relative = parent.Substring(normalizedRoot.Length).TrimStart('/'); - var group = FindOrCreateGroupRecursive(Preferences.Instance.RepositoryNodes, relative); - Preferences.Instance.FindOrAddNodeByRepositoryPath(f, group, false, false); - } + Preferences.Instance.FindOrAddNodeByRepositoryPath(f, null, false, false); } + else if (parent.StartsWith(normalizedRoot, StringComparison.Ordinal)) + { + var relative = parent.Substring(normalizedRoot.Length).TrimStart('/'); + var group = FindOrCreateGroupRecursive(Preferences.Instance.RepositoryNodes, relative); + Preferences.Instance.FindOrAddNodeByRepositoryPath(f, group, false, false); + } + } - Preferences.Instance.AutoRemoveInvalidNode(); - Preferences.Instance.Save(); - - Welcome.Instance.Refresh(); - }); + Preferences.Instance.AutoRemoveInvalidNode(); + Preferences.Instance.Save(); - return true; + Welcome.Instance.Refresh(); }); + + return true; } private void GetManagedRepositories(List group, HashSet repos) diff --git a/src/ViewModels/SetUpstream.cs b/src/ViewModels/SetUpstream.cs index a51586e6a..44812d8fe 100644 --- a/src/ViewModels/SetUpstream.cs +++ b/src/ViewModels/SetUpstream.cs @@ -50,26 +50,23 @@ public SetUpstream(Repository repo, Models.Branch local, List rem } } - public override Task Sure() + public override async Task Sure() { ProgressDescription = "Setting upstream..."; var upstream = (_unset || SelectedRemoteBranch == null) ? string.Empty : SelectedRemoteBranch.FullName; if (upstream == Local.Upstream) - return null; + return true; var log = _repo.CreateLog("Set Upstream"); Use(log); - return Task.Run(() => - { - var succ = Commands.Branch.SetUpstream(_repo.FullPath, Local.Name, upstream.Replace("refs/remotes/", ""), log); - if (succ) - _repo.RefreshBranches(); + var succ = await Commands.Branch.SetUpstreamAsync(_repo.FullPath, Local.Name, upstream.Replace("refs/remotes/", ""), log); + if (succ) + _repo.RefreshBranches(); - log.Complete(); - return true; - }); + log.Complete(); + return true; } private readonly Repository _repo; diff --git a/src/ViewModels/Squash.cs b/src/ViewModels/Squash.cs index 9574beb06..e97364058 100644 --- a/src/ViewModels/Squash.cs +++ b/src/ViewModels/Squash.cs @@ -24,7 +24,7 @@ public Squash(Repository repo, Models.Commit target, string shaToGetPreferMessag Target = target; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Squashing ..."; @@ -32,36 +32,33 @@ public override Task Sure() var log = _repo.CreateLog("Squash"); Use(log); - return Task.Run(() => - { - var signOff = _repo.Settings.EnableSignOffForCommit; - var autoStashed = false; - bool succ; + var signOff = _repo.Settings.EnableSignOffForCommit; + var autoStashed = false; + bool succ; - if (_repo.LocalChangesCount > 0) + if (_repo.LocalChangesCount > 0) + { + succ = await new Commands.Stash(_repo.FullPath).Use(log).PushAsync("SQUASH_AUTO_STASH"); + if (!succ) { - succ = new Commands.Stash(_repo.FullPath).Use(log).Push("SQUASH_AUTO_STASH"); - if (!succ) - { - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return false; - } - - autoStashed = true; + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return false; } - succ = new Commands.Reset(_repo.FullPath, Target.SHA, "--soft").Use(log).Exec(); - if (succ) - succ = new Commands.Commit(_repo.FullPath, _message, signOff, true, false).Use(log).Run(); + autoStashed = true; + } + + succ = await new Commands.Reset(_repo.FullPath, Target.SHA, "--soft").Use(log).ExecAsync(); + if (succ) + succ = await new Commands.Commit(_repo.FullPath, _message, signOff, true, false).Use(log).RunAsync(); - if (succ && autoStashed) - new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}"); + if (succ && autoStashed) + await new Commands.Stash(_repo.FullPath).Use(log).PopAsync("stash@{0}"); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return succ; - }); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return succ; } private readonly Repository _repo; diff --git a/src/ViewModels/StashChanges.cs b/src/ViewModels/StashChanges.cs index 0fb243f53..ceede29c5 100644 --- a/src/ViewModels/StashChanges.cs +++ b/src/ViewModels/StashChanges.cs @@ -50,7 +50,7 @@ public StashChanges(Repository repo, List changes, bool hasSelect HasSelectedFiles = hasSelectedFiles; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); ProgressDescription = "Stash changes ..."; @@ -58,57 +58,54 @@ public override Task Sure() var log = _repo.CreateLog("Stash Local Changes"); Use(log); - return Task.Run(() => - { - var mode = (DealWithChangesAfterStashing)ChangesAfterStashing; - var keepIndex = mode == DealWithChangesAfterStashing.KeepIndex; - bool succ; + var mode = (DealWithChangesAfterStashing)ChangesAfterStashing; + var keepIndex = mode == DealWithChangesAfterStashing.KeepIndex; + bool succ; - if (!HasSelectedFiles) + if (!HasSelectedFiles) + { + if (OnlyStaged) { - if (OnlyStaged) + if (Native.OS.GitVersion >= Models.GitVersions.STASH_PUSH_ONLY_STAGED) { - if (Native.OS.GitVersion >= Models.GitVersions.STASH_PUSH_ONLY_STAGED) - { - succ = new Commands.Stash(_repo.FullPath).Use(log).PushOnlyStaged(Message, keepIndex); - } - else - { - var staged = new List(); - foreach (var c in _changes) - { - if (c.Index != Models.ChangeState.None && c.Index != Models.ChangeState.Untracked) - staged.Add(c); - } - - succ = StashWithChanges(staged, keepIndex, log); - } + succ = await new Commands.Stash(_repo.FullPath).Use(log).PushOnlyStagedAsync(Message, keepIndex); } else { - succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, IncludeUntracked, keepIndex); + var staged = new List(); + foreach (var c in _changes) + { + if (c.Index != Models.ChangeState.None && c.Index != Models.ChangeState.Untracked) + staged.Add(c); + } + + succ = await StashWithChangesAsync(staged, keepIndex, log); } } else { - succ = StashWithChanges(_changes, keepIndex, log); + succ = await new Commands.Stash(_repo.FullPath).Use(log).PushAsync(Message, IncludeUntracked, keepIndex); } + } + else + { + succ = await StashWithChangesAsync(_changes, keepIndex, log); + } - if (mode == DealWithChangesAfterStashing.KeepAll && succ) - succ = new Commands.Stash(_repo.FullPath).Use(log).Apply("stash@{0}", true); + if (mode == DealWithChangesAfterStashing.KeepAll && succ) + succ = await new Commands.Stash(_repo.FullPath).Use(log).ApplyAsync("stash@{0}", true); - log.Complete(); - CallUIThread(() => - { - _repo.MarkWorkingCopyDirtyManually(); - _repo.SetWatcherEnabled(true); - }); - - return succ; + log.Complete(); + await CallUIThreadAsync(() => + { + _repo.MarkWorkingCopyDirtyManually(); + _repo.SetWatcherEnabled(true); }); + + return succ; } - private bool StashWithChanges(List changes, bool keepIndex, CommandLog log) + private async Task StashWithChangesAsync(List changes, bool keepIndex, CommandLog log) { if (changes.Count == 0) return true; @@ -121,8 +118,8 @@ private bool StashWithChanges(List changes, bool keepIndex, Comma paths.Add(c.Path); var pathSpecFile = Path.GetTempFileName(); - File.WriteAllLines(pathSpecFile, paths); - succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, pathSpecFile, keepIndex); + await File.WriteAllLinesAsync(pathSpecFile, paths); + succ = await new Commands.Stash(_repo.FullPath).Use(log).PushAsync(Message, pathSpecFile, keepIndex); File.Delete(pathSpecFile); } else @@ -131,7 +128,7 @@ private bool StashWithChanges(List changes, bool keepIndex, Comma { var count = Math.Min(32, changes.Count - i); var step = changes.GetRange(i, count); - succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, step, keepIndex); + succ = await new Commands.Stash(_repo.FullPath).Use(log).PushAsync(Message, step, keepIndex); if (!succ) break; } diff --git a/src/ViewModels/StashesPage.cs b/src/ViewModels/StashesPage.cs index 431f61e63..f5f680e1d 100644 --- a/src/ViewModels/StashesPage.cs +++ b/src/ViewModels/StashesPage.cs @@ -57,14 +57,14 @@ public Models.Stash SelectedStash } else { - Task.Run(() => + Task.Run(async () => { - var changes = new Commands.CompareRevisions(_repo.FullPath, $"{value.SHA}^", value.SHA).Result(); + var changes = await new Commands.CompareRevisions(_repo.FullPath, $"{value.SHA}^", value.SHA).ResultAsync(); var untracked = new List(); if (value.Parents.Count == 3) { - untracked = new Commands.CompareRevisions(_repo.FullPath, Models.Commit.EmptyTreeSHA1, value.Parents[2]).Result(); + untracked = await new Commands.CompareRevisions(_repo.FullPath, Models.Commit.EmptyTreeSHA1, value.Parents[2]).ResultAsync(); var needSort = changes.Count > 0 && untracked.Count > 0; foreach (var c in untracked) @@ -74,7 +74,7 @@ public Models.Stash SelectedStash changes.Sort((l, r) => Models.NumericSort.Compare(l.Path, r.Path)); } - Dispatcher.UIThread.Invoke(() => + await Dispatcher.UIThread.InvokeAsync(() => { _untracked = untracked; Changes = changes; @@ -188,7 +188,7 @@ public ContextMenu MakeContextMenu(Models.Stash stash) opts.Add(new Models.DiffOption(_selectedStash.Parents[0], _selectedStash.SHA, c)); } - var succ = await Task.Run(() => Commands.SaveChangesAsPatch.ProcessStashChanges(_repo.FullPath, opts, storageFile.Path.LocalPath)); + var succ = await Commands.SaveChangesAsPatch.ProcessStashChangesAsync(_repo.FullPath, opts, storageFile.Path.LocalPath); if (succ) App.SendNotification(_repo.FullPath, App.Text("SaveAsPatchSuccess")); } @@ -229,7 +229,7 @@ public ContextMenu MakeContextMenuForChange(Models.Change change) var toolPath = Preferences.Instance.ExternalMergeToolPath; var opt = new Models.DiffOption($"{_selectedStash.SHA}^", _selectedStash.SHA, change); - Task.Run(() => Commands.MergeTool.OpenForDiff(_repo.FullPath, toolType, toolPath, opt)); + Task.Run(() => Commands.MergeTool.OpenForDiffAsync(_repo.FullPath, toolType, toolPath, opt)); ev.Handled = true; }; @@ -251,23 +251,20 @@ public ContextMenu MakeContextMenuForChange(Models.Change change) { var log = _repo.CreateLog($"Reset File to '{_selectedStash.SHA}'"); - await Task.Run(() => + if (_untracked.Contains(change)) { - if (_untracked.Contains(change)) - { - Commands.SaveRevisionFile.Run(_repo.FullPath, _selectedStash.Parents[2], change.Path, fullPath); - } - else if (change.Index == Models.ChangeState.Added) - { - Commands.SaveRevisionFile.Run(_repo.FullPath, _selectedStash.SHA, change.Path, fullPath); - } - else - { - new Commands.Checkout(_repo.FullPath) - .Use(log) - .FileWithRevision(change.Path, $"{_selectedStash.SHA}"); - } - }); + await Commands.SaveRevisionFile.RunAsync(_repo.FullPath, _selectedStash.Parents[2], change.Path, fullPath); + } + else if (change.Index == Models.ChangeState.Added) + { + await Commands.SaveRevisionFile.RunAsync(_repo.FullPath, _selectedStash.SHA, change.Path, fullPath); + } + else + { + await new Commands.Checkout(_repo.FullPath) + .Use(log) + .FileWithRevisionAsync(change.Path, $"{_selectedStash.SHA}"); + } log.Complete(); ev.Handled = true; diff --git a/src/ViewModels/Statistics.cs b/src/ViewModels/Statistics.cs index 3a87607ec..e630a763f 100644 --- a/src/ViewModels/Statistics.cs +++ b/src/ViewModels/Statistics.cs @@ -56,10 +56,10 @@ public IBrush SampleBrush public Statistics(string repo) { - Task.Run(() => + Task.Run(async () => { - var result = new Commands.Statistics(repo, Preferences.Instance.MaxHistoryCommits).Result(); - Dispatcher.UIThread.Invoke(() => + var result = await new Commands.Statistics(repo, Preferences.Instance.MaxHistoryCommits).ResultAsync(); + await Dispatcher.UIThread.InvokeAsync(() => { _data = result; RefreshReport(); diff --git a/src/ViewModels/UpdateSubmodules.cs b/src/ViewModels/UpdateSubmodules.cs index df2d55657..7b08f1116 100644 --- a/src/ViewModels/UpdateSubmodules.cs +++ b/src/ViewModels/UpdateSubmodules.cs @@ -50,7 +50,7 @@ public UpdateSubmodules(Repository repo) SelectedSubmodule = Submodules.Count > 0 ? Submodules[0] : string.Empty; } - public override Task Sure() + public override async Task Sure() { _repo.SetWatcherEnabled(false); @@ -63,16 +63,13 @@ public override Task Sure() var log = _repo.CreateLog("Update Submodule"); Use(log); - return Task.Run(() => - { - new Commands.Submodule(_repo.FullPath) - .Use(log) - .Update(targets, EnableInit, EnableRecursive, EnableRemote); + await new Commands.Submodule(_repo.FullPath) + .Use(log) + .UpdateAsync(targets, EnableInit, EnableRecursive, EnableRemote); - log.Complete(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); - return true; - }); + log.Complete(); + await CallUIThreadAsync(() => _repo.SetWatcherEnabled(true)); + return true; } private readonly Repository _repo = null; diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index b53d0d2f6..408e64fd3 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -410,7 +410,7 @@ public async void UseTheirs(List changes) if (files.Count > 0) { - var succ = await Task.Run(() => new Commands.Checkout(_repo.FullPath).Use(log).UseTheirs(files)); + var succ = await new Commands.Checkout(_repo.FullPath).Use(log).UseTheirsAsync(files); if (succ) needStage.AddRange(files); } @@ -419,7 +419,7 @@ public async void UseTheirs(List changes) { var pathSpecFile = Path.GetTempFileName(); await File.WriteAllLinesAsync(pathSpecFile, needStage); - await Task.Run(() => new Commands.Add(_repo.FullPath, pathSpecFile).Use(log).Exec()); + await new Commands.Add(_repo.FullPath, pathSpecFile).Use(log).ExecAsync(); File.Delete(pathSpecFile); } @@ -459,7 +459,7 @@ public async void UseMine(List changes) if (files.Count > 0) { - var succ = await Task.Run(() => new Commands.Checkout(_repo.FullPath).Use(log).UseMine(files)); + var succ = await new Commands.Checkout(_repo.FullPath).Use(log).UseMineAsync(files); if (succ) needStage.AddRange(files); } @@ -468,7 +468,7 @@ public async void UseMine(List changes) { var pathSpecFile = Path.GetTempFileName(); await File.WriteAllLinesAsync(pathSpecFile, needStage); - await Task.Run(() => new Commands.Add(_repo.FullPath, pathSpecFile).Use(log).Exec()); + await new Commands.Add(_repo.FullPath, pathSpecFile).Use(log).ExecAsync(); File.Delete(pathSpecFile); } @@ -482,7 +482,7 @@ public async void UseExternalMergeTool(Models.Change change) var toolType = Preferences.Instance.ExternalMergeToolType; var toolPath = Preferences.Instance.ExternalMergeToolPath; var file = change?.Path; // NOTE: With no arg, mergetool runs on every file with merge conflicts! - await Task.Run(() => Commands.MergeTool.OpenForMerge(_repo.FullPath, toolType, toolPath, file)); + await Commands.MergeTool.OpenForMergeAsync(_repo.FullPath, toolType, toolPath, file); } public void ContinueMerge() @@ -492,14 +492,14 @@ public void ContinueMerge() if (_inProgressContext != null) { _repo.SetWatcherEnabled(false); - Task.Run(() => + Task.Run(async () => { var mergeMsgFile = Path.Combine(_repo.GitDir, "MERGE_MSG"); if (File.Exists(mergeMsgFile) && !string.IsNullOrWhiteSpace(_commitMessage)) - File.WriteAllText(mergeMsgFile, _commitMessage); + await File.WriteAllTextAsync(mergeMsgFile, _commitMessage); - var succ = _inProgressContext.Continue(); - Dispatcher.UIThread.Invoke(() => + var succ = await _inProgressContext.ContinueAsync(); + await Dispatcher.UIThread.InvokeAsync(() => { if (succ) CommitMessage = string.Empty; @@ -523,10 +523,10 @@ public void SkipMerge() if (_inProgressContext != null) { _repo.SetWatcherEnabled(false); - Task.Run(() => + Task.Run(async () => { - var succ = _inProgressContext.Skip(); - Dispatcher.UIThread.Invoke(() => + var succ = await _inProgressContext.SkipAsync(); + await Dispatcher.UIThread.InvokeAsync(() => { if (succ) CommitMessage = string.Empty; @@ -550,10 +550,10 @@ public void AbortMerge() if (_inProgressContext != null) { _repo.SetWatcherEnabled(false); - Task.Run(() => + Task.Run(async () => { - var succ = _inProgressContext.Abort(); - Dispatcher.UIThread.Invoke(() => + var succ = await _inProgressContext.AbortAsync(); + await Dispatcher.UIThread.InvokeAsync(() => { if (succ) CommitMessage = string.Empty; @@ -725,7 +725,7 @@ public ContextMenu CreateContextMenuForUnstagedChanges(string selectedSingleFold var storageFile = await storageProvider.SaveFilePickerAsync(options); if (storageFile != null) { - var succ = await Task.Run(() => Commands.SaveChangesAsPatch.ProcessLocalChanges(_repo.FullPath, _selectedUnstaged, true, storageFile.Path.LocalPath)); + var succ = await Commands.SaveChangesAsPatch.ProcessLocalChangesAsync(_repo.FullPath, _selectedUnstaged, true, storageFile.Path.LocalPath); if (succ) App.SendNotification(_repo.FullPath, App.Text("SaveAsPatchSuccess")); } @@ -737,10 +737,10 @@ public ContextMenu CreateContextMenuForUnstagedChanges(string selectedSingleFold assumeUnchanged.Header = App.Text("FileCM.AssumeUnchanged"); assumeUnchanged.Icon = App.CreateMenuIcon("Icons.File.Ignore"); assumeUnchanged.IsVisible = change.WorkTree != Models.ChangeState.Untracked; - assumeUnchanged.Click += (_, e) => + assumeUnchanged.Click += async (_, e) => { var log = _repo.CreateLog("Assume File Unchanged"); - new Commands.AssumeUnchanged(_repo.FullPath, change.Path, true).Use(log).Exec(); + await new Commands.AssumeUnchanged(_repo.FullPath, change.Path, true).Use(log).ExecAsync(); log.Complete(); e.Handled = true; }; @@ -850,7 +850,7 @@ public ContextMenu CreateContextMenuForUnstagedChanges(string selectedSingleFold lfsTrackThisFile.Click += async (_, e) => { var log = _repo.CreateLog("Track LFS"); - var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Track(filename, true, log)); + var succ = await new Commands.LFS(_repo.FullPath).TrackAsync(filename, true, log); if (succ) App.SendNotification(_repo.FullPath, $"Tracking file named {filename} successfully!"); @@ -866,7 +866,7 @@ public ContextMenu CreateContextMenuForUnstagedChanges(string selectedSingleFold lfsTrackByExtension.Click += async (_, e) => { var log = _repo.CreateLog("Track LFS"); - var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Track($"*{extension}", false, log)); + var succ = await new Commands.LFS(_repo.FullPath).TrackAsync($"*{extension}", false, log); if (succ) App.SendNotification(_repo.FullPath, $"Tracking all *{extension} files successfully!"); @@ -888,7 +888,7 @@ public ContextMenu CreateContextMenuForUnstagedChanges(string selectedSingleFold lfsLock.Click += async (_, e) => { var log = _repo.CreateLog("Lock LFS File"); - var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Lock(_repo.Remotes[0].Name, change.Path, log)); + var succ = await new Commands.LFS(_repo.FullPath).LockAsync(_repo.Remotes[0].Name, change.Path, log); if (succ) App.SendNotification(_repo.FullPath, $"Lock file \"{change.Path}\" successfully!"); @@ -906,7 +906,7 @@ public ContextMenu CreateContextMenuForUnstagedChanges(string selectedSingleFold lockRemote.Click += async (_, e) => { var log = _repo.CreateLog("Lock LFS File"); - var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Lock(remoteName, change.Path, log)); + var succ = await new Commands.LFS(_repo.FullPath).LockAsync(remoteName, change.Path, log); if (succ) App.SendNotification(_repo.FullPath, $"Lock file \"{change.Path}\" successfully!"); @@ -927,7 +927,7 @@ public ContextMenu CreateContextMenuForUnstagedChanges(string selectedSingleFold lfsUnlock.Click += async (_, e) => { var log = _repo.CreateLog("Unlock LFS File"); - var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Unlock(_repo.Remotes[0].Name, change.Path, false, log)); + var succ = await new Commands.LFS(_repo.FullPath).UnlockAsync(_repo.Remotes[0].Name, change.Path, false, log); if (succ) App.SendNotification(_repo.FullPath, $"Unlock file \"{change.Path}\" successfully!"); @@ -945,7 +945,7 @@ public ContextMenu CreateContextMenuForUnstagedChanges(string selectedSingleFold unlockRemote.Click += async (_, e) => { var log = _repo.CreateLog("Unlock LFS File"); - var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Unlock(remoteName, change.Path, false, log)); + var succ = await new Commands.LFS(_repo.FullPath).UnlockAsync(remoteName, change.Path, false, log); if (succ) App.SendNotification(_repo.FullPath, $"Unlock file \"{change.Path}\" successfully!"); @@ -1127,7 +1127,7 @@ public ContextMenu CreateContextMenuForUnstagedChanges(string selectedSingleFold var storageFile = await storageProvider.SaveFilePickerAsync(options); if (storageFile != null) { - var succ = await Task.Run(() => Commands.SaveChangesAsPatch.ProcessLocalChanges(_repo.FullPath, _selectedUnstaged, true, storageFile.Path.LocalPath)); + var succ = await Commands.SaveChangesAsPatch.ProcessLocalChangesAsync(_repo.FullPath, _selectedUnstaged, true, storageFile.Path.LocalPath); if (succ) App.SendNotification(_repo.FullPath, App.Text("SaveAsPatchSuccess")); } @@ -1302,7 +1302,7 @@ public ContextMenu CreateContextMenuForStagedChanges(string selectedSingleFolder var storageFile = await storageProvider.SaveFilePickerAsync(options); if (storageFile != null) { - var succ = await Task.Run(() => Commands.SaveChangesAsPatch.ProcessLocalChanges(_repo.FullPath, _selectedStaged, false, storageFile.Path.LocalPath)); + var succ = await Commands.SaveChangesAsPatch.ProcessLocalChangesAsync(_repo.FullPath, _selectedStaged, false, storageFile.Path.LocalPath); if (succ) App.SendNotification(_repo.FullPath, App.Text("SaveAsPatchSuccess")); } @@ -1334,7 +1334,7 @@ public ContextMenu CreateContextMenuForStagedChanges(string selectedSingleFolder lfsLock.Click += async (_, e) => { var log = _repo.CreateLog("Lock LFS File"); - var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Lock(_repo.Remotes[0].Name, change.Path, log)); + var succ = await new Commands.LFS(_repo.FullPath).LockAsync(_repo.Remotes[0].Name, change.Path, log); if (succ) App.SendNotification(_repo.FullPath, $"Lock file \"{change.Path}\" successfully!"); @@ -1352,7 +1352,7 @@ public ContextMenu CreateContextMenuForStagedChanges(string selectedSingleFolder lockRemote.Click += async (_, e) => { var log = _repo.CreateLog("Lock LFS File"); - var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Lock(remoteName, change.Path, log)); + var succ = await new Commands.LFS(_repo.FullPath).LockAsync(remoteName, change.Path, log); if (succ) App.SendNotification(_repo.FullPath, $"Lock file \"{change.Path}\" successfully!"); @@ -1373,7 +1373,7 @@ public ContextMenu CreateContextMenuForStagedChanges(string selectedSingleFolder lfsUnlock.Click += async (_, e) => { var log = _repo.CreateLog("Unlock LFS File"); - var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Unlock(_repo.Remotes[0].Name, change.Path, false, log)); + var succ = await new Commands.LFS(_repo.FullPath).UnlockAsync(_repo.Remotes[0].Name, change.Path, false, log); if (succ) App.SendNotification(_repo.FullPath, $"Unlock file \"{change.Path}\" successfully!"); @@ -1391,7 +1391,7 @@ public ContextMenu CreateContextMenuForStagedChanges(string selectedSingleFolder unlockRemote.Click += async (_, e) => { var log = _repo.CreateLog("Unlock LFS File"); - var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Unlock(remoteName, change.Path, false, log)); + var succ = await new Commands.LFS(_repo.FullPath).UnlockAsync(remoteName, change.Path, false, log); if (succ) App.SendNotification(_repo.FullPath, $"Unlock file \"{change.Path}\" successfully!"); @@ -1505,7 +1505,7 @@ public ContextMenu CreateContextMenuForStagedChanges(string selectedSingleFolder var storageFile = await storageProvider.SaveFilePickerAsync(options); if (storageFile != null) { - var succ = await Task.Run(() => Commands.SaveChangesAsPatch.ProcessLocalChanges(_repo.FullPath, _selectedStaged, false, storageFile.Path.LocalPath)); + var succ = await Commands.SaveChangesAsPatch.ProcessLocalChangesAsync(_repo.FullPath, _selectedStaged, false, storageFile.Path.LocalPath); if (succ) App.SendNotification(_repo.FullPath, App.Text("SaveAsPatchSuccess")); } @@ -1791,18 +1791,18 @@ private async void StageChanges(List changes, Models.Change next) var log = _repo.CreateLog("Stage"); if (count == _unstaged.Count) { - await Task.Run(() => new Commands.Add(_repo.FullPath, _repo.IncludeUntracked).Use(log).Exec()); + await new Commands.Add(_repo.FullPath, _repo.IncludeUntracked).Use(log).ExecAsync(); } else { var pathSpecFile = Path.GetTempFileName(); - using (var writer = new StreamWriter(pathSpecFile)) + await using (var writer = new StreamWriter(pathSpecFile)) { foreach (var c in changes) await writer.WriteLineAsync(c.Path); } - await Task.Run(() => new Commands.Add(_repo.FullPath, pathSpecFile).Use(log).Exec()); + await new Commands.Add(_repo.FullPath, pathSpecFile).Use(log).ExecAsync(); File.Delete(pathSpecFile); } log.Complete(); @@ -1828,12 +1828,12 @@ private async void UnstageChanges(List changes, Models.Change nex if (_useAmend) { log.AppendLine("$ git update-index --index-info "); - await Task.Run(() => new Commands.UnstageChangesForAmend(_repo.FullPath, changes).Exec()); + await new Commands.UnstageChangesForAmend(_repo.FullPath, changes).ExecAsync(); } else { var pathSpecFile = Path.GetTempFileName(); - using (var writer = new StreamWriter(pathSpecFile)) + await using (var writer = new StreamWriter(pathSpecFile)) { foreach (var c in changes) { @@ -1843,7 +1843,7 @@ private async void UnstageChanges(List changes, Models.Change nex } } - await Task.Run(() => new Commands.Restore(_repo.FullPath, pathSpecFile, true).Use(log).Exec()); + await new Commands.Restore(_repo.FullPath, pathSpecFile, true).Use(log).ExecAsync(); File.Delete(pathSpecFile); } log.Complete(); @@ -1906,14 +1906,14 @@ private void DoCommit(bool autoStage, bool autoPush, CommitCheckPassed checkPass var signOff = _repo.Settings.EnableSignOffForCommit; var log = _repo.CreateLog("Commit"); - Task.Run(() => + Task.Run(async () => { var succ = true; if (autoStage && _unstaged.Count > 0) - succ = new Commands.Add(_repo.FullPath, _repo.IncludeUntracked).Use(log).Exec(); + succ = await new Commands.Add(_repo.FullPath, _repo.IncludeUntracked).Use(log).ExecAsync(); if (succ) - succ = new Commands.Commit(_repo.FullPath, _commitMessage, signOff, _useAmend, _resetAuthor).Use(log).Run(); + succ = await new Commands.Commit(_repo.FullPath, _commitMessage, signOff, _useAmend, _resetAuthor).Use(log).RunAsync(); log.Complete(); diff --git a/src/Views/AssumeUnchangedManager.axaml.cs b/src/Views/AssumeUnchangedManager.axaml.cs index a0a5a3529..f673fb313 100644 --- a/src/Views/AssumeUnchangedManager.axaml.cs +++ b/src/Views/AssumeUnchangedManager.axaml.cs @@ -10,10 +10,10 @@ public AssumeUnchangedManager() InitializeComponent(); } - private void OnRemoveButtonClicked(object sender, RoutedEventArgs e) + private async void OnRemoveButtonClicked(object sender, RoutedEventArgs e) { if (DataContext is ViewModels.AssumeUnchangedManager vm && sender is Button button) - vm.Remove(button.DataContext as string); + await vm.RemoveAsync(button.DataContext as string); e.Handled = true; } diff --git a/src/Views/Preferences.axaml.cs b/src/Views/Preferences.axaml.cs index 9e2f6713a..f9f7404ad 100644 --- a/src/Views/Preferences.axaml.cs +++ b/src/Views/Preferences.axaml.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Avalonia; using Avalonia.Controls; @@ -153,13 +154,13 @@ public Preferences() InitializeComponent(); } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + protected override async void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); if (change.Property == GPGFormatProperty) { - var config = new Commands.Config(null).ListAll(); + var config = await new Commands.Config(null).ListAllAsync(); if (GPGFormat.Value == "openpgp" && config.TryGetValue("gpg.program", out var openpgp)) GPGExecutableFile = openpgp; else if (config.TryGetValue($"gpg.{GPGFormat.Value}.program", out var gpgProgram)) @@ -167,23 +168,23 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang } } - protected override void OnClosing(WindowClosingEventArgs e) + protected override async void OnClosing(WindowClosingEventArgs e) { base.OnClosing(e); if (Design.IsDesignMode) return; - var config = new Commands.Config(null).ListAll(); - SetIfChanged(config, "user.name", DefaultUser, ""); - SetIfChanged(config, "user.email", DefaultEmail, ""); - SetIfChanged(config, "user.signingkey", GPGUserKey, ""); - SetIfChanged(config, "core.autocrlf", CRLFMode?.Value, null); - SetIfChanged(config, "fetch.prune", EnablePruneOnFetch ? "true" : "false", "false"); - SetIfChanged(config, "commit.gpgsign", EnableGPGCommitSigning ? "true" : "false", "false"); - SetIfChanged(config, "tag.gpgsign", EnableGPGTagSigning ? "true" : "false", "false"); - SetIfChanged(config, "http.sslverify", EnableHTTPSSLVerify ? "" : "false", ""); - SetIfChanged(config, "gpg.format", GPGFormat.Value, "openpgp"); + var config = await new Commands.Config(null).ListAllAsync(); + await SetIfChangedAsync(config, "user.name", DefaultUser, ""); + await SetIfChangedAsync(config, "user.email", DefaultEmail, ""); + await SetIfChangedAsync(config, "user.signingkey", GPGUserKey, ""); + await SetIfChangedAsync(config, "core.autocrlf", CRLFMode?.Value, null); + await SetIfChangedAsync(config, "fetch.prune", EnablePruneOnFetch ? "true" : "false", "false"); + await SetIfChangedAsync(config, "commit.gpgsign", EnableGPGCommitSigning ? "true" : "false", "false"); + await SetIfChangedAsync(config, "tag.gpgsign", EnableGPGTagSigning ? "true" : "false", "false"); + await SetIfChangedAsync(config, "http.sslverify", EnableHTTPSSLVerify ? "" : "false", ""); + await SetIfChangedAsync(config, "gpg.format", GPGFormat.Value, "openpgp"); if (!GPGFormat.Value.Equals("ssh", StringComparison.Ordinal)) { @@ -200,7 +201,7 @@ protected override void OnClosing(WindowClosingEventArgs e) changed = true; if (changed) - new Commands.Config(null).Set($"gpg.{GPGFormat.Value}.program", GPGExecutableFile); + await new Commands.Config(null).SetAsync($"gpg.{GPGFormat.Value}.program", GPGExecutableFile); } ViewModels.Preferences.Instance.Save(); @@ -365,7 +366,7 @@ private async void SelectExternalMergeTool(object _, RoutedEventArgs e) e.Handled = true; } - private void SetIfChanged(Dictionary cached, string key, string value, string defValue) + private static async Task SetIfChangedAsync(Dictionary cached, string key, string value, string defValue) { bool changed = false; if (cached.TryGetValue(key, out var old)) @@ -374,7 +375,7 @@ private void SetIfChanged(Dictionary cached, string key, string changed = true; if (changed) - new Commands.Config(null).Set(key, value); + await new Commands.Config(null).SetAsync(key, value); } private void OnUseNativeWindowFrameChanged(object sender, RoutedEventArgs e) diff --git a/src/Views/RepositoryConfigure.axaml.cs b/src/Views/RepositoryConfigure.axaml.cs index 47895ba1b..bd509a701 100644 --- a/src/Views/RepositoryConfigure.axaml.cs +++ b/src/Views/RepositoryConfigure.axaml.cs @@ -20,12 +20,12 @@ protected override void OnKeyDown(KeyEventArgs e) Close(); } - protected override void OnClosing(WindowClosingEventArgs e) + protected override async void OnClosing(WindowClosingEventArgs e) { base.OnClosing(e); if (!Design.IsDesignMode && DataContext is ViewModels.RepositoryConfigure configure) - configure.Save(); + await configure.SaveAsync(); } private async void SelectExecutableForCustomAction(object sender, RoutedEventArgs e) diff --git a/src/Views/TextDiffView.axaml.cs b/src/Views/TextDiffView.axaml.cs index b84a6423e..ac31a9877 100644 --- a/src/Views/TextDiffView.axaml.cs +++ b/src/Views/TextDiffView.axaml.cs @@ -1823,7 +1823,7 @@ private void RefreshBlockNavigation() TryRaiseBlockNavigationChanged(); } - private void OnStageChunk(object _1, RoutedEventArgs _2) + private async void OnStageChunk(object _1, RoutedEventArgs _2) { var chunk = SelectedChunk; if (chunk == null) @@ -1853,7 +1853,7 @@ private void OnStageChunk(object _1, RoutedEventArgs _2) if (!selection.HasLeftChanges) { - new Commands.Add(repo.FullPath, change).Exec(); + await new Commands.Add(repo.FullPath, change).ExecAsync(); } else { @@ -1864,16 +1864,16 @@ private void OnStageChunk(object _1, RoutedEventArgs _2) } else if (chunk.Combined) { - var treeGuid = new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).Result(); + var treeGuid = await new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).ResultAsync(); diff.GeneratePatchFromSelection(change, treeGuid, selection, false, tmpFile); } else { - var treeGuid = new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).Result(); + var treeGuid = await new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).ResultAsync(); diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, false, chunk.IsOldSide, tmpFile); } - new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--cache --index").Exec(); + await new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--cache --index").ExecAsync(); File.Delete(tmpFile); } @@ -1881,7 +1881,7 @@ private void OnStageChunk(object _1, RoutedEventArgs _2) repo.SetWatcherEnabled(true); } - private void OnUnstageChunk(object _1, RoutedEventArgs _2) + private async void OnUnstageChunk(object _1, RoutedEventArgs _2) { var chunk = SelectedChunk; if (chunk == null) @@ -1912,13 +1912,13 @@ private void OnUnstageChunk(object _1, RoutedEventArgs _2) if (!selection.HasLeftChanges) { if (change.DataForAmend != null) - new Commands.UnstageChangesForAmend(repo.FullPath, [change]).Exec(); + await new Commands.UnstageChangesForAmend(repo.FullPath, [change]).ExecAsync(); else - new Commands.Restore(repo.FullPath, change).Exec(); + await new Commands.Restore(repo.FullPath, change).ExecAsync(); } else { - var treeGuid = new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).Result(); + var treeGuid = await new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).ResultAsync(); var tmpFile = Path.GetTempFileName(); if (change.Index == Models.ChangeState.Added) diff.GenerateNewPatchFromSelection(change, treeGuid, selection, true, tmpFile); @@ -1927,7 +1927,7 @@ private void OnUnstageChunk(object _1, RoutedEventArgs _2) else diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, chunk.IsOldSide, tmpFile); - new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--cache --index --reverse").Exec(); + await new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--cache --index --reverse").ExecAsync(); File.Delete(tmpFile); } @@ -1935,7 +1935,7 @@ private void OnUnstageChunk(object _1, RoutedEventArgs _2) repo.SetWatcherEnabled(true); } - private void OnDiscardChunk(object _1, RoutedEventArgs _2) + private async void OnDiscardChunk(object _1, RoutedEventArgs _2) { var chunk = SelectedChunk; if (chunk == null) @@ -1965,7 +1965,7 @@ private void OnDiscardChunk(object _1, RoutedEventArgs _2) if (!selection.HasLeftChanges) { - Commands.Discard.Changes(repo.FullPath, [change], null); + await Commands.Discard.ChangesAsync(repo.FullPath, [change], null); } else { @@ -1976,16 +1976,16 @@ private void OnDiscardChunk(object _1, RoutedEventArgs _2) } else if (chunk.Combined) { - var treeGuid = new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).Result(); + var treeGuid = await new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).ResultAsync(); diff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile); } else { - var treeGuid = new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).Result(); + var treeGuid = await new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).ResultAsync(); diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, chunk.IsOldSide, tmpFile); } - new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--reverse").Exec(); + await new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--reverse").ExecAsync(); File.Delete(tmpFile); }