Step 15: CLI wiring, prune, and sgardd daemon.

Local prune: garden.Prune() removes orphaned blobs. 2 tests.

CLI commands: sgard push, sgard pull (with SSH auth via --ssh-key
or ssh-agent), sgard prune (local by default, remote with --remote).

Server daemon: cmd/sgardd with --listen, --repo, --authorized-keys
flags. Runs gRPC server with optional SSH key auth interceptor.

Root command gains --remote and --ssh-key persistent flags with
resolveRemote() (flag > env > repo/remote file).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-24 00:03:51 -07:00
parent 4b841cdd82
commit 94963bb8d6
9 changed files with 420 additions and 14 deletions

31
garden/prune.go Normal file
View File

@@ -0,0 +1,31 @@
package garden
import "fmt"
// Prune removes orphaned blobs that are not referenced by any manifest entry.
// Returns the number of blobs removed.
func (g *Garden) Prune() (int, error) {
referenced := make(map[string]bool)
for _, e := range g.manifest.Files {
if e.Type == "file" && e.Hash != "" {
referenced[e.Hash] = true
}
}
allBlobs, err := g.store.List()
if err != nil {
return 0, fmt.Errorf("listing blobs: %w", err)
}
removed := 0
for _, hash := range allBlobs {
if !referenced[hash] {
if err := g.store.Delete(hash); err != nil {
return removed, fmt.Errorf("deleting blob %s: %w", hash, err)
}
removed++
}
}
return removed, nil
}