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
|
## Roadmap
|
||||||
|
|
||||||
- [X] Recursively traverse the `recipes` directory.
|
- [X] Recursively traverse the `recipes` directory.
|
||||||
|
- [X] Add a proper CLI.
|
||||||
- [ ] Add a default CSS file.
|
- [ ] Add a default CSS file.
|
||||||
- [ ] Improve the steps rendering logic to avoid doing all of it
|
- [ ] Improve the steps rendering logic to avoid doing all of it
|
||||||
inside a template function.
|
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
|
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 h1:ynbGKI3o060m9NTlxnc1k7unjGOtJcfbxKWfiIOSqVo=
|
||||||
github.com/aquilax/cooklang-go v0.1.7/go.mod h1:1/65y8LN2Nhr6WNVh64ZqggvZmeymQHKavxUONeJmTk=
|
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 (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"embed"
|
"embed"
|
||||||
"flag"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
|
@ -13,6 +12,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/alecthomas/kong"
|
||||||
"github.com/aquilax/cooklang-go"
|
"github.com/aquilax/cooklang-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -128,38 +128,41 @@ func copyFile(srcpath, dstpath string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
recipesFlag := flag.String("recipes", "recipes", "Path to the directory with the recipes.")
|
ctx := kong.Parse(&cli)
|
||||||
outputFlag := flag.String("output", "dist", "Path to the directory where the files will be generated.")
|
if cli.Debug {
|
||||||
debugFlag := flag.Bool("debug", false, "Enables debug information.")
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
if *debugFlag {
|
|
||||||
slog.SetLogLoggerLevel(slog.LevelDebug)
|
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) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
panic(err)
|
return fmt.Errorf("cannot stat %q: %w", g.Output, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !os.IsNotExist(err) && !fi.IsDir() {
|
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 {
|
} else {
|
||||||
if err := os.RemoveAll(*outputFlag); err != nil {
|
if err := os.RemoveAll(g.Output); err != nil {
|
||||||
panic(err)
|
return fmt.Errorf("cannot remove %q: %w", g.Output, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := os.Mkdir(*outputFlag, 0755); err != nil {
|
if err := os.Mkdir(g.Output, 0755); err != nil {
|
||||||
panic(err)
|
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)
|
slog.Debug("Walking through file", "path", path)
|
||||||
relpath := filepath.Join(strings.Split(path, "/")[1:]...)
|
relpath := filepath.Join(strings.Split(path, "/")[1:]...)
|
||||||
ext := filepath.Ext(d.Name())
|
ext := filepath.Ext(d.Name())
|
||||||
recipeName := strings.TrimSuffix(d.Name(), ext)
|
recipeName := strings.TrimSuffix(d.Name(), ext)
|
||||||
if d.IsDir() {
|
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)
|
slog.Debug("Directory found, creating output dir", "path", path, "dirpath", dirpath)
|
||||||
if err := os.MkdirAll(dirpath, 0755); err != nil {
|
if err := os.MkdirAll(dirpath, 0755); err != nil {
|
||||||
return fmt.Errorf("cannot create directory %s: %w", dirpath, err)
|
return fmt.Errorf("cannot create directory %s: %w", dirpath, err)
|
||||||
|
@ -168,7 +171,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ext != ".cook" {
|
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)
|
slog.Debug("Non-recipe file found, copying", "src", path, "dst", dstPath)
|
||||||
if err := copyFile(path, dstPath); err != nil {
|
if err := copyFile(path, dstPath); err != nil {
|
||||||
return fmt.Errorf("cannot copy file from %q to %q: %w", path, dstPath, err)
|
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)
|
slog.Debug("Parsing file", "name", path)
|
||||||
recipe, err := cooklang.ParseFile(path)
|
recipe, err := cooklang.ParseFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return fmt.Errorf("cannot parse file %q: %w", path, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(recipe.Steps) == 0 {
|
if len(recipe.Steps) == 0 {
|
||||||
|
@ -189,17 +192,19 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.Debug("Parsed file", "path", path, "steps", len(recipe.Steps))
|
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}
|
data := map[string]any{"name": recipeName, "recipe": recipe}
|
||||||
slog.Debug("Executing template", "recipeName", recipeName, "recipeWebPath", recipeDistPath)
|
slog.Debug("Executing template", "recipeName", recipeName, "recipeWebPath", recipeDistPath)
|
||||||
if err := executeTemplateToFile("recipe", data, recipeDistPath); err != nil {
|
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
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if walkErr != 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