github.com/hbbio/afero@v1.2.3-0.20190412153849-bd67867be27b/README.md (about)

     1  ![afero logo-sm](https://cloud.githubusercontent.com/assets/173412/11490338/d50e16dc-97a5-11e5-8b12-019a300d0fcb.png)
     2  
     3  A FileSystem Abstraction System for Go
     4  
     5  [![Build Status](https://travis-ci.org/hbbio/afero.svg)](https://travis-ci.org/hbbio/afero) [![Build status](https://ci.appveyor.com/api/projects/status/github/hbbio/afero?branch=master&svg=true)](https://ci.appveyor.com/project/hbbio/afero) [![GoDoc](https://godoc.org/github.com/hbbio/afero?status.svg)](https://godoc.org/github.com/hbbio/afero) [![Join the chat at https://gitter.im/hbbio/afero](https://badges.gitter.im/Dev%20Chat.svg)](https://gitter.im/hbbio/afero?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
     6  
     7  # Overview
     8  
     9  Afero is an filesystem framework providing a simple, uniform and universal API
    10  interacting with any filesystem, as an abstraction layer providing interfaces,
    11  types and methods. Afero has an exceptionally clean interface and simple design
    12  without needless constructors or initialization methods.
    13  
    14  Afero is also a library providing a base set of interoperable backend
    15  filesystems that make it easy to work with afero while retaining all the power
    16  and benefit of the os and ioutil packages.
    17  
    18  Afero provides significant improvements over using the os package alone, most
    19  notably the ability to create mock and testing filesystems without relying on the disk.
    20  
    21  It is suitable for use in a any situation where you would consider using the OS
    22  package as it provides an additional abstraction that makes it easy to use a
    23  memory backed file system during testing. It also adds support for the http
    24  filesystem for full interoperability.
    25  
    26  ## Afero Features
    27  
    28  - A single consistent API for accessing a variety of filesystems
    29  - Interoperation between a variety of file system types
    30  - A set of interfaces to encourage and enforce interoperability between backends
    31  - An atomic cross platform memory backed file system
    32  - Support for compositional (union) file systems by combining multiple file systems acting as one
    33  - Specialized backends which modify existing filesystems (Read Only, Regexp filtered)
    34  - A set of utility functions ported from io, ioutil & hugo to be afero aware
    35  
    36  # Using Afero
    37  
    38  Afero is easy to use and easier to adopt.
    39  
    40  A few different ways you could use Afero:
    41  
    42  - Use the interfaces alone to define you own file system.
    43  - Wrap for the OS packages.
    44  - Define different filesystems for different parts of your application.
    45  - Use Afero for mock filesystems while testing
    46  
    47  ## Step 1: Install Afero
    48  
    49  First use go get to install the latest version of the library.
    50  
    51      $ go get github.com/hbbio/afero
    52  
    53  Next include Afero in your application.
    54  
    55  ```go
    56  import "github.com/hbbio/afero"
    57  ```
    58  
    59  ## Step 2: Declare a backend
    60  
    61  First define a package variable and set it to a pointer to a filesystem.
    62  
    63  ```go
    64  var AppFs = afero.NewMemMapFs()
    65  
    66  or
    67  
    68  var AppFs = afero.NewOsFs()
    69  ```
    70  
    71  It is important to note that if you repeat the composite literal you
    72  will be using a completely new and isolated filesystem. In the case of
    73  OsFs it will still use the same underlying filesystem but will reduce
    74  the ability to drop in other filesystems as desired.
    75  
    76  ## Step 3: Use it like you would the OS package
    77  
    78  Throughout your application use any function and method like you normally
    79  would.
    80  
    81  So if my application before had:
    82  
    83  ```go
    84  os.Open('/tmp/foo')
    85  ```
    86  
    87  We would replace it with:
    88  
    89  ```go
    90  AppFs.Open('/tmp/foo')
    91  ```
    92  
    93  `AppFs` being the variable we defined above.
    94  
    95  ## List of all available functions
    96  
    97  File System Methods Available:
    98  
    99  ```go
   100  Chmod(name string, mode os.FileMode) : error
   101  Chtimes(name string, atime time.Time, mtime time.Time) : error
   102  Create(name string) : File, error
   103  Mkdir(name string, perm os.FileMode) : error
   104  MkdirAll(path string, perm os.FileMode) : error
   105  Name() : string
   106  Open(name string) : File, error
   107  OpenFile(name string, flag int, perm os.FileMode) : File, error
   108  Remove(name string) : error
   109  RemoveAll(path string) : error
   110  Rename(oldname, newname string) : error
   111  Stat(name string) : os.FileInfo, error
   112  ```
   113  
   114  File Interfaces and Methods Available:
   115  
   116  ```go
   117  io.Closer
   118  io.Reader
   119  io.ReaderAt
   120  io.Seeker
   121  io.Writer
   122  io.WriterAt
   123  
   124  Name() : string
   125  Readdir(count int) : []os.FileInfo, error
   126  Readdirnames(n int) : []string, error
   127  Stat() : os.FileInfo, error
   128  Sync() : error
   129  Truncate(size int64) : error
   130  WriteString(s string) : ret int, err error
   131  ```
   132  
   133  In some applications it may make sense to define a new package that
   134  simply exports the file system variable for easy access from anywhere.
   135  
   136  ## Using Afero's utility functions
   137  
   138  Afero provides a set of functions to make it easier to use the underlying file systems.
   139  These functions have been primarily ported from io & ioutil with some developed for Hugo.
   140  
   141  The afero utilities support all afero compatible backends.
   142  
   143  The list of utilities includes:
   144  
   145  ```go
   146  DirExists(path string) (bool, error)
   147  Exists(path string) (bool, error)
   148  FileContainsBytes(filename string, subslice []byte) (bool, error)
   149  GetTempDir(subPath string) string
   150  IsDir(path string) (bool, error)
   151  IsEmpty(path string) (bool, error)
   152  ReadDir(dirname string) ([]os.FileInfo, error)
   153  ReadFile(filename string) ([]byte, error)
   154  SafeWriteReader(path string, r io.Reader) (err error)
   155  TempDir(dir, prefix string) (name string, err error)
   156  TempFile(dir, prefix string) (f File, err error)
   157  Walk(root string, walkFn filepath.WalkFunc) error
   158  WriteFile(filename string, data []byte, perm os.FileMode) error
   159  WriteReader(path string, r io.Reader) (err error)
   160  ```
   161  
   162  For a complete list see [Afero's GoDoc](https://godoc.org/github.com/hbbio/afero)
   163  
   164  They are available under two different approaches to use. You can either call
   165  them directly where the first parameter of each function will be the file
   166  system, or you can declare a new `Afero`, a custom type used to bind these
   167  functions as methods to a given filesystem.
   168  
   169  ### Calling utilities directly
   170  
   171  ```go
   172  fs := new(afero.MemMapFs)
   173  f, err := afero.TempFile(fs,"", "ioutil-test")
   174  
   175  ```
   176  
   177  ### Calling via Afero
   178  
   179  ```go
   180  fs := afero.NewMemMapFs()
   181  afs := &afero.Afero{Fs: fs}
   182  f, err := afs.TempFile("", "ioutil-test")
   183  ```
   184  
   185  ## Using Afero for Testing
   186  
   187  There is a large benefit to using a mock filesystem for testing. It has a
   188  completely blank state every time it is initialized and can be easily
   189  reproducible regardless of OS. You could create files to your heart’s content
   190  and the file access would be fast while also saving you from all the annoying
   191  issues with deleting temporary files, Windows file locking, etc. The MemMapFs
   192  backend is perfect for testing.
   193  
   194  - Much faster than performing I/O operations on disk
   195  - Avoid security issues and permissions
   196  - Far more control. 'rm -rf /' with confidence
   197  - Test setup is far more easier to do
   198  - No test cleanup needed
   199  
   200  One way to accomplish this is to define a variable as mentioned above.
   201  In your application this will be set to afero.NewOsFs() during testing you
   202  can set it to afero.NewMemMapFs().
   203  
   204  It wouldn't be uncommon to have each test initialize a blank slate memory
   205  backend. To do this I would define my `appFS = afero.NewOsFs()` somewhere
   206  appropriate in my application code. This approach ensures that Tests are order
   207  independent, with no test relying on the state left by an earlier test.
   208  
   209  Then in my tests I would initialize a new MemMapFs for each test:
   210  
   211  ```go
   212  func TestExist(t *testing.T) {
   213  	appFS := afero.NewMemMapFs()
   214  	// create test files and directories
   215  	appFS.MkdirAll("src/a", 0755)
   216  	afero.WriteFile(appFS, "src/a/b", []byte("file b"), 0644)
   217  	afero.WriteFile(appFS, "src/c", []byte("file c"), 0644)
   218  	name := "src/c"
   219  	_, err := appFS.Stat(name)
   220  	if os.IsNotExist(err) {
   221  		t.Errorf("file \"%s\" does not exist.\n", name)
   222  	}
   223  }
   224  ```
   225  
   226  # Available Backends
   227  
   228  ## Operating System Native
   229  
   230  ### OsFs
   231  
   232  The first is simply a wrapper around the native OS calls. This makes it
   233  very easy to use as all of the calls are the same as the existing OS
   234  calls. It also makes it trivial to have your code use the OS during
   235  operation and a mock filesystem during testing or as needed.
   236  
   237  ```go
   238  appfs := afero.NewOsFs()
   239  appfs.MkdirAll("src/a", 0755))
   240  ```
   241  
   242  ## Memory Backed Storage
   243  
   244  ### MemMapFs
   245  
   246  Afero also provides a fully atomic memory backed filesystem perfect for use in
   247  mocking and to speed up unnecessary disk io when persistence isn’t
   248  necessary. It is fully concurrent and will work within go routines
   249  safely.
   250  
   251  ```go
   252  mm := afero.NewMemMapFs()
   253  mm.MkdirAll("src/a", 0755))
   254  ```
   255  
   256  #### InMemoryFile
   257  
   258  As part of MemMapFs, Afero also provides an atomic, fully concurrent memory
   259  backed file implementation. This can be used in other memory backed file
   260  systems with ease. Plans are to add a radix tree memory stored file
   261  system using InMemoryFile.
   262  
   263  ## Network Interfaces
   264  
   265  ### SftpFs
   266  
   267  Afero has experimental support for secure file transfer protocol (sftp). Which can
   268  be used to perform file operations over a encrypted channel.
   269  
   270  ## Filtering Backends
   271  
   272  ### BasePathFs
   273  
   274  The BasePathFs restricts all operations to a given path within an Fs.
   275  The given file name to the operations on this Fs will be prepended with
   276  the base path before calling the source Fs.
   277  
   278  ```go
   279  bp := afero.NewBasePathFs(afero.NewOsFs(), "/base/path")
   280  ```
   281  
   282  ### ReadOnlyFs
   283  
   284  A thin wrapper around the source Fs providing a read only view.
   285  
   286  ```go
   287  fs := afero.NewReadOnlyFs(afero.NewOsFs())
   288  _, err := fs.Create("/file.txt")
   289  // err = syscall.EPERM
   290  ```
   291  
   292  # RegexpFs
   293  
   294  A filtered view on file names, any file NOT matching
   295  the passed regexp will be treated as non-existing.
   296  Files not matching the regexp provided will not be created.
   297  Directories are not filtered.
   298  
   299  ```go
   300  fs := afero.NewRegexpFs(afero.NewMemMapFs(), regexp.MustCompile(`\.txt$`))
   301  _, err := fs.Create("/file.html")
   302  // err = syscall.ENOENT
   303  ```
   304  
   305  ### HttpFs
   306  
   307  Afero provides an http compatible backend which can wrap any of the existing
   308  backends.
   309  
   310  The Http package requires a slightly specific version of Open which
   311  returns an http.File type.
   312  
   313  Afero provides an httpFs file system which satisfies this requirement.
   314  Any Afero FileSystem can be used as an httpFs.
   315  
   316  ```go
   317  httpFs := afero.NewHttpFs(<ExistingFS>)
   318  fileserver := http.FileServer(httpFs.Dir(<PATH>)))
   319  http.Handle("/", fileserver)
   320  ```
   321  
   322  ## Composite Backends
   323  
   324  Afero provides the ability have two filesystems (or more) act as a single
   325  file system.
   326  
   327  ### CacheOnReadFs
   328  
   329  The CacheOnReadFs will lazily make copies of any accessed files from the base
   330  layer into the overlay. Subsequent reads will be pulled from the overlay
   331  directly permitting the request is within the cache duration of when it was
   332  created in the overlay.
   333  
   334  If the base filesystem is writeable, any changes to files will be
   335  done first to the base, then to the overlay layer. Write calls to open file
   336  handles like `Write()` or `Truncate()` to the overlay first.
   337  
   338  To writing files to the overlay only, you can use the overlay Fs directly (not
   339  via the union Fs).
   340  
   341  Cache files in the layer for the given time.Duration, a cache duration of 0
   342  means "forever" meaning the file will not be re-requested from the base ever.
   343  
   344  A read-only base will make the overlay also read-only but still copy files
   345  from the base to the overlay when they're not present (or outdated) in the
   346  caching layer.
   347  
   348  ```go
   349  base := afero.NewOsFs()
   350  layer := afero.NewMemMapFs()
   351  ufs := afero.NewCacheOnReadFs(base, layer, 100 * time.Second)
   352  ```
   353  
   354  ### CopyOnWriteFs()
   355  
   356  The CopyOnWriteFs is a read only base file system with a potentially
   357  writeable layer on top.
   358  
   359  Read operations will first look in the overlay and if not found there, will
   360  serve the file from the base.
   361  
   362  Changes to the file system will only be made in the overlay.
   363  
   364  Any attempt to modify a file found only in the base will copy the file to the
   365  overlay layer before modification (including opening a file with a writable
   366  handle).
   367  
   368  Removing and Renaming files present only in the base layer is not currently
   369  permitted. If a file is present in the base layer and the overlay, only the
   370  overlay will be removed/renamed.
   371  
   372  ```go
   373  	base := afero.NewOsFs()
   374  	roBase := afero.NewReadOnlyFs(base)
   375  	ufs := afero.NewCopyOnWriteFs(roBase, afero.NewMemMapFs())
   376  
   377  	fh, _ = ufs.Create("/home/test/file2.txt")
   378  	fh.WriteString("This is a test")
   379  	fh.Close()
   380  ```
   381  
   382  In this example all write operations will only occur in memory (MemMapFs)
   383  leaving the base filesystem (OsFs) untouched.
   384  
   385  ## Desired/possible backends
   386  
   387  The following is a short list of possible backends we hope someone will
   388  implement:
   389  
   390  - SSH
   391  - ZIP
   392  - TAR
   393  - S3
   394  
   395  # About the project
   396  
   397  ## What's in the name
   398  
   399  Afero comes from the latin roots Ad-Facere.
   400  
   401  **"Ad"** is a prefix meaning "to".
   402  
   403  **"Facere"** is a form of the root "faciō" making "make or do".
   404  
   405  The literal meaning of afero is "to make" or "to do" which seems very fitting
   406  for a library that allows one to make files and directories and do things with them.
   407  
   408  The English word that shares the same roots as Afero is "affair". Affair shares
   409  the same concept but as a noun it means "something that is made or done" or "an
   410  object of a particular type".
   411  
   412  It's also nice that unlike some of my other libraries (hugo, cobra, viper) it
   413  Googles very well.
   414  
   415  ## Release Notes
   416  
   417  - **0.10.0** 2015.12.10
   418    - Full compatibility with Windows
   419    - Introduction of afero utilities
   420    - Test suite rewritten to work cross platform
   421    - Normalize paths for MemMapFs
   422    - Adding Sync to the file interface
   423    - **Breaking Change** Walk and ReadDir have changed parameter order
   424    - Moving types used by MemMapFs to a subpackage
   425    - General bugfixes and improvements
   426  - **0.9.0** 2015.11.05
   427    - New Walk function similar to filepath.Walk
   428    - MemMapFs.OpenFile handles O_CREATE, O_APPEND, O_TRUNC
   429    - MemMapFs.Remove now really deletes the file
   430    - InMemoryFile.Readdir and Readdirnames work correctly
   431    - InMemoryFile functions lock it for concurrent access
   432    - Test suite improvements
   433  - **0.8.0** 2014.10.28
   434    - First public version
   435    - Interfaces feel ready for people to build using
   436    - Interfaces satisfy all known uses
   437    - MemMapFs passes the majority of the OS test suite
   438    - OsFs passes the majority of the OS test suite
   439  
   440  ## Contributing
   441  
   442  1. Fork it
   443  2. Create your feature branch (`git checkout -b my-new-feature`)
   444  3. Commit your changes (`git commit -am 'Add some feature'`)
   445  4. Push to the branch (`git push origin my-new-feature`)
   446  5. Create new Pull Request
   447  
   448  ## Contributors
   449  
   450  Names in no particular order:
   451  
   452  - [spf13](https://github.com/spf13)
   453  - [jaqx0r](https://github.com/jaqx0r)
   454  - [mbertschler](https://github.com/mbertschler)
   455  - [xor-gate](https://github.com/xor-gate)
   456  
   457  ## License
   458  
   459  Afero is released under the Apache 2.0 license. See
   460  [LICENSE.txt](https://github.com/hbbio/afero/blob/master/LICENSE.txt)