123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- package vessel
- import (
- "io/fs"
- "net/http"
- "os"
- )
- // OverlayFS allows us to stack multiple overlapping http.FileSystems and search for a file in them in order
- type OverlayFS struct {
- search []http.FileSystem
- }
- // verify we implement the http.FileSystem interface
- var _ http.FileSystem = (*OverlayFS)(nil)
- // NewOverlayFS returns a new overlay FileSystem
- func NewOverlayFS() *OverlayFS {
- return &OverlayFS{}
- }
- // Append appends a filesystem to our overlay group.
- // Filesystems are searched in the order they are appended
- func (f *OverlayFS) Append(fs http.FileSystem) {
- f.search = append(f.search, fs)
- }
- // Open implements http.FileSystem
- func (f *OverlayFS) Open(name string) (http.File, error) {
- dir := &OverlayDir{}
- for _, source := range f.search {
- file, err := source.Open(name)
- if err == nil {
- s, err := file.Stat()
- if err != nil {
- continue
- }
- if !s.IsDir() {
- return file, nil
- }
- dir.files = append(dir.files, file)
- }
- }
- if len(dir.files) != 0 {
- return dir, nil
- }
- return nil, os.ErrNotExist
- }
- type OverlayDir struct {
- files []http.File
- }
- // Readdir implements http.FileSystem Readdir
- func (f *OverlayDir) Readdir(count int) ([]fs.FileInfo, error) {
- // for read dir we need all of the content
- content := make(map[string]fs.FileInfo)
- for _, dir := range f.files {
- list, err := dir.Readdir(count)
- if err != nil {
- continue
- }
- for idx, x := range list {
- if _, ok := content[x.Name()]; ok {
- continue
- }
- content[x.Name()] = list[idx]
- }
- }
- files := make([]fs.FileInfo, 0, count)
- for k := range content {
- files = append(files, content[k])
- }
- if len(files) > count {
- return files[0:count], nil
- }
- return files, nil
- }
- // Stat implements http.FileSystem Stat
- func (f *OverlayDir) Stat() (fs.FileInfo, error) {
- return f.files[0].Stat()
- }
- // Seek implements http.FileSystem Seek
- func (f *OverlayDir) Seek(offset int64, whence int) (int64, error) {
- return f.files[0].Seek(offset, whence)
- }
- // Read implements http.FileSystem Read
- func (f *OverlayDir) Read(p []byte) (n int, err error) {
- return f.files[0].Read(p)
- }
- // Close implements http.FileSystem Close
- func (f *OverlayDir) Close() error {
- return f.files[0].Close()
- }
|