github.com/kyleu/dbaudit@v0.0.2-0.20240321155047-ff2f2c940496/app/lib/filesystem/filesystem.go (about) 1 // Package filesystem - Content managed by Project Forge, see [projectforge.md] for details. 2 package filesystem 3 4 import ( 5 "fmt" 6 "path/filepath" 7 "runtime" 8 "strings" 9 10 "github.com/pkg/errors" 11 "github.com/spf13/afero" 12 ) 13 14 var memFS, osFS afero.Fs 15 16 func MemFS() afero.Fs { 17 if memFS == nil { 18 memFS = afero.NewMemMapFs() 19 } 20 return memFS 21 } 22 23 func OSFS() afero.Fs { 24 if osFS == nil { 25 osFS = afero.NewOsFs() 26 } 27 return osFS 28 } 29 30 type FileSystem struct { 31 Mode string `json:"mode,omitempty"` 32 ReadOnly bool `json:"readOnly,omitempty"` 33 root string 34 f afero.Fs 35 } 36 37 var _ FileLoader = (*FileSystem)(nil) 38 39 func NewFileSystem(root string, readonly bool, mode string) (*FileSystem, error) { 40 root = strings.TrimPrefix(root, "./") 41 var f afero.Fs 42 switch mode { 43 case "memory": 44 f = MemFS() 45 case "file": 46 f = OSFS() 47 case "": 48 switch runtime.GOOS { 49 case "js": 50 f = MemFS() 51 default: 52 f = OSFS() 53 } 54 default: 55 return nil, errors.Errorf("invalid filesystem mode [%s]", mode) 56 } 57 if readonly { 58 f = afero.NewReadOnlyFs(f) 59 } 60 return &FileSystem{root: root, f: f}, nil 61 } 62 63 func (f *FileSystem) getPath(ss ...string) string { 64 s := filepath.Join(ss...) 65 if strings.HasPrefix(s, f.root) { 66 return s 67 } 68 return filepath.Join(f.root, s) 69 } 70 71 func (f *FileSystem) Root() string { 72 return f.root 73 } 74 75 func (f *FileSystem) Clone() FileLoader { 76 ret, _ := NewFileSystem(f.root, f.ReadOnly, f.Mode) 77 return ret 78 } 79 80 func (f *FileSystem) Stat(path string) (*FileInfo, error) { 81 p := f.getPath(path) 82 s, err := f.f.Stat(p) 83 if err != nil { 84 return nil, err 85 } 86 return FileInfoFromFS(s), nil 87 } 88 89 func (f *FileSystem) SetMode(path string, mode FileMode) error { 90 p := f.getPath(path) 91 return f.f.Chmod(p, mode.ToFS()) 92 } 93 94 func (f *FileSystem) Exists(path string) bool { 95 x, _ := f.Stat(path) 96 return x != nil 97 } 98 99 func (f *FileSystem) IsDir(path string) bool { 100 s, err := f.Stat(path) 101 if s == nil || err != nil { 102 return false 103 } 104 return s.IsDir 105 } 106 107 func (f *FileSystem) CreateDirectory(path string) error { 108 p := f.getPath(path) 109 if err := f.f.MkdirAll(p, DirectoryMode.ToFS()); err != nil { 110 return errors.Wrapf(err, "unable to create data directory [%s]", p) 111 } 112 return nil 113 } 114 115 func (f *FileSystem) String() string { 116 return fmt.Sprintf("fs://%s", f.root) 117 }