rclone/cmd/gendocs/gendocs.go
albertony fbc7f2e61b lib/file: improve error message when attempting to create dir on nonexistent drive on windows
This replaces built-in os.MkdirAll with a patched version that stops the recursion
when reaching the volume part of the path. The original version would continue recursion,
and for extended length paths end up with \\? as the top-level directory, and the error
message would then be something like:
mkdir \\?: The filename, directory name, or volume label syntax is incorrect.
2021-10-01 23:18:39 +02:00

155 lines
3.9 KiB
Go

package gendocs
import (
"bytes"
"io/ioutil"
"log"
"os"
"path"
"path/filepath"
"regexp"
"strings"
"text/template"
"time"
"github.com/rclone/rclone/cmd"
"github.com/rclone/rclone/lib/file"
"github.com/spf13/cobra"
"github.com/spf13/cobra/doc"
"github.com/spf13/pflag"
)
func init() {
cmd.Root.AddCommand(commandDefinition)
}
// define things which go into the frontmatter
type frontmatter struct {
Date string
Title string
Description string
Slug string
URL string
Source string
}
var frontmatterTemplate = template.Must(template.New("frontmatter").Parse(`---
title: "{{ .Title }}"
description: "{{ .Description }}"
slug: {{ .Slug }}
url: {{ .URL }}
# autogenerated - DO NOT EDIT, instead edit the source code in {{ .Source }} and as part of making a release run "make commanddocs"
---
`))
var commandDefinition = &cobra.Command{
Use: "gendocs output_directory",
Short: `Output markdown docs for rclone to the directory supplied.`,
Long: `
This produces markdown docs for the rclone commands to the directory
supplied. These are in a format suitable for hugo to render into the
rclone.org website.`,
RunE: func(command *cobra.Command, args []string) error {
cmd.CheckArgs(1, 1, command, args)
now := time.Now().Format(time.RFC3339)
// Create the directory structure
root := args[0]
out := filepath.Join(root, "commands")
err := file.MkdirAll(out, 0777)
if err != nil {
return err
}
// Write the flags page
var buf bytes.Buffer
cmd.Root.SetOutput(&buf)
cmd.Root.SetArgs([]string{"help", "flags"})
cmd.GeneratingDocs = true
err = cmd.Root.Execute()
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(root, "flags.md"), buf.Bytes(), 0777)
if err != nil {
return err
}
// Look up name => description for prepender
var description = map[string]string{}
var addDescription func(root *cobra.Command)
addDescription = func(root *cobra.Command) {
name := strings.Replace(root.CommandPath(), " ", "_", -1) + ".md"
description[name] = root.Short
for _, c := range root.Commands() {
addDescription(c)
}
}
addDescription(cmd.Root)
// markup for the docs files
prepender := func(filename string) string {
name := filepath.Base(filename)
base := strings.TrimSuffix(name, path.Ext(name))
data := frontmatter{
Date: now,
Title: strings.Replace(base, "_", " ", -1),
Description: description[name],
Slug: base,
URL: "/commands/" + strings.ToLower(base) + "/",
Source: strings.Replace(strings.Replace(base, "rclone", "cmd", -1), "_", "/", -1) + "/",
}
var buf bytes.Buffer
err := frontmatterTemplate.Execute(&buf, data)
if err != nil {
log.Fatalf("Failed to render frontmatter template: %v", err)
}
return buf.String()
}
linkHandler := func(name string) string {
base := strings.TrimSuffix(name, path.Ext(name))
return "/commands/" + strings.ToLower(base) + "/"
}
// Hide all of the root entries flags
cmd.Root.Flags().VisitAll(func(flag *pflag.Flag) {
flag.Hidden = true
})
err = doc.GenMarkdownTreeCustom(cmd.Root, out, prepender, linkHandler)
if err != nil {
return err
}
var outdentTitle = regexp.MustCompile(`(?m)^#(#+)`)
// Munge the files to add a link to the global flags page
err = filepath.Walk(out, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
b, err := ioutil.ReadFile(path)
if err != nil {
return err
}
doc := string(b)
doc = strings.Replace(doc, "\n### SEE ALSO", `
See the [global flags page](/flags/) for global options not listed here.
### SEE ALSO`, 1)
// outdent all the titles by one
doc = outdentTitle.ReplaceAllString(doc, `$1`)
err = ioutil.WriteFile(path, []byte(doc), 0777)
if err != nil {
return err
}
}
return nil
})
if err != nil {
return err
}
return nil
},
}