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 }