Skip to content

Commit

Permalink
Merge pull request #780 from rsteube/add-restic
Browse files Browse the repository at this point in the history
added restic
  • Loading branch information
rsteube authored Nov 29, 2021
2 parents 1da5e49 + 7b47e3a commit 4986577
Show file tree
Hide file tree
Showing 36 changed files with 1,036 additions and 12 deletions.
4 changes: 2 additions & 2 deletions completers/gh_completer/cmd/action/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"time"

"github.com/rsteube/carapace"
"github.com/rsteube/carapace-bin/completers/gh_completer/cmd/action/utils"
"github.com/rsteube/carapace-bin/pkg/util"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -43,7 +43,7 @@ func ActionReleases(cmd *cobra.Command) carapace.Action {
vals := make([]string, 0, len(releases)*2)
for _, release := range releases {
if release.Node.Tag.Name != "" {
vals = append(vals, release.Node.Tag.Name, utils.FuzzyAgo(time.Since(release.Node.CreatedAt)))
vals = append(vals, release.Node.Tag.Name, util.FuzzyAgo(time.Since(release.Node.CreatedAt)))
}
}
return carapace.ActionValuesDescribed(vals...)
Expand Down
4 changes: 2 additions & 2 deletions completers/gh_completer/cmd/action/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"time"

"github.com/rsteube/carapace"
"github.com/rsteube/carapace-bin/completers/gh_completer/cmd/action/utils"
"github.com/rsteube/carapace-bin/pkg/util"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -46,7 +46,7 @@ func ActionWorkflowRuns(cmd *cobra.Command, opts RunOpts) carapace.Action {
(opts.InProgress && run.Status == "in_progress") ||
(opts.Failed && run.Status == "completed" && run.Conclusion != "success") ||
(opts.Successful && run.Status == "completed" && run.Conclusion == "success") {
vals = append(vals, strconv.Itoa(run.Id), fmt.Sprintf("%v (%v) %v", run.Name, run.HeadBranch, utils.FuzzyAgo(ago)))
vals = append(vals, strconv.Itoa(run.Id), fmt.Sprintf("%v (%v) %v", run.Name, run.HeadBranch, util.FuzzyAgo(ago)))
}
}
return carapace.ActionValuesDescribed(vals...)
Expand Down
32 changes: 32 additions & 0 deletions completers/restic_completer/cmd/action/host.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package action

import (
"github.com/rsteube/carapace"
"github.com/rsteube/carapace-bin/pkg/util"
)

func ActionRepo() carapace.Action {
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
if util.HasPathPrefix(c.CallbackValue) {
return carapace.ActionDirectories()
}
return carapace.ActionMultiParts(":", func(c carapace.Context) carapace.Action {
switch len(c.Parts) {
case 0:
return carapace.ActionValuesDescribed(
"sftp", "SFTP",
"rest", "HTTP",
"s3", "Amazon S3",
"swift", "OpenStack Swift",
"b2", "Backblaze B2",
"azure", "Microsoft Azure Blob Storage",
"gs", "Google Cloud Storage",
"rclone", "rclone",
).Invoke(c).Suffix(":").ToA()
default:
// TODO completion
return carapace.ActionValues()
}
})
})
}
90 changes: 90 additions & 0 deletions completers/restic_completer/cmd/action/snapshot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package action

import (
"encoding/json"
"time"

"github.com/rsteube/carapace"
"github.com/rsteube/carapace-bin/pkg/util"
"github.com/spf13/cobra"
)

type snapshot struct {
Hostname string
Short_id string
Tags []string `json:"tags,omitempty"`
Time time.Time
}

type snapshotDetails struct {
Hostname string
Paths []string
Tags []string `json:"tags,omitempty"`
Time time.Time
}

func actionSnapshots(cmd *cobra.Command, f func(snapshots []snapshot) carapace.Action) carapace.Action {
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
args := []string{"snapshots", "--json"}
if f := cmd.Flag("repo"); f.Changed {
args = append(args, "--repo", f.Value.String())
}
return carapace.ActionExecCommand("restic", args...)(func(output []byte) carapace.Action {
var snapshots []snapshot
if err := json.Unmarshal(output, &snapshots); err != nil {
return carapace.ActionMessage(err.Error())
}
return f(snapshots)
})
})
}

