Skip to content

Commit 7ddf2be

Browse files
committed
Fix very minor continuation bugs for better coverage
There were some very minor/subtle bugs in how I implemented continuation that wouldn't affect any real-world parsing we did, but still bothered me because I'm me. This fixes them (and further increases test coverage as a result).
1 parent 0e00438 commit 7ddf2be

File tree

2 files changed

+62
-6
lines changed

2 files changed

+62
-6
lines changed

pkg/dockerfile/parse.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"io"
66
"strconv"
77
"strings"
8+
"unicode"
89
)
910

1011
type Metadata struct {
@@ -31,10 +32,11 @@ func ParseReader(dockerfile io.Reader) (*Metadata, error) {
3132
line := strings.TrimSpace(scanner.Text())
3233

3334
if line == "" {
34-
// ignore blank lines
35+
// ignore straight up blank lines (no complexity)
3536
continue
3637
}
3738

39+
// (we can't have a comment that ends in a continuation line - that's not continuation, that's part of the comment)
3840
if line[0] == '#' {
3941
// TODO handle "escape" parser directive
4042
// TODO handle "syntax" parser directive -- explode appropriately (since custom syntax invalidates our Dockerfile parsing)
@@ -44,20 +46,36 @@ func ParseReader(dockerfile io.Reader) (*Metadata, error) {
4446

4547
// handle line continuations
4648
// (TODO see note above regarding "escape" parser directive)
47-
for line[len(line)-1] == '\\' && scanner.Scan() {
48-
nextLine := strings.TrimSpace(scanner.Text())
49-
if nextLine == "" || nextLine[0] == '#' {
50-
// ignore blank lines and comments
49+
for line[len(line)-1] == '\\' {
50+
if !scanner.Scan() {
51+
line = line[0:len(line)-1]
52+
break
53+
}
54+
// "strings.TrimRightFunc(IsSpace)" because whitespace *after* the escape character is supported and ignored 🙈
55+
nextLine := strings.TrimRightFunc(scanner.Text(), unicode.IsSpace)
56+
if nextLine == "" { // if it's all space, TrimRight will be TrimSpace 😏
57+
// ignore "empty continuation" lines (https://github.com/moby/moby/pull/33719)
58+
continue
59+
}
60+
if strings.TrimLeftFunc(nextLine, unicode.IsSpace)[0] == '#' {
61+
// ignore comments inside continuation (https://github.com/moby/moby/issues/29005)
5162
continue
5263
}
5364
line = line[0:len(line)-1] + nextLine
5465
}
5566

67+
68+
// TODO *technically* a line like " RUN echo hi " should be parsed as "RUN" "echo hi" (cut off instruction, then the rest of the line with TrimSpace), but for our needs "strings.Fields" is good enough for now
69+
70+
// line = strings.TrimSpace(line) // (emulated below; "strings.Fields" does essentially the same exact thing so we don't need to do it explicitly here too)
71+
5672
fields := strings.Fields(line)
73+
5774
if len(fields) < 1 {
58-
// must be a much more complex empty line??
75+
// ignore empty lines
5976
continue
6077
}
78+
6179
instruction := strings.ToUpper(fields[0])
6280

6381
// TODO balk at ARG / $ in from values

pkg/dockerfile/parse_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,44 @@ func TestParse(t *testing.T) {
7575
Froms: []string{"bash:latest", "busybox:uclibc", "bash:5", "bash:latest", "scratch", "bash:latest", "bash:5", "bash:latest"},
7676
},
7777
},
78+
{
79+
name: "empty continuations",
80+
dockerfile: `
81+
\
82+
\
83+
\
84+
\
85+
\
86+
\
87+
`,
88+
},
89+
{
90+
name: "continuation edge cases",
91+
dockerfile: `
92+
# continuation does not apply to this comment \
93+
FROM scratch
94+
# but everything below this is part of a single continuation
95+
96+
FROM\
97+
98+
\
99+
\
100+
101+
\
102+
\
103+
104+
# comments inside are fine
105+
# and really yucky empty lines:
106+
107+
\
108+
\
109+
110+
scratch\
111+
`,
112+
metadata: dockerfile.Metadata{
113+
Froms: []string{"scratch", "scratch"},
114+
},
115+
},
78116
{
79117
// TODO is this even something that's supported by classic builder/buildkit? (Tianon *thinks* it was supported once, but maybe he's misremembering and it's never been a thing Dockerfiles, only docker build --target=N ?)
80118
name: "numbered stages",

0 commit comments

Comments
 (0)