acdream/src/AcDream.Headless/Configuration/HeadlessCommandLine.cs
Erik 215442dc1d refactor(headless): N2 rename HeadlessCommandLine.Console to ConsoleEnabled
"Console" read as if it might mean System.Console; ConsoleEnabled says
what the flag actually gates. Pure rename, no behavior change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 07:48:42 +02:00

125 lines
4 KiB
C#

namespace AcDream.Headless.Configuration;
internal sealed record HeadlessCommandLine(
string Command,
string ConfigurationPath,
HeadlessPathOverrides Paths,
HeadlessDirectCredentials? DirectCredentials,
bool ConsoleEnabled = false)
{
internal static HeadlessCommandLine Parse(
IReadOnlyList<string> arguments)
{
ArgumentNullException.ThrowIfNull(arguments);
if (arguments.Count < 3)
throw new HeadlessCommandLineException("Missing command options.");
string command = arguments[0];
if (command is not ("validate" or "run"))
throw new HeadlessCommandLineException("Unknown command.");
string? configurationPath = null;
string? configDirectory = null;
string? dataDirectory = null;
string? cacheDirectory = null;
string? user = null;
string? password = null;
bool console = false;
int index = 1;
while (index < arguments.Count)
{
string name = arguments[index];
// --console is a bare flag (no value token) — the interactive
// console for the run command (see HeadlessConsoleOptions).
if (name == "--console")
{
console = true;
index += 1;
continue;
}
if (index + 1 >= arguments.Count)
{
throw new HeadlessCommandLineException(
"Every command option requires a value.");
}
string value = arguments[index + 1];
if (string.IsNullOrWhiteSpace(value))
{
throw new HeadlessCommandLineException(
"Command option values cannot be empty.");
}
switch (name)
{
case "--config":
SetOnce(ref configurationPath, value);
break;
case "--config-dir":
SetOnce(ref configDirectory, value);
break;
case "--data-dir":
SetOnce(ref dataDirectory, value);
break;
case "--cache-dir":
SetOnce(ref cacheDirectory, value);
break;
case "-user":
case "--user":
SetOnce(ref user, value);
break;
case "-password":
case "--password":
SetOnce(ref password, value);
break;
default:
throw new HeadlessCommandLineException(
"Unknown command option.");
}
index += 2;
}
if (configurationPath is null)
{
throw new HeadlessCommandLineException(
"The --config option is required.");
}
if ((user is null) != (password is null))
{
throw new HeadlessCommandLineException(
"The user and password options must be supplied together.");
}
if (user is not null && command != "run")
{
throw new HeadlessCommandLineException(
"Direct credentials are valid only for run mode.");
}
return new HeadlessCommandLine(
command,
configurationPath,
new HeadlessPathOverrides(
configDirectory,
dataDirectory,
cacheDirectory),
user is null
? null
: new HeadlessDirectCredentials(user, password!),
console);
}
private static void SetOnce(ref string? destination, string value)
{
if (destination is not null)
{
throw new HeadlessCommandLineException(
"Command options cannot be repeated.");
}
destination = value;
}
}
internal sealed record HeadlessDirectCredentials(
string User,
string Password);