13 func readManDir() (string, []os.FileInfo) {
16 "/tmp/docker_run/git-lfs",
20 for _, rootDir := range rootDirs {
21 fs, err := ioutil.ReadDir(filepath.Join(rootDir, "docs", "man"))
27 fmt.Fprintf(os.Stderr, "Failed to open man dir: %v\n", err)
32 // Reads all .ronn files & and converts them to string literals
33 // triggered by "go generate" comment
34 // Literals are inserted into a map using an init function, this means
35 // that there are no compilation errors if 'go generate' hasn't been run, just
38 fmt.Fprintf(os.Stderr, "Converting man pages into code...\n")
39 rootDir, fs := readManDir()
40 manDir := filepath.Join(rootDir, "docs", "man")
41 out, err := os.Create(filepath.Join(rootDir, "commands", "mancontent_gen.go"))
43 fmt.Fprintf(os.Stderr, "Failed to create go file: %v\n", err)
46 out.WriteString("package commands\n\nfunc init() {\n")
47 out.WriteString("// THIS FILE IS GENERATED, DO NOT EDIT\n")
48 out.WriteString("// Use 'go generate ./commands' to update\n")
49 fileregex := regexp.MustCompile(`git-lfs(?:-([A-Za-z\-]+))?.\d.ronn`)
50 headerregex := regexp.MustCompile(`^###?\s+([A-Za-z0-9 ]+)`)
51 // only pick up caps in links to avoid matching optional args
52 linkregex := regexp.MustCompile(`\[([A-Z\- ]+)\]`)
54 manlinkregex := regexp.MustCompile(`(git)(?:-(lfs))?-([a-z\-]+)\(\d\)`)
56 for _, f := range fs {
57 if match := fileregex.FindStringSubmatch(f.Name()); match != nil {
58 fmt.Fprintf(os.Stderr, "%v\n", f.Name())
61 // This is git-lfs.1.ronn
64 out.WriteString("ManPages[\"" + cmd + "\"] = `")
65 contentf, err := os.Open(filepath.Join(manDir, f.Name()))
67 fmt.Fprintf(os.Stderr, "Failed to open %v: %v\n", f.Name(), err)
70 // Process the ronn to make it nicer as help text
71 scanner := bufio.NewScanner(contentf)
72 firstHeaderDone := false
73 skipNextLineIfBlank := false
74 lastLineWasBullet := false
77 line := scanner.Text()
78 trimmedline := strings.TrimSpace(line)
79 if skipNextLineIfBlank && len(trimmedline) == 0 {
80 skipNextLineIfBlank = false
81 lastLineWasBullet = false
85 // Special case headers
86 if hmatch := headerregex.FindStringSubmatch(line); hmatch != nil {
87 header := strings.ToLower(hmatch[1])
90 // Ignore this, just go direct to command
93 // Just skip the header & newline
94 skipNextLineIfBlank = true
96 out.WriteString("Options:" + "\n")
98 // don't include any content after this
101 out.WriteString(strings.ToUpper(header[:1]) + header[1:] + "\n")
102 out.WriteString(strings.Repeat("-", len(header)) + "\n")
104 firstHeaderDone = true
105 lastLineWasBullet = false
109 if lmatches := linkregex.FindAllStringSubmatch(line, -1); lmatches != nil {
110 for _, lmatch := range lmatches {
111 linktext := strings.ToLower(lmatch[1])
112 line = strings.Replace(line, lmatch[0], `"`+strings.ToUpper(linktext[:1])+linktext[1:]+`"`, 1)
115 if manmatches := manlinkregex.FindAllStringSubmatch(line, -1); manmatches != nil {
116 for _, manmatch := range manmatches {
117 line = strings.Replace(line, manmatch[0], strings.Join(manmatch[1:], " "), 1)
121 // Skip content until after first header
122 if !firstHeaderDone {
127 // remove characters that markdown would render invisible in a text env.
128 for _, invis := range []string{"`", "<br>"} {
129 line = strings.Replace(line, invis, "", -1)
133 if strings.HasPrefix(line, "*") {
134 lastLineWasBullet = true
135 } else if lastLineWasBullet && !strings.HasPrefix(line, " ") {
136 // indent paragraphs under bullets if not already done
140 out.WriteString(line + "\n")
142 out.WriteString("`\n")
147 out.WriteString("}\n")
148 fmt.Fprintf(os.Stderr, "Successfully processed %d man pages.\n", count)