From f6a9ee76d594a32042a9b95461fad1221e47556a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Apr 2026 18:51:44 +0000 Subject: [PATCH 1/6] Add LockFile with TryAcquire and tests Agent-Logs-Url: https://github.com/Tyrrrz/PowerKit/sessions/72a664dd-2122-4767-ab00-e3b28dd0b458 Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com> --- PowerKit.Tests/LockFileTests.cs | 52 +++++++++++++++++++++++++++++++++ PowerKit/LockFile.cs | 39 +++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 PowerKit.Tests/LockFileTests.cs create mode 100644 PowerKit/LockFile.cs diff --git a/PowerKit.Tests/LockFileTests.cs b/PowerKit.Tests/LockFileTests.cs new file mode 100644 index 0000000..7c1dc5b --- /dev/null +++ b/PowerKit.Tests/LockFileTests.cs @@ -0,0 +1,52 @@ +using System.IO; +using FluentAssertions; +using PowerKit; +using Xunit; + +namespace PowerKit.Tests; + +public class LockFileTests +{ + [Fact] + public void TryAcquire_Test() + { + // Arrange + using var tempFile = TempFile.Create(); + + // Act + using var lockFile = LockFile.TryAcquire(tempFile.Path); + + // Assert + lockFile.Should().NotBeNull(); + File.Exists(tempFile.Path).Should().BeTrue(); + } + + [Fact] + public void TryAcquire_AlreadyLocked_Test() + { + // Arrange + using var tempFile = TempFile.Create(); + using var lockFile = LockFile.TryAcquire(tempFile.Path); + + // Act + using var lockFile2 = LockFile.TryAcquire(tempFile.Path); + + // Assert + lockFile2.Should().BeNull(); + } + + [Fact] + public void Dispose_Test() + { + // Arrange + using var tempFile = TempFile.Create(); + var lockFile = LockFile.TryAcquire(tempFile.Path); + + // Act + lockFile!.Dispose(); + + // Assert: lock can be reacquired after disposal + using var lockFile2 = LockFile.TryAcquire(tempFile.Path); + lockFile2.Should().NotBeNull(); + } +} diff --git a/PowerKit/LockFile.cs b/PowerKit/LockFile.cs new file mode 100644 index 0000000..9459e68 --- /dev/null +++ b/PowerKit/LockFile.cs @@ -0,0 +1,39 @@ +using System; +using System.IO; + +namespace PowerKit; + +/// +/// Represents a file-based lock that prevents concurrent access to a shared resource. +/// +internal partial class LockFile(FileStream fileStream) : IDisposable +{ + /// + public void Dispose() => fileStream.Dispose(); +} + +internal partial class LockFile +{ + /// + /// Tries to acquire a lock on the specified file path. + /// Returns if the lock could not be acquired. + /// + public static LockFile? TryAcquire(string filePath) + { + try + { + var fileStream = File.Open( + filePath, + FileMode.Create, + FileAccess.ReadWrite, + FileShare.None + ); + return new LockFile(fileStream); + } + // This is the most specific exception for "access denied" + catch (IOException) + { + return null; + } + } +} From 155b41ae99f1c3adaa8287c40d7c902af3039886 Mon Sep 17 00:00:00 2001 From: Oleksii Holub <1935960+Tyrrrz@users.noreply.github.com> Date: Tue, 14 Apr 2026 18:23:30 +0300 Subject: [PATCH 2/6] Update LockFileTests.cs --- PowerKit.Tests/LockFileTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PowerKit.Tests/LockFileTests.cs b/PowerKit.Tests/LockFileTests.cs index 7c1dc5b..49d4e75 100644 --- a/PowerKit.Tests/LockFileTests.cs +++ b/PowerKit.Tests/LockFileTests.cs @@ -43,7 +43,7 @@ public void Dispose_Test() var lockFile = LockFile.TryAcquire(tempFile.Path); // Act - lockFile!.Dispose(); + lockFile?.Dispose(); // Assert: lock can be reacquired after disposal using var lockFile2 = LockFile.TryAcquire(tempFile.Path); From dc9e4c53a865751ee16e17e90b8f2b8c9f3c0bff Mon Sep 17 00:00:00 2001 From: Oleksii Holub <1935960+Tyrrrz@users.noreply.github.com> Date: Tue, 14 Apr 2026 18:24:09 +0300 Subject: [PATCH 3/6] Update LockFile.cs --- PowerKit/LockFile.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/PowerKit/LockFile.cs b/PowerKit/LockFile.cs index 9459e68..5f97483 100644 --- a/PowerKit/LockFile.cs +++ b/PowerKit/LockFile.cs @@ -28,6 +28,7 @@ internal partial class LockFile FileAccess.ReadWrite, FileShare.None ); + return new LockFile(fileStream); } // This is the most specific exception for "access denied" From 2183aef6ca47d5d7e3ab20619fdb513d8dc026aa Mon Sep 17 00:00:00 2001 From: Oleksii Holub <1935960+Tyrrrz@users.noreply.github.com> Date: Tue, 14 Apr 2026 18:39:30 +0300 Subject: [PATCH 4/6] Update PowerKit/LockFile.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- PowerKit/LockFile.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PowerKit/LockFile.cs b/PowerKit/LockFile.cs index 5f97483..ced66ff 100644 --- a/PowerKit/LockFile.cs +++ b/PowerKit/LockFile.cs @@ -24,7 +24,7 @@ internal partial class LockFile { var fileStream = File.Open( filePath, - FileMode.Create, + FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None ); From 2a1c063370a3652f1a9ff5ad370ef760a4a7a34d Mon Sep 17 00:00:00 2001 From: Oleksii Holub <1935960+Tyrrrz@users.noreply.github.com> Date: Tue, 14 Apr 2026 18:40:13 +0300 Subject: [PATCH 5/6] Update PowerKit.Tests/LockFileTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- PowerKit.Tests/LockFileTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PowerKit.Tests/LockFileTests.cs b/PowerKit.Tests/LockFileTests.cs index 49d4e75..342a2e0 100644 --- a/PowerKit.Tests/LockFileTests.cs +++ b/PowerKit.Tests/LockFileTests.cs @@ -41,9 +41,10 @@ public void Dispose_Test() // Arrange using var tempFile = TempFile.Create(); var lockFile = LockFile.TryAcquire(tempFile.Path); + lockFile.Should().NotBeNull(); // Act - lockFile?.Dispose(); + lockFile.Dispose(); // Assert: lock can be reacquired after disposal using var lockFile2 = LockFile.TryAcquire(tempFile.Path); From e5711056fbcfd92bf59a6b9cc946cd3f221ec5a5 Mon Sep 17 00:00:00 2001 From: Oleksii Holub <1935960+Tyrrrz@users.noreply.github.com> Date: Tue, 14 Apr 2026 18:41:20 +0300 Subject: [PATCH 6/6] Update LockFileTests.cs --- PowerKit.Tests/LockFileTests.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/PowerKit.Tests/LockFileTests.cs b/PowerKit.Tests/LockFileTests.cs index 342a2e0..7c1dc5b 100644 --- a/PowerKit.Tests/LockFileTests.cs +++ b/PowerKit.Tests/LockFileTests.cs @@ -41,10 +41,9 @@ public void Dispose_Test() // Arrange using var tempFile = TempFile.Create(); var lockFile = LockFile.TryAcquire(tempFile.Path); - lockFile.Should().NotBeNull(); // Act - lockFile.Dispose(); + lockFile!.Dispose(); // Assert: lock can be reacquired after disposal using var lockFile2 = LockFile.TryAcquire(tempFile.Path);