* Use vendored go-swagger * vendor go-swagger * revert un wanteed change * remove un-needed GO111MODULE * Update Makefile Co-Authored-By: techknowlogick <matti@mdranta.net>
		
			
				
	
	
		
			492 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			492 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
| // Copyright 2012 Jesse van den Kieboom. All rights reserved.
 | |
| // Use of this source code is governed by a BSD-style
 | |
| // license that can be found in the LICENSE file.
 | |
| 
 | |
| package flags
 | |
| 
 | |
| import (
 | |
| 	"bufio"
 | |
| 	"bytes"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"runtime"
 | |
| 	"strings"
 | |
| 	"unicode/utf8"
 | |
| )
 | |
| 
 | |
| type alignmentInfo struct {
 | |
| 	maxLongLen      int
 | |
| 	hasShort        bool
 | |
| 	hasValueName    bool
 | |
| 	terminalColumns int
 | |
| 	indent          bool
 | |
| }
 | |
| 
 | |
| const (
 | |
| 	paddingBeforeOption                 = 2
 | |
| 	distanceBetweenOptionAndDescription = 2
 | |
| )
 | |
| 
 | |
| func (a *alignmentInfo) descriptionStart() int {
 | |
| 	ret := a.maxLongLen + distanceBetweenOptionAndDescription
 | |
| 
 | |
| 	if a.hasShort {
 | |
| 		ret += 2
 | |
| 	}
 | |
| 
 | |
| 	if a.maxLongLen > 0 {
 | |
| 		ret += 4
 | |
| 	}
 | |
| 
 | |
| 	if a.hasValueName {
 | |
| 		ret += 3
 | |
| 	}
 | |
| 
 | |
| 	return ret
 | |
| }
 | |
| 
 | |
