summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/snonux/main.go113
1 files changed, 113 insertions, 0 deletions
diff --git a/cmd/snonux/main.go b/cmd/snonux/main.go
new file mode 100644
index 0000000..5a9c9d3
--- /dev/null
+++ b/cmd/snonux/main.go
@@ -0,0 +1,113 @@
+// Command snonux is the static microblog generator for snonux.foo.
+// It processes new source files from the input directory into post directories,
+// then regenerates all HTML pages and the Atom feed in the output directory.
+//
+// Usage:
+//
+// snonux --input ./inbox --output ./outdir [--base-url https://snonux.foo]
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+
+ "codeberg.org/snonux/snonux/internal/config"
+ "codeberg.org/snonux/snonux/internal/generator"
+ "codeberg.org/snonux/snonux/internal/processor"
+)
+
+func main() {
+ cfg, err := parseFlags()
+ if err != nil {
+ log.Fatalf("error: %v", err)
+ }
+
+ if err := run(cfg); err != nil {
+ log.Fatalf("error: %v", err)
+ }
+}
+
+// parseFlags reads CLI flags and returns a validated Config.
+func parseFlags() (*config.Config, error) {
+ cfg := &config.Config{}
+
+ flag.StringVar(&cfg.InputDir, "input", "./inbox", "directory containing new source files to process")
+ flag.StringVar(&cfg.OutputDir, "output", "~/git/snonux.foo/dist", "root directory for generated static site output")
+ flag.StringVar(&cfg.BaseURL, "base-url", "https://snonux.foo", "canonical base URL used in Atom feed links")
+ flag.StringVar(&cfg.Theme, "theme", "neon", "visual theme: aurora, brutalist, glass, matrix, minimal, neon, ocean, paper, retro, synthwave, terminal")
+ flag.Parse()
+
+ var err error
+
+ cfg.InputDir, err = expandHome(cfg.InputDir)
+ if err != nil {
+ return nil, fmt.Errorf("input dir: %w", err)
+ }
+
+ cfg.OutputDir, err = expandHome(cfg.OutputDir)
+ if err != nil {
+ return nil, fmt.Errorf("output dir: %w", err)
+ }
+
+ if err := ensureDir(cfg.InputDir); err != nil {
+ return nil, fmt.Errorf("input dir: %w", err)
+ }
+
+ if err := ensureDir(cfg.OutputDir); err != nil {
+ return nil, fmt.Errorf("output dir: %w", err)
+ }
+
+ return cfg, nil
+}
+
+// expandHome replaces a leading ~ with the current user's home directory.
+func expandHome(path string) (string, error) {
+ if len(path) == 0 || path[0] != '~' {
+ return path, nil
+ }
+
+ home, err := os.UserHomeDir()
+ if err != nil {
+ return "", fmt.Errorf("resolve home dir: %w", err)
+ }
+
+ return filepath.Join(home, path[1:]), nil
+}
+
+// run executes both pipeline phases: process inputs, then regenerate pages.
+func run(cfg *config.Config) error {
+ processed, err := processor.Run(cfg)
+ if err != nil {
+ return fmt.Errorf("processing input files: %w", err)
+ }
+
+ log.Printf("processed %d new post(s) from %s", processed, cfg.InputDir)
+
+ if err := generator.Run(cfg); err != nil {
+ return fmt.Errorf("generating site: %w", err)
+ }
+
+ log.Printf("site regenerated in %s", cfg.OutputDir)
+
+ return nil
+}
+
+// ensureDir creates dir if it does not exist, or returns an error if path
+// exists but is not a directory.
+func ensureDir(dir string) error {
+ info, err := os.Stat(dir)
+ if os.IsNotExist(err) {
+ return os.MkdirAll(dir, 0o755)
+ }
+ if err != nil {
+ return err
+ }
+ if !info.IsDir() {
+ return fmt.Errorf("%s exists but is not a directory", dir)
+ }
+
+ return nil
+}