Browse code

Merge pull request #24725 from yongtang/24693-dockerfile-empty-line-after-escape

Fix dockerfile parser with empty line after escape

Sebastiaan van Stijn authored on 2016/10/29 05:53:15
Showing 11 changed files
... ...
@@ -176,10 +176,17 @@ func Parse(rwc io.Reader, d *Directive) (*Node, error) {
176 176
 				newline := scanner.Text()
177 177
 				currentLine++
178 178
 
179
-				if stripComments(strings.TrimSpace(newline)) == "" {
180
-					continue
179
+				// If escape followed by a comment line then stop
180
+				// Note here that comment line starts with `#` at
181
+				// the first pos of the line
182
+				if stripComments(newline) == "" {
183
+					break
181 184
 				}
182 185
 
186
+				// If escape followed by an empty line then stop
187
+				if strings.TrimSpace(newline) == "" {
188
+					break
189
+				}
183 190
 				line, child, err = ParseLine(line+newline, d)
184 191
 				if err != nil {
185 192
 					return nil, err
... ...
@@ -150,8 +150,8 @@ func TestLineInformation(t *testing.T) {
150 150
 		t.Fatalf("Error parsing dockerfile %s: %v", testFileLineInfo, err)
151 151
 	}
152 152
 
153
-	if ast.StartLine != 5 || ast.EndLine != 31 {
154
-		fmt.Fprintf(os.Stderr, "Wrong root line information: expected(%d-%d), actual(%d-%d)\n", 5, 31, ast.StartLine, ast.EndLine)
153
+	if ast.StartLine != 5 || ast.EndLine != 27 {
154
+		fmt.Fprintf(os.Stderr, "Wrong root line information: expected(%d-%d), actual(%d-%d)\n", 5, 27, ast.StartLine, ast.EndLine)
155 155
 		t.Fatalf("Root line information doesn't match result.")
156 156
 	}
157 157
 	if len(ast.Children) != 3 {
... ...
@@ -161,7 +161,7 @@ func TestLineInformation(t *testing.T) {
161 161
 	expected := [][]int{
162 162
 		{5, 5},
163 163
 		{11, 12},
164
-		{17, 31},
164
+		{17, 27},
165 165
 	}
166 166
 	for i, child := range ast.Children {
167 167
 		if child.StartLine != expected[i][0] || child.EndLine != expected[i][1] {
... ...
@@ -16,15 +16,11 @@ ENV GOPATH \
16 16
 # Install the packages we need, clean up after them and us
17 17
 RUN apt-get update \
18 18
 	&& dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.clean \
19
-
20
-
21 19
     && apt-get install -y --no-install-recommends git golang ca-certificates \
22 20
     && apt-get clean \
23 21
     && rm -rf /var/lib/apt/lists \
24
-
25 22
 	&& go get -v github.com/brimstone/consuldock \
26 23
     && mv $GOPATH/bin/consuldock /usr/local/bin/consuldock \
27
-
28 24
 	&& dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.dirty \
29 25
 	&& apt-get remove --purge -y $(diff /tmp/dpkg.clean /tmp/dpkg.dirty | awk '/^>/ {print $2}') \
30 26
 	&& rm /tmp/dpkg.* \
... ...
@@ -16,10 +16,8 @@ RUN apt-get update \
16 16
     && apt-get install -y --no-install-recommends git golang ca-certificates \
17 17
     && apt-get clean \
18 18
     && rm -rf /var/lib/apt/lists \
19
-
20 19
 	&& go get -v github.com/brimstone/consuldock \
21 20
     && mv $GOPATH/bin/consuldock /usr/local/bin/consuldock \
22
-
23 21
 	&& dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.dirty \
24 22
 	&& apt-get remove --purge -y $(diff /tmp/dpkg.clean /tmp/dpkg.dirty | awk '/^>/ {print $2}') \
25 23
 	&& rm /tmp/dpkg.* \
... ...
@@ -23,14 +23,12 @@ RUN apt-get update \
23 23
     && apt-get install -y --no-install-recommends unzip wget \
24 24
     && apt-get clean \
25 25
     && rm -rf /var/lib/apt/lists \
26
-
27 26
     && cd /tmp \
28 27
     && wget https://dl.bintray.com/mitchellh/consul/0.3.1_web_ui.zip \
29 28
        -O web_ui.zip \
30 29
     && unzip web_ui.zip \
31 30
     && mv dist /webui \
32 31
     && rm web_ui.zip \
33
-
34 32
 	&& dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.dirty \
35 33
 	&& apt-get remove --purge -y $(diff /tmp/dpkg.clean /tmp/dpkg.dirty | awk '/^>/ {print $2}') \
36 34
 	&& rm /tmp/dpkg.*
... ...
@@ -42,10 +40,8 @@ RUN apt-get update \
42 42
     && apt-get install -y --no-install-recommends git golang ca-certificates build-essential \
43 43
     && apt-get clean \
44 44
     && rm -rf /var/lib/apt/lists \
45
-
46 45
 	&& go get -v github.com/hashicorp/consul \
47 46
 	&& mv $GOPATH/bin/consul /usr/bin/consul \
48
-
49 47
 	&& dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.dirty \
50 48
 	&& apt-get remove --purge -y $(diff /tmp/dpkg.clean /tmp/dpkg.dirty | awk '/^>/ {print $2}') \
51 49
 	&& rm /tmp/dpkg.* \
... ...
@@ -27,8 +27,5 @@ bye\
27 27
 frog
28 28
 
29 29
 RUN echo hello \
30
-# this is a comment
31
-
32
-# this is a comment with a blank line surrounding it
33
-
34
-this is some more useful stuff
30
+# this is a comment that breaks escape continuation
31
+RUN echo this is some more useful stuff
... ...
@@ -6,4 +6,5 @@
6 6
 (run "echo hi   world  goodnight")
7 7
 (run "echo goodbyefrog")
8 8
 (run "echo goodbyefrog")
9
-(run "echo hello this is some more useful stuff")
9
+(run "echo hello")
10
+(run "echo this is some more useful stuff")
10 11
new file mode 100644
... ...
@@ -0,0 +1,15 @@
0
+FROM busybox
1
+
2
+# The following will create two instructions
3
+# `Run foo`
4
+# `bar`
5
+# because empty line will break the escape.
6
+# The parser will generate the following:
7
+# (from "busybox")
8
+# (run "foo")
9
+# (bar "")
10
+# And `bar` will return an error instruction later
11
+# Note: Parse() will not immediately error out.
12
+RUN foo \
13
+
14
+bar
0 15
new file mode 100644
... ...
@@ -0,0 +1,3 @@
0
+(from "busybox")
1
+(run "foo")
2
+(bar "")
... ...
@@ -6,9 +6,7 @@ RUN apt-get \update && \
6 6
 ADD \conf\\" /.znc
7 7
 
8 8
 RUN foo \
9
-
10 9
 bar \
11
-
12 10
 baz
13 11
 
14 12
 CMD [ "\/usr\\\"/bin/znc", "-f", "-r" ]
... ...
@@ -3610,8 +3610,8 @@ RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/do
3610 3610
 
3611 3611
 # Switch back to root and double check that worked exactly as we might expect it to
3612 3612
 USER root
3613
+# Add a "supplementary" group for our dockerio user
3613 3614
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '0:0/root:root/0 10:root wheel' ] && \
3614
-	# Add a "supplementary" group for our dockerio user \
3615 3615
 	echo 'supplementary:x:1002:dockerio' >> /etc/group
3616 3616
 
3617 3617
 # ... and then go verify that we get it like we expect
... ...
@@ -7139,3 +7139,38 @@ func (s *DockerSuite) TestBuildNetContainer(c *check.C) {
7139 7139
 	host, _ := dockerCmd(c, "run", "testbuildnetcontainer", "cat", "/otherhost")
7140 7140
 	c.Assert(strings.TrimSpace(host), check.Equals, "foobar")
7141 7141
 }
7142
+
7143
+// Test case for #24693
7144
+func (s *DockerSuite) TestBuildRunEmptyLineAfterEscape(c *check.C) {
7145
+	name := "testbuildemptylineafterescape"
7146
+	_, out, err := buildImageWithOut(name,
7147
+		`
7148
+FROM busybox
7149
+RUN echo x \
7150
+
7151
+RUN echo y
7152
+RUN echo z
7153
+# Comment requires the '#' to start from position 1
7154
+# RUN echo w
7155
+`, true)
7156
+	c.Assert(err, checker.IsNil)
7157
+	c.Assert(out, checker.Contains, "Step 1/4 : FROM busybox")
7158
+	c.Assert(out, checker.Contains, "Step 2/4 : RUN echo x")
7159
+	c.Assert(out, checker.Contains, "Step 3/4 : RUN echo y")
7160
+	c.Assert(out, checker.Contains, "Step 4/4 : RUN echo z")
7161
+
7162
+	// With comment, see #24693
7163
+	name = "testbuildcommentandemptylineafterescape"
7164
+	_, out, err = buildImageWithOut(name,
7165
+		`
7166
+FROM busybox
7167
+RUN echo grafana && \
7168
+    echo raintank \
7169
+#echo env-load
7170
+RUN echo vegeta
7171
+`, true)
7172
+	c.Assert(err, checker.IsNil)
7173
+	c.Assert(out, checker.Contains, "Step 1/3 : FROM busybox")
7174
+	c.Assert(out, checker.Contains, "Step 2/3 : RUN echo grafana &&     echo raintank")
7175
+	c.Assert(out, checker.Contains, "Step 3/3 : RUN echo vegeta")
7176
+}