Skip to content

Commit

Permalink
Merge pull request #2 from drlau/refactor-parse
Browse files Browse the repository at this point in the history
refactor parsing
  • Loading branch information
drlau authored Aug 11, 2020
2 parents 46a00be + 03975f2 commit b7d3d31
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 56 deletions.
116 changes: 70 additions & 46 deletions parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package tfplanparse

import (
"bufio"
"fmt"
"io"
"os"
"strings"
Expand All @@ -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
}
Expand All @@ -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))
}
20 changes: 10 additions & 10 deletions resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit b7d3d31

Please sign in to comment.