go-fsx — golang filesystems interfaces, extended
Golang introduced the io/fs.FS
interface in Go 1.16.
While having this interface was a very welcome improvement to the golang library ecosystem, it doesn’t 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) is 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 (WIP)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.- 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.
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.
Example Usage
Hello World
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.)
Importing as ‘fs’
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.
Future Work
chmod
,chown
, and other similar operations are not yet present. (PRs welcome!)- Your ideas here?
Related Work
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.
License
You can have it as Apache-2.0 OR MIT OR BSD-3-Clause, or really anything you want.