Browse code

Merge pull request #17599 from perhapszzy/master

Add line information in the parsed Dockerfile.

Doug Davis authored on 2015/11/14 06:53:59
Showing 3 changed files
... ...
@@ -30,6 +30,8 @@ type Node struct {
30 30
 	Attributes map[string]bool // special attributes for this node
31 31
 	Original   string          // original line used before parsing
32 32
 	Flags      []string        // only top Node should have this set
33
+	StartLine  int             // the line in the original dockerfile where the node begins
34
+	EndLine    int             // the line in the original dockerfile where the node ends
33 35
 }
34 36
 
35 37
 var (
... ...
@@ -101,19 +103,24 @@ func parseLine(line string) (string, *Node, error) {
101 101
 // Parse is the main parse routine.
102 102
 // It handles an io.ReadWriteCloser and returns the root of the AST.
103 103
 func Parse(rwc io.Reader) (*Node, error) {
104
+	currentLine := 0
104 105
 	root := &Node{}
106
+	root.StartLine = -1
105 107
 	scanner := bufio.NewScanner(rwc)
106 108
 
107 109
 	for scanner.Scan() {
108 110
 		scannedLine := strings.TrimLeftFunc(scanner.Text(), unicode.IsSpace)
111
+		currentLine++
109 112
 		line, child, err := parseLine(scannedLine)
110 113
 		if err != nil {
111 114
 			return nil, err
112 115
 		}
116
+		startLine := currentLine
113 117
 
114 118
 		if line != "" && child == nil {
115 119
 			for scanner.Scan() {
116 120
 				newline := scanner.Text()
121
+				currentLine++
117 122
 
118 123
 				if stripComments(strings.TrimSpace(newline)) == "" {
119 124
 					continue
... ...
@@ -137,6 +144,15 @@ func Parse(rwc io.Reader) (*Node, error) {
137 137
 		}
138 138
 
139 139
 		if child != nil {
140
+			// Update the line information for the current child.
141
+			child.StartLine = startLine
142
+			child.EndLine = currentLine
143
+			// Update the line information for the root. The starting line of the root is always the
144
+			// starting line of the first child and the ending line is the ending line of the last child.
145
+			if root.StartLine < 0 {
146
+				root.StartLine = currentLine
147
+			}
148
+			root.EndLine = currentLine
140 149
 			root.Children = append(root.Children, child)
141 150
 		}
142 151
 	}
... ...
@@ -12,6 +12,7 @@ import (
12 12
 
13 13
 const testDir = "testfiles"
14 14
 const negativeTestDir = "testfiles-negative"
15
+const testFileLineInfo = "testfile-line/Dockerfile"
15 16
 
16 17
 func getDirs(t *testing.T, dir string) []string {
17 18
 	f, err := os.Open(dir)
... ...
@@ -117,3 +118,37 @@ func TestParseWords(t *testing.T) {
117 117
 		}
118 118
 	}
119 119
 }
120
+
121
+func TestLineInformation(t *testing.T) {
122
+	df, err := os.Open(testFileLineInfo)
123
+	if err != nil {
124
+		t.Fatalf("Dockerfile missing for %s: %v", testFileLineInfo, err)
125
+	}
126
+	defer df.Close()
127
+
128
+	ast, err := Parse(df)
129
+	if err != nil {
130
+		t.Fatalf("Error parsing dockerfile %s: %v", testFileLineInfo, err)
131
+	}
132
+
133
+	if ast.StartLine != 4 || ast.EndLine != 30 {
134
+		fmt.Fprintf(os.Stderr, "Wrong root line information: expected(%d-%d), actual(%d-%d)\n", 4, 30, ast.StartLine, ast.EndLine)
135
+		t.Fatalf("Root line information doesn't match result.")
136
+	}
137
+	if len(ast.Children) != 3 {
138
+		fmt.Fprintf(os.Stderr, "Wrong number of child: expected(%d), actual(%d)\n", 3, len(ast.Children))
139
+		t.Fatalf("Root line information doesn't match result.")
140
+	}
141
+	expected := [][]int{
142
+		{4, 4},
143
+		{10, 11},
144
+		{16, 30},
145
+	}
146
+	for i, child := range ast.Children {
147
+		if child.StartLine != expected[i][0] || child.EndLine != expected[i][1] {
148
+			fmt.Fprintf(os.Stderr, "Wrong line information for child %d: expected(%d-%d), actual(%d-%d)\n",
149
+				i, expected[i][0], expected[i][1], child.StartLine, child.EndLine)
150
+			t.Fatalf("Root line information doesn't match result.")
151
+		}
152
+	}
153
+}
120 154
new file mode 100644
... ...
@@ -0,0 +1,34 @@
0
+
1
+
2
+
3
+FROM brimstone/ubuntu:14.04
4
+
5
+
6
+# TORUN -v /var/run/docker.sock:/var/run/docker.sock
7
+
8
+
9
+ENV GOPATH \
10
+/go
11
+
12
+
13
+
14
+# Install the packages we need, clean up after them and us
15
+RUN apt-get update \
16
+	&& dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.clean \
17
+
18
+
19
+    && apt-get install -y --no-install-recommends git golang ca-certificates \
20
+    && apt-get clean \
21
+    && rm -rf /var/lib/apt/lists \
22
+
23
+	&& go get -v github.com/brimstone/consuldock \
24
+    && mv $GOPATH/bin/consuldock /usr/local/bin/consuldock \
25
+
26
+	&& dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.dirty \
27
+	&& apt-get remove --purge -y $(diff /tmp/dpkg.clean /tmp/dpkg.dirty | awk '/^>/ {print $2}') \
28
+	&& rm /tmp/dpkg.* \
29
+	&& rm -rf $GOPATH
30
+
31
+
32
+
33
+