diff --git a/builder/dockerfile/parser/parser.go b/builder/dockerfile/parser/parser.go index 0729fa539d..fa57d3953c 100644 --- a/builder/dockerfile/parser/parser.go +++ b/builder/dockerfile/parser/parser.go @@ -107,29 +107,28 @@ func (d *Directive) setEscapeToken(s string) error { return nil } -// processLine looks for a parser directive '# escapeToken=. Parser -// directives must precede any builder instruction or other comments, and cannot -// be repeated. -func (d *Directive) processLine(line string) error { +// possibleParserDirective looks for one or more parser directives '# escapeToken=' and +// '# platform='. Parser directives must precede any builder instruction +// or other comments, and cannot be repeated. +func (d *Directive) possibleParserDirective(line string) error { if d.processingComplete { return nil } - // Processing is finished after the first call - defer func() { d.processingComplete = true }() tecMatch := tokenEscapeCommand.FindStringSubmatch(strings.ToLower(line)) - if len(tecMatch) == 0 { - return nil - } - if d.escapeSeen == true { - return errors.New("only one escape parser directive can be used") - } - for i, n := range tokenEscapeCommand.SubexpNames() { - if n == "escapechar" { - d.escapeSeen = true - return d.setEscapeToken(tecMatch[i]) + if len(tecMatch) != 0 { + for i, n := range tokenEscapeCommand.SubexpNames() { + if n == "escapechar" { + if d.escapeSeen == true { + return errors.New("only one escape parser directive can be used") + } + d.escapeSeen = true + return d.setEscapeToken(tecMatch[i]) + } } } + + d.processingComplete = true return nil } @@ -213,34 +212,36 @@ func Parse(rwc io.Reader) (*Result, error) { var err error for scanner.Scan() { - bytes := scanner.Bytes() - switch currentLine { - case 0: - bytes, err = processFirstLine(d, bytes) - if err != nil { - return nil, err - } - default: - bytes = processLine(bytes, true) + bytesRead := scanner.Bytes() + if currentLine == 0 { + // First line, strip the byte-order-marker if present + bytesRead = bytes.TrimPrefix(bytesRead, utf8bom) + } + bytesRead, err = processLine(d, bytesRead, true) + if err != nil { + return nil, err } currentLine++ startLine := currentLine - line, isEndOfLine := trimContinuationCharacter(string(bytes), d) + line, isEndOfLine := trimContinuationCharacter(string(bytesRead), d) if isEndOfLine && line == "" { continue } for !isEndOfLine && scanner.Scan() { - bytes := processLine(scanner.Bytes(), false) + bytesRead, err := processLine(d, scanner.Bytes(), false) + if err != nil { + return nil, err + } currentLine++ // TODO: warn this is being deprecated/removed - if isEmptyContinuationLine(bytes) { + if isEmptyContinuationLine(bytesRead) { continue } - continuationLine := string(bytes) + continuationLine := string(bytesRead) continuationLine, isEndOfLine = trimContinuationCharacter(continuationLine, d) line += continuationLine } @@ -251,7 +252,6 @@ func Parse(rwc io.Reader) (*Result, error) { } root.AddChild(child, startLine, currentLine) } - return &Result{AST: root, EscapeToken: d.escapeToken}, nil } @@ -279,16 +279,10 @@ func trimContinuationCharacter(line string, d *Directive) (string, bool) { // TODO: remove stripLeftWhitespace after deprecation period. It seems silly // to preserve whitespace on continuation lines. Why is that done? -func processLine(token []byte, stripLeftWhitespace bool) []byte { +func processLine(d *Directive, token []byte, stripLeftWhitespace bool) ([]byte, error) { if stripLeftWhitespace { token = trimWhitespace(token) } - return trimComments(token) -} - -func processFirstLine(d *Directive, token []byte) ([]byte, error) { - token = bytes.TrimPrefix(token, utf8bom) - token = trimWhitespace(token) - err := d.processLine(string(token)) + err := d.possibleParserDirective(string(token)) return trimComments(token), err }