golang.org/x/build@v0.0.0-20240506185731-218518f32b70/perfdata/fs/fs.go (about) 1 // Copyright 2016 The Go 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 fs provides a backend-agnostic filesystem layer for storing 6 // performance results. 7 package fs 8 9 import ( 10 "context" 11 "errors" 12 "io" 13 "sort" 14 "sync" 15 ) 16 17 // An FS stores uploaded benchmark data files. 18 type FS interface { 19 // NewWriter returns a Writer for a given file name. 20 // When the Writer is closed, the file will be stored with the 21 // given metadata and the data written to the writer. 22 NewWriter(ctx context.Context, name string, metadata map[string]string) (Writer, error) 23 } 24 25 // A Writer is an io.Writer that can also be closed with an error. 26 type Writer interface { 27 io.WriteCloser 28 // CloseWithError cancels the writing of the file, removing 29 // any partially written data. 30 CloseWithError(error) error 31 } 32 33 // MemFS is an in-memory filesystem implementing the FS interface. 34 type MemFS struct { 35 mu sync.Mutex 36 content map[string]*memFile 37 } 38 39 // NewMemFS constructs a new, empty MemFS. 40 func NewMemFS() *MemFS { 41 return &MemFS{ 42 content: make(map[string]*memFile), 43 } 44 } 45 46 // NewWriter returns a Writer for a given file name. As a side effect, 47 // it associates the given metadata with the file. 48 func (fs *MemFS) NewWriter(_ context.Context, name string, metadata map[string]string) (Writer, error) { 49 meta := make(map[string]string) 50 for k, v := range metadata { 51 meta[k] = v 52 } 53 return &memFile{fs: fs, name: name, metadata: meta}, nil 54 } 55 56 // Files returns the names of the files written to fs. 57 func (fs *MemFS) Files() []string { 58 fs.mu.Lock() 59 defer fs.mu.Unlock() 60 var files []string 61 for f := range fs.content { 62 files = append(files, f) 63 } 64 sort.Strings(files) 65 return files 66 } 67 68 // memFile represents a file in a MemFS. While the file is being 69 // written, fs points to the filesystem. Close writes the file's 70 // content to fs and sets fs to nil. 71 type memFile struct { 72 fs *MemFS 73 name string 74 metadata map[string]string 75 content []byte 76 } 77 78 func (f *memFile) Write(p []byte) (int, error) { 79 f.content = append(f.content, p...) 80 return len(p), nil 81 } 82 83 func (f *memFile) Close() error { 84 if f.fs == nil { 85 return errors.New("already closed") 86 } 87 f.fs.mu.Lock() 88 defer f.fs.mu.Unlock() 89 f.fs.content[f.name] = f 90 f.fs = nil 91 return nil 92 } 93 94 func (f *memFile) CloseWithError(error) error { 95 f.fs = nil 96 return nil 97 }