github.com/rgonomic/rgo@v0.2.2-0.20220708095818-4747f0905d6e/internal/vfs/txtar/txtar.go (about) 1 // Copyright ©2019 The rgonomic Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package txtar provides a simple write-only filesystem based on the txtar archive format. 6 package txtar 7 8 import ( 9 "bytes" 10 "io" 11 "os" 12 "sort" 13 14 "golang.org/x/tools/txtar" 15 ) 16 17 // FileSystem is a write-only filesystem based on the txtar text archive format 18 // provided by golang.org/x/tools/txtar. 19 type FileSystem struct { 20 // Output is the destination of the filesystem 21 // when the Flush method is called. If Output 22 // is nil, data is written to os.Stdout. 23 Output io.Writer 24 ar txtar.Archive 25 buf bytes.Buffer 26 } 27 28 // Open returns a new io.WriteCloser file whose writes will added to the 29 // txtar output of the Filesystem with the given path. Writes to the 30 // file are buffered until the Flush method is called. The file must 31 // be closed before calling Flush. 32 func (fs *FileSystem) Open(path string) (io.WriteCloser, error) { 33 return file{path: path, buf: &fs.buf, owner: fs}, nil 34 } 35 36 func (fs *FileSystem) add(path string, data []byte) { 37 fs.ar.Files = append(fs.ar.Files, txtar.File{ 38 Name: path, 39 Data: data, 40 }) 41 } 42 43 // Flush writes all closed io.Writers to the FileSystem's Output 44 // or os.Stdout if Output is nil. The files in the txtar are sorted 45 // lexically by name. 46 func (fs *FileSystem) Flush() error { 47 sort.Sort(byPath(fs.ar.Files)) 48 var dst io.Writer = os.Stdout 49 if fs.Output != nil { 50 dst = fs.Output 51 } 52 _, err := dst.Write(txtar.Format(&fs.ar)) 53 return err 54 } 55 56 type file struct { 57 path string 58 buf *bytes.Buffer 59 owner *FileSystem 60 } 61 62 func (f file) Write(b []byte) (int, error) { 63 return f.buf.Write(b) 64 } 65 66 func (f file) Close() error { 67 b := make([]byte, f.buf.Len()) 68 copy(b, f.buf.Bytes()) 69 f.owner.add(f.path, b) 70 f.buf.Reset() 71 return nil 72 } 73 74 type byPath []txtar.File 75 76 func (f byPath) Len() int { return len(f) } 77 func (f byPath) Less(i, j int) bool { return f[i].Name < f[j].Name } 78 func (f byPath) Swap(i, j int) { f[i], f[j] = f[j], f[i] }