package cli import ( "context" "os" "git.eeqj.de/sneak/vaultik/internal/log" "git.eeqj.de/sneak/vaultik/internal/vaultik" "github.com/spf13/cobra" "go.uber.org/fx" ) // NewPruneCommand creates the prune command func NewPruneCommand() *cobra.Command { opts := &vaultik.PruneOptions{} cmd := &cobra.Command{ Use: "prune", Short: "Remove unreferenced blobs", Long: `Removes blobs that are not referenced by any snapshot. This command scans all snapshots and their manifests to build a list of referenced blobs, then removes any blobs in storage that are not in this list. Use this command after deleting snapshots with 'vaultik purge' to reclaim storage space.`, Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { // Use unified config resolution configPath, err := ResolveConfigPath() if err != nil { return err } // Use the app framework like other commands rootFlags := GetRootFlags() return RunWithApp(cmd.Context(), AppOptions{ ConfigPath: configPath, LogOptions: log.LogOptions{ Verbose: rootFlags.Verbose, Debug: rootFlags.Debug, }, Modules: []fx.Option{}, Invokes: []fx.Option{ fx.Invoke(func(v *vaultik.Vaultik, lc fx.Lifecycle) { lc.Append(fx.Hook{ OnStart: func(ctx context.Context) error { // Start the prune operation in a goroutine go func() { // Run the prune operation if err := v.PruneBlobs(opts); err != nil { if err != context.Canceled { log.Error("Prune operation failed", "error", err) os.Exit(1) } } // Shutdown the app when prune completes if err := v.Shutdowner.Shutdown(); err != nil { log.Error("Failed to shutdown", "error", err) } }() return nil }, OnStop: func(ctx context.Context) error { log.Debug("Stopping prune operation") v.Cancel() return nil }, }) }), }, }) }, } cmd.Flags().BoolVar(&opts.Force, "force", false, "Skip confirmation prompt") return cmd }