87 lines
3 KiB
C#
87 lines
3 KiB
C#
using NozCli.Repl;
|
|
using Spectre.Console;
|
|
|
|
namespace NozCli.Commands;
|
|
|
|
/// push <local-path> — reads .md files from a local directory and uploads changed ones.
|
|
public class PushCommand : ICommand
|
|
{
|
|
public string Name => "push";
|
|
public string Description => "Push local markdown files to the server";
|
|
public string Usage => "push <local-path> [--all]";
|
|
|
|
public async Task ExecuteAsync(string[] args, ReplContext ctx)
|
|
{
|
|
var localPath = args.FirstOrDefault(a => !a.StartsWith("--"));
|
|
var force = args.Contains("--all");
|
|
|
|
if (localPath is null)
|
|
{
|
|
AnsiConsole.MarkupLine("[red]Usage: push <local-path> [--all][/]");
|
|
return;
|
|
}
|
|
|
|
localPath = Path.GetFullPath(localPath);
|
|
if (!Directory.Exists(localPath))
|
|
{
|
|
AnsiConsole.MarkupLine($"[red]Directory not found: {localPath}[/]");
|
|
return;
|
|
}
|
|
|
|
var files = Directory.EnumerateFiles(localPath, "*.md", SearchOption.AllDirectories)
|
|
.Where(f => !Path.GetFileName(f).StartsWith("_"))
|
|
.ToList();
|
|
|
|
if (files.Count == 0)
|
|
{
|
|
AnsiConsole.MarkupLine("[yellow]No markdown files found.[/]");
|
|
return;
|
|
}
|
|
|
|
// Build slug → server hash map for incremental push
|
|
var serverHashes = ctx.NoteCache.ToDictionary(n => n.Slug, n => n.Hash ?? "");
|
|
|
|
int pushed = 0, skipped = 0, failed = 0;
|
|
|
|
await AnsiConsole.Progress()
|
|
.Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new SpinnerColumn())
|
|
.StartAsync(async progress =>
|
|
{
|
|
var task = progress.AddTask("Pushing notes…", maxValue: files.Count);
|
|
|
|
foreach (var file in files)
|
|
{
|
|
var relative = Path.GetRelativePath(localPath, file);
|
|
var slug = relative.Replace(Path.DirectorySeparatorChar, '/').Replace(".md", "");
|
|
|
|
var markdown = await File.ReadAllTextAsync(file);
|
|
var localHash = NozCli.Core.Client.HashHelper.Sha256(markdown);
|
|
|
|
if (!force && serverHashes.TryGetValue(slug, out var serverHash) && serverHash == localHash)
|
|
{
|
|
skipped++;
|
|
task.Increment(1);
|
|
continue;
|
|
}
|
|
|
|
try
|
|
{
|
|
await ctx.Api.PutNoteAsync(slug, markdown);
|
|
pushed++;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
AnsiConsole.MarkupLine($"[red]✗ {slug}: {ex.Message}[/]");
|
|
failed++;
|
|
}
|
|
|
|
task.Increment(1);
|
|
}
|
|
});
|
|
|
|
AnsiConsole.MarkupLine($"[green]↑ {pushed} pushed[/] [dim]{skipped} unchanged {(failed > 0 ? $"[red]{failed} failed[/]" : "")}[/]");
|
|
|
|
// Refresh note cache
|
|
ctx.NoteCache = await ctx.Api.GetNotesAsync();
|
|
}
|
|
}
|