| func (a *alignmentInfo) updateLen(name string, indent bool) {
 | |
| 	l := utf8.RuneCountInString(name)
 | |
| 
 | |
| 	if indent {
 | |
| 		l = l + 4
 | |
| 	}
 | |
| 
 | |
| 	if l > a.maxLongLen {
 | |
| 		a.maxLongLen = l
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (p *Parser) getAlignmentInfo() alignmentInfo {
 | |
| 	ret := alignmentInfo{
 | |
| 		maxLongLen:      0,
 | |
| 		hasShort:        false,
 | |
| 		hasValueName:    false,
 | |
| 		terminalColumns: getTerminalColumns(),
 | |
| 	}
 | |
| 
 | |
| 	if ret.terminalColumns <= 0 {
 | |
| 		ret.terminalColumns = 80
 | |
| 	}
 | |
| 
 | |
| 	var prevcmd *Command
 | |
| 
 | |
| 	p.eachActiveGroup(func(c *Command, grp *Group) {
 | |
| 		if c != prevcmd {
 | |
| 			for _, arg := range c.args {
 | |
| 				ret.updateLen(arg.Name, c != p.Command)
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		for _, info := range grp.options {
 | |
| 			if !info.canCli() {
 | |
| 				continue
 | |
| 			}
 | |
| 
 | |
| 			if info.ShortName != 0 {
 | |
| 				ret.hasShort = true
 | |
| 			}
 | |
| 
 | |
| 			if len(info.ValueName) > 0 {
 | |
| 				ret.hasValueName = true
 | |
| 			}
 | |
| 
 | |
| 			l := info.LongNameWithNamespace() + info.ValueName
 | |
| 
 | |
| 			if len(info.Choices) != 0 {
 | |
| 				l += "[" + strings.Join(info.Choices, "|") + "]"
 | |
| 			}
 | |
| 
 | |
| 			ret.updateLen(l, c != p.Command)
 | |
| 		}
 | |
| 	})
 | |
| 
 | |
| 	return ret
 | |
| }
 | |
| 
 | |
| func wrapText(s string, l int, prefix string) string {
 | |
| 	var ret string
 | |
| 
 | |
| 	if l < 10 {
 | |
| 		l = 10
 | |
| 	}
 | |
| 
 | |
| 	// Basic text wrapping of s at spaces to fit in l
 | |
| 	lines := strings.Split(s, "\n")
 | |
| 
 | |
| 	for _, line := range lines {
 | |
| 		var retline string
 | |
| 
 | |
| 		line = strings.TrimSpace(line)
 | |
| 
 | |
| 		for len(line) > l {
 | |
| 			// Try to split on space
 | |
| 			suffix := ""
 | |
| 
 | |
| 			pos := strings.LastIndex(line[:l], " ")
 | |
| 
 | |
| 			if pos < 0 {
 | |
| 				pos = l - 1
 | |
| 				suffix = "-\n"
 | |
| 			}
 | |
| 
 | |
| 			if len(retline) != 0 {
 | |
| 				retline += "\n" + prefix
 | |
| 			}
 | |
| 
 | |
| 			retline += strings.TrimSpace(line[:pos]) + suffix
 | |
| 			line = strings.TrimSpace(line[pos:])
 | |
| 		}
 | |
| 
 | |
| 		if len(line) > 0 {
 | |
| 			if len(retline) != 0 {
 | |
| 				retline += "\n" + prefix
 | |
| 			}
 | |
| 
 | |
| 			retline += line
 | |
| 		}
 | |
| 
 | |
| 		if len(ret) > 0 {
 | |
| 			ret += "\n"
 | |
| 
 | |
| 			if len(retline) > 0 {
 | |
| 				ret += prefix
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		ret += retline
 | |
| 	}
 | |
| 
 | |
| 	return ret
 | |
| }
 | |
| 
 | |
| func (p *Parser) writeHelpOption(writer *bufio.Writer, option *Option, info alignmentInfo) {
 | |
| 	line := &bytes.Buffer{}
 | |
| 
 | |
| 	prefix := paddingBeforeOption
 | |
| 
 | |
| 	if info.indent {
 | |
| 		prefix += 4
 | |
| 	}
 | |
| 
 | |
| 	if option.Hidden {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	line.WriteString(strings.Repeat(" ", prefix))
 | |
| 
 | |
| 	if option.ShortName != 0 {
 | |
| 		line.WriteRune(defaultShortOptDelimiter)
 | |
| 		line.WriteRune(option.ShortName)
 | |
| 	} else if info.hasShort {
 | |
| 		line.WriteString("  ")
 | |
| 	}
 | |
| 
 | |
| 	descstart := info.descriptionStart() + paddingBeforeOption
 | |
| 
 | |
| 	if len(option.LongName) > 0 {
 | |
| 		if option.ShortName != 0 {
 | |
| 			line.WriteString(", ")
 | |
| 		} else if info.hasShort {
 | |
| 			line.WriteString("  ")
 | |
| 		}
 | |
| 
 | |
| 		line.WriteString(defaultLongOptDelimiter)
 | |
| 		line.WriteString(option.LongNameWithNamespace())
 | |
| 	}
 | |
| 
 | |
| 	if option.canArgument() {
 | |
| 		line.WriteRune(defaultNameArgDelimiter)
 | |
| 
 | |
| 		if len(option.ValueName) > 0 {
 | |
| 			line.WriteString(option.ValueName)
 | |
| 		}
 | |
| 
 | |
| 		if len(option.Choices) > 0 {
 | |
| 			line.WriteString("[" + strings.Join(option.Choices, "|") + "]")
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	written := line.Len()
 | |
| 	line.WriteTo(writer)
 | |
| 
 | |
| 	if option.Description != "" {
 | |
| 		dw := descstart - written
 | |
| 		writer.WriteString(strings.Repeat(" ", dw))
 | |
| 
 | |
| 		var def string
 | |
| 
 | |
| 		if len(option.DefaultMask) != 0 {
 | |
| 			if option.DefaultMask != "-" {
 | |
| 				def = option.DefaultMask
 | |
| 			}
 | |
| 		} else {
 | |
| 			def = option.defaultLiteral
 | |
| 		}
 | |
| 
 | |
| 		var envDef string
 | |
| 		if option.EnvDefaultKey != "" {
 | |
| 			var envPrintable string
 | |
| 			if runtime.GOOS == "windows" {
 | |
| 				envPrintable = "%" + option.EnvDefaultKey + "%"
 | |
| 			} else {
 | |
| 				envPrintable = "$" + option.EnvDefaultKey
 | |
| 			}
 | |
| 			envDef = fmt.Sprintf(" [%s]", envPrintable)
 | |
| 		}
 | |
| 
 | |
| 		var desc string
 | |
| 
 | |
| 		if def != "" {
 | |
| 			desc = fmt.Sprintf("%s (default: %v)%s", option.Description, def, envDef)
 | |
| 		} else {
 | |
| 			desc = option.Description + envDef
 | |
| 		}
 | |
| 
 | |
| 		writer.WriteString(wrapText(desc,
 | |
| 			info.terminalColumns-descstart,
 | |
| 			strings.Repeat(" ", descstart)))
 | |
| 	}
 | |
| 
 | |
| 	writer.WriteString("\n")
 | |
| }
 | |
| 
 | |
| func maxCommandLength(s []*Command) int {
 | |
| 	if len(s) == 0 {
 | |
| 		return 0
 | |
| 	}
 | |
| 
 | |
| 	ret := len(s[0].Name)
 | |
| 
 | |
| 	for _, v := range s[1:] {
 | |
| 		l := len(v.Name)
 | |
| 
 | |
| 		if l > ret {
 | |
| 			ret = l
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return ret
 | |
| }
 | |
| 
 | |
| // WriteHelp writes a help message containing all the possible options and
 | |
| // their descriptions to the provided writer. Note that the HelpFlag parser
 | |
| // option provides a convenient way to add a -h/--help option group to the
 | |
| // command line parser which will automatically show the help messages using
 | |
| // this method.
 | |
| func (p *Parser) WriteHelp(writer io.Writer) {
 | |
| 	if writer == nil {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	wr := bufio.NewWriter(writer)
 | |
| 	aligninfo := p.getAlignmentInfo()
 | |
| 
 | |
| 	cmd := p.Command
 | |
| 
 | |
| 	for cmd.Active != nil {
 | |
| 		cmd = cmd.Active
 | |
| 	}
 | |
| 
 | |
| 	if p.Name != "" {
 | |
| 		wr.WriteString("Usage:\n")
 | |
| 		wr.WriteString(" ")
 | |
| 
 | |
| 		allcmd := p.Command
 | |
| 
 | |
| 		for allcmd != nil {
 | |
| 			var usage string
 | |
| 
 | |
| 			if allcmd == p.Command {
 | |
| 				if len(p.Usage) != 0 {
 | |
| 					usage = p.Usage
 | |
| 				} else if p.Options&HelpFlag != 0 {
 | |
| 					usage = "[OPTIONS]"
 | |
| 				}
 | |
| 			} else if us, ok := allcmd.data.(Usage); ok {
 | |
| 				usage = us.Usage()
 | |
| 			} else if allcmd.hasCliOptions() {
 | |
| 				usage = fmt.Sprintf("[%s-OPTIONS]", allcmd.Name)
 | |
| 			}
 | |
| 
 | |
| 			if len(usage) != 0 {
 | |
| 				fmt.Fprintf(wr, " %s %s", allcmd.Name, usage)
 | |
| 			} else {
 | |
| 				fmt.Fprintf(wr, " %s", allcmd.Name)
 | |
| 			}
 | |
| 
 | |
| 			if len(allcmd.args) > 0 {
 | |
| 				fmt.Fprintf(wr, " ")
 | |
| 			}
 | |
| 
 | |
| 			for i, arg := range allcmd.args {
 | |
| 				if i != 0 {
 | |
| 					fmt.Fprintf(wr, " ")
 | |
| 				}
 | |
| 
 | |
| 				name := arg.Name
 | |
| 
 | |
| 				if arg.isRemaining() {
 | |
| 					name = name + "..."
 | |
| 				}
 | |
| 
 | |
| 				if !allcmd.ArgsRequired {
 | |
| 					fmt.Fprintf(wr, "[%s]", name)
 | |
| 				} else {
 | |
| 					fmt.Fprintf(wr, "%s", name)
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if allcmd.Active == nil && len(allcmd.commands) > 0 {
 | |
| 				var co, cc string
 | |
| 
 | |
| 				if allcmd.SubcommandsOptional {
 | |
| 					co, cc = "[", "]"
 | |
| 				} else {
 | |
| 					co, cc = "<", ">"
 | |
| 				}
 | |
| 
 | |
| 				visibleCommands := allcmd.visibleCommands()
 | |
| 
 | |
| 				if len(visibleCommands) > 3 {
 | |
| 					fmt.Fprintf(wr, " %scommand%s", co, cc)
 | |
| 				} else {
 | |
| 					subcommands := allcmd.sortedVisibleCommands()
 | |
| 					names := make([]string, len(subcommands))
 | |
| 
 | |
| 					for i, subc := range subcommands {
 | |
| 						names[i] = subc.Name
 | |
| 					}
 | |
| 
 | |
| 					fmt.Fprintf(wr, " %s%s%s", co, strings.Join(names, " | "), cc)
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			allcmd = allcmd.Active
 | |
| 		}
 | |
| 
 | |
| 		fmt.Fprintln(wr)
 | |
| 
 | |
| 		if len(cmd.LongDescription) != 0 {
 | |
| 			fmt.Fprintln(wr)
 | |
| 
 | |
| 			t := wrapText(cmd.LongDescription,
 | |
| 				aligninfo.terminalColumns,
 | |
| 				"")
 | |
| 
 | |
| 			fmt.Fprintln(wr, t)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	c := p.Command
 | |
| 
 | |
| 	for c != nil {
 | |
| 		printcmd := c != p.Command
 | |
| 
 | |
| 		c.eachGroup(func(grp *Group) {
 | |
| 			first := true
 | |
| 
 | |
| 			// Skip built-in help group for all commands except the top-level
 | |
| 			// parser
 | |
| 			if grp.Hidden || (grp.isBuiltinHelp && c != p.Command) {
 | |
| 				return
 | |
| 			}
 | |
| 
 | |
| 			for _, info := range grp.options {
 | |
| 				if !info.canCli() || info.Hidden {
 | |
| 					continue
 | |
| 				}
 | |
| 
 | |
| 				if printcmd {
 | |
| 					fmt.Fprintf(wr, "\n[%s command options]\n", c.Name)
 | |
| 					aligninfo.indent = true
 | |
| 					printcmd = false
 | |
| 				}
 | |
| 
 | |
| 				if first && cmd.Group != grp {
 | |
| 					fmt.Fprintln(wr)
 | |
| 
 | |
| 					if aligninfo.indent {
 | |
| 						wr.WriteString("    ")
 | |
| 					}
 | |
| 
 | |
| 					fmt.Fprintf(wr, "%s:\n", grp.ShortDescription)
 | |
| 					first = false
 | |
| 				}
 | |
| 
 | |
| 				p.writeHelpOption(wr, info, aligninfo)
 | |
| 			}
 | |
| 		})
 | |
| 
 | |
| 		var args []*Arg
 | |
| 		for _, arg := range c.args {
 | |
| 			if arg.Description != "" {
 | |
| 				args = append(args, arg)
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if len(args) > 0 {
 | |
| 			if c == p.Command {
 | |
| 				fmt.Fprintf(wr, "\nArguments:\n")
 | |
| 			} else {
 | |
| 				fmt.Fprintf(wr, "\n[%s command arguments]\n", c.Name)
 | |
| 			}
 | |
| 
 | |
| 			descStart := aligninfo.descriptionStart() + paddingBeforeOption
 | |
| 
 | |
| 			for _, arg := range args {
 | |
| 				argPrefix := strings.Repeat(" ", paddingBeforeOption)
 | |
| 				argPrefix += arg.Name
 | |
| 
 | |
| 				if len(arg.Description) > 0 {
 | |
| 					argPrefix += ":"
 | |
| 					wr.WriteString(argPrefix)
 | |
| 
 | |
| 					// Space between "arg:" and the description start
 | |
| 					descPadding := strings.Repeat(" ", descStart-len(argPrefix))
 | |
| 					// How much space the description gets before wrapping
 | |
| 					descWidth := aligninfo.terminalColumns - 1 - descStart
 | |
| 					// Whitespace to which we can indent new description lines
 | |
| 					descPrefix := strings.Repeat(" ", descStart)
 | |
| 
 | |
| 					wr.WriteString(descPadding)
 | |
| 					wr.WriteString(wrapText(arg.Description, descWidth, descPrefix))
 | |
| 				} else {
 | |
| 					wr.WriteString(argPrefix)
 | |
| 				}
 | |
| 
 | |
| 				fmt.Fprintln(wr)
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		c = c.Active
 | |
| 	}
 | |
| 
 | |
| 	scommands := cmd.sortedVisibleCommands()
 | |
| 
 | |
| 	if len(scommands) > 0 {
 | |
| 		maxnamelen := maxCommandLength(scommands)
 | |
| 
 | |
| 		fmt.Fprintln(wr)
 | |
| 		fmt.Fprintln(wr, "Available commands:")
 | |
| 
 | |
| 		for _, c := range scommands {
 | |
| 			fmt.Fprintf(wr, "  %s", c.Name)
 | |
| 
 | |
| 			if len(c.ShortDescription) > 0 {
 | |
| 				pad := strings.Repeat(" ", maxnamelen-len(c.Name))
 | |
| 				fmt.Fprintf(wr, "%s  %s", pad, c.ShortDescription)
 | |
| 
 | |
| 				if len(c.Aliases) > 0 {
 | |
| 					fmt.Fprintf(wr, " (aliases: %s)", strings.Join(c.Aliases, ", "))
 | |
| 				}
 | |
| 
 | |
| 			}
 | |
| 
 | |
| 			fmt.Fprintln(wr)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	wr.Flush()
 | |
| }
 |