package cli import ( "context" "encoding/json" stderrors "errors" "fmt" "io" "os" "github.com/pkg/errors" "github.com/kopia/kopia/internal/impossible" "github.com/kopia/kopia/repo" "github.com/kopia/kopia/snapshot/policy" ) type commandPolicyExport struct { policyTargetFlags filePath string overwrite bool jsonIndent bool svc appServices } const exportFilePerms = 0o600 func (c *commandPolicyExport) setup(svc appServices, parent commandParent) { cmd := parent.Command("export", "Exports the policies to the specified file, or to stdout if none is specified.") cmd.Flag("to-file", "File path to export to").StringVar(&c.filePath) cmd.Flag("overwrite", "Overwrite the file if it exists").BoolVar(&c.overwrite) cmd.Flag("json-indent", "Output result in indented JSON format").Hidden().BoolVar(&c.jsonIndent) c.policyTargetFlags.setup(cmd) c.svc = svc cmd.Action(svc.repositoryReaderAction(c.run)) } func (c *commandPolicyExport) run(ctx context.Context, rep repo.Repository) error { output, err := getOutput(c) if err != nil { return err } if file, ok := output.(*os.File); ok { defer func() { err = stderrors.Join(err, file.Close()) }() } policies := make(map[string]*policy.Policy) if c.global || len(c.targets) > 0 { targets, err := c.policyTargets(ctx, rep) if err != nil { return err } for _, target := range targets { definedPolicy, err := policy.GetDefinedPolicy(ctx, rep, target) if err != nil { return errors.Wrapf(err, "can't get defined policy for %q", target) } policies[target.String()] = definedPolicy } } else { ps, err := policy.ListPolicies(ctx, rep) if err != nil { return errors.Wrap(err, "failed to list policies") } for _, policy := range ps { policies[policy.Target().String()] = policy } } var toWrite []byte if c.jsonIndent { toWrite, err = json.MarshalIndent(policies, "", " ") } else { toWrite, err = json.Marshal(policies) } impossible.PanicOnError(err) _, err = fmt.Fprintf(output, "%s\n", toWrite) return errors.Wrap(err, "unable to write policy to output") } func getOutput(c *commandPolicyExport) (io.Writer, error) { var err error if c.filePath == "" { if c.overwrite { return nil, errors.New("overwrite was passed but no file path was given") } return c.svc.stdout(), nil } var file *os.File if c.overwrite { file, err = os.Create(c.filePath) } else { file, err = os.OpenFile(c.filePath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, exportFilePerms) if os.IsExist(err) { return nil, errors.Wrap(err, "file already exists and overwrite flag is not set") } } if err != nil { return nil, errors.Wrap(err, "error opening file to write to") } return file, nil }