func ActionSnapshotTags(cmd *cobra.Command) carapace.Action {
return actionSnapshots(cmd, func(snapshots []snapshot) carapace.Action {
tags := make(map[string]bool)
for _, s := range snapshots {
for _, t := range s.Tags {
tags[t] = true
}
}

vals := make([]string, 0)
for tag := range tags {
vals = append(vals, tag)
}
return carapace.ActionValues(vals...)
})
}

func ActionSnapshotHosts(cmd *cobra.Command) carapace.Action {
return actionSnapshots(cmd, func(snapshots []snapshot) carapace.Action {
vals := make([]string, 0)
for _, s := range snapshots {
vals = append(vals, s.Hostname)
}
return carapace.ActionValues(vals...)
})
}

func ActionSnapshotIDs(cmd *cobra.Command) carapace.Action {
return actionSnapshots(cmd, func(snapshots []snapshot) carapace.Action {
vals := make([]string, 0)
for _, s := range snapshots {
vals = append(vals, s.Short_id, util.FuzzyAgo(time.Since(s.Time)))
}
return carapace.ActionValuesDescribed(vals...)
})
}

func ActionSnapshotPaths(cmd *cobra.Command, id string) carapace.Action {
// TODO repo/path/alias flags
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
return carapace.ActionExecCommand("restic", "cat", "snapshot", id)(func(output []byte) carapace.Action {
var details snapshotDetails
if err := json.Unmarshal(output, &details); err != nil {
return carapace.ActionMessage(err.Error())
}
return carapace.ActionValues(details.Paths...)
})
})
}
59 changes: 59 additions & 0 deletions completers/restic_completer/cmd/backup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package cmd

import (
"github.com/rsteube/carapace"
"github.com/rsteube/carapace-bin/completers/restic_completer/cmd/action"
"github.com/rsteube/carapace-bin/pkg/actions/time"
"github.com/spf13/cobra"
)

var backupCmd = &cobra.Command{
Use: "backup",
Short: "Create a new backup of files and/or directories",
Run: func(cmd *cobra.Command, args []string) {},
}

