15 func infof(w io.Writer, format string, a ...interface{}) {
19 fmt.Fprintf(w, format, a...)
22 func warnf(w io.Writer, format string, a ...interface{}) {
23 fmt.Fprintf(w, format, a...)
26 func readManDir() (string, []os.FileInfo) {
29 "/tmp/docker_run/git-lfs",
33 for _, rootDir := range rootDirs {
34 fs, err := ioutil.ReadDir(filepath.Join(rootDir, "docs", "man"))
40 warnf(os.Stderr, "Failed to open man dir: %v\n", err)
46 verbose = flag.Bool("verbose", false, "Show verbose output.")
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
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"))
62 warnf(os.Stderr, "Failed to create go file: %v\n", err)
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\- ]+)\]`)
73 manlinkregex := regexp.MustCompile(`(git)(?:-(lfs))?-([a-z\-]+)\(\d\)`)
75 for _, f := range fs {
76 if match := fileregex.FindStringSubmatch(f.Name()); match != nil {
77 infof(os.Stderr, "%v\n", f.Name())
80 // This is git-lfs.1.ronn
83 out.WriteString("ManPages[\"" + cmd + "\"] = `")
84 contentf, err := os.Open(filepath.Join(manDir, f.Name()))
86 warnf(os.Stderr, "Failed to open %v: %v\n", f.Name(), err)
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
96 line := scanner.Text()
97 trimmedline := strings.TrimSpace(line)
98 if skipNextLineIfBlank && len(trimmedline) == 0 {
99 skipNextLineIfBlank = false
100 lastLineWasBullet = false
104 // Special case headers
105 if hmatch := headerregex.FindStringSubmatch(line); hmatch != nil {
106 header := strings.ToLower(hmatch[1])
109 // Ignore this, just go direct to command
112 // Just skip the header & newline
113 skipNextLineIfBlank = true
115 out.WriteString("Options:" + "\n")
117 // don't include any content after this
120 out.WriteString(strings.ToUpper(header[:1]) + header[1:] + "\n")
121 out.WriteString(strings.Repeat("-", len(header)) + "\n")
123 firstHeaderDone = true
124 lastLineWasBullet = false
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)
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)
140 // Skip content until after first header
141 if !firstHeaderDone {
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)
152 if strings.HasPrefix(line, "*") {
153 lastLineWasBullet = true
154 } else if lastLineWasBullet && !strings.HasPrefix(line, " ") {
155 // indent paragraphs under bullets if not already done
159 out.WriteString(line + "\n")
161 out.WriteString("`\n")
166 out.WriteString("}\n")
167 infof(os.Stderr, "Successfully processed %d man pages.\n", count)