snapshot/snapshots/fake_filer.go (124 lines of code) (raw):
package snapshots
import (
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strconv"
"time"
"github.com/twitter/scoot/snapshot"
)
// Make an invalid Filer
func MakeInvalidFiler() snapshot.Filer {
return MakeFilerFacade(MakeInvalidCheckouter(), MakeNoopIngester(), MakeNoopUpdater())
}
func MakeNoopFiler(path string) snapshot.Filer {
return MakeFilerFacade(MakeNoopCheckouter(path), MakeNoopIngester(), MakeNoopUpdater())
}
// Make invalid filer with an updater
func MakeInvalidFilerUpdater(updater snapshot.Updater) snapshot.Filer {
return MakeFilerFacade(MakeInvalidCheckouter(), MakeNoopIngester(), updater)
}
// FilerFacade creates a Filer from a Checkouter and Ingester
type FilerFacade struct {
snapshot.Checkouter
snapshot.Ingester
snapshot.Updater
}
// Make a Filer from a Checkouter and Ingester
func MakeFilerFacade(
checkouter snapshot.Checkouter,
ingester snapshot.Ingester,
updater snapshot.Updater) *FilerFacade {
return &FilerFacade{checkouter, ingester, updater}
}
// Make a Filer that can Checkout() but does a noop Ingest().
func MakeTempCheckouterFiler(tmp string) snapshot.Filer {
return MakeFilerFacade(MakeTempCheckouter(tmp), MakeNoopIngester(), MakeNoopUpdater())
}
// Creates a filer that copies ingested paths in and then back out for checkouts.
func MakeTempFiler(tmp string) snapshot.Filer {
return &tempFiler{tmp: tmp, snapshots: make(map[string]string)}
}
type tempFiler struct {
tmp string
snapshots map[string]string
}
func (t *tempFiler) Ingest(path string) (id string, err error) {
return t.IngestMap(map[string]string{path: ""})
}
func (t *tempFiler) IngestMap(srcToDest map[string]string) (id string, err error) {
var s string
s, err = ioutil.TempDir(t.tmp, "snapshot-")
if err != nil {
return "", err
}
for src, dest := range srcToDest {
// absDest is a parent directory in which we place the contents of src.
absDest := filepath.Join(s, dest)
slashDot := ""
if fi, err := os.Stat(src); err == nil && fi.IsDir() {
// If src is a dir, we append a slash dot to copy contents rather than the dir itself.
slashDot = "/."
err = os.MkdirAll(absDest, os.ModePerm)
} else {
// If src is a file, we treat the base of absDest as a file instead of a directory.
err = os.MkdirAll(filepath.Dir(absDest), os.ModePerm)
}
if err != nil {
return
}
err = exec.Command("sh", "-c", fmt.Sprintf("cp -r %s%s %s", src, slashDot, absDest)).Run()
if err != nil {
return
}
}
id = strconv.Itoa(len(t.snapshots))
t.snapshots[id] = s
return
}
func (t *tempFiler) CancelIngest() error {
return nil
}
func (t *tempFiler) Checkout(id string) (snapshot.Checkout, error) {
dir, err := ioutil.TempDir(t.tmp, "checkout-"+id+"__")
if err != nil {
return nil, err
}
co, err := t.CheckoutAt(id, dir)
if err != nil {
os.RemoveAll(dir)
return nil, err
}
return co, nil
}
func (t *tempFiler) CheckoutAt(id string, dir string) (snapshot.Checkout, error) {
snap, ok := t.snapshots[id]
if !ok {
return nil, errors.New("No snapshot with id: " + id)
}
// Copy contents of snapshot dir to the output dir using cp '.' terminator syntax (incompatible with path/filepath).
if err := exec.Command("cp", "-rf", snap+"/.", dir).Run(); err != nil {
return nil, err
}
return &staticCheckout{
path: dir,
id: id,
}, nil
}
func (t *tempFiler) CancelCheckout() error {
return nil
}
func (t *tempFiler) Update() error { return nil }
func (t *tempFiler) UpdateInterval() time.Duration { return snapshot.NoDuration }
// Make an Ingester that does nothing
func MakeNoopIngester() *NoopIngester {
return &NoopIngester{}
}
// Ingester that does nothing.
type NoopIngester struct{}
func (n *NoopIngester) Ingest(string) (string, error) {
return "", nil
}
func (n *NoopIngester) IngestMap(map[string]string) (string, error) {
return "", nil
}
func (n *NoopIngester) CancelIngest() error {
return nil
}
// Make an Updater that does nothing
func MakeNoopUpdater() *NoopUpdater {
return &NoopUpdater{}
}
type NoopUpdater struct{}
func (n *NoopUpdater) Update() error { return nil }
func (n *NoopUpdater) UpdateInterval() time.Duration { return snapshot.NoDuration }