func init() {
carapace.Gen(backupCmd).Standalone()
backupCmd.Flags().BoolP("dry-run", "n", false, "do not upload or write any data, just show what would be done")
backupCmd.Flags().StringArrayP("exclude", "e", []string{}, "exclude a `pattern` (can be specified multiple times)")
backupCmd.Flags().Bool("exclude-caches", false, "excludes cache directories that are marked with a CACHEDIR.TAG file. See https://bford.info/cachedir/ for the Cache Directory Tagging Standard")
backupCmd.Flags().StringArray("exclude-file", []string{}, "read exclude patterns from a `file` (can be specified multiple times)")
backupCmd.Flags().StringArray("exclude-if-present", []string{}, "takes `filename[:header]`, exclude contents of directories containing filename (except filename itself) if header of that file is as provided (can be specified multiple times)")
backupCmd.Flags().String("exclude-larger-than", "", "max `size` of the files to be backed up (allowed suffixes: k/K, m/M, g/G, t/T)")
backupCmd.Flags().StringArray("files-from", []string{}, "read the files to backup from `file` (can be combined with file args; can be specified multiple times)")
backupCmd.Flags().StringArray("files-from-raw", []string{}, "read the files to backup from `file` (can be combined with file args; can be specified multiple times)")
backupCmd.Flags().StringArray("files-from-verbatim", []string{}, "read the files to backup from `file` (can be combined with file args; can be specified multiple times)")
backupCmd.Flags().BoolP("force", "f", false, "force re-reading the target files/directories (overrides the \"parent\" flag)")
backupCmd.Flags().StringP("host", "H", "", "set the `hostname` for the snapshot manually. To prevent an expensive rescan use the \"parent\" flag")
backupCmd.Flags().String("hostname", "", "set the `hostname` for the snapshot manually")
backupCmd.Flags().StringArray("iexclude", []string{}, "same as --exclude `pattern` but ignores the casing of filenames")
backupCmd.Flags().StringArray("iexclude-file", []string{}, "same as --exclude-file but ignores casing of `file`names in patterns")
backupCmd.Flags().Bool("ignore-ctime", false, "ignore ctime changes when checking for modified files")
backupCmd.Flags().Bool("ignore-inode", false, "ignore inode number changes when checking for modified files")
backupCmd.Flags().BoolP("one-file-system", "x", false, "exclude other file systems, don't cross filesystem boundaries and subvolumes")
backupCmd.Flags().String("parent", "", "use this parent `snapshot` (default: last snapshot in the repo that has the same target files/directories)")
backupCmd.Flags().Bool("stdin", false, "read backup from stdin")
backupCmd.Flags().String("stdin-filename", "stdin", "`filename` to use when reading from stdin")
backupCmd.Flags().StringSlice("tag", []string{}, "add `tags` for the new snapshot in the format `tag[,tag,...]` (can be specified multiple times)")
backupCmd.Flags().String("time", "", "`time` of the backup (ex. '2012-11-01 22:08:41') (default: now)")
backupCmd.Flags().Bool("with-atime", false, "store the atime for all files and directories")
rootCmd.AddCommand(backupCmd)

carapace.Gen(backupCmd).FlagCompletion(carapace.ActionMap{
"exclude-file": carapace.ActionFiles(),
"files-from": carapace.ActionFiles(),
"files-from-raw": carapace.ActionFiles(),
"files-from-verbatim": carapace.ActionFiles(),
"host": action.ActionSnapshotHosts(backupCmd),
"parent": action.ActionSnapshotIDs(backupCmd),
"tag": carapace.ActionMultiParts(",", func(c carapace.Context) carapace.Action {
return action.ActionSnapshotTags(backupCmd).Invoke(c).Filter(c.Parts).ToA()
}),
"time": time.ActionDateTime(),
})

carapace.Gen(backupCmd).PositionalAnyCompletion(
carapace.ActionFiles(),
)
}
20 changes: 20 additions & 0 deletions completers/restic_completer/cmd/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package cmd

import (
"github.com/rsteube/carapace"
"github.com/spf13/cobra"
)

var cacheCmd = &cobra.Command{
Use: "cache",
Short: "Operate on local cache directories",
Run: func(cmd *cobra.Command, args []string) {},
}

func init() {
carapace.Gen(cacheCmd).Standalone()
cacheCmd.Flags().Bool("cleanup", false, "remove old cache directories")
cacheCmd.Flags().Uint("max-age", 30, "max age in `days` for cache directories to be considered old")
cacheCmd.Flags().Bool("no-size", false, "do not output the size of the cache directories")
rootCmd.AddCommand(cacheCmd)
}
31 changes: 31 additions & 0 deletions completers/restic_completer/cmd/cat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package cmd

import (
"github.com/rsteube/carapace"
"github.com/rsteube/carapace-bin/completers/restic_completer/cmd/action"
"github.com/spf13/cobra"
)

var catCmd = &cobra.Command{
Use: "cat",
Short: "Print internal objects to stdout",
Run: func(cmd *cobra.Command, args []string) {},
}

func init() {
carapace.Gen(catCmd).Standalone()
rootCmd.AddCommand(catCmd)

carapace.Gen(catCmd).PositionalCompletion(
carapace.ActionValues("pack", "blob", "snapshot", "index", "key", "masterkey", "config", "lock"),
carapace.ActionCallback(func(c carapace.Context) carapace.Action {
// TODO complete more objects
switch c.Args[0] {
case "snapshot":
return action.ActionSnapshotIDs(catCmd)
default:
return carapace.ActionValues()
}
}),
)
}
21 changes: 21 additions & 0 deletions completers/restic_completer/cmd/check.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package cmd

import (
"github.com/rsteube/carapace"
"github.com/spf13/cobra"
)

var checkCmd = &cobra.Command{
Use: "check",
Short: "Check the repository for errors",
Run: func(cmd *cobra.Command, args []string) {},
}

