...

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

Documentation: github.com/Shopify/go-storage

     1  package storage
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  	"path/filepath"
     9  	"strings"
    10  )
    11  
    12  // DefaultLocalCreatePathMode is the default os.FileMode used when creating directories
    13  // during a localFS.Create call.
    14  const DefaultLocalCreatePathMode = os.FileMode(0o755)
    15  
    16  // LocalCreatePathMode is the os.FileMode used when creating directories via localFS.Create
    17  var LocalCreatePathMode = DefaultLocalCreatePathMode
    18  
    19  // localFS is a local FS and Walker implementation.
    20  type localFS string
    21  
    22  func NewLocalFS(path string) FS {
    23  	fs := localFS(path)
    24  
    25  	return &fs
    26  }
    27  
    28  func (l *localFS) fullPath(path string) string {
    29  	return filepath.Join(string(*l), path)
    30  }
    31  
    32  func (l *localFS) wrapError(path string, err error) error {
    33  	if os.IsNotExist(err) {
    34  		return &notExistError{
    35  			Path: path,
    36  		}
    37  	}
    38  
    39  	return err
    40  }
    41  
    42  // Open implements FS.
    43  func (l *localFS) Open(_ context.Context, path string, _ *ReaderOptions) (*File, error) {
    44  	path = l.fullPath(path)
    45  
    46  	f, err := os.Open(path)
    47  	if err != nil {
    48  		return nil, l.wrapError(path, err)
    49  	}
    50  
    51  	stat, err := f.Stat()
    52  	if err != nil {
    53  		return nil, l.wrapError(path, err)
    54  	}
    55  
    56  	return &File{
    57  		ReadCloser: f,
    58  		Attributes: Attributes{
    59  			ModTime: stat.ModTime(),
    60  			Size:    stat.Size(),
    61  		},
    62  	}, nil
    63  }
    64  
    65  // Attributes implements FS.
    66  func (l *localFS) Attributes(_ context.Context, path string, _ *ReaderOptions) (*Attributes, error) {
    67  	path = l.fullPath(path)
    68  
    69  	stat, err := os.Stat(path)
    70  	if err != nil {
    71  		return nil, l.wrapError(path, err)
    72  	}
    73  
    74  	return &Attributes{
    75  		ModTime: stat.ModTime(),
    76  		Size:    stat.Size(),
    77  	}, nil
    78  }
    79  
    80  // Create implements FS.  If the path contains any directories which do not already exist
    81  // then Create will try to make them, returning an error if it fails.
    82  func (l *localFS) Create(_ context.Context, path string, options *WriterOptions) (io.WriteCloser, error) {
    83  	path = l.fullPath(path)
    84  
    85  	dir := filepath.Dir(path)
    86  	if _, err := os.Stat(dir); os.IsNotExist(err) {
    87  		if err := os.MkdirAll(dir, LocalCreatePathMode); err != nil {
    88  			return nil, err
    89  		}
    90  	}
    91  
    92  	f, err := os.Create(path)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  	if options != nil {
    97  		if !options.Attributes.CreationTime.IsZero() {
    98  			// There is no way to store the CreationTime, so overwrite the ModTime
    99  			// This is necessary so the CacheWrapper can use LocalFS
   100  			options.Attributes.ModTime = options.Attributes.CreationTime
   101  		}
   102  		if !options.Attributes.ModTime.IsZero() {
   103  			if err := os.Chtimes(path, options.Attributes.ModTime, options.Attributes.ModTime); err != nil {
   104  				return f, err
   105  			}
   106  		}
   107  	}
   108  
   109  	return f, nil
   110  }
   111  
   112  // Delete implements FS.  All files underneath path will be removed.
   113  func (l *localFS) Delete(_ context.Context, path string) error {
   114  	return os.RemoveAll(l.fullPath(path))
   115  }
   116  
   117  // Walk implements Walker.
   118  func (l *localFS) Walk(_ context.Context, path string, fn WalkFn) error {
   119  	return filepath.Walk(l.fullPath(path), func(path string, f os.FileInfo, err error) error {
   120  		if err != nil {
   121  			return err
   122  		}
   123  
   124  		if !f.IsDir() {
   125  			path = strings.TrimPrefix(path, string(*l))
   126  
   127  			return fn(path)
   128  		}
   129  
   130  		return nil
   131  	})
   132  }
   133  
   134  func (l *localFS) URL(_ context.Context, path string, _ *SignedURLOptions) (string, error) {
   135  	path = l.fullPath(path)
   136  	_, err := os.Stat(path)
   137  	if err != nil {
   138  		return "", l.wrapError(path, err)
   139  	}
   140  
   141  	return fmt.Sprintf("file://%s", path), nil
   142  }
   143  

View as plain text