1 Star 0 Fork 0

unomit / packr

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
box.go 4.19 KB
一键复制 编辑 原始数据 按行查看 历史
Mark Bates 提交于 2017-12-20 16:18 . removed Printlns
package packr
import (
"bytes"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"runtime"
"strings"
"compress/gzip"
"github.com/gobuffalo/envy"
"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(envy.GoPath(), "src", cd)
}
return Box{
Path: path,
callingDir: cd,
}
}
// 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
}
// 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) {
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
}
return newVirtualDir(cleanName), nil
}
// 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)
if f, err := os.Open(p); err == nil {
return physicalFile{f}, nil
}
return nil, os.ErrNotExist
}
type WalkFunc func(string, File) error
func (b Box) Walk(wf WalkFunc) error {
if data[b.Path] == nil {
base := filepath.Join(b.callingDir, b.Path)
return filepath.Walk(base, func(path string, info os.FileInfo, err error) error {
shortPath := strings.TrimPrefix(path, base)
if info == nil || info.IsDir() {
return nil
}
f, err := os.Open(path)
if err != nil {
return err
}
return wf(shortPath, physicalFile{f})
})
}
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 {
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
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/sodacan/packr.git
git@gitee.com:sodacan/packr.git
sodacan
packr
packr
v1.9.10

搜索帮助

344bd9b3 5694891 D2dac590 5694891