diff --git a/Directory.Packages.props b/Directory.Packages.props
index e6e3983..83d9ded 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -35,6 +35,7 @@
+
diff --git a/KtsuTools.BuildMonitor/BuildMonitorService.cs b/KtsuTools.BuildMonitor/BuildMonitorService.cs
index a584655..5d97f7a 100644
--- a/KtsuTools.BuildMonitor/BuildMonitorService.cs
+++ b/KtsuTools.BuildMonitor/BuildMonitorService.cs
@@ -10,6 +10,7 @@ namespace KtsuTools.BuildMonitor;
using System.Threading;
using System.Threading.Tasks;
using Humanizer;
+using ktsu.IntervalAction;
using KtsuTools.Core.Services.GitHub;
using Spectre.Console;
using Spectre.Console.Rendering;
@@ -37,31 +38,42 @@ await AnsiConsole.Live(initial)
.AutoClear(true)
.StartAsync(async ctx =>
{
- while (!ct.IsCancellationRequested)
+ TimeSpan interval = TimeSpan.FromSeconds(refreshIntervalSeconds);
+
+ void Tick()
{
try
{
- Table table = await BuildDashboardTableAsync(owner, ct).ConfigureAwait(false);
+ Table table = BuildDashboardTableAsync(owner, ct).GetAwaiter().GetResult();
ctx.UpdateTarget(table);
}
catch (OperationCanceledException)
{
- break;
}
catch (HttpRequestException ex)
{
ctx.UpdateTarget(new Markup($"[red]API Error: {ex.Message.EscapeMarkup()}[/]"));
}
+ }
- try
- {
- await Task.Delay(TimeSpan.FromSeconds(refreshIntervalSeconds), ct).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- break;
- }
+ Tick();
+
+ IntervalAction ticker = IntervalAction.Start(new IntervalActionOptions
+ {
+ ActionInterval = interval,
+ PollingInterval = interval,
+ Action = Tick,
+ });
+
+ try
+ {
+ await Task.Delay(Timeout.InfiniteTimeSpan, ct).ConfigureAwait(false);
}
+ catch (OperationCanceledException)
+ {
+ }
+
+ ticker.Stop();
}).ConfigureAwait(false);
}
diff --git a/KtsuTools.BuildMonitor/KtsuTools.BuildMonitor.csproj b/KtsuTools.BuildMonitor/KtsuTools.BuildMonitor.csproj
index a0a01df..be68e45 100644
--- a/KtsuTools.BuildMonitor/KtsuTools.BuildMonitor.csproj
+++ b/KtsuTools.BuildMonitor/KtsuTools.BuildMonitor.csproj
@@ -11,6 +11,7 @@
+
diff --git a/KtsuTools.CodeGen/CodeGenService.cs b/KtsuTools.CodeGen/CodeGenService.cs
index 6dd3f61..1f3ec66 100644
--- a/KtsuTools.CodeGen/CodeGenService.cs
+++ b/KtsuTools.CodeGen/CodeGenService.cs
@@ -285,6 +285,7 @@ public class CodeGenService
public async Task GenerateAsync(AbsoluteFilePath inputFile, string language, AbsoluteFilePath? outputFile = null, CancellationToken ct = default)
#pragma warning restore CA1822
{
+ Ensure.NotNull(inputFile);
Ensure.NotNull(language);
string fullPath = inputFile.ToString();
diff --git a/KtsuTools.FileExplorer/FileExplorerService.cs b/KtsuTools.FileExplorer/FileExplorerService.cs
index d748529..0b0e950 100644
--- a/KtsuTools.FileExplorer/FileExplorerService.cs
+++ b/KtsuTools.FileExplorer/FileExplorerService.cs
@@ -62,6 +62,8 @@ public class FileExplorerService
public async Task RunAsync(AbsoluteDirectoryPath startPath, bool showHidden = false, bool showSizes = true, CancellationToken ct = default)
#pragma warning restore CA1822
{
+ Ensure.NotNull(startPath);
+
string currentPath = startPath.ToString();
if (!Directory.Exists(currentPath))
diff --git a/KtsuTools.Machine/KtsuTools.Machine.csproj b/KtsuTools.Machine/KtsuTools.Machine.csproj
index be933ac..7825c24 100644
--- a/KtsuTools.Machine/KtsuTools.Machine.csproj
+++ b/KtsuTools.Machine/KtsuTools.Machine.csproj
@@ -11,6 +11,7 @@
+
diff --git a/KtsuTools.Machine/MachineMonitorService.cs b/KtsuTools.Machine/MachineMonitorService.cs
index 21028bd..9c29245 100644
--- a/KtsuTools.Machine/MachineMonitorService.cs
+++ b/KtsuTools.Machine/MachineMonitorService.cs
@@ -10,6 +10,7 @@ namespace KtsuTools.Machine;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using ktsu.IntervalAction;
using LibreHardwareMonitor.Hardware;
using Spectre.Console;
using Spectre.Console.Rendering;
@@ -48,31 +49,33 @@ public async Task RunDashboardAsync(int refreshIntervalMs = 1000, Cancellat
AnsiConsole.WriteLine();
IRenderable initial = new Text("Loading hardware sensors...");
+ Computer computerCapture = computer;
await AnsiConsole.Live(initial)
.AutoClear(true)
.StartAsync(async ctx =>
{
- while (!ct.IsCancellationRequested)
+ TimeSpan interval = TimeSpan.FromMilliseconds(refreshIntervalMs);
+
+ void Tick() => ctx.UpdateTarget(BuildDashboard(computerCapture));
+
+ Tick();
+
+ IntervalAction ticker = IntervalAction.Start(new IntervalActionOptions
+ {
+ ActionInterval = interval,
+ PollingInterval = interval,
+ Action = Tick,
+ });
+
+ try
+ {
+ await Task.Delay(Timeout.InfiniteTimeSpan, ct).ConfigureAwait(false);
+ }
+ catch (OperationCanceledException)
{
- try
- {
- Table dashboard = BuildDashboard(computer);
- ctx.UpdateTarget(dashboard);
- }
- catch (OperationCanceledException)
- {
- break;
- }
-
- try
- {
- await Task.Delay(refreshIntervalMs, ct).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- break;
- }
}
+
+ ticker.Stop();
}).ConfigureAwait(false);
}
finally
diff --git a/KtsuTools.MemFrag/KtsuTools.MemFrag.csproj b/KtsuTools.MemFrag/KtsuTools.MemFrag.csproj
index 4d92c11..9a5e030 100644
--- a/KtsuTools.MemFrag/KtsuTools.MemFrag.csproj
+++ b/KtsuTools.MemFrag/KtsuTools.MemFrag.csproj
@@ -9,6 +9,7 @@
+
diff --git a/KtsuTools.MemFrag/MemFragService.cs b/KtsuTools.MemFrag/MemFragService.cs
index 9e4631f..06e9e68 100644
--- a/KtsuTools.MemFrag/MemFragService.cs
+++ b/KtsuTools.MemFrag/MemFragService.cs
@@ -9,6 +9,7 @@ namespace KtsuTools.MemFrag;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
+using ktsu.IntervalAction;
using Spectre.Console;
using Spectre.Console.Rendering;
@@ -78,33 +79,46 @@ public async Task MonitorAsync(int processId, int refreshIntervalMs = 1000,
AnsiConsole.WriteLine();
IRenderable initial = new Text("Loading...");
+ Process processCapture = process;
await AnsiConsole.Live(initial)
.AutoClear(true)
.StartAsync(async ctx =>
{
- while (!ct.IsCancellationRequested)
+ using CancellationTokenSource exitedCts = CancellationTokenSource.CreateLinkedTokenSource(ct);
+ TimeSpan interval = TimeSpan.FromMilliseconds(refreshIntervalMs);
+
+ void Tick()
{
try
{
- process.Refresh();
- Table table = BuildMemoryTable(process);
- ctx.UpdateTarget(table);
+ processCapture.Refresh();
+ ctx.UpdateTarget(BuildMemoryTable(processCapture));
}
catch (InvalidOperationException)
{
ctx.UpdateTarget(new Markup("[red]Process has exited.[/]"));
- break;
+ exitedCts.Cancel();
}
+ }
- try
- {
- await Task.Delay(refreshIntervalMs, ct).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- break;
- }
+ Tick();
+
+ IntervalAction ticker = IntervalAction.Start(new IntervalActionOptions
+ {
+ ActionInterval = interval,
+ PollingInterval = interval,
+ Action = Tick,
+ });
+
+ try
+ {
+ await Task.Delay(Timeout.InfiniteTimeSpan, exitedCts.Token).ConfigureAwait(false);
}
+ catch (OperationCanceledException)
+ {
+ }
+
+ ticker.Stop();
}).ConfigureAwait(false);
}
diff --git a/KtsuTools.Merge/MergeService.cs b/KtsuTools.Merge/MergeService.cs
index e549908..2503e84 100644
--- a/KtsuTools.Merge/MergeService.cs
+++ b/KtsuTools.Merge/MergeService.cs
@@ -57,6 +57,7 @@ public class MergeService
public async Task RunMergeAsync(AbsoluteDirectoryPath directory, string filename, CancellationToken ct = default)
#pragma warning restore CA1822
{
+ Ensure.NotNull(directory);
Ensure.NotNull(filename);
string fullPath = directory.ToString();
diff --git a/KtsuTools/Commands/SyncCommand.cs b/KtsuTools/Commands/SyncCommand.cs
index 5ebfb3d..bbd5abe 100644
--- a/KtsuTools/Commands/SyncCommand.cs
+++ b/KtsuTools/Commands/SyncCommand.cs
@@ -38,7 +38,9 @@ public sealed class Settings : CommandSettings
///
[CommandOption("--filename ")]
[Description("Filename pattern to scan for. Repeat the flag or pass a comma-separated list to sync several files in one run.")]
+#pragma warning disable CA1819 // Properties should not return arrays - Spectre.Console.Cli binds multi-value options via T[] only.
public string[] Filename { get; init; } = [];
+#pragma warning restore CA1819
///
/// Gets a value indicating whether to push without prompting when all unpushed commits were authored by KtsuTools.