2
2
mirror of https://github.com/octoleo/restic.git synced 2024-12-22 02:48:55 +00:00

Add commands 'cat','list' and 'ls'

This commit is contained in:
Alexander Neumann 2014-10-05 14:44:59 +02:00
parent f848afed27
commit 09702c1c61
5 changed files with 243 additions and 11 deletions

133
cmd/khepri/cmd_cat.go Normal file
View File

@ -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
}

View File

@ -1,21 +1,44 @@
package main
import (
"errors"
"fmt"
"github.com/fd0/khepri"
"github.com/fd0/khepri/backend"
)
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()
// if err != nil {
// fmt.Fprintf(os.Stderr, "error: %v\n", err)
// return nil
// }
var (
t backend.Type
each func(backend.Server, backend.Type, func(backend.ID, []byte, error)) error = backend.Each
)
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 {
// fmt.Printf("%v\n", id)
// }
return nil
return each(be, t, func(id backend.ID, data []byte, err error) {
if t == backend.Blob || t == backend.Tree {
fmt.Printf("%s %s\n", id, backend.Hash(data))
} else {
fmt.Printf("%s\n", id)
}
})
}

74
cmd/khepri/cmd_ls.go Normal file
View File

@ -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)
}

View File

@ -124,6 +124,8 @@ func init() {
commands["restore"] = commandRestore
commands["list"] = commandList
commands["snapshots"] = commandSnapshots
commands["cat"] = commandCat
commands["ls"] = commandLs
}
func main() {

View File

@ -29,7 +29,7 @@ func NewContentHandler(be backend.Server, key *Key) (*ContentHandler, error) {
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) {
sn, err := LoadSnapshot(ch, id)
if err != nil {