147 lines
6.6 KiB
C#
147 lines
6.6 KiB
C#
using System.CommandLine;
|
|
using NatsNet.PortTracker.Data;
|
|
|
|
namespace NatsNet.PortTracker.Commands;
|
|
|
|
public static class DependencyCommands
|
|
{
|
|
public static Command Create(Option<string> dbOption, Option<string> schemaOption)
|
|
{
|
|
var depCommand = new Command("dependency", "Manage dependencies");
|
|
|
|
// show
|
|
var showType = new Argument<string>("type") { Description = "Item type (module, feature, unit_test)" };
|
|
var showId = new Argument<int>("id") { Description = "Item ID" };
|
|
var showCmd = new Command("show", "Show dependencies for an item");
|
|
showCmd.Add(showType);
|
|
showCmd.Add(showId);
|
|
showCmd.SetAction(parseResult =>
|
|
{
|
|
var dbPath = parseResult.GetValue(dbOption)!;
|
|
var type = parseResult.GetValue(showType)!;
|
|
var id = parseResult.GetValue(showId);
|
|
using var db = new Database(dbPath);
|
|
|
|
var deps = db.Query(
|
|
"SELECT target_type, target_id, dependency_kind FROM dependencies WHERE source_type = @type AND source_id = @id",
|
|
("@type", type), ("@id", id));
|
|
Console.WriteLine($"Dependencies of {type} #{id} ({deps.Count}):");
|
|
foreach (var d in deps)
|
|
Console.WriteLine($" -> {d["target_type"]} #{d["target_id"]} [{d["dependency_kind"]}]");
|
|
|
|
var rdeps = db.Query(
|
|
"SELECT source_type, source_id, dependency_kind FROM dependencies WHERE target_type = @type AND target_id = @id",
|
|
("@type", type), ("@id", id));
|
|
Console.WriteLine($"\nReverse dependencies (depends on {type} #{id}) ({rdeps.Count}):");
|
|
foreach (var d in rdeps)
|
|
Console.WriteLine($" <- {d["source_type"]} #{d["source_id"]} [{d["dependency_kind"]}]");
|
|
});
|
|
|
|
// blocked
|
|
var blockedCmd = new Command("blocked", "Show items blocked by unported dependencies");
|
|
blockedCmd.SetAction(parseResult =>
|
|
{
|
|
var dbPath = parseResult.GetValue(dbOption)!;
|
|
using var db = new Database(dbPath);
|
|
|
|
var sql = @"
|
|
SELECT 'module' as item_type, m.id, m.name, m.status, d.target_type, d.target_id, d.dependency_kind
|
|
FROM modules m
|
|
JOIN dependencies d ON d.source_type = 'module' AND d.source_id = m.id
|
|
WHERE m.status NOT IN ('complete', 'verified', 'n_a')
|
|
AND (
|
|
(d.target_type = 'module' AND d.target_id IN (SELECT id FROM modules WHERE status NOT IN ('complete', 'verified', 'n_a')))
|
|
OR (d.target_type = 'feature' AND d.target_id IN (SELECT id FROM features WHERE status NOT IN ('complete', 'verified', 'n_a')))
|
|
OR (d.target_type = 'unit_test' AND d.target_id IN (SELECT id FROM unit_tests WHERE status NOT IN ('complete', 'verified', 'n_a')))
|
|
)
|
|
UNION ALL
|
|
SELECT 'feature' as item_type, f.id, f.name, f.status, d.target_type, d.target_id, d.dependency_kind
|
|
FROM features f
|
|
JOIN dependencies d ON d.source_type = 'feature' AND d.source_id = f.id
|
|
WHERE f.status NOT IN ('complete', 'verified', 'n_a')
|
|
AND (
|
|
(d.target_type = 'module' AND d.target_id IN (SELECT id FROM modules WHERE status NOT IN ('complete', 'verified', 'n_a')))
|
|
OR (d.target_type = 'feature' AND d.target_id IN (SELECT id FROM features WHERE status NOT IN ('complete', 'verified', 'n_a')))
|
|
OR (d.target_type = 'unit_test' AND d.target_id IN (SELECT id FROM unit_tests WHERE status NOT IN ('complete', 'verified', 'n_a')))
|
|
)
|
|
ORDER BY 1, 2";
|
|
|
|
var rows = db.Query(sql);
|
|
if (rows.Count == 0)
|
|
{
|
|
Console.WriteLine("No blocked items found.");
|
|
return;
|
|
}
|
|
Console.WriteLine($"{"Type",-10} {"ID",-5} {"Name",-30} {"Status",-15} {"Blocked By",-15} {"Dep ID",-8} {"Kind",-10}");
|
|
Console.WriteLine(new string('-', 93));
|
|
foreach (var row in rows)
|
|
{
|
|
Console.WriteLine($"{row["item_type"],-10} {row["id"],-5} {Truncate(row["name"]?.ToString(), 29),-30} {row["status"],-15} {row["target_type"],-15} {row["target_id"],-8} {row["dependency_kind"],-10}");
|
|
}
|
|
Console.WriteLine($"\n{rows.Count} blocking relationships found.");
|
|
});
|
|
|
|
// ready
|
|
var readyCmd = new Command("ready", "Show items ready to port (no unported dependencies)");
|
|
readyCmd.SetAction(parseResult =>
|
|
{
|
|
var dbPath = parseResult.GetValue(dbOption)!;
|
|
using var db = new Database(dbPath);
|
|
|
|
var sql = @"
|
|
SELECT 'module' as item_type, m.id, m.name, m.status
|
|
FROM modules m
|
|
WHERE m.status IN ('not_started', 'stub')
|
|
AND NOT EXISTS (
|
|
SELECT 1 FROM dependencies d
|
|
WHERE d.source_type = 'module' AND d.source_id = m.id
|
|
AND (
|
|
(d.target_type = 'module' AND d.target_id IN (SELECT id FROM modules WHERE status NOT IN ('complete', 'verified', 'n_a')))
|
|
OR (d.target_type = 'feature' AND d.target_id IN (SELECT id FROM features WHERE status NOT IN ('complete', 'verified', 'n_a')))
|
|
OR (d.target_type = 'unit_test' AND d.target_id IN (SELECT id FROM unit_tests WHERE status NOT IN ('complete', 'verified', 'n_a')))
|
|
)
|
|
)
|
|
UNION ALL
|
|
SELECT 'feature' as item_type, f.id, f.name, f.status
|
|
FROM features f
|
|
WHERE f.status IN ('not_started', 'stub')
|
|
AND NOT EXISTS (
|
|
SELECT 1 FROM dependencies d
|
|
WHERE d.source_type = 'feature' AND d.source_id = f.id
|
|
AND (
|
|
(d.target_type = 'module' AND d.target_id IN (SELECT id FROM modules WHERE status NOT IN ('complete', 'verified', 'n_a')))
|
|
OR (d.target_type = 'feature' AND d.target_id IN (SELECT id FROM features WHERE status NOT IN ('complete', 'verified', 'n_a')))
|
|
OR (d.target_type = 'unit_test' AND d.target_id IN (SELECT id FROM unit_tests WHERE status NOT IN ('complete', 'verified', 'n_a')))
|
|
)
|
|
)
|
|
ORDER BY 1, 2";
|
|
|
|
var rows = db.Query(sql);
|
|
if (rows.Count == 0)
|
|
{
|
|
Console.WriteLine("No items are ready to port (all items either have unported deps or are already done).");
|
|
return;
|
|
}
|
|
Console.WriteLine($"{"Type",-10} {"ID",-5} {"Name",-40} {"Status",-15}");
|
|
Console.WriteLine(new string('-', 70));
|
|
foreach (var row in rows)
|
|
{
|
|
Console.WriteLine($"{row["item_type"],-10} {row["id"],-5} {Truncate(row["name"]?.ToString(), 39),-40} {row["status"],-15}");
|
|
}
|
|
Console.WriteLine($"\n{rows.Count} items ready to port.");
|
|
});
|
|
|
|
depCommand.Add(showCmd);
|
|
depCommand.Add(blockedCmd);
|
|
depCommand.Add(readyCmd);
|
|
|
|
return depCommand;
|
|
}
|
|
|
|
private static string Truncate(string? s, int maxLen)
|
|
{
|
|
if (s is null) return "";
|
|
return s.Length <= maxLen ? s : s[..(maxLen - 2)] + "..";
|
|
}
|
|
}
|