fix: running git command in UIThread via context menu entry blocks whole app (#1384)
Some checks failed
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Has been cancelled

Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
leo 2025-06-03 23:36:15 +08:00
parent d85f82e171
commit c2187edbe9
No known key found for this signature in database
4 changed files with 37 additions and 24 deletions

View file

@ -56,7 +56,7 @@ namespace SourceGit.ViewModels
{ {
get; get;
private set; private set;
} = []; }
public List<string> Children public List<string> Children
{ {
@ -426,12 +426,12 @@ namespace SourceGit.ViewModels
var openWith = new MenuItem(); var openWith = new MenuItem();
openWith.Header = App.Text("OpenWith"); openWith.Header = App.Text("OpenWith");
openWith.Icon = App.CreateMenuIcon("Icons.OpenWith"); openWith.Icon = App.CreateMenuIcon("Icons.OpenWith");
openWith.Click += (_, ev) => openWith.Click += async (_, ev) =>
{ {
var fileName = Path.GetFileNameWithoutExtension(fullPath) ?? ""; var fileName = Path.GetFileNameWithoutExtension(fullPath) ?? "";
var fileExt = Path.GetExtension(fullPath) ?? ""; var fileExt = Path.GetExtension(fullPath) ?? "";
var tmpFile = Path.Combine(Path.GetTempPath(), $"{fileName}~{_commit.SHA.Substring(0, 10)}{fileExt}"); var tmpFile = Path.Combine(Path.GetTempPath(), $"{fileName}~{_commit.SHA.Substring(0, 10)}{fileExt}");
Commands.SaveRevisionFile.Run(_repo.FullPath, _commit.SHA, file.Path, tmpFile); await Task.Run(() => Commands.SaveRevisionFile.Run(_repo.FullPath, _commit.SHA, file.Path, tmpFile));
Native.OS.OpenWithDefaultEditor(tmpFile); Native.OS.OpenWithDefaultEditor(tmpFile);
ev.Handled = true; ev.Handled = true;
}; };
@ -453,9 +453,9 @@ namespace SourceGit.ViewModels
if (selected.Count == 1) if (selected.Count == 1)
{ {
var folder = selected[0]; var folder = selected[0];
var folderPath = folder is { Path: { IsAbsoluteUri: true } path } ? path.LocalPath : folder?.Path.ToString(); var folderPath = folder is { Path: { IsAbsoluteUri: true } path } ? path.LocalPath : folder.Path.ToString();
var saveTo = Path.Combine(folderPath, Path.GetFileName(file.Path)); var saveTo = Path.Combine(folderPath, Path.GetFileName(file.Path)!);
Commands.SaveRevisionFile.Run(_repo.FullPath, _commit.SHA, file.Path, saveTo); await Task.Run(() => Commands.SaveRevisionFile.Run(_repo.FullPath, _commit.SHA, file.Path, saveTo));
} }
} }
catch (Exception e) catch (Exception e)

View file

@ -47,9 +47,9 @@ namespace SourceGit.ViewModels
RefreshViewContent(); RefreshViewContent();
} }
public void ResetToSelectedRevision() public Task<bool> ResetToSelectedRevision()
{ {
new Commands.Checkout(_repo.FullPath).FileWithRevision(_file, $"{_revision.SHA}"); return Task.Run(() => new Commands.Checkout(_repo.FullPath).FileWithRevision(_file, $"{_revision.SHA}"));
} }
private void RefreshViewContent() private void RefreshViewContent()
@ -84,7 +84,7 @@ namespace SourceGit.ViewModels
var stream = Commands.QueryFileContent.Run(_repo.FullPath, _revision.SHA, _file); var stream = Commands.QueryFileContent.Run(_repo.FullPath, _revision.SHA, _file);
var fileSize = stream.Length; var fileSize = stream.Length;
var bitmap = fileSize > 0 ? new Bitmap(stream) : null; var bitmap = fileSize > 0 ? new Bitmap(stream) : null;
var imageType = Path.GetExtension(_file).TrimStart('.').ToUpper(CultureInfo.CurrentCulture); var imageType = Path.GetExtension(_file)!.TrimStart('.').ToUpper(CultureInfo.CurrentCulture);
var image = new Models.RevisionImageFile() { Image = bitmap, FileSize = fileSize, ImageType = imageType }; var image = new Models.RevisionImageFile() { Image = bitmap, FileSize = fileSize, ImageType = imageType };
Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, image)); Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, image));
} }
@ -103,7 +103,7 @@ namespace SourceGit.ViewModels
var matchLFS = REG_LFS_FORMAT().Match(content); var matchLFS = REG_LFS_FORMAT().Match(content);
if (matchLFS.Success) if (matchLFS.Success)
{ {
var lfs = new Models.RevisionLFSObject() { Object = new Models.LFSObject() }; var lfs = new Models.RevisionLFSObject() { Object = new() };
lfs.Object.Oid = matchLFS.Groups[1].Value; lfs.Object.Oid = matchLFS.Groups[1].Value;
lfs.Object.Size = long.Parse(matchLFS.Groups[2].Value); lfs.Object.Size = long.Parse(matchLFS.Groups[2].Value);
Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, lfs)); Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, lfs));
@ -156,15 +156,12 @@ namespace SourceGit.ViewModels
[GeneratedRegex(@"^version https://git-lfs.github.com/spec/v\d+\r?\noid sha256:([0-9a-f]+)\r?\nsize (\d+)[\r\n]*$")] [GeneratedRegex(@"^version https://git-lfs.github.com/spec/v\d+\r?\noid sha256:([0-9a-f]+)\r?\nsize (\d+)[\r\n]*$")]
private static partial Regex REG_LFS_FORMAT(); private static partial Regex REG_LFS_FORMAT();
private static readonly HashSet<string> IMG_EXTS = new HashSet<string>() private static readonly HashSet<string> IMG_EXTS = [".ico", ".bmp", ".jpg", ".png", ".jpeg", ".webp"];
{
".ico", ".bmp", ".jpg", ".png", ".jpeg", ".webp"
};
private Repository _repo = null; private Repository _repo = null;
private string _file = null; private string _file = null;
private Models.Commit _revision = null; private Models.Commit _revision = null;
private bool _isDiffMode = true; private bool _isDiffMode = false;
private object _viewContent = null; private object _viewContent = null;
} }
@ -265,7 +262,6 @@ namespace SourceGit.ViewModels
public FileHistories(Repository repo, string file, string commit = null) public FileHistories(Repository repo, string file, string commit = null)
{ {
_repo = repo; _repo = repo;
_file = file;
Task.Run(() => Task.Run(() =>
{ {
@ -288,10 +284,10 @@ namespace SourceGit.ViewModels
switch (SelectedCommits.Count) switch (SelectedCommits.Count)
{ {
case 1: case 1:
ViewContent = new FileHistoriesSingleRevision(_repo, _file, SelectedCommits[0], _prevIsDiffMode); ViewContent = new FileHistoriesSingleRevision(_repo, file, SelectedCommits[0], _prevIsDiffMode);
break; break;
case 2: case 2:
ViewContent = new FileHistoriesCompareRevisions(_repo, _file, SelectedCommits[0], SelectedCommits[1]); ViewContent = new FileHistoriesCompareRevisions(_repo, file, SelectedCommits[0], SelectedCommits[1]);
break; break;
default: default:
ViewContent = SelectedCommits.Count; ViewContent = SelectedCommits.Count;
@ -317,11 +313,10 @@ namespace SourceGit.ViewModels
} }
private readonly Repository _repo = null; private readonly Repository _repo = null;
private readonly string _file = null;
private bool _isLoading = true; private bool _isLoading = true;
private bool _prevIsDiffMode = true; private bool _prevIsDiffMode = true;
private List<Models.Commit> _commits = null; private List<Models.Commit> _commits = null;
private Dictionary<string, string> _fullCommitMessages = new Dictionary<string, string>(); private Dictionary<string, string> _fullCommitMessages = new();
private object _viewContent = null; private object _viewContent = null;
} }
} }

View file

@ -234,10 +234,28 @@ namespace SourceGit.ViewModels
var resetToThisRevision = new MenuItem(); var resetToThisRevision = new MenuItem();
resetToThisRevision.Header = App.Text("ChangeCM.CheckoutThisRevision"); resetToThisRevision.Header = App.Text("ChangeCM.CheckoutThisRevision");
resetToThisRevision.Icon = App.CreateMenuIcon("Icons.File.Checkout"); resetToThisRevision.Icon = App.CreateMenuIcon("Icons.File.Checkout");
resetToThisRevision.Click += (_, ev) => resetToThisRevision.Click += async (_, ev) =>
{ {
var log = _repo.CreateLog($"Reset File to '{_selectedStash.SHA}'"); var log = _repo.CreateLog($"Reset File to '{_selectedStash.SHA}'");
new Commands.Checkout(_repo.FullPath).Use(log).FileWithRevision(change.Path, $"{_selectedStash.SHA}");
await Task.Run(() =>
{
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}");
}
});
log.Complete(); log.Complete();
ev.Handled = true; ev.Handled = true;
}; };

View file

@ -25,11 +25,11 @@ namespace SourceGit.Views
e.Handled = true; e.Handled = true;
} }
private void OnResetToSelectedRevision(object sender, RoutedEventArgs e) private async void OnResetToSelectedRevision(object sender, RoutedEventArgs e)
{ {
if (sender is Button { DataContext: ViewModels.FileHistoriesSingleRevision single }) if (sender is Button { DataContext: ViewModels.FileHistoriesSingleRevision single })
{ {
single.ResetToSelectedRevision(); await single.ResetToSelectedRevision();
NotifyDonePanel.IsVisible = true; NotifyDonePanel.IsVisible = true;
} }