Skip to content

Commit

Permalink
Support fs.FS (#118)
Browse files Browse the repository at this point in the history
  • Loading branch information
cristaloleg committed May 15, 2022
1 parent b6d6be7 commit 65d3f2b
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 3 deletions.
17 changes: 16 additions & 1 deletion aconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package aconfig
import (
"flag"
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
Expand All @@ -24,6 +25,7 @@ type Loader struct {
config Config
dst interface{}
fields []*fieldData
fsys fs.FS
flagSet *flag.FlagSet
errInit error
}
Expand Down Expand Up @@ -69,6 +71,9 @@ type Config struct {
// FailOnFileNotFound will stop Loader on a first not found file from Files field in this structure.
FailOnFileNotFound bool

// FileSystem from which files will be loaded. Default is nil (OS file system).
FileSystem fs.FS

// MergeFiles set to true will collect all the entries from all the given files.
// Easy wat to cobine base.yaml with prod.yaml
MergeFiles bool
Expand Down Expand Up @@ -100,6 +105,7 @@ type Config struct {
type FileDecoder interface {
Format() string
DecodeFile(filename string) (map[string]interface{}, error)
// Init(fsys fs.FS)
}

// Field of the user configuration structure.
Expand Down Expand Up @@ -142,12 +148,21 @@ func (l *Loader) init() {
l.config.FlagPrefix += l.config.FlagDelimiter
}

l.fsys = &fsOrOS{l.config.FileSystem}

if _, ok := l.config.FileDecoders[".json"]; !ok {
if l.config.FileDecoders == nil {
l.config.FileDecoders = map[string]FileDecoder{}
}
l.config.FileDecoders[".json"] = &jsonDecoder{}
}
for _, dec := range l.config.FileDecoders {
dec, ok := dec.(interface{ Init(fs.FS) })
if !ok {
continue
}
dec.Init(l.fsys)
}

if l.config.Args == nil {
l.config.Args = os.Args[1:]
Expand Down Expand Up @@ -280,7 +295,7 @@ func (l *Loader) loadFiles() error {
}

for _, file := range l.config.Files {
if _, err := os.Stat(file); os.IsNotExist(err) {
if _, err := fs.Stat(l.fsys, file); os.IsNotExist(err) {
if l.config.FailOnFileNotFound {
return err
}
Expand Down
39 changes: 39 additions & 0 deletions aconfig_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package aconfig

import (
"embed"
"io/ioutil"
"net/url"
"os"
Expand Down Expand Up @@ -242,6 +243,44 @@ func TestFile(t *testing.T) {
}
}

//go:embed testdata
var configEmbed embed.FS

func TestFileEmbed(t *testing.T) {
filepath := "testdata/config.json"

var cfg TestConfig
loader := LoaderFor(&cfg, Config{
SkipDefaults: true,
SkipEnv: true,
SkipFlags: true,
Files: []string{filepath},
FileSystem: configEmbed,
})
if err := loader.Load(); err != nil {
t.Fatal(err)
}

want := TestConfig{
Str: "str-json",
Bytes: []byte("Ynl0ZXMtanNvbg=="),
Int: int32Ptr(101),
HTTPPort: 65000,
Sub: SubConfig{
Float: 999.111,
},
Anon: struct {
IsAnon bool `default:"true"`
}{
IsAnon: true,
},
}

if got := cfg; !reflect.DeepEqual(want, got) {
t.Fatalf("want %v, got %v", want, got)
}
}

func TestFileMerging(t *testing.T) {
file1 := "testdata/config1.json"
file2 := "testdata/config2.json"
Expand Down
22 changes: 20 additions & 2 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"flag"
"fmt"
"io/fs"
"os"
"reflect"
"strings"
Expand Down Expand Up @@ -138,7 +139,24 @@ func cut(s, sep string) (before, after string, found bool) {
return s, "", false
}

type jsonDecoder struct{}
var _ fs.FS = &fsOrOS{}

type fsOrOS struct{ fs.FS }

func (fs *fsOrOS) Open(name string) (fs.File, error) {
if fs.FS == nil {
return os.Open(name)
}
return fs.FS.Open(name)
}

type jsonDecoder struct {
fsys fs.FS
}

func (d *jsonDecoder) Init(fsys fs.FS) {
d.fsys = fsys
}

// Format of the decoder.
func (d *jsonDecoder) Format() string {
Expand All @@ -147,7 +165,7 @@ func (d *jsonDecoder) Format() string {

// DecodeFile implements FileDecoder.
func (d *jsonDecoder) DecodeFile(filename string) (map[string]interface{}, error) {
f, err := os.Open(filename)
f, err := d.fsys.Open(filename)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit 65d3f2b

Please sign in to comment.