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  }