refactor to use constructor functions to create cobra commands

This allows getting rid of the global options variables
This commit is contained in:
Michael Eischer 2025-02-06 23:02:00 +01:00
parent dc9b6378f3
commit aacd6a47e3
35 changed files with 755 additions and 602 deletions

View File

@ -31,7 +31,10 @@ import (
"github.com/restic/restic/internal/ui/termstatus" "github.com/restic/restic/internal/ui/termstatus"
) )
var cmdBackup = &cobra.Command{ func newBackupCommand() *cobra.Command {
var opts BackupOptions
cmd := &cobra.Command{
Use: "backup [flags] [FILE/DIR] ...", Use: "backup [flags] [FILE/DIR] ...",
Short: "Create a new backup of files and/or directories", Short: "Create a new backup of files and/or directories",
Long: ` Long: `
@ -49,13 +52,13 @@ Exit status is 11 if the repository is already locked.
Exit status is 12 if the password is incorrect. Exit status is 12 if the password is incorrect.
`, `,
PreRun: func(_ *cobra.Command, _ []string) { PreRun: func(_ *cobra.Command, _ []string) {
if backupOptions.Host == "" { if opts.Host == "" {
hostname, err := os.Hostname() hostname, err := os.Hostname()
if err != nil { if err != nil {
debug.Log("os.Hostname() returned err: %v", err) debug.Log("os.Hostname() returned err: %v", err)
return return
} }
backupOptions.Host = hostname opts.Host = hostname
} }
}, },
GroupID: cmdGroupDefault, GroupID: cmdGroupDefault,
@ -63,10 +66,18 @@ Exit status is 12 if the password is incorrect.
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
term, cancel := setupTermstatus() term, cancel := setupTermstatus()
defer cancel() defer cancel()
return runBackup(cmd.Context(), backupOptions, globalOptions, term, args) return runBackup(cmd.Context(), opts, globalOptions, term, args)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newBackupCommand())
}
// BackupOptions bundles all options for the backup command. // BackupOptions bundles all options for the backup command.
type BackupOptions struct { type BackupOptions struct {
filter.ExcludePatternOptions filter.ExcludePatternOptions
@ -147,17 +158,11 @@ func (opts *BackupOptions) AddFlags(f *pflag.FlagSet) {
} }
} }
var backupOptions BackupOptions
var backupFSTestHook func(fs fs.FS) fs.FS var backupFSTestHook func(fs fs.FS) fs.FS
// ErrInvalidSourceData is used to report an incomplete backup // ErrInvalidSourceData is used to report an incomplete backup
var ErrInvalidSourceData = errors.New("at least one source file could not be read") var ErrInvalidSourceData = errors.New("at least one source file could not be read")
func init() {
cmdRoot.AddCommand(cmdBackup)
backupOptions.AddFlags(cmdBackup.Flags())
}
// filterExisting returns a slice of all existing items, or an error if no // filterExisting returns a slice of all existing items, or an error if no
// items exist at all. // items exist at all.
func filterExisting(items []string) (result []string, err error) { func filterExisting(items []string) (result []string, err error) {

View File

@ -16,7 +16,10 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
var cmdCache = &cobra.Command{ func newCacheCommand() *cobra.Command {
var opts CacheOptions
cmd := &cobra.Command{
Use: "cache", Use: "cache",
Short: "Operate on local cache directories", Short: "Operate on local cache directories",
Long: ` Long: `
@ -31,10 +34,18 @@ Exit status is 1 if there was any error.
GroupID: cmdGroupDefault, GroupID: cmdGroupDefault,
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(_ *cobra.Command, args []string) error { RunE: func(_ *cobra.Command, args []string) error {
return runCache(cacheOptions, globalOptions, args) return runCache(opts, globalOptions, args)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newCacheCommand())
}
// CacheOptions bundles all options for the snapshots command. // CacheOptions bundles all options for the snapshots command.
type CacheOptions struct { type CacheOptions struct {
Cleanup bool Cleanup bool
@ -48,13 +59,6 @@ func (opts *CacheOptions) AddFlags(f *pflag.FlagSet) {
f.BoolVar(&opts.NoSize, "no-size", false, "do not output the size of the cache directories") f.BoolVar(&opts.NoSize, "no-size", false, "do not output the size of the cache directories")
} }
var cacheOptions CacheOptions
func init() {
cmdRoot.AddCommand(cmdCache)
cacheOptions.AddFlags(cmdCache.Flags())
}
func runCache(opts CacheOptions, gopts GlobalOptions, args []string) error { func runCache(opts CacheOptions, gopts GlobalOptions, args []string) error {
if len(args) > 0 { if len(args) > 0 {
return errors.Fatal("the cache command expects no arguments, only options - please see `restic help cache` for usage and flags") return errors.Fatal("the cache command expects no arguments, only options - please see `restic help cache` for usage and flags")

View File

@ -14,7 +14,8 @@ import (
var catAllowedCmds = []string{"config", "index", "snapshot", "key", "masterkey", "lock", "pack", "blob", "tree"} var catAllowedCmds = []string{"config", "index", "snapshot", "key", "masterkey", "lock", "pack", "blob", "tree"}
var cmdCat = &cobra.Command{ func newCatCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "cat [flags] [masterkey|config|pack ID|blob ID|snapshot ID|index ID|key ID|lock ID|tree snapshot:subfolder]", Use: "cat [flags] [masterkey|config|pack ID|blob ID|snapshot ID|index ID|key ID|lock ID|tree snapshot:subfolder]",
Short: "Print internal objects to stdout", Short: "Print internal objects to stdout",
Long: ` Long: `
@ -36,9 +37,11 @@ Exit status is 12 if the password is incorrect.
}, },
ValidArgs: catAllowedCmds, ValidArgs: catAllowedCmds,
} }
return cmd
}
func init() { func init() {
cmdRoot.AddCommand(cmdCat) cmdRoot.AddCommand(newCatCommand())
} }
func validateCatArgs(args []string) error { func validateCatArgs(args []string) error {

View File

@ -23,7 +23,9 @@ import (
"github.com/restic/restic/internal/ui/termstatus" "github.com/restic/restic/internal/ui/termstatus"
) )
var cmdCheck = &cobra.Command{ func newCheckCommand() *cobra.Command {
var opts CheckOptions
cmd := &cobra.Command{
Use: "check [flags]", Use: "check [flags]",
Short: "Check the repository for errors", Short: "Check the repository for errors",
Long: ` Long: `
@ -47,7 +49,7 @@ Exit status is 12 if the password is incorrect.
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
term, cancel := setupTermstatus() term, cancel := setupTermstatus()
defer cancel() defer cancel()
summary, err := runCheck(cmd.Context(), checkOptions, globalOptions, args, term) summary, err := runCheck(cmd.Context(), opts, globalOptions, args, term)
if globalOptions.JSON { if globalOptions.JSON {
if err != nil && summary.NumErrors == 0 { if err != nil && summary.NumErrors == 0 {
summary.NumErrors = 1 summary.NumErrors = 1
@ -57,10 +59,18 @@ Exit status is 12 if the password is incorrect.
return err return err
}, },
PreRunE: func(_ *cobra.Command, _ []string) error { PreRunE: func(_ *cobra.Command, _ []string) error {
return checkFlags(checkOptions) return checkFlags(opts)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newCheckCommand())
}
// CheckOptions bundles all options for the 'check' command. // CheckOptions bundles all options for the 'check' command.
type CheckOptions struct { type CheckOptions struct {
ReadData bool ReadData bool
@ -82,13 +92,6 @@ func (opts *CheckOptions) AddFlags(f *pflag.FlagSet) {
f.BoolVar(&opts.WithCache, "with-cache", false, "use existing cache, only read uncached data from repository") f.BoolVar(&opts.WithCache, "with-cache", false, "use existing cache, only read uncached data from repository")
} }
var checkOptions CheckOptions
func init() {
cmdRoot.AddCommand(cmdCheck)
checkOptions.AddFlags(cmdCheck.Flags())
}
func checkFlags(opts CheckOptions) error { func checkFlags(opts CheckOptions) error {
if opts.ReadData && opts.ReadDataSubset != "" { if opts.ReadData && opts.ReadDataSubset != "" {
return errors.Fatal("check flags --read-data and --read-data-subset cannot be used together") return errors.Fatal("check flags --read-data and --read-data-subset cannot be used together")

View File

@ -14,7 +14,9 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
var cmdCopy = &cobra.Command{ func newCopyCommand() *cobra.Command {
var opts CopyOptions
cmd := &cobra.Command{
Use: "copy [flags] [snapshotID ...]", Use: "copy [flags] [snapshotID ...]",
Short: "Copy snapshots from one repository to another", Short: "Copy snapshots from one repository to another",
Long: ` Long: `
@ -44,10 +46,18 @@ Exit status is 12 if the password is incorrect.
GroupID: cmdGroupDefault, GroupID: cmdGroupDefault,
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runCopy(cmd.Context(), copyOptions, globalOptions, args) return runCopy(cmd.Context(), opts, globalOptions, args)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newCopyCommand())
}
// CopyOptions bundles all options for the copy command. // CopyOptions bundles all options for the copy command.
type CopyOptions struct { type CopyOptions struct {
secondaryRepoOptions secondaryRepoOptions
@ -59,13 +69,6 @@ func (opts *CopyOptions) AddFlags(f *pflag.FlagSet) {
initMultiSnapshotFilter(f, &opts.SnapshotFilter, true) initMultiSnapshotFilter(f, &opts.SnapshotFilter, true)
} }
var copyOptions CopyOptions
func init() {
cmdRoot.AddCommand(cmdCopy)
copyOptions.AddFlags(cmdCopy.Flags())
}
func runCopy(ctx context.Context, opts CopyOptions, gopts GlobalOptions, args []string) error { func runCopy(ctx context.Context, opts CopyOptions, gopts GlobalOptions, args []string) error {
secondaryGopts, isFromRepo, err := fillSecondaryGlobalOpts(ctx, opts.secondaryRepoOptions, gopts, "destination") secondaryGopts, isFromRepo, err := fillSecondaryGlobalOpts(ctx, opts.secondaryRepoOptions, gopts, "destination")
if err != nil { if err != nil {

View File

@ -29,14 +29,24 @@ import (
"github.com/restic/restic/internal/restic" "github.com/restic/restic/internal/restic"
) )
var cmdDebug = &cobra.Command{ func newDebugCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "debug", Use: "debug",
Short: "Debug commands", Short: "Debug commands",
GroupID: cmdGroupDefault, GroupID: cmdGroupDefault,
DisableAutoGenTag: true, DisableAutoGenTag: true,
} }
cmd.AddCommand(newDebugDumpCommand())
cmd.AddCommand(newDebugExamineCommand())
return cmd
}
var cmdDebugDump = &cobra.Command{ func init() {
cmdRoot.AddCommand(newDebugCommand())
}
func newDebugDumpCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "dump [indexes|snapshots|all|packs]", Use: "dump [indexes|snapshots|all|packs]",
Short: "Dump data structures", Short: "Dump data structures",
Long: ` Long: `
@ -57,6 +67,24 @@ Exit status is 12 if the password is incorrect.
return runDebugDump(cmd.Context(), globalOptions, args) return runDebugDump(cmd.Context(), globalOptions, args)
}, },
} }
return cmd
}
func newDebugExamineCommand() *cobra.Command {
var opts DebugExamineOptions
cmd := &cobra.Command{
Use: "examine pack-ID...",
Short: "Examine a pack file",
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return runDebugExamine(cmd.Context(), globalOptions, opts, args)
},
}
opts.AddFlags(cmd.Flags())
return cmd
}
type DebugExamineOptions struct { type DebugExamineOptions struct {
TryRepair bool TryRepair bool
@ -72,15 +100,6 @@ func (opts *DebugExamineOptions) AddFlags(f *pflag.FlagSet) {
f.BoolVar(&opts.RepairByte, "repair-byte", false, "try to repair broken blobs by trying bytes") f.BoolVar(&opts.RepairByte, "repair-byte", false, "try to repair broken blobs by trying bytes")
} }
var debugExamineOpts DebugExamineOptions
func init() {
cmdRoot.AddCommand(cmdDebug)
cmdDebug.AddCommand(cmdDebugDump)
cmdDebug.AddCommand(cmdDebugExamine)
debugExamineOpts.AddFlags(cmdDebugExamine.Flags())
}
func prettyPrintJSON(wr io.Writer, item interface{}) error { func prettyPrintJSON(wr io.Writer, item interface{}) error {
buf, err := json.MarshalIndent(item, "", " ") buf, err := json.MarshalIndent(item, "", " ")
if err != nil { if err != nil {
@ -197,15 +216,6 @@ func runDebugDump(ctx context.Context, gopts GlobalOptions, args []string) error
} }
} }
var cmdDebugExamine = &cobra.Command{
Use: "examine pack-ID...",
Short: "Examine a pack file",
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return runDebugExamine(cmd.Context(), globalOptions, debugExamineOpts, args)
},
}
func tryRepairWithBitflip(ctx context.Context, key *crypto.Key, input []byte, bytewise bool) []byte { func tryRepairWithBitflip(ctx context.Context, key *crypto.Key, input []byte, bytewise bool) []byte {
if bytewise { if bytewise {
Printf(" trying to repair blob by finding a broken byte\n") Printf(" trying to repair blob by finding a broken byte\n")

View File

@ -15,7 +15,10 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
var cmdDiff = &cobra.Command{ func newDiffCommand() *cobra.Command {
var opts DiffOptions
cmd := &cobra.Command{
Use: "diff [flags] snapshotID snapshotID", Use: "diff [flags] snapshotID snapshotID",
Short: "Show differences between two snapshots", Short: "Show differences between two snapshots",
Long: ` Long: `
@ -49,10 +52,18 @@ Exit status is 12 if the password is incorrect.
GroupID: cmdGroupDefault, GroupID: cmdGroupDefault,
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runDiff(cmd.Context(), diffOptions, globalOptions, args) return runDiff(cmd.Context(), opts, globalOptions, args)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newDiffCommand())
}
// DiffOptions collects all options for the diff command. // DiffOptions collects all options for the diff command.
type DiffOptions struct { type DiffOptions struct {
ShowMetadata bool ShowMetadata bool
@ -62,13 +73,6 @@ func (opts *DiffOptions) AddFlags(f *pflag.FlagSet) {
f.BoolVar(&opts.ShowMetadata, "metadata", false, "print changes in metadata") f.BoolVar(&opts.ShowMetadata, "metadata", false, "print changes in metadata")
} }
var diffOptions DiffOptions
func init() {
cmdRoot.AddCommand(cmdDiff)
diffOptions.AddFlags(cmdDiff.Flags())
}
func loadSnapshot(ctx context.Context, be restic.Lister, repo restic.LoaderUnpacked, desc string) (*restic.Snapshot, string, error) { func loadSnapshot(ctx context.Context, be restic.Lister, repo restic.LoaderUnpacked, desc string) (*restic.Snapshot, string, error) {
sn, subfolder, err := restic.FindSnapshot(ctx, be, repo, desc) sn, subfolder, err := restic.FindSnapshot(ctx, be, repo, desc)
if err != nil { if err != nil {

View File

@ -16,7 +16,9 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
var cmdDump = &cobra.Command{ func newDumpCommand() *cobra.Command {
var opts DumpOptions
cmd := &cobra.Command{
Use: "dump [flags] snapshotID file", Use: "dump [flags] snapshotID file",
Short: "Print a backed-up file to stdout", Short: "Print a backed-up file to stdout",
Long: ` Long: `
@ -44,10 +46,18 @@ Exit status is 12 if the password is incorrect.
GroupID: cmdGroupDefault, GroupID: cmdGroupDefault,
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runDump(cmd.Context(), dumpOptions, globalOptions, args) return runDump(cmd.Context(), opts, globalOptions, args)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newDumpCommand())
}
// DumpOptions collects all options for the dump command. // DumpOptions collects all options for the dump command.
type DumpOptions struct { type DumpOptions struct {
restic.SnapshotFilter restic.SnapshotFilter
@ -61,13 +71,6 @@ func (opts *DumpOptions) AddFlags(f *pflag.FlagSet) {
f.StringVarP(&opts.Target, "target", "t", "", "write the output to target `path`") f.StringVarP(&opts.Target, "target", "t", "", "write the output to target `path`")
} }
var dumpOptions DumpOptions
func init() {
cmdRoot.AddCommand(cmdDump)
dumpOptions.AddFlags(cmdDump.Flags())
}
func splitPath(p string) []string { func splitPath(p string) []string {
d, f := path.Split(p) d, f := path.Split(p)
if d == "" || d == "/" { if d == "" || d == "/" {

View File

@ -10,7 +10,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var featuresCmd = &cobra.Command{ func newFeaturesCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "features", Use: "features",
Short: "Print list of feature flags", Short: "Print list of feature flags",
Long: ` Long: `
@ -54,6 +55,9 @@ Exit status is 1 if there was any error.
}, },
} }
func init() { return cmd
cmdRoot.AddCommand(featuresCmd) }
func init() {
cmdRoot.AddCommand(newFeaturesCommand())
} }

View File

@ -17,7 +17,10 @@ import (
"github.com/restic/restic/internal/walker" "github.com/restic/restic/internal/walker"
) )
var cmdFind = &cobra.Command{ func newFindCommand() *cobra.Command {
var opts FindOptions
cmd := &cobra.Command{
Use: "find [flags] PATTERN...", Use: "find [flags] PATTERN...",
Short: "Find a file, a directory or restic IDs", Short: "Find a file, a directory or restic IDs",
Long: ` Long: `
@ -45,10 +48,18 @@ Exit status is 12 if the password is incorrect.
GroupID: cmdGroupDefault, GroupID: cmdGroupDefault,
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runFind(cmd.Context(), findOptions, globalOptions, args) return runFind(cmd.Context(), opts, globalOptions, args)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newFindCommand())
}
// FindOptions bundles all options for the find command. // FindOptions bundles all options for the find command.
type FindOptions struct { type FindOptions struct {
Oldest string Oldest string
@ -79,13 +90,6 @@ func (opts *FindOptions) AddFlags(f *pflag.FlagSet) {
initMultiSnapshotFilter(f, &opts.SnapshotFilter, true) initMultiSnapshotFilter(f, &opts.SnapshotFilter, true)
} }
var findOptions FindOptions
func init() {
cmdRoot.AddCommand(cmdFind)
findOptions.AddFlags(cmdFind.Flags())
}
type findPattern struct { type findPattern struct {
oldest, newest time.Time oldest, newest time.Time
pattern []string pattern []string

View File

@ -14,7 +14,11 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
var cmdForget = &cobra.Command{ func newForgetCommand() *cobra.Command {
var opts ForgetOptions
var pruneOpts PruneOptions
cmd := &cobra.Command{
Use: "forget [flags] [snapshot ID] [...]", Use: "forget [flags] [snapshot ID] [...]",
Short: "Remove snapshots from the repository", Short: "Remove snapshots from the repository",
Long: ` Long: `
@ -46,10 +50,19 @@ Exit status is 12 if the password is incorrect.
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
term, cancel := setupTermstatus() term, cancel := setupTermstatus()
defer cancel() defer cancel()
return runForget(cmd.Context(), forgetOptions, forgetPruneOptions, globalOptions, term, args) return runForget(cmd.Context(), opts, pruneOpts, globalOptions, term, args)
}, },
} }
opts.AddFlags(cmd.Flags())
pruneOpts.AddLimitedFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newForgetCommand())
}
type ForgetPolicyCount int type ForgetPolicyCount int
var ErrNegativePolicyCount = errors.New("negative values not allowed, use 'unlimited' instead") var ErrNegativePolicyCount = errors.New("negative values not allowed, use 'unlimited' instead")
@ -145,15 +158,6 @@ func (opts *ForgetOptions) AddFlags(f *pflag.FlagSet) {
f.SortFlags = false f.SortFlags = false
} }
var forgetOptions ForgetOptions
var forgetPruneOptions PruneOptions
func init() {
cmdRoot.AddCommand(cmdForget)
forgetOptions.AddFlags(cmdForget.Flags())
forgetPruneOptions.AddLimitedFlags(cmdForget.Flags())
}
func verifyForgetOptions(opts *ForgetOptions) error { func verifyForgetOptions(opts *ForgetOptions) error {
if opts.Last < -1 || opts.Hourly < -1 || opts.Daily < -1 || opts.Weekly < -1 || if opts.Last < -1 || opts.Hourly < -1 || opts.Daily < -1 || opts.Weekly < -1 ||
opts.Monthly < -1 || opts.Yearly < -1 { opts.Monthly < -1 || opts.Yearly < -1 {

View File

@ -11,7 +11,10 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
var cmdGenerate = &cobra.Command{ func newGenerateCommand() *cobra.Command {
var opts generateOptions
cmd := &cobra.Command{
Use: "generate [flags]", Use: "generate [flags]",
Short: "Generate manual pages and auto-completion files (bash, fish, zsh, powershell)", Short: "Generate manual pages and auto-completion files (bash, fish, zsh, powershell)",
Long: ` Long: `
@ -26,9 +29,16 @@ Exit status is 1 if there was any error.
`, `,
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(_ *cobra.Command, args []string) error { RunE: func(_ *cobra.Command, args []string) error {
return runGenerate(genOpts, args) return runGenerate(opts, args)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newGenerateCommand())
}
type generateOptions struct { type generateOptions struct {
ManDir string ManDir string
@ -46,13 +56,6 @@ func (opts *generateOptions) AddFlags(f *pflag.FlagSet) {
f.StringVar(&opts.PowerShellCompletionFile, "powershell-completion", "", "write powershell completion `file` (`-` for stdout)") f.StringVar(&opts.PowerShellCompletionFile, "powershell-completion", "", "write powershell completion `file` (`-` for stdout)")
} }
var genOpts generateOptions
func init() {
cmdRoot.AddCommand(cmdGenerate)
genOpts.AddFlags(cmdGenerate.Flags())
}
func writeManpages(dir string) error { func writeManpages(dir string) error {
// use a fixed date for the man pages so that generating them is deterministic // use a fixed date for the man pages so that generating them is deterministic
date, err := time.Parse("Jan 2006", "Jan 2017") date, err := time.Parse("Jan 2006", "Jan 2017")

View File

@ -15,7 +15,10 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
var cmdInit = &cobra.Command{ func newInitCommand() *cobra.Command {
var opts InitOptions
cmd := &cobra.Command{
Use: "init", Use: "init",
Short: "Initialize a new repository", Short: "Initialize a new repository",
Long: ` Long: `
@ -30,9 +33,16 @@ Exit status is 1 if there was any error.
GroupID: cmdGroupDefault, GroupID: cmdGroupDefault,
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runInit(cmd.Context(), initOptions, globalOptions, args) return runInit(cmd.Context(), opts, globalOptions, args)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newInitCommand())
}
// InitOptions bundles all options for the init command. // InitOptions bundles all options for the init command.
type InitOptions struct { type InitOptions struct {
@ -47,13 +57,6 @@ func (opts *InitOptions) AddFlags(f *pflag.FlagSet) {
f.StringVar(&opts.RepositoryVersion, "repository-version", "stable", "repository format version to use, allowed values are a format version, 'latest' and 'stable'") f.StringVar(&opts.RepositoryVersion, "repository-version", "stable", "repository format version to use, allowed values are a format version, 'latest' and 'stable'")
} }
var initOptions InitOptions
func init() {
cmdRoot.AddCommand(cmdInit)
initOptions.AddFlags(cmdInit.Flags())
}
func runInit(ctx context.Context, opts InitOptions, gopts GlobalOptions, args []string) error { func runInit(ctx context.Context, opts InitOptions, gopts GlobalOptions, args []string) error {
if len(args) > 0 { if len(args) > 0 {
return errors.Fatal("the init command expects no arguments, only options - please see `restic help init` for usage and flags") return errors.Fatal("the init command expects no arguments, only options - please see `restic help init` for usage and flags")

View File

@ -10,7 +10,10 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
var cmdKeyAdd = &cobra.Command{ func newKeyAddCommand() *cobra.Command {
var opts KeyAddOptions
cmd := &cobra.Command{
Use: "add", Use: "add",
Short: "Add a new key (password) to the repository; returns the new key ID", Short: "Add a new key (password) to the repository; returns the new key ID",
Long: ` Long: `
@ -26,6 +29,13 @@ Exit status is 11 if the repository is already locked.
Exit status is 12 if the password is incorrect. Exit status is 12 if the password is incorrect.
`, `,
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return runKeyAdd(cmd.Context(), globalOptions, opts, args)
},
}
opts.Add(cmd.Flags())
return cmd
} }
type KeyAddOptions struct { type KeyAddOptions struct {
@ -43,13 +53,7 @@ func (opts *KeyAddOptions) Add(flags *pflag.FlagSet) {
} }
func init() { func init() {
cmdKey.AddCommand(cmdKeyAdd) cmdKey.AddCommand(newKeyAddCommand())
var keyAddOpts KeyAddOptions
keyAddOpts.Add(cmdKeyAdd.Flags())
cmdKeyAdd.RunE = func(cmd *cobra.Command, args []string) error {
return runKeyAdd(cmd.Context(), globalOptions, keyAddOpts, args)
}
} }
func runKeyAdd(ctx context.Context, gopts GlobalOptions, opts KeyAddOptions, args []string) error { func runKeyAdd(ctx context.Context, gopts GlobalOptions, opts KeyAddOptions, args []string) error {

View File

@ -12,7 +12,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var cmdKeyList = &cobra.Command{ func newKeyListCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "list", Use: "list",
Short: "List keys (passwords)", Short: "List keys (passwords)",
Long: ` Long: `
@ -34,9 +35,11 @@ Exit status is 12 if the password is incorrect.
return runKeyList(cmd.Context(), globalOptions, args) return runKeyList(cmd.Context(), globalOptions, args)
}, },
} }
return cmd
}
func init() { func init() {
cmdKey.AddCommand(cmdKeyList) cmdKey.AddCommand(newKeyListCommand())
} }
func runKeyList(ctx context.Context, gopts GlobalOptions, args []string) error { func runKeyList(ctx context.Context, gopts GlobalOptions, args []string) error {

View File

@ -7,9 +7,13 @@ import (
"github.com/restic/restic/internal/errors" "github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/repository" "github.com/restic/restic/internal/repository"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag"
) )
var cmdKeyPasswd = &cobra.Command{ func newKeyPasswdCommand() *cobra.Command {
var opts KeyPasswdOptions
cmd := &cobra.Command{
Use: "passwd", Use: "passwd",
Short: "Change key (password); creates a new key ID and removes the old key ID, returns new key ID", Short: "Change key (password); creates a new key ID and removes the old key ID, returns new key ID",
Long: ` Long: `
@ -26,20 +30,25 @@ Exit status is 11 if the repository is already locked.
Exit status is 12 if the password is incorrect. Exit status is 12 if the password is incorrect.
`, `,
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return runKeyPasswd(cmd.Context(), globalOptions, opts, args)
},
}
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdKey.AddCommand(newKeyPasswdCommand())
} }
type KeyPasswdOptions struct { type KeyPasswdOptions struct {
KeyAddOptions KeyAddOptions
} }
func init() { func (opts *KeyPasswdOptions) AddFlags(flags *pflag.FlagSet) {
cmdKey.AddCommand(cmdKeyPasswd) opts.KeyAddOptions.Add(flags)
var keyPasswdOpts KeyPasswdOptions
keyPasswdOpts.KeyAddOptions.Add(cmdKeyPasswd.Flags())
cmdKeyPasswd.RunE = func(cmd *cobra.Command, args []string) error {
return runKeyPasswd(cmd.Context(), globalOptions, keyPasswdOpts, args)
}
} }
func runKeyPasswd(ctx context.Context, gopts GlobalOptions, opts KeyPasswdOptions, args []string) error { func runKeyPasswd(ctx context.Context, gopts GlobalOptions, opts KeyPasswdOptions, args []string) error {

View File

@ -10,7 +10,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var cmdKeyRemove = &cobra.Command{ func newKeyRemoveCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "remove [ID]", Use: "remove [ID]",
Short: "Remove key ID (password) from the repository.", Short: "Remove key ID (password) from the repository.",
Long: ` Long: `
@ -31,9 +32,11 @@ Exit status is 12 if the password is incorrect.
return runKeyRemove(cmd.Context(), globalOptions, args) return runKeyRemove(cmd.Context(), globalOptions, args)
}, },
} }
return cmd
}
func init() { func init() {
cmdKey.AddCommand(cmdKeyRemove) cmdKey.AddCommand(newKeyRemoveCommand())
} }
func runKeyRemove(ctx context.Context, gopts GlobalOptions, args []string) error { func runKeyRemove(ctx context.Context, gopts GlobalOptions, args []string) error {

View File

@ -11,10 +11,11 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func newListCommand() *cobra.Command {
var listAllowedArgs = []string{"blobs", "packs", "index", "snapshots", "keys", "locks"} var listAllowedArgs = []string{"blobs", "packs", "index", "snapshots", "keys", "locks"}
var listAllowedArgsUseString = strings.Join(listAllowedArgs, "|") var listAllowedArgsUseString = strings.Join(listAllowedArgs, "|")
var cmdList = &cobra.Command{ cmd := &cobra.Command{
Use: "list [flags] [" + listAllowedArgsUseString + "]", Use: "list [flags] [" + listAllowedArgsUseString + "]",
Short: "List objects in the repository", Short: "List objects in the repository",
Long: ` Long: `
@ -37,9 +38,11 @@ Exit status is 12 if the password is incorrect.
ValidArgs: listAllowedArgs, ValidArgs: listAllowedArgs,
Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
} }
return cmd
}
func init() { func init() {
cmdRoot.AddCommand(cmdList) cmdRoot.AddCommand(newListCommand())
} }
func runList(ctx context.Context, gopts GlobalOptions, args []string) error { func runList(ctx context.Context, gopts GlobalOptions, args []string) error {

View File

@ -21,7 +21,10 @@ import (
"github.com/restic/restic/internal/walker" "github.com/restic/restic/internal/walker"
) )
var cmdLs = &cobra.Command{ func newLsCommand() *cobra.Command {
var opts LsOptions
cmd := &cobra.Command{
Use: "ls [flags] snapshotID [dir...]", Use: "ls [flags] snapshotID [dir...]",
Short: "List files in a snapshot", Short: "List files in a snapshot",
Long: ` Long: `
@ -56,9 +59,16 @@ Exit status is 12 if the password is incorrect.
DisableAutoGenTag: true, DisableAutoGenTag: true,
GroupID: cmdGroupDefault, GroupID: cmdGroupDefault,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runLs(cmd.Context(), lsOptions, globalOptions, args) return runLs(cmd.Context(), opts, globalOptions, args)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newLsCommand())
}
// LsOptions collects all options for the ls command. // LsOptions collects all options for the ls command.
type LsOptions struct { type LsOptions struct {
@ -81,13 +91,6 @@ func (opts *LsOptions) AddFlags(f *pflag.FlagSet) {
f.BoolVar(&opts.Reverse, "reverse", false, "reverse sorted output") f.BoolVar(&opts.Reverse, "reverse", false, "reverse sorted output")
} }
var lsOptions LsOptions
func init() {
cmdRoot.AddCommand(cmdLs)
lsOptions.AddFlags(cmdLs.Flags())
}
type lsPrinter interface { type lsPrinter interface {
Snapshot(sn *restic.Snapshot) error Snapshot(sn *restic.Snapshot) error
Node(path string, node *restic.Node, isPrefixDirectory bool) error Node(path string, node *restic.Node, isPrefixDirectory bool) error

View File

@ -12,7 +12,10 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
var cmdMigrate = &cobra.Command{ func newMigrateCommand() *cobra.Command {
var opts MigrateOptions
cmd := &cobra.Command{
Use: "migrate [flags] [migration name] [...]", Use: "migrate [flags] [migration name] [...]",
Short: "Apply migrations", Short: "Apply migrations",
Long: ` Long: `
@ -34,10 +37,18 @@ Exit status is 12 if the password is incorrect.
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
term, cancel := setupTermstatus() term, cancel := setupTermstatus()
defer cancel() defer cancel()
return runMigrate(cmd.Context(), migrateOptions, globalOptions, args, term) return runMigrate(cmd.Context(), opts, globalOptions, args, term)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newMigrateCommand())
}
// MigrateOptions bundles all options for the 'check' command. // MigrateOptions bundles all options for the 'check' command.
type MigrateOptions struct { type MigrateOptions struct {
Force bool Force bool
@ -47,13 +58,6 @@ func (opts *MigrateOptions) AddFlags(f *pflag.FlagSet) {
f.BoolVarP(&opts.Force, "force", "f", false, `apply a migration a second time`) f.BoolVarP(&opts.Force, "force", "f", false, `apply a migration a second time`)
} }
var migrateOptions MigrateOptions
func init() {
cmdRoot.AddCommand(cmdMigrate)
migrateOptions.AddFlags(cmdMigrate.Flags())
}
func checkMigrations(ctx context.Context, repo restic.Repository, printer progress.Printer) error { func checkMigrations(ctx context.Context, repo restic.Repository, printer progress.Printer) error {
printer.P("available migrations:\n") printer.P("available migrations:\n")
found := false found := false

View File

@ -22,7 +22,10 @@ import (
"github.com/anacrolix/fuse/fs" "github.com/anacrolix/fuse/fs"
) )
var cmdMount = &cobra.Command{ func newMountCommand() *cobra.Command {
var opts MountOptions
cmd := &cobra.Command{
Use: "mount [flags] mountpoint", Use: "mount [flags] mountpoint",
Short: "Mount the repository", Short: "Mount the repository",
Long: ` Long: `
@ -73,10 +76,18 @@ Exit status is 12 if the password is incorrect.
DisableAutoGenTag: true, DisableAutoGenTag: true,
GroupID: cmdGroupDefault, GroupID: cmdGroupDefault,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runMount(cmd.Context(), mountOptions, globalOptions, args) return runMount(cmd.Context(), opts, globalOptions, args)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newMountCommand())
}
// MountOptions collects all options for the mount command. // MountOptions collects all options for the mount command.
type MountOptions struct { type MountOptions struct {
OwnerRoot bool OwnerRoot bool
@ -100,13 +111,6 @@ func (opts *MountOptions) AddFlags(f *pflag.FlagSet) {
_ = f.MarkDeprecated("snapshot-template", "use --time-template") _ = f.MarkDeprecated("snapshot-template", "use --time-template")
} }
var mountOptions MountOptions
func init() {
cmdRoot.AddCommand(cmdMount)
mountOptions.AddFlags(cmdMount.Flags())
}
func runMount(ctx context.Context, opts MountOptions, gopts GlobalOptions, args []string) error { func runMount(ctx context.Context, opts MountOptions, gopts GlobalOptions, args []string) error {
if opts.TimeTemplate == "" { if opts.TimeTemplate == "" {
return errors.Fatal("time template string cannot be empty") return errors.Fatal("time template string cannot be empty")

View File

@ -8,7 +8,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var optionsCmd = &cobra.Command{ func newOptionsCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "options", Use: "options",
Short: "Print list of extended options", Short: "Print list of extended options",
Long: ` Long: `
@ -35,7 +36,9 @@ Exit status is 1 if there was any error.
} }
}, },
} }
return cmd
}
func init() { func init() {
cmdRoot.AddCommand(optionsCmd) cmdRoot.AddCommand(newOptionsCommand())
} }

View File

@ -19,7 +19,10 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
var cmdPrune = &cobra.Command{ func newPruneCommand() *cobra.Command {
var opts PruneOptions
cmd := &cobra.Command{
Use: "prune [flags]", Use: "prune [flags]",
Short: "Remove unneeded data from the repository", Short: "Remove unneeded data from the repository",
Long: ` Long: `
@ -40,10 +43,18 @@ Exit status is 12 if the password is incorrect.
RunE: func(cmd *cobra.Command, _ []string) error { RunE: func(cmd *cobra.Command, _ []string) error {
term, cancel := setupTermstatus() term, cancel := setupTermstatus()
defer cancel() defer cancel()
return runPrune(cmd.Context(), pruneOptions, globalOptions, term) return runPrune(cmd.Context(), opts, globalOptions, term)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newPruneCommand())
}
// PruneOptions collects all options for the cleanup command. // PruneOptions collects all options for the cleanup command.
type PruneOptions struct { type PruneOptions struct {
DryRun bool DryRun bool
@ -76,13 +87,6 @@ func (opts *PruneOptions) AddLimitedFlags(f *pflag.FlagSet) {
f.BoolVar(&opts.RepackUncompressed, "repack-uncompressed", false, "repack all uncompressed data") f.BoolVar(&opts.RepackUncompressed, "repack-uncompressed", false, "repack all uncompressed data")
} }
var pruneOptions PruneOptions
func init() {
cmdRoot.AddCommand(cmdPrune)
pruneOptions.AddFlags(cmdPrune.Flags())
}
func verifyPruneOptions(opts *PruneOptions) error { func verifyPruneOptions(opts *PruneOptions) error {
opts.MaxRepackBytes = math.MaxUint64 opts.MaxRepackBytes = math.MaxUint64
if len(opts.MaxRepackSize) > 0 { if len(opts.MaxRepackSize) > 0 {

View File

@ -11,7 +11,8 @@ import (
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
var cmdRecover = &cobra.Command{ func newRecoverCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "recover [flags]", Use: "recover [flags]",
Short: "Recover data from the repository not referenced by snapshots", Short: "Recover data from the repository not referenced by snapshots",
Long: ` Long: `
@ -34,9 +35,11 @@ Exit status is 12 if the password is incorrect.
return runRecover(cmd.Context(), globalOptions) return runRecover(cmd.Context(), globalOptions)
}, },
} }
return cmd
}
func init() { func init() {
cmdRoot.AddCommand(cmdRecover) cmdRoot.AddCommand(newRecoverCommand())
} }
func runRecover(ctx context.Context, gopts GlobalOptions) error { func runRecover(ctx context.Context, gopts GlobalOptions) error {

View File

@ -9,7 +9,10 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
var cmdRepairIndex = &cobra.Command{ func newRepairIndexCommand() *cobra.Command {
var opts RepairIndexOptions
cmd := &cobra.Command{
Use: "index [flags]", Use: "index [flags]",
Short: "Build a new index", Short: "Build a new index",
Long: ` Long: `
@ -29,17 +32,16 @@ Exit status is 12 if the password is incorrect.
RunE: func(cmd *cobra.Command, _ []string) error { RunE: func(cmd *cobra.Command, _ []string) error {
term, cancel := setupTermstatus() term, cancel := setupTermstatus()
defer cancel() defer cancel()
return runRebuildIndex(cmd.Context(), repairIndexOptions, globalOptions, term) return runRebuildIndex(cmd.Context(), opts, globalOptions, term)
}, },
} }
var cmdRebuildIndex = &cobra.Command{ opts.AddFlags(cmd.Flags())
Use: "rebuild-index [flags]", return cmd
Short: cmdRepairIndex.Short, }
Long: cmdRepairIndex.Long,
Deprecated: `Use "repair index" instead`, func init() {
DisableAutoGenTag: true, cmdRepair.AddCommand(newRepairIndexCommand())
RunE: cmdRepairIndex.RunE,
} }
// RepairIndexOptions collects all options for the repair index command. // RepairIndexOptions collects all options for the repair index command.
@ -51,14 +53,32 @@ func (opts *RepairIndexOptions) AddFlags(f *pflag.FlagSet) {
f.BoolVar(&opts.ReadAllPacks, "read-all-packs", false, "read all pack files to generate new index from scratch") f.BoolVar(&opts.ReadAllPacks, "read-all-packs", false, "read all pack files to generate new index from scratch")
} }
var repairIndexOptions RepairIndexOptions func newRebuildIndexCommand() *cobra.Command {
var opts RepairIndexOptions
replacement := newRepairIndexCommand()
cmd := &cobra.Command{
Use: "rebuild-index [flags]",
Short: replacement.Short,
Long: replacement.Long,
Deprecated: `Use "repair index" instead`,
DisableAutoGenTag: true,
// must create a new instance of the run function as it captures opts
// by reference
RunE: func(cmd *cobra.Command, _ []string) error {
term, cancel := setupTermstatus()
defer cancel()
return runRebuildIndex(cmd.Context(), opts, globalOptions, term)
},
}
opts.AddFlags(cmd.Flags())
return cmd
}
func init() { func init() {
cmdRepair.AddCommand(cmdRepairIndex)
repairIndexOptions.AddFlags(cmdRepairIndex.Flags())
// add alias for old name // add alias for old name
cmdRoot.AddCommand(cmdRebuildIndex) cmdRoot.AddCommand(newRebuildIndexCommand())
repairIndexOptions.AddFlags(cmdRebuildIndex.Flags())
} }
func runRebuildIndex(ctx context.Context, opts RepairIndexOptions, gopts GlobalOptions, term *termstatus.Terminal) error { func runRebuildIndex(ctx context.Context, opts RepairIndexOptions, gopts GlobalOptions, term *termstatus.Terminal) error {

View File

@ -13,7 +13,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var cmdRepairPacks = &cobra.Command{ func newRepairPacksCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "packs [packIDs...]", Use: "packs [packIDs...]",
Short: "Salvage damaged pack files", Short: "Salvage damaged pack files",
Long: ` Long: `
@ -36,9 +37,11 @@ Exit status is 12 if the password is incorrect.
return runRepairPacks(cmd.Context(), globalOptions, term, args) return runRepairPacks(cmd.Context(), globalOptions, term, args)
}, },
} }
return cmd
}
func init() { func init() {
cmdRepair.AddCommand(cmdRepairPacks) cmdRepair.AddCommand(newRepairPacksCommand())
} }
func runRepairPacks(ctx context.Context, gopts GlobalOptions, term *termstatus.Terminal, args []string) error { func runRepairPacks(ctx context.Context, gopts GlobalOptions, term *termstatus.Terminal, args []string) error {

View File

@ -11,7 +11,10 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
var cmdRepairSnapshots = &cobra.Command{ func newRepairSnapshotsCommand() *cobra.Command {
var opts RepairOptions
cmd := &cobra.Command{
Use: "snapshots [flags] [snapshot ID] [...]", Use: "snapshots [flags] [snapshot ID] [...]",
Short: "Repair snapshots", Short: "Repair snapshots",
Long: ` Long: `
@ -46,10 +49,18 @@ Exit status is 12 if the password is incorrect.
`, `,
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runRepairSnapshots(cmd.Context(), globalOptions, repairSnapshotOptions, args) return runRepairSnapshots(cmd.Context(), globalOptions, opts, args)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRepair.AddCommand(newRepairSnapshotsCommand())
}
// RepairOptions collects all options for the repair command. // RepairOptions collects all options for the repair command.
type RepairOptions struct { type RepairOptions struct {
DryRun bool DryRun bool
@ -65,13 +76,6 @@ func (opts *RepairOptions) AddFlags(f *pflag.FlagSet) {
initMultiSnapshotFilter(f, &opts.SnapshotFilter, true) initMultiSnapshotFilter(f, &opts.SnapshotFilter, true)
} }
var repairSnapshotOptions RepairOptions
func init() {
cmdRepair.AddCommand(cmdRepairSnapshots)
repairSnapshotOptions.AddFlags(cmdRepairSnapshots.Flags())
}
func runRepairSnapshots(ctx context.Context, gopts GlobalOptions, opts RepairOptions, args []string) error { func runRepairSnapshots(ctx context.Context, gopts GlobalOptions, opts RepairOptions, args []string) error {
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, opts.DryRun) ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, opts.DryRun)
if err != nil { if err != nil {

View File

@ -18,7 +18,10 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
var cmdRestore = &cobra.Command{ func newRestoreCommand() *cobra.Command {
var opts RestoreOptions
cmd := &cobra.Command{
Use: "restore [flags] snapshotID", Use: "restore [flags] snapshotID",
Short: "Extract the data from a snapshot", Short: "Extract the data from a snapshot",
Long: ` Long: `
@ -45,10 +48,18 @@ Exit status is 12 if the password is incorrect.
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
term, cancel := setupTermstatus() term, cancel := setupTermstatus()
defer cancel() defer cancel()
return runRestore(cmd.Context(), restoreOptions, globalOptions, term, args) return runRestore(cmd.Context(), opts, globalOptions, term, args)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newRestoreCommand())
}
// RestoreOptions collects all options for the restore command. // RestoreOptions collects all options for the restore command.
type RestoreOptions struct { type RestoreOptions struct {
filter.ExcludePatternOptions filter.ExcludePatternOptions
@ -81,13 +92,6 @@ func (opts *RestoreOptions) AddFlags(f *pflag.FlagSet) {
f.BoolVar(&opts.Delete, "delete", false, "delete files from target directory if they do not exist in snapshot. Use '--dry-run -vv' to check what would be deleted") f.BoolVar(&opts.Delete, "delete", false, "delete files from target directory if they do not exist in snapshot. Use '--dry-run -vv' to check what would be deleted")
} }
var restoreOptions RestoreOptions
func init() {
cmdRoot.AddCommand(cmdRestore)
restoreOptions.AddFlags(cmdRestore.Flags())
}
func runRestore(ctx context.Context, opts RestoreOptions, gopts GlobalOptions, func runRestore(ctx context.Context, opts RestoreOptions, gopts GlobalOptions,
term *termstatus.Terminal, args []string) error { term *termstatus.Terminal, args []string) error {

View File

@ -16,7 +16,10 @@ import (
"github.com/restic/restic/internal/walker" "github.com/restic/restic/internal/walker"
) )
var cmdRewrite = &cobra.Command{ func newRewriteCommand() *cobra.Command {
var opts RewriteOptions
cmd := &cobra.Command{
Use: "rewrite [flags] [snapshotID ...]", Use: "rewrite [flags] [snapshotID ...]",
Short: "Rewrite snapshots to exclude unwanted files", Short: "Rewrite snapshots to exclude unwanted files",
Long: ` Long: `
@ -55,10 +58,18 @@ Exit status is 12 if the password is incorrect.
GroupID: cmdGroupDefault, GroupID: cmdGroupDefault,
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runRewrite(cmd.Context(), rewriteOptions, globalOptions, args) return runRewrite(cmd.Context(), opts, globalOptions, args)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newRewriteCommand())
}
type snapshotMetadata struct { type snapshotMetadata struct {
Hostname string Hostname string
Time *time.Time Time *time.Time
@ -111,13 +122,6 @@ func (opts *RewriteOptions) AddFlags(f *pflag.FlagSet) {
opts.ExcludePatternOptions.Add(f) opts.ExcludePatternOptions.Add(f)
} }
var rewriteOptions RewriteOptions
func init() {
cmdRoot.AddCommand(cmdRewrite)
rewriteOptions.AddFlags(cmdRewrite.Flags())
}
// rewriteFilterFunc returns the filtered tree ID or an error. If a snapshot summary is returned, the snapshot will // rewriteFilterFunc returns the filtered tree ID or an error. If a snapshot summary is returned, the snapshot will
// be updated accordingly. // be updated accordingly.
type rewriteFilterFunc func(ctx context.Context, sn *restic.Snapshot) (restic.ID, *restic.SnapshotSummary, error) type rewriteFilterFunc func(ctx context.Context, sn *restic.Snapshot) (restic.ID, *restic.SnapshotSummary, error)

View File

@ -13,7 +13,10 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
var cmdSelfUpdate = &cobra.Command{ func newSelfUpdateCommand() *cobra.Command {
var opts SelfUpdateOptions
cmd := &cobra.Command{
Use: "self-update [flags]", Use: "self-update [flags]",
Short: "Update the restic binary", Short: "Update the restic binary",
Long: ` Long: `
@ -33,10 +36,18 @@ Exit status is 12 if the password is incorrect.
`, `,
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runSelfUpdate(cmd.Context(), selfUpdateOptions, globalOptions, args) return runSelfUpdate(cmd.Context(), opts, globalOptions, args)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newSelfUpdateCommand())
}
// SelfUpdateOptions collects all options for the update-restic command. // SelfUpdateOptions collects all options for the update-restic command.
type SelfUpdateOptions struct { type SelfUpdateOptions struct {
Output string Output string
@ -46,13 +57,6 @@ func (opts *SelfUpdateOptions) AddFlags(f *pflag.FlagSet) {
f.StringVar(&opts.Output, "output", "", "Save the downloaded file as `filename` (default: running binary itself)") f.StringVar(&opts.Output, "output", "", "Save the downloaded file as `filename` (default: running binary itself)")
} }
var selfUpdateOptions SelfUpdateOptions
func init() {
cmdRoot.AddCommand(cmdSelfUpdate)
selfUpdateOptions.AddFlags(cmdSelfUpdate.Flags())
}
func runSelfUpdate(ctx context.Context, opts SelfUpdateOptions, gopts GlobalOptions, args []string) error { func runSelfUpdate(ctx context.Context, opts SelfUpdateOptions, gopts GlobalOptions, args []string) error {
if opts.Output == "" { if opts.Output == "" {
file, err := os.Executable() file, err := os.Executable()

View File

@ -15,7 +15,10 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
var cmdSnapshots = &cobra.Command{ func newSnapshotsCommand() *cobra.Command {
var opts SnapshotOptions
cmd := &cobra.Command{
Use: "snapshots [flags] [snapshotID ...]", Use: "snapshots [flags] [snapshotID ...]",
Short: "List all snapshots", Short: "List all snapshots",
Long: ` Long: `
@ -33,10 +36,18 @@ Exit status is 12 if the password is incorrect.
GroupID: cmdGroupDefault, GroupID: cmdGroupDefault,
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runSnapshots(cmd.Context(), snapshotOptions, globalOptions, args) return runSnapshots(cmd.Context(), opts, globalOptions, args)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newSnapshotsCommand())
}
// SnapshotOptions bundles all options for the snapshots command. // SnapshotOptions bundles all options for the snapshots command.
type SnapshotOptions struct { type SnapshotOptions struct {
restic.SnapshotFilter restic.SnapshotFilter
@ -59,13 +70,6 @@ func (opts *SnapshotOptions) AddFlags(f *pflag.FlagSet) {
f.VarP(&opts.GroupBy, "group-by", "g", "`group` snapshots by host, paths and/or tags, separated by comma") f.VarP(&opts.GroupBy, "group-by", "g", "`group` snapshots by host, paths and/or tags, separated by comma")
} }
var snapshotOptions SnapshotOptions
func init() {
cmdRoot.AddCommand(cmdSnapshots)
snapshotOptions.AddFlags(cmdSnapshots.Flags())
}
func runSnapshots(ctx context.Context, opts SnapshotOptions, gopts GlobalOptions, args []string) error { func runSnapshots(ctx context.Context, opts SnapshotOptions, gopts GlobalOptions, args []string) error {
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock) ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
if err != nil { if err != nil {

View File

@ -21,7 +21,10 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
var cmdStats = &cobra.Command{ func newStatsCommand() *cobra.Command {
var opts StatsOptions
cmd := &cobra.Command{
Use: "stats [flags] [snapshot ID] [...]", Use: "stats [flags] [snapshot ID] [...]",
Short: "Scan the repository and show basic statistics", Short: "Scan the repository and show basic statistics",
Long: ` Long: `
@ -59,10 +62,21 @@ Exit status is 12 if the password is incorrect.
GroupID: cmdGroupDefault, GroupID: cmdGroupDefault,
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runStats(cmd.Context(), statsOptions, globalOptions, args) return runStats(cmd.Context(), opts, globalOptions, args)
}, },
} }
opts.AddFlags(cmd.Flags())
must(cmd.RegisterFlagCompletionFunc("mode", func(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
return []string{countModeRestoreSize, countModeUniqueFilesByContents, countModeBlobsPerFile, countModeRawData}, cobra.ShellCompDirectiveDefault
}))
return cmd
}
func init() {
cmdRoot.AddCommand(newStatsCommand())
}
// StatsOptions collects all options for the stats command. // StatsOptions collects all options for the stats command.
type StatsOptions struct { type StatsOptions struct {
// the mode of counting to perform (see consts for available modes) // the mode of counting to perform (see consts for available modes)
@ -76,22 +90,12 @@ func (opts *StatsOptions) AddFlags(f *pflag.FlagSet) {
initMultiSnapshotFilter(f, &opts.SnapshotFilter, true) initMultiSnapshotFilter(f, &opts.SnapshotFilter, true)
} }
var statsOptions StatsOptions
func must(err error) { func must(err error) {
if err != nil { if err != nil {
panic(fmt.Sprintf("error during setup: %v", err)) panic(fmt.Sprintf("error during setup: %v", err))
} }
} }
func init() {
cmdRoot.AddCommand(cmdStats)
statsOptions.AddFlags(cmdStats.Flags())
must(cmdStats.RegisterFlagCompletionFunc("mode", func(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
return []string{countModeRestoreSize, countModeUniqueFilesByContents, countModeBlobsPerFile, countModeRawData}, cobra.ShellCompDirectiveDefault
}))
}
func runStats(ctx context.Context, opts StatsOptions, gopts GlobalOptions, args []string) error { func runStats(ctx context.Context, opts StatsOptions, gopts GlobalOptions, args []string) error {
err := verifyStatsInput(opts) err := verifyStatsInput(opts)
if err != nil { if err != nil {

View File

@ -14,7 +14,10 @@ import (
"github.com/restic/restic/internal/ui/termstatus" "github.com/restic/restic/internal/ui/termstatus"
) )
var cmdTag = &cobra.Command{ func newTagCommand() *cobra.Command {
var opts TagOptions
cmd := &cobra.Command{
Use: "tag [flags] [snapshotID ...]", Use: "tag [flags] [snapshotID ...]",
Short: "Modify tags on snapshots", Short: "Modify tags on snapshots",
Long: ` Long: `
@ -39,10 +42,18 @@ Exit status is 12 if the password is incorrect.
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
term, cancel := setupTermstatus() term, cancel := setupTermstatus()
defer cancel() defer cancel()
return runTag(cmd.Context(), tagOptions, globalOptions, term, args) return runTag(cmd.Context(), opts, globalOptions, term, args)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newTagCommand())
}
// TagOptions bundles all options for the 'tag' command. // TagOptions bundles all options for the 'tag' command.
type TagOptions struct { type TagOptions struct {
restic.SnapshotFilter restic.SnapshotFilter
@ -58,13 +69,6 @@ func (opts *TagOptions) AddFlags(f *pflag.FlagSet) {
initMultiSnapshotFilter(f, &opts.SnapshotFilter, true) initMultiSnapshotFilter(f, &opts.SnapshotFilter, true)
} }
var tagOptions TagOptions
func init() {
cmdRoot.AddCommand(cmdTag)
tagOptions.AddFlags(cmdTag.Flags())
}
type changedSnapshot struct { type changedSnapshot struct {
MessageType string `json:"message_type"` // changed MessageType string `json:"message_type"` // changed
OldSnapshotID restic.ID `json:"old_snapshot_id"` OldSnapshotID restic.ID `json:"old_snapshot_id"`

View File

@ -8,7 +8,10 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
var unlockCmd = &cobra.Command{ func newUnlockCommand() *cobra.Command {
var opts UnlockOptions
cmd := &cobra.Command{
Use: "unlock", Use: "unlock",
Short: "Remove locks other processes created", Short: "Remove locks other processes created",
Long: ` Long: `
@ -23,9 +26,16 @@ Exit status is 1 if there was any error.
GroupID: cmdGroupDefault, GroupID: cmdGroupDefault,
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, _ []string) error { RunE: func(cmd *cobra.Command, _ []string) error {
return runUnlock(cmd.Context(), unlockOptions, globalOptions) return runUnlock(cmd.Context(), opts, globalOptions)
}, },
} }
opts.AddFlags(cmd.Flags())
return cmd
}
func init() {
cmdRoot.AddCommand(newUnlockCommand())
}
// UnlockOptions collects all options for the unlock command. // UnlockOptions collects all options for the unlock command.
type UnlockOptions struct { type UnlockOptions struct {
@ -36,13 +46,6 @@ func (opts *UnlockOptions) AddFlags(f *pflag.FlagSet) {
f.BoolVar(&opts.RemoveAll, "remove-all", false, "remove all locks, even non-stale ones") f.BoolVar(&opts.RemoveAll, "remove-all", false, "remove all locks, even non-stale ones")
} }
var unlockOptions UnlockOptions
func init() {
cmdRoot.AddCommand(unlockCmd)
unlockOptions.AddFlags(unlockCmd.Flags())
}
func runUnlock(ctx context.Context, opts UnlockOptions, gopts GlobalOptions) error { func runUnlock(ctx context.Context, opts UnlockOptions, gopts GlobalOptions) error {
repo, err := OpenRepository(ctx, gopts) repo, err := OpenRepository(ctx, gopts)
if err != nil { if err != nil {

View File

@ -8,7 +8,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var versionCmd = &cobra.Command{ func newVersionCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "version", Use: "version",
Short: "Print version information", Short: "Print version information",
Long: ` Long: `
@ -52,7 +53,9 @@ Exit status is 1 if there was any error.
}, },
} }
return cmd
}
func init() { func init() {
cmdRoot.AddCommand(versionCmd) cmdRoot.AddCommand(newVersionCommand())
} }