mirror of https://github.com/restic/restic.git
Add commands 'cat','list' and 'ls'
This commit is contained in:
parent
f848afed27
commit
09702c1c61
|
@ -0,0 +1,133 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/fd0/khepri"
|
||||||
|
"github.com/fd0/khepri/backend"
|
||||||
|
)
|
||||||
|
|
||||||
|
func commandCat(be backend.Server, key *khepri.Key, args []string) error {
|
||||||
|
if len(args) != 2 {
|
||||||
|
return errors.New("usage: cat [blob|tree|snapshot|key|lock] ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
tpe := args[0]
|
||||||
|
|
||||||
|
id, err := backend.ParseID(args[1])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ch, err := khepri.NewContentHandler(be, key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ch.LoadAllSnapshots()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch tpe {
|
||||||
|
case "blob":
|
||||||
|
// try id
|
||||||
|
data, err := ch.Load(backend.Blob, id)
|
||||||
|
if err == nil {
|
||||||
|
_, err = os.Stdout.Write(data)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// try storage id
|
||||||
|
buf, err := be.Get(backend.Blob, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrypt
|
||||||
|
buf, err = key.Decrypt(buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = os.Stdout.Write(data)
|
||||||
|
return err
|
||||||
|
|
||||||
|
case "tree":
|
||||||
|
var tree khepri.Tree
|
||||||
|
// try id
|
||||||
|
err := ch.LoadJSON(backend.Tree, id, &tree)
|
||||||
|
if err != nil {
|
||||||
|
// try storage id
|
||||||
|
buf, err := be.Get(backend.Tree, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrypt
|
||||||
|
buf, err = key.Decrypt(buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmarshal
|
||||||
|
err = json.Unmarshal(backend.Uncompress(buf), &tree)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, err := json.MarshalIndent(&tree, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(buf))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
case "snapshot":
|
||||||
|
var sn khepri.Snapshot
|
||||||
|
err := ch.LoadJSONRaw(backend.Snapshot, id, &sn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, err := json.MarshalIndent(&sn, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(buf))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
case "key":
|
||||||
|
data, err := be.Get(backend.Key, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var key khepri.Key
|
||||||
|
err = json.Unmarshal(data, &key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, err := json.MarshalIndent(&key, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(buf))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
case "lock":
|
||||||
|
return errors.New("not yet implemented")
|
||||||
|
default:
|
||||||
|
return errors.New("invalid type")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,21 +1,44 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/fd0/khepri"
|
"github.com/fd0/khepri"
|
||||||
"github.com/fd0/khepri/backend"
|
"github.com/fd0/khepri/backend"
|
||||||
)
|
)
|
||||||
|
|
||||||
func commandList(be backend.Server, key *khepri.Key, args []string) error {
|
func commandList(be backend.Server, key *khepri.Key, args []string) error {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return errors.New("usage: list [blobs|trees|snapshots|keys|locks]")
|
||||||
|
}
|
||||||
|
|
||||||
// ids, err := be.ListRefs()
|
var (
|
||||||
// if err != nil {
|
t backend.Type
|
||||||
// fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
each func(backend.Server, backend.Type, func(backend.ID, []byte, error)) error = backend.Each
|
||||||
// return nil
|
)
|
||||||
// }
|
switch args[0] {
|
||||||
|
case "blobs":
|
||||||
|
t = backend.Blob
|
||||||
|
each = key.Each
|
||||||
|
case "trees":
|
||||||
|
t = backend.Tree
|
||||||
|
each = key.Each
|
||||||
|
case "snapshots":
|
||||||
|
t = backend.Snapshot
|
||||||
|
case "keys":
|
||||||
|
t = backend.Key
|
||||||
|
case "locks":
|
||||||
|
t = backend.Lock
|
||||||
|
default:
|
||||||
|
return errors.New("invalid type")
|
||||||
|
}
|
||||||
|
|
||||||
// for _, id := range ids {
|
return each(be, t, func(id backend.ID, data []byte, err error) {
|
||||||
// fmt.Printf("%v\n", id)
|
if t == backend.Blob || t == backend.Tree {
|
||||||
// }
|
fmt.Printf("%s %s\n", id, backend.Hash(data))
|
||||||
|
} else {
|
||||||
return nil
|
fmt.Printf("%s\n", id)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/fd0/khepri"
|
||||||
|
"github.com/fd0/khepri/backend"
|
||||||
|
)
|
||||||
|
|
||||||
|
func print_node(prefix string, n *khepri.Node) string {
|
||||||
|
switch n.Type {
|
||||||
|
case "file":
|
||||||
|
return fmt.Sprintf("%s %5d %5d %6d %s %s",
|
||||||
|
n.Mode, n.UID, n.GID, n.Size, n.ModTime, filepath.Join(prefix, n.Name))
|
||||||
|
case "dir":
|
||||||
|
return fmt.Sprintf("%s %5d %5d %6d %s %s",
|
||||||
|
n.Mode|os.ModeDir, n.UID, n.GID, n.Size, n.ModTime, filepath.Join(prefix, n.Name))
|
||||||
|
case "symlink":
|
||||||
|
return fmt.Sprintf("%s %5d %5d %6d %s %s -> %s",
|
||||||
|
n.Mode|os.ModeSymlink, n.UID, n.GID, n.Size, n.ModTime, filepath.Join(prefix, n.Name), n.LinkTarget)
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("<Node(%s) %s>", n.Type, n.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func print_tree(prefix string, ch *khepri.ContentHandler, id backend.ID) error {
|
||||||
|
tree := &khepri.Tree{}
|
||||||
|
|
||||||
|
err := ch.LoadJSON(backend.Tree, id, tree)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range *tree {
|
||||||
|
fmt.Println(print_node(prefix, entry))
|
||||||
|
|
||||||
|
if entry.Type == "dir" && entry.Subtree != nil {
|
||||||
|
err = print_tree(filepath.Join(prefix, entry.Name), ch, entry.Subtree)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func commandLs(be backend.Server, key *khepri.Key, args []string) error {
|
||||||
|
if len(args) < 1 || len(args) > 2 {
|
||||||
|
return errors.New("usage: ls SNAPSHOT_ID [dir]")
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := backend.ParseID(args[0])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ch, err := khepri.NewContentHandler(be, key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sn, err := ch.LoadSnapshot(id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("snapshot of %s at %s:\n", sn.Dir, sn.Time)
|
||||||
|
|
||||||
|
return print_tree("", ch, sn.Content)
|
||||||
|
}
|
|
@ -124,6 +124,8 @@ func init() {
|
||||||
commands["restore"] = commandRestore
|
commands["restore"] = commandRestore
|
||||||
commands["list"] = commandList
|
commands["list"] = commandList
|
||||||
commands["snapshots"] = commandSnapshots
|
commands["snapshots"] = commandSnapshots
|
||||||
|
commands["cat"] = commandCat
|
||||||
|
commands["ls"] = commandLs
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -29,7 +29,7 @@ func NewContentHandler(be backend.Server, key *Key) (*ContentHandler, error) {
|
||||||
return ch, nil
|
return ch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadSnapshotadds all blobs from a snapshot into the content handler and returns the snapshot.
|
// LoadSnapshot adds all blobs from a snapshot into the content handler and returns the snapshot.
|
||||||
func (ch *ContentHandler) LoadSnapshot(id backend.ID) (*Snapshot, error) {
|
func (ch *ContentHandler) LoadSnapshot(id backend.ID) (*Snapshot, error) {
|
||||||
sn, err := LoadSnapshot(ch, id)
|
sn, err := LoadSnapshot(ch, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue