Adds a proper CLI
This commit is contained in:
parent
8213c61bf7
commit
943e9df086
5 changed files with 51 additions and 22 deletions
|
@ -6,6 +6,7 @@ A simple CLI tool to generate a static website from a
|
|||
## Roadmap
|
||||
|
||||
- [X] Recursively traverse the `recipes` directory.
|
||||
- [X] Add a proper CLI.
|
||||
- [ ] Add a default CSS file.
|
||||
- [ ] Improve the steps rendering logic to avoid doing all of it
|
||||
inside a template function.
|
||||
|
|
12
cmd.go
Normal file
12
cmd.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
package main
|
||||
|
||||
type generateCmd struct {
|
||||
Path string `arg:"" help:"Path to the directory with the recipes."`
|
||||
Output string `default:"dist" help:"Path to the directory where the files will be generated."`
|
||||
}
|
||||
|
||||
var cli struct {
|
||||
Debug bool `help:"Print debug information."`
|
||||
|
||||
Generate generateCmd `cmd:"" help:"Generate the web files for a directory of recipes."`
|
||||
}
|
5
go.mod
5
go.mod
|
@ -2,4 +2,7 @@ module git.ctrlz.es/sandwitchboard
|
|||
|
||||
go 1.22.3
|
||||
|
||||
require github.com/aquilax/cooklang-go v0.1.7
|
||||
require (
|
||||
github.com/alecthomas/kong v0.9.0
|
||||
github.com/aquilax/cooklang-go v0.1.7
|
||||
)
|
||||
|
|
8
go.sum
8
go.sum
|
@ -1,2 +1,10 @@
|
|||
github.com/alecthomas/assert/v2 v2.6.0 h1:o3WJwILtexrEUk3cUVal3oiQY2tfgr/FHWiz/v2n4FU=
|
||||
github.com/alecthomas/assert/v2 v2.6.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/kong v0.9.0 h1:G5diXxc85KvoV2f0ZRVuMsi45IrBgx9zDNGNj165aPA=
|
||||
github.com/alecthomas/kong v0.9.0/go.mod h1:Y47y5gKfHp1hDc7CH7OeXgLIpp+Q2m1Ni0L5s3bI8Os=
|
||||
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
||||
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/aquilax/cooklang-go v0.1.7 h1:ynbGKI3o060m9NTlxnc1k7unjGOtJcfbxKWfiIOSqVo=
|
||||
github.com/aquilax/cooklang-go v0.1.7/go.mod h1:1/65y8LN2Nhr6WNVh64ZqggvZmeymQHKavxUONeJmTk=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||
|
|
|
@ -3,7 +3,6 @@ package main
|
|||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"flag"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
|
@ -13,6 +12,7 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/alecthomas/kong"
|
||||
"github.com/aquilax/cooklang-go"
|
||||
)
|
||||
|
||||
|
@ -128,38 +128,41 @@ func copyFile(srcpath, dstpath string) error {
|
|||
}
|
||||
|
||||
func main() {
|
||||
recipesFlag := flag.String("recipes", "recipes", "Path to the directory with the recipes.")
|
||||
outputFlag := flag.String("output", "dist", "Path to the directory where the files will be generated.")
|
||||
debugFlag := flag.Bool("debug", false, "Enables debug information.")
|
||||
flag.Parse()
|
||||
|
||||
if *debugFlag {
|
||||
ctx := kong.Parse(&cli)
|
||||
if cli.Debug {
|
||||
slog.SetLogLoggerLevel(slog.LevelDebug)
|
||||
}
|
||||
|
||||
fi, err := os.Stat(*outputFlag)
|
||||
if err := ctx.Run(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *generateCmd) Run() error {
|
||||
fi, err := os.Stat(g.Output)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
panic(err)
|
||||
return fmt.Errorf("cannot stat %q: %w", g.Output, err)
|
||||
}
|
||||
|
||||
if !os.IsNotExist(err) && !fi.IsDir() {
|
||||
panic(fmt.Errorf("path %q is not a directory", *outputFlag))
|
||||
return fmt.Errorf("path %q is not a directory", g.Output)
|
||||
} else {
|
||||
if err := os.RemoveAll(*outputFlag); err != nil {
|
||||
panic(err)
|
||||
if err := os.RemoveAll(g.Output); err != nil {
|
||||
return fmt.Errorf("cannot remove %q: %w", g.Output, err)
|
||||
}
|
||||
}
|
||||
if err := os.Mkdir(*outputFlag, 0755); err != nil {
|
||||
panic(err)
|
||||
if err := os.Mkdir(g.Output, 0755); err != nil {
|
||||
return fmt.Errorf("cannot create directory on path %q: %w", g.Output, err)
|
||||
}
|
||||
|
||||
walkErr := filepath.WalkDir(*recipesFlag, func(path string, d fs.DirEntry, err error) error {
|
||||
walkErr := filepath.WalkDir(g.Path, func(path string, d fs.DirEntry, err error) error {
|
||||
slog.Debug("Walking through file", "path", path)
|
||||
relpath := filepath.Join(strings.Split(path, "/")[1:]...)
|
||||
ext := filepath.Ext(d.Name())
|
||||
recipeName := strings.TrimSuffix(d.Name(), ext)
|
||||
if d.IsDir() {
|
||||
dirpath := filepath.Join(*outputFlag, relpath)
|
||||
dirpath := filepath.Join(g.Output, relpath)
|
||||
slog.Debug("Directory found, creating output dir", "path", path, "dirpath", dirpath)
|
||||
if err := os.MkdirAll(dirpath, 0755); err != nil {
|
||||
return fmt.Errorf("cannot create directory %s: %w", dirpath, err)
|
||||
|
@ -168,7 +171,7 @@ func main() {
|
|||
}
|
||||
|
||||
if ext != ".cook" {
|
||||
dstPath := filepath.Join(*outputFlag, relpath)
|
||||
dstPath := filepath.Join(g.Output, relpath)
|
||||
slog.Debug("Non-recipe file found, copying", "src", path, "dst", dstPath)
|
||||
if err := copyFile(path, dstPath); err != nil {
|
||||
return fmt.Errorf("cannot copy file from %q to %q: %w", path, dstPath, err)
|
||||
|
@ -180,7 +183,7 @@ func main() {
|
|||
slog.Debug("Parsing file", "name", path)
|
||||
recipe, err := cooklang.ParseFile(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return fmt.Errorf("cannot parse file %q: %w", path, err)
|
||||
}
|
||||
|
||||
if len(recipe.Steps) == 0 {
|
||||
|
@ -189,17 +192,19 @@ func main() {
|
|||
}
|
||||
|
||||
slog.Debug("Parsed file", "path", path, "steps", len(recipe.Steps))
|
||||
recipeDistPath := filepath.Join(*outputFlag, filepath.Dir(relpath), fmt.Sprintf("%s.html", recipeName))
|
||||
recipeDistPath := filepath.Join(g.Output, filepath.Dir(relpath), fmt.Sprintf("%s.html", recipeName))
|
||||
data := map[string]any{"name": recipeName, "recipe": recipe}
|
||||
slog.Debug("Executing template", "recipeName", recipeName, "recipeWebPath", recipeDistPath)
|
||||
if err := executeTemplateToFile("recipe", data, recipeDistPath); err != nil {
|
||||
panic(err)
|
||||
return fmt.Errorf("cannot execute template \"recipe\" to file %q: %w", recipeDistPath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if walkErr != nil {
|
||||
panic(walkErr)
|
||||
return fmt.Errorf("error while walking directory %q: %w", g.Path, walkErr)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue