2019-09-04 13:53:54 -06:00
|
|
|
package flags
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
2021-04-22 18:08:53 -06:00
|
|
|
"os"
|
2019-09-04 13:53:54 -06:00
|
|
|
"runtime"
|
2021-04-22 18:08:53 -06:00
|
|
|
"strconv"
|
2019-09-04 13:53:54 -06:00
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2021-04-22 18:08:53 -06:00
|
|
|
func manQuoteLines(s string) string {
|
|
|
|
lines := strings.Split(s, "\n")
|
|
|
|
parts := []string{}
|
|
|
|
|
|
|
|
for _, line := range lines {
|
|
|
|
parts = append(parts, manQuote(line))
|
|
|
|
}
|
|
|
|
|
|
|
|
return strings.Join(parts, "\n")
|
|
|
|
}
|
|
|
|
|
2019-09-04 13:53:54 -06:00
|
|
|
func manQuote(s string) string {
|
|
|
|
return strings.Replace(s, "\\", "\\\\", -1)
|
|
|
|
}
|
|
|
|
|
2021-04-22 18:08:53 -06:00
|
|
|
func formatForMan(wr io.Writer, s string, quoter func(s string) string) {
|
2019-09-04 13:53:54 -06:00
|
|
|
for {
|
|
|
|
idx := strings.IndexRune(s, '`')
|
|
|
|
|
|
|
|
if idx < 0 {
|
2021-04-22 18:08:53 -06:00
|
|
|
fmt.Fprintf(wr, "%s", quoter(s))
|
2019-09-04 13:53:54 -06:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2021-04-22 18:08:53 -06:00
|
|
|
fmt.Fprintf(wr, "%s", quoter(s[:idx]))
|
2019-09-04 13:53:54 -06:00
|
|
|
|
|
|
|
s = s[idx+1:]
|
|
|
|
idx = strings.IndexRune(s, '\'')
|
|
|
|
|
|
|
|
if idx < 0 {
|
2021-04-22 18:08:53 -06:00
|
|
|
fmt.Fprintf(wr, "%s", quoter(s))
|
2019-09-04 13:53:54 -06:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2021-04-22 18:08:53 -06:00
|
|
|
fmt.Fprintf(wr, "\\fB%s\\fP", quoter(s[:idx]))
|
2019-09-04 13:53:54 -06:00
|
|
|
s = s[idx+1:]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func writeManPageOptions(wr io.Writer, grp *Group) {
|
|
|
|
grp.eachGroup(func(group *Group) {
|
2021-04-22 18:08:53 -06:00
|
|
|
if !group.showInHelp() {
|
2019-09-04 13:53:54 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the parent (grp) has any subgroups, display their descriptions as
|
|
|
|
// subsection headers similar to the output of --help.
|
|
|
|
if group.ShortDescription != "" && len(grp.groups) > 0 {
|
|
|
|
fmt.Fprintf(wr, ".SS %s\n", group.ShortDescription)
|
|
|
|
|
|
|
|
if group.LongDescription != "" {
|
2021-04-22 18:08:53 -06:00
|
|
|
formatForMan(wr, group.LongDescription, manQuoteLines)
|
2019-09-04 13:53:54 -06:00
|
|
|
fmt.Fprintln(wr, "")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, opt := range group.options {
|
2021-04-22 18:08:53 -06:00
|
|
|
if !opt.showInHelp() {
|
2019-09-04 13:53:54 -06:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintln(wr, ".TP")
|
|
|
|
fmt.Fprintf(wr, "\\fB")
|
|
|
|
|
|
|
|
if opt.ShortName != 0 {
|
|
|
|
fmt.Fprintf(wr, "\\fB\\-%c\\fR", opt.ShortName)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(opt.LongName) != 0 {
|
|
|
|
if opt.ShortName != 0 {
|
|
|
|
fmt.Fprintf(wr, ", ")
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintf(wr, "\\fB\\-\\-%s\\fR", manQuote(opt.LongNameWithNamespace()))
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(opt.ValueName) != 0 || opt.OptionalArgument {
|
|
|
|
if opt.OptionalArgument {
|
|
|
|
fmt.Fprintf(wr, " [\\fI%s=%s\\fR]", manQuote(opt.ValueName), manQuote(strings.Join(quoteV(opt.OptionalValue), ", ")))
|
|
|
|
} else {
|
|
|
|
fmt.Fprintf(wr, " \\fI%s\\fR", manQuote(opt.ValueName))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(opt.Default) != 0 {
|
|
|
|
fmt.Fprintf(wr, " <default: \\fI%s\\fR>", manQuote(strings.Join(quoteV(opt.Default), ", ")))
|
2021-04-22 18:08:53 -06:00
|
|
|
} else if len(opt.EnvKeyWithNamespace()) != 0 {
|
2019-09-04 13:53:54 -06:00
|
|
|
if runtime.GOOS == "windows" {
|
2021-04-22 18:08:53 -06:00
|
|
|
fmt.Fprintf(wr, " <default: \\fI%%%s%%\\fR>", manQuote(opt.EnvKeyWithNamespace()))
|
2019-09-04 13:53:54 -06:00
|
|
|
} else {
|
2021-04-22 18:08:53 -06:00
|
|
|
fmt.Fprintf(wr, " <default: \\fI$%s\\fR>", manQuote(opt.EnvKeyWithNamespace()))
|
2019-09-04 13:53:54 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if opt.Required {
|
|
|
|
fmt.Fprintf(wr, " (\\fIrequired\\fR)")
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintln(wr, "\\fP")
|
|
|
|
|
|
|
|
if len(opt.Description) != 0 {
|
2021-04-22 18:08:53 -06:00
|
|
|
formatForMan(wr, opt.Description, manQuoteLines)
|
2019-09-04 13:53:54 -06:00
|
|
|
fmt.Fprintln(wr, "")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-04-22 18:08:53 -06:00
|
|
|
func writeManPageSubcommands(wr io.Writer, name string, usagePrefix string, root *Command) {
|
2019-09-04 13:53:54 -06:00
|
|
|
commands := root.sortedVisibleCommands()
|
|
|
|
|
|
|
|
for _, c := range commands {
|
|
|
|
var nn string
|
|
|
|
|
|
|
|
if c.Hidden {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(name) != 0 {
|
|
|
|
nn = name + " " + c.Name
|
|
|
|
} else {
|
|
|
|
nn = c.Name
|
|
|
|
}
|
|
|
|
|
2021-04-22 18:08:53 -06:00
|
|
|
writeManPageCommand(wr, nn, usagePrefix, c)
|
2019-09-04 13:53:54 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-22 18:08:53 -06:00
|
|
|
func writeManPageCommand(wr io.Writer, name string, usagePrefix string, command *Command) {
|
2019-09-04 13:53:54 -06:00
|
|
|
fmt.Fprintf(wr, ".SS %s\n", name)
|
|
|
|
fmt.Fprintln(wr, command.ShortDescription)
|
|
|
|
|
|
|
|
if len(command.LongDescription) > 0 {
|
|
|
|
fmt.Fprintln(wr, "")
|
|
|
|
|
|
|
|
cmdstart := fmt.Sprintf("The %s command", manQuote(command.Name))
|
|
|
|
|
|
|
|
if strings.HasPrefix(command.LongDescription, cmdstart) {
|
|
|
|
fmt.Fprintf(wr, "The \\fI%s\\fP command", manQuote(command.Name))
|
|
|
|
|
2021-04-22 18:08:53 -06:00
|
|
|
formatForMan(wr, command.LongDescription[len(cmdstart):], manQuoteLines)
|
2019-09-04 13:53:54 -06:00
|
|
|
fmt.Fprintln(wr, "")
|
|
|
|
} else {
|
2021-04-22 18:08:53 -06:00
|
|
|
formatForMan(wr, command.LongDescription, manQuoteLines)
|
2019-09-04 13:53:54 -06:00
|
|
|
fmt.Fprintln(wr, "")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-22 18:08:53 -06:00
|
|
|
var pre = usagePrefix + " " + command.Name
|
|
|
|
|
2019-09-04 13:53:54 -06:00
|
|
|
var usage string
|
|
|
|
if us, ok := command.data.(Usage); ok {
|
|
|
|
usage = us.Usage()
|
2021-04-22 18:08:53 -06:00
|
|
|
} else if command.hasHelpOptions() {
|
2019-09-04 13:53:54 -06:00
|
|
|
usage = fmt.Sprintf("[%s-OPTIONS]", command.Name)
|
|
|
|
}
|
|
|
|
|
2021-04-22 18:08:53 -06:00
|
|
|
var nextPrefix = pre
|
2019-09-04 13:53:54 -06:00
|
|
|
if len(usage) > 0 {
|
|
|
|
fmt.Fprintf(wr, "\n\\fBUsage\\fP: %s %s\n.TP\n", manQuote(pre), manQuote(usage))
|
2021-04-22 18:08:53 -06:00
|
|
|
nextPrefix = pre + " " + usage
|
2019-09-04 13:53:54 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(command.Aliases) > 0 {
|
|
|
|
fmt.Fprintf(wr, "\n\\fBAliases\\fP: %s\n\n", manQuote(strings.Join(command.Aliases, ", ")))
|
|
|
|
}
|
|
|
|
|
|
|
|
writeManPageOptions(wr, command.Group)
|
2021-04-22 18:08:53 -06:00
|
|
|
writeManPageSubcommands(wr, name, nextPrefix, command)
|
2019-09-04 13:53:54 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// WriteManPage writes a basic man page in groff format to the specified
|
|
|
|
// writer.
|
|
|
|
func (p *Parser) WriteManPage(wr io.Writer) {
|
|
|
|
t := time.Now()
|
2021-04-22 18:08:53 -06:00
|
|
|
source_date_epoch := os.Getenv("SOURCE_DATE_EPOCH")
|
|
|
|
if source_date_epoch != "" {
|
|
|
|
sde, err := strconv.ParseInt(source_date_epoch, 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Sprintf("Invalid SOURCE_DATE_EPOCH: %s", err))
|
|
|
|
}
|
|
|
|
t = time.Unix(sde, 0)
|
|
|
|
}
|
2019-09-04 13:53:54 -06:00
|
|
|
|
|
|
|
fmt.Fprintf(wr, ".TH %s 1 \"%s\"\n", manQuote(p.Name), t.Format("2 January 2006"))
|
|
|
|
fmt.Fprintln(wr, ".SH NAME")
|
2021-04-22 18:08:53 -06:00
|
|
|
fmt.Fprintf(wr, "%s \\- %s\n", manQuote(p.Name), manQuoteLines(p.ShortDescription))
|
2019-09-04 13:53:54 -06:00
|
|
|
fmt.Fprintln(wr, ".SH SYNOPSIS")
|
|
|
|
|
|
|
|
usage := p.Usage
|
|
|
|
|
|
|
|
if len(usage) == 0 {
|
|
|
|
usage = "[OPTIONS]"
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintf(wr, "\\fB%s\\fP %s\n", manQuote(p.Name), manQuote(usage))
|
|
|
|
fmt.Fprintln(wr, ".SH DESCRIPTION")
|
|
|
|
|
2021-04-22 18:08:53 -06:00
|
|
|
formatForMan(wr, p.LongDescription, manQuoteLines)
|
2019-09-04 13:53:54 -06:00
|
|
|
fmt.Fprintln(wr, "")
|
|
|
|
|
|
|
|
fmt.Fprintln(wr, ".SH OPTIONS")
|
|
|
|
|
|
|
|
writeManPageOptions(wr, p.Command.Group)
|
|
|
|
|
|
|
|
if len(p.visibleCommands()) > 0 {
|
|
|
|
fmt.Fprintln(wr, ".SH COMMANDS")
|
|
|
|
|
2021-04-22 18:08:53 -06:00
|
|
|
writeManPageSubcommands(wr, "", p.Name+" "+usage, p.Command)
|
2019-09-04 13:53:54 -06:00
|
|
|
}
|
|
|
|
}
|