From a8471bfda587c8da149e1f1dabc7b0f044c8cd06 Mon Sep 17 00:00:00 2001 From: Gadfly Date: Mon, 27 Oct 2025 11:14:32 +0800 Subject: [PATCH] fix: avoid crash when closing a repo which is deleted in file system related to #415 --- src/ViewModels/Repository.cs | 21 ++++++++---- src/Views/BranchCompare.axaml.cs | 15 ++++++--- src/Views/CommitDetail.axaml.cs | 45 +++++++++++++++++++------- src/Views/FileHistories.axaml.cs | 16 ++++++--- src/Views/RevisionCompare.axaml.cs | 28 ++++++++++++---- src/Views/StashesPage.axaml.cs | 13 ++++++-- src/Views/WorkingCopy.axaml.cs | 52 +++++++++++++++++++++++------- 7 files changed, 141 insertions(+), 49 deletions(-) diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index 6b520595d..5ca5ca82b 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -565,15 +565,22 @@ public void Close() SelectedView = null; // Do NOT modify. Used to remove exists widgets for GC.Collect Logs.Clear(); - if (!_isWorktree) + if (!_isWorktree && Directory.Exists(_gitCommonDir)) { - if (_workingCopy.InProgressContext != null && !string.IsNullOrEmpty(_workingCopy.CommitMessage)) - File.WriteAllText(Path.Combine(GitDir, "MERGE_MSG"), _workingCopy.CommitMessage); - else - _settings.LastCommitMessage = _workingCopy.CommitMessage; + try + { + if (_workingCopy.InProgressContext != null && !string.IsNullOrEmpty(_workingCopy.CommitMessage)) + File.WriteAllText(Path.Combine(GitDir, "MERGE_MSG"), _workingCopy.CommitMessage); + else + _settings.LastCommitMessage = _workingCopy.CommitMessage; - using var stream = File.Create(Path.Combine(_gitCommonDir, "sourcegit.settings")); - JsonSerializer.Serialize(stream, _settings, JsonCodeGen.Default.RepositorySettings); + using var stream = File.Create(Path.Combine(_gitCommonDir, "sourcegit.settings")); + JsonSerializer.Serialize(stream, _settings, JsonCodeGen.Default.RepositorySettings); + } + catch (Exception) + { + // Ignore + } } if (_cancellationRefreshBranches is { IsCancellationRequested: false }) diff --git a/src/Views/BranchCompare.axaml.cs b/src/Views/BranchCompare.axaml.cs index 08083ccca..f0815bfa3 100644 --- a/src/Views/BranchCompare.axaml.cs +++ b/src/Views/BranchCompare.axaml.cs @@ -37,11 +37,18 @@ private void OnChangeContextRequested(object sender, ContextRequestedEventArgs e options.DefaultExtension = ".patch"; options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }]; - var storageFile = await storageProvider.SaveFilePickerAsync(options); - if (storageFile != null) + try { - var saveTo = storageFile.Path.LocalPath; - await vm.SaveChangesAsPatchAsync(selected, saveTo); + var storageFile = await storageProvider.SaveFilePickerAsync(options); + if (storageFile != null) + { + var saveTo = storageFile.Path.LocalPath; + await vm.SaveChangesAsPatchAsync(selected, saveTo); + } + } + catch (Exception exception) + { + App.RaiseException(repo, $"Failed to save as patch: {exception.Message}"); } e.Handled = true; diff --git a/src/Views/CommitDetail.axaml.cs b/src/Views/CommitDetail.axaml.cs index ee570e64f..bfe7f3a47 100644 --- a/src/Views/CommitDetail.axaml.cs +++ b/src/Views/CommitDetail.axaml.cs @@ -56,11 +56,18 @@ public ContextMenu CreateChangeContextMenuByFolder(ViewModels.ChangeTreeNode nod options.DefaultExtension = ".patch"; options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }]; - var storageFile = await storageProvider.SaveFilePickerAsync(options); - if (storageFile != null) + try { - var saveTo = storageFile.Path.LocalPath; - await vm.SaveChangesAsPatchAsync(changes, saveTo); + var storageFile = await storageProvider.SaveFilePickerAsync(options); + if (storageFile != null) + { + var saveTo = storageFile.Path.LocalPath; + await vm.SaveChangesAsPatchAsync(changes, saveTo); + } + } + catch (Exception exception) + { + App.RaiseException(repo.FullPath, $"Failed to save as patch: {exception.Message}"); } e.Handled = true; @@ -117,11 +124,18 @@ public ContextMenu CreateMultipleChangesContextMenu(List changes) options.DefaultExtension = ".patch"; options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }]; - var storageFile = await storageProvider.SaveFilePickerAsync(options); - if (storageFile != null) + try + { + var storageFile = await storageProvider.SaveFilePickerAsync(options); + if (storageFile != null) + { + var saveTo = storageFile.Path.LocalPath; + await vm.SaveChangesAsPatchAsync(changes, saveTo); + } + } + catch (Exception exception) { - var saveTo = storageFile.Path.LocalPath; - await vm.SaveChangesAsPatchAsync(changes, saveTo); + App.RaiseException(repo.FullPath, $"Failed to save as patch: {exception.Message}"); } e.Handled = true; @@ -259,11 +273,18 @@ public ContextMenu CreateChangeContextMenu(Models.Change change) options.DefaultExtension = ".patch"; options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }]; - var storageFile = await storageProvider.SaveFilePickerAsync(options); - if (storageFile != null) + try + { + var storageFile = await storageProvider.SaveFilePickerAsync(options); + if (storageFile != null) + { + var saveTo = storageFile.Path.LocalPath; + await vm.SaveChangesAsPatchAsync([change], saveTo); + } + } + catch (Exception exception) { - var saveTo = storageFile.Path.LocalPath; - await vm.SaveChangesAsPatchAsync([change], saveTo); + App.RaiseException(repo.FullPath, $"Failed to save as patch: {exception.Message}"); } e.Handled = true; diff --git a/src/Views/FileHistories.axaml.cs b/src/Views/FileHistories.axaml.cs index 24c450861..793fd4114 100644 --- a/src/Views/FileHistories.axaml.cs +++ b/src/Views/FileHistories.axaml.cs @@ -51,11 +51,19 @@ private async void OnSaveAsPatch(object sender, RoutedEventArgs e) options.DefaultExtension = ".patch"; options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }]; - var storageFile = await StorageProvider.SaveFilePickerAsync(options); - if (storageFile != null) - await compare.SaveAsPatch(storageFile.Path.LocalPath); + try + { + var storageFile = await StorageProvider.SaveFilePickerAsync(options); + if (storageFile != null) + await compare.SaveAsPatch(storageFile.Path.LocalPath); + + NotifyDonePanel.IsVisible = true; + } + catch (Exception exception) + { + App.RaiseException(string.Empty, $"Failed to save as patch: {exception.Message}"); + } - NotifyDonePanel.IsVisible = true; e.Handled = true; } } diff --git a/src/Views/RevisionCompare.axaml.cs b/src/Views/RevisionCompare.axaml.cs index 3a84baca1..eb78d4c20 100644 --- a/src/Views/RevisionCompare.axaml.cs +++ b/src/Views/RevisionCompare.axaml.cs @@ -35,11 +35,18 @@ private void OnChangeContextRequested(object sender, ContextRequestedEventArgs e options.DefaultExtension = ".patch"; options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }]; - var storageFile = await storageProvider.SaveFilePickerAsync(options); - if (storageFile != null) + try { - var saveTo = storageFile.Path.LocalPath; - await vm.SaveChangesAsPatchAsync(selected, saveTo); + var storageFile = await storageProvider.SaveFilePickerAsync(options); + if (storageFile != null) + { + var saveTo = storageFile.Path.LocalPath; + await vm.SaveChangesAsPatchAsync(selected, saveTo); + } + } + catch (Exception exception) + { + App.RaiseException(string.Empty, $"Failed to save as patch: {exception.Message}"); } e.Handled = true; @@ -166,9 +173,16 @@ private async void OnSaveAsPatch(object sender, RoutedEventArgs e) options.DefaultExtension = ".patch"; options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }]; - var storageFile = await storage.SaveFilePickerAsync(options); - if (storageFile != null) - await vm.SaveChangesAsPatchAsync(null, storageFile.Path.LocalPath); + try + { + var storageFile = await storage.SaveFilePickerAsync(options); + if (storageFile != null) + await vm.SaveChangesAsPatchAsync(null, storageFile.Path.LocalPath); + } + catch (Exception exception) + { + App.RaiseException(string.Empty, $"Failed to save as patch: {exception.Message}"); + } e.Handled = true; } diff --git a/src/Views/StashesPage.axaml.cs b/src/Views/StashesPage.axaml.cs index ec19e27ae..acc091973 100644 --- a/src/Views/StashesPage.axaml.cs +++ b/src/Views/StashesPage.axaml.cs @@ -83,9 +83,16 @@ private void OnStashContextRequested(object sender, ContextRequestedEventArgs e) options.DefaultExtension = ".patch"; options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }]; - var storageFile = await storageProvider.SaveFilePickerAsync(options); - if (storageFile != null) - await vm.SaveStashAsPatchAsync(stash, storageFile.Path.LocalPath); + try + { + var storageFile = await storageProvider.SaveFilePickerAsync(options); + if (storageFile != null) + await vm.SaveStashAsPatchAsync(stash, storageFile.Path.LocalPath); + } + catch (Exception exception) + { + App.RaiseException(string.Empty, $"Failed to save as patch: {exception.Message}"); + } ev.Handled = true; }; diff --git a/src/Views/WorkingCopy.axaml.cs b/src/Views/WorkingCopy.axaml.cs index 8920800ac..df8c3d9f8 100644 --- a/src/Views/WorkingCopy.axaml.cs +++ b/src/Views/WorkingCopy.axaml.cs @@ -391,9 +391,16 @@ private ContextMenu CreateContextMenuForUnstagedChanges(ViewModels.WorkingCopy v options.DefaultExtension = ".patch"; options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }]; - var storageFile = await storageProvider.SaveFilePickerAsync(options); - if (storageFile != null) - await vm.SaveChangesToPatchAsync(selectedUnstaged, true, storageFile.Path.LocalPath); + try + { + var storageFile = await storageProvider.SaveFilePickerAsync(options); + if (storageFile != null) + await vm.SaveChangesToPatchAsync(selectedUnstaged, true, storageFile.Path.LocalPath); + } + catch (Exception exception) + { + App.RaiseException(repo.FullPath, $"Failed to save as patch: {exception.Message}"); + } e.Handled = true; }; @@ -788,9 +795,16 @@ private ContextMenu CreateContextMenuForUnstagedChanges(ViewModels.WorkingCopy v options.DefaultExtension = ".patch"; options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }]; - var storageFile = await storageProvider.SaveFilePickerAsync(options); - if (storageFile != null) - await vm.SaveChangesToPatchAsync(selectedUnstaged, true, storageFile.Path.LocalPath); + try + { + var storageFile = await storageProvider.SaveFilePickerAsync(options); + if (storageFile != null) + await vm.SaveChangesToPatchAsync(selectedUnstaged, true, storageFile.Path.LocalPath); + } + catch (Exception exception) + { + App.RaiseException(repo.FullPath, $"Failed to save as patch: {exception.Message}"); + } e.Handled = true; }; @@ -975,9 +989,16 @@ public ContextMenu CreateContextMenuForStagedChanges(ViewModels.WorkingCopy vm, options.DefaultExtension = ".patch"; options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }]; - var storageFile = await storageProvider.SaveFilePickerAsync(options); - if (storageFile != null) - await vm.SaveChangesToPatchAsync(selectedStaged, false, storageFile.Path.LocalPath); + try + { + var storageFile = await storageProvider.SaveFilePickerAsync(options); + if (storageFile != null) + await vm.SaveChangesToPatchAsync(selectedStaged, false, storageFile.Path.LocalPath); + } + catch (Exception exception) + { + App.RaiseException(repo.FullPath, $"Failed to save as patch: {exception.Message}"); + } e.Handled = true; }; @@ -1183,9 +1204,16 @@ public ContextMenu CreateContextMenuForStagedChanges(ViewModels.WorkingCopy vm, options.DefaultExtension = ".patch"; options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }]; - var storageFile = await storageProvider.SaveFilePickerAsync(options); - if (storageFile != null) - await vm.SaveChangesToPatchAsync(selectedStaged, false, storageFile.Path.LocalPath); + try + { + var storageFile = await storageProvider.SaveFilePickerAsync(options); + if (storageFile != null) + await vm.SaveChangesToPatchAsync(selectedStaged, false, storageFile.Path.LocalPath); + } + catch (Exception exception) + { + App.RaiseException(repo.FullPath, $"Failed to save as patch: {exception.Message}"); + } e.Handled = true; };