mirror of
https://github.com/octoleo/restic.git
synced 2024-11-24 21:57:41 +00:00
Refactor
This commit is contained in:
parent
022f514b09
commit
e8b83e460f
@ -24,7 +24,7 @@ func hash(filename string) (khepri.ID, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func store_file(repo *khepri.Repository, path string) (khepri.ID, error) {
|
func store_file(repo *khepri.Repository, path string) (khepri.ID, error) {
|
||||||
obj, err := repo.NewObject(khepri.TYPE_BLOB)
|
obj, idch, err := repo.Create(khepri.TYPE_BLOB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -44,7 +44,7 @@ func store_file(repo *khepri.Repository, path string) (khepri.ID, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj.ID(), nil
|
return <-idch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func archive_dir(repo *khepri.Repository, path string) (khepri.ID, error) {
|
func archive_dir(repo *khepri.Repository, path string) (khepri.ID, error) {
|
||||||
@ -92,7 +92,7 @@ func archive_dir(repo *khepri.Repository, path string) (khepri.ID, error) {
|
|||||||
|
|
||||||
log.Printf(" dir %q: %v entries", path, len(t.Nodes))
|
log.Printf(" dir %q: %v entries", path, len(t.Nodes))
|
||||||
|
|
||||||
obj, err := repo.NewObject(khepri.TYPE_BLOB)
|
obj, idch, err := repo.Create(khepri.TYPE_BLOB)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error creating object for tree: %v", err)
|
log.Printf("error creating object for tree: %v", err)
|
||||||
@ -106,7 +106,7 @@ func archive_dir(repo *khepri.Repository, path string) (khepri.ID, error) {
|
|||||||
|
|
||||||
obj.Close()
|
obj.Close()
|
||||||
|
|
||||||
id := obj.ID()
|
id := <-idch
|
||||||
log.Printf("tree for %q saved at %s", path, id)
|
log.Printf("tree for %q saved at %s", path, id)
|
||||||
|
|
||||||
return id, nil
|
return id, nil
|
||||||
@ -124,11 +124,15 @@ func commandBackup(repo *khepri.Repository, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sn := repo.NewSnapshot(target)
|
sn := khepri.NewSnapshot(target)
|
||||||
sn.Tree = id
|
sn.Tree = id
|
||||||
sn.Save()
|
snid, err := sn.Save(repo)
|
||||||
|
|
||||||
fmt.Printf("%q archived as %v\n", target, sn.ID())
|
if err != nil {
|
||||||
|
log.Printf("error saving snapshopt: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%q archived as %v\n", target, snid)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
@ -49,7 +50,7 @@ func restore_file(repo *khepri.Repository, node khepri.Node, target string) erro
|
|||||||
|
|
||||||
func restore_dir(repo *khepri.Repository, id khepri.ID, target string) error {
|
func restore_dir(repo *khepri.Repository, id khepri.ID, target string) error {
|
||||||
fmt.Printf(" restore dir %q\n", target)
|
fmt.Printf(" restore dir %q\n", target)
|
||||||
rd, err := repo.Get(khepri.TYPE_REF, id)
|
rd, err := repo.Get(khepri.TYPE_BLOB, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -121,7 +122,12 @@ func commandRestore(repo *khepri.Repository, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = restore_dir(repo, id, target)
|
sn, err := khepri.LoadSnapshot(repo, id)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error loading snapshot %s", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = restore_dir(repo, sn.Tree, target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
109
object.go
109
object.go
@ -1,78 +1,60 @@
|
|||||||
package khepri
|
package khepri
|
||||||
|
|
||||||
import "os"
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
type Object struct {
|
type createObject struct {
|
||||||
repo *Repository
|
repo *Repository
|
||||||
|
|
||||||
id ID
|
|
||||||
tpe Type
|
tpe Type
|
||||||
|
|
||||||
hw HashingWriter
|
hw HashingWriter
|
||||||
file *os.File
|
file *os.File
|
||||||
|
|
||||||
|
ch chan ID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repository) NewObject(t Type) (*Object, error) {
|
func (repo *Repository) Create(t Type) (io.WriteCloser, <-chan ID, error) {
|
||||||
obj := &Object{
|
obj := &createObject{
|
||||||
repo: repo,
|
repo: repo,
|
||||||
tpe: t,
|
tpe: t,
|
||||||
|
ch: make(chan ID, 1),
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj, obj.open()
|
// save contents to tempfile in repository, hash while writing
|
||||||
|
var err error
|
||||||
|
obj.file, err = obj.repo.tempFile()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// create hashing writer
|
||||||
|
obj.hw = NewHashingWriter(obj.file, obj.repo.hash)
|
||||||
|
|
||||||
|
return obj, obj.ch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (obj *Object) open() error {
|
func (obj *createObject) Write(data []byte) (int, error) {
|
||||||
if obj.isFinal() {
|
|
||||||
panic("object is finalized")
|
|
||||||
}
|
|
||||||
|
|
||||||
if obj.isOpen() {
|
|
||||||
panic("object already open")
|
|
||||||
}
|
|
||||||
|
|
||||||
// create tempfile in repository
|
|
||||||
if obj.hw == nil {
|
if obj.hw == nil {
|
||||||
// save contents to tempfile, hash while writing
|
panic("createObject: already closed!")
|
||||||
var err error
|
|
||||||
obj.file, err = obj.repo.tempFile()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// create hashing writer
|
|
||||||
obj.hw = NewHashingWriter(obj.file, obj.repo.hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (obj *Object) isOpen() bool {
|
|
||||||
return obj.file != nil && obj.hw != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (obj *Object) isFinal() bool {
|
|
||||||
return obj.id != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (obj *Object) Write(data []byte) (int, error) {
|
|
||||||
if !obj.isOpen() {
|
|
||||||
panic("object not open")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj.hw.Write(data)
|
return obj.hw.Write(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (obj *Object) Close() error {
|
func (obj *createObject) Close() error {
|
||||||
if obj.file == nil || obj.hw == nil {
|
if obj.hw == nil {
|
||||||
panic("object is not open")
|
panic("createObject: already closed!")
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.file.Close()
|
obj.file.Close()
|
||||||
|
|
||||||
hash := obj.hw.Hash()
|
id := ID(obj.hw.Hash())
|
||||||
|
obj.ch <- id
|
||||||
|
|
||||||
// move file to final name using hash of contents
|
// move file to final name using hash of contents
|
||||||
id := ID(hash)
|
|
||||||
err := obj.repo.renameFile(obj.file, obj.tpe, id)
|
err := obj.repo.renameFile(obj.file, obj.tpe, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -80,40 +62,5 @@ func (obj *Object) Close() error {
|
|||||||
|
|
||||||
obj.hw = nil
|
obj.hw = nil
|
||||||
obj.file = nil
|
obj.file = nil
|
||||||
|
|
||||||
obj.id = id
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (obj *Object) ID() ID {
|
|
||||||
if !obj.isFinal() {
|
|
||||||
panic("object not finalized")
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj.id
|
|
||||||
}
|
|
||||||
|
|
||||||
func (obj *Object) Type() Type {
|
|
||||||
return obj.tpe
|
|
||||||
}
|
|
||||||
|
|
||||||
func (obj *Object) Remove() error {
|
|
||||||
if obj.id != nil {
|
|
||||||
return obj.repo.Remove(obj.tpe, obj.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
if obj.file != nil {
|
|
||||||
file := obj.file
|
|
||||||
obj.hw = nil
|
|
||||||
obj.file = nil
|
|
||||||
|
|
||||||
err := file.Close()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.Remove(file.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -16,16 +16,18 @@ func TestObjects(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
for _, test := range TestStrings {
|
for _, test := range TestStrings {
|
||||||
obj, err := repo.NewObject(khepri.TYPE_BLOB)
|
obj, ch, err := repo.Create(khepri.TYPE_BLOB)
|
||||||
ok(t, err)
|
ok(t, err)
|
||||||
|
|
||||||
_, err = obj.Write([]byte(test.data))
|
_, err = obj.Write([]byte(test.data))
|
||||||
ok(t, err)
|
ok(t, err)
|
||||||
|
|
||||||
obj.Close()
|
err = obj.Close()
|
||||||
|
ok(t, err)
|
||||||
|
|
||||||
id, err := khepri.ParseID(test.id)
|
id, err := khepri.ParseID(test.id)
|
||||||
ok(t, err)
|
ok(t, err)
|
||||||
|
|
||||||
equals(t, id, obj.ID())
|
equals(t, id, <-ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ func (r *Repository) Test(t Type, id ID) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get returns a reader for the content stored under the given ID.
|
// Get returns a reader for the content stored under the given ID.
|
||||||
func (r *Repository) Get(t Type, id ID) (io.Reader, error) {
|
func (r *Repository) Get(t Type, id ID) (io.ReadCloser, error) {
|
||||||
// try to open file
|
// try to open file
|
||||||
file, err := os.Open(r.filename(t, id))
|
file, err := os.Open(r.filename(t, id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -75,7 +75,7 @@ func TestRepository(t *testing.T) {
|
|||||||
// add files
|
// add files
|
||||||
for _, test := range TestStrings {
|
for _, test := range TestStrings {
|
||||||
// store string in repository
|
// store string in repository
|
||||||
obj, err := repo.NewObject(test.t)
|
obj, id_ch, err := repo.Create(test.t)
|
||||||
ok(t, err)
|
ok(t, err)
|
||||||
|
|
||||||
_, err = obj.Write([]byte(test.data))
|
_, err = obj.Write([]byte(test.data))
|
||||||
@ -84,7 +84,7 @@ func TestRepository(t *testing.T) {
|
|||||||
err = obj.Close()
|
err = obj.Close()
|
||||||
ok(t, err)
|
ok(t, err)
|
||||||
|
|
||||||
id := obj.ID()
|
id := <-id_ch
|
||||||
equals(t, test.id, id.String())
|
equals(t, test.id, id.String())
|
||||||
|
|
||||||
// try to get it out again
|
// try to get it out again
|
||||||
|
35
snapshot.go
35
snapshot.go
@ -15,14 +15,11 @@ type Snapshot struct {
|
|||||||
Username string `json:"username,omitempty"`
|
Username string `json:"username,omitempty"`
|
||||||
UID string `json:"uid,omitempty"`
|
UID string `json:"uid,omitempty"`
|
||||||
GID string `json:"gid,omitempty"`
|
GID string `json:"gid,omitempty"`
|
||||||
id ID
|
|
||||||
repo *Repository
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repository) NewSnapshot(dir string) *Snapshot {
|
func NewSnapshot(dir string) *Snapshot {
|
||||||
sn := &Snapshot{
|
sn := &Snapshot{
|
||||||
Dir: dir,
|
Dir: dir,
|
||||||
repo: repo,
|
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,31 +38,43 @@ func (repo *Repository) NewSnapshot(dir string) *Snapshot {
|
|||||||
return sn
|
return sn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sn *Snapshot) Save() error {
|
func (sn *Snapshot) Save(repo *Repository) (ID, error) {
|
||||||
if sn.Tree == nil {
|
if sn.Tree == nil {
|
||||||
panic("Snapshot.Save() called with nil tree id")
|
panic("Snapshot.Save() called with nil tree id")
|
||||||
}
|
}
|
||||||
|
|
||||||
obj, err := sn.repo.NewObject(TYPE_REF)
|
obj, id_ch, err := repo.Create(TYPE_REF)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
enc := json.NewEncoder(obj)
|
enc := json.NewEncoder(obj)
|
||||||
err = enc.Encode(sn)
|
err = enc.Encode(sn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = obj.Close()
|
err = obj.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sn.id = obj.ID()
|
return <-id_ch, nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sn *Snapshot) ID() ID {
|
func LoadSnapshot(repo *Repository, id ID) (*Snapshot, error) {
|
||||||
return sn.id
|
rd, err := repo.Get(TYPE_REF, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dec := json.NewDecoder(rd)
|
||||||
|
sn := &Snapshot{}
|
||||||
|
err = dec.Decode(sn)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sn, nil
|
||||||
}
|
}
|
||||||
|
@ -16,11 +16,12 @@ func TestSnapshot(t *testing.T) {
|
|||||||
ok(t, err)
|
ok(t, err)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
sn := repo.NewSnapshot("/home/foobar")
|
sn := khepri.NewSnapshot("/home/foobar")
|
||||||
sn.Tree, err = khepri.ParseID("c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2")
|
sn.Tree, err = khepri.ParseID("c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2")
|
||||||
ok(t, err)
|
ok(t, err)
|
||||||
sn.Time, err = time.Parse(time.RFC3339Nano, "2014-08-03T17:49:05.378595539+02:00")
|
sn.Time, err = time.Parse(time.RFC3339Nano, "2014-08-03T17:49:05.378595539+02:00")
|
||||||
ok(t, err)
|
ok(t, err)
|
||||||
|
|
||||||
ok(t, sn.Save())
|
_, err = sn.Save(repo)
|
||||||
|
ok(t, err)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user