123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- package vessel
- import (
- "archive/zip"
- "fmt"
- "net/http"
- "os"
- "path"
- "path/filepath"
- "strings"
- "time"
- )
- // FileSystem implements an http filesystem access to the bundle
- type FileSystem struct {
- cacheTime time.Time
- b *Bundle
- files map[string]os.FileInfo
- }
- // verify we implement the http.FileSystem interface
- var _ http.FileSystem = (*FileSystem)(nil)
- func (f *FileSystem) get(name string) (*zip.File, error) {
- zr, err := zip.NewReader(f.b, f.b.Size())
- if err != nil {
- return nil, os.ErrNotExist
- }
- for idx := range zr.File {
- z := zr.File[idx]
- if z.Name == name {
- return z, nil
- }
- }
- return nil, os.ErrNotExist
- }
- // Open opens a file in the filesystem
- func (f *FileSystem) Open(name string) (http.File, error) {
- log.Log("vessel.FileSystem Open: %s|%s\n", name, filepath.Dir(name))
- v, ok := f.files[name]
- if !ok {
- return nil, os.ErrNotExist
- }
- if v.IsDir() {
- return &Dir{
- name: name,
- mode: os.ModeDir,
- fs: f,
- }, nil
- }
- z, err := f.get(name)
- if err != nil {
- return nil, err
- }
- if !z.FileInfo().IsDir() {
- z.Modified = v.ModTime()
- return newFile(z)
- }
- return nil, os.ErrNotExist
- }
- // Stat returns file info for a file in the bundle filesystem
- func (f *FileSystem) Stat(name string) (os.FileInfo, error) {
- v, ok := f.files[name]
- if !ok {
- return nil, os.ErrNotExist
- }
- return v, nil
- }
- func (f *FileSystem) isDir(path string) bool {
- if path == string(os.PathSeparator) {
- return true
- }
- v, ok := f.files[path]
- if !ok {
- return false
- }
- return v.IsDir()
- }
- // Dir return a list of files contained in a subdirectory of our bundle
- func (f *FileSystem) Dir(path string) ([]os.FileInfo, error) {
- if f.isDir(path) == false {
- return nil, os.ErrNotExist
- }
- ls := make([]os.FileInfo, 0)
- for k := range f.files {
- if k == path {
- continue
- }
- d := filepath.Dir(k)
- if d == path {
- fmt.Printf("+%s\n", k)
- ls = append(ls, f.files[k])
- }
- }
- return ls, nil
- }
- func (f *FileSystem) initCaches(cacheTime time.Time) error {
- zr, err := zip.NewReader(f.b, f.b.Size())
- if err != nil {
- return os.ErrNotExist
- }
- f.cacheTime = cacheTime
- files := make(map[string]os.FileInfo)
- for idx := range zr.File {
- z := zr.File[idx]
- if !f.cacheTime.IsZero() {
- z.Modified = f.cacheTime
- }
- files[z.Name] = z.FileInfo()
- }
- // zip files don't contain directories
- for k, v := range files {
- if v.IsDir() {
- continue
- }
- dir := filepath.Dir(k)
- chunks := strings.Split(dir, string(os.PathSeparator))
- for i := 2; i <= len(chunks); i++ {
- dir := fmt.Sprintf("/%s", path.Join(chunks[:i]...))
- if _, ok := files[dir]; !ok {
- files[dir] = &Dir{
- name: dir,
- mode: os.ModeDir,
- fs: f,
- }
- }
- }
- }
- f.files = files
- return nil
- }
|