mirror of
https://github.com/caddyserver/caddy.git
synced 2026-02-09 01:59:21 +08:00
filesystem: Globally declared filesystems, fs directive (#5833)
This commit is contained in:
77
internal/filesystems/map.go
Normal file
77
internal/filesystems/map.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package filesystems
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultFilesystemKey = "default"
|
||||
)
|
||||
|
||||
var DefaultFilesystem = &wrapperFs{key: DefaultFilesystemKey, FS: OsFS{}}
|
||||
|
||||
// wrapperFs exists so can easily add to wrapperFs down the line
|
||||
type wrapperFs struct {
|
||||
key string
|
||||
fs.FS
|
||||
}
|
||||
|
||||
// FilesystemMap stores a map of filesystems
|
||||
// the empty key will be overwritten to be the default key
|
||||
// it includes a default filesystem, based off the os fs
|
||||
type FilesystemMap struct {
|
||||
m sync.Map
|
||||
}
|
||||
|
||||
// note that the first invocation of key cannot be called in a racy context.
|
||||
func (f *FilesystemMap) key(k string) string {
|
||||
if k == "" {
|
||||
k = DefaultFilesystemKey
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
// Register will add the filesystem with key to later be retrieved
|
||||
// A call with a nil fs will call unregister, ensuring that a call to Default() will never be nil
|
||||
func (f *FilesystemMap) Register(k string, v fs.FS) {
|
||||
k = f.key(k)
|
||||
if v == nil {
|
||||
f.Unregister(k)
|
||||
return
|
||||
}
|
||||
f.m.Store(k, &wrapperFs{key: k, FS: v})
|
||||
}
|
||||
|
||||
// Unregister will remove the filesystem with key from the filesystem map
|
||||
// if the key is the default key, it will set the default to the osFS instead of deleting it
|
||||
// modules should call this on cleanup to be safe
|
||||
func (f *FilesystemMap) Unregister(k string) {
|
||||
k = f.key(k)
|
||||
if k == DefaultFilesystemKey {
|
||||
f.m.Store(k, DefaultFilesystem)
|
||||
} else {
|
||||
f.m.Delete(k)
|
||||
}
|
||||
}
|
||||
|
||||
// Get will get a filesystem with a given key
|
||||
func (f *FilesystemMap) Get(k string) (v fs.FS, ok bool) {
|
||||
k = f.key(k)
|
||||
c, ok := f.m.Load(strings.TrimSpace(k))
|
||||
if !ok {
|
||||
if k == DefaultFilesystemKey {
|
||||
f.m.Store(k, DefaultFilesystem)
|
||||
return DefaultFilesystem, true
|
||||
}
|
||||
return nil, ok
|
||||
}
|
||||
return c.(fs.FS), true
|
||||
}
|
||||
|
||||
// Default will get the default filesystem in the filesystem map
|
||||
func (f *FilesystemMap) Default() fs.FS {
|
||||
val, _ := f.Get(DefaultFilesystemKey)
|
||||
return val
|
||||
}
|
||||
29
internal/filesystems/os.go
Normal file
29
internal/filesystems/os.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package filesystems
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// OsFS is a simple fs.FS implementation that uses the local
|
||||
// file system. (We do not use os.DirFS because we do our own
|
||||
// rooting or path prefixing without being constrained to a single
|
||||
// root folder. The standard os.DirFS implementation is problematic
|
||||
// since roots can be dynamic in our application.)
|
||||
//
|
||||
// OsFS also implements fs.StatFS, fs.GlobFS, fs.ReadDirFS, and fs.ReadFileFS.
|
||||
type OsFS struct{}
|
||||
|
||||
func (OsFS) Open(name string) (fs.File, error) { return os.Open(name) }
|
||||
func (OsFS) Stat(name string) (fs.FileInfo, error) { return os.Stat(name) }
|
||||
func (OsFS) Glob(pattern string) ([]string, error) { return filepath.Glob(pattern) }
|
||||
func (OsFS) ReadDir(name string) ([]fs.DirEntry, error) { return os.ReadDir(name) }
|
||||
func (OsFS) ReadFile(name string) ([]byte, error) { return os.ReadFile(name) }
|
||||
|
||||
var (
|
||||
_ fs.StatFS = (*OsFS)(nil)
|
||||
_ fs.GlobFS = (*OsFS)(nil)
|
||||
_ fs.ReadDirFS = (*OsFS)(nil)
|
||||
_ fs.ReadFileFS = (*OsFS)(nil)
|
||||
)
|
||||
Reference in New Issue
Block a user