Example #1
0
func getCompletionData() (complete bool, words []string, compWord int, prefix string) {

	var err error

	autocomplete := os.Getenv("OPTPARSE_AUTO_COMPLETE")
	if autocomplete != "" {

		complete = true

		words, err = shlex.Split(os.Getenv("COMP_LINE"))
		if err != nil {
			exit("optparse: could not shlex autocompletion words: %s", err)
		}

		compWord, err = strconv.Atoi(os.Getenv("COMP_CWORD"))
		if err != nil {
			process.Exit(1)
		}

		if compWord > 0 {
			if compWord < len(words) {
				prefix = words[compWord]
			}
		}

	}

	return

}
Example #2
0
// 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)

}
Example #3
0
func exit(message string, v ...interface{}) {
	log.Errorf(message, v...)
	process.Exit(1)
}
Example #4
0
// Parse will parse the given args slice and try and define
// the defined options.
func (p *Parser) Parse(args []string) (remainder []string) {

	if p.ParseHelp && !p.helpAdded {
		description := p.HelpOptDescription
		if description == "" {
			description = "Show this help and exit"
		}
		if p.HideHelpOpt {
			p.Hidden()
		}
		p.Flags("-h", "--help").Bool(description)
		p.helpAdded = true
	}

	if p.ParseVersion && !p.versionAdded {
		description := p.VersionOptDescription
		if description == "" {
			description = "Show the version and exit"
		}
		if p.HideVersionOpt {
			p.Hidden()
		}
		p.Flags("-v", "--version").Bool(description)
		p.versionAdded = true
	}

	argLength := len(args) - 1
	complete, words, compWord, prefix := getCompletionData()

	// Command-line auto-completion support.
	if complete {

		seenLong := []string{}
		seenShort := []string{}

		subcommands, err := shlex.Split(args[0])
		if err != nil {
			process.Exit(1)
		}

		words = words[len(subcommands):]
		compWord -= len(subcommands)

		argWords := []string{}
		skipNext := false
		optCount := 0

		for _, word := range words {
			if skipNext {
				skipNext = false
				optCount += 1
				continue
			}
			if strings.HasPrefix(word, "--") && word != "--" {
				op, ok := p.long2options[word]
				if ok {
					seenLong = append(seenLong, op.longFlag)
					seenShort = append(seenShort, op.shortFlag)
					if op.label != "" {
						skipNext = true
					}
				}
				optCount += 1
			} else if strings.HasPrefix(word, "-") && !(word == "-" || word == "--") {
				op, ok := p.short2options[word]
				if ok {
					seenLong = append(seenLong, op.longFlag)
					seenShort = append(seenShort, op.shortFlag)
					if op.label != "" {
						skipNext = true
					}
				}
				optCount += 1
			} else {
				argWords = append(argWords, word)
				if p.haltFlagParsing {
					if p.haltFlagParsingString != "" {
						if word == p.haltFlagParsingString {
							process.Exit(1)
						}
					} else if (compWord - optCount) == p.haltFlagParsingN {
						process.Exit(1)
					}
				}
			}
		}

		// Pass to the shell completion if the previous word was a flag
		// expecting some parameter.
		if compWord >= 1 {
			var completer Completer
			prev := words[compWord-1]
			if prev != "--" && prev != "-" {
				if strings.HasPrefix(prev, "--") {
					op, ok := p.long2options[prev]
					if ok && op.label != "" {
						if op.completer == nil {
							process.Exit(1)
						} else {
							completer = op.completer
						}
					}
				} else if strings.HasPrefix(prev, "-") {
					op, ok := p.short2options[prev]
					if ok && op.label != "" {
						if op.completer == nil {
							process.Exit(1)
						} else {
							completer = op.completer
						}
					}
				}
			}
			if completer != nil {
				completions := make([]string, 0)
				for _, item := range completer.Complete(argWords, compWord) {
					if strings.HasPrefix(item, prefix) {
						completions = append(completions, item)
					}
				}
				fmt.Print(strings.Join(completions, " "))
				process.Exit(1)
			}
		}

		completions := make([]string, 0)

		if p.Completer != nil {
			for _, item := range p.Completer.Complete(argWords, compWord-optCount) {
				if strings.HasPrefix(item, prefix) {
					completions = append(completions, item)
				}
			}
		}

		for flag, op := range p.long2options {
			if !(contains(seenLong, op.longFlag) || contains(seenShort, op.shortFlag) || op.hidden) {
				if strings.HasPrefix(flag, prefix) {
					completions = append(completions, flag)
				}
			}
		}

		for flag, op := range p.short2options {
			if !(contains(seenLong, op.longFlag) || contains(seenShort, op.shortFlag) || op.hidden) {
				if strings.HasPrefix(flag, prefix) {
					completions = append(completions, flag)
				}
			}
		}

		fmt.Print(strings.Join(completions, " "))
		process.Exit(1)

	}

	if argLength == 0 {
		return
	}

	var op *option
	var ok bool

	idx := 1
	addNext := false

	for {
		arg := args[idx]
		noOpt := true
		if addNext {
			remainder = append(remainder, arg)
			if idx == argLength {
				break
			}
			idx += 1
			continue
		} else if strings.HasPrefix(arg, "--") && arg != "--" {
			op, ok = p.long2options[arg]
			if ok {
				noOpt = false
			}
		} else if strings.HasPrefix(arg, "-") && !(arg == "-" || arg == "--") {
			op, ok = p.short2options[arg]
			if ok {
				noOpt = false
			}
		} else {
			remainder = append(remainder, arg)
			if p.haltFlagParsing {
				if arg == p.haltFlagParsingString {
					addNext = true
				} else if len(remainder) == p.haltFlagParsingN {
					addNext = true
				}
			}
			if idx == argLength {
				break
			}
			idx += 1
			continue
		}
		if noOpt {
			exit("%s: no such option: %s", args[0], arg)
		}
		if op.label != "" {
			if idx == argLength {
				exit("%s: %s option requires an argument", args[0], arg)
			}
		}
		if op.valueType == boolValue {
			if op.longFlag == "--help" && p.ParseHelp {
				p.PrintUsage()
				process.Exit(1)
			} else if op.longFlag == "--version" && p.ParseVersion {
				fmt.Printf("%s\n", p.version())
				process.Exit(0)
			}
			v := op.value.(*bool)
			*v = true
			op.defined = true
			idx += 1
		} else if op.valueType == stringValue {
			if idx == argLength {
				exit("%s: no value specified for %s", args[0], arg)
			}
			v := op.value.(*string)
			*v = args[idx+1]
			op.defined = true
			idx += 2
		} else if op.valueType == intValue {
			if idx == argLength {
				exit("%s: no value specified for %s", args[0], arg)
			}
			intValue, err := strconv.Atoi(args[idx+1])
			if err != nil {
				exit("%s: couldn't convert %s value '%s' to an integer", args[0], arg, args[idx+1])
			}
			v := op.value.(*int)
			*v = intValue
			op.defined = true
			idx += 2
		}
		if idx > argLength {
			break
		}
	}

	for _, op := range p.options {
		if op.required && !op.defined {
			exit("%s: required: %s", args[0], op)
		}
	}

	return

}
Example #5
0
File: log.go Project: runique/golly
func Fatalf(format string, args ...interface{}) {
	root.log(fmt.Sprintf(format, args...), nil, true, false)
	process.Exit(1)
}
Example #6
0
File: log.go Project: runique/golly
func Fatal(args ...interface{}) {
	root.log(fmt.Sprint(args...), nil, true, false)
	process.Exit(1)
}