mirror of
https://github.com/kopia/kopia.git
synced 2026-07-11 22:26:11 -04:00
* fix(cli): only run automatic maintenance after data-modifying operations Automatic maintenance previously ran after any successful repository-writer command, including control-only operations such as `policy set`, `acl ...` and `user ...`. Make repositoryWriterAction skip maintenance by default and add repositoryWriterActionWithMaintenance, used only by data-modifying commands (snapshot create/delete/expire/migrate/fix-*/copy-move-history/pin, manifest delete). Fixes #3174 * fix(cli): treat snapshot pin and manifest delete as control-only Per review, move both to repositoryWriterAction so they no longer trigger opportunistic automatic maintenance. pin orphans no content and manifest delete is a low-level operation not meant for direct use; any content it orphans is reclaimed at the next scheduled maintenance. --------- Co-authored-by: max <max@example.com>
79 lines
2.1 KiB
Go
79 lines
2.1 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"sort"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/kopia/kopia/repo"
|
|
"github.com/kopia/kopia/snapshot"
|
|
"github.com/kopia/kopia/snapshot/policy"
|
|
)
|
|
|
|
type commandSnapshotExpire struct {
|
|
snapshotExpireAll bool
|
|
snapshotExpirePaths []string
|
|
snapshotExpireDelete bool
|
|
}
|
|
|
|
func (c *commandSnapshotExpire) setup(svc appServices, parent commandParent) {
|
|
cmd := parent.Command("expire", "Remove old snapshots according to defined expiration policies.")
|
|
|
|
cmd.Flag("all", "Expire all snapshots").BoolVar(&c.snapshotExpireAll)
|
|
cmd.Arg("path", "Expire snapshots for given paths only").StringsVar(&c.snapshotExpirePaths)
|
|
cmd.Flag("delete", "Whether to actually delete snapshots").BoolVar(&c.snapshotExpireDelete)
|
|
cmd.Action(svc.repositoryWriterActionWithMaintenance(c.run))
|
|
}
|
|
|
|
func (c *commandSnapshotExpire) getSnapshotSourcesToExpire(ctx context.Context, rep repo.Repository) ([]snapshot.SourceInfo, error) {
|
|
if c.snapshotExpireAll {
|
|
//nolint:wrapcheck
|
|
return snapshot.ListSources(ctx, rep)
|
|
}
|
|
|
|
var result []snapshot.SourceInfo
|
|
|
|
for _, p := range c.snapshotExpirePaths {
|
|
src, err := snapshot.ParseSourceInfo(p, rep.ClientOptions().Hostname, rep.ClientOptions().Username)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "unable to parse %q", p)
|
|
}
|
|
|
|
result = append(result, src)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (c *commandSnapshotExpire) run(ctx context.Context, rep repo.RepositoryWriter) error {
|
|
sources, err := c.getSnapshotSourcesToExpire(ctx, rep)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
sort.Slice(sources, func(i, j int) bool {
|
|
return sources[i].String() < sources[j].String()
|
|
})
|
|
|
|
for _, src := range sources {
|
|
deleted, err := policy.ApplyRetentionPolicy(ctx, rep, src, c.snapshotExpireDelete)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "error applying retention policy to %v", src)
|
|
}
|
|
|
|
if len(deleted) == 0 {
|
|
log(ctx).Infof("Nothing to delete for %v.", src)
|
|
continue
|
|
}
|
|
|
|
if c.snapshotExpireDelete {
|
|
log(ctx).Infof("Deleted %v snapshots of %v...", len(deleted), src)
|
|
} else {
|
|
log(ctx).Infof("%v snapshot(s) of %v would be deleted. Pass --delete to do it.", len(deleted), src)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|