2014-08-04 18:47:04 +00:00
|
|
|
package khepri
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2014-08-11 20:47:24 +00:00
|
|
|
"fmt"
|
2014-08-04 18:47:04 +00:00
|
|
|
"os"
|
|
|
|
"os/user"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Snapshot struct {
|
|
|
|
Time time.Time `json:"time"`
|
2014-08-11 20:47:24 +00:00
|
|
|
Content ID `json:"content"`
|
|
|
|
Tree *Tree `json:"-"`
|
2014-08-04 18:47:04 +00:00
|
|
|
Dir string `json:"dir"`
|
|
|
|
Hostname string `json:"hostname,omitempty"`
|
|
|
|
Username string `json:"username,omitempty"`
|
|
|
|
UID string `json:"uid,omitempty"`
|
|
|
|
GID string `json:"gid,omitempty"`
|
2014-08-11 20:47:24 +00:00
|
|
|
id ID `json:omit`
|
2014-08-11 21:14:40 +00:00
|
|
|
repo *Repository
|
2014-08-04 18:47:04 +00:00
|
|
|
}
|
|
|
|
|
2014-08-04 20:46:14 +00:00
|
|
|
func NewSnapshot(dir string) *Snapshot {
|
2014-08-04 18:47:04 +00:00
|
|
|
sn := &Snapshot{
|
|
|
|
Dir: dir,
|
|
|
|
Time: time.Now(),
|
|
|
|
}
|
|
|
|
|
|
|
|
hn, err := os.Hostname()
|
|
|
|
if err == nil {
|
|
|
|
sn.Hostname = hn
|
|
|
|
}
|
|
|
|
|
|
|
|
usr, err := user.Current()
|
|
|
|
if err == nil {
|
|
|
|
sn.Username = usr.Username
|
|
|
|
sn.UID = usr.Uid
|
|
|
|
sn.GID = usr.Gid
|
|
|
|
}
|
|
|
|
|
|
|
|
return sn
|
|
|
|
}
|
|
|
|
|
2014-08-04 20:46:14 +00:00
|
|
|
func (sn *Snapshot) Save(repo *Repository) (ID, error) {
|
2014-08-11 20:47:24 +00:00
|
|
|
if sn.Content == nil {
|
2014-08-04 18:47:04 +00:00
|
|
|
panic("Snapshot.Save() called with nil tree id")
|
|
|
|
}
|
|
|
|
|
2014-08-04 20:46:14 +00:00
|
|
|
obj, id_ch, err := repo.Create(TYPE_REF)
|
2014-08-04 18:47:04 +00:00
|
|
|
if err != nil {
|
2014-08-04 20:46:14 +00:00
|
|
|
return nil, err
|
2014-08-04 18:47:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
enc := json.NewEncoder(obj)
|
|
|
|
err = enc.Encode(sn)
|
|
|
|
if err != nil {
|
2014-08-04 20:46:14 +00:00
|
|
|
return nil, err
|
2014-08-04 18:47:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
err = obj.Close()
|
|
|
|
if err != nil {
|
2014-08-04 20:46:14 +00:00
|
|
|
return nil, err
|
2014-08-04 18:47:04 +00:00
|
|
|
}
|
|
|
|
|
2014-08-11 20:47:24 +00:00
|
|
|
sn.id = <-id_ch
|
|
|
|
|
|
|
|
return sn.id, nil
|
2014-08-04 18:47:04 +00:00
|
|
|
}
|
|
|
|
|
2014-08-04 20:46:14 +00:00
|
|
|
func LoadSnapshot(repo *Repository, id ID) (*Snapshot, error) {
|
|
|
|
rd, err := repo.Get(TYPE_REF, id)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2014-08-04 21:25:58 +00:00
|
|
|
// TODO: maybe inject a hashing reader here and test if the given id is correct
|
|
|
|
|
2014-08-04 20:46:14 +00:00
|
|
|
dec := json.NewDecoder(rd)
|
|
|
|
sn := &Snapshot{}
|
|
|
|
err = dec.Decode(sn)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2014-08-11 20:47:24 +00:00
|
|
|
sn.id = id
|
2014-08-11 21:14:40 +00:00
|
|
|
sn.repo = repo
|
2014-08-11 20:47:24 +00:00
|
|
|
|
2014-08-04 20:46:14 +00:00
|
|
|
return sn, nil
|
2014-08-04 18:47:04 +00:00
|
|
|
}
|
2014-08-11 20:47:24 +00:00
|
|
|
|
2014-08-11 21:14:40 +00:00
|
|
|
func (sn *Snapshot) RestoreAt(path string) error {
|
|
|
|
err := os.MkdirAll(path, 0700)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if sn.Tree == nil {
|
|
|
|
sn.Tree, err = NewTreeFromRepo(sn.repo, sn.Content)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return sn.Tree.CreateAt(path)
|
|
|
|
}
|
|
|
|
|
2014-08-11 20:47:24 +00:00
|
|
|
func (sn *Snapshot) ID() ID {
|
|
|
|
return sn.id
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sn *Snapshot) String() string {
|
|
|
|
return fmt.Sprintf("<Snapshot of %q at %s>", sn.Dir, sn.Time.Format(time.RFC822Z))
|
|
|
|
}
|