diff --git a/tools/NatsNet.PortTracker/Commands/ModuleCommands.cs b/tools/NatsNet.PortTracker/Commands/ModuleCommands.cs new file mode 100644 index 0000000..0b180ac --- /dev/null +++ b/tools/NatsNet.PortTracker/Commands/ModuleCommands.cs @@ -0,0 +1,153 @@ +using System.CommandLine; +using NatsNet.PortTracker.Data; + +namespace NatsNet.PortTracker.Commands; + +public static class ModuleCommands +{ + public static Command Create(Option dbOption, Option schemaOption) + { + var moduleCommand = new Command("module", "Manage modules"); + + // list + var listStatus = new Option("--status") { Description = "Filter by status" }; + var listCmd = new Command("list", "List modules"); + listCmd.Add(listStatus); + listCmd.SetAction(parseResult => + { + var dbPath = parseResult.GetValue(dbOption)!; + var status = parseResult.GetValue(listStatus); + using var db = new Database(dbPath); + var sql = "SELECT id, name, status, go_package, go_line_count, dotnet_project, dotnet_class FROM modules"; + var parameters = new List<(string, object?)>(); + if (status is not null) + { + sql += " WHERE status = @status"; + parameters.Add(("@status", status)); + } + sql += " ORDER BY name"; + + var rows = db.Query(sql, parameters.ToArray()); + Console.WriteLine($"{"ID",-5} {"Name",-25} {"Status",-15} {"Go Pkg",-15} {"LOC",-8} {"DotNet Project",-25} {"DotNet Class",-20}"); + Console.WriteLine(new string('-', 113)); + foreach (var row in rows) + { + Console.WriteLine($"{row["id"],-5} {row["name"],-25} {row["status"],-15} {row["go_package"],-15} {row["go_line_count"],-8} {row["dotnet_project"] ?? "",-25} {row["dotnet_class"] ?? "",-20}"); + } + Console.WriteLine($"\nTotal: {rows.Count} modules"); + }); + + // show + var showId = new Argument("id") { Description = "Module ID" }; + var showCmd = new Command("show", "Show module details"); + showCmd.Add(showId); + showCmd.SetAction(parseResult => + { + var dbPath = parseResult.GetValue(dbOption)!; + var id = parseResult.GetValue(showId); + using var db = new Database(dbPath); + var modules = db.Query("SELECT * FROM modules WHERE id = @id", ("@id", id)); + if (modules.Count == 0) + { + Console.WriteLine($"Module {id} not found."); + return; + } + var mod = modules[0]; + Console.WriteLine($"Module #{mod["id"]}: {mod["name"]}"); + Console.WriteLine($" Status: {mod["status"]}"); + Console.WriteLine($" Go Package: {mod["go_package"]}"); + Console.WriteLine($" Go File: {mod["go_file"]}"); + Console.WriteLine($" Go LOC: {mod["go_line_count"]}"); + Console.WriteLine($" .NET: {mod["dotnet_project"]} / {mod["dotnet_namespace"]} / {mod["dotnet_class"]}"); + Console.WriteLine($" Notes: {mod["notes"]}"); + + var features = db.Query( + "SELECT id, name, status, go_method, dotnet_method FROM features WHERE module_id = @id ORDER BY name", + ("@id", id)); + Console.WriteLine($"\n Features ({features.Count}):"); + foreach (var f in features) + Console.WriteLine($" #{f["id"],-5} {f["name"],-35} {f["status"],-15} {f["dotnet_method"] ?? ""}"); + + var tests = db.Query( + "SELECT id, name, status, dotnet_method FROM unit_tests WHERE module_id = @id ORDER BY name", + ("@id", id)); + Console.WriteLine($"\n Tests ({tests.Count}):"); + foreach (var t in tests) + Console.WriteLine($" #{t["id"],-5} {t["name"],-35} {t["status"],-15} {t["dotnet_method"] ?? ""}"); + + var deps = db.Query( + "SELECT d.target_type, d.target_id, d.dependency_kind, m.name as target_name FROM dependencies d LEFT JOIN modules m ON d.target_type = 'module' AND d.target_id = m.id WHERE d.source_type = 'module' AND d.source_id = @id", + ("@id", id)); + Console.WriteLine($"\n Dependencies ({deps.Count}):"); + foreach (var d in deps) + Console.WriteLine($" -> {d["target_type"]} #{d["target_id"]} ({d["target_name"]}) [{d["dependency_kind"]}]"); + }); + + // update + var updateId = new Argument("id") { Description = "Module ID" }; + var updateStatus = new Option("--status") { Description = "New status", Required = true }; + var updateCmd = new Command("update", "Update module status"); + updateCmd.Add(updateId); + updateCmd.Add(updateStatus); + updateCmd.SetAction(parseResult => + { + var dbPath = parseResult.GetValue(dbOption)!; + var id = parseResult.GetValue(updateId); + var status = parseResult.GetValue(updateStatus)!; + using var db = new Database(dbPath); + var affected = db.Execute("UPDATE modules SET status = @status WHERE id = @id", + ("@status", status), ("@id", id)); + Console.WriteLine(affected > 0 ? $"Module {id} updated to '{status}'." : $"Module {id} not found."); + }); + + // map + var mapId = new Argument("id") { Description = "Module ID" }; + var mapProject = new Option("--project") { Description = "Target .NET project", Required = true }; + var mapNamespace = new Option("--namespace") { Description = "Target namespace" }; + var mapClass = new Option("--class") { Description = "Target class" }; + var mapCmd = new Command("map", "Map module to .NET project"); + mapCmd.Add(mapId); + mapCmd.Add(mapProject); + mapCmd.Add(mapNamespace); + mapCmd.Add(mapClass); + mapCmd.SetAction(parseResult => + { + var dbPath = parseResult.GetValue(dbOption)!; + var id = parseResult.GetValue(mapId); + var project = parseResult.GetValue(mapProject)!; + var ns = parseResult.GetValue(mapNamespace); + var cls = parseResult.GetValue(mapClass); + using var db = new Database(dbPath); + var affected = db.Execute( + "UPDATE modules SET dotnet_project = @project, dotnet_namespace = @ns, dotnet_class = @cls WHERE id = @id", + ("@project", project), ("@ns", ns), ("@cls", cls), ("@id", id)); + Console.WriteLine(affected > 0 ? $"Module {id} mapped to {project}." : $"Module {id} not found."); + }); + + // set-na + var naId = new Argument("id") { Description = "Module ID" }; + var naReason = new Option("--reason") { Description = "Reason for N/A", Required = true }; + var naCmd = new Command("set-na", "Mark module as N/A"); + naCmd.Add(naId); + naCmd.Add(naReason); + naCmd.SetAction(parseResult => + { + var dbPath = parseResult.GetValue(dbOption)!; + var id = parseResult.GetValue(naId); + var reason = parseResult.GetValue(naReason)!; + using var db = new Database(dbPath); + var affected = db.Execute( + "UPDATE modules SET status = 'n_a', notes = @reason WHERE id = @id", + ("@reason", reason), ("@id", id)); + Console.WriteLine(affected > 0 ? $"Module {id} set to N/A: {reason}" : $"Module {id} not found."); + }); + + moduleCommand.Add(listCmd); + moduleCommand.Add(showCmd); + moduleCommand.Add(updateCmd); + moduleCommand.Add(mapCmd); + moduleCommand.Add(naCmd); + + return moduleCommand; + } +} diff --git a/tools/NatsNet.PortTracker/Program.cs b/tools/NatsNet.PortTracker/Program.cs index a69eaef..dbc1ab0 100644 --- a/tools/NatsNet.PortTracker/Program.cs +++ b/tools/NatsNet.PortTracker/Program.cs @@ -1,4 +1,5 @@ using System.CommandLine; +using NatsNet.PortTracker.Commands; using NatsNet.PortTracker.Data; var dbOption = new Option("--db") @@ -31,6 +32,7 @@ initCommand.SetAction(parseResult => }); rootCommand.Add(initCommand); +rootCommand.Add(ModuleCommands.Create(dbOption, schemaOption)); var parseResult = rootCommand.Parse(args); return await parseResult.InvokeAsync();