parse.go 2.12 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 17 18 19 20 21
  options, err := root.GetOptions(path)
  if err != nil {
    return nil, nil, nil, err
  }

  opts, args, err := parseOptions(input, options)
22 23 24 25 26
  if err != nil {
    return nil, nil, nil, err
  }

  return path, args, opts, nil
27 28
}

29
// parsePath gets the command path from the command line input
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
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
}

50
// parseOptions parses the raw string values of the given options
51
// returns the parsed options as strings, along with the CLI args
52
func parseOptions(input []string, options map[string]commands.Option) (map[string]string, []string, error) {
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
}