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  }