github.com/stffabi/git-lfs@v2.3.5-0.20180214015214-8eeaa8d88902+incompatible/docs/man/mangen.go (about)

     1  package main
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"regexp"
    10  	"strings"
    11  )
    12  
    13  func readManDir() (string, []os.FileInfo) {
    14  	rootDirs := []string{
    15  		"..",
    16  		"/tmp/docker_run/git-lfs",
    17  	}
    18  
    19  	var err error
    20  	for _, rootDir := range rootDirs {
    21  		fs, err := ioutil.ReadDir(filepath.Join(rootDir, "docs", "man"))
    22  		if err == nil {
    23  			return rootDir, fs
    24  		}
    25  	}
    26  
    27  	fmt.Fprintf(os.Stderr, "Failed to open man dir: %v\n", err)
    28  	os.Exit(2)
    29  	return "", nil
    30  }
    31  
    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
    36  // blank man files.
    37  func main() {
    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"))
    42  	if err != nil {
    43  		fmt.Fprintf(os.Stderr, "Failed to create go file: %v\n", err)
    44  		os.Exit(2)
    45  	}
    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\- ]+)\]`)
    53  	// man links
    54  	manlinkregex := regexp.MustCompile(`(git)(?:-(lfs))?-([a-z\-]+)\(\d\)`)
    55  	count := 0
    56  	for _, f := range fs {
    57  		if match := fileregex.FindStringSubmatch(f.Name()); match != nil {
    58  			fmt.Fprintf(os.Stderr, "%v\n", f.Name())
    59  			cmd := match[1]
    60  			if len(cmd) == 0 {
    61  				// This is git-lfs.1.ronn
    62  				cmd = "git-lfs"
    63  			}
    64  			out.WriteString("ManPages[\"" + cmd + "\"] = `")
    65  			contentf, err := os.Open(filepath.Join(manDir, f.Name()))
    66  			if err != nil {
    67  				fmt.Fprintf(os.Stderr, "Failed to open %v: %v\n", f.Name(), err)
    68  				os.Exit(2)
    69  			}
    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
    75  		scanloop:
    76  			for scanner.Scan() {
    77  				line := scanner.Text()
    78  				trimmedline := strings.TrimSpace(line)
    79  				if skipNextLineIfBlank && len(trimmedline) == 0 {
    80  					skipNextLineIfBlank = false
    81  					lastLineWasBullet = false
    82  					continue
    83  				}
    84  
    85  				// Special case headers
    86  				if hmatch := headerregex.FindStringSubmatch(line); hmatch != nil {
    87  					header := strings.ToLower(hmatch[1])
    88  					switch header {
    89  					case "synopsis":
    90  						// Ignore this, just go direct to command
    91  
    92  					case "description":
    93  						// Just skip the header & newline
    94  						skipNextLineIfBlank = true
    95  					case "options":
    96  						out.WriteString("Options:" + "\n")
    97  					case "see also":
    98  						// don't include any content after this
    99  						break scanloop
   100  					default:
   101  						out.WriteString(strings.ToUpper(header[:1]) + header[1:] + "\n")
   102  						out.WriteString(strings.Repeat("-", len(header)) + "\n")
   103  					}
   104  					firstHeaderDone = true
   105  					lastLineWasBullet = false
   106  					continue
   107  				}
   108  
   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)
   113  					}
   114  				}
   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)
   118  					}
   119  				}
   120  
   121  				// Skip content until after first header
   122  				if !firstHeaderDone {
   123  					continue
   124  				}
   125  				// OK, content here
   126  
   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)
   130  				}
   131  
   132  				// indent bullets
   133  				if strings.HasPrefix(line, "*") {
   134  					lastLineWasBullet = true
   135  				} else if lastLineWasBullet && !strings.HasPrefix(line, " ") {
   136  					// indent paragraphs under bullets if not already done
   137  					line = "  " + line
   138  				}
   139  
   140  				out.WriteString(line + "\n")
   141  			}
   142  			out.WriteString("`\n")
   143  			contentf.Close()
   144  			count++
   145  		}
   146  	}
   147  	out.WriteString("}\n")
   148  	fmt.Fprintf(os.Stderr, "Successfully processed %d man pages.\n", count)
   149  
   150  }