package cli import ( "github.com/spf13/cobra" "sneak.berlin/go/vaultik/internal/log" "sneak.berlin/go/vaultik/internal/vaultik" ) // NewPruneCommand creates the prune command func NewPruneCommand() *cobra.Command { opts := &vaultik.PruneOptions{} cmd := &cobra.Command{ Use: "prune", Short: "Tidy local database and remote storage", Long: `Removes orphaned data from the local index database, and unreferenced blobs and directories under metadata/ with no manifest from the backup destination store. Local cleanup drops incomplete snapshots and any files, chunks, or blobs no longer referenced by a completed snapshot. Remote cleanup scans every snapshot manifest in the destination store, builds the set of still-referenced blob hashes, and deletes any blob not in that set that is older than prune_grace_period (default 24h). A newer one is kept: it may belong to a backup still running, on this host or another sharing the destination store, that has not yet uploaded its manifest. The grace period does not protect a blob such a backup reuses from an earlier run that stopped before its manifest: that blob keeps the time of its first upload, so it can be deleted. Remote cleanup also deletes each directory under metadata/ with no manifest, as a backup that stopped before its manifest leaves, once all its objects are older than prune_grace_period and its snapshot is not in the local index. Snapshot create --prune runs the same cleanup automatically; this command is the manual entry point for the same work (e.g. after a crashed backup or to reclaim storage). Snapshot remove leaves blobs in place; run this command afterwards to delete the ones no longer referenced.`, Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { // Use unified config resolution configPath, err := ResolveConfigPath() if err != nil { return err } // Use the app framework like other commands rootFlags := GetRootFlags() return RunOperation(cmd.Context(), AppOptions{ ConfigPath: configPath, LogOptions: log.Options{ Verbose: rootFlags.Verbose, Debug: rootFlags.Debug, Quiet: rootFlags.Quiet, JSON: opts.JSON, }, Mode: mutating, }, func(v *vaultik.Vaultik) error { return v.Prune(opts) }, func(err error) { log.Error("Prune operation failed", "error", err) ReportErrorf("Prune failed: %v", err) }) }, } cmd.Flags().BoolVar(&opts.Force, "force", false, "Skip confirmation prompt") cmd.Flags().BoolVar(&opts.JSON, "json", false, "Output pruning stats as JSON; skips the confirmation prompt, as --force does") return cmd }