mirror of
https://github.com/kopia/kopia.git
synced 2026-01-16 18:37:52 -05:00
Reader methods go to repo.Reader and write methods go to repo.Writer Switched usage to new interfaces based on linter errors.
136 lines
3.5 KiB
Go
136 lines
3.5 KiB
Go
package cli
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/kopia/kopia/internal/editor"
|
|
"github.com/kopia/kopia/repo"
|
|
"github.com/kopia/kopia/snapshot/policy"
|
|
)
|
|
|
|
const policyEditHelpText = `
|
|
# Editing policy for '%v'
|
|
|
|
# Make changes to the policy, save your file and exit the editor.
|
|
# The output must be valid JSON.
|
|
|
|
# Lines starting with # are comments and automatically removed.
|
|
|
|
`
|
|
|
|
const policyEditRetentionHelpText = ` # Retention for snapshots of this directory. Options include:
|
|
# "keepLatest": number
|
|
# "keepDaily": number
|
|
# "keepHourly": number
|
|
# "keepWeekly": number
|
|
# "keepMonthly": number
|
|
# "keepAnnual": number
|
|
`
|
|
|
|
const policyEditFilesHelpText = `
|
|
# Which files to include in snapshots. Options include:
|
|
# "ignore": ["*.ext", "*.ext2"]
|
|
# "dotIgnoreFiles": [".gitignore", ".kopiaignore"]
|
|
# "maxFileSize": number
|
|
# "noParentDotFiles": true
|
|
# "noParentIgnore": true
|
|
# "oneFileSystem": false
|
|
`
|
|
|
|
const policyEditSchedulingHelpText = `
|
|
# Snapshot scheduling options. Options include:
|
|
# "intervalSeconds": number /* 86400-day, 3600-hour, 60-minute */
|
|
# "timesOfDay": [{"hour":H,"min":M},{"hour":H,"min":M}]
|
|
`
|
|
|
|
var (
|
|
policyEditCommand = policyCommands.Command("edit", "Set snapshot policy for a single directory, user@host or a global policy.")
|
|
policyEditTargets = policyEditCommand.Arg("target", "Target of a policy ('global','user@host','@host') or a path").Strings()
|
|
policyEditGlobal = policyEditCommand.Flag("global", "Set global policy").Bool()
|
|
)
|
|
|
|
func init() {
|
|
policyEditCommand.Action(repositoryWriterAction(editPolicy))
|
|
}
|
|
|
|
func editPolicy(ctx context.Context, rep repo.Writer) error {
|
|
targets, err := policyTargets(ctx, rep, policyEditGlobal, policyEditTargets)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, target := range targets {
|
|
original, err := policy.GetDefinedPolicy(ctx, rep, target)
|
|
if errors.Is(err, policy.ErrPolicyNotFound) {
|
|
original = &policy.Policy{}
|
|
}
|
|
|
|
log(ctx).Infof("Editing policy for %v using external editor...", target)
|
|
|
|
s := policyEditHelpText + prettyJSON(original)
|
|
s = insertHelpText(s, ` "retention": {`, policyEditRetentionHelpText)
|
|
s = insertHelpText(s, ` "files": {`, policyEditFilesHelpText)
|
|
s = insertHelpText(s, ` "scheduling": {`, policyEditSchedulingHelpText)
|
|
|
|
var updated *policy.Policy
|
|
|
|
if err := editor.EditLoop(ctx, "policy.conf", s, func(edited string) error {
|
|
updated = &policy.Policy{}
|
|
d := json.NewDecoder(bytes.NewBufferString(edited))
|
|
d.DisallowUnknownFields()
|
|
return d.Decode(updated)
|
|
}); err != nil {
|
|
return errors.Wrap(err, "unable to launch editor")
|
|
}
|
|
|
|
if jsonEqual(updated, original) {
|
|
log(ctx).Infof("Policy for %v unchanged", target)
|
|
continue
|
|
}
|
|
|
|
log(ctx).Infof("Updated policy for %v\n%v", target, prettyJSON(updated))
|
|
|
|
fmt.Print("Save updated policy? (y/N) ")
|
|
|
|
var shouldSave string
|
|
|
|
fmt.Scanf("%v", &shouldSave)
|
|
|
|
if strings.HasPrefix(strings.ToLower(shouldSave), "y") {
|
|
if err := policy.SetPolicy(ctx, rep, target, updated); err != nil {
|
|
return errors.Wrapf(err, "can't save policy for %v", target)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func prettyJSON(v interface{}) string {
|
|
var b bytes.Buffer
|
|
e := json.NewEncoder(&b)
|
|
e.SetIndent("", " ")
|
|
e.Encode(v) //nolint:errcheck
|
|
|
|
return b.String()
|
|
}
|
|
|
|
func jsonEqual(v1, v2 interface{}) bool {
|
|
return prettyJSON(v1) == prettyJSON(v2)
|
|
}
|
|
|
|
func insertHelpText(s, lookFor, help string) string {
|
|
p := strings.Index(s, lookFor)
|
|
if p < 0 {
|
|
return s
|
|
}
|
|
|
|
return s[0:p] + help + s[p:]
|
|
}
|