github.com/databricks/cli@v0.203.0/libs/filer/fs.go (about) 1 package filer 2 3 import ( 4 "bytes" 5 "context" 6 "io" 7 "io/fs" 8 ) 9 10 // filerFS implements the fs.FS interface for a filer. 11 type filerFS struct { 12 ctx context.Context 13 filer Filer 14 } 15 16 // NewFS returns an fs.FS backed by a filer. 17 func NewFS(ctx context.Context, filer Filer) fs.FS { 18 return &filerFS{ctx: ctx, filer: filer} 19 } 20 21 func (fs *filerFS) Open(name string) (fs.File, error) { 22 stat, err := fs.filer.Stat(fs.ctx, name) 23 if err != nil { 24 return nil, err 25 } 26 27 if stat.IsDir() { 28 return &fsDir{fs: fs, name: name, stat: stat}, nil 29 } 30 31 return &fsFile{fs: fs, name: name, stat: stat}, nil 32 } 33 34 func (fs *filerFS) ReadDir(name string) ([]fs.DirEntry, error) { 35 return fs.filer.ReadDir(fs.ctx, name) 36 } 37 38 func (fs *filerFS) ReadFile(name string) ([]byte, error) { 39 reader, err := fs.filer.Read(fs.ctx, name) 40 if err != nil { 41 return nil, err 42 } 43 44 var buf bytes.Buffer 45 _, err = io.Copy(&buf, reader) 46 if err != nil { 47 return nil, err 48 } 49 50 return buf.Bytes(), nil 51 } 52 53 func (fs *filerFS) Stat(name string) (fs.FileInfo, error) { 54 return fs.filer.Stat(fs.ctx, name) 55 } 56 57 // Type that implements fs.File for a filer-backed fs.FS. 58 type fsFile struct { 59 fs *filerFS 60 name string 61 stat fs.FileInfo 62 63 reader io.Reader 64 } 65 66 func (f *fsFile) Stat() (fs.FileInfo, error) { 67 return f.stat, nil 68 } 69 70 func (f *fsFile) Read(buf []byte) (int, error) { 71 if f.reader == nil { 72 reader, err := f.fs.filer.Read(f.fs.ctx, f.name) 73 if err != nil { 74 return 0, err 75 } 76 f.reader = reader 77 } 78 79 return f.reader.Read(buf) 80 } 81 82 func (f *fsFile) Close() error { 83 if f.reader == nil { 84 return fs.ErrClosed 85 } 86 f.reader = nil 87 return nil 88 } 89 90 // Type that implements fs.ReadDirFile for a filer-backed fs.FS. 91 type fsDir struct { 92 fs *filerFS 93 name string 94 stat fs.FileInfo 95 96 open bool 97 entries []fs.DirEntry 98 } 99 100 func (f *fsDir) Stat() (fs.FileInfo, error) { 101 return f.stat, nil 102 } 103 104 func (f *fsDir) Read(buf []byte) (int, error) { 105 return 0, fs.ErrInvalid 106 } 107 108 func (f *fsDir) ReadDir(n int) ([]fs.DirEntry, error) { 109 // Load all directory entries if not already loaded. 110 if !f.open { 111 entries, err := f.fs.ReadDir(f.name) 112 if err != nil { 113 return nil, err 114 } 115 f.open = true 116 f.entries = entries 117 } 118 119 // Return all entries if n <= 0. 120 if n <= 0 { 121 entries := f.entries 122 f.entries = nil 123 return entries, nil 124 } 125 126 // If there are no more entries, return io.EOF. 127 if len(f.entries) == 0 { 128 return nil, io.EOF 129 } 130 131 // If there are less than n entries, return all entries. 132 if len(f.entries) < n { 133 entries := f.entries 134 f.entries = nil 135 return entries, nil 136 } 137 138 // Return n entries. 139 entries := f.entries[:n] 140 f.entries = f.entries[n:] 141 return entries, nil 142 } 143 144 func (f *fsDir) Close() error { 145 if !f.open { 146 return fs.ErrClosed 147 } 148 f.open = false 149 f.entries = nil 150 return nil 151 }