using System; using System.CommandLine; using System.IO; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using StellaOps.Auth.Client; using StellaOps.Cli.Commands; using StellaOps.Cli.Configuration; using StellaOps.Cli.Services; using StellaOps.Cli.Telemetry; namespace StellaOps.Cli; internal static class Program { internal static async Task Main(string[] args) { var (options, configuration) = CliBootstrapper.Build(args); var services = new ServiceCollection(); services.AddSingleton(configuration); services.AddSingleton(options); var verbosityState = new VerbosityState(); services.AddSingleton(verbosityState); services.AddLogging(builder => { builder.ClearProviders(); builder.AddSimpleConsole(logOptions => { logOptions.TimestampFormat = "HH:mm:ss "; logOptions.SingleLine = true; }); builder.AddFilter((category, level) => level >= verbosityState.MinimumLevel); }); if (!string.IsNullOrWhiteSpace(options.Authority.Url)) { services.AddStellaOpsAuthClient(clientOptions => { clientOptions.Authority = options.Authority.Url; clientOptions.ClientId = options.Authority.ClientId ?? string.Empty; clientOptions.ClientSecret = options.Authority.ClientSecret; clientOptions.DefaultScopes.Clear(); clientOptions.DefaultScopes.Add(string.IsNullOrWhiteSpace(options.Authority.Scope) ? StellaOps.Auth.Abstractions.StellaOpsScopes.ConcelierJobsTrigger : options.Authority.Scope); var resilience = options.Authority.Resilience ?? new StellaOpsCliAuthorityResilienceOptions(); clientOptions.EnableRetries = resilience.EnableRetries ?? true; if (resilience.RetryDelays is { Count: > 0 }) { clientOptions.RetryDelays.Clear(); foreach (var delay in resilience.RetryDelays) { if (delay > TimeSpan.Zero) { clientOptions.RetryDelays.Add(delay); } } } if (resilience.AllowOfflineCacheFallback.HasValue) { clientOptions.AllowOfflineCacheFallback = resilience.AllowOfflineCacheFallback.Value; } if (resilience.OfflineCacheTolerance.HasValue && resilience.OfflineCacheTolerance.Value >= TimeSpan.Zero) { clientOptions.OfflineCacheTolerance = resilience.OfflineCacheTolerance.Value; } }); var cacheDirectory = options.Authority.TokenCacheDirectory; if (!string.IsNullOrWhiteSpace(cacheDirectory)) { Directory.CreateDirectory(cacheDirectory); services.AddStellaOpsFileTokenCache(cacheDirectory); } services.AddHttpClient(client => { client.Timeout = TimeSpan.FromMinutes(2); if (Uri.TryCreate(options.Authority.Url, UriKind.Absolute, out var authorityUri)) { client.BaseAddress = authorityUri; } }); } services.AddHttpClient(client => { client.Timeout = TimeSpan.FromMinutes(5); if (!string.IsNullOrWhiteSpace(options.BackendUrl) && Uri.TryCreate(options.BackendUrl, UriKind.Absolute, out var backendUri)) { client.BaseAddress = backendUri; } }); services.AddSingleton(); services.AddSingleton(); await using var serviceProvider = services.BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); var startupLogger = loggerFactory.CreateLogger("StellaOps.Cli.Startup"); AuthorityDiagnosticsReporter.Emit(configuration, startupLogger); using var cts = new CancellationTokenSource(); Console.CancelKeyPress += (_, eventArgs) => { eventArgs.Cancel = true; cts.Cancel(); }; var rootCommand = CommandFactory.Create(serviceProvider, options, cts.Token); var commandConfiguration = new CommandLineConfiguration(rootCommand); var commandExit = await commandConfiguration.InvokeAsync(args, cts.Token).ConfigureAwait(false); var finalExit = Environment.ExitCode != 0 ? Environment.ExitCode : commandExit; if (cts.IsCancellationRequested && finalExit == 0) { finalExit = 130; // Typical POSIX cancellation exit code } return finalExit; } }