示例#1
0
// SubCommands provides support for git subcommands style command handling.
func SubCommands(name, version string, commands map[string]func([]string, string), commandsUsage map[string]string, additional ...string) {

	var commandNames, helpCommands []string
	var complete bool
	var mainUsage string

	callCommand := func(command string, args []string, complete bool) {
		var findexe bool
		if command[0] == '-' {
			args[0] = name
		} else {
			args[0] = fmt.Sprintf("%s %s", name, command)
			findexe = true
		}
		if handler, ok := commands[command]; ok {
			handler(args, commandsUsage[command])
		} else if findexe {

			exe := fmt.Sprintf("%s-%s", strings.Replace(name, " ", "-", -1), command)
			exePath, err := exec.LookPath(exe)
			if err != nil {
				exit("ERROR: Couldn't find '%s'\n", exe)
			}

			args[0] = exe
			process, err := os.StartProcess(exePath, args,
				&os.ProcAttr{
					Dir:   ".",
					Env:   os.Environ(),
					Files: []*os.File{nil, os.Stdout, os.Stderr},
				})

			if err != nil {
				exit(fmt.Sprintf("ERROR: %s: %s\n", exe, err))
			}

			_, err = process.Wait()
			if err != nil {
				exit(fmt.Sprintf("ERROR: %s: %s\n", exe, err))
			}

		} else {
			exit(fmt.Sprintf("%s: error: no such option: %s\n", name, command))
		}
		os.Exit(0)
	}

	if _, ok := commands["help"]; !ok {
		commands["help"] = func(args []string, usage string) {

			opts := New(mainUsage)
			opts.ParseHelp = false
			opts.Completer = ListCompleter(helpCommands...)
			helpArgs := opts.Parse(args)

			if len(helpArgs) == 0 {
				fmt.Print(mainUsage)
				return
			}

			if len(helpArgs) != 1 {
				exit("ERROR: Unknown command '%s'\n", strings.Join(helpArgs, " "))
			}

			command := helpArgs[0]
			if command == "help" {
				fmt.Print(mainUsage)
			} else {
				if !complete {
					argLen := len(os.Args)
					os.Args[argLen-2], os.Args[argLen-1] = os.Args[argLen-1], "--help"
				}
				callCommand(command, []string{name, "--help"}, false)
			}

		}
		commands["-h"] = commands["help"]
		commands["--help"] = commands["help"]
	}

	if len(version) != 0 {
		if _, ok := commands["version"]; !ok {
			commands["version"] = func(args []string, usage string) {
				opts := New(fmt.Sprintf("Usage: %s version\n\n    %s\n", name, usage))
				opts.Parse(args)
				fmt.Printf("%s\n", version)
				return
			}
			commands["-v"] = commands["version"]
			commands["--version"] = commands["version"]
		}
	}

	commandNames = make([]string, len(commands))
	helpCommands = make([]string, len(commands))
	i, j := 0, 0

	for name, _ := range commands {
		if !strings.HasPrefix(name, "-") {
			commandNames[i] = name
			i += 1
			if name != "help" {
				helpCommands[j] = name
				j += 1
			}
		}
	}

	usageKeys := structure.SortedKeys(commandsUsage)
	padding := 10

	for _, key := range usageKeys {
		if len(key) > padding {
			padding = len(key)
		}
	}

	var suffix string

	additionalItems := len(additional)
	if additionalItems == 0 {
		suffix = ""
	} else if additionalItems == 1 {
		mainUsage = additional[0] + "\n"
		suffix = ""
	} else {
		mainUsage = additional[0] + "\n"
		suffix = "\n" + additional[1]
	}

	mainUsage += fmt.Sprintf("Usage: %s <command> [options]\n\nCommands:\n\n", name)
	usageLine := fmt.Sprintf("    %%-%ds %%s\n", padding)

	for _, key := range usageKeys {
		mainUsage += fmt.Sprintf(usageLine, key, commandsUsage[key])
	}

	mainUsage += suffix
	mainUsage += fmt.Sprintf(
		"\nSee `%s help <command>` for more info on a specific command.\n", name)

	complete, words, compWord, prefix := getCompletionData()
	baseLength := len(strings.Split(name, " "))
	args := os.Args

	if complete && len(args) == 1 {
		if compWord == baseLength {
			completions := make([]string, 0)
			for _, cmd := range commandNames {
				if strings.HasPrefix(cmd, prefix) {
					completions = append(completions, cmd)
				}
			}
			fmt.Print(strings.Join(completions, " "))
			os.Exit(1)
		} else {
			command := words[baseLength]
			args = []string{name}
			callCommand(command, args, true)
		}
	}

	args = args[baseLength:]

	if len(args) == 0 {
		fmt.Print(mainUsage)
		os.Exit(0)
	}

	command := args[0]
	args[0] = name

	callCommand(command, args, false)

}
示例#2
0
文件: optparse.go 项目: runique/golly
// Commands provides support for git subcommands style command handling.
func Commands(name string, version interface{}, commands map[string]func([]string, string), commandsUsage map[string]string, additional ...string) {

	var commandNames, helpCommands []string
	var complete bool
	var mainUsage string

	callCommand := func(command string, args []string, complete bool) {
		var findexe bool
		if command[0] == '-' {
			args[0] = name
		} else {
			args[0] = fmt.Sprintf("%s %s", name, command)
			findexe = true
		}
		if handler, ok := commands[command]; ok {
			handler(args, commandsUsage[command])
		} else if findexe {

			exe := fmt.Sprintf("%s-%s", strings.Replace(name, " ", "-", -1), command)
			exePath, err := exec.LookPath(exe)
			if err != nil {
				exit("%s: '%s' is not a valid command: see '%s help'", name, command, name)
			}

			args[0] = exe
			process, err := os.StartProcess(exePath, args,
				&os.ProcAttr{
					Dir:   ".",
					Env:   os.Environ(),
					Files: []*os.File{nil, os.Stdout, os.Stderr},
				})

			if err != nil {
				exit("%s: %s", exe, err)
			}

			_, err = process.Wait()
			if err != nil {
				exit("%s: %s", exe, err)
			}

		} else {
			exit(fmt.Sprintf("%s: no such option: %s", name, command))
		}
		process.Exit(0)
	}

	if _, ok := commands["help"]; !ok {
		commands["help"] = func(args []string, usage string) {

			opts := New(mainUsage)
			opts.ParseHelp = false
			opts.Completer = ListCompleter(helpCommands)
			helpArgs := opts.Parse(args)

			if len(helpArgs) == 0 {
				fmt.Print(mainUsage)
				process.Exit(1)
			}

			if len(helpArgs) != 1 {
				exit("%s: invalid help option: '%s'", name, strings.Join(helpArgs, " "))
			}

			command := helpArgs[0]
			if command == "help" {
				exit("%s: invalid help command on help", name)
			} else {
				if !complete {
					argLen := len(os.Args)
					os.Args[argLen-2], os.Args[argLen-1] = os.Args[argLen-1], "--help"
				}
				callCommand(command, []string{name, "--help"}, false)
			}

			process.Exit(1)

		}
		commands["-h"] = commands["help"]
		commands["--help"] = commands["help"]
	}

	var setVersion bool
	var versionFunc func() string

	if versionString, found := version.(string); found {
		if len(versionString) != 0 {
			setVersion = true
			versionFunc = func() string {
				return versionString
			}
		}
	} else if versionFunc, found = version.(func() string); found {
		setVersion = true
	}

	if _, ok := commands["version"]; !ok && setVersion {
		commands["version"] = func(args []string, usage string) {
			if usage == "" {
				usage = fmt.Sprintf("  Show the %s version information.", name)
			}
			opts := New(fmt.Sprintf("Usage: %s version\n\n%s\n", name, usage))
			opts.HideHelpOpt = true
			opts.Parse(args)
			fmt.Printf("%s\n", versionFunc())
			return
		}
		commands["-v"] = commands["version"]
		commands["--version"] = commands["version"]
	}

	commandNames = make([]string, len(commands))
	helpCommands = make([]string, len(commands))
	i, j := 0, 0

	for name, _ := range commands {
		if !strings.HasPrefix(name, "-") {
			commandNames[i] = name
			i += 1
			if name != "help" {
				helpCommands[j] = name
				j += 1
			}
		}
	}

	usageKeys := structure.SortedKeys(commandsUsage)
	padding := 10

	for _, key := range usageKeys {
		if len(key) > padding {
			padding = len(key)
		}
	}

	var prefix string
	var suffix string

	lenExtra := len(additional)
	if lenExtra >= 1 {
		prefix = additional[0] + "\n\n"
	}
	if lenExtra >= 2 {
		suffix = additional[1] + "\n"
	}
	if lenExtra >= 3 {
		mainUsage = additional[2] + "\n"
	}

	mainUsage += fmt.Sprintf("Usage: %s COMMAND [OPTIONS]\n\n%sCommands:\n\n", name, prefix)
	usageLine := fmt.Sprintf("    %%-%ds %%s\n", padding)

	for _, key := range usageKeys {
		mainUsage += fmt.Sprintf(usageLine, key, commandsUsage[key])
	}

	mainUsage += fmt.Sprintf(
		`
Run "%s help <command>" for more info on a specific command.
%s`, name, suffix)

	complete, words, compWord, prefix := getCompletionData()
	baseLength := len(strings.Split(name, " "))
	args := os.Args

	if complete && len(args) == 1 {
		if compWord == baseLength {
			completions := make([]string, 0)
			for _, cmd := range commandNames {
				if strings.HasPrefix(cmd, prefix) {
					completions = append(completions, cmd)
				}
			}
			fmt.Print(strings.Join(completions, " "))
			process.Exit(1)
		} else {
			command := words[baseLength]
			args = []string{name}
			callCommand(command, args, true)
		}
	}

	args = args[baseLength:]

	if len(args) == 0 {
		fmt.Print(mainUsage)
		process.Exit(1)
	}

	command := args[0]
	args[0] = name

	callCommand(command, args, false)

}