Skip to content

Commit 9e1ed94

Browse files
committed
async locking around ide vs external disk file tree changes
1 parent cb35803 commit 9e1ed94

File tree

2 files changed

+22
-1
lines changed

2 files changed

+22
-1
lines changed

src/SharpIDE.Application/Features/FileWatching/IdeFileExternalChangeHandler.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Collections.Immutable;
22
using Ardalis.GuardClauses;
33
using Microsoft.Extensions.Logging;
4+
using NeoSmart.AsyncLock;
45
using SharpIDE.Application.Features.Events;
56
using SharpIDE.Application.Features.FileSystem;
67
using SharpIDE.Application.Features.SolutionDiscovery;
@@ -16,6 +17,7 @@ public class IdeFileExternalChangeHandler
1617
public SharpIdeSolutionModel SolutionModel { get; set; } = null!;
1718

1819
private SharpIdeRootFolder RootFolder => SolutionModel.RootFolder;
20+
public AsyncLock IdeChangeLock { get; } = new AsyncLock();
1921

2022
public IdeFileExternalChangeHandler(FileChangedService fileChangedService, SharpIdeRootFolderModificationService rootFolderModificationService, ILogger<IdeFileExternalChangeHandler> logger)
2123
{
@@ -34,13 +36,15 @@ public IdeFileExternalChangeHandler(FileChangedService fileChangedService, Sharp
3436

3537
private async Task OnFileRenamed(string oldFilePath, string newFilePath)
3638
{
39+
using var _ = await IdeChangeLock.LockAsync();
3740
var sharpIdeFile = RootFolder.AllFiles.GetValueOrDefault(oldFilePath);
3841
if (sharpIdeFile is null) return;
3942
await _rootFolderModificationService.RenameFile(sharpIdeFile, Path.GetFileName(newFilePath));
4043
}
4144

4245
private async Task OnFileDeleted(string filePath)
4346
{
47+
using var _ = await IdeChangeLock.LockAsync();
4448
var sharpIdeFile = RootFolder.AllFiles.GetValueOrDefault(filePath);
4549
if (sharpIdeFile is null) return;
4650
await _rootFolderModificationService.RemoveFile(sharpIdeFile);
@@ -49,6 +53,7 @@ private async Task OnFileDeleted(string filePath)
4953
// TODO: Test - this most likely only will ever be called on linux - windows and macos(?) does delete + create on rename of folders
5054
private async Task OnFolderRenamed(string oldFolderPath, string newFolderPath)
5155
{
56+
using var _ = await IdeChangeLock.LockAsync();
5257
var sharpIdeFolder = RootFolder.AllFolders.SingleOrDefault(f => f.Path == oldFolderPath);
5358
if (sharpIdeFolder is null)
5459
{
@@ -70,6 +75,7 @@ private async Task OnFolderRenamed(string oldFolderPath, string newFolderPath)
7075

7176
private async Task OnFolderDeleted(string folderPath)
7277
{
78+
using var _ = await IdeChangeLock.LockAsync();
7379
var sharpIdeFolder = RootFolder.AllFolders.SingleOrDefault(f => f.Path == folderPath);
7480
if (sharpIdeFolder is null)
7581
{
@@ -80,6 +86,7 @@ private async Task OnFolderDeleted(string folderPath)
8086

8187
private async Task OnFolderCreated(string folderPath)
8288
{
89+
using var _ = await IdeChangeLock.LockAsync();
8390
var sharpIdeFolder = RootFolder.AllFolders.SingleOrDefault(f => f.Path == folderPath);
8491
if (sharpIdeFolder is not null)
8592
{
@@ -99,6 +106,7 @@ private async Task OnFolderCreated(string folderPath)
99106

100107
private async Task OnFileCreated(string filePath)
101108
{
109+
using var _ = await IdeChangeLock.LockAsync();
102110
var sharpIdeFile = RootFolder.AllFiles.GetValueOrDefault(filePath);
103111
if (sharpIdeFile is not null)
104112
{
@@ -118,6 +126,7 @@ private async Task OnFileCreated(string filePath)
118126

119127
private async Task OnFileChanged(string filePath)
120128
{
129+
using var _ = await IdeChangeLock.LockAsync();
121130
var sharpIdeFile = RootFolder.AllFiles.GetValueOrDefault(filePath);
122131
if (sharpIdeFile is null) return;
123132
if (sharpIdeFile.SuppressDiskChangeEvents is true) return;
@@ -139,6 +148,7 @@ private async Task OnFileChanged(string filePath)
139148

140149
private async Task OnAnalyzerDllsChanged(ImmutableArray<string> analyzerDllPaths)
141150
{
151+
using var _ = await IdeChangeLock.LockAsync();
142152
await _fileChangedService.AnalyzerDllFilesChanged(analyzerDllPaths);
143153
}
144154
}

src/SharpIDE.Application/Features/FileWatching/IdeFileOperationsService.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,39 @@
44

55
namespace SharpIDE.Application.Features.FileWatching;
66

7-
public class IdeFileOperationsService(SharpIdeRootFolderModificationService rootFolderModificationService)
7+
public class IdeFileOperationsService(SharpIdeRootFolderModificationService rootFolderModificationService, IdeFileExternalChangeHandler ideFileExternalChangeHandler)
88
{
99
private readonly SharpIdeRootFolderModificationService _rootFolderModificationService = rootFolderModificationService;
10+
private readonly IdeFileExternalChangeHandler _ideFileExternalChangeHandler = ideFileExternalChangeHandler;
1011

1112
public async Task RenameDirectory(SharpIdeFolder folder, string newDirectoryName)
1213
{
1314
var parentPath = Path.GetDirectoryName(folder.Path)!;
1415
var newDirectoryPath = Path.Combine(parentPath, newDirectoryName);
16+
using var _ = await _ideFileExternalChangeHandler.IdeChangeLock.LockAsync();
1517
Directory.Move(folder.Path, newDirectoryPath);
1618
await _rootFolderModificationService.RenameDirectory(folder, newDirectoryName);
1719
}
1820

1921
public async Task CreateDirectory(SharpIdeFolder parentFolder, string newDirectoryName)
2022
{
2123
var newDirectoryPath = Path.Combine(parentFolder.ChildNodeBasePath, newDirectoryName);
24+
using var _ = await _ideFileExternalChangeHandler.IdeChangeLock.LockAsync();
2225
Directory.CreateDirectory(newDirectoryPath);
2326
await _rootFolderModificationService.AddDirectory(parentFolder, newDirectoryName);
2427
}
2528

2629
public async Task DeleteDirectory(SharpIdeFolder folder)
2730
{
31+
using var _ = await _ideFileExternalChangeHandler.IdeChangeLock.LockAsync();
2832
Directory.Delete(folder.Path, true);
2933
await _rootFolderModificationService.RemoveDirectory(folder);
3034
}
3135

3236
public async Task CopyDirectory(SharpIdeFolder destinationParentFolder, string sourceDirectoryPath, string newDirectoryName)
3337
{
3438
var newDirectoryPath = Path.Combine(destinationParentFolder.ChildNodeBasePath, newDirectoryName);
39+
using var _ = await _ideFileExternalChangeHandler.IdeChangeLock.LockAsync();
3540
CopyAll(new DirectoryInfo(sourceDirectoryPath), new DirectoryInfo(newDirectoryPath));
3641
await _rootFolderModificationService.AddDirectory(destinationParentFolder, newDirectoryName);
3742
return;
@@ -55,12 +60,14 @@ static void CopyAll(DirectoryInfo source, DirectoryInfo target)
5560
public async Task MoveDirectory(SharpIdeFolder destinationParentFolder, SharpIdeFolder folderToMove)
5661
{
5762
var newDirectoryPath = Path.Combine(destinationParentFolder.ChildNodeBasePath, folderToMove.Name.Value);
63+
using var _ = await _ideFileExternalChangeHandler.IdeChangeLock.LockAsync();
5864
Directory.Move(folderToMove.Path, newDirectoryPath);
5965
await _rootFolderModificationService.MoveDirectory(destinationParentFolder, folderToMove);
6066
}
6167

6268
public async Task DeleteFile(SharpIdeFile file)
6369
{
70+
using var _ = await _ideFileExternalChangeHandler.IdeChangeLock.LockAsync();
6471
File.Delete(file.Path);
6572
await _rootFolderModificationService.RemoveFile(file);
6673
}
@@ -72,6 +79,7 @@ public async Task<SharpIdeFile> CreateCsFile(SharpIdeFolder parentFolder, string
7279
var className = Path.GetFileNameWithoutExtension(newFileName);
7380
var @namespace = NewFileTemplates.ComputeNamespace(parentFolder);
7481
var fileText = NewFileTemplates.CsharpFile(className, @namespace, typeKeyword);
82+
using var _ = await _ideFileExternalChangeHandler.IdeChangeLock.LockAsync();
7583
await File.WriteAllTextAsync(newFilePath, fileText);
7684
var sharpIdeFile = await _rootFolderModificationService.CreateFile(parentFolder, newFilePath, newFileName, fileText);
7785
return sharpIdeFile;
@@ -82,6 +90,7 @@ public async Task<SharpIdeFile> CopyFile(SharpIdeFolder destinationParentFolder,
8290
var newFilePath = Path.Combine(destinationParentFolder.Path, newFileName);
8391
if (File.Exists(newFilePath)) throw new InvalidOperationException($"File {newFilePath} already exists.");
8492
var fileContents = await File.ReadAllTextAsync(sourceFilePath);
93+
using var _ = await _ideFileExternalChangeHandler.IdeChangeLock.LockAsync();
8594
File.Copy(sourceFilePath, newFilePath);
8695
var sharpIdeFile = await _rootFolderModificationService.CreateFile(destinationParentFolder, newFilePath, newFileName, fileContents);
8796
return sharpIdeFile;
@@ -92,6 +101,7 @@ public async Task<SharpIdeFile> RenameFile(SharpIdeFile file, string newFileName
92101
var parentPath = Path.GetDirectoryName(file.Path)!;
93102
var newFilePath = Path.Combine(parentPath, newFileName);
94103
if (File.Exists(newFilePath)) throw new InvalidOperationException($"File {newFilePath} already exists.");
104+
using var _ = await _ideFileExternalChangeHandler.IdeChangeLock.LockAsync();
95105
File.Move(file.Path, newFilePath);
96106
var sharpIdeFile = await _rootFolderModificationService.RenameFile(file, newFileName);
97107
return sharpIdeFile;
@@ -101,6 +111,7 @@ public async Task<SharpIdeFile> MoveFile(SharpIdeFolder destinationParentFolder,
101111
{
102112
var newFilePath = Path.Combine(destinationParentFolder.ChildNodeBasePath, fileToMove.Name.Value);
103113
if (File.Exists(newFilePath)) throw new InvalidOperationException($"File {newFilePath} already exists.");
114+
using var _ = await _ideFileExternalChangeHandler.IdeChangeLock.LockAsync();
104115
File.Move(fileToMove.Path, newFilePath);
105116
var sharpIdeFile = await _rootFolderModificationService.MoveFile(destinationParentFolder, fileToMove);
106117
return sharpIdeFile;

0 commit comments

Comments
 (0)