forked from TrueCloudLab/restic
Restructure cmd/restic
, no functional changes
This commit is contained in:
parent
2fa259816b
commit
4388474cdc
16 changed files with 309 additions and 264 deletions
|
@ -16,13 +16,15 @@ import (
|
||||||
type CmdBackup struct {
|
type CmdBackup struct {
|
||||||
Parent string `short:"p" long:"parent" description:"use this parent snapshot (default: last snapshot in repo that has the same target)"`
|
Parent string `short:"p" long:"parent" description:"use this parent snapshot (default: last snapshot in repo that has the same target)"`
|
||||||
Force bool `short:"f" long:"force" description:"Force re-reading the target. Overrides the \"parent\" flag"`
|
Force bool `short:"f" long:"force" description:"Force re-reading the target. Overrides the \"parent\" flag"`
|
||||||
|
|
||||||
|
global *GlobalOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
_, err := parser.AddCommand("backup",
|
_, err := parser.AddCommand("backup",
|
||||||
"save file/directory",
|
"save file/directory",
|
||||||
"The backup command creates a snapshot of a file or directory",
|
"The backup command creates a snapshot of a file or directory",
|
||||||
&CmdBackup{})
|
&CmdBackup{global: &globalOpts})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -97,8 +99,8 @@ func (cmd CmdBackup) Usage() string {
|
||||||
return "DIR/FILE [DIR/FILE] [...]"
|
return "DIR/FILE [DIR/FILE] [...]"
|
||||||
}
|
}
|
||||||
|
|
||||||
func newScanProgress() *restic.Progress {
|
func (cmd CmdBackup) newScanProgress() *restic.Progress {
|
||||||
if disableProgress() {
|
if !cmd.global.ShowProgress() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,8 +115,8 @@ func newScanProgress() *restic.Progress {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func newArchiveProgress(todo restic.Stat) *restic.Progress {
|
func (cmd CmdBackup) newArchiveProgress(todo restic.Stat) *restic.Progress {
|
||||||
if disableProgress() {
|
if !cmd.global.ShowProgress() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,7 +215,7 @@ func (cmd CmdBackup) Execute(args []string) error {
|
||||||
target = append(target, d)
|
target = append(target, d)
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := OpenRepo()
|
s, err := cmd.global.OpenRepository()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -232,7 +234,7 @@ func (cmd CmdBackup) Execute(args []string) error {
|
||||||
return fmt.Errorf("invalid id %q: %v", cmd.Parent, err)
|
return fmt.Errorf("invalid id %q: %v", cmd.Parent, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
verbosePrintf("found parent snapshot %v\n", parentSnapshotID.Str())
|
cmd.global.Printf("found parent snapshot %v\n", parentSnapshotID.Str())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find last snapshot to set it as parent, if not already set
|
// Find last snapshot to set it as parent, if not already set
|
||||||
|
@ -243,13 +245,13 @@ func (cmd CmdBackup) Execute(args []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if parentSnapshotID != nil {
|
if parentSnapshotID != nil {
|
||||||
verbosePrintf("using parent snapshot %v\n", parentSnapshotID)
|
cmd.global.Printf("using parent snapshot %v\n", parentSnapshotID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
verbosePrintf("scan %v\n", target)
|
cmd.global.Printf("scan %v\n", target)
|
||||||
|
|
||||||
stat, err := restic.Scan(target, newScanProgress())
|
stat, err := restic.Scan(target, cmd.newScanProgress())
|
||||||
|
|
||||||
// TODO: add filter
|
// TODO: add filter
|
||||||
// arch.Filter = func(dir string, fi os.FileInfo) bool {
|
// arch.Filter = func(dir string, fi os.FileInfo) bool {
|
||||||
|
@ -264,12 +266,12 @@ func (cmd CmdBackup) Execute(args []string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, id, err := arch.Snapshot(newArchiveProgress(stat), target, parentSnapshotID)
|
_, id, err := arch.Snapshot(cmd.newArchiveProgress(stat), target, parentSnapshotID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
verbosePrintf("snapshot %s saved\n", id.Str())
|
cmd.global.Printf("snapshot %s saved\n", id.Str())
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,15 @@ import (
|
||||||
"github.com/restic/restic"
|
"github.com/restic/restic"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CmdCache struct{}
|
type CmdCache struct {
|
||||||
|
global *GlobalOptions
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
_, err := parser.AddCommand("cache",
|
_, err := parser.AddCommand("cache",
|
||||||
"manage cache",
|
"manage cache",
|
||||||
"The cache command creates and manages the local cache",
|
"The cache command creates and manages the local cache",
|
||||||
&CmdCache{})
|
&CmdCache{global: &globalOpts})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -27,12 +29,12 @@ func (cmd CmdCache) Execute(args []string) error {
|
||||||
// return fmt.Errorf("wrong number of parameters, Usage: %s", cmd.Usage())
|
// return fmt.Errorf("wrong number of parameters, Usage: %s", cmd.Usage())
|
||||||
// }
|
// }
|
||||||
|
|
||||||
s, err := OpenRepo()
|
s, err := cmd.global.OpenRepository()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cache, err := restic.NewCache(s, mainOpts.CacheDir)
|
cache, err := restic.NewCache(s, cmd.global.CacheDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,15 @@ import (
|
||||||
"github.com/restic/restic/repository"
|
"github.com/restic/restic/repository"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CmdCat struct{}
|
type CmdCat struct {
|
||||||
|
global *GlobalOptions
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
_, err := parser.AddCommand("cat",
|
_, err := parser.AddCommand("cat",
|
||||||
"dump something",
|
"dump something",
|
||||||
"The cat command dumps data structures or data from a repository",
|
"The cat command dumps data structures or data from a repository",
|
||||||
&CmdCat{})
|
&CmdCat{global: &globalOpts})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -35,7 +37,7 @@ func (cmd CmdCat) Execute(args []string) error {
|
||||||
return fmt.Errorf("type or ID not specified, Usage: %s", cmd.Usage())
|
return fmt.Errorf("type or ID not specified, Usage: %s", cmd.Usage())
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := OpenRepo()
|
s, err := cmd.global.OpenRepository()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,13 +15,15 @@ import (
|
||||||
"github.com/restic/restic/repository"
|
"github.com/restic/restic/repository"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CmdDump struct{}
|
type CmdDump struct {
|
||||||
|
global *MainOptions
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
_, err := parser.AddCommand("dump",
|
_, err := parser.AddCommand("dump",
|
||||||
"dump data structures",
|
"dump data structures",
|
||||||
"The dump command dumps data structures from a repository as JSON documents",
|
"The dump command dumps data structures from a repository as JSON documents",
|
||||||
&CmdDump{})
|
&CmdDump{global: &mainOpts})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -102,7 +104,7 @@ func (cmd CmdDump) Execute(args []string) error {
|
||||||
return fmt.Errorf("type not specified, Usage: %s", cmd.Usage())
|
return fmt.Errorf("type not specified, Usage: %s", cmd.Usage())
|
||||||
}
|
}
|
||||||
|
|
||||||
repo, err := OpenRepo()
|
repo, err := cmd.global.OpenRepository()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ type CmdFind struct {
|
||||||
|
|
||||||
oldest, newest time.Time
|
oldest, newest time.Time
|
||||||
pattern string
|
pattern string
|
||||||
|
global *GlobalOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
var timeFormats = []string{
|
var timeFormats = []string{
|
||||||
|
@ -43,7 +44,7 @@ func init() {
|
||||||
_, err := parser.AddCommand("find",
|
_, err := parser.AddCommand("find",
|
||||||
"find a file/directory",
|
"find a file/directory",
|
||||||
"The find command searches for files or directories in snapshots",
|
"The find command searches for files or directories in snapshots",
|
||||||
&CmdFind{})
|
&CmdFind{global: &globalOpts})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -156,7 +157,7 @@ func (c CmdFind) Execute(args []string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := OpenRepo()
|
s, err := c.global.OpenRepository()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@ type CmdFsck struct {
|
||||||
Orphaned bool `short:"o" long:"orphaned" description:"Check for orphaned blobs"`
|
Orphaned bool `short:"o" long:"orphaned" description:"Check for orphaned blobs"`
|
||||||
RemoveOrphaned bool `short:"r" long:"remove-orphaned" description:"Remove orphaned blobs (implies -o)"`
|
RemoveOrphaned bool `short:"r" long:"remove-orphaned" description:"Remove orphaned blobs (implies -o)"`
|
||||||
|
|
||||||
|
global *GlobalOptions
|
||||||
|
|
||||||
// lists checking for orphaned blobs
|
// lists checking for orphaned blobs
|
||||||
o_data *backend.IDSet
|
o_data *backend.IDSet
|
||||||
o_trees *backend.IDSet
|
o_trees *backend.IDSet
|
||||||
|
@ -28,13 +30,13 @@ func init() {
|
||||||
_, err := parser.AddCommand("fsck",
|
_, err := parser.AddCommand("fsck",
|
||||||
"check the repository",
|
"check the repository",
|
||||||
"The fsck command check the integrity and consistency of the repository",
|
"The fsck command check the integrity and consistency of the repository",
|
||||||
&CmdFsck{})
|
&CmdFsck{global: &globalOpts})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fsckFile(opts CmdFsck, repo *repository.Repository, IDs []backend.ID) (uint64, error) {
|
func fsckFile(global CmdFsck, repo *repository.Repository, IDs []backend.ID) (uint64, error) {
|
||||||
debug.Log("restic.fsckFile", "checking file %v", IDs)
|
debug.Log("restic.fsckFile", "checking file %v", IDs)
|
||||||
var bytes uint64
|
var bytes uint64
|
||||||
|
|
||||||
|
@ -50,7 +52,7 @@ func fsckFile(opts CmdFsck, repo *repository.Repository, IDs []backend.ID) (uint
|
||||||
bytes += uint64(length - crypto.Extension)
|
bytes += uint64(length - crypto.Extension)
|
||||||
debug.Log("restic.fsck", " blob found in pack %v\n", packID)
|
debug.Log("restic.fsck", " blob found in pack %v\n", packID)
|
||||||
|
|
||||||
if opts.CheckData {
|
if global.CheckData {
|
||||||
// load content
|
// load content
|
||||||
_, err := repo.LoadBlob(pack.Data, id)
|
_, err := repo.LoadBlob(pack.Data, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -69,16 +71,16 @@ func fsckFile(opts CmdFsck, repo *repository.Repository, IDs []backend.ID) (uint
|
||||||
}
|
}
|
||||||
|
|
||||||
// if orphan check is active, record storage id
|
// if orphan check is active, record storage id
|
||||||
if opts.o_data != nil {
|
if global.o_data != nil {
|
||||||
debug.Log("restic.fsck", " recording blob %v as used\n", id)
|
debug.Log("restic.fsck", " recording blob %v as used\n", id)
|
||||||
opts.o_data.Insert(id)
|
global.o_data.Insert(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytes, nil
|
return bytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fsckTree(opts CmdFsck, repo *repository.Repository, id backend.ID) error {
|
func fsckTree(global CmdFsck, repo *repository.Repository, id backend.ID) error {
|
||||||
debug.Log("restic.fsckTree", "checking tree %v", id.Str())
|
debug.Log("restic.fsckTree", "checking tree %v", id.Str())
|
||||||
|
|
||||||
tree, err := restic.LoadTree(repo, id)
|
tree, err := restic.LoadTree(repo, id)
|
||||||
|
@ -87,9 +89,9 @@ func fsckTree(opts CmdFsck, repo *repository.Repository, id backend.ID) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if orphan check is active, record storage id
|
// if orphan check is active, record storage id
|
||||||
if opts.o_trees != nil {
|
if global.o_trees != nil {
|
||||||
// add ID to list
|
// add ID to list
|
||||||
opts.o_trees.Insert(id)
|
global.o_trees.Insert(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
var firstErr error
|
var firstErr error
|
||||||
|
@ -123,7 +125,7 @@ func fsckTree(opts CmdFsck, repo *repository.Repository, id backend.ID) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
debug.Log("restic.fsckTree", "check file %v (%v)", node.Name, id.Str())
|
debug.Log("restic.fsckTree", "check file %v (%v)", node.Name, id.Str())
|
||||||
bytes, err := fsckFile(opts, repo, node.Content)
|
bytes, err := fsckFile(global, repo, node.Content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -140,7 +142,7 @@ func fsckTree(opts CmdFsck, repo *repository.Repository, id backend.ID) error {
|
||||||
// record id
|
// record id
|
||||||
seenIDs.Insert(node.Subtree)
|
seenIDs.Insert(node.Subtree)
|
||||||
|
|
||||||
err = fsckTree(opts, repo, node.Subtree)
|
err = fsckTree(global, repo, node.Subtree)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
firstErr = err
|
firstErr = err
|
||||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||||
|
@ -158,7 +160,7 @@ func fsckTree(opts CmdFsck, repo *repository.Repository, id backend.ID) error {
|
||||||
return firstErr
|
return firstErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func fsckSnapshot(opts CmdFsck, repo *repository.Repository, id backend.ID) error {
|
func fsckSnapshot(global CmdFsck, repo *repository.Repository, id backend.ID) error {
|
||||||
debug.Log("restic.fsck", "checking snapshot %v\n", id)
|
debug.Log("restic.fsck", "checking snapshot %v\n", id)
|
||||||
|
|
||||||
sn, err := restic.LoadSnapshot(repo, id)
|
sn, err := restic.LoadSnapshot(repo, id)
|
||||||
|
@ -166,7 +168,7 @@ func fsckSnapshot(opts CmdFsck, repo *repository.Repository, id backend.ID) erro
|
||||||
return fmt.Errorf("loading snapshot %v failed: %v", id, err)
|
return fmt.Errorf("loading snapshot %v failed: %v", id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = fsckTree(opts, repo, sn.Tree)
|
err = fsckTree(global, repo, sn.Tree)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
debug.Log("restic.fsck", " checking tree %v for snapshot %v\n", sn.Tree, id)
|
debug.Log("restic.fsck", " checking tree %v for snapshot %v\n", sn.Tree, id)
|
||||||
fmt.Fprintf(os.Stderr, "snapshot %v:\n error for tree %v:\n %v\n", id, sn.Tree, err)
|
fmt.Fprintf(os.Stderr, "snapshot %v:\n error for tree %v:\n %v\n", id, sn.Tree, err)
|
||||||
|
@ -188,7 +190,7 @@ func (cmd CmdFsck) Execute(args []string) error {
|
||||||
cmd.Orphaned = true
|
cmd.Orphaned = true
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := OpenRepo()
|
s, err := cmd.global.OpenRepository()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
52
cmd/restic/cmd_init.go
Normal file
52
cmd/restic/cmd_init.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/restic/restic/repository"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CmdInit struct {
|
||||||
|
global *GlobalOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd CmdInit) Execute(args []string) error {
|
||||||
|
if cmd.global.Repo == "" {
|
||||||
|
return errors.New("Please specify repository location (-r)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if cmd.global.password == "" {
|
||||||
|
cmd.global.password = cmd.global.ReadPasswordTwice(
|
||||||
|
"enter password for new backend: ",
|
||||||
|
"enter password again: ")
|
||||||
|
}
|
||||||
|
|
||||||
|
be, err := create(cmd.global.Repo)
|
||||||
|
if err != nil {
|
||||||
|
cmd.global.Exitf(1, "creating backend at %s failed: %v\n", cmd.global.Repo, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s := repository.New(be)
|
||||||
|
err = s.Init(cmd.global.password)
|
||||||
|
if err != nil {
|
||||||
|
cmd.global.Exitf(1, "creating key in backend at %s failed: %v\n", cmd.global.Repo, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.global.Printf("created restic backend %v at %s\n", s.Config.ID[:10], cmd.global.Repo)
|
||||||
|
cmd.global.Printf("\n")
|
||||||
|
cmd.global.Printf("Please note that knowledge of your password is required to access\n")
|
||||||
|
cmd.global.Printf("the repository. Losing your password means that your data is\n")
|
||||||
|
cmd.global.Printf("irrecoverably lost.\n")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
_, err := parser.AddCommand("init",
|
||||||
|
"create repository",
|
||||||
|
"The init command creates a new repository",
|
||||||
|
&CmdInit{global: &globalOpts})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,19 +9,21 @@ import (
|
||||||
"github.com/restic/restic/repository"
|
"github.com/restic/restic/repository"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CmdKey struct{}
|
type CmdKey struct {
|
||||||
|
global *GlobalOptions
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
_, err := parser.AddCommand("key",
|
_, err := parser.AddCommand("key",
|
||||||
"manage keys",
|
"manage keys",
|
||||||
"The key command manages keys (passwords) of a repository",
|
"The key command manages keys (passwords) of a repository",
|
||||||
&CmdKey{})
|
&CmdKey{global: &globalOpts})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func listKeys(s *repository.Repository) error {
|
func (cmd CmdKey) listKeys(s *repository.Repository) error {
|
||||||
tab := NewTable()
|
tab := NewTable()
|
||||||
tab.Header = fmt.Sprintf(" %-10s %-10s %-10s %s", "ID", "User", "Host", "Created")
|
tab.Header = fmt.Sprintf(" %-10s %-10s %-10s %s", "ID", "User", "Host", "Created")
|
||||||
tab.RowFormat = "%s%-10s %-10s %-10s %s"
|
tab.RowFormat = "%s%-10s %-10s %-10s %s"
|
||||||
|
@ -56,23 +58,20 @@ func listKeys(s *repository.Repository) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNewPassword() (string, error) {
|
func (cmd CmdKey) getNewPassword() (string, error) {
|
||||||
newPassword := os.Getenv("RESTIC_NEWPASSWORD")
|
newPassword := os.Getenv("RESTIC_NEWPASSWORD")
|
||||||
|
|
||||||
if newPassword == "" {
|
if newPassword == "" {
|
||||||
newPassword = readPassword("enter password for new key: ")
|
newPassword = cmd.global.ReadPasswordTwice(
|
||||||
newPassword2 := readPassword("enter password again: ")
|
"enter password for new key: ",
|
||||||
|
"enter password again: ")
|
||||||
if newPassword != newPassword2 {
|
|
||||||
return "", errors.New("passwords do not match")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return newPassword, nil
|
return newPassword, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addKey(repo *repository.Repository) error {
|
func (cmd CmdKey) addKey(repo *repository.Repository) error {
|
||||||
newPassword, err := getNewPassword()
|
newPassword, err := cmd.getNewPassword()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -87,7 +86,7 @@ func addKey(repo *repository.Repository) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteKey(repo *repository.Repository, name string) error {
|
func (cmd CmdKey) deleteKey(repo *repository.Repository, name string) error {
|
||||||
if name == repo.KeyName() {
|
if name == repo.KeyName() {
|
||||||
return errors.New("refusing to remove key currently used to access repository")
|
return errors.New("refusing to remove key currently used to access repository")
|
||||||
}
|
}
|
||||||
|
@ -101,8 +100,8 @@ func deleteKey(repo *repository.Repository, name string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func changePassword(repo *repository.Repository) error {
|
func (cmd CmdKey) changePassword(repo *repository.Repository) error {
|
||||||
newPassword, err := getNewPassword()
|
newPassword, err := cmd.getNewPassword()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -131,25 +130,25 @@ func (cmd CmdKey) Execute(args []string) error {
|
||||||
return fmt.Errorf("wrong number of arguments, Usage: %s", cmd.Usage())
|
return fmt.Errorf("wrong number of arguments, Usage: %s", cmd.Usage())
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := OpenRepo()
|
s, err := cmd.global.OpenRepository()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch args[0] {
|
switch args[0] {
|
||||||
case "list":
|
case "list":
|
||||||
return listKeys(s)
|
return cmd.listKeys(s)
|
||||||
case "add":
|
case "add":
|
||||||
return addKey(s)
|
return cmd.addKey(s)
|
||||||
case "rm":
|
case "rm":
|
||||||
id, err := backend.Find(s.Backend(), backend.Key, args[1])
|
id, err := backend.Find(s.Backend(), backend.Key, args[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return deleteKey(s, id)
|
return cmd.deleteKey(s, id)
|
||||||
case "passwd":
|
case "passwd":
|
||||||
return changePassword(s)
|
return cmd.changePassword(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -10,14 +10,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type CmdList struct {
|
type CmdList struct {
|
||||||
w io.Writer
|
w io.Writer
|
||||||
|
global *GlobalOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
_, err := parser.AddCommand("list",
|
_, err := parser.AddCommand("list",
|
||||||
"lists data",
|
"lists data",
|
||||||
"The list command lists structures or data of a repository",
|
"The list command lists structures or data of a repository",
|
||||||
&CmdList{})
|
&CmdList{global: &globalOpts})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -36,7 +37,7 @@ func (cmd CmdList) Execute(args []string) error {
|
||||||
return fmt.Errorf("type not specified, Usage: %s", cmd.Usage())
|
return fmt.Errorf("type not specified, Usage: %s", cmd.Usage())
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := OpenRepo()
|
s, err := cmd.global.OpenRepository()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,15 @@ import (
|
||||||
"github.com/restic/restic/repository"
|
"github.com/restic/restic/repository"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CmdLs struct{}
|
type CmdLs struct {
|
||||||
|
global *GlobalOptions
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
_, err := parser.AddCommand("ls",
|
_, err := parser.AddCommand("ls",
|
||||||
"list files",
|
"list files",
|
||||||
"The ls command lists all files and directories in a snapshot",
|
"The ls command lists all files and directories in a snapshot",
|
||||||
&CmdLs{})
|
&CmdLs{global: &globalOpts})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -67,7 +69,7 @@ func (cmd CmdLs) Execute(args []string) error {
|
||||||
return fmt.Errorf("wrong number of arguments, Usage: %s", cmd.Usage())
|
return fmt.Errorf("wrong number of arguments, Usage: %s", cmd.Usage())
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := OpenRepo()
|
s, err := cmd.global.OpenRepository()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,15 @@ import (
|
||||||
"github.com/restic/restic"
|
"github.com/restic/restic"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CmdRestore struct{}
|
type CmdRestore struct {
|
||||||
|
global *GlobalOptions
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
_, err := parser.AddCommand("restore",
|
_, err := parser.AddCommand("restore",
|
||||||
"restore a snapshot",
|
"restore a snapshot",
|
||||||
"The restore command restores a snapshot to a directory",
|
"The restore command restores a snapshot to a directory",
|
||||||
&CmdRestore{})
|
&CmdRestore{global: &globalOpts})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -29,7 +31,7 @@ func (cmd CmdRestore) Execute(args []string) error {
|
||||||
return fmt.Errorf("wrong number of arguments, Usage: %s", cmd.Usage())
|
return fmt.Errorf("wrong number of arguments, Usage: %s", cmd.Usage())
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := OpenRepo()
|
s, err := cmd.global.OpenRepository()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -41,7 +43,7 @@ func (cmd CmdRestore) Execute(args []string) error {
|
||||||
|
|
||||||
id, err := restic.FindSnapshot(s, args[0])
|
id, err := restic.FindSnapshot(s, args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errx(1, "invalid id %q: %v", args[0], err)
|
cmd.global.Exitf(1, "invalid id %q: %v", args[0], err)
|
||||||
}
|
}
|
||||||
|
|
||||||
target := args[1]
|
target := args[1]
|
||||||
|
@ -81,7 +83,7 @@ func (cmd CmdRestore) Execute(args []string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
verbosePrintf("restoring %s to %s\n", res.Snapshot(), target)
|
cmd.global.Printf("restoring %s to %s\n", res.Snapshot(), target)
|
||||||
|
|
||||||
err = res.RestoreTo(target)
|
err = res.RestoreTo(target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -71,13 +71,15 @@ func reltime(t time.Time) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type CmdSnapshots struct{}
|
type CmdSnapshots struct {
|
||||||
|
global *GlobalOptions
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
_, err := parser.AddCommand("snapshots",
|
_, err := parser.AddCommand("snapshots",
|
||||||
"show snapshots",
|
"show snapshots",
|
||||||
"The snapshots command lists all snapshots stored in a repository",
|
"The snapshots command lists all snapshots stored in a repository",
|
||||||
&CmdSnapshots{})
|
&CmdSnapshots{global: &globalOpts})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -92,7 +94,7 @@ func (cmd CmdSnapshots) Execute(args []string) error {
|
||||||
return fmt.Errorf("wrong number of arguments, usage: %s", cmd.Usage())
|
return fmt.Errorf("wrong number of arguments, usage: %s", cmd.Usage())
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := OpenRepo()
|
s, err := cmd.global.OpenRepository()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
162
cmd/restic/global.go
Normal file
162
cmd/restic/global.go
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/jessevdk/go-flags"
|
||||||
|
"github.com/restic/restic/backend"
|
||||||
|
"github.com/restic/restic/backend/local"
|
||||||
|
"github.com/restic/restic/backend/sftp"
|
||||||
|
"github.com/restic/restic/repository"
|
||||||
|
"golang.org/x/crypto/ssh/terminal"
|
||||||
|
)
|
||||||
|
|
||||||
|
var version = "compiled manually"
|
||||||
|
|
||||||
|
type GlobalOptions struct {
|
||||||
|
Repo string `short:"r" long:"repo" description:"Repository directory to backup to/restore from"`
|
||||||
|
CacheDir string ` long:"cache-dir" description:"Directory to use as a local cache"`
|
||||||
|
Quiet bool `short:"q" long:"quiet" default:"false" description:"Do not output comprehensive progress report"`
|
||||||
|
|
||||||
|
password string
|
||||||
|
stdout io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
var globalOpts = GlobalOptions{stdout: os.Stdout}
|
||||||
|
var parser = flags.NewParser(&globalOpts, flags.Default)
|
||||||
|
|
||||||
|
func (o GlobalOptions) Printf(format string, args ...interface{}) {
|
||||||
|
if o.Quiet {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := fmt.Fprintf(o.stdout, format, args...)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "unable to write to stdout: %v\n", err)
|
||||||
|
os.Exit(100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o GlobalOptions) ShowProgress() bool {
|
||||||
|
if o.Quiet {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !terminal.IsTerminal(int(os.Stdout.Fd())) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o GlobalOptions) Warnf(format string, args ...interface{}) {
|
||||||
|
_, err := fmt.Fprintf(os.Stderr, format, args...)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "unable to write to stderr: %v\n", err)
|
||||||
|
os.Exit(100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o GlobalOptions) Exitf(exitcode int, format string, args ...interface{}) {
|
||||||
|
if format[len(format)-1] != '\n' {
|
||||||
|
format += "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
o.Warnf(format, args...)
|
||||||
|
os.Exit(exitcode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o GlobalOptions) ReadPassword(prompt string) string {
|
||||||
|
fmt.Fprint(os.Stderr, prompt)
|
||||||
|
pw, err := terminal.ReadPassword(int(os.Stdin.Fd()))
|
||||||
|
if err != nil {
|
||||||
|
o.Exitf(2, "unable to read password: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(os.Stderr)
|
||||||
|
|
||||||
|
return string(pw)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o GlobalOptions) ReadPasswordTwice(prompt1, prompt2 string) string {
|
||||||
|
pw1 := o.ReadPassword(prompt1)
|
||||||
|
pw2 := o.ReadPassword(prompt2)
|
||||||
|
if pw1 != pw2 {
|
||||||
|
o.Exitf(1, "passwords do not match")
|
||||||
|
}
|
||||||
|
|
||||||
|
return pw1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o GlobalOptions) OpenRepository() (*repository.Repository, error) {
|
||||||
|
if o.Repo == "" {
|
||||||
|
return nil, errors.New("Please specify repository location (-r)")
|
||||||
|
}
|
||||||
|
|
||||||
|
be, err := open(o.Repo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s := repository.New(be)
|
||||||
|
|
||||||
|
if o.password == "" {
|
||||||
|
o.password = o.ReadPassword("enter password for repository: ")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.SearchKey(o.password)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to open repo: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the backend specified by URI.
|
||||||
|
// Valid formats are:
|
||||||
|
// * /foo/bar -> local repository at /foo/bar
|
||||||
|
// * sftp://user@host/foo/bar -> remote sftp repository on host for user at path foo/bar
|
||||||
|
// * sftp://host//tmp/backup -> remote sftp repository on host at path /tmp/backup
|
||||||
|
func open(u string) (backend.Backend, error) {
|
||||||
|
url, err := url.Parse(u)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if url.Scheme == "" {
|
||||||
|
return local.Open(url.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{url.Host}
|
||||||
|
if url.User != nil && url.User.Username() != "" {
|
||||||
|
args = append(args, "-l")
|
||||||
|
args = append(args, url.User.Username())
|
||||||
|
}
|
||||||
|
args = append(args, "-s")
|
||||||
|
args = append(args, "sftp")
|
||||||
|
return sftp.Open(url.Path[1:], "ssh", args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the backend specified by URI.
|
||||||
|
func create(u string) (backend.Backend, error) {
|
||||||
|
url, err := url.Parse(u)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if url.Scheme == "" {
|
||||||
|
return local.Create(url.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{url.Host}
|
||||||
|
if url.User != nil && url.User.Username() != "" {
|
||||||
|
args = append(args, "-l")
|
||||||
|
args = append(args, url.User.Username())
|
||||||
|
}
|
||||||
|
args = append(args, "-s")
|
||||||
|
args = append(args, "sftp")
|
||||||
|
return sftp.Create(url.Path[1:], "ssh", args...)
|
||||||
|
}
|
|
@ -177,11 +177,11 @@ type testEnvironment struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureRestic(t testing.TB, cache, repo string) {
|
func configureRestic(t testing.TB, cache, repo string) {
|
||||||
mainOpts.CacheDir = cache
|
globalOpts.CacheDir = cache
|
||||||
mainOpts.Repo = repo
|
globalOpts.Repo = repo
|
||||||
mainOpts.Quiet = true
|
globalOpts.Quiet = true
|
||||||
|
|
||||||
mainOpts.password = TestPassword
|
globalOpts.password = TestPassword
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanupTempdir(t testing.TB, tempdir string) {
|
func cleanupTempdir(t testing.TB, tempdir string) {
|
||||||
|
|
|
@ -49,7 +49,7 @@ func cmdInit(t testing.TB) {
|
||||||
cmd := &CmdInit{}
|
cmd := &CmdInit{}
|
||||||
OK(t, cmd.Execute(nil))
|
OK(t, cmd.Execute(nil))
|
||||||
|
|
||||||
t.Logf("repository initialized at %v", mainOpts.Repo)
|
t.Logf("repository initialized at %v", globalOpts.Repo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdBackup(t testing.TB, target []string, parentID backend.ID) {
|
func cmdBackup(t testing.TB, target []string, parentID backend.ID) {
|
||||||
|
|
|
@ -1,209 +1,23 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
|
||||||
|
|
||||||
"github.com/jessevdk/go-flags"
|
"github.com/jessevdk/go-flags"
|
||||||
"github.com/restic/restic/backend"
|
|
||||||
"github.com/restic/restic/backend/local"
|
|
||||||
"github.com/restic/restic/backend/sftp"
|
|
||||||
"github.com/restic/restic/debug"
|
"github.com/restic/restic/debug"
|
||||||
"github.com/restic/restic/repository"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = "compiled manually"
|
|
||||||
|
|
||||||
var mainOpts struct {
|
|
||||||
Repo string `short:"r" long:"repo" description:"Repository directory to backup to/restore from"`
|
|
||||||
CacheDir string ` long:"cache-dir" description:"Directory to use as a local cache"`
|
|
||||||
Quiet bool `short:"q" long:"quiet" default:"false" description:"Do not output comprehensive progress report"`
|
|
||||||
|
|
||||||
password string
|
|
||||||
}
|
|
||||||
|
|
||||||
var parser = flags.NewParser(&mainOpts, flags.Default)
|
|
||||||
|
|
||||||
func errx(code int, format string, data ...interface{}) {
|
|
||||||
if len(format) > 0 && format[len(format)-1] != '\n' {
|
|
||||||
format += "\n"
|
|
||||||
}
|
|
||||||
fmt.Fprintf(os.Stderr, format, data...)
|
|
||||||
os.Exit(code)
|
|
||||||
}
|
|
||||||
|
|
||||||
func readPassword(prompt string) string {
|
|
||||||
fmt.Fprint(os.Stderr, prompt)
|
|
||||||
pw, err := terminal.ReadPassword(int(os.Stdin.Fd()))
|
|
||||||
if err != nil {
|
|
||||||
errx(2, "unable to read password: %v", err)
|
|
||||||
}
|
|
||||||
fmt.Fprintln(os.Stderr)
|
|
||||||
|
|
||||||
return string(pw)
|
|
||||||
}
|
|
||||||
|
|
||||||
func disableProgress() bool {
|
|
||||||
if mainOpts.Quiet {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if !terminal.IsTerminal(int(os.Stdout.Fd())) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func silenceRequested() bool {
|
|
||||||
if mainOpts.Quiet {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func verbosePrintf(format string, args ...interface{}) {
|
|
||||||
if silenceRequested() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
type CmdInit struct{}
|
|
||||||
|
|
||||||
func (cmd CmdInit) Execute(args []string) error {
|
|
||||||
if mainOpts.Repo == "" {
|
|
||||||
return errors.New("Please specify repository location (-r)")
|
|
||||||
}
|
|
||||||
|
|
||||||
if mainOpts.password == "" {
|
|
||||||
pw := readPassword("enter password for new backend: ")
|
|
||||||
pw2 := readPassword("enter password again: ")
|
|
||||||
|
|
||||||
if pw != pw2 {
|
|
||||||
errx(1, "passwords do not match")
|
|
||||||
}
|
|
||||||
|
|
||||||
mainOpts.password = pw
|
|
||||||
}
|
|
||||||
|
|
||||||
be, err := create(mainOpts.Repo)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "creating backend at %s failed: %v\n", mainOpts.Repo, err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
s := repository.New(be)
|
|
||||||
err = s.Init(mainOpts.password)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "creating key in backend at %s failed: %v\n", mainOpts.Repo, err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
verbosePrintf("created restic backend %v at %s\n", s.Config.ID[:10], mainOpts.Repo)
|
|
||||||
verbosePrintf("\n")
|
|
||||||
verbosePrintf("Please note that knowledge of your password is required to access\n")
|
|
||||||
verbosePrintf("the repository. Losing your password means that your data is\n")
|
|
||||||
verbosePrintf("irrecoverably lost.\n")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open the backend specified by URI.
|
|
||||||
// Valid formats are:
|
|
||||||
// * /foo/bar -> local repository at /foo/bar
|
|
||||||
// * sftp://user@host/foo/bar -> remote sftp repository on host for user at path foo/bar
|
|
||||||
// * sftp://host//tmp/backup -> remote sftp repository on host at path /tmp/backup
|
|
||||||
func open(u string) (backend.Backend, error) {
|
|
||||||
url, err := url.Parse(u)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if url.Scheme == "" {
|
|
||||||
return local.Open(url.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
args := []string{url.Host}
|
|
||||||
if url.User != nil && url.User.Username() != "" {
|
|
||||||
args = append(args, "-l")
|
|
||||||
args = append(args, url.User.Username())
|
|
||||||
}
|
|
||||||
args = append(args, "-s")
|
|
||||||
args = append(args, "sftp")
|
|
||||||
return sftp.Open(url.Path[1:], "ssh", args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the backend specified by URI.
|
|
||||||
func create(u string) (backend.Backend, error) {
|
|
||||||
url, err := url.Parse(u)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if url.Scheme == "" {
|
|
||||||
return local.Create(url.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
args := []string{url.Host}
|
|
||||||
if url.User != nil && url.User.Username() != "" {
|
|
||||||
args = append(args, "-l")
|
|
||||||
args = append(args, url.User.Username())
|
|
||||||
}
|
|
||||||
args = append(args, "-s")
|
|
||||||
args = append(args, "sftp")
|
|
||||||
return sftp.Create(url.Path[1:], "ssh", args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func OpenRepo() (*repository.Repository, error) {
|
|
||||||
if mainOpts.Repo == "" {
|
|
||||||
return nil, errors.New("Please specify repository location (-r)")
|
|
||||||
}
|
|
||||||
|
|
||||||
be, err := open(mainOpts.Repo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
s := repository.New(be)
|
|
||||||
|
|
||||||
if mainOpts.password == "" {
|
|
||||||
mainOpts.password = readPassword("enter password for repository: ")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = s.SearchKey(mainOpts.password)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to open repo: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// set GOMAXPROCS to number of CPUs
|
// set GOMAXPROCS to number of CPUs
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
|
|
||||||
_, err := parser.AddCommand("init",
|
|
||||||
"create repository",
|
|
||||||
"The init command creates a new repository",
|
|
||||||
&CmdInit{})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// defer profile.Start(profile.MemProfileRate(100000), profile.ProfilePath(".")).Stop()
|
// defer profile.Start(profile.MemProfileRate(100000), profile.ProfilePath(".")).Stop()
|
||||||
// defer profile.Start(profile.CPUProfile, profile.ProfilePath(".")).Stop()
|
// defer profile.Start(profile.CPUProfile, profile.ProfilePath(".")).Stop()
|
||||||
mainOpts.Repo = os.Getenv("RESTIC_REPOSITORY")
|
globalOpts.Repo = os.Getenv("RESTIC_REPOSITORY")
|
||||||
mainOpts.password = os.Getenv("RESTIC_PASSWORD")
|
globalOpts.password = os.Getenv("RESTIC_PASSWORD")
|
||||||
|
|
||||||
debug.Log("restic", "main %#v", os.Args)
|
debug.Log("restic", "main %#v", os.Args)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue