dockerscript.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. package dockerscript
  2. import (
  3. "github.com/dotcloud/docker/pkg/dockerscript/scanner"
  4. "fmt"
  5. "io"
  6. "strings"
  7. )
  8. type Command struct {
  9. Args []string
  10. Children []*Command
  11. }
  12. func Parse(src io.Reader) ([]*Command, error) {
  13. s := &scanner.Scanner{}
  14. s.Init(src)
  15. s.Whitespace = 1<<'\t' | 1<<' '
  16. s.Mode = scanner.ScanStrings | scanner.ScanRawStrings | scanner.ScanIdents
  17. expr, err := parse(s, "")
  18. if err != nil {
  19. return nil, fmt.Errorf("line %d:%d: %v\n", s.Pos().Line, s.Pos().Column, err)
  20. }
  21. return expr, nil
  22. }
  23. func (cmd *Command) subString(depth int) string {
  24. var prefix string
  25. for i:=0; i<depth; i++ {
  26. prefix += " "
  27. }
  28. s := prefix + strings.Join(cmd.Args, ", ")
  29. if len(cmd.Children) > 0 {
  30. s += " {\n"
  31. for _, subcmd := range cmd.Children {
  32. s += subcmd.subString(depth + 1)
  33. }
  34. s += prefix + "}"
  35. }
  36. s += "\n"
  37. return s
  38. }
  39. func (cmd *Command) String() string {
  40. return cmd.subString(0)
  41. }
  42. func parseArgs(s *scanner.Scanner) ([]string, rune, error) {
  43. var parseError error
  44. // FIXME: we overwrite previously set error
  45. s.Error = func(s *scanner.Scanner, msg string) {
  46. parseError = fmt.Errorf(msg)
  47. // parseError = fmt.Errorf("line %d:%d: %s\n", s.Pos().Line, s.Pos().Column, msg)
  48. }
  49. var args []string
  50. tok := s.Scan()
  51. for tok != scanner.EOF {
  52. if parseError != nil {
  53. return args, tok, parseError
  54. }
  55. text := s.TokenText()
  56. if text == "{" || text == "}" || text == "\n" || text == "\r" || text == ";" {
  57. return args, tok, nil
  58. }
  59. args = append(args, text)
  60. tok = s.Scan()
  61. }
  62. return args, tok, nil
  63. }
  64. func parse(s *scanner.Scanner, opener string) (expr []*Command, err error) {
  65. /*
  66. defer func() {
  67. fmt.Printf("parse() returned %d commands:\n", len(expr))
  68. for _, c := range expr {
  69. fmt.Printf("\t----> %s\n", c)
  70. }
  71. }()
  72. */
  73. for {
  74. args, tok, err := parseArgs(s)
  75. if err != nil {
  76. return nil, err
  77. }
  78. cmd := &Command{Args: args}
  79. afterArgs := s.TokenText()
  80. if afterArgs == "{" {
  81. children, err := parse(s, "{")
  82. if err != nil {
  83. return nil, err
  84. }
  85. cmd.Children = children
  86. } else if afterArgs == "}" && opener != "{" {
  87. return nil, fmt.Errorf("unexpected end of block '}'")
  88. }
  89. if len(cmd.Args) > 0 || len(cmd.Children) > 0 {
  90. expr = append(expr, cmd)
  91. }
  92. if tok == scanner.EOF || afterArgs == "}" {
  93. break
  94. }
  95. }
  96. return expr, nil
  97. }