Parse zk config

pull/6/head
Mickaël Menu 4 years ago
parent 9f4d2ac81b
commit c4a5648238
No known key found for this signature in database
GPG Key ID: 53D73664CD359895

@ -1,11 +1,17 @@
package cmd
import "github.com/mickael-menu/zk/core/zk"
import (
"fmt"
"github.com/mickael-menu/zk/core/zk"
)
type New struct {
Directory string `arg optional name:"directory" default:"."`
}
func (cmd *New) Run() error {
return zk.Open(cmd.Directory)
zk, err := zk.Open(cmd.Directory)
fmt.Printf("%+v\n", zk)
return err
}

@ -0,0 +1,49 @@
package zk
import (
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/hcl/v2/hclsimple"
"github.com/mickael-menu/zk/util/errors"
)
// Config holds the user configuration of a slip box.
type Config struct {
root rootConfig
}
func (c1 Config) Equal(c2 Config) bool {
return cmp.Equal(c1.root, c2.root)
}
type rootConfig struct {
Editor string `hcl:"editor,optional"`
Extension string `hcl:"extension,optional"`
Filename string `hcl:"filename,optional"`
Template string `hcl:"template,optional"`
RandomID *randomIDConfig `hcl:"random_id,block"`
Dirs []dirConfig `hcl:"dir,block"`
Ext map[string]string `hcl:"ext,optional"`
}
type randomIDConfig struct {
Charset string `hcl:"charset,optional"`
Length int `hcl:"length,optional"`
Case string `hcl:"case,optional"`
}
type dirConfig struct {
Dir string `hcl:"dir,label"`
Filename string `hcl:"filename,optional"`
Template string `hcl:"template,optional"`
Ext map[string]string `hcl:"ext,optional"`
}
// parseConfig creates a new Config instance from its HCL representation.
func parseConfig(content []byte) (*Config, error) {
var root rootConfig
err := hclsimple.Decode(".zk/config.hcl", content, nil, &root)
if err != nil {
return nil, errors.Wrap(err, "failed to read config")
}
return &Config{root}, nil
}

@ -0,0 +1,75 @@
package zk
import (
"testing"
"github.com/mickael-menu/zk/util/assert"
)
// Parse a minimal configuration file.
func TestParseMinimal(t *testing.T) {
config, err := parseConfig([]byte(""))
assert.Nil(t, err)
assert.Equal(t, config, &Config{rootConfig{}})
}
// Parse a complete configuration file.
func TestParseComplete(t *testing.T) {
config, err := parseConfig([]byte(`
// Comment
editor = "vim"
extension = "note"
filename = "{{random-id}}.note"
template = "default.note"
random_id {
charset = "alphanum"
length = 4
case = "lower"
}
ext = {
hello = "world"
salut = "le monde"
}
dir "log" {
filename = "{{date}}.md"
template = "log.md"
ext = {
log-ext = "value"
}
}
`))
assert.Nil(t, err)
assert.Equal(t, config, &Config{rootConfig{
Editor: "vim",
Extension: "note",
Filename: "{{random-id}}.note",
Template: "default.note",
RandomID: &randomIDConfig{
Charset: "alphanum",
Length: 4,
Case: "lower",
},
Dirs: []dirConfig{
dirConfig{
Dir: "log",
Filename: "{{date}}.md",
Template: "log.md",
Ext: map[string]string{"log-ext": "value"},
},
},
Ext: map[string]string{
"hello": "world",
"salut": "le monde",
},
}})
}
// Parsing failure
func TestParseInvalidConfig(t *testing.T) {
config, err := parseConfig([]byte("unknown = 'value'"))
assert.NotNil(t, err)
assert.Nil(t, config)
}

@ -2,27 +2,47 @@ package zk
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/mickael-menu/zk/util/errors"
)
const defaultConfig = `
# Test
test = thing
const defaultConfig = `editor = "nvim"
dir "log" {
template = "log.md"
}
`
type Zk struct {
Config Config
}
// Open locates a slip box at the given path and parses its configuration.
func Open(path string) error {
func Open(path string) (*Zk, error) {
wrap := errors.Wrapper("open failed")
path, err := filepath.Abs(path)
if err != nil {
return wrap(err)
return nil, wrap(err)
}
_, err = locateRoot(path)
return wrap(err)
path, err = locateRoot(path)
if err != nil {
return nil, wrap(err)
}
configContent, err := ioutil.ReadFile(filepath.Join(path, ".zk/config.hcl"))
if err != nil {
return nil, wrap(err)
}
config, err := parseConfig(configContent)
if err != nil {
return nil, wrap(err)
}
return &Zk{*config}, nil
}
// Create initializes a new slip box at the given path.
@ -45,7 +65,7 @@ func Create(path string) error {
}
// Write default config.toml.
f, err := os.Create(filepath.Join(path, ".zk/config.toml"))
f, err := os.Create(filepath.Join(path, ".zk/config.hcl"))
if err != nil {
return wrap(err)
}

@ -2,4 +2,8 @@ module github.com/mickael-menu/zk
go 1.15
require github.com/alecthomas/kong v0.2.12
require (
github.com/alecthomas/kong v0.2.12
github.com/google/go-cmp v0.3.1
github.com/hashicorp/hcl/v2 v2.8.1
)

@ -1,7 +1,46 @@
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/alecthomas/kong v0.2.12 h1:X3kkCOXGUNzLmiu+nQtoxWqj4U2a39MpSJR3QdQXOwI=
github.com/alecthomas/kong v0.2.12/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0=
github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk=
github.com/apparentlymart/go-textseg/v12 v12.0.0 h1:bNEQyAGak9tojivJNkoqWErVCQbjdL7GzRt3F8NvfJ0=
github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl/v2 v2.8.1 h1:FJ60CIYaMyJOKzPndhMyjiz353Fd+2jr6PodF5Xzb08=
github.com/hashicorp/hcl/v2 v2.8.1/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/zclconf/go-cty v1.2.0 h1:sPHsy7ADcIZQP3vILvTjrh74ZA175TFP5vqiNK1UmlI=
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

@ -0,0 +1,31 @@
package assert
import (
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
)
func Nil(t *testing.T, value interface{}) {
if !isNil(value) {
t.Errorf("Expected %v (type %v) to be nil", value, reflect.TypeOf(value))
}
}
func NotNil(t *testing.T, value interface{}) {
if isNil(value) {
t.Errorf("Expected %v (type %v) to not be nil", value, reflect.TypeOf(value))
}
}
func isNil(value interface{}) bool {
return value == nil ||
(reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil())
}
func Equal(t *testing.T, value interface{}, expected interface{}) {
if !cmp.Equal(value, expected) {
t.Errorf("Received %+v (type %v), expected %+v (type %v)", value, reflect.TypeOf(value), expected, reflect.TypeOf(expected))
}
}
Loading…
Cancel
Save