Преглед изворни кода

Fix config path resolution and improve CLI error messages

Resolve config directory relative to binary location (AppContext.BaseDirectory)
instead of CWD, allowing rpk to run from any directory. Also display contextual
help output when users enter invalid commands or argument types.

Fixes #116
shifusen329 пре 1 месец
родитељ
комит
8561f0a2ed
2 измењених фајлова са 54 додато и 3 уклоњено
  1. 2 1
      RackPeek/Program.cs
  2. 52 2
      Shared.Rcl/CliBootstrap.cs

+ 2 - 1
RackPeek/Program.cs

@@ -11,7 +11,7 @@ public static class Program
     public static async Task<int> Main(string[] args)
     public static async Task<int> Main(string[] args)
     {
     {
         // Configuration
         // Configuration
-        var configuration = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory())
+        var configuration = new ConfigurationBuilder().SetBasePath(AppContext.BaseDirectory)
             .AddJsonFile("appsettings.json", optional: true)
             .AddJsonFile("appsettings.json", optional: true)
             .Build();
             .Build();
 
 
@@ -28,6 +28,7 @@ public static class Program
         var app = new CommandApp(registrar);
         var app = new CommandApp(registrar);
 
 
         CliBootstrap.BuildApp(app);
         CliBootstrap.BuildApp(app);
+        CliBootstrap.SetContext(args, app);
 
 
         return await app.RunAsync(args);
         return await app.RunAsync(args);
     }
     }

+ 52 - 2
Shared.Rcl/CliBootstrap.cs

@@ -42,19 +42,27 @@ namespace RackPeek;
 
 
 public static class CliBootstrap
 public static class CliBootstrap
 {
 {
+    private static string[]? _lastArgs;
+    private static CommandApp? _app;
+
+    public static void SetContext(string[] args, CommandApp app)
+    {
+        _lastArgs = args;
+        _app = app;
+    }
     public static async Task RegisterInternals(IServiceCollection services, IConfiguration configuration,
     public static async Task RegisterInternals(IServiceCollection services, IConfiguration configuration,
         string yamlDir, string yamlFile)
         string yamlDir, string yamlFile)
     {
     {
         services.AddSingleton(configuration);
         services.AddSingleton(configuration);
 
 
-        var basePath = configuration["HardwarePath"] ?? Directory.GetCurrentDirectory();
+        var basePath = configuration["HardwarePath"] ?? AppContext.BaseDirectory;
 
 
         // Resolve yamlDir as relative to basePath
         // Resolve yamlDir as relative to basePath
         var yamlPath = Path.IsPathRooted(yamlDir) ? yamlDir : Path.Combine(basePath, yamlDir);
         var yamlPath = Path.IsPathRooted(yamlDir) ? yamlDir : Path.Combine(basePath, yamlDir);
 
 
         if (!Directory.Exists(yamlPath)) throw new DirectoryNotFoundException($"YAML directory not found: {yamlPath}");
         if (!Directory.Exists(yamlPath)) throw new DirectoryNotFoundException($"YAML directory not found: {yamlPath}");
 
 
-        var collection = new YamlResourceCollection(Path.Combine(yamlDir, yamlFile), new PhysicalTextFileStore(), new ResourceCollection());
+        var collection = new YamlResourceCollection(Path.Combine(yamlPath, yamlFile), new PhysicalTextFileStore(), new ResourceCollection());
         await collection.LoadAsync();
         await collection.LoadAsync();
         services.AddSingleton<IResourceCollection>(collection);
         services.AddSingleton<IResourceCollection>(collection);
 
 
@@ -490,10 +498,52 @@ public static class CliBootstrap
                 AnsiConsole.MarkupLine($"[red]Not found:[/] {ne.Message}");
                 AnsiConsole.MarkupLine($"[red]Not found:[/] {ne.Message}");
                 return 4;
                 return 4;
 
 
+            case CommandParseException pe:
+                if (_showingHelp) return 1; // suppress errors during help lookup
+                AnsiConsole.MarkupLine($"[red]Invalid command:[/] {pe.Message}");
+                if (pe.Pretty != null) AnsiConsole.Write(pe.Pretty);
+                ShowContextualHelp();
+                return 1;
+
+            case CommandRuntimeException re:
+                if (_showingHelp) return 1;
+                AnsiConsole.MarkupLine($"[red]Error:[/] {re.Message}");
+                if (re.Pretty != null) AnsiConsole.Write(re.Pretty);
+                ShowContextualHelp();
+                return 1;
+
             default:
             default:
                 AnsiConsole.MarkupLine("[red]Unexpected error occurred.[/]");
                 AnsiConsole.MarkupLine("[red]Unexpected error occurred.[/]");
                 AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything);
                 AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything);
                 return 99;
                 return 99;
         }
         }
     }
     }
+
+    private static bool _showingHelp;
+
+    private static void ShowContextualHelp()
+    {
+        if (_lastArgs == null || _app == null || _showingHelp) return;
+
+        _showingHelp = true;
+        try
+        {
+            // Extract command path (args before any --flags)
+            var commandPath = _lastArgs.TakeWhile(a => !a.StartsWith("-")).ToList();
+
+            // Try progressively shorter command paths until --help succeeds
+            while (commandPath.Count > 0)
+            {
+                var helpArgs = commandPath.Append("--help").ToArray();
+                AnsiConsole.WriteLine();
+                var result = _app.Run(helpArgs);
+                if (result == 0) return;
+                commandPath.RemoveAt(commandPath.Count - 1);
+            }
+        }
+        finally
+        {
+            _showingHelp = false;
+        }
+    }
 }
 }