From ac5a7dbbfd25adf59962357d8ed5861a86af1656 Mon Sep 17 00:00:00 2001 From: xdrm-brackets Date: Mon, 12 Nov 2018 17:43:01 +0100 Subject: [PATCH] remove cnf/confl parser | add cnf/nginx conf parser using cnf/parser/nginx | implement cnf/nginx.Get() --- internal/cnf/confl.go | 136 --------------------- internal/cnf/confl_test.go | 190 ----------------------------- internal/cnf/loader.go | 2 +- internal/cnf/nginx.go | 102 ++++++++++++++++ internal/cnf/parser/nginx/line.go | 22 ---- internal/cnf/parser/nginx/nginx.go | 22 ---- 6 files changed, 103 insertions(+), 371 deletions(-) delete mode 100644 internal/cnf/confl.go delete mode 100644 internal/cnf/confl_test.go create mode 100644 internal/cnf/nginx.go diff --git a/internal/cnf/confl.go b/internal/cnf/confl.go deleted file mode 100644 index 3ebd515..0000000 --- a/internal/cnf/confl.go +++ /dev/null @@ -1,136 +0,0 @@ -package cnf - -import ( - lib "github.com/lytics/confl" - "io" - "strings" -) - -type confl struct { - data interface{} - parsed bool -} - -// ReadFrom implements io.ReaderFrom -func (d *confl) ReadFrom(_reader io.Reader) (int64, error) { - - // 1. get confl decoder - decoder := lib.NewDecoder(_reader) - err := decoder.Decode(&d.data) - if err != nil { - return 0, err - } - - d.parsed = true - return 0, nil - -} - -// WriteTo implements io.WriterTo -func (d *confl) WriteTo(_writer io.Writer) (int64, error) { - encoder := lib.NewEncoder(_writer) - return 0, encoder.Encode(&d.data) -} - -// browse returns the target of a dot-separated path (as an interface{} chain where the last is the target if found) -func (d *confl) browse(_path string) ([]interface{}, bool) { - - // 1. extract path - path := strings.Split(_path, ".") - - // 2. init output chain - current := d.data - chain := make([]interface{}, 0, len(path)+1) - chain = append(chain, current) - - // 3. iterate over path / nested fields - for _, field := range path { - fmap, ok := current.(map[string]interface{}) - if !ok { // incomplete path - return chain, false - } - - child, ok := fmap[field] - if !ok { // incomplete path - return chain, false - } - - current = child - chain = append(chain, current) - } - - return chain, true -} - -// Get returns the value of a dot-separated path, and if it exists -func (d *confl) Get(_path string) (string, bool) { - - // 1. browse path - chain, found := d.browse(_path) - if !found { - return "", false - } - - // 2. return if string value - value, ok := chain[len(chain)-1].(string) - return value, ok - -} - -// Set the value of a dot-separated path, and creates it if not found -func (d *confl) Set(_path, _value string) bool { - - // 1. browse path + create it if does not exist - path := strings.Split(_path, ".") - lp := len(path) - chain, found := d.browse(_path) - - // 2. if found -> set value - if found { - mapWrapper, ok := chain[len(chain)-2].(map[string]interface{}) - if !ok { // impossible - return false - } - key := path[lp-1] - mapWrapper[key] = _value - return true - } - - // 3. create path until the end to set value - root := make(map[string]interface{}) - current := root - - // create children until second to last - for i, l := len(chain)-1, lp-1; i < l; i++ { - child := make(map[string]interface{}) - current[path[i]] = child - current = child - } - - // set value - current[path[lp-1]] = _value - - // replace whole object if empty - if len(chain) < 2 { - wrapper, ok := d.data.(map[string]interface{}) - if !ok { // impossible - return false - } - key := path[0] - wrapper[key] = root[key] // store with key ; eitherway it will erase all brother keys - return true - } - - // update last found object to add the value - wrapper, ok := chain[len(chain)-1].(map[string]interface{}) - if !ok { // impossible - return false - } - - // add each subkey - for subkey, subvalue := range root { - wrapper[subkey] = subvalue - } - return true - -} diff --git a/internal/cnf/confl_test.go b/internal/cnf/confl_test.go deleted file mode 100644 index 6c45796..0000000 --- a/internal/cnf/confl_test.go +++ /dev/null @@ -1,190 +0,0 @@ -package cnf - -import ( - "bytes" - "testing" -) - -func TestConflGet(t *testing.T) { - - tests := []struct { - raw string - key string - }{ - {"key: value", "key"}, - {"ignore xxx\nkey value", "key"}, - {"parent {\n\tchild value\n}", "parent.child"}, - {"ignore xxx\nparent {\n\tchild value\n}", "parent.child"}, - } - - for _, test := range tests { - - parser := new(confl) - reader := bytes.NewBufferString(test.raw) - - // try to extract value - _, err := parser.ReadFrom(reader) - if err != nil { - t.Errorf("parse error: %s", err) - continue - } - - // extract value - value, found := parser.Get(test.key) - if !found { - t.Errorf("expected a result, got none") - continue - } - - // check value - if value != "value" { - t.Errorf("expected 'value' got '%s'", value) - } - - } - -} - -func TestConflGetNotString(t *testing.T) { - - tests := []struct { - raw string - key string - }{ - {"key [\"value\"]", "key"}, - {"parent {\n\tchild [ \"value\" ]\n}", "parent.child"}, - } - - for _, test := range tests { - - parser := new(confl) - reader := bytes.NewBufferString(test.raw) - - // try to extract value - _, err := parser.ReadFrom(reader) - if err != nil { - t.Errorf("parse error: %s", err) - continue - } - - // extract value - value, found := parser.Get(test.key) - if found || len(value) > 0 { - t.Errorf("expected no result, got '%s'", value) - continue - } - - } - -} - -func TestConflSetPathExistsAndIsString(t *testing.T) { - - tests := []struct { - raw string - key string - value string - }{ - {"key value", "key", "newvalue"}, - {"ignore xxx\nkey value\n", "key", "newvalue"}, - {"parent {\n\tchild value\n}", "parent.child", "newvalue"}, - {"ignore xxx\nparent {\n\tchild value\n}", "parent.child", "newvalue"}, - } - - for _, test := range tests { - - parser := new(confl) - reader := bytes.NewBufferString(test.raw) - - // try to extract value - _, err := parser.ReadFrom(reader) - if err != nil { - t.Errorf("parse error: %s", err) - continue - } - - // update value - if !parser.Set(test.key, test.value) { - t.Errorf("cannot set '%s' to '%s'", test.key, test.value) - continue - } - - // check new value - value, found := parser.Get(test.key) - if !found { - t.Errorf("expected a result, got none") - continue - } - - // check value - if value != test.value { - t.Errorf("expected '%s' got '%s'", test.value, value) - } - - } - -} - -func TestConflSetCreatePath(t *testing.T) { - - tests := []struct { - raw string - key string - ignore string // path to field that must be present after transformation - value string - }{ - {"ignore xxx", "key", "ignore", "newvalue"}, - {"ignore xxx", "parent.child", "ignore", "newvalue"}, - {"ignore xxx", "parent.child.subchild", "ignore", "newvalue"}, - - {"ignore xxx", "key", "ignore", "newvalue"}, - {"parent {\n\tignore xxx\n}", "parent.child", "parent.ignore", "newvalue"}, - {"ignore xxx\nparent {\n}", "parent.child", "ignore", "newvalue"}, - } - - for i, test := range tests { - - parser := new(confl) - reader := bytes.NewBufferString(test.raw) - - // try to extract value - _, err := parser.ReadFrom(reader) - if err != nil { - t.Errorf("[%d] parse error: %s", i, err) - continue - } - - // update value - if !parser.Set(test.key, test.value) { - t.Errorf("[%d] cannot set '%s' to '%s'", i, test.key, test.value) - continue - } - - // check new value - value, found := parser.Get(test.key) - if !found { - t.Errorf("[%d] expected a result, got none", i) - continue - } - - // check value - if value != test.value { - t.Errorf("[%d] expected '%s' got '%s'", i, test.value, value) - continue - } - - // check that ignore field is still there - value, found = parser.Get(test.ignore) - if !found { - t.Errorf("[%d] expected ignore field, got none", i) - continue - } - - // check value - if value != "xxx" { - t.Errorf("[%d] expected ignore value to be '%s' got '%s'", i, "xxx", value) - continue - } - } - -} diff --git a/internal/cnf/loader.go b/internal/cnf/loader.go index 18ecb25..fefa723 100644 --- a/internal/cnf/loader.go +++ b/internal/cnf/loader.go @@ -77,7 +77,7 @@ func loadFromExtension(ext string) ConfigurationFormat { case ".yaml": return new(yaml) case ".conf": - return new(confl) + return new(nginx) default: return nil } diff --git a/internal/cnf/nginx.go b/internal/cnf/nginx.go new file mode 100644 index 0000000..6594348 --- /dev/null +++ b/internal/cnf/nginx.go @@ -0,0 +1,102 @@ +package cnf + +import ( + lib "git.xdrm.io/go/nix-amer/internal/cnf/parser/nginx" + "io" + "strings" +) + +type nginx struct { + data *lib.Model + parsed bool +} + +// ReadFrom implements io.ReaderFrom +func (d *nginx) ReadFrom(_reader io.Reader) (int64, error) { + + d.data = new(lib.Model) + + // 1. get nginx decoder + decoder := lib.NewDecoder(_reader) + err := decoder.Decode(d.data) + if err != nil { + return 0, err + } + + d.parsed = true + return 0, nil + +} + +// WriteTo implements io.WriterTo +func (d *nginx) WriteTo(_writer io.Writer) (int64, error) { + encoder := lib.NewEncoder(_writer) + return 0, encoder.Encode(d.data) +} + +// browse returns the target of a dot-separated path (as an interface{} chain where the last is the target if found) +func (d *nginx) browse(_path string) ([][]*lib.Line, bool) { + + // 1. extract path + path := strings.Split(_path, ".") + if len(path) > 0 { // remove last field + path = path[:len(path)-1] + } + + // 2. init output chain + var current []*lib.Line = d.data.Lines + chain := make([][]*lib.Line, 0, len(path)+1) + chain = append(chain, current) + + // 3. iterate over path / nested fields + for _, field := range path { + + for _, child := range current { + if child.Type == lib.SECTION && child.Components[0] == field { + current = child.Lines + chain = append(chain, current) + break + } + } + + return chain, false + } + + return chain, true +} + +// Get returns the value of a dot-separated path, and if it exists +func (d *nginx) Get(_path string) (string, bool) { + + // 1. browse path + chain, found := d.browse(_path) + if !found { + return "", false + } + + // 2. Get last field + fields := strings.Split(_path, ".") + field := fields[len(fields)-1] + + // 3. search in last chain element + last := chain[len(chain)-1] + + for _, line := range last { + + // 4. return value + if line.Type == lib.ASSIGNMENT && line.Components[0] == field { + return line.Components[1], true + } + + } + + return "", false + +} + +// Set the value of a dot-separated path, and creates it if not found +func (d *nginx) Set(_path, _value string) bool { + + return false + +} diff --git a/internal/cnf/parser/nginx/line.go b/internal/cnf/parser/nginx/line.go index a05350f..655ffbf 100644 --- a/internal/cnf/parser/nginx/line.go +++ b/internal/cnf/parser/nginx/line.go @@ -31,25 +31,3 @@ type Line struct { // Lines children of the current section (nil if not a section) Lines []*Line } - -// Section returns the section with a given name *directly* -// inside the current line ; nil is returned if no match found -func (l *Line) Section(name string) *Line { - for _, elem := range l.Lines { - if elem.Type == SECTION && elem.Components[0] == name { - return elem - } - } - return nil -} - -// Get returns a pointer to the assignment line the given name as key -// *directly* inside the current line ; nil is returned if no match found -func (l *Line) Get(name string) *Line { - for _, elem := range l.Lines { - if elem.Type == ASSIGNMENT && elem.Components[0] == name { - return elem - } - } - return nil -} diff --git a/internal/cnf/parser/nginx/nginx.go b/internal/cnf/parser/nginx/nginx.go index d76b020..04137b8 100644 --- a/internal/cnf/parser/nginx/nginx.go +++ b/internal/cnf/parser/nginx/nginx.go @@ -17,25 +17,3 @@ func NewDecoder(r io.Reader) *decoder { func NewEncoder(w io.Writer) *encoder { return &encoder{writer: w} } - -// Section returns the section with a given name at the root level -// nil is returned if no match found -func (l *Model) Section(name string) *Line { - for _, elem := range l.Lines { - if elem.Type == SECTION && elem.Components[0] == name { - return elem - } - } - return nil -} - -// Get returns a pointer to the assignment line the given name as key -// at the root level -func (l *Model) Get(name string) *Line { - for _, elem := range l.Lines { - if elem.Type == ASSIGNMENT && elem.Components[0] == name { - return elem - } - } - return nil -}