mirror of
https://github.com/kopia/kopia.git
synced 2025-12-23 22:57:50 -05:00
130 lines
3.0 KiB
Go
130 lines
3.0 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"os"
|
|
"slices"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/kopia/kopia/repo"
|
|
"github.com/kopia/kopia/snapshot"
|
|
"github.com/kopia/kopia/snapshot/policy"
|
|
)
|
|
|
|
type commandPolicyImport struct {
|
|
policyTargetFlags
|
|
filePath string
|
|
allowUnknownFields bool
|
|
deleteOtherPolicies bool
|
|
|
|
svc appServices
|
|
}
|
|
|
|
func (c *commandPolicyImport) setup(svc appServices, parent commandParent) {
|
|
cmd := parent.Command("import", "Imports policies from a specified file, or stdin if no file is specified.")
|
|
cmd.Flag("from-file", "File path to import from").StringVar(&c.filePath)
|
|
cmd.Flag("allow-unknown-fields", "Allow unknown fields in the policy file").BoolVar(&c.allowUnknownFields)
|
|
cmd.Flag("delete-other-policies", "Delete all other policies, keeping only those that got imported").BoolVar(&c.deleteOtherPolicies)
|
|
|
|
c.policyTargetFlags.setup(cmd)
|
|
c.svc = svc
|
|
|
|
cmd.Action(svc.repositoryWriterAction(c.run))
|
|
}
|
|
|
|
func (c *commandPolicyImport) run(ctx context.Context, rep repo.RepositoryWriter) error {
|
|
var input io.Reader
|
|
|
|
var err error
|
|
|
|
if c.filePath != "" {
|
|
file, err := os.Open(c.filePath)
|
|
if err != nil {
|
|
return errors.Wrap(err, "unable to read policy file")
|
|
}
|
|
|
|
defer file.Close() //nolint:errcheck
|
|
|
|
input = file
|
|
} else {
|
|
input = c.svc.stdin()
|
|
}
|
|
|
|
policies := make(map[string]*policy.Policy)
|
|
d := json.NewDecoder(input)
|
|
|
|
if !c.allowUnknownFields {
|
|
d.DisallowUnknownFields()
|
|
}
|
|
|
|
err = d.Decode(&policies)
|
|
if err != nil {
|
|
return errors.Wrap(err, "unable to decode policy file as valid json")
|
|
}
|
|
|
|
var targetLimit []snapshot.SourceInfo
|
|
|
|
if c.global || len(c.targets) > 0 {
|
|
targetLimit, err = c.policyTargets(ctx, rep)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
shouldImportSource := func(target snapshot.SourceInfo) bool {
|
|
if targetLimit == nil {
|
|
return true
|
|
}
|
|
|
|
return slices.Contains(targetLimit, target)
|
|
}
|
|
|
|
importedSources := make([]string, 0, len(policies))
|
|
|
|
for ts, newPolicy := range policies {
|
|
target, err := snapshot.ParseSourceInfo(ts, rep.ClientOptions().Hostname, rep.ClientOptions().Username)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "unable to parse source info: %q", ts)
|
|
}
|
|
|
|
if !shouldImportSource(target) {
|
|
continue
|
|
}
|
|
// used for deleteOtherPolicies
|
|
importedSources = append(importedSources, ts)
|
|
|
|
if err := policy.SetPolicy(ctx, rep, target, newPolicy); err != nil {
|
|
return errors.Wrapf(err, "can't save policy for %v", target)
|
|
}
|
|
}
|
|
|
|
if c.deleteOtherPolicies {
|
|
err := deleteOthers(ctx, rep, importedSources)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func deleteOthers(ctx context.Context, rep repo.RepositoryWriter, importedSources []string) error {
|
|
ps, err := policy.ListPolicies(ctx, rep)
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to list policies")
|
|
}
|
|
|
|
for _, p := range ps {
|
|
if !slices.Contains(importedSources, p.Target().String()) {
|
|
if err := policy.RemovePolicy(ctx, rep, p.Target()); err != nil {
|
|
return errors.Wrapf(err, "can't delete policy for %v", p.Target())
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|