Take a filesystem, not a path.
fsutil provides file operations written against
afero.Fs rather than against the real
filesystem, so the code that calls them can be tested without touching a disk.
Status: early. Only copying is here so far. The rest arrives as each
operation earns its place.
Introduction
A function that calls os.Create has decided, permanently, that it writes to the
real filesystem. Testing it means a temporary directory, cleanup, and the quiet
possibility of one test seeing another's leftovers. A function that takes an
afero.Fs has decided nothing: production passes afero.NewOsFs(), a test passes
afero.NewMemMapFs(), and the same code runs against both.
That is the convention this module exists to make cheap. afero supplies the
filesystem abstraction and the operations the standard library has; fsutil adds
the ones it does not, in the same shape — filesystem first, paths after.
// Reaches for the disk, whatever the caller wanted.
func writeReport(path string) error
// Writes wherever it is told to.
func writeReport(fs afero.Fs, path string) error
Usage
go get github.com/MarkRosemaker/fsutil
import (
"github.com/MarkRosemaker/fsutil"
"github.com/spf13/afero"
)
// Copies within one filesystem, creating the destination directory as needed.
if err := fsutil.Copy(afero.NewOsFs(), "api/openapi.json", "build/openapi.json"); err != nil {
log.Fatal(err)
}
The copy creates any missing parent directories, preserves the source file's
permissions on a best-effort basis, and syncs before returning.
In a test, the same call runs entirely in memory:
fs := afero.NewMemMapFs()
afero.WriteFile(fs, "src.txt", []byte("hello"), 0o644)
if err := fsutil.Copy(fs, "src.txt", "nested/dst.txt"); err != nil {
t.Fatal(err)
}
When the filesystem is not in question
Command-line tools and code generators operate on the real filesystem by
definition, and threading afero.NewOsFs() through them buys nothing. The
osutil subpackage is the same operations with that argument already applied:
import "github.com/MarkRosemaker/fsutil/osutil"
if err := osutil.Copy("api/openapi.json", "build/openapi.json"); err != nil {
log.Fatal(err)
}
| Package |
Signature |
Use when |
fsutil |
Copy(fs afero.Fs, src, dst string) error |
The caller should be able to choose the filesystem — which is most of the time |
fsutil/osutil |
Copy(src, dst string) error |
The real filesystem is the whole point, as in a CLI or a generator |
Used by
The openapi family reaches for
osutil in the generators that build their test fixtures:
openapi-flatten,
openapi-compress and
openapi-codegen.
Contributing
If you have any contributions to make, please submit a pull request or open an issue on the GitHub repository.
License
This project is licensed under the Apache 2.0 License.