...

Source file src/github.com/Shopify/go-storage/memory_fs.go

Documentation: github.com/Shopify/go-storage

     1  package storage
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"io"
     7  	"strings"
     8  	"sync"
     9  	"time"
    10  )
    11  
    12  // NewMemoryFS creates a a basic in-memory implementation of FS.
    13  func NewMemoryFS() FS {
    14  	return &memoryFS{
    15  		data: make(map[string]*memFile),
    16  	}
    17  }
    18  
    19  type memFile struct {
    20  	data  []byte
    21  	attrs Attributes
    22  }
    23  
    24  func (f *memFile) readCloser() io.ReadCloser {
    25  	return io.NopCloser(bytes.NewReader(f.data))
    26  }
    27  
    28  type memoryFS struct {
    29  	sync.RWMutex
    30  
    31  	data map[string]*memFile
    32  }
    33  
    34  // Open implements FS.
    35  func (m *memoryFS) Open(_ context.Context, path string, _ *ReaderOptions) (*File, error) {
    36  	m.RLock()
    37  	f, ok := m.data[path]
    38  	m.RUnlock()
    39  
    40  	if ok {
    41  		return &File{
    42  			ReadCloser: f.readCloser(),
    43  			Attributes: f.attrs,
    44  		}, nil
    45  	}
    46  
    47  	return nil, &notExistError{
    48  		Path: path,
    49  	}
    50  }
    51  
    52  // Attributes implements FS.
    53  func (m *memoryFS) Attributes(_ context.Context, path string, _ *ReaderOptions) (*Attributes, error) {
    54  	m.RLock()
    55  	f, ok := m.data[path]
    56  	m.RUnlock()
    57  
    58  	if ok {
    59  		attrs := f.attrs
    60  
    61  		return &attrs, nil
    62  	}
    63  
    64  	return nil, &notExistError{
    65  		Path: path,
    66  	}
    67  }
    68  
    69  type writingFile struct {
    70  	*bytes.Buffer
    71  	path string
    72  
    73  	m       *memoryFS
    74  	options *WriterOptions
    75  }
    76  
    77  func (wf *writingFile) Close() error {
    78  	if wf.options.Attributes.Size == 0 {
    79  		wf.options.Attributes.Size = int64(wf.Buffer.Len())
    80  	}
    81  
    82  	wf.m.Lock()
    83  	// Record time with the lock so the time is accurate
    84  	if wf.options.Attributes.ModTime.IsZero() {
    85  		wf.options.Attributes.ModTime = time.Now()
    86  	}
    87  	wf.m.data[wf.path] = &memFile{
    88  		data:  wf.Buffer.Bytes(),
    89  		attrs: wf.options.Attributes,
    90  	}
    91  	wf.m.Unlock()
    92  
    93  	return nil
    94  }
    95  
    96  // Create implements FS.  NB: Callers must close the io.WriteCloser to create the file.
    97  func (m *memoryFS) Create(_ context.Context, path string, options *WriterOptions) (io.WriteCloser, error) {
    98  	if options == nil {
    99  		options = &WriterOptions{}
   100  	}
   101  
   102  	return &writingFile{
   103  		Buffer:  &bytes.Buffer{},
   104  		path:    path,
   105  		m:       m,
   106  		options: options,
   107  	}, nil
   108  }
   109  
   110  // Delete implements FS.
   111  func (m *memoryFS) Delete(_ context.Context, path string) error {
   112  	m.Lock()
   113  	delete(m.data, path)
   114  	m.Unlock()
   115  
   116  	return nil
   117  }
   118  
   119  // Walk implements FS.
   120  func (m *memoryFS) Walk(_ context.Context, path string, fn WalkFn) error {
   121  	var list []string
   122  	m.RLock()
   123  	for k := range m.data {
   124  		if strings.HasPrefix(k, path) {
   125  			list = append(list, k)
   126  		}
   127  	}
   128  	m.RUnlock()
   129  
   130  	for _, k := range list {
   131  		if err := fn(k); err != nil {
   132  			return err
   133  		}
   134  	}
   135  
   136  	return nil
   137  }
   138  
   139  func (m *memoryFS) URL(_ context.Context, _ string, _ *SignedURLOptions) (string, error) {
   140  	return "", ErrNotImplemented
   141  }
   142  

View as plain text