aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/gobuffalo/packr/box.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/gobuffalo/packr/box.go')
-rw-r--r--vendor/github.com/gobuffalo/packr/box.go241
1 files changed, 241 insertions, 0 deletions
diff --git a/vendor/github.com/gobuffalo/packr/box.go b/vendor/github.com/gobuffalo/packr/box.go
new file mode 100644
index 0000000..30eb6e2
--- /dev/null
+++ b/vendor/github.com/gobuffalo/packr/box.go
@@ -0,0 +1,241 @@
+package packr
+
+import (
+ "bytes"
+ "compress/gzip"
+ "io/ioutil"
+ "net/http"
+ "os"
+ "path"
+ "path/filepath"
+ "runtime"
+ "strings"
+
+ "github.com/pkg/errors"
+)
+
+var (
+ ErrResOutsideBox = errors.New("Can't find a resource outside the box")
+)
+
+// NewBox returns a Box that can be used to
+// retrieve files from either disk or the embedded
+// binary.
+func NewBox(path string) Box {
+ var cd string
+ if !filepath.IsAbs(path) {
+ _, filename, _, _ := runtime.Caller(1)
+ cd = filepath.Dir(filename)
+ }
+
+ // this little hack courtesy of the `-cover` flag!!
+ cov := filepath.Join("_test", "_obj_test")
+ cd = strings.Replace(cd, string(filepath.Separator)+cov, "", 1)
+ if !filepath.IsAbs(cd) && cd != "" {
+ cd = filepath.Join(GoPath(), "src", cd)
+ }
+
+ return Box{
+ Path: path,
+ callingDir: cd,
+ data: map[string][]byte{},
+ }
+}
+
+// Box represent a folder on a disk you want to
+// have access to in the built Go binary.
+type Box struct {
+ Path string
+ callingDir string
+ data map[string][]byte
+ directories map[string]bool
+}
+
+func (b Box) AddString(path string, t string) {
+ b.AddBytes(path, []byte(t))
+}
+
+func (b Box) AddBytes(path string, t []byte) {
+ b.data[path] = t
+}
+
+// String of the file asked for or an empty string.
+func (b Box) String(name string) string {
+ return string(b.Bytes(name))
+}
+
+// MustString returns either the string of the requested
+// file or an error if it can not be found.
+func (b Box) MustString(name string) (string, error) {
+ bb, err := b.MustBytes(name)
+ return string(bb), err
+}
+
+// Bytes of the file asked for or an empty byte slice.
+func (b Box) Bytes(name string) []byte {
+ bb, _ := b.MustBytes(name)
+ return bb
+}
+
+// MustBytes returns either the byte slice of the requested
+// file or an error if it can not be found.
+func (b Box) MustBytes(name string) ([]byte, error) {
+ f, err := b.find(name)
+ if err == nil {
+ bb := &bytes.Buffer{}
+ bb.ReadFrom(f)
+ return bb.Bytes(), err
+ }
+ return nil, err
+}
+
+// Has returns true if the resource exists in the box
+func (b Box) Has(name string) bool {
+ _, err := b.find(name)
+ if err != nil {
+ return false
+ }
+ return true
+}
+
+func (b Box) decompress(bb []byte) []byte {
+ reader, err := gzip.NewReader(bytes.NewReader(bb))
+ if err != nil {
+ return bb
+ }
+ data, err := ioutil.ReadAll(reader)
+ if err != nil {
+ return bb
+ }
+ return data
+}
+
+func (b Box) find(name string) (File, error) {
+ if bb, ok := b.data[name]; ok {
+ return newVirtualFile(name, bb), nil
+ }
+ if b.directories == nil {
+ b.indexDirectories()
+ }
+
+ cleanName := filepath.ToSlash(filepath.Clean(name))
+ // Ensure name is not outside the box
+ if strings.HasPrefix(cleanName, "../") {
+ return nil, ErrResOutsideBox
+ }
+ // Absolute name is considered as relative to the box root
+ cleanName = strings.TrimPrefix(cleanName, "/")
+
+ // Try to get the resource from the box
+ if _, ok := data[b.Path]; ok {
+ if bb, ok := data[b.Path][cleanName]; ok {
+ bb = b.decompress(bb)
+ return newVirtualFile(cleanName, bb), nil
+ }
+ if filepath.Ext(cleanName) != "" {
+ // The Handler created by http.FileSystem checks for those errors and
+ // returns http.StatusNotFound instead of http.StatusInternalServerError.
+ return nil, os.ErrNotExist
+ }
+ if _, ok := b.directories[cleanName]; ok {
+ return newVirtualDir(cleanName), nil
+ }
+ return nil, os.ErrNotExist
+ }
+
+ // Not found in the box virtual fs, try to get it from the file system
+ cleanName = filepath.FromSlash(cleanName)
+ p := filepath.Join(b.callingDir, b.Path, cleanName)
+ return fileFor(p, cleanName)
+}
+
+type WalkFunc func(string, File) error
+
+func (b Box) Walk(wf WalkFunc) error {
+ if data[b.Path] == nil {
+ base, err := filepath.EvalSymlinks(filepath.Join(b.callingDir, b.Path))
+ if err != nil {
+ return errors.WithStack(err)
+ }
+ return filepath.Walk(base, func(path string, info os.FileInfo, err error) error {
+ cleanName, err := filepath.Rel(base, path)
+ if err != nil {
+ cleanName = strings.TrimPrefix(path, base)
+ }
+ cleanName = filepath.ToSlash(filepath.Clean(cleanName))
+ cleanName = strings.TrimPrefix(cleanName, "/")
+ cleanName = filepath.FromSlash(cleanName)
+ if info == nil || info.IsDir() {
+ return nil
+ }
+
+ file, err := fileFor(path, cleanName)
+ if err != nil {
+ return err
+ }
+ return wf(cleanName, file)
+ })
+ }
+ for n := range data[b.Path] {
+ f, err := b.find(n)
+ if err != nil {
+ return err
+ }
+ err = wf(n, f)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Open returns a File using the http.File interface
+func (b Box) Open(name string) (http.File, error) {
+ return b.find(name)
+}
+
+// List shows "What's in the box?"
+func (b Box) List() []string {
+ var keys []string
+
+ if b.data == nil || len(b.data) == 0 {
+ b.Walk(func(path string, info File) error {
+ finfo, _ := info.FileInfo()
+ if !finfo.IsDir() {
+ keys = append(keys, finfo.Name())
+ }
+ return nil
+ })
+ } else {
+ for k := range b.data {
+ keys = append(keys, k)
+ }
+ }
+ return keys
+}
+
+func (b *Box) indexDirectories() {
+ b.directories = map[string]bool{}
+ if _, ok := data[b.Path]; ok {
+ for name := range data[b.Path] {
+ prefix, _ := path.Split(name)
+ // Even on Windows the suffix appears to be a /
+ prefix = strings.TrimSuffix(prefix, "/")
+ b.directories[prefix] = true
+ }
+ }
+}
+
+func fileFor(p string, name string) (File, error) {
+ fi, err := os.Stat(p)
+ if err != nil {
+ return nil, err
+ }
+ if fi.IsDir() {
+ return newVirtualDir(p), nil
+ }
+ if bb, err := ioutil.ReadFile(p); err == nil {
+ return newVirtualFile(name, bb), nil
+ }
+ return nil, os.ErrNotExist
+}