Rebrand overlay

Signed-off-by: jolheiser <john.olheiser@gmail.com>
pull/3/head v0.0.1
jolheiser 2021-02-17 22:39:52 -06:00
parent 57470b0615
commit 5f001da59e
Signed by: jolheiser
GPG Key ID: B853ADA5DA7BBF7A
6 changed files with 95 additions and 95 deletions

View File

@ -1,7 +1,7 @@
# XTFS
eXTended File System
# Overlay
Overlay File System
XTFS is an easy way to implement a file system in such a way that
Overlay is an easy way to implement a file system in such a way that
production assets can be overridden by assets on disk.
## Usage
@ -12,14 +12,14 @@ package main
import (
"embed"
"go.jolheiser.com/xtfs"
"go.jolheiser.com/overlay"
)
//go:embed assets
var assets embed.FS
func main() {
xfs, err := xtfs.New("/var/lib/myapp/custom", assets)
ofs, err := overlay.New("/var/lib/myapp/custom", assets)
if err != nil {
panic(err)
}
@ -38,14 +38,14 @@ package main
import (
"embed"
"go.jolheiser.com/xtfs"
"go.jolheiser.com/overlay"
)
//go:embed assets
var assets embed.FS
func main() {
xfs, err := xtfs.New("/var/lib/myapp/custom", assets, xtfs.WithSub("assets"))
ofs, err := overlay.New("/var/lib/myapp/custom", assets, overlay.WithSub("assets"))
if err != nil {
panic(err)
}

View File

@ -1,9 +1,9 @@
go test -benchmem -bench=.
goos: linux
goarch: amd64
pkg: go.jolheiser.com/xtfs
pkg: go.jolheiser.com/overlay
cpu: Intel(R) Core(TM) i7-4700MQ CPU @ 2.40GHz
BenchmarkCache-8 133917188 8.970 ns/op 0 B/op 0 allocs/op
BenchmarkNoCache-8 931821 1362 ns/op 280 B/op 4 allocs/op
BenchmarkCache-8 134959974 9.003 ns/op 0 B/op 0 allocs/op
BenchmarkNoCache-8 897212 1369 ns/op 280 B/op 4 allocs/op
PASS
ok go.jolheiser.com/xtfs 3.394s
ok go.jolheiser.com/overlay 3.360s

2
go.mod
View File

@ -1,3 +1,3 @@
module go.jolheiser.com/xtfs
module go.jolheiser.com/overlay
go 1.16

79
overlay.go 100644
View File

@ -0,0 +1,79 @@
package overlay
import (
"io/fs"
"os"
"path"
)
// FS is an overlay File System
type FS struct {
fs fs.FS
root string
doCache bool
cache map[string]bool
}
func (f *FS) apn(name string) string {
return path.Join(f.root, name)
}
func (f *FS) exists(name string) bool {
if has, ok := f.cache[name]; ok && f.doCache {
return has
}
_, err := os.Stat(f.apn(name))
if err != nil {
f.cache[name] = false
return false
}
f.cache[name] = true
return true
}
// Open opens an fs.File, preferring disk
func (f *FS) Open(name string) (fs.File, error) {
if f.exists(name) {
return os.Open(f.apn(name))
}
return f.fs.Open(name)
}
// Option is a functional option for an FS
type Option func(*FS) error
// New returns a new FS
func New(root string, fs fs.FS, opts ...Option) (*FS, error) {
x := &FS{
fs: fs,
root: root,
doCache: true,
cache: make(map[string]bool),
}
for _, opt := range opts {
if err := opt(x); err != nil {
return x, err
}
}
return x, nil
}
// WithSub sets a fs.Sub for an FS
func WithSub(sub string) Option {
return func(x *FS) (err error) {
x.fs, err = fs.Sub(x.fs, sub)
return
}
}
// WithCaching sets a caching mode for an FS
// Caching avoids subsequent os.Stat to determine if a file exists on disk
// See bench.txt for differences in usage
func WithCaching(doCache bool) Option {
return func(x *FS) error {
x.doCache = doCache
return nil
}
}

View File

@ -1,4 +1,4 @@
package xtfs
package overlay
import (
"embed"
@ -15,7 +15,7 @@ func TestMain(m *testing.M) {
os.Exit(m.Run())
}
func TestXTFS(t *testing.T) {
func TestOverlay(t *testing.T) {
tt := []struct {
Name string
File string
@ -55,7 +55,7 @@ func TestXTFS(t *testing.T) {
}
if !strings.EqualFold(string(contents), tc.Expected) {
t.Logf("xtfs did not match:\n\tgot: %s\n\texpected: %s\n", string(contents), tc.Expected)
t.Logf("fs did not match:\n\tgot: %s\n\texpected: %s\n", string(contents), tc.Expected)
t.FailNow()
}
})
@ -67,7 +67,7 @@ var emptyFS embed.FS
func TestInvalid(t *testing.T) {
_, err := New("/var/lib/myapp/assets/custom", emptyFS)
if err != nil {
t.Log("invalid XTFS should not error explicitly")
t.Log("invalid FS should not error explicitly")
t.FailNow()
}
}

79
xtfs.go
View File

@ -1,79 +0,0 @@
package xtfs
import (
"io/fs"
"os"
"path"
)
// XTFS is an eXTended File System
type XTFS struct {
fs fs.FS
root string
doCache bool
cache map[string]bool
}
func (x *XTFS) apn(name string) string {
return path.Join(x.root, name)
}
func (x *XTFS) exists(name string) bool {
if has, ok := x.cache[name]; ok && x.doCache {
return has
}
_, err := os.Stat(x.apn(name))
if err != nil {
x.cache[name] = false
return false
}
x.cache[name] = true
return true
}
// Open opens an fs.File, preferring disk
func (x *XTFS) Open(name string) (fs.File, error) {
if x.exists(name) {
return os.Open(x.apn(name))
}
return x.fs.Open(name)
}
// Option is a functional option for an XTFS
type Option func(*XTFS) error
// New returns a new XTFS
func New(root string, fs fs.FS, opts ...Option) (*XTFS, error) {
x := &XTFS{
fs: fs,
root: root,
doCache: true,
cache: make(map[string]bool),
}
for _, opt := range opts {
if err := opt(x); err != nil {
return x, err
}
}
return x, nil
}
// WithSub sets a fs.Sub for an XTFS
func WithSub(sub string) Option {
return func(x *XTFS) (err error) {
x.fs, err = fs.Sub(x.fs, sub)
return
}
}
// WithCaching sets a caching mode for an XTFS
// Caching avoids subsequent os.Stat to determine if a file exists on disk
// See bench.txt for differences in usage
func WithCaching(doCache bool) Option {
return func(x *XTFS) error {
x.doCache = doCache
return nil
}
}