Files
natsnet/tools/NatsNet.PortTracker/Commands/PhaseCommands.cs

213 lines
9.8 KiB
C#

using System.CommandLine;
using NatsNet.PortTracker.Data;
namespace NatsNet.PortTracker.Commands;
public static class PhaseCommands
{
private static readonly (int Number, string Name, string Description)[] Phases =
[
(1, "Analysis & Schema", "Run Go AST analyzer, populate DB schema, map libraries"),
(2, "Core Infrastructure", "Port foundational modules (logging, errors, options)"),
(3, "Message Layer", "Port message parsing, headers, protocol handling"),
(4, "Connection Layer", "Port connection management, reconnection logic"),
(5, "Client API", "Port publish, subscribe, request-reply"),
(6, "Advanced Features", "Port JetStream, KV, Object Store, Services"),
(7, "Testing & Verification", "Port and verify all unit tests, integration tests"),
];
public static Command Create(Option<string> dbOption, Option<string> schemaOption)
{
var phaseCommand = new Command("phase", "Manage porting phases");
// list
var listCmd = new Command("list", "List all phases with status");
listCmd.SetAction(parseResult =>
{
var dbPath = parseResult.GetValue(dbOption)!;
using var db = new Database(dbPath);
Console.WriteLine($"{"Phase",-7} {"Name",-25} {"Description",-55} {"Status",-12}");
Console.WriteLine(new string('-', 99));
foreach (var (number, name, description) in Phases)
{
var status = CalculatePhaseStatus(db, number);
Console.WriteLine($"{number,-7} {name,-25} {description,-55} {status,-12}");
}
});
// check
var checkPhase = new Argument<int>("phase") { Description = "Phase number (1-7)" };
var checkCmd = new Command("check", "Check phase completion status");
checkCmd.Add(checkPhase);
checkCmd.SetAction(parseResult =>
{
var dbPath = parseResult.GetValue(dbOption)!;
var phase = parseResult.GetValue(checkPhase);
using var db = new Database(dbPath);
if (phase < 1 || phase > 7)
{
Console.WriteLine("Phase must be between 1 and 7.");
return;
}
var (_, name, description) = Phases[phase - 1];
Console.WriteLine($"Phase {phase}: {name}");
Console.WriteLine($" {description}\n");
RunPhaseCheck(db, phase);
});
phaseCommand.Add(listCmd);
phaseCommand.Add(checkCmd);
return phaseCommand;
}
private static string CalculatePhaseStatus(Database db, int phase)
{
return phase switch
{
1 => CalculatePhase1Status(db),
2 => CalculateModulePhaseStatus(db, "Core Infrastructure"),
3 => CalculateModulePhaseStatus(db, "Message Layer"),
4 => CalculateModulePhaseStatus(db, "Connection Layer"),
5 => CalculateModulePhaseStatus(db, "Client API"),
6 => CalculateModulePhaseStatus(db, "Advanced Features"),
7 => CalculatePhase7Status(db),
_ => "unknown"
};
}
private static string CalculatePhase1Status(Database db)
{
var totalModules = db.ExecuteScalar<long>("SELECT COUNT(*) FROM modules");
var totalLibraries = db.ExecuteScalar<long>("SELECT COUNT(*) FROM library_mappings");
if (totalModules == 0 && totalLibraries == 0) return "not_started";
var mappedLibraries = db.ExecuteScalar<long>("SELECT COUNT(*) FROM library_mappings WHERE status != 'not_mapped'");
if (totalModules > 0 && (totalLibraries == 0 || mappedLibraries == totalLibraries)) return "complete";
return "in_progress";
}
private static string CalculateModulePhaseStatus(Database db, string phaseDescription)
{
// Generic phase status based on overall module completion
var total = db.ExecuteScalar<long>("SELECT COUNT(*) FROM modules");
if (total == 0) return "not_started";
var done = db.ExecuteScalar<long>("SELECT COUNT(*) FROM modules WHERE status IN ('complete', 'verified', 'n_a')");
if (done == total) return "complete";
var started = db.ExecuteScalar<long>("SELECT COUNT(*) FROM modules WHERE status != 'not_started'");
return started > 0 ? "in_progress" : "not_started";
}
private static string CalculatePhase7Status(Database db)
{
var totalTests = db.ExecuteScalar<long>("SELECT COUNT(*) FROM unit_tests");
if (totalTests == 0) return "not_started";
var doneTests = db.ExecuteScalar<long>("SELECT COUNT(*) FROM unit_tests WHERE status IN ('complete', 'verified', 'n_a')");
if (doneTests == totalTests) return "complete";
var startedTests = db.ExecuteScalar<long>("SELECT COUNT(*) FROM unit_tests WHERE status != 'not_started'");
return startedTests > 0 ? "in_progress" : "not_started";
}
private static void RunPhaseCheck(Database db, int phase)
{
switch (phase)
{
case 1:
CheckPhase1(db);
break;
case 2:
case 3:
case 4:
case 5:
case 6:
CheckModulePhase(db, phase);
break;
case 7:
CheckPhase7(db);
break;
}
}
private static void CheckPhase1(Database db)
{
var totalModules = db.ExecuteScalar<long>("SELECT COUNT(*) FROM modules");
var totalFeatures = db.ExecuteScalar<long>("SELECT COUNT(*) FROM features");
var totalTests = db.ExecuteScalar<long>("SELECT COUNT(*) FROM unit_tests");
var totalLibs = db.ExecuteScalar<long>("SELECT COUNT(*) FROM library_mappings");
var mappedLibs = db.ExecuteScalar<long>("SELECT COUNT(*) FROM library_mappings WHERE status != 'not_mapped'");
var totalDeps = db.ExecuteScalar<long>("SELECT COUNT(*) FROM dependencies");
Console.WriteLine("Phase 1 Checklist:");
Console.WriteLine($" [{ (totalModules > 0 ? "x" : " ") }] Modules populated: {totalModules}");
Console.WriteLine($" [{ (totalFeatures > 0 ? "x" : " ") }] Features populated: {totalFeatures}");
Console.WriteLine($" [{ (totalTests > 0 ? "x" : " ") }] Unit tests populated: {totalTests}");
Console.WriteLine($" [{ (totalDeps > 0 ? "x" : " ") }] Dependencies mapped: {totalDeps}");
Console.WriteLine($" [{ (totalLibs > 0 ? "x" : " ") }] Libraries identified: {totalLibs}");
Console.WriteLine($" [{ (totalLibs > 0 && mappedLibs == totalLibs ? "x" : " ") }] All libraries mapped: {mappedLibs}/{totalLibs}");
}
private static void CheckModulePhase(Database db, int phase)
{
var totalModules = db.ExecuteScalar<long>("SELECT COUNT(*) FROM modules");
var doneModules = db.ExecuteScalar<long>("SELECT COUNT(*) FROM modules WHERE status IN ('complete', 'verified', 'n_a')");
var stubModules = db.ExecuteScalar<long>("SELECT COUNT(*) FROM modules WHERE status = 'stub'");
var totalFeatures = db.ExecuteScalar<long>("SELECT COUNT(*) FROM features");
var doneFeatures = db.ExecuteScalar<long>("SELECT COUNT(*) FROM features WHERE status IN ('complete', 'verified', 'n_a')");
var stubFeatures = db.ExecuteScalar<long>("SELECT COUNT(*) FROM features WHERE status = 'stub'");
var modPct = totalModules > 0 ? (double)doneModules / totalModules * 100 : 0;
var featPct = totalFeatures > 0 ? (double)doneFeatures / totalFeatures * 100 : 0;
Console.WriteLine($"Phase {phase} Progress:");
Console.WriteLine($" Modules: {doneModules}/{totalModules} complete ({modPct:F1}%), {stubModules} stubs");
Console.WriteLine($" Features: {doneFeatures}/{totalFeatures} complete ({featPct:F1}%), {stubFeatures} stubs");
// Show incomplete modules
var incomplete = db.Query(
"SELECT id, name, status FROM modules WHERE status NOT IN ('complete', 'verified', 'n_a') ORDER BY name");
if (incomplete.Count > 0)
{
Console.WriteLine($"\n Incomplete modules ({incomplete.Count}):");
foreach (var m in incomplete)
Console.WriteLine($" #{m["id"],-5} {m["name"],-30} {m["status"]}");
}
}
private static void CheckPhase7(Database db)
{
var totalTests = db.ExecuteScalar<long>("SELECT COUNT(*) FROM unit_tests");
var doneTests = db.ExecuteScalar<long>("SELECT COUNT(*) FROM unit_tests WHERE status IN ('complete', 'verified', 'n_a')");
var stubTests = db.ExecuteScalar<long>("SELECT COUNT(*) FROM unit_tests WHERE status = 'stub'");
var verifiedTests = db.ExecuteScalar<long>("SELECT COUNT(*) FROM unit_tests WHERE status = 'verified'");
var pct = totalTests > 0 ? (double)doneTests / totalTests * 100 : 0;
Console.WriteLine("Phase 7 Progress:");
Console.WriteLine($" Total tests: {totalTests}");
Console.WriteLine($" Complete: {doneTests - verifiedTests}");
Console.WriteLine($" Verified: {verifiedTests}");
Console.WriteLine($" Stubs: {stubTests}");
Console.WriteLine($" Not started: {totalTests - doneTests - stubTests}");
Console.WriteLine($" Progress: {pct:F1}%");
// Modules with incomplete tests
var modulesWithIncomplete = db.Query(@"
SELECT m.id, m.name, COUNT(*) as total,
SUM(CASE WHEN t.status IN ('complete', 'verified', 'n_a') THEN 1 ELSE 0 END) as done
FROM unit_tests t
JOIN modules m ON t.module_id = m.id
GROUP BY m.id, m.name
HAVING done < total
ORDER BY m.name");
if (modulesWithIncomplete.Count > 0)
{
Console.WriteLine($"\n Modules with incomplete tests ({modulesWithIncomplete.Count}):");
foreach (var m in modulesWithIncomplete)
Console.WriteLine($" #{m["id"],-5} {m["name"],-30} {m["done"]}/{m["total"]}");
}
}
}