From 5b6c4dd3df4d501018268d5c32bf78380923c292 Mon Sep 17 00:00:00 2001 From: "perhapszzy@sina.com" Date: Sun, 1 Nov 2015 16:28:30 -0500 Subject: [PATCH] Add line information in the parsed Dockerfile Signed-off-by: perhapszzy@sina.com --- builder/dockerfile/parser/parser.go | 16 +++++++++ builder/dockerfile/parser/parser_test.go | 35 +++++++++++++++++++ .../parser/testfile-line/Dockerfile | 34 ++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 builder/dockerfile/parser/testfile-line/Dockerfile diff --git a/builder/dockerfile/parser/parser.go b/builder/dockerfile/parser/parser.go index 2c1cacc939..ce258c5653 100644 --- a/builder/dockerfile/parser/parser.go +++ b/builder/dockerfile/parser/parser.go @@ -30,6 +30,8 @@ type Node struct { Attributes map[string]bool // special attributes for this node Original string // original line used before parsing Flags []string // only top Node should have this set + StartLine int // the line in the original dockerfile where the node begins + EndLine int // the line in the original dockerfile where the node ends } var ( @@ -101,19 +103,24 @@ func parseLine(line string) (string, *Node, error) { // Parse is the main parse routine. // It handles an io.ReadWriteCloser and returns the root of the AST. func Parse(rwc io.Reader) (*Node, error) { + currentLine := 0 root := &Node{} + root.StartLine = -1 scanner := bufio.NewScanner(rwc) for scanner.Scan() { scannedLine := strings.TrimLeftFunc(scanner.Text(), unicode.IsSpace) + currentLine++ line, child, err := parseLine(scannedLine) if err != nil { return nil, err } + startLine := currentLine if line != "" && child == nil { for scanner.Scan() { newline := scanner.Text() + currentLine++ if stripComments(strings.TrimSpace(newline)) == "" { continue @@ -137,6 +144,15 @@ func Parse(rwc io.Reader) (*Node, error) { } if child != nil { + // Update the line information for the current child. + child.StartLine = startLine + child.EndLine = currentLine + // Update the line information for the root. The starting line of the root is always the + // starting line of the first child and the ending line is the ending line of the last child. + if root.StartLine < 0 { + root.StartLine = currentLine + } + root.EndLine = currentLine root.Children = append(root.Children, child) } } diff --git a/builder/dockerfile/parser/parser_test.go b/builder/dockerfile/parser/parser_test.go index 9734676469..25104af768 100644 --- a/builder/dockerfile/parser/parser_test.go +++ b/builder/dockerfile/parser/parser_test.go @@ -10,6 +10,7 @@ import ( const testDir = "testfiles" const negativeTestDir = "testfiles-negative" +const testFileLineInfo = "testfile-line/Dockerfile" func getDirs(t *testing.T, dir string) []string { f, err := os.Open(dir) @@ -110,3 +111,37 @@ func TestParseWords(t *testing.T) { } } } + +func TestLineInformation(t *testing.T) { + df, err := os.Open(testFileLineInfo) + if err != nil { + t.Fatalf("Dockerfile missing for %s: %v", testFileLineInfo, err) + } + defer df.Close() + + ast, err := Parse(df) + if err != nil { + t.Fatalf("Error parsing dockerfile %s: %v", testFileLineInfo, err) + } + + if ast.StartLine != 4 || ast.EndLine != 30 { + fmt.Fprintf(os.Stderr, "Wrong root line information: expected(%d-%d), actual(%d-%d)\n", 4, 30, ast.StartLine, ast.EndLine) + t.Fatalf("Root line information doesn't match result.") + } + if len(ast.Children) != 3 { + fmt.Fprintf(os.Stderr, "Wrong number of child: expected(%d), actual(%d)\n", 3, len(ast.Children)) + t.Fatalf("Root line information doesn't match result.") + } + expected := [][]int{ + {4, 4}, + {10, 11}, + {16, 30}, + } + for i, child := range ast.Children { + if child.StartLine != expected[i][0] || child.EndLine != expected[i][1] { + fmt.Fprintf(os.Stderr, "Wrong line information for child %d: expected(%d-%d), actual(%d-%d)\n", + i, expected[i][0], expected[i][1], child.StartLine, child.EndLine) + t.Fatalf("Root line information doesn't match result.") + } + } +} diff --git a/builder/dockerfile/parser/testfile-line/Dockerfile b/builder/dockerfile/parser/testfile-line/Dockerfile new file mode 100644 index 0000000000..0e77e85e4f --- /dev/null +++ b/builder/dockerfile/parser/testfile-line/Dockerfile @@ -0,0 +1,34 @@ + + + +FROM brimstone/ubuntu:14.04 + + +# TORUN -v /var/run/docker.sock:/var/run/docker.sock + + +ENV GOPATH \ +/go + + + +# Install the packages we need, clean up after them and us +RUN apt-get update \ + && dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.clean \ + + + && apt-get install -y --no-install-recommends git golang ca-certificates \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists \ + + && go get -v github.com/brimstone/consuldock \ + && mv $GOPATH/bin/consuldock /usr/local/bin/consuldock \ + + && dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.dirty \ + && apt-get remove --purge -y $(diff /tmp/dpkg.clean /tmp/dpkg.dirty | awk '/^>/ {print $2}') \ + && rm /tmp/dpkg.* \ + && rm -rf $GOPATH + + + +