From 03975f2e80b9d411022f8ce70d591c0b31ea7add Mon Sep 17 00:00:00 2001 From: d-lau Date: Tue, 11 Aug 2020 21:31:10 +0900 Subject: [PATCH] refactor parsing --- parse.go | 116 +++++++++++++++++++++++++++++++--------------------- resource.go | 20 ++++----- 2 files changed, 80 insertions(+), 56 deletions(-) diff --git a/parse.go b/parse.go index bb3a3d2..6a8ba6b 100644 --- a/parse.go +++ b/parse.go @@ -2,6 +2,7 @@ package tfplanparse import ( "bufio" + "fmt" "io" "os" "strings" @@ -16,15 +17,11 @@ const ( func Parse(input io.Reader) ([]*ResourceChange, error) { result := []*ResourceChange{} - var resourceChange *ResourceChange - var mapAttributeChange *MapAttributeChange - var err error - parse := false scanner := bufio.NewScanner(input) for scanner.Scan() { - text := strings.TrimSpace(uncolor(scanner.Bytes())) + text := formatInput(scanner.Bytes()) if text == "" { continue } @@ -41,64 +38,91 @@ func Parse(input io.Reader) ([]*ResourceChange, error) { continue } - if strings.Contains(text, CHANGES_END_STRING) { - // we are done - if resourceChange != nil { - result = append(result, resourceChange) + if IsResourceCommentLine(text) { + rc, err := parseResource(scanner) + if err != nil { + return nil, err } + result = append(result, rc) + } + + if strings.Contains(formatInput(scanner.Bytes()), CHANGES_END_STRING) { + // we are done return result, nil } + } - if IsResourceCommentLine(text) { - // if parsing a resource before, append it as is - if resourceChange != nil { - result = append(result, resourceChange) - } + return nil, fmt.Errorf("unexpected end of input while parsing plan") +} - resourceChange, err = NewResourceChangeFromComment(text) - if err != nil { - return result, err - } - // TODO: handle nested maps - } else if IsMapAttributeChangeLine(text) { - mapAttributeChange, err = NewMapAttributeChangeFromLine(text) +func ParseFromFile(filepath string) ([]*ResourceChange, error) { + f, err := os.Open(filepath) + if err != nil { + return []*ResourceChange{}, err + } + + return Parse(f) +} + +func parseResource(s *bufio.Scanner) (*ResourceChange, error) { + rc, err := NewResourceChangeFromComment(s.Text()) + if err != nil { + return nil, err + } + for s.Scan() { + text := formatInput(s.Bytes()) + switch { + case IsResourceCommentLine(text), strings.Contains(text, CHANGES_END_STRING): + return rc, nil + case IsMapAttributeChangeLine(text): + ma, err := parseMapAttribute(s) if err != nil { - return result, err + return nil, err } - } else if IsAttributeChangeLine(text) { + rc.MapAttributeChanges = append(rc.MapAttributeChanges, ma) + case IsAttributeChangeLine(text): ac, err := NewAttributeChangeFromLine(text) if err != nil { - return result, err - } - - // if currently parsing a map attribute, this attribute belongs to the map - if mapAttributeChange != nil { - mapAttributeChange.AttributeChanges = append(mapAttributeChange.AttributeChanges, ac) - } else { - resourceChange.AttributeChanges = append(resourceChange.AttributeChanges, ac) - } - // TODO: this does not handle nested maps at all - } else if mapAttributeChange != nil && IsMapAttributeTerminator(text) { - if resourceChange != nil { - resourceChange.MapAttributeChanges = append(resourceChange.MapAttributeChanges, mapAttributeChange) - mapAttributeChange = nil + return nil, err } + rc.AttributeChanges = append(rc.AttributeChanges, ac) } } - if resourceChange != nil { - result = append(result, resourceChange) - } - - return result, nil + return nil, fmt.Errorf("unexpected end of input while parsing resource") } -func ParseFromFile(filepath string) ([]*ResourceChange, error) { - f, err := os.Open(filepath) +func parseMapAttribute(s *bufio.Scanner) (*MapAttributeChange, error) { + result, err := NewMapAttributeChangeFromLine(s.Text()) if err != nil { - return []*ResourceChange{}, err + return nil, err + } + for s.Scan() { + text := formatInput(s.Bytes()) + switch { + case IsMapAttributeTerminator(text): + return result, nil + case IsResourceCommentLine(text), strings.Contains(text, CHANGES_END_STRING): + return nil, fmt.Errorf("unexpected line while parsing map attribute: %s", text) + case IsMapAttributeChangeLine(text): + ma, err := parseMapAttribute(s) + if err != nil { + return nil, err + } + result.MapAttributeChanges = append(result.MapAttributeChanges, ma) + case IsAttributeChangeLine(text): + ac, err := NewAttributeChangeFromLine(text) + if err != nil { + return nil, err + } + result.AttributeChanges = append(result.AttributeChanges, ac) + } } - return Parse(f) + return nil, fmt.Errorf("unexpected end of input while parsing map attribute") } + +func formatInput(input []byte) string { + return strings.TrimSpace(uncolor(input)) +} \ No newline at end of file diff --git a/resource.go b/resource.go index 597ec8b..5c3b623 100644 --- a/resource.go +++ b/resource.go @@ -6,6 +6,16 @@ import ( "strings" ) +const ( + RESOURCE_CREATED = " will be created" + RESOURCE_READ = " will be read during apply" + RESOURCE_READ_VALUES_NOT_YET_KNOWN = " (config refers to values not yet known)" + RESOURCE_UPDATED_IN_PLACE = " will be updated in-place" + RESOURCE_TAINTED = " is tainted, so must be replaced" + RESOURCE_REPLACED = " must be replaced" + RESOURCE_DESTROYED = " will be destroyed" +) + type ResourceChange struct { // Address contains the absolute resource address Address string @@ -39,16 +49,6 @@ type ResourceChange struct { MapAttributeChanges []*MapAttributeChange } -const ( - RESOURCE_CREATED = " will be created" - RESOURCE_READ = " will be read during apply" - RESOURCE_READ_VALUES_NOT_YET_KNOWN = " (config refers to values not yet known)" - RESOURCE_UPDATED_IN_PLACE = " will be updated in-place" - RESOURCE_TAINTED = " is tainted, so must be replaced" - RESOURCE_REPLACED = " must be replaced" - RESOURCE_DESTROYED = " will be destroyed" -) - // IsResourceCommentLine returns true if the line is a valid resource comment line // A valid line starts with a "#" and has a suffix describing the change // Example: # module.type.item will be created