utils.go 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. package parser
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. // QuoteString walks characters (after trimming), escapes any quotes and
  7. // escapes, then wraps the whole thing in quotes. Very useful for generating
  8. // argument output in nodes.
  9. func QuoteString(str string) string {
  10. result := ""
  11. chars := strings.Split(strings.TrimSpace(str), "")
  12. for _, char := range chars {
  13. switch char {
  14. case `"`:
  15. result += `\"`
  16. case `\`:
  17. result += `\\`
  18. default:
  19. result += char
  20. }
  21. }
  22. return `"` + result + `"`
  23. }
  24. // dumps the AST defined by `node` as a list of sexps. Returns a string
  25. // suitable for printing.
  26. func (node *Node) Dump() string {
  27. str := ""
  28. str += node.Value
  29. for _, n := range node.Children {
  30. str += "(" + n.Dump() + ")\n"
  31. }
  32. if node.Next != nil {
  33. for n := node.Next; n != nil; n = n.Next {
  34. if len(n.Children) > 0 {
  35. str += " " + n.Dump()
  36. } else {
  37. str += " " + QuoteString(n.Value)
  38. }
  39. }
  40. }
  41. return strings.TrimSpace(str)
  42. }
  43. // performs the dispatch based on the two primal strings, cmd and args. Please
  44. // look at the dispatch table in parser.go to see how these dispatchers work.
  45. func fullDispatch(cmd, args string) (*Node, map[string]bool, error) {
  46. fn := dispatch[cmd]
  47. // Ignore invalid Dockerfile instructions
  48. if fn == nil {
  49. fn = parseIgnore
  50. }
  51. sexp, attrs, err := fn(args)
  52. if err != nil {
  53. return nil, nil, err
  54. }
  55. return sexp, attrs, nil
  56. }
  57. // splitCommand takes a single line of text and parses out the cmd and args,
  58. // which are used for dispatching to more exact parsing functions.
  59. func splitCommand(line string) (string, string, error) {
  60. cmdline := TOKEN_WHITESPACE.Split(line, 2)
  61. if len(cmdline) != 2 {
  62. return "", "", fmt.Errorf("We do not understand this file. Please ensure it is a valid Dockerfile. Parser error at %q", line)
  63. }
  64. cmd := strings.ToLower(cmdline[0])
  65. // the cmd should never have whitespace, but it's possible for the args to
  66. // have trailing whitespace.
  67. return cmd, strings.TrimSpace(cmdline[1]), nil
  68. }
  69. // covers comments and empty lines. Lines should be trimmed before passing to
  70. // this function.
  71. func stripComments(line string) string {
  72. // string is already trimmed at this point
  73. if TOKEN_COMMENT.MatchString(line) {
  74. return TOKEN_COMMENT.ReplaceAllString(line, "")
  75. }
  76. return line
  77. }