fix(ui): reparse-check repo-scan root folder and move scan off UI thread

RepoScanner.Scan() only guarded reparse points on subdirectories found
during recursion, so a configured import root that is itself a junction
walked straight through onto other drives. Apply the same
FileAttributes.ReparsePoint check to the root before scanning.

RepoImportModalViewModel.ScanAndAdd ran the full 5-level recursive scan
synchronously on the UI thread; pointing the folder picker at a broad
directory froze the app. Offload RepoScanner.Scan to Task.Run per folder
and apply results back on the UI thread.

Add a RepoScannerTests case that creates a real junction (mklink /J) at
the scan root and asserts Scan returns empty.
This commit is contained in:
mika kuns
2026-08-06 14:27:39 +02:00
parent bac8387069
commit b97f55bfb6
3 changed files with 37 additions and 4 deletions
@@ -117,6 +117,29 @@ public sealed class RepoScannerTests : IDisposable
Assert.Empty(result);
}
[Fact]
public void Scan_ReturnsEmptyWhenRootIsAReparsePoint()
{
var repo = MakeDir("real-repo");
Directory.CreateDirectory(Path.Combine(repo, ".git"));
var junction = Path.Combine(_root, "junction-to-real-repo");
var mklink = System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = $"/c mklink /J \"{junction}\" \"{repo}\"",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
})!;
mklink.WaitForExit();
Assert.True(Directory.Exists(junction), "Failed to create test junction: " + mklink.StandardError.ReadToEnd());
var result = RepoScanner.Scan(junction);
Assert.Empty(result);
}
[Fact]
#pragma warning disable CA1416 // ACL manipulation is Windows-only; this test targets the Windows dev/CI environment
public void Scan_ContinuesAfterUnreadableSubdirectory()