mirror of
https://github.com/kopia/kopia.git
synced 2026-03-17 21:56:14 -04:00
cli: major refactoring of how CLI commands are registered The goal is to eliminate flags as global variables to allow for better testing. Each command and subcommand and most sets of flags are now their own struct with 'setup()' methods that attached the flags or subcommand to the provided parent. This change is 94.3% mechanical, but is fully organic and hand-made. * introduced cli.appServices interface which provides the environment in which commands run * remove auto-maintenance global flag * removed globals in memory_tracking.go * removed globals from cli_progress.go * removed globals from the update_check.go * moved configPath into TheApp * removed remaining globals from config.go * refactored logfile to get rid of global variables * removed 'app' global variable * linter fixes * fixed password_*.go build * fixed BSD build
78 lines
2.5 KiB
Go
78 lines
2.5 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/kopia/kopia/repo"
|
|
"github.com/kopia/kopia/repo/manifest"
|
|
"github.com/kopia/kopia/repo/object"
|
|
"github.com/kopia/kopia/snapshot"
|
|
)
|
|
|
|
type commandSnapshotDelete struct {
|
|
snapshotDeleteIDs []string
|
|
snapshotDeleteConfirm bool
|
|
}
|
|
|
|
func (c *commandSnapshotDelete) setup(svc appServices, parent commandParent) {
|
|
cmd := parent.Command("delete", "Explicitly delete a snapshot by providing a snapshot ID.")
|
|
cmd.Arg("id", "Snapshot ID or root object ID to be deleted").Required().StringsVar(&c.snapshotDeleteIDs)
|
|
cmd.Flag("delete", "Confirm deletion").BoolVar(&c.snapshotDeleteConfirm)
|
|
// hidden flag for backwards compatibility
|
|
cmd.Flag("unsafe-ignore-source", "Alias for --delete").Hidden().BoolVar(&c.snapshotDeleteConfirm)
|
|
cmd.Action(svc.repositoryWriterAction(c.run))
|
|
}
|
|
|
|
func (c *commandSnapshotDelete) run(ctx context.Context, rep repo.RepositoryWriter) error {
|
|
for _, id := range c.snapshotDeleteIDs {
|
|
m, err := snapshot.LoadSnapshot(ctx, rep, manifest.ID(id))
|
|
if err == nil {
|
|
// snapshot found by manifest ID, delete it directly.
|
|
if err = c.deleteSnapshot(ctx, rep, m); err != nil {
|
|
return errors.Wrapf(err, "error deleting %v", id)
|
|
}
|
|
} else if !errors.Is(err, snapshot.ErrSnapshotNotFound) {
|
|
return errors.Wrapf(err, "error loading snapshot %v", id)
|
|
} else if err := c.deleteSnapshotsByRootObjectID(ctx, rep, object.ID(id)); err != nil {
|
|
return errors.Wrapf(err, "error deleting snapshots by root ID %v", id)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *commandSnapshotDelete) deleteSnapshot(ctx context.Context, rep repo.RepositoryWriter, m *snapshot.Manifest) error {
|
|
desc := fmt.Sprintf("snapshot %v of %v at %v", m.ID, m.Source, formatTimestamp(m.StartTime))
|
|
|
|
if !c.snapshotDeleteConfirm {
|
|
log(ctx).Infof("Would delete %v (pass --delete to confirm)\n", desc)
|
|
return nil
|
|
}
|
|
|
|
log(ctx).Infof("Deleting %v...", desc)
|
|
|
|
return rep.DeleteManifest(ctx, m.ID)
|
|
}
|
|
|
|
func (c *commandSnapshotDelete) deleteSnapshotsByRootObjectID(ctx context.Context, rep repo.RepositoryWriter, rootID object.ID) error {
|
|
manifests, err := snapshot.FindSnapshotsByRootObjectID(ctx, rep, rootID)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "unable to find snapshots by root %v", rootID)
|
|
}
|
|
|
|
if len(manifests) == 0 {
|
|
return errors.Errorf("no snapshots matched %v", rootID)
|
|
}
|
|
|
|
for _, m := range manifests {
|
|
if err := c.deleteSnapshot(ctx, rep, m); err != nil {
|
|
return errors.Wrap(err, "error deleting")
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|