git-lfs/docs/man/mangen.go
Chris Darroch 18b71e3bd5 docs/man: do not support parentheses in headers
This reverts commit 08cb542b1d83ca611e2403150d26194f08e4d86d
from PR #4458 because that change, while it does resolve some
formatting issues in the output from the "git lfs help" command,
does not address the fact that ronn(1) is unable to process
parentheses in header text and therefore still generates
pages (particularly for the git-lfs-migrate(1) page) with
broken references for such headers.

Since we will rewrite the relevant manual pages in a subsequent
commit to remove the parentheses, we simply revert this change first.
2022-02-07 00:24:46 -08:00

170 lines
4.6 KiB
Go

package main
import (
"bufio"
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"
)
func infof(w io.Writer, format string, a ...interface{}) {
if !*verbose {
return
}
fmt.Fprintf(w, format, a...)
}
func warnf(w io.Writer, format string, a ...interface{}) {
fmt.Fprintf(w, format, a...)
}
func readManDir() (string, []os.FileInfo) {
rootDirs := []string{
"..",
"/tmp/docker_run/git-lfs",
}
var err error
for _, rootDir := range rootDirs {
fs, err := ioutil.ReadDir(filepath.Join(rootDir, "docs", "man"))
if err == nil {
return rootDir, fs
}
}
warnf(os.Stderr, "Failed to open man dir: %v\n", err)
os.Exit(2)
return "", nil
}
var (
verbose = flag.Bool("verbose", false, "Show verbose output.")
)
// Reads all .ronn files & and converts them to string literals
// triggered by "go generate" comment
// Literals are inserted into a map using an init function, this means
// that there are no compilation errors if 'go generate' hasn't been run, just
// blank man files.
func main() {
flag.Parse()
infof(os.Stderr, "Converting man pages into code...\n")
rootDir, fs := readManDir()
manDir := filepath.Join(rootDir, "docs", "man")
out, err := os.Create(filepath.Join(rootDir, "commands", "mancontent_gen.go"))
if err != nil {
warnf(os.Stderr, "Failed to create go file: %v\n", err)
os.Exit(2)
}
out.WriteString("package commands\n\nfunc init() {\n")
out.WriteString("\t// THIS FILE IS GENERATED, DO NOT EDIT\n")
out.WriteString("\t// Use 'go generate ./commands' to update\n")
fileregex := regexp.MustCompile(`git-lfs(?:-([A-Za-z\-]+))?.\d.ronn`)
headerregex := regexp.MustCompile(`^###?\s+([A-Za-z0-9 ]+)`)
// only pick up caps in links to avoid matching optional args
linkregex := regexp.MustCompile(`\[([A-Z\- ]+)\]`)
// man links
manlinkregex := regexp.MustCompile(`(git)(?:-(lfs))?-([a-z\-]+)\(\d\)`)
count := 0
for _, f := range fs {
if match := fileregex.FindStringSubmatch(f.Name()); match != nil {
infof(os.Stderr, "%v\n", f.Name())
cmd := match[1]
if len(cmd) == 0 {
// This is git-lfs.1.ronn
cmd = "git-lfs"
}
out.WriteString("\tManPages[\"" + cmd + "\"] = `")
contentf, err := os.Open(filepath.Join(manDir, f.Name()))
if err != nil {
warnf(os.Stderr, "Failed to open %v: %v\n", f.Name(), err)
os.Exit(2)
}
// Process the ronn to make it nicer as help text
scanner := bufio.NewScanner(contentf)
firstHeaderDone := false
skipNextLineIfBlank := false
lastLineWasBullet := false
scanloop:
for scanner.Scan() {
line := scanner.Text()
trimmedline := strings.TrimSpace(line)
if skipNextLineIfBlank && len(trimmedline) == 0 {
skipNextLineIfBlank = false
lastLineWasBullet = false
continue
}
// Special case headers
if hmatch := headerregex.FindStringSubmatch(line); hmatch != nil {
header := strings.ToLower(hmatch[1])
switch header {
case "synopsis":
// Ignore this, just go direct to command
case "description":
// Just skip the header & newline
skipNextLineIfBlank = true
case "options":
out.WriteString("Options:" + "\n")
case "see also":
// don't include any content after this
break scanloop
default:
out.WriteString(strings.ToUpper(header[:1]) + header[1:] + "\n")
out.WriteString(strings.Repeat("-", len(header)) + "\n")
}
firstHeaderDone = true
lastLineWasBullet = false
continue
}
if lmatches := linkregex.FindAllStringSubmatch(line, -1); lmatches != nil {
for _, lmatch := range lmatches {
linktext := strings.ToLower(lmatch[1])
line = strings.Replace(line, lmatch[0], `"`+strings.ToUpper(linktext[:1])+linktext[1:]+`"`, 1)
}
}
if manmatches := manlinkregex.FindAllStringSubmatch(line, -1); manmatches != nil {
for _, manmatch := range manmatches {
line = strings.Replace(line, manmatch[0], strings.Join(manmatch[1:], " "), 1)
}
}
// Skip content until after first header
if !firstHeaderDone {
continue
}
// OK, content here
// remove characters that markdown would render invisible in a text env.
for _, invis := range []string{"`", "<br>"} {
line = strings.Replace(line, invis, "", -1)
}
// indent bullets
if strings.HasPrefix(line, "*") {
lastLineWasBullet = true
} else if lastLineWasBullet && !strings.HasPrefix(line, " ") {
// indent paragraphs under bullets if not already done
line = " " + line
}
out.WriteString(line + "\n")
}
out.WriteString("`\n")
contentf.Close()
count++
}
}
out.WriteString("}\n")
infof(os.Stderr, "Successfully processed %d man pages.\n", count)
}