2013-05-29 22:58:46 +04:00
|
|
|
package commands
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2018-12-29 12:07:57 +03:00
|
|
|
"regexp"
|
2013-05-29 22:58:46 +04:00
|
|
|
"strings"
|
2014-04-13 07:44:07 +04:00
|
|
|
|
2020-04-17 02:02:37 +03:00
|
|
|
"github.com/github/hub/v2/utils"
|
2013-05-29 22:58:46 +04:00
|
|
|
)
|
|
|
|
|
2013-06-30 20:00:21 +04:00
|
|
|
var (
|
2019-03-18 14:27:19 +03:00
|
|
|
NameRe = `[\w.-]+`
|
2013-06-30 20:00:21 +04:00
|
|
|
OwnerRe = "[a-zA-Z0-9][a-zA-Z0-9-]*"
|
2019-03-18 14:27:19 +03:00
|
|
|
NameWithOwnerRe = fmt.Sprintf(`^(%s/)?%s$`, OwnerRe, NameRe)
|
2013-12-30 02:18:14 +04:00
|
|
|
|
|
|
|
CmdRunner = NewRunner()
|
2013-06-30 20:00:21 +04:00
|
|
|
)
|
|
|
|
|
2013-05-29 22:58:46 +04:00
|
|
|
type Command struct {
|
2019-01-18 06:03:58 +03:00
|
|
|
Run func(cmd *Command, args *Args)
|
2013-05-29 22:58:46 +04:00
|
|
|
|
2013-12-30 02:18:14 +04:00
|
|
|
Key string
|
2013-06-18 00:56:57 +04:00
|
|
|
Usage string
|
|
|
|
Long string
|
2019-01-18 04:59:25 +03:00
|
|
|
KnownFlags string
|
2013-06-18 00:56:57 +04:00
|
|
|
GitExtension bool
|
2013-12-29 09:24:08 +04:00
|
|
|
|
2019-01-18 04:27:38 +03:00
|
|
|
subCommands map[string]*Command
|
|
|
|
parentCommand *Command
|
2013-12-29 09:24:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Command) Call(args *Args) (err error) {
|
2015-01-13 09:13:41 +03:00
|
|
|
runCommand, err := c.lookupSubCommand(args)
|
2013-12-30 02:18:14 +04:00
|
|
|
if err != nil {
|
|
|
|
return
|
2013-12-29 09:24:08 +04:00
|
|
|
}
|
|
|
|
|
2013-12-30 02:44:09 +04:00
|
|
|
if !c.GitExtension {
|
|
|
|
err = runCommand.parseArguments(args)
|
|
|
|
if err != nil {
|
|
|
|
return
|
2013-12-30 02:18:14 +04:00
|
|
|
}
|
2013-12-29 09:24:08 +04:00
|
|
|
}
|
|
|
|
|
2013-12-30 02:44:09 +04:00
|
|
|
runCommand.Run(runCommand, args)
|
|
|
|
|
2013-12-29 09:24:08 +04:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-01-16 06:19:49 +03:00
|
|
|
type ErrHelp struct {
|
|
|
|
err string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e ErrHelp) Error() string {
|
|
|
|
return e.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Command) parseArguments(args *Args) error {
|
2019-01-18 06:03:58 +03:00
|
|
|
knownFlags := c.KnownFlags
|
|
|
|
if knownFlags == "" {
|
|
|
|
knownFlags = c.Long
|
2019-01-16 06:19:49 +03:00
|
|
|
}
|
2019-01-18 06:03:58 +03:00
|
|
|
args.Flag = utils.NewArgsParserWithUsage("-h, --help\n" + knownFlags)
|
2019-01-16 06:19:49 +03:00
|
|
|
|
2020-03-21 01:30:49 +03:00
|
|
|
rest, err := args.Flag.Parse(args.Params)
|
|
|
|
if err != nil {
|
2019-01-16 06:19:49 +03:00
|
|
|
return fmt.Errorf("%s\n%s", err, c.Synopsis())
|
2013-12-29 09:24:08 +04:00
|
|
|
}
|
2020-03-21 01:30:49 +03:00
|
|
|
if args.Flag.Bool("--help") {
|
|
|
|
return &ErrHelp{err: c.Synopsis()}
|
|
|
|
}
|
|
|
|
args.Params = rest
|
|
|
|
args.Terminator = args.Flag.HasTerminated
|
|
|
|
return nil
|
2013-12-29 09:24:08 +04:00
|
|
|
}
|
|
|
|
|
2013-12-30 02:18:14 +04:00
|
|
|
func (c *Command) Use(subCommand *Command) {
|
2013-12-29 09:24:08 +04:00
|
|
|
if c.subCommands == nil {
|
|
|
|
c.subCommands = make(map[string]*Command)
|
|
|
|
}
|
2013-12-30 02:18:14 +04:00
|
|
|
c.subCommands[subCommand.Name()] = subCommand
|
2019-01-18 04:27:38 +03:00
|
|
|
subCommand.parentCommand = c
|
2013-05-29 22:58:46 +04:00
|
|
|
}
|
|
|
|
|
2019-01-18 03:34:25 +03:00
|
|
|
func (c *Command) UsageError(msg string) error {
|
|
|
|
nl := ""
|
|
|
|
if msg != "" {
|
|
|
|
nl = "\n"
|
|
|
|
}
|
|
|
|
return fmt.Errorf("%s%s%s", msg, nl, c.Synopsis())
|
|
|
|
}
|
|
|
|
|
2016-01-24 11:47:17 +03:00
|
|
|
func (c *Command) Synopsis() string {
|
|
|
|
lines := []string{}
|
|
|
|
usagePrefix := "Usage:"
|
2019-01-18 04:27:38 +03:00
|
|
|
usageStr := c.Usage
|
|
|
|
if usageStr == "" && c.parentCommand != nil {
|
|
|
|
usageStr = c.parentCommand.Usage
|
|
|
|
}
|
2013-12-30 02:18:14 +04:00
|
|
|
|
2019-01-18 04:27:38 +03:00
|
|
|
for _, line := range strings.Split(usageStr, "\n") {
|
2016-01-24 11:47:17 +03:00
|
|
|
if line != "" {
|
|
|
|
usage := fmt.Sprintf("%s hub %s", usagePrefix, line)
|
|
|
|
usagePrefix = " "
|
|
|
|
lines = append(lines, usage)
|
|
|
|
}
|
2013-12-29 09:58:29 +04:00
|
|
|
}
|
2016-01-24 11:47:17 +03:00
|
|
|
return strings.Join(lines, "\n")
|
2013-12-30 02:18:14 +04:00
|
|
|
}
|
|
|
|
|
2016-01-24 11:47:17 +03:00
|
|
|
func (c *Command) HelpText() string {
|
2018-12-29 12:07:57 +03:00
|
|
|
usage := strings.Replace(c.Usage, "-^", "`-^`", 1)
|
|
|
|
usageRe := regexp.MustCompile(`(?m)^([a-z-]+)(.*)$`)
|
|
|
|
usage = usageRe.ReplaceAllString(usage, "`hub $1`$2 ")
|
|
|
|
usage = strings.TrimSpace(usage)
|
|
|
|
|
|
|
|
var desc string
|
|
|
|
long := strings.TrimSpace(c.Long)
|
|
|
|
if lines := strings.Split(long, "\n"); len(lines) > 1 {
|
|
|
|
desc = lines[0]
|
|
|
|
long = strings.Join(lines[1:], "\n")
|
|
|
|
}
|
|
|
|
|
2019-06-26 13:34:29 +03:00
|
|
|
long = strings.Replace(long, "''", "`", -1)
|
2018-12-29 12:07:57 +03:00
|
|
|
headingRe := regexp.MustCompile(`(?m)^(## .+):$`)
|
|
|
|
long = headingRe.ReplaceAllString(long, "$1")
|
|
|
|
|
|
|
|
indentRe := regexp.MustCompile(`(?m)^\t`)
|
|
|
|
long = indentRe.ReplaceAllLiteralString(long, "")
|
|
|
|
definitionListRe := regexp.MustCompile(`(?m)^(\* )?([^#\s][^\n]*?):?\n\t`)
|
|
|
|
long = definitionListRe.ReplaceAllString(long, "$2\n:\t")
|
|
|
|
|
|
|
|
return fmt.Sprintf("hub-%s(1) -- %s\n===\n\n## Synopsis\n\n%s\n%s", c.Name(), desc, usage, long)
|
2013-12-14 19:22:23 +04:00
|
|
|
}
|
|
|
|
|
2013-05-29 22:58:46 +04:00
|
|
|
func (c *Command) Name() string {
|
2013-12-30 02:18:14 +04:00
|
|
|
if c.Key != "" {
|
|
|
|
return c.Key
|
2013-05-29 22:58:46 +04:00
|
|
|
}
|
2016-01-30 12:05:06 +03:00
|
|
|
usageLine := strings.Split(strings.TrimSpace(c.Usage), "\n")[0]
|
|
|
|
return strings.Split(usageLine, " ")[0]
|
2013-05-29 22:58:46 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Command) Runnable() bool {
|
|
|
|
return c.Run != nil
|
|
|
|
}
|
|
|
|
|
2015-01-13 09:13:41 +03:00
|
|
|
func (c *Command) lookupSubCommand(args *Args) (runCommand *Command, err error) {
|
2013-12-30 02:18:14 +04:00
|
|
|
if len(c.subCommands) > 0 && args.HasSubcommand() {
|
|
|
|
subCommandName := args.FirstParam()
|
|
|
|
if subCommand, ok := c.subCommands[subCommandName]; ok {
|
|
|
|
runCommand = subCommand
|
|
|
|
args.Params = args.Params[1:]
|
|
|
|
} else {
|
2016-01-24 11:47:17 +03:00
|
|
|
err = fmt.Errorf("error: Unknown subcommand: %s", subCommandName)
|
2013-12-30 02:18:14 +04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
runCommand = c
|
|
|
|
}
|
2013-12-29 09:58:29 +04:00
|
|
|
|
2013-12-30 02:18:14 +04:00
|
|
|
return
|
2013-12-29 09:58:29 +04:00
|
|
|
}
|