Add snippet-extract cmd that allows to extract parts of examples for docs

This commit is contained in:
Adrien Delorme 2020-07-16 15:14:04 +02:00
parent 0fe0cfc4cd
commit a7abf75794
1 changed files with 146 additions and 0 deletions

View File

@ -0,0 +1,146 @@
// snippet-extract --begin=#_BEGIN_WRAP_TAG_ --end=#_END_WRAP_TAG_ -output_dir=./docs/ [./file|./directory/]...
// Extracts markdown snippets from relative files into output_dir, keeping the
// directory layout.
// It is not mandatory to terminate a snippet, the extractor will simply add
// line until EOF.
// Lines matching begin or end tags will not be put in the resulting file.
// When a directory is passed, all files from directory will be parsed.
package main
import (
"bufio"
"bytes"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
)
type options struct {
filenames []string
begin, end string
outputDir string
extension string
}
func (o *options) AddFlagSets(fs *flag.FlagSet) {
fs.StringVar(&o.begin, "begin", "#_BEGIN_WRAP_TAG_", "flag to mark beginning of a snippet")
fs.StringVar(&o.end, "end", "#_END_WRAP_TAG_", "flag to mark ending of a snippet")
fs.StringVar(&o.outputDir, "output_dir", "./docs/", "flag to mark ending of a snippet")
fs.StringVar(&o.extension, "extension", ".mdx", "extension for generated files")
}
func main() {
fs := flag.NewFlagSet("snippet-extract", flag.ContinueOnError)
opts := options{}
opts.AddFlagSets(fs)
if err := fs.Parse(os.Args[1:]); err != nil {
fs.Usage()
os.Exit(1)
}
wd, _ := os.Getwd()
fmt.Printf("working from %s\n", wd)
opts.filenames = extactFilenames(fs.Args())
for _, filename := range opts.filenames {
ext := filepath.Ext(filename)
snippets := extractSnippets(opts.begin, opts.end, filename)
for _, snippet := range snippets {
outputFile := filepath.Join(opts.outputDir, filepath.Base(filename), snippet.Identifier+opts.extension)
folder := filepath.Dir(outputFile)
err := os.MkdirAll(folder, os.ModePerm)
if err != nil {
log.Printf("cannot mkdir %s: %s", folder, err)
}
f := bytes.NewBuffer(nil)
fmt.Fprintf(f, `<!-- Code generated by snippet-extractor %s; DO NOT EDIT MANUALLY -->`, strings.Join(os.Args[1:], " "))
fmt.Fprintf(f, "\n\n```%s\n%s```\n", ext, snippet.Text)
err = ioutil.WriteFile(outputFile, f.Bytes(), 0600)
if err != nil {
log.Printf("cannot write %s in %s: %s", filepath.Base(outputFile), folder, err)
}
}
}
}
type snippet struct {
Identifier string
Text string
Closed bool
}
func extractSnippets(beginPattern, endPattern, filename string) []snippet {
file, err := os.Open(filename)
if err != nil {
log.Printf("could not open file: %s", err)
os.Exit(1)
}
defer file.Close()
scanner := bufio.NewScanner(file)
snippets := []snippet{}
for scanner.Scan() {
line := scanner.Text()
if identifier := matches(line, beginPattern); identifier != "" {
snippets = append(snippets, snippet{
Identifier: identifier,
})
continue
}
if identifier := matches(line, endPattern); identifier != "" {
for i := range snippets {
snippet := &snippets[i]
if snippet.Identifier == identifier {
snippet.Closed = true
}
}
continue
}
for i := range snippets {
snippet := &snippets[i]
if snippet.Closed {
continue
}
snippet.Text = snippet.Text + line + "\n"
}
}
return snippets
}
func matches(s, prefix string) string {
trimmed := strings.TrimSpace(s)
lenDiff := len(s) - len(trimmed)
if strings.HasPrefix(trimmed, prefix) {
return s[len(prefix)+lenDiff:]
}
return ""
}
// if an entry is a directory all files from directory will be listed.
func extactFilenames(in []string) []string {
out := []string{}
for _, path := range in {
fi, err := os.Stat(path)
if err != nil {
log.Fatalf("%s: %s", path, err)
}
if !fi.IsDir() {
out = append(out, path)
continue
}
files, err := ioutil.ReadDir(path)
if err != nil {
log.Fatalf("could not read directory %s: %s", path, err)
}
for _, file := range files {
if file.IsDir() {
continue
}
out = append(out, file.Name())
}
}
return in
}