• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

mem/H17-Feb-2017-

sftpfs/H17-Feb-2017-

.travis.ymlH A D17-Feb-2017203

README.mdH A D17-Feb-201714.2 KiB

afero.goH A D17-Feb-20173.2 KiB

afero_test.goH A D17-Feb-201715.4 KiB

appveyor.ymlH A D17-Feb-2017287

basepath.goH A D17-Feb-20174.1 KiB

basepath_test.goH A D17-Feb-20173.3 KiB

cacheOnReadFs.goH A D17-Feb-20176.8 KiB

composite_test.goH A D17-Feb-20178.2 KiB

const_bsds.goH A D17-Feb-2017721

const_win_unix.goH A D17-Feb-2017766

copyOnWriteFs.goH A D17-Feb-20176 KiB

copyOnWriteFs_test.goH A D17-Feb-2017399

httpFs.goH A D17-Feb-20172.6 KiB

ioutil.goH A D17-Feb-20176.6 KiB

ioutil_test.goH A D17-Feb-20173 KiB

memmap.goH A D17-Feb-20177.3 KiB

memmap_test.goH A D17-Feb-20177.6 KiB

memradix.goH A D17-Feb-2017618

os.goH A D17-Feb-20172.4 KiB

path.goH A D17-Feb-20172.8 KiB

path_test.goH A D17-Feb-20171.6 KiB

readonlyfs.goH A D17-Feb-20171.4 KiB

regexpfs.goH A D17-Feb-20174.1 KiB

ro_regexp_test.goH A D17-Feb-20172.1 KiB

unionFile.goH A D17-Feb-20175.8 KiB

util.goH A D17-Feb-20177.2 KiB

util_test.goH A D17-Feb-201712.6 KiB

README.md

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