parse.go 2.11 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
package cli

import (
  "strings"
  "fmt"

  "github.com/jbenet/go-ipfs/commands"
)

func Parse(input []string, root *commands.Command) ([]string, []string, map[string]string, error) {
11
  path, input, err := parsePath(input, root)
12 13 14 15
  if err != nil {
    return nil, nil, nil, err
  }

16
  opts, args, err := parseOptions(input, path, root)
17 18 19 20 21
  if err != nil {
    return nil, nil, nil, err
  }

  return path, args, opts, nil
22 23
}

24
// parsePath gets the command path from the command line input
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
func parsePath(input []string, root *commands.Command) ([]string, []string, error) {
  cmd := root
  i := 0

  for _, blob := range input {
    if strings.HasPrefix(blob, "-") {
      break
    }

    cmd := cmd.Sub(blob)
    if cmd == nil {
      break
    }

    i++
  }

  return input[:i], input[i:], nil
}

45
// parseOptions parses the raw string values of the given options
46 47
// returns the parsed options as strings, along with the CLI args
func parseOptions(input, path []string, root *commands.Command) (map[string]string, []string, error) {
48
  options, err := root.GetOptions(path)
49 50 51 52
  if err != nil {
    return nil, nil, err
  }

53
  opts := make(map[string]string)
54
  args := make([]string, 0)
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79

  // TODO: error if one option is defined multiple times

  for i := 0; i < len(input); i++ {
    blob := input[i]

    if strings.HasPrefix(blob, "--") {
      name := blob[2:]
      value := ""

      if strings.Contains(name, "=") {
        split := strings.SplitN(name, "=", 2)
        name = split[0]
        value = split[1]
      }

      opts[name] = value

    } else if strings.HasPrefix(blob, "-") {
      blob = blob[1:]

      if strings.ContainsAny(blob, "-=\"") {
        return nil, nil, fmt.Errorf("Invalid option blob: '%s'", input[i])
      }

80
      nameS := ""
81
      for _, name := range blob {
82 83
        nameS = string(name)
        opts[nameS] = ""
84 85
      }

86 87 88 89 90 91 92 93 94
      if nameS != "" {
        opt, ok := options[nameS]
        if ok && opt.Type != commands.Bool {
          i++
          if i <= len(input) {
            opts[nameS] = input[i]
          }
        }
      }
95 96

    } else {
97
      args = append(args, blob)
98 99 100
    }
  }

101
  return opts, args, nil
102
}