hugoext/main.go

198 lines
4.7 KiB
Go
Raw Normal View History

2021-07-10 16:27:58 +03:00
package main
import (
"bytes"
2021-07-10 16:27:58 +03:00
"flag"
"fmt"
2021-07-11 07:27:33 +03:00
"io"
2021-07-10 16:27:58 +03:00
"log"
"os"
"os/exec"
2021-07-10 16:27:58 +03:00
"path/filepath"
"github.com/gohugoio/hugo/config"
"github.com/spf13/afero"
)
const (
2021-07-10 20:29:02 +03:00
defaultExt = "md"
defaultProcessor = ""
2021-07-10 16:27:58 +03:00
defaultSource = "content"
defaultDestination = "public"
defaultConfigPath = "config.toml"
defaultPermalinkFormat = "/:year/:month/:title/"
)
func main() {
2021-07-11 07:27:33 +03:00
var ext, pipecmd, source, destination, cfgPath string
2021-07-11 07:02:22 +03:00
var noSectionList bool
2021-07-10 16:27:58 +03:00
flag.StringVar(&ext, "ext", defaultExt, "ext to look for templates in ./layout")
2021-07-11 07:27:33 +03:00
flag.StringVar(&pipecmd, "pipe", defaultProcessor, "pipe markdown to this program for content processing")
2021-07-10 16:27:58 +03:00
flag.StringVar(&source, "source", defaultSource, "source directory")
flag.StringVar(&destination, "destination", defaultDestination, "output directory")
2021-07-10 20:18:52 +03:00
flag.StringVar(&cfgPath, "config", defaultConfigPath, "hugo config path")
flag.BoolVar(&noSectionList, "no-section-list", false, "disable auto append of section content lists")
2021-07-10 16:27:58 +03:00
flag.Parse()
// what are we doing
2021-07-11 07:27:33 +03:00
fmt.Printf("hugoext: converting hugo markdown to %v with %v\n", ext, pipecmd)
2021-07-10 20:33:55 +03:00
// config
cfg, err := config.FromFile(afero.NewOsFs(), "config.toml")
2021-07-10 16:27:58 +03:00
if err != nil {
log.Fatal("config from file", err)
}
uglyURLs := cfg.GetBool("uglyURLs")
if !cfg.IsSet("uglyURLs") {
fmt.Println("config: no uglyURLs set, using default: ", uglyURLs)
}
2021-07-11 07:02:22 +03:00
buildDrafts := cfg.GetBool("buildDrafts")
if !cfg.IsSet("buildDrafts") {
fmt.Println("config: no buildDrafts set, using default: ", buildDrafts)
}
2021-07-10 16:27:58 +03:00
permalinks := cfg.GetStringMapString("permalinks")
2021-07-10 19:32:21 +03:00
if permalinks == nil {
fmt.Println("config: no permalinks set, using default: ", defaultPermalinkFormat)
2021-07-10 19:32:21 +03:00
}
2021-07-10 16:27:58 +03:00
linkpattern := func(section string) string {
format, ok := permalinks[section]
2021-07-10 16:27:58 +03:00
if ok {
return format
}
return defaultPermalinkFormat
}
2021-07-10 17:44:25 +03:00
// process sources
// iterate through file tree source
2021-07-10 17:44:25 +03:00
files := make(chan File)
go collectFiles(source, files)
// for each file, get destination path, switch file extension, remove underscore for index
var tree FileTree
2021-07-10 17:44:25 +03:00
for file := range files {
2021-07-10 19:32:21 +03:00
pattern := linkpattern(file.Parent)
2021-07-10 17:44:25 +03:00
err := destinationPath(&file, pattern)
if err != nil {
2021-07-11 07:27:33 +03:00
log.Fatalf("failed to derive destination for %v error: %v", file.Source, err)
2021-07-10 17:44:25 +03:00
}
2021-07-11 07:27:33 +03:00
2021-07-11 07:02:22 +03:00
if file.Draft && !buildDrafts {
2021-07-10 20:18:52 +03:00
fmt.Printf("skipping draft %s (%dbytes)\n", file.Source, len(file.Body))
continue
}
tree.Files = append(tree.Files, file)
}
// call proc and pipe content through it, catch output of proc
for i, file := range tree.Files {
buf := bytes.NewReader(file.Body)
2021-07-11 07:27:33 +03:00
out := pipe(pipecmd, buf)
// write to source
2021-07-11 07:27:33 +03:00
tree.Files[i].NewBody = out
2021-07-10 19:32:21 +03:00
fmt.Printf("processed %s (%dbytes)\n", file.Source, len(tree.Files[i].Body))
}
2021-07-11 07:27:33 +03:00
newdir := filepath.Join(".", "public")
if made, err := mkdir(newdir); err != nil {
log.Fatal(err)
2021-07-11 07:27:33 +03:00
} else if made {
fmt.Printf("mkdir %s\n", newdir)
}
// write to destination
for _, file := range tree.Files {
2021-07-11 07:27:33 +03:00
outdir, outfile := targetPath(file.Destination, ext, uglyURLs)
2021-07-11 05:46:19 +03:00
// ensure directory exists
2021-07-11 07:27:33 +03:00
newdir := filepath.Join(destination, outdir)
if made, err := mkdir(newdir); err != nil {
log.Fatal(err)
} else if made {
fmt.Printf("mkdir %s\n", newdir)
}
2021-07-11 07:27:33 +03:00
fullpath := filepath.Join(newdir, outfile)
2021-07-11 05:46:19 +03:00
// create file based on directory and filename
newfile, err := os.Create(fullpath)
if err != nil {
2021-07-11 05:46:19 +03:00
log.Fatalf("cannot create file %s, error: %v", fullpath, err)
}
2021-07-10 19:32:21 +03:00
2021-07-11 05:46:19 +03:00
n, err := newfile.Write(file.NewBody)
if err != nil {
log.Fatalf("cannot write file %s, error: %v", fullpath, err)
}
newfile.Close()
2021-07-10 19:32:21 +03:00
fmt.Printf("written %s (%dbytes)\n", fullpath, n)
2021-07-10 17:44:25 +03:00
}
2021-07-11 07:27:33 +03:00
for _, file := range tree.Files {
fmt.Printf("section %v\n", file.Parent)
}
2021-07-10 20:18:52 +03:00
// TODO
//
// append section listings
// => link title line
// date - summary block
2021-07-10 19:32:21 +03:00
// TODO
2021-07-11 05:46:19 +03:00
// in watch mode, compare timestamps of files before replacement, keep index?
2021-07-10 19:32:21 +03:00
// check/replace links
2021-07-10 17:44:25 +03:00
// write rss?
// write listings from template?
2021-07-10 16:27:58 +03:00
}
2021-07-11 07:27:33 +03:00
func pipe(cmd string, input io.Reader) []byte {
extpipe := exec.Command(cmd)
extpipe.Stdin = input
var pipeout bytes.Buffer
extpipe.Stdout = &pipeout
extpipe.Start()
extpipe.Wait()
return pipeout.Bytes()
}
func targetPath(dest, newext string, uglyURLs bool) (dir string, filename string) {
filename = "index." + newext
dir = dest
if uglyURLs && dest != "index" {
// make the last element in destination the file
filename = filepath.Base(dest) + "." + newext
// set the parent directory of that file to be the dir to create
dir = filepath.Dir(dest)
}
if dest == "index" {
dir = "."
}
return
}
func mkdir(dir string) (bool, error) {
// skip if this exists
if _, err := os.Stat(dir); err == nil {
return false, nil
}
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
return false, err
}
return true, nil
}