Files
kopia/cli/command_policy_edit.go
Jarek Kowalski e03971fc59 Upgraded linter to v1.33.0 (#734)
* linter: upgraded to 1.33, disabled some linters

* lint: fixed 'errorlint' errors

This ensures that all error comparisons use errors.Is() or errors.As().
We will be wrapping more errors going forward so it's important that
error checks are not strict everywhere.

Verified that there are no exceptions for errorlint linter which
guarantees that.

* lint: fixed or suppressed wrapcheck errors

* lint: nolintlint and misc cleanups

Co-authored-by: Julio López <julio+gh@kasten.io>
2020-12-21 22:39:22 -08:00

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(repositoryAction(editPolicy))
}
func editPolicy(ctx context.Context, rep repo.Repository) 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:]
}