authelia/cmd/authelia-gen/cmd_docs_date.go

226 lines
4.0 KiB
Go

package main
import (
"bufio"
"bytes"
"fmt"
"io/fs"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
)
func newDocsDateCmd() *cobra.Command {
cmd := &cobra.Command{
Use: cmdUseDocsDate,
Short: "Generate doc dates",
RunE: docsDateRunE,
DisableAutoGenTag: true,
}
cmd.Flags().String("commit-until", "HEAD", "The commit to check the logs until")
cmd.Flags().String("commit-since", "", "The commit to check the logs since")
return cmd
}
func docsDateRunE(cmd *cobra.Command, args []string) (err error) {
var (
root, pathDocsContent, cwd, commitUtil, commitSince, commitFilter string
)
if root, err = cmd.Flags().GetString(cmdFlagRoot); err != nil {
return err
}
if pathDocsContent, err = cmd.Flags().GetString(cmdFlagDocsContent); err != nil {
return err
}
if cwd, err = cmd.Flags().GetString(cmdFlagCwd); err != nil {
return err
}
if cmd.Flags().Changed("commit-since") {
if commitUtil, err = cmd.Flags().GetString("commit-util"); err != nil {
return err
}
if commitSince, err = cmd.Flags().GetString("commit-since"); err != nil {
return err
}
commitFilter = fmt.Sprintf("%s...%s", commitUtil, commitSince)
}
return filepath.Walk(filepath.Join(root, pathDocsContent), func(path string, info fs.FileInfo, err error) error {
if err != nil {
return err
}
if !strings.HasSuffix(info.Name(), ".md") {
return nil
}
abs, err := filepath.Abs(path)
if err != nil {
return nil
}
frontmatterBytes := getFrontmatter(abs)
if frontmatterBytes == nil {
return nil
}
frontmatter := map[string]interface{}{}
if err = yaml.Unmarshal(frontmatterBytes, frontmatter); err != nil {
return err
}
var (
date time.Time
)
if value, ok := frontmatter["date"]; ok {
date = value.(time.Time)
}
dateGit := getDateFromGit(cwd, abs, commitFilter)
replaceDates(abs, date, dateGit)
return nil
})
}
var newline = []byte("\n")
func getDateFromGit(cwd, path, commitFilter string) *time.Time {
var args []string
if len(cwd) != 0 {
args = append(args, "-C", cwd)
}
args = append(args, "log")
if len(commitFilter) != 0 {
args = append(args, commitFilter)
}
args = append(args, "-1", "--follow", "--diff-filter=A", "--pretty=format:%cD", "--", path)
return getTimeFromGitCmd(exec.Command("git", args...))
}
func getTimeFromGitCmd(cmd *exec.Cmd) *time.Time {
var (
output []byte
err error
t time.Time
)
if output, err = cmd.Output(); err != nil {
return nil
}
if t, err = time.Parse(dateFmtRFC2822, string(output)); err != nil {
return nil
}
return &t
}
func replaceDates(path string, date time.Time, dateGit *time.Time) {
f, err := os.Open(path)
if err != nil {
return
}
buf := bytes.Buffer{}
scanner := bufio.NewScanner(f)
var dateGitLine string
dateLine := fmt.Sprintf("date: %s", date.Format(dateFmtYAML))
if dateGit != nil {
dateGitLine = fmt.Sprintf("date: %s", dateGit.Format(dateFmtYAML))
} else {
dateGitLine = dateLine
}
found := 0
frontmatter := 0
for scanner.Scan() {
if found < 2 && frontmatter < 2 {
switch {
case scanner.Text() == delimiterLineFrontMatter:
buf.Write(scanner.Bytes())
frontmatter++
case frontmatter != 0 && strings.HasPrefix(scanner.Text(), "date: "):
buf.WriteString(dateGitLine)
found++
default:
buf.Write(scanner.Bytes())
}
} else {
buf.Write(scanner.Bytes())
}
buf.Write(newline)
}
f.Close()
newF, err := os.Create(path)
if err != nil {
return
}
_, _ = buf.WriteTo(newF)
newF.Close()
}
func getFrontmatter(path string) []byte {
f, err := os.Open(path)
if err != nil {
return nil
}
defer f.Close()
scanner := bufio.NewScanner(f)
var start bool
buf := bytes.Buffer{}
for scanner.Scan() {
if start {
if scanner.Text() == delimiterLineFrontMatter {
break
}
buf.Write(scanner.Bytes())
buf.Write(newline)
} else if scanner.Text() == delimiterLineFrontMatter {
start = true
}
}
return buf.Bytes()
}