github.com/x-oss-byte/git-lfs@v2.5.2+incompatible/docs/man/mangen.go (about) 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 }