mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Refactor some builder code
Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
parent
b86efd2707
commit
d7807c7316
2 changed files with 86 additions and 85 deletions
|
@ -7,6 +7,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
|
@ -36,6 +37,31 @@ type Node struct {
|
||||||
EndLine int // the line in the original dockerfile where the node ends
|
EndLine int // the line in the original dockerfile where the node ends
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dump dumps the AST defined by `node` as a list of sexps.
|
||||||
|
// Returns a string suitable for printing.
|
||||||
|
func (node *Node) Dump() string {
|
||||||
|
str := ""
|
||||||
|
str += node.Value
|
||||||
|
|
||||||
|
if len(node.Flags) > 0 {
|
||||||
|
str += fmt.Sprintf(" %q", node.Flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, n := range node.Children {
|
||||||
|
str += "(" + n.Dump() + ")\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
for n := node.Next; n != nil; n = n.Next {
|
||||||
|
if len(n.Children) > 0 {
|
||||||
|
str += " " + n.Dump()
|
||||||
|
} else {
|
||||||
|
str += " " + strconv.Quote(n.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimSpace(str)
|
||||||
|
}
|
||||||
|
|
||||||
// Directive is the structure used during a build run to hold the state of
|
// Directive is the structure used during a build run to hold the state of
|
||||||
// parsing directives.
|
// parsing directives.
|
||||||
type Directive struct {
|
type Directive struct {
|
||||||
|
@ -96,24 +122,9 @@ func init() {
|
||||||
|
|
||||||
// ParseLine parses a line and returns the remainder.
|
// ParseLine parses a line and returns the remainder.
|
||||||
func ParseLine(line string, d *Directive, ignoreCont bool) (string, *Node, error) {
|
func ParseLine(line string, d *Directive, ignoreCont bool) (string, *Node, error) {
|
||||||
// Handle the parser directive '# escape=<char>. Parser directives must precede
|
if escapeFound, err := handleParserDirective(line, d); err != nil || escapeFound {
|
||||||
// any builder instruction or other comments, and cannot be repeated.
|
d.EscapeSeen = escapeFound
|
||||||
if d.LookingForDirectives {
|
return "", nil, err
|
||||||
tecMatch := tokenEscapeCommand.FindStringSubmatch(strings.ToLower(line))
|
|
||||||
if len(tecMatch) > 0 {
|
|
||||||
if d.EscapeSeen == true {
|
|
||||||
return "", nil, fmt.Errorf("only one escape parser directive can be used")
|
|
||||||
}
|
|
||||||
for i, n := range tokenEscapeCommand.SubexpNames() {
|
|
||||||
if n == "escapechar" {
|
|
||||||
if err := SetEscapeToken(tecMatch[i], d); err != nil {
|
|
||||||
return "", nil, err
|
|
||||||
}
|
|
||||||
d.EscapeSeen = true
|
|
||||||
return "", nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
d.LookingForDirectives = false
|
d.LookingForDirectives = false
|
||||||
|
@ -127,25 +138,60 @@ func ParseLine(line string, d *Directive, ignoreCont bool) (string, *Node, error
|
||||||
return line, nil, nil
|
return line, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node, err := newNodeFromLine(line, d)
|
||||||
|
return "", node, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// newNodeFromLine splits the line into parts, and dispatches to a function
|
||||||
|
// based on the command and command arguments. A Node is created from the
|
||||||
|
// result of the dispatch.
|
||||||
|
func newNodeFromLine(line string, directive *Directive) (*Node, error) {
|
||||||
cmd, flags, args, err := splitCommand(line)
|
cmd, flags, args, err := splitCommand(line)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
node := &Node{}
|
fn := dispatch[cmd]
|
||||||
node.Value = cmd
|
// Ignore invalid Dockerfile instructions
|
||||||
|
if fn == nil {
|
||||||
sexp, attrs, err := fullDispatch(cmd, args, d)
|
fn = parseIgnore
|
||||||
|
}
|
||||||
|
next, attrs, err := fn(args, directive)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
node.Next = sexp
|
return &Node{
|
||||||
node.Attributes = attrs
|
Value: cmd,
|
||||||
node.Original = line
|
Original: line,
|
||||||
node.Flags = flags
|
Flags: flags,
|
||||||
|
Next: next,
|
||||||
|
Attributes: attrs,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
return "", node, nil
|
// Handle the parser directive '# escape=<char>. Parser directives must precede
|
||||||
|
// any builder instruction or other comments, and cannot be repeated.
|
||||||
|
func handleParserDirective(line string, d *Directive) (bool, error) {
|
||||||
|
if !d.LookingForDirectives {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
tecMatch := tokenEscapeCommand.FindStringSubmatch(strings.ToLower(line))
|
||||||
|
if len(tecMatch) == 0 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
if d.EscapeSeen == true {
|
||||||
|
return false, fmt.Errorf("only one escape parser directive can be used")
|
||||||
|
}
|
||||||
|
for i, n := range tokenEscapeCommand.SubexpNames() {
|
||||||
|
if n == "escapechar" {
|
||||||
|
if err := SetEscapeToken(tecMatch[i], d); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse is the main parse routine.
|
// Parse is the main parse routine.
|
||||||
|
@ -219,3 +265,14 @@ func Parse(rwc io.Reader, d *Directive) (*Node, error) {
|
||||||
|
|
||||||
return root, nil
|
return root, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// covers comments and empty lines. Lines should be trimmed before passing to
|
||||||
|
// this function.
|
||||||
|
func stripComments(line string) string {
|
||||||
|
// string is already trimmed at this point
|
||||||
|
if tokenComment.MatchString(line) {
|
||||||
|
return tokenComment.ReplaceAllString(line, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
|
|
@ -1,55 +1,10 @@
|
||||||
package parser
|
package parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Dump dumps the AST defined by `node` as a list of sexps.
|
|
||||||
// Returns a string suitable for printing.
|
|
||||||
func (node *Node) Dump() string {
|
|
||||||
str := ""
|
|
||||||
str += node.Value
|
|
||||||
|
|
||||||
if len(node.Flags) > 0 {
|
|
||||||
str += fmt.Sprintf(" %q", node.Flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, n := range node.Children {
|
|
||||||
str += "(" + n.Dump() + ")\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
for n := node.Next; n != nil; n = n.Next {
|
|
||||||
if len(n.Children) > 0 {
|
|
||||||
str += " " + n.Dump()
|
|
||||||
} else {
|
|
||||||
str += " " + strconv.Quote(n.Value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.TrimSpace(str)
|
|
||||||
}
|
|
||||||
|
|
||||||
// performs the dispatch based on the two primal strings, cmd and args. Please
|
|
||||||
// look at the dispatch table in parser.go to see how these dispatchers work.
|
|
||||||
func fullDispatch(cmd, args string, d *Directive) (*Node, map[string]bool, error) {
|
|
||||||
fn := dispatch[cmd]
|
|
||||||
|
|
||||||
// Ignore invalid Dockerfile instructions
|
|
||||||
if fn == nil {
|
|
||||||
fn = parseIgnore
|
|
||||||
}
|
|
||||||
|
|
||||||
sexp, attrs, err := fn(args, d)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sexp, attrs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// splitCommand takes a single line of text and parses out the cmd and args,
|
// splitCommand takes a single line of text and parses out the cmd and args,
|
||||||
// which are used for dispatching to more exact parsing functions.
|
// which are used for dispatching to more exact parsing functions.
|
||||||
func splitCommand(line string) (string, []string, string, error) {
|
func splitCommand(line string) (string, []string, string, error) {
|
||||||
|
@ -71,17 +26,6 @@ func splitCommand(line string) (string, []string, string, error) {
|
||||||
return cmd, flags, strings.TrimSpace(args), nil
|
return cmd, flags, strings.TrimSpace(args), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// covers comments and empty lines. Lines should be trimmed before passing to
|
|
||||||
// this function.
|
|
||||||
func stripComments(line string) string {
|
|
||||||
// string is already trimmed at this point
|
|
||||||
if tokenComment.MatchString(line) {
|
|
||||||
return tokenComment.ReplaceAllString(line, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
return line
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractBuilderFlags(line string) (string, []string, error) {
|
func extractBuilderFlags(line string) (string, []string, error) {
|
||||||
// Parses the BuilderFlags and returns the remaining part of the line
|
// Parses the BuilderFlags and returns the remaining part of the line
|
||||||
|
|
Loading…
Add table
Reference in a new issue