mirror of
https://github.com/kopia/kopia.git
synced 2026-03-15 21:01:37 -04:00
This is mostly mechanical and changes how loggers are instantiated. Logger is now associated with a context, passed around all methods, (most methods had ctx, but had to add it in a few missing places). By default Kopia does not produce any logs, but it can be overridden, either locally for a nested context, by calling ctx = logging.WithLogger(ctx, newLoggerFunc) To override logs globally, call logging.SetDefaultLogger(newLoggerFunc) This refactoring allowed removing dependency from Kopia repo and go-logging library (the CLI still uses it, though). It is now also possible to have all test methods emit logs using t.Logf() so that they show up in failure reports, which should make debugging of test failures suck less.
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
|
|
`
|
|
|
|
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() {
|
|
addUserAndHostFlags(policyEditCommand)
|
|
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 err == policy.ErrPolicyNotFound {
|
|
original = &policy.Policy{}
|
|
}
|
|
|
|
printStderr("Editing policy for %v using external editor...\n", 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 err
|
|
}
|
|
|
|
if jsonEqual(updated, original) {
|
|
printStderr("Policy for %v unchanged\n", target)
|
|
continue
|
|
}
|
|
|
|
printStderr("Updated policy for %v\n%v\n", target, prettyJSON(updated))
|
|
|
|
fmt.Print("Save updated policy? (y/N) ")
|
|
|
|
var shouldSave string
|
|
|
|
fmt.Scanf("%v", &shouldSave) //nolint:errcheck
|
|
|
|
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:]
|
|
}
|