-
-
Save kevinburke/07a21855df700b0acdea9e91c6fde7cf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package configparser | |
import ( | |
"encoding/json" | |
"io/ioutil" | |
"os" | |
"path/filepath" | |
"github.com/hashicorp/hcl" | |
"github.com/hashicorp/hcl/hcl/ast" | |
"github.com/hashicorp/hcl/hcl/token" | |
) | |
func NewMap(l *ast.ObjectList) *Map { | |
return &Map{ | |
ol: l, | |
} | |
} | |
type Map struct { | |
ol *ast.ObjectList | |
} | |
func NewMapValue(lt *ast.LiteralType) *MapValue { | |
return &MapValue{ | |
lt: lt, | |
} | |
} | |
type MapValue struct { | |
lt *ast.LiteralType | |
} | |
func (mv *MapValue) Text() string { | |
return mv.lt.Token.Text | |
} | |
func (m *Map) Keys() []string { | |
var keys []string | |
for _, item := range m.ol.Items { | |
if len(item.Keys) != 1 { | |
continue | |
} | |
if item.Keys[0].Token.Text == "" { | |
continue | |
} | |
keys = append(keys, item.Keys[0].Token.Text) | |
} | |
return keys | |
} | |
// Get a ast.Node from the map | |
func (m *Map) Get(key string) (ast.Node, bool) { | |
for _, item := range m.ol.Items { | |
if len(item.Keys) != 1 { | |
continue | |
} | |
if item.Keys[0].Token.Text == key { | |
return item.Val, true | |
} | |
} | |
return nil, false | |
} | |
// Get a ast.LiteralType from the map | |
func (m *Map) GetValue(key string) (*MapValue, bool) { | |
node, ok := m.Get(key) | |
if !ok { | |
return nil, ok | |
} | |
lt, ok := node.(*ast.LiteralType) | |
if !ok { | |
return nil, false | |
} | |
return NewMapValue(lt), true | |
} | |
func (m *Map) GetAll(key string) []ast.Node { | |
nodes := make([]ast.Node, 0) | |
for _, item := range m.ol.Items { | |
if len(item.Keys) != 1 { | |
continue | |
} | |
if item.Keys[0].Token.Text == key { | |
nodes = append(nodes, item.Val) | |
} | |
} | |
return nodes | |
} | |
func newval(val interface{}, line int) *ast.LiteralType { | |
// this should hopefully be a simple value like int, string. TODO actual | |
// switch(type) command | |
bits, err := json.Marshal(val) | |
if err != nil { | |
panic(err) | |
} | |
return &ast.LiteralType{ | |
Token: token.Token{ | |
Type: token.STRING, | |
Pos: token.Pos{ | |
Line: line, | |
}, | |
Text: string(bits), | |
}, | |
} | |
} | |
func (m *Map) Set(key string, val interface{}) { | |
set := false | |
for _, item := range m.ol.Items { | |
if len(item.Keys) != 1 { | |
continue | |
} | |
if item.Keys[0].Token.Text == key { | |
item.Val = newval(val, item.Assign.Line) | |
set = true | |
break | |
} | |
} | |
if !set { | |
lastItem := m.ol.Items[len(m.ol.Items)-1] | |
m.ol.Items = append(m.ol.Items, &ast.ObjectItem{ | |
Keys: []*ast.ObjectKey{ | |
{token.Token{ | |
Type: token.STRING, | |
Pos: token.Pos{ | |
Line: lastItem.Assign.Line + 1, | |
}, | |
Text: key, | |
}}, | |
}, | |
Assign: token.Pos{ | |
Line: lastItem.Assign.Line + 1, | |
}, | |
Val: newval(val, lastItem.Assign.Line+1), | |
}) | |
} | |
return | |
} | |
func ParseFile(filename string) (*ast.File, error) { | |
bits, err := ioutil.ReadFile(filename) | |
if err != nil { | |
return nil, err | |
} | |
return hcl.ParseBytes(bits) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package configparser | |
import ( | |
"testing" | |
"github.com/letsencrypt/boulder/test" | |
"github.com/hashicorp/hcl" | |
"github.com/hashicorp/hcl/hcl/ast" | |
) | |
var configfile = ` | |
handler { | |
# this is a route | |
route = "/v1/hello_world" | |
/* | |
* this si a multiline comment | |
* about this handler */ | |
function_name = "Functionname" | |
foo = 3 | |
bar = 7 | |
blah = 8 | |
} | |
handler { | |
# this is a route | |
route = "/v1/hello_world" | |
/* | |
* this si a multiline comment | |
* about this handler */ | |
function_name = "Functionname" | |
}` | |
func TestGet(t *testing.T) { | |
f, err := hcl.ParseBytes([]byte(configfile)) | |
if err != nil { | |
t.Fatal(err) | |
} | |
// "An HCL file is an object list" so this should work | |
m := NewMap(f.Node.(*ast.ObjectList)) | |
node, found := m.Get("handler") | |
test.AssertEquals(t, found, true) | |
_, found = m.Get("unknown_key") | |
test.AssertEquals(t, found, false) | |
innerm := NewMap(node.(*ast.ObjectType).List) | |
node, found = innerm.Get("function_name") | |
test.AssertEquals(t, found, true) | |
lt, ok := node.(*ast.LiteralType) | |
test.Assert(t, ok, "converting to literal type") | |
test.AssertEquals(t, lt.Token.Text, "\"Functionname\"") | |
} | |
func TestGetAll(t *testing.T) { | |
f, err := hcl.ParseBytes([]byte(configfile)) | |
if err != nil { | |
t.Fatal(err) | |
} | |
// "An HCL file is an object list" so this should work | |
m := NewMap(f.Node.(*ast.ObjectList)) | |
nodes := m.GetAll("handler") | |
test.AssertEquals(t, len(nodes), 2) | |
nodes = m.GetAll("unknown_key") | |
test.AssertEquals(t, len(nodes), 0) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment