github.com/hairyhenderson/gomplate/v4@v4.0.0-pre-2.0.20240520121557-362f058f0c93/internal/datafs/stdinfs.go (about)

     1  package datafs
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"io"
     7  	"io/fs"
     8  	"net/url"
     9  	"time"
    10  
    11  	"github.com/hairyhenderson/go-fsimpl"
    12  )
    13  
    14  // NewStdinFS returns a filesystem (an fs.FS) that can be used to read data from
    15  // standard input (os.Stdin).
    16  func NewStdinFS(_ *url.URL) (fs.FS, error) {
    17  	return &stdinFS{ctx: context.Background()}, nil
    18  }
    19  
    20  type stdinFS struct {
    21  	ctx context.Context
    22  }
    23  
    24  //nolint:gochecknoglobals
    25  var StdinFS = fsimpl.FSProviderFunc(NewStdinFS, "stdin")
    26  
    27  var (
    28  	_ fs.FS         = (*stdinFS)(nil)
    29  	_ fs.ReadFileFS = (*stdinFS)(nil)
    30  	_ withContexter = (*stdinFS)(nil)
    31  )
    32  
    33  func (f stdinFS) WithContext(ctx context.Context) fs.FS {
    34  	fsys := f
    35  	fsys.ctx = ctx
    36  
    37  	return &fsys
    38  }
    39  
    40  func (f *stdinFS) Open(name string) (fs.File, error) {
    41  	if !fs.ValidPath(name) {
    42  		return nil, &fs.PathError{
    43  			Op:   "open",
    44  			Path: name,
    45  			Err:  fs.ErrInvalid,
    46  		}
    47  	}
    48  
    49  	stdin := StdinFromContext(f.ctx)
    50  
    51  	return &stdinFile{name: name, body: stdin}, nil
    52  }
    53  
    54  func (f *stdinFS) ReadFile(name string) ([]byte, error) {
    55  	if !fs.ValidPath(name) {
    56  		return nil, &fs.PathError{
    57  			Op:   "readFile",
    58  			Path: name,
    59  			Err:  fs.ErrInvalid,
    60  		}
    61  	}
    62  
    63  	stdin := StdinFromContext(f.ctx)
    64  
    65  	return io.ReadAll(stdin)
    66  }
    67  
    68  type stdinFile struct {
    69  	body io.Reader
    70  	name string
    71  }
    72  
    73  var _ fs.File = (*stdinFile)(nil)
    74  
    75  func (f *stdinFile) Close() error {
    76  	if f.body == nil {
    77  		return &fs.PathError{Op: "close", Path: f.name, Err: fs.ErrClosed}
    78  	}
    79  
    80  	f.body = nil
    81  	return nil
    82  }
    83  
    84  func (f *stdinFile) stdinReader() (int, error) {
    85  	b, err := io.ReadAll(f.body)
    86  	if err != nil {
    87  		return 0, err
    88  	}
    89  
    90  	f.body = bytes.NewReader(b)
    91  
    92  	return len(b), err
    93  }
    94  
    95  func (f *stdinFile) Stat() (fs.FileInfo, error) {
    96  	n, err := f.stdinReader()
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  
   101  	return FileInfo(f.name, int64(n), 0o444, time.Time{}, ""), nil
   102  }
   103  
   104  func (f *stdinFile) Read(p []byte) (int, error) {
   105  	if f.body == nil {
   106  		return 0, io.EOF
   107  	}
   108  
   109  	return f.body.Read(p)
   110  }