Golang introduced the io/fs.FS
interface in Go 1.16.
go-fsx
extends it with support for writing to the filesystem, handling symlinks, and also brings some conveniences.
While having the standard library's fs.FS
interface was a very welcome improvement to the golang library ecosystem,
it doesn't (yet) go far enough:
the interface only covers read operations (no write support at all!),
and many features in common filesystems (such as understanding of symlinks) are absent.
This package, fsx
, takes the style of the io/fs
package, and extends it with more features:
fsx
provides the ability to write files (usingOpenFile
, which is much like theos
package feature you're already familiar with)fsx
provides the ability to create directoriesfsx
provides the ability to delete files and directoriesfsx
provides features for reading symlinks, and creating them
Everything is done with the intention of feeling normal, and being a smooth extension of what we already know:
fsx
does everything it does in the functional idiom already used inio/fs
, so it feels "natural" --fsx
has just got more of it.fsx
still usesfs.FileInfo
,fs.FileMode
, andfs.File
-- no changes there. Everything is aliases -- easy to combine with other code.- All of the
fsx
functions take anfs.FS
, and do feature detection internally -- so you can keep usingfs.FS
in code that's already passing that interface around! - As with
io/fs
, we attempt to add new convenient behaviors as package-scope functions... so that thefsx.FS
interface doesn't grow over time, and bumping library versions forward is easy, even if you created your own unique implementations of the interface.
Ease of use is a paramount consideration.
Additionally, we alias other fs
package features, and relevant os
constants, into this package --
so that you can have just one thing on your import path when working with filesystems.
Less to think about is better.
import (
"github.com/warpfork/go-fsx"
"github.com/warpfork/go-fsx/osfs"
)
func ExampleHello() {
fsys := osfs.DirFS("/tmp/")
fsx.Mkdir(fsys, "hello", 0777)
fsx.WriteFile(fsys, "hello/world.txt", 0666, []byte(`hello world!`))
body, err := fsx.ReadFile(fsys, "hello/world.txt")
}
Note that the function for creating an FS is in the osfs
subpackage.
Other implementations of the FS interface can be in other packages!
The fsx
package is only interfaces.
(This is similar to how os.DirFS
is used to get an io/fs.FS
, in the standard library.)
You may also choose to import fsx as just "fs", if you so choose:
import (
fs "github.com/warpfork/go-fsx"
)
This is a reasonably safe choice since we alias everything from the io/fs
package,
so it should never be necessary to import both at the same time.
chmod
,chown
, and other similar operations are not yet present. (PRs welcome!)- Your ideas here?
Writable FS interfaces have been discussed before! In particular, golang/go#45757 contains a very rich discussion.
If anyone is interested in taking this code further upstream, either as reference material, or verbatim copied, please, be my guest.
No. :)
This package doesn't attempt to do anything regarding controlling concurrent access to the filesystem. (Generally, any abstraction there would be leaky; and a leaky abstraction would be worse than none at all.)
This package doesn't provide any interfaces around FDs (file descriptors); it's just path names.
(Working with FDs is very powerful, but considerably different than where Golang's fs
package is oriented, and this package stays similar to its upstream.)
This package does not attempt to standardize or normalize error codes in any way.
Errors returned by this package are generally of type *fs.PathError
-- the same as the upstream fs
package.
Subpackages that provide real implementations, such as osfs
(which uses stdlib fs
and os
) generally return errors from the underlying code unmodified.
You can have it as Apache-2.0 OR MIT OR BSD-3-Clause, or really anything you want.
I'm finding it difficult to express this in a way that license checking machines tolerate (no one seems to implement "OR" as a concept; it's all just magic strings of which that's an indistinguishable substring, apparently), so for the purposes of machines, let's just say:
SPDX-License-Identifier: Apache-2.0 OR MIT