noz-cli/NozCli/Commands/StatusCommand.cs
2026-05-16 19:25:39 +02:00

55 lines
2.1 KiB
C#

using System.Security.Cryptography;
using System.Text;
using NozCli.Repl;
using Spectre.Console;
namespace NozCli.Commands;
public class StatusCommand : ICommand
{
public string Name => "status";
public string Description => "Show diff between a local folder and the server";
public string Usage => "status <local-path>";
public async Task ExecuteAsync(string[] args, ReplContext ctx)
{
var localPath = args.FirstOrDefault();
if (localPath is null) { AnsiConsole.MarkupLine("[red]Usage: status <local-path>[/]"); return; }
localPath = Path.GetFullPath(localPath);
if (!Directory.Exists(localPath)) { AnsiConsole.MarkupLine($"[red]Not found: {localPath}[/]"); return; }
var serverMap = ctx.NoteCache.ToDictionary(n => n.Slug, n => n.Hash ?? "");
var localFiles = Directory.EnumerateFiles(localPath, "*.md", SearchOption.AllDirectories)
.Where(f => !Path.GetFileName(f).StartsWith("_"));
var added = new List<string>();
var modified = new List<string>();
foreach (var file in localFiles)
{
var slug = Path.GetRelativePath(localPath, file).Replace(Path.DirectorySeparatorChar, '/').Replace(".md", "");
var markdown = await File.ReadAllTextAsync(file);
var localHash = Sha256(markdown);
if (!serverMap.ContainsKey(slug))
added.Add(slug);
else if (serverMap[slug] != localHash)
modified.Add(slug);
}
if (added.Count == 0 && modified.Count == 0)
{
AnsiConsole.MarkupLine("[green]✓ Everything up to date[/]");
return;
}
foreach (var s in added) AnsiConsole.MarkupLine($" [green]+[/] {s}");
foreach (var s in modified) AnsiConsole.MarkupLine($" [yellow]~[/] {s}");
AnsiConsole.MarkupLine($"\n[dim]{added.Count} new · {modified.Count} modified[/]");
}
private static string Sha256(string text) =>
Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(text))).ToLower();
}