Imported Upstream version 2.5.1
[scm/test.git] / docs / man / mangen.go
1 package main
2
3 import (
4         "bufio"
5         "flag"
6         "fmt"
7         "io"
8         "io/ioutil"
9         "os"
10         "path/filepath"
11         "regexp"
12         "strings"
13 )
14
15 func infof(w io.Writer, format string, a ...interface{}) {
16         if !*verbose {
17                 return
18         }
19         fmt.Fprintf(w, format, a...)
20 }
21
22 func warnf(w io.Writer, format string, a ...interface{}) {
23         fmt.Fprintf(w, format, a...)
24 }
25
26 func readManDir() (string, []os.FileInfo) {
27         rootDirs := []string{
28                 "..",
29                 "/tmp/docker_run/git-lfs",
30         }
31
32         var err error
33         for _, rootDir := range rootDirs {
34                 fs, err := ioutil.ReadDir(filepath.Join(rootDir, "docs", "man"))
35                 if err == nil {
36                         return rootDir, fs
37                 }
38         }
39
40         warnf(os.Stderr, "Failed to open man dir: %v\n", err)
41         os.Exit(2)
42         return "", nil
43 }
44
45 var (
46         verbose = flag.Bool("verbose", false, "Show verbose output.")
47 )
48
49 // Reads all .ronn files & and converts them to string literals
50 // triggered by "go generate" comment
51 // Literals are inserted into a map using an init function, this means
52 // that there are no compilation errors if 'go generate' hasn't been run, just
53 // blank man files.
54 func main() {
55         flag.Parse()
56
57         infof(os.Stderr, "Converting man pages into code...\n")
58         rootDir, fs := readManDir()
59         manDir := filepath.Join(rootDir, "docs", "man")
60         out, err := os.Create(filepath.Join(rootDir, "commands", "mancontent_gen.go"))
61         if err != nil {
62                 warnf(os.Stderr, "Failed to create go file: %v\n", err)
63                 os.Exit(2)
64         }
65         out.WriteString("package commands\n\nfunc init() {\n")
66         out.WriteString("// THIS FILE IS GENERATED, DO NOT EDIT\n")
67         out.WriteString("// Use 'go generate ./commands' to update\n")
68         fileregex := regexp.MustCompile(`git-lfs(?:-([A-Za-z\-]+))?.\d.ronn`)
69         headerregex := regexp.MustCompile(`^###?\s+([A-Za-z0-9 ]+)`)
70         // only pick up caps in links to avoid matching optional args
71         linkregex := regexp.MustCompile(`\[([A-Z\- ]+)\]`)
72         // man links
73         manlinkregex := regexp.MustCompile(`(git)(?:-(lfs))?-([a-z\-]+)\(\d\)`)
74         count := 0
75         for _, f := range fs {
76                 if match := fileregex.FindStringSubmatch(f.Name()); match != nil {
77                         infof(os.Stderr, "%v\n", f.Name())
78                         cmd := match[1]
79                         if len(cmd) == 0 {
80                                 // This is git-lfs.1.ronn
81                                 cmd = "git-lfs"
82                         }
83                         out.WriteString("ManPages[\"" + cmd + "\"] = `")
84                         contentf, err := os.Open(filepath.Join(manDir, f.Name()))
85                         if err != nil {
86                                 warnf(os.Stderr, "Failed to open %v: %v\n", f.Name(), err)
87                                 os.Exit(2)
88                         }
89                         // Process the ronn to make it nicer as help text
90                         scanner := bufio.NewScanner(contentf)
91                         firstHeaderDone := false
92                         skipNextLineIfBlank := false
93                         lastLineWasBullet := false
94                 scanloop:
95                         for scanner.Scan() {
96                                 line := scanner.Text()
97                                 trimmedline := strings.TrimSpace(line)
98                                 if skipNextLineIfBlank && len(trimmedline) == 0 {
99                                         skipNextLineIfBlank = false
100                                         lastLineWasBullet = false
101                                         continue
102                                 }
103
104                                 // Special case headers
105                                 if hmatch := headerregex.FindStringSubmatch(line); hmatch != nil {
106                                         header := strings.ToLower(hmatch[1])
107                                         switch header {
108                                         case "synopsis":
109                                                 // Ignore this, just go direct to command
110
111                                         case "description":
112                                                 // Just skip the header & newline
113                                                 skipNextLineIfBlank = true
114                                         case "options":
115                                                 out.WriteString("Options:" + "\n")
116                                         case "see also":
117                                                 // don't include any content after this
118                                                 break scanloop
119                                         default:
120                                                 out.WriteString(strings.ToUpper(header[:1]) + header[1:] + "\n")
121                                                 out.WriteString(strings.Repeat("-", len(header)) + "\n")
122                                         }
123                                         firstHeaderDone = true
124                                         lastLineWasBullet = false
125                                         continue
126                                 }
127
128                                 if lmatches := linkregex.FindAllStringSubmatch(line, -1); lmatches != nil {
129                                         for _, lmatch := range lmatches {
130                                                 linktext := strings.ToLower(lmatch[1])
131                                                 line = strings.Replace(line, lmatch[0], `"`+strings.ToUpper(linktext[:1])+linktext[1:]+`"`, 1)
132                                         }
133                                 }
134                                 if manmatches := manlinkregex.FindAllStringSubmatch(line, -1); manmatches != nil {
135                                         for _, manmatch := range manmatches {
136                                                 line = strings.Replace(line, manmatch[0], strings.Join(manmatch[1:], " "), 1)
137                                         }
138                                 }
139
140                                 // Skip content until after first header
141                                 if !firstHeaderDone {
142                                         continue
143                                 }
144                                 // OK, content here
145
146                                 // remove characters that markdown would render invisible in a text env.
147                                 for _, invis := range []string{"`", "<br>"} {
148                                         line = strings.Replace(line, invis, "", -1)
149                                 }
150
151                                 // indent bullets
152                                 if strings.HasPrefix(line, "*") {
153                                         lastLineWasBullet = true
154                                 } else if lastLineWasBullet && !strings.HasPrefix(line, " ") {
155                                         // indent paragraphs under bullets if not already done
156                                         line = "  " + line
157                                 }
158
159                                 out.WriteString(line + "\n")
160                         }
161                         out.WriteString("`\n")
162                         contentf.Close()
163                         count++
164                 }
165         }
166         out.WriteString("}\n")
167         infof(os.Stderr, "Successfully processed %d man pages.\n", count)
168
169 }