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:
parent
f848afed27
commit
09702c1c61
133
cmd/khepri/cmd_cat.go
Normal file
133
cmd/khepri/cmd_cat.go
Normal 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
|
||||
}
|
@ -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
74
cmd/khepri/cmd_ls.go
Normal 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)
|
||||
}
|
@ -124,6 +124,8 @@ func init() {
|
||||
commands["restore"] = commandRestore
|
||||
commands["list"] = commandList
|
||||
commands["snapshots"] = commandSnapshots
|
||||
commands["cat"] = commandCat
|
||||
commands["ls"] = commandLs
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user