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);