Implement support for preprocess command

This commit is contained in:
Adnan Maolood 2021-04-20 21:28:29 -04:00
parent 99f11c2876
commit 4cc4546526
3 changed files with 69 additions and 90 deletions

View file

@ -1,11 +1,8 @@
package main package main
import ( import (
"log"
"os" "os"
"os/exec"
"path" "path"
"strings"
"text/template" "text/template"
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
@ -25,28 +22,14 @@ type Task struct {
InputExt string `toml:"input_ext"` // input file extension InputExt string `toml:"input_ext"` // input file extension
OutputExt string `toml:"output_ext"` // output file extension OutputExt string `toml:"output_ext"` // output file extension
TemplateExt string `toml:"template_ext"` // template file extension TemplateExt string `toml:"template_ext"` // template file extension
PreProcess string `toml:"preprocess"` // preprocess command
PostProcess string `toml:"postprocess"` // postprocess command PostProcess string `toml:"postprocess"` // postprocess command
StaticDir string `toml:"static_dir"` // static file directory StaticDir string `toml:"static_dir"` // static file directory
OutputDir string `toml:"output_dir"` // output directory OutputDir string `toml:"output_dir"` // output directory
} }
func (t Task) Format(p *Page) (string, []byte) { func (t Task) OutputPath(pagePath string) string {
path := path.Join(p.Path, "index"+t.OutputExt) return path.Join(pagePath, "index"+t.OutputExt)
// Run a custom command.
if t.PostProcess != "" {
split := strings.Split(t.PostProcess, " ")
cmd := exec.Command(split[0], split[1:]...)
cmd.Stdin = strings.NewReader(p.Content)
cmd.Stderr = os.Stderr
output, err := cmd.Output()
if err != nil {
log.Fatal(err)
}
return path, output
}
return path, []byte(p.Content)
} }
// LoadConfig loads the configuration from the provided path. // LoadConfig loads the configuration from the provided path.

105
dir.go
View file

@ -2,8 +2,11 @@ package main
import ( import (
"bytes" "bytes"
"io"
"io/ioutil" "io/ioutil"
"log"
"os" "os"
"os/exec"
pathpkg "path" pathpkg "path"
"sort" "sort"
"strings" "strings"
@ -19,10 +22,6 @@ type Dir struct {
Dirs []*Dir // Subdirectories. Dirs []*Dir // Subdirectories.
index *Page // The index page. index *Page // The index page.
feed []byte // Atom feed. feed []byte // Atom feed.
inputExt string // input file extension
outputExt string // output file extension
templateExt string // template file extension
} }
// NewDir returns a new Dir with the given path. // NewDir returns a new Dir with the given path.
@ -37,8 +36,12 @@ func NewDir(path string) *Dir {
} }
} }
// read reads from a directory and indexes the files and directories within it. // Read reads from a directory and indexes the files and directories within it.
func (d *Dir) read(srcDir string, path string) error { func (d *Dir) Read(srcDir string, task *Task) error {
return d.read(srcDir, "", task)
}
func (d *Dir) read(srcDir, path string, task *Task) error {
entries, err := ioutil.ReadDir(pathpkg.Join(srcDir, path)) entries, err := ioutil.ReadDir(pathpkg.Join(srcDir, path))
if err != nil { if err != nil {
return err return err
@ -53,20 +56,21 @@ func (d *Dir) read(srcDir string, path string) error {
if entry.IsDir() { if entry.IsDir() {
// Gather directory data // Gather directory data
dir := NewDir(path) dir := NewDir(path)
dir.inputExt = d.inputExt if err := dir.read(srcDir, path, task); err != nil {
dir.outputExt = d.outputExt
dir.templateExt = d.templateExt
if err := dir.read(srcDir, path); err != nil {
return err return err
} }
d.Dirs = append(d.Dirs, dir) d.Dirs = append(d.Dirs, dir)
} else { } else if ext := pathpkg.Ext(name); ext == task.InputExt {
srcPath := pathpkg.Join(srcDir, path) srcPath := pathpkg.Join(srcDir, path)
content, err := ioutil.ReadFile(srcPath) content, err := ioutil.ReadFile(srcPath)
if err != nil { if err != nil {
return err return err
} }
if ext := pathpkg.Ext(name); ext == d.inputExt {
if cmd := task.PreProcess; cmd != "" {
content = RunProcessCmd(cmd, bytes.NewReader(content))
}
// Gather page data // Gather page data
if strings.TrimSuffix(name, ext) == "index" { if strings.TrimSuffix(name, ext) == "index" {
d.index = NewPage(d.Path, content) d.index = NewPage(d.Path, content)
@ -77,27 +81,26 @@ func (d *Dir) read(srcDir string, path string) error {
} }
} }
} }
}
return nil return nil
} }
// manipulate processes and manipulates the directory's contents. // Process processes the directory's contents.
func (d *Dir) manipulate(cfg *Config) error { func (d *Dir) Process(cfg *Config, task *Task) error {
if d.templateExt != "" { if task.TemplateExt != "" {
// Create index // Create index
if d.index != nil { if d.index != nil {
var b strings.Builder var b strings.Builder
tmpl := cfg.Templates.FindTemplate(d.Path, "index"+d.templateExt) tmpl := cfg.Templates.FindTemplate(d.Path, "index"+task.TemplateExt)
if err := tmpl.Execute(&b, d); err != nil { if err := tmpl.Execute(&b, d); err != nil {
return err return err
} }
d.index.Content = b.String() d.index.Content = b.String()
} }
// Manipulate pages // Process pages
for i := range d.Pages { for i := range d.Pages {
var b strings.Builder var b strings.Builder
tmpl := cfg.Templates.FindTemplate(d.Path, "page"+d.templateExt) tmpl := cfg.Templates.FindTemplate(d.Path, "page"+task.TemplateExt)
if err := tmpl.Execute(&b, d.Pages[i]); err != nil { if err := tmpl.Execute(&b, d.Pages[i]); err != nil {
return err return err
} }
@ -129,22 +132,17 @@ func (d *Dir) manipulate(cfg *Config) error {
d.feed = b.Bytes() d.feed = b.Bytes()
} }
// Manipulate subdirectories // Process subdirectories
for _, d := range d.Dirs { for _, d := range d.Dirs {
if err := d.manipulate(cfg); err != nil { if err := d.Process(cfg, task); err != nil {
return err return err
} }
} }
return nil return nil
} }
// Format represents an output format. // Write writes the directory's contents to the provided destination path.
type Format interface { func (d *Dir) Write(dstDir string, task *Task) error {
Format(*Page) (path string, content []byte)
}
// write writes the Dir to the provided destination path.
func (d *Dir) write(dstDir string, format Format) error {
// Create the directory // Create the directory
dirPath := pathpkg.Join(dstDir, d.Path) dirPath := pathpkg.Join(dstDir, d.Path)
if err := os.MkdirAll(dirPath, 0755); err != nil { if err := os.MkdirAll(dirPath, 0755); err != nil {
@ -152,31 +150,23 @@ func (d *Dir) write(dstDir string, format Format) error {
} }
// Write pages // Write pages
for _, page := range d.Pages { pages := d.Pages
path, content := format.Format(page) if d.index != nil {
dstPath := pathpkg.Join(dstDir, path) pages = append(pages, d.index)
dir := pathpkg.Dir(dstPath)
os.MkdirAll(dir, 0755)
f, err := os.Create(dstPath)
if err != nil {
return err
}
if _, err := f.Write(content); err != nil {
return err
} }
for _, page := range pages {
path := task.OutputPath(page.Path)
var content []byte
if cmd := task.PostProcess; cmd != "" {
content = RunProcessCmd(cmd, strings.NewReader(page.Content))
} else {
content = []byte(page.Content)
} }
// Write the index file
if d.index != nil {
path, content := format.Format(d.index)
dstPath := pathpkg.Join(dstDir, path) dstPath := pathpkg.Join(dstDir, path)
dir := pathpkg.Dir(dstPath) dir := pathpkg.Dir(dstPath)
os.MkdirAll(dir, 0755) os.MkdirAll(dir, 0755)
f, err := os.Create(dstPath) if err := os.WriteFile(dstPath, content, 0644); err != nil {
if err != nil {
return err
}
if _, err := f.Write(content); err != nil {
return err return err
} }
} }
@ -186,18 +176,14 @@ func (d *Dir) write(dstDir string, format Format) error {
const path = "atom.xml" const path = "atom.xml"
dstPath := pathpkg.Join(dstDir, path) dstPath := pathpkg.Join(dstDir, path)
os.MkdirAll(dstDir, 0755) os.MkdirAll(dstDir, 0755)
f, err := os.Create(dstPath) if err := os.WriteFile(dstPath, d.feed, 0644); err != nil {
if err != nil {
return err
}
if _, err := f.Write(d.feed); err != nil {
return err return err
} }
} }
// Write subdirectories // Write subdirectories
for _, dir := range d.Dirs { for _, dir := range d.Dirs {
dir.write(dstDir, format) dir.Write(dstDir, task)
} }
return nil return nil
} }
@ -212,3 +198,16 @@ func (d *Dir) sort() {
d.sort() d.sort()
} }
} }
// RunProcessCmd runs a process command.
func RunProcessCmd(command string, input io.Reader) []byte {
split := strings.Split(command, " ")
cmd := exec.Command(split[0], split[1:]...)
cmd.Stdin = input
cmd.Stderr = os.Stderr
output, err := cmd.Output()
if err != nil {
log.Fatal(err)
}
return output
}

13
main.go
View file

@ -86,21 +86,18 @@ func runAll(cfg *Config) error {
} }
func runTask(cfg *Config, task *Task) error { func runTask(cfg *Config, task *Task) error {
// Load content // Read content
dir := NewDir("") dir := NewDir("")
dir.inputExt = task.InputExt if err := dir.Read("content", task); err != nil {
dir.outputExt = task.OutputExt
dir.templateExt = task.TemplateExt
if err := dir.read("content", ""); err != nil {
return err return err
} }
dir.sort() dir.sort()
// Manipulate content // Process content
if err := dir.manipulate(cfg); err != nil { if err := dir.Process(cfg, task); err != nil {
return err return err
} }
// Write content // Write content
if err := dir.write(task.OutputDir, task); err != nil { if err := dir.Write(task.OutputDir, task); err != nil {
return err return err
} }
// Copy static files // Copy static files