Browse code

Fix case where \\ at EOF made the builder ignore the command

Came from looking at issue #27545

Signed-off-by: Doug Davis <dug@us.ibm.com>

Doug Davis authored on 2016/10/29 06:11:36
Showing 4 changed files
... ...
@@ -238,7 +238,7 @@ func (b *Builder) build(stdout io.Writer, stderr io.Writer, out io.Writer) (stri
238 238
 		for k, v := range b.options.Labels {
239 239
 			line += fmt.Sprintf("%q='%s' ", k, v)
240 240
 		}
241
-		_, node, err := parser.ParseLine(line, &b.directive)
241
+		_, node, err := parser.ParseLine(line, &b.directive, false)
242 242
 		if err != nil {
243 243
 			return "", err
244 244
 		}
... ...
@@ -35,7 +35,7 @@ func parseSubCommand(rest string, d *Directive) (*Node, map[string]bool, error)
35 35
 		return nil, nil, nil
36 36
 	}
37 37
 
38
-	_, child, err := ParseLine(rest, d)
38
+	_, child, err := ParseLine(rest, d, false)
39 39
 	if err != nil {
40 40
 		return nil, nil, err
41 41
 	}
... ...
@@ -95,7 +95,7 @@ func init() {
95 95
 }
96 96
 
97 97
 // ParseLine parses a line and returns the remainder.
98
-func ParseLine(line string, d *Directive) (string, *Node, error) {
98
+func ParseLine(line string, d *Directive, ignoreCont bool) (string, *Node, error) {
99 99
 	// Handle the parser directive '# escape=<char>. Parser directives must precede
100 100
 	// any builder instruction or other comments, and cannot be repeated.
101 101
 	if d.LookingForDirectives {
... ...
@@ -122,7 +122,7 @@ func ParseLine(line string, d *Directive) (string, *Node, error) {
122 122
 		return "", nil, nil
123 123
 	}
124 124
 
125
-	if d.LineContinuationRegex.MatchString(line) {
125
+	if !ignoreCont && d.LineContinuationRegex.MatchString(line) {
126 126
 		line = d.LineContinuationRegex.ReplaceAllString(line, "")
127 127
 		return line, nil, nil
128 128
 	}
... ...
@@ -165,7 +165,7 @@ func Parse(rwc io.Reader, d *Directive) (*Node, error) {
165 165
 		}
166 166
 		scannedLine := strings.TrimLeftFunc(string(scannedBytes), unicode.IsSpace)
167 167
 		currentLine++
168
-		line, child, err := ParseLine(scannedLine, d)
168
+		line, child, err := ParseLine(scannedLine, d, false)
169 169
 		if err != nil {
170 170
 			return nil, err
171 171
 		}
... ...
@@ -187,7 +187,7 @@ func Parse(rwc io.Reader, d *Directive) (*Node, error) {
187 187
 				if strings.TrimSpace(newline) == "" {
188 188
 					break
189 189
 				}
190
-				line, child, err = ParseLine(line+newline, d)
190
+				line, child, err = ParseLine(line+newline, d, false)
191 191
 				if err != nil {
192 192
 					return nil, err
193 193
 				}
... ...
@@ -197,7 +197,13 @@ func Parse(rwc io.Reader, d *Directive) (*Node, error) {
197 197
 				}
198 198
 			}
199 199
 			if child == nil && line != "" {
200
-				_, child, err = ParseLine(line, d)
200
+				// When we call ParseLine we'll pass in 'true' for
201
+				// the ignoreCont param if we're at the EOF. This will
202
+				// prevent the func from returning immediately w/o
203
+				// parsing the line thinking that there's more input
204
+				// to come.
205
+
206
+				_, child, err = ParseLine(line, d, scanner.Err() == nil)
201 207
 				if err != nil {
202 208
 					return nil, err
203 209
 				}
... ...
@@ -7237,3 +7237,33 @@ func (s *DockerSuite) TestBuildSquashParent(c *check.C) {
7237 7237
 	c.Assert(err, checker.IsNil)
7238 7238
 	c.Assert(strings.TrimSpace(out), checker.Equals, "3")
7239 7239
 }
7240
+
7241
+func (s *DockerSuite) TestBuildContChar(c *check.C) {
7242
+	name := "testbuildcontchar"
7243
+
7244
+	_, out, err := buildImageWithOut(name,
7245
+		`FROM busybox\`, true)
7246
+	c.Assert(err, checker.IsNil)
7247
+	c.Assert(out, checker.Contains, "Step 1/1 : FROM busybox")
7248
+
7249
+	_, out, err = buildImageWithOut(name,
7250
+		`FROM busybox
7251
+		 RUN echo hi \`, true)
7252
+	c.Assert(err, checker.IsNil)
7253
+	c.Assert(out, checker.Contains, "Step 1/2 : FROM busybox")
7254
+	c.Assert(out, checker.Contains, "Step 2/2 : RUN echo hi\n")
7255
+
7256
+	_, out, err = buildImageWithOut(name,
7257
+		`FROM busybox
7258
+		 RUN echo hi \\`, true)
7259
+	c.Assert(err, checker.IsNil)
7260
+	c.Assert(out, checker.Contains, "Step 1/2 : FROM busybox")
7261
+	c.Assert(out, checker.Contains, "Step 2/2 : RUN echo hi \\\n")
7262
+
7263
+	_, out, err = buildImageWithOut(name,
7264
+		`FROM busybox
7265
+		 RUN echo hi \\\`, true)
7266
+	c.Assert(err, checker.IsNil)
7267
+	c.Assert(out, checker.Contains, "Step 1/2 : FROM busybox")
7268
+	c.Assert(out, checker.Contains, "Step 2/2 : RUN echo hi \\\\\n")
7269
+}