feat: refactor for library and add test

Signed-off-by: jolheiser <john.olheiser@gmail.com>
main
jolheiser 2024-06-05 20:11:19 -05:00
parent b939bb8cfe
commit b4097abed2
Signed by: jolheiser
GPG Key ID: B853ADA5DA7BBF7A
5 changed files with 180 additions and 41 deletions

94
cfg.go 100644
View File

@ -0,0 +1,94 @@
package cfg
import (
"encoding/json"
"fmt"
"strings"
"github.com/pelletier/go-toml/v2"
"github.com/philandstuff/dhall-golang/v6"
"github.com/tailscale/hujson"
"go.jolheiser.com/nixfig"
"gopkg.in/yaml.v3"
)
// Encoding is a type of configuration encoding
type Encoding string
const (
JSON Encoding = "json"
JSONC Encoding = "jsonc"
YAML Encoding = "yaml"
TOML Encoding = "toml"
NIX Encoding = "nix"
DHALL Encoding = "dhall"
)
// Marshal takes data and encodes for an [Encoding]
func (e Encoding) Marshal(v any) ([]byte, error) {
return Marshal(e, v)
}
// Unmarshal decodes data for an [Encoding]
func (e Encoding) Unmarshal(data []byte, v any) error {
return Unmarshal(e, data, v)
}
// ParseEncoding parses a string into an [Encoding]
func ParseEncoding(s string) (Encoding, error) {
switch strings.ToLower(s) {
case "json":
return JSON, nil
case "jsonc":
return JSONC, nil
case "yaml":
return YAML, nil
case "toml":
return TOML, nil
case "nix":
return NIX, nil
case "dhall":
return DHALL, nil
default:
return "", fmt.Errorf("unknown encoding %q", s)
}
}
// Marshal is a top-level helper for encoding data
func Marshal(e Encoding, v any) ([]byte, error) {
switch e {
case JSON, JSONC:
return json.MarshalIndent(v, "", "\t")
case YAML:
return yaml.Marshal(v)
case TOML:
return toml.Marshal(v)
case NIX:
return nixfig.Marshal(v)
default:
return nil, fmt.Errorf("unknown marshal format %q", e)
}
}
// Unmarshal is a top-level helper for decoding data
func Unmarshal(e Encoding, data []byte, v any) error {
switch e {
case JSON, JSONC:
b, err := hujson.Standardize(data)
if err != nil {
return err
}
return json.Unmarshal(b, v)
case YAML:
return yaml.Unmarshal(data, v)
case TOML:
return toml.Unmarshal(data, v)
case NIX:
return nixfig.Unmarshal(data, v)
case DHALL:
return dhall.Unmarshal(data, v)
default:
return fmt.Errorf("unknown unmarshal format %q", e)
}
}

67
cfg_test.go 100644
View File

@ -0,0 +1,67 @@
package cfg
import (
"testing"
"github.com/matryer/is"
"go.jolheiser.com/nixfig"
)
type TestData struct {
Foo string
Baz bool
Bux int
Qux TestSubData
}
type TestSubData struct {
Honk string
Chonk int
Gonk bool
}
func TestEncoding(t *testing.T) {
assert := is.New(t)
// Starting with dhall since it can't be encoded
dhall := `
{
Foo = "bar"
, Baz = True
, Bux = 10
, Qux = {
Honk = "bonk"
, Chonk = 50
, Gonk = False
}
}
`
final := TestData{
Foo: "bar",
Baz: true,
Bux: 10,
Qux: TestSubData{
Honk: "bonk",
Chonk: 50,
Gonk: false,
},
}
encoders := []Encoding{JSON, JSONC, YAML, TOML}
// Only test nix if it's available
if nixfig.Nix != "" {
encoders = append(encoders, NIX)
}
var data TestData
err := DHALL.Unmarshal([]byte(dhall), &data)
assert.NoErr(err) // Should be able to unmarshal dhall
for _, e := range encoders {
out, err := e.Marshal(data)
assert.NoErr(err) // Should be able to marshal
err = e.Unmarshal(out, &data)
assert.NoErr(err) // Should be able to unmarshal
}
assert.Equal(data, final) // Final structs should be equal
}

View File

@ -1,7 +1,6 @@
package main
import (
"encoding/json"
"errors"
"flag"
"fmt"
@ -9,11 +8,7 @@ import (
"path/filepath"
"strings"
"github.com/pelletier/go-toml/v2"
"github.com/philandstuff/dhall-golang/v6"
"github.com/tailscale/hujson"
"go.jolheiser.com/nixfig"
"gopkg.in/yaml.v3"
"go.jolheiser.com/cfg"
)
func maine() error {
@ -22,45 +17,21 @@ func maine() error {
fs := flag.NewFlagSet("cfg", flag.ExitOnError)
fromFunc := func(s string) error {
switch strings.ToLower(s) {
case "json", "jsonc":
unmarshal = func(b []byte, a any) error {
b, err := hujson.Standardize(b)
if err != nil {
return err
}
return json.Unmarshal(b, a)
}
case "yaml":
unmarshal = yaml.Unmarshal
case "toml":
unmarshal = toml.Unmarshal
case "dhall":
unmarshal = dhall.Unmarshal
case "nix":
unmarshal = nixfig.Unmarshal
default:
return fmt.Errorf("unknown format %q", s)
e, err := cfg.ParseEncoding(s)
if err != nil {
return err
}
unmarshal = e.Unmarshal
return nil
}
fs.Func("from", "The format to convert from", fromFunc)
fs.Func("f", "--from", fromFunc)
toFunc := func(s string) error {
switch strings.ToLower(s) {
case "json", "jsonc":
marshal = func(a any) ([]byte, error) {
return json.MarshalIndent(a, "", "\t")
}
case "yaml":
marshal = yaml.Marshal
case "toml":
marshal = toml.Marshal
case "nix":
marshal = nixfig.Marshal
default:
return fmt.Errorf("unknown format %q", s)
e, err := cfg.ParseEncoding(s)
if err != nil {
return err
}
marshal = e.Marshal
return nil
}
fs.Func("to", "The format to convert to", toFunc)
@ -95,7 +66,7 @@ func maine() error {
}
}
} else if marshal == nil {
marshal = json.Marshal
marshal = cfg.JSON.Marshal
}
var data any

3
go.mod
View File

@ -3,6 +3,7 @@ module go.jolheiser.com/cfg
go 1.22.3
require (
github.com/matryer/is v1.4.1
github.com/pelletier/go-toml/v2 v2.2.2
github.com/philandstuff/dhall-golang/v6 v6.0.2
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a
@ -13,4 +14,6 @@ require (
require (
github.com/fxamacker/cbor/v2 v2.2.1-0.20200511212021-28e39be4a84f // indirect
github.com/x448/float16 v0.8.4 // indirect
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
golang.org/x/text v0.3.7 // indirect
)

8
go.sum
View File

@ -25,6 +25,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leanovate/gopter v0.2.5-0.20190402064358-634a59d12406 h1:+OUpk+IVvmKU0jivOVFGtOzA6U5AWFs8HE4DRzWLOUE=
github.com/leanovate/gopter v0.2.5-0.20190402064358-634a59d12406/go.mod h1:gNcbPWNEWRe4lm+bycKqxUYoH5uoVje5SkOJ3uoLer8=
github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@ -64,10 +66,12 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=