func init() {
carapace.Gen(checkCmd).Standalone()
checkCmd.Flags().Bool("check-unused", false, "find unused blobs")
checkCmd.Flags().Bool("read-data", false, "read all data blobs")
checkCmd.Flags().String("read-data-subset", "", "read a `subset` of data packs, specified as 'n/t' for specific subset or either 'x%' or 'x.y%' for random subset")
checkCmd.Flags().Bool("with-cache", false, "use the cache")
rootCmd.AddCommand(checkCmd)
}
44 changes: 44 additions & 0 deletions completers/restic_completer/cmd/copy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package cmd

import (
"github.com/rsteube/carapace"
"github.com/rsteube/carapace-bin/completers/restic_completer/cmd/action"
"github.com/spf13/cobra"
)

var copyCmd = &cobra.Command{
Use: "copy",
Short: "Copy snapshots from one repository to another",
Run: func(cmd *cobra.Command, args []string) {},
}

func init() {
carapace.Gen(copyCmd).Standalone()
copyCmd.Flags().StringArrayP("host", "H", []string{}, "only consider snapshots for this `host`, when no snapshot ID is given (can be specified multiple times)")
copyCmd.Flags().String("key-hint2", "", "key ID of key to try decrypting the destination repository first (default: $RESTIC_KEY_HINT2)")
copyCmd.Flags().String("password-command2", "", "shell `command` to obtain the destination repository password from (default: $RESTIC_PASSWORD_COMMAND2)")
copyCmd.Flags().String("password-file2", "", "`file` to read the destination repository password from (default: $RESTIC_PASSWORD_FILE2)")
copyCmd.Flags().StringArray("path", []string{}, "only consider snapshots which include this (absolute) `path`, when no snapshot ID is given")
copyCmd.Flags().String("repo2", "", "destination `repository` to copy snapshots to (default: $RESTIC_REPOSITORY2)")
copyCmd.Flags().String("repository-file2", "", "`file` from which to read the destination repository location to copy snapshots to (default: $RESTIC_REPOSITORY_FILE2)")
copyCmd.Flags().StringSlice("tag", []string{}, "only consider snapshots which include this `taglist`, when no snapshot ID is given")
rootCmd.AddCommand(copyCmd)

carapace.Gen(copyCmd).FlagCompletion(carapace.ActionMap{
"host": action.ActionSnapshotHosts(copyCmd),
"password-command2": carapace.ActionFiles(),
"password-file2": carapace.ActionFiles(),
"path": carapace.ActionFiles(),
"repo2": action.ActionRepo(),
"repository-file2": carapace.ActionFiles(),
"tag": carapace.ActionMultiParts(",", func(c carapace.Context) carapace.Action {
return action.ActionSnapshotTags(copyCmd).Invoke(c).Filter(c.Parts).ToA()
}),
})

carapace.Gen(copyCmd).PositionalAnyCompletion(
carapace.ActionCallback(func(c carapace.Context) carapace.Action {
return action.ActionSnapshotIDs(copyCmd).Invoke(c).Filter(c.Args).ToA()
}),
)
}
26 changes: 26 additions & 0 deletions completers/restic_completer/cmd/diff.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package cmd

import (
"github.com/rsteube/carapace"
"github.com/rsteube/carapace-bin/completers/restic_completer/cmd/action"
"github.com/spf13/cobra"
)

var diffCmd = &cobra.Command{
Use: "diff",
Short: "Show differences between two snapshots",
Run: func(cmd *cobra.Command, args []string) {},
}

func init() {
carapace.Gen(diffCmd).Standalone()
diffCmd.Flags().Bool("metadata", false, "print changes in metadata")
rootCmd.AddCommand(diffCmd)

carapace.Gen(diffCmd).PositionalCompletion(
action.ActionSnapshotIDs(diffCmd),
carapace.ActionCallback(func(c carapace.Context) carapace.Action {
return action.ActionSnapshotIDs(diffCmd).Invoke(c).Filter(c.Args[:1]).ToA()
}),
)
}
Loading

0 comments on commit 4986577

Please sign in to comment.