Beispiel #1
0
func Example() {
	type Inventory struct {
		Item string
		positional.Optional
		Count int
	}

	porch := Inventory{}
	err := positional.Parse(&porch, []string{"cat", "3"})
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	fmt.Printf("You have %d %s(s) on the porch\n", porch.Count, porch.Item)

	house := Inventory{
		Count: 1,
	}
	err = positional.Parse(&house, []string{"dog"})
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	fmt.Printf("You have %d %s(s) in the house\n", house.Count, house.Item)

	// Output:
	// You have 3 cat(s) on the porch
	// You have 1 dog(s) in the house
}
Beispiel #2
0
func TestParseEmpty(t *testing.T) {
	var args struct {
	}
	err := positional.Parse(&args, []string{})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
}
Beispiel #3
0
func TestParseMandatory(t *testing.T) {
	var args struct {
		Foo string
	}
	err := positional.Parse(&args, []string{"one"})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if g, e := args.Foo, "one"; g != e {
		t.Errorf("unexpected value for Foo: %q != %q", g, e)
	}
}
Beispiel #4
0
func TestParseInt(t *testing.T) {
	var args struct {
		Foo int
	}
	err := positional.Parse(&args, []string{"1"})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if g, e := args.Foo, 1; g != e {
		t.Errorf("unexpected value for Foo: %d != %d", g, e)
	}
}
Beispiel #5
0
func TestParseOptionalMissing(t *testing.T) {
	var args struct {
		positional.Optional
		Foo string
	}
	err := positional.Parse(&args, []string{})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if g, e := args.Foo, ""; g != e {
		t.Errorf("unexpected value for Foo: %q != %q", g, e)
	}
}
Beispiel #6
0
func TestParseBothMissingOptional(t *testing.T) {
	var args struct {
		Foo string
		positional.Optional
		Bar string
	}
	err := positional.Parse(&args, []string{"one"})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if g, e := args.Foo, "one"; g != e {
		t.Errorf("unexpected value for Foo: %q != %q", g, e)
	}
	if g, e := args.Bar, ""; g != e {
		t.Errorf("unexpected value for Bar: %q != %q", g, e)
	}
}
Beispiel #7
0
func TestParseMandatoryMissing(t *testing.T) {
	var args struct {
		Foo string
	}
	err := positional.Parse(&args, []string{})
	if err == nil {
		t.Fatalf("expected an error")
	}
	if _, ok := err.(positional.ErrMissingMandatoryArg); !ok {
		t.Errorf("unexpected error type: %T", err)
	}
	if err.Error() != "missing mandatory argument: FOO" {
		t.Errorf("unexpected error message: %q", err.Error())
	}
	if g, e := args.Foo, ""; g != e {
		t.Errorf("unexpected value for Foo: %q != %q", g, e)
	}
}
Beispiel #8
0
func TestParseTooMany(t *testing.T) {
	var args struct {
		Foo string
	}
	err := positional.Parse(&args, []string{"one", "two"})
	if err == nil {
		t.Fatalf("expected an error")
	}
	if _, ok := err.(positional.ErrTooManyArgs); !ok {
		t.Errorf("unexpected error type: %T", err)
	}
	if err.Error() != "too many arguments" {
		t.Errorf("unexpected error message: %q", err.Error())
	}
	if g, e := args.Foo, "one"; g != e {
		t.Errorf("unexpected value for Foo: %q != %q", g, e)
	}
}
Beispiel #9
0
func TestParseMandatoryPlural(t *testing.T) {
	var args struct {
		Foo []string
	}
	err := positional.Parse(&args, []string{"one", "two"})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if g, e := len(args.Foo), 2; g != e {
		t.Errorf("unexpected length for Foo: %d != %d", g, e)
	}
	if g, e := args.Foo[0], "one"; g != e {
		t.Errorf("unexpected value for Foo[0]: %q != %q", g, e)
	}
	if g, e := args.Foo[1], "two"; g != e {
		t.Errorf("unexpected value for Foo[1]: %q != %q", g, e)
	}
}
Beispiel #10
0
// Parse examines the command line from args based on the top-level
// command cmd with the given name. It returns a Result that describes
// the result of the parsing, and an error. Result is valid even when
// error is not nil.
func (s *Shell) Parse(cmd interface{}, name string, args []string) (Result, error) {
	result := Result{
		parser: s,
	}
	pkg := pkgName(cmd)
	result.add(name, pkg, cmd)
	if pkg == "" {
		return result, fmt.Errorf("dispatch called for unnamed type: %v", cmd)
	}

dispatch:
	for {

		// parse flags
		parser, ok := cmd.(FlagParser)
		if !ok {
			parser = &flag.FlagSet{}
		}

		if fl, ok := parser.(FlagSetter); ok {
			// we provide our own usage text, so this FlagSet name is only
			// used in programmer error related messages
			fl.Init(pkg, flag.ContinueOnError)

			// flag has a bad habit of polluting stderr in .Parse() *and*
			// getting the formatting wrong (e.g. we want to include
			// command name as prefix), plus we want to control error &
			// usage output to unify all the possible error sources;
			// silence Parse and output the error and usage later, in the
			// caller
			fl.SetOutput(ioutil.Discard)
		}

		err := parser.Parse(args)
		if err != nil {
			return result, err
		}
		args = parser.Args()

		// see if we have positional args to parse
		if cmd != nil {
			argsField := reflect.ValueOf(cmd).Elem().FieldByName("Arguments")
			if argsField.IsValid() {
				argsI := argsField.Addr().Interface()
				err := positional.Parse(argsI, args)
				if err != nil {
					return result, err
				}
			}
		}

		var hasSub bool
		for _, subcmd := range s.listSubcommands(pkg) {
			if len(args) > 0 && subcmd.pkg == pkg+"/"+args[0] {
				// exact match
				pkg = subcmd.pkg
				cmd = subcmd.cmd
				result.add(args[0], pkg, cmd)
				args = args[1:]
				continue dispatch
			}

			if len(args) > 0 && strings.HasPrefix(subcmd.pkg, pkg+"/"+args[0]+"/") {
				// step in the right direction
				pkg = pkg + "/" + args[0]
				cmd = nil
				result.add(args[0], pkg, cmd)
				args = args[1:]
				continue dispatch
			}

			if strings.HasPrefix(subcmd.pkg, pkg+"/") {
				_, runnable := cmd.(Runner)
				if len(args) == 0 && !runnable {
					// we have subcommands but no args
					return result, ErrMissingCommand{}
				}

				hasSub = true
			}

		}

		if len(args) > 0 && hasSub {
			return result, fmt.Errorf("command not found: %v", args[0])
		}
		break
	}

	return result, nil
}