diff --git a/Directory.Packages.props b/Directory.Packages.props
index c8c0525..bf29479 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -5,7 +5,6 @@
-
-
+
-
\ No newline at end of file
+
diff --git a/src/process.dummy.app/AsyncOutputCommand.cs b/src/process.dummy.app/AsyncOutputCommand.cs
deleted file mode 100644
index 6ec859c..0000000
--- a/src/process.dummy.app/AsyncOutputCommand.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) The Geekeey Authors
-// SPDX-License-Identifier: EUPL-1.2
-
-using Spectre.Console.Cli;
-
-internal abstract class AsyncOutputCommand : AsyncCommand where T : OutputCommandSettings
-{
-}
-
-internal abstract class OutputCommandSettings : CommandSettings
-{
- [CommandOption("--target")] public OutputTarget Target { get; init; } = OutputTarget.StdOut;
-}
\ No newline at end of file
diff --git a/src/process.dummy.app/Geekeey.Process.Dummy.App.csproj b/src/process.dummy.app/Geekeey.Process.Dummy.App.csproj
index 64c3538..a8234c4 100644
--- a/src/process.dummy.app/Geekeey.Process.Dummy.App.csproj
+++ b/src/process.dummy.app/Geekeey.Process.Dummy.App.csproj
@@ -11,7 +11,6 @@
-
-
+
-
\ No newline at end of file
+
diff --git a/src/process.dummy.app/Output.cs b/src/process.dummy.app/Output.cs
index 8080687..554cafa 100644
--- a/src/process.dummy.app/Output.cs
+++ b/src/process.dummy.app/Output.cs
@@ -3,32 +3,17 @@
internal sealed class Output : IDisposable
{
- private readonly CancellationTokenSource _cts = new();
-
- public Output()
- {
- Console.CancelKeyPress += Cancel;
- }
-
public StreamReader Stdin { get; } = new(Console.OpenStandardInput(), leaveOpen: false);
public StreamWriter Stdout { get; } = new(Console.OpenStandardOutput(), leaveOpen: false);
public StreamWriter Stderr { get; } = new(Console.OpenStandardError(), leaveOpen: false);
- public CancellationToken CancellationToken => _cts.Token;
-
public static Output Connect()
{
return new Output();
}
- private void Cancel(object? sender, ConsoleCancelEventArgs args)
- {
- args.Cancel = true;
- _cts.Cancel();
- }
-
public void Dispose()
{
Stdout.BaseStream.Flush();
@@ -36,7 +21,5 @@ internal sealed class Output : IDisposable
Stderr.BaseStream.Flush();
Stderr.Dispose();
Stdin.Dispose();
- Console.CancelKeyPress -= Cancel;
- _cts.Dispose();
}
}
\ No newline at end of file
diff --git a/src/process.dummy.app/Program.cs b/src/process.dummy.app/Program.cs
index d6cc593..b207174 100644
--- a/src/process.dummy.app/Program.cs
+++ b/src/process.dummy.app/Program.cs
@@ -1,11 +1,10 @@
// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
+using System.CommandLine;
using System.Reflection;
using System.Runtime.InteropServices;
-using Spectre.Console.Cli;
-
namespace Geekeey.Process.Testing.Fixture;
public static class Program
@@ -18,28 +17,36 @@ public static class Program
public static string FilePath { get; } = Path.ChangeExtension(AssemblyPath, FileExtension);
- private static Task Main(string[] args)
+ private static async Task Main(string[] args)
{
Environment.SetEnvironmentVariable("DOTNET_SYSTEM_CONSOLE_ALLOW_ANSI_COLOR_REDIRECTION", "false");
- var app = new CommandApp();
- app.Configure(Configuration);
- return app.RunAsync(args);
- static void Configuration(IConfigurator configuration)
+ var app = new RootCommand
{
- configuration.AddCommand("echo");
- configuration.AddCommand("echo-stdin");
- configuration.AddCommand("env");
- configuration.AddCommand("cwd");
- configuration.AddCommand("cwd");
- configuration.AddCommand("exit");
- configuration.AddCommand("length");
- configuration.AddCommand("sleep");
- configuration.AddBranch("generate", static generate =>
+ new EchoCommand(),
+ new EchoStdinCommand(),
+ new EnvironmentCommand(),
+ new WorkingDirectoryCommand(),
+ new ExitCommand(),
+ new LengthCommand(),
+ new SleepCommand(),
+ new Command("generate")
{
- generate.AddCommand("blob");
- generate.AddCommand("clob");
- });
+ new GenerateBlobCommand(), //
+ new GenerateClobCommand()
+ }
+ };
+
+ var cts = new CancellationTokenSource();
+ using (PosixSignalRegistration.Create(PosixSignal.SIGINT, Cancel))
+ {
+ return await app.Parse(args).InvokeAsync(configuration: null, cts.Token);
+ }
+
+ void Cancel(PosixSignalContext context)
+ {
+ context.Cancel = true;
+ cts.Cancel();
}
}
}
\ No newline at end of file
diff --git a/src/process.dummy.app/_commands/EchoCommand.cs b/src/process.dummy.app/_commands/EchoCommand.cs
index 29dfb4c..a6ea50a 100644
--- a/src/process.dummy.app/_commands/EchoCommand.cs
+++ b/src/process.dummy.app/_commands/EchoCommand.cs
@@ -1,23 +1,29 @@
// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
-using Spectre.Console.Cli;
+using System.CommandLine;
-internal sealed class EchoCommand : AsyncOutputCommand
+internal sealed class EchoCommand : Command
{
- public sealed class Settings : OutputCommandSettings
+ private static readonly Option Target = new("--target") { DefaultValueFactory = _ => OutputTarget.StdOut };
+ private static readonly Option Separator = new("--separator") { DefaultValueFactory = _ => " " };
+ private static readonly Argument Items = new("line") { Arity = ArgumentArity.ZeroOrMore, DefaultValueFactory = _ => [] };
+
+ public EchoCommand() : base("echo")
{
- [CommandOption("--separator ")] public string Separator { get; init; } = " ";
- [CommandArgument(0, "[line]")] public string[] Items { get; init; } = [];
+ Add(Target);
+ Add(Separator);
+ Add(Items);
+ SetAction(ExecuteAsync);
}
- public override async Task ExecuteAsync(CommandContext context, Settings settings, CancellationToken cancellationToken)
+ public async Task ExecuteAsync(ParseResult result, CancellationToken cancellationToken)
{
using var output = Output.Connect();
- foreach (var writer in output.GetWriters(settings.Target))
+ foreach (var writer in output.GetWriters(result.GetValue(Target)))
{
- await writer.WriteLineAsync(string.Join(settings.Separator, settings.Items));
+ await writer.WriteLineAsync(string.Join(result.GetRequiredValue(Separator), result.GetRequiredValue(Items)));
}
return 0;
diff --git a/src/process.dummy.app/_commands/EchoStdinCommand.cs b/src/process.dummy.app/_commands/EchoStdinCommand.cs
index 92517a4..f9ea769 100644
--- a/src/process.dummy.app/_commands/EchoStdinCommand.cs
+++ b/src/process.dummy.app/_commands/EchoStdinCommand.cs
@@ -2,25 +2,30 @@
// SPDX-License-Identifier: EUPL-1.2
using System.Buffers;
+using System.CommandLine;
-using Spectre.Console.Cli;
-
-internal sealed class EchoStdinCommand : AsyncOutputCommand
+internal sealed class EchoStdinCommand : Command
{
- public sealed class Settings : OutputCommandSettings
+ private static readonly Option Target = new("--target") { DefaultValueFactory = _ => OutputTarget.StdOut };
+ private static readonly Option Length = new("--length") { DefaultValueFactory = _ => long.MaxValue };
+
+ public EchoStdinCommand() : base("echo-stdin")
{
- [CommandOption("--length")] public long Length { get; init; } = long.MaxValue;
+ Add(Target);
+ Add(Length);
+ SetAction(ExecuteAsync);
}
- public override async Task ExecuteAsync(CommandContext context, Settings settings, CancellationToken cancellationToken)
+ public async Task ExecuteAsync(ParseResult result, CancellationToken cancellationToken)
{
using var output = Output.Connect();
using var buffer = MemoryPool.Shared.Rent(81920);
var count = 0L;
- while (count < settings.Length)
+ var max = result.GetRequiredValue(Length);
+ while (count < max)
{
- var bytesWanted = (int)Math.Min(buffer.Memory.Length, settings.Length - count);
+ var bytesWanted = (int)Math.Min(buffer.Memory.Length, max - count);
var bytesRead = await output.Stdin.BaseStream.ReadAsync(buffer.Memory[..bytesWanted], cancellationToken);
if (bytesRead <= 0)
@@ -28,7 +33,7 @@ internal sealed class EchoStdinCommand : AsyncOutputCommand
+internal sealed class EnvironmentCommand : Command
{
- public sealed class Settings : OutputCommandSettings
+ private static readonly Option Target = new("--target") { DefaultValueFactory = _ => OutputTarget.StdOut };
+ private static readonly Argument Variables = new("argument") { Arity = ArgumentArity.ZeroOrMore, DefaultValueFactory = _ => [] };
+
+ public EnvironmentCommand() : base("env")
{
- [CommandArgument(0, "")] public string[] Variables { get; init; } = [];
+ Add(Target);
+ Add(Variables);
+ SetAction(ExecuteAsync);
}
- public override async Task ExecuteAsync(CommandContext context, Settings settings, CancellationToken cancellationToken)
+ public async Task ExecuteAsync(ParseResult result, CancellationToken cancellationToken)
{
using var output = Output.Connect();
- foreach (var name in settings.Variables)
+ foreach (var name in result.GetRequiredValue(Variables))
{
var value = Environment.GetEnvironmentVariable(name) ?? string.Empty;
- foreach (var writer in output.GetWriters(settings.Target))
+ foreach (var writer in output.GetWriters(result.GetRequiredValue(Target)))
{
await writer.WriteLineAsync(value);
}
diff --git a/src/process.dummy.app/_commands/ExitCommand.cs b/src/process.dummy.app/_commands/ExitCommand.cs
index d429027..60f5fd0 100644
--- a/src/process.dummy.app/_commands/ExitCommand.cs
+++ b/src/process.dummy.app/_commands/ExitCommand.cs
@@ -1,21 +1,23 @@
// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
-using Spectre.Console.Cli;
+using System.CommandLine;
-internal sealed class ExitCommand : AsyncCommand
+internal sealed class ExitCommand : Command
{
- public sealed class Settings : CommandSettings
+ private static readonly Argument Code = new("code");
+
+ public ExitCommand() : base("exit")
{
- [CommandArgument(1, "")] public int Code { get; init; }
+ Add(Code);
+ SetAction(ExecuteAsync);
}
- public override async Task ExecuteAsync(CommandContext context, Settings settings, CancellationToken cancellationToken)
+ public async Task ExecuteAsync(ParseResult result, CancellationToken cancellationToken)
{
using var output = Output.Connect();
-
- await output.Stderr.WriteLineAsync($"Exit code set to {settings.Code}");
-
- return settings.Code;
+ var code = result.GetValue(Code);
+ await output.Stderr.WriteLineAsync($"Exit code set to {code}");
+ return code;
}
}
\ No newline at end of file
diff --git a/src/process.dummy.app/_commands/GenerateBlobCommand.cs b/src/process.dummy.app/_commands/GenerateBlobCommand.cs
index 3479cde..b078a27 100644
--- a/src/process.dummy.app/_commands/GenerateBlobCommand.cs
+++ b/src/process.dummy.app/_commands/GenerateBlobCommand.cs
@@ -2,32 +2,38 @@
// SPDX-License-Identifier: EUPL-1.2
using System.Buffers;
+using System.CommandLine;
-using Spectre.Console.Cli;
-
-internal sealed class GenerateBlobCommand : AsyncOutputCommand
+internal sealed class GenerateBlobCommand : Command
{
private readonly Random _random = new(1234567);
- public sealed class Settings : OutputCommandSettings
+ private static readonly Option Target = new("--target") { DefaultValueFactory = _ => OutputTarget.StdOut };
+ private static readonly Option Length = new("--length") { DefaultValueFactory = _ => 100_000L };
+ private static readonly Option Buffer = new("--buffer") { DefaultValueFactory = _ => 1024 };
+
+ public GenerateBlobCommand() : base("blob")
{
- [CommandOption("--length")] public long Length { get; init; } = 100_000;
- [CommandOption("--buffer")] public int BufferSize { get; init; } = 1024;
+ Add(Target);
+ Add(Length);
+ Add(Buffer);
+ SetAction(ExecuteAsync);
}
- public override async Task ExecuteAsync(CommandContext context, Settings settings, CancellationToken cancellationToken)
+ public async Task ExecuteAsync(ParseResult result, CancellationToken cancellationToken)
{
using var output = Output.Connect();
- using var bytes = MemoryPool.Shared.Rent(settings.BufferSize);
+ using var bytes = MemoryPool.Shared.Rent(result.GetRequiredValue(Buffer));
var total = 0L;
- while (total < settings.Length)
+ var length = result.GetRequiredValue(Length);
+ while (total < length)
{
_random.NextBytes(bytes.Memory.Span);
- var count = (int)Math.Min(bytes.Memory.Length, settings.Length - total);
- foreach (var writer in output.GetWriters(settings.Target))
+ var count = (int)Math.Min(bytes.Memory.Length, length - total);
+ foreach (var writer in output.GetWriters(result.GetRequiredValue(Target)))
{
await writer.BaseStream.WriteAsync(bytes.Memory[..count], cancellationToken);
}
diff --git a/src/process.dummy.app/_commands/GenerateClobCommand.cs b/src/process.dummy.app/_commands/GenerateClobCommand.cs
index e285071..066a538 100644
--- a/src/process.dummy.app/_commands/GenerateClobCommand.cs
+++ b/src/process.dummy.app/_commands/GenerateClobCommand.cs
@@ -1,37 +1,42 @@
// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
+using System.CommandLine;
using System.Text;
-using Spectre.Console.Cli;
-
-internal sealed class GenerateClobCommand : AsyncOutputCommand
+internal sealed class GenerateClobCommand : Command
{
private readonly Random _random = new(1234567);
private readonly char[] _chars = [.. Enumerable.Range(32, 94).Select(i => (char)i)];
- public sealed class Settings : OutputCommandSettings
+ private static readonly Option Target = new("--target") { DefaultValueFactory = _ => OutputTarget.StdOut };
+ private static readonly Option Length = new("--length") { DefaultValueFactory = _ => 100_000 };
+ private static readonly Option Lines = new("--lines") { DefaultValueFactory = _ => 1 };
+
+ public GenerateClobCommand() : base("clob")
{
- [CommandOption("--length")] public int Length { get; init; } = 100_000;
- [CommandOption("--lines")] public int LinesCount { get; init; } = 1;
+ Add(Target);
+ Add(Length);
+ Add(Lines);
+ SetAction(ExecuteAsync);
}
- public override async Task ExecuteAsync(CommandContext context, Settings settings, CancellationToken cancellationToken)
+ public async Task ExecuteAsync(ParseResult result, CancellationToken cancellationToken)
{
using var output = Output.Connect();
- var buffer = new StringBuilder(settings.Length);
+ var buffer = new StringBuilder(result.GetRequiredValue(Length));
- for (var line = 0; line < settings.LinesCount; line++)
+ for (var line = 0; line < result.GetRequiredValue(Lines); line++)
{
buffer.Clear();
- for (var i = 0; i < settings.Length; i++)
+ for (var i = 0; i < result.GetRequiredValue(Length); i++)
{
buffer.Append(_chars[_random.Next(0, _chars.Length)]);
}
- foreach (var writer in output.GetWriters(settings.Target))
+ foreach (var writer in output.GetWriters(result.GetRequiredValue(Target)))
{
await writer.WriteLineAsync(buffer.ToString());
}
diff --git a/src/process.dummy.app/_commands/LengthCommand.cs b/src/process.dummy.app/_commands/LengthCommand.cs
index 45c7aa6..c3e883f 100644
--- a/src/process.dummy.app/_commands/LengthCommand.cs
+++ b/src/process.dummy.app/_commands/LengthCommand.cs
@@ -2,21 +2,26 @@
// SPDX-License-Identifier: EUPL-1.2
using System.Buffers;
+using System.CommandLine;
using System.Globalization;
-using Spectre.Console.Cli;
-
-internal sealed class LengthCommand : AsyncOutputCommand
+internal sealed class LengthCommand : Command
{
- public sealed class Settings : OutputCommandSettings
+ private static readonly Option Target = new("--target") { DefaultValueFactory = _ => OutputTarget.StdOut };
+ private static readonly Option Buffer = new("--buffer") { DefaultValueFactory = _ => 81920 };
+
+ public LengthCommand() : base("length")
{
+ Add(Target);
+ Add(Buffer);
+ SetAction(ExecuteAsync);
}
- public override async Task ExecuteAsync(CommandContext context, Settings settings, CancellationToken cancellationToken)
+ public async Task ExecuteAsync(ParseResult result, CancellationToken cancellationToken)
{
using var output = Output.Connect();
- using var buffer = MemoryPool.Shared.Rent(81920);
+ using var buffer = MemoryPool.Shared.Rent(result.GetRequiredValue(Buffer));
var count = 0L;
while (true)
@@ -30,7 +35,7 @@ internal sealed class LengthCommand : AsyncOutputCommand
count += bytesRead;
}
- foreach (var writer in output.GetWriters(settings.Target))
+ foreach (var writer in output.GetWriters(result.GetRequiredValue(Target)))
{
await writer.WriteLineAsync(count.ToString(CultureInfo.InvariantCulture));
}
diff --git a/src/process.dummy.app/_commands/SleepCommand.cs b/src/process.dummy.app/_commands/SleepCommand.cs
index 95bcbe6..0c4448b 100644
--- a/src/process.dummy.app/_commands/SleepCommand.cs
+++ b/src/process.dummy.app/_commands/SleepCommand.cs
@@ -1,34 +1,37 @@
// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
-using Spectre.Console.Cli;
+using System.CommandLine;
-internal sealed class SleepCommand : AsyncCommand
+internal sealed class SleepCommand : Command
{
- public sealed class Settings : CommandSettings
+ private static readonly Argument Duration = new("duration") { DefaultValueFactory = _ => TimeSpan.FromSeconds(1) };
+
+ public SleepCommand() : base("sleep")
{
- [CommandArgument(0, "[duration]")] public TimeSpan Duration { get; init; } = TimeSpan.FromSeconds(1);
+ Add(Duration);
+ SetAction(ExecuteAsync);
}
- public override async Task ExecuteAsync(CommandContext context, Settings settings, CancellationToken cancellationToken)
+ public async Task ExecuteAsync(ParseResult result, CancellationToken cancellationToken)
{
using var output = Output.Connect();
try
{
- await Console.Out.WriteLineAsync($"Sleeping for {settings.Duration}...");
- await Console.Out.FlushAsync(CancellationToken.None);
+ await output.Stdout.WriteLineAsync($"Sleeping for {result.GetRequiredValue(Duration)}...");
+ await output.Stdout.FlushAsync(CancellationToken.None);
- await Task.Delay(settings.Duration, output.CancellationToken);
+ await Task.Delay(result.GetRequiredValue(Duration), cancellationToken);
}
catch (OperationCanceledException)
{
- await Console.Out.WriteLineAsync("Canceled.");
- await Console.Out.FlushAsync(CancellationToken.None);
+ await output.Stdout.WriteLineAsync("Canceled.");
+ await output.Stdout.FlushAsync(CancellationToken.None);
}
- await Console.Out.WriteLineAsync("Done.");
- await Console.Out.FlushAsync(CancellationToken.None);
+ await output.Stdout.WriteLineAsync("Done.");
+ await output.Stdout.FlushAsync(CancellationToken.None);
return 0;
}
}
\ No newline at end of file
diff --git a/src/process.dummy.app/_commands/WorkingDirectoryCommand.cs b/src/process.dummy.app/_commands/WorkingDirectoryCommand.cs
index 6aa32d0..1e65131 100644
--- a/src/process.dummy.app/_commands/WorkingDirectoryCommand.cs
+++ b/src/process.dummy.app/_commands/WorkingDirectoryCommand.cs
@@ -1,19 +1,23 @@
// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
-using Spectre.Console.Cli;
+using System.CommandLine;
-internal sealed class WorkingDirectoryCommand : AsyncOutputCommand
+internal sealed class WorkingDirectoryCommand : Command
{
- public sealed class Settings : OutputCommandSettings
+ private static readonly Option Target = new("--target") { DefaultValueFactory = _ => OutputTarget.StdOut };
+
+ public WorkingDirectoryCommand() : base("cwd")
{
+ Add(Target);
+ SetAction(ExecuteAsync);
}
- public override async Task ExecuteAsync(CommandContext context, Settings settings, CancellationToken cancellationToken)
+ public async Task ExecuteAsync(ParseResult result, CancellationToken cancellationToken)
{
using var output = Output.Connect();
- foreach (var writer in output.GetWriters(settings.Target))
+ foreach (var writer in output.GetWriters(result.GetRequiredValue(Target)))
{
await writer.WriteLineAsync(Directory.GetCurrentDirectory());
}