123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- package assetfs
- import (
- "bytes"
- "errors"
- "io"
- "io/ioutil"
- "net/http"
- "os"
- "path"
- "path/filepath"
- "strings"
- "time"
- )
- var (
- defaultFileTimestamp = time.Now()
- )
- // FakeFile implements os.FileInfo interface for a given path and size
- type FakeFile struct {
- // Path is the path of this file
- Path string
- // Dir marks of the path is a directory
- Dir bool
- // Len is the length of the fake file, zero if it is a directory
- Len int64
- // Timestamp is the ModTime of this file
- Timestamp time.Time
- }
- func (f *FakeFile) Name() string {
- _, name := filepath.Split(f.Path)
- return name
- }
- func (f *FakeFile) Mode() os.FileMode {
- mode := os.FileMode(0644)
- if f.Dir {
- return mode | os.ModeDir
- }
- return mode
- }
- func (f *FakeFile) ModTime() time.Time {
- return f.Timestamp
- }
- func (f *FakeFile) Size() int64 {
- return f.Len
- }
- func (f *FakeFile) IsDir() bool {
- return f.Mode().IsDir()
- }
- func (f *FakeFile) Sys() interface{} {
- return nil
- }
- // AssetFile implements http.File interface for a no-directory file with content
- type AssetFile struct {
- *bytes.Reader
- io.Closer
- FakeFile
- }
- func NewAssetFile(name string, content []byte, timestamp time.Time) *AssetFile {
- if timestamp.IsZero() {
- timestamp = defaultFileTimestamp
- }
- return &AssetFile{
- bytes.NewReader(content),
- ioutil.NopCloser(nil),
- FakeFile{name, false, int64(len(content)), timestamp}}
- }
- func (f *AssetFile) Readdir(count int) ([]os.FileInfo, error) {
- return nil, errors.New("not a directory")
- }
- func (f *AssetFile) Size() int64 {
- return f.FakeFile.Size()
- }
- func (f *AssetFile) Stat() (os.FileInfo, error) {
- return f, nil
- }
- // AssetDirectory implements http.File interface for a directory
- type AssetDirectory struct {
- AssetFile
- ChildrenRead int
- Children []os.FileInfo
- }
- func NewAssetDirectory(name string, children []string, fs *AssetFS) *AssetDirectory {
- fileinfos := make([]os.FileInfo, 0, len(children))
- for _, child := range children {
- _, err := fs.AssetDir(filepath.Join(name, child))
- fileinfos = append(fileinfos, &FakeFile{child, err == nil, 0, time.Time{}})
- }
- return &AssetDirectory{
- AssetFile{
- bytes.NewReader(nil),
- ioutil.NopCloser(nil),
- FakeFile{name, true, 0, time.Time{}},
- },
- 0,
- fileinfos}
- }
- func (f *AssetDirectory) Readdir(count int) ([]os.FileInfo, error) {
- if count <= 0 {
- return f.Children, nil
- }
- if f.ChildrenRead+count > len(f.Children) {
- count = len(f.Children) - f.ChildrenRead
- }
- rv := f.Children[f.ChildrenRead : f.ChildrenRead+count]
- f.ChildrenRead += count
- return rv, nil
- }
- func (f *AssetDirectory) Stat() (os.FileInfo, error) {
- return f, nil
- }
- // AssetFS implements http.FileSystem, allowing
- // embedded files to be served from net/http package.
- type AssetFS struct {
- // Asset should return content of file in path if exists
- Asset func(path string) ([]byte, error)
- // AssetDir should return list of files in the path
- AssetDir func(path string) ([]string, error)
- // AssetInfo should return the info of file in path if exists
- AssetInfo func(path string) (os.FileInfo, error)
- // Prefix would be prepended to http requests
- Prefix string
- }
- func (fs *AssetFS) Open(name string) (http.File, error) {
- name = path.Join(fs.Prefix, name)
- if len(name) > 0 && name[0] == '/' {
- name = name[1:]
- }
- if b, err := fs.Asset(name); err == nil {
- timestamp := defaultFileTimestamp
- if fs.AssetInfo != nil {
- if info, err := fs.AssetInfo(name); err == nil {
- timestamp = info.ModTime()
- }
- }
- return NewAssetFile(name, b, timestamp), nil
- }
- if children, err := fs.AssetDir(name); err == nil {
- return NewAssetDirectory(name, children, fs), nil
- } else {
- // If the error is not found, return an error that will
- // result in a 404 error. Otherwise the server returns
- // a 500 error for files not found.
- if strings.Contains(err.Error(), "not found") {
- return nil, os.ErrNotExist
- }
- return nil, err
- }
- }
|