main.go
117 Zeilen · 3.0 KB · Go
| 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "flag" |
| 5 | "fmt" |
| 6 | "log" |
| 7 | "os" |
| 8 | "path/filepath" |
| 9 | "sort" |
| 10 | "strings" |
| 11 | |
| 12 | "github.com/ruedigerp/newblog/internal/config" |
| 13 | "github.com/ruedigerp/newblog/internal/content" |
| 14 | "github.com/ruedigerp/newblog/internal/generator" |
| 15 | "github.com/ruedigerp/newblog/internal/server" |
| 16 | "github.com/ruedigerp/newblog/internal/templates" |
| 17 | ) |
| 18 | |
| 19 | func usage() { |
| 20 | fmt.Println("Usage: quilldrop <serve|generate> [flags]") |
| 21 | fmt.Println() |
| 22 | fmt.Println("Commands:") |
| 23 | fmt.Println(" serve Start the dynamic HTTP server") |
| 24 | fmt.Println(" generate Generate static HTML files") |
| 25 | fmt.Println() |
| 26 | fmt.Println("Flags:") |
| 27 | fmt.Println(" -config <path> Config file (default: config.yaml)") |
| 28 | fmt.Println(" -theme <name> Theme to use, overrides 'theme' from the config") |
| 29 | fmt.Println(" -dev serve: reload templates on every request (live reload)") |
| 30 | } |
| 31 | |
| 32 | func main() { |
| 33 | if len(os.Args) < 2 { |
| 34 | usage() |
| 35 | os.Exit(1) |
| 36 | } |
| 37 | |
| 38 | cmd := os.Args[1] |
| 39 | if cmd != "serve" && cmd != "generate" { |
| 40 | fmt.Printf("Unknown command: %s\n", cmd) |
| 41 | usage() |
| 42 | os.Exit(1) |
| 43 | } |
| 44 | |
| 45 | fs := flag.NewFlagSet(cmd, flag.ExitOnError) |
| 46 | configPath := fs.String("config", "config.yaml", "path to the config file") |
| 47 | theme := fs.String("theme", "", "theme to use, overrides 'theme' from the config") |
| 48 | dev := fs.Bool("dev", false, "serve: reload templates on every request") |
| 49 | if err := fs.Parse(os.Args[2:]); err != nil { |
| 50 | os.Exit(1) |
| 51 | } |
| 52 | if *dev && cmd != "serve" { |
| 53 | log.Fatalf("-dev is only supported for 'serve'") |
| 54 | } |
| 55 | templates.SetDevMode(*dev) |
| 56 | |
| 57 | cfg, err := config.Load(*configPath) |
| 58 | if err != nil { |
| 59 | log.Fatalf("Failed to load config: %v", err) |
| 60 | } |
| 61 | if *theme != "" { |
| 62 | cfg.Theme = *theme |
| 63 | } |
| 64 | if err := checkTheme(cfg); err != nil { |
| 65 | log.Fatalf("%v", err) |
| 66 | } |
| 67 | |
| 68 | posts, err := content.LoadAll(cfg.ContentDir) |
| 69 | if err != nil { |
| 70 | log.Fatalf("Failed to load posts: %v", err) |
| 71 | } |
| 72 | log.Printf("Loaded %d posts", len(posts)) |
| 73 | |
| 74 | pages, err := content.LoadAllPages(cfg.SitesDir) |
| 75 | if err != nil { |
| 76 | log.Fatalf("Failed to load pages: %v", err) |
| 77 | } |
| 78 | log.Printf("Loaded %d pages", len(pages)) |
| 79 | |
| 80 | switch cmd { |
| 81 | case "serve": |
| 82 | server.Start(cfg, posts, pages) |
| 83 | case "generate": |
| 84 | generator.Generate(cfg, posts, pages) |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | // checkTheme verifies the configured theme exists and reports the available |
| 89 | // themes otherwise. |
| 90 | func checkTheme(cfg *config.Config) error { |
| 91 | if info, err := os.Stat(cfg.ThemeTemplatesDir()); err == nil && info.IsDir() { |
| 92 | return nil |
| 93 | } |
| 94 | msg := fmt.Sprintf("Theme %q not found: %s is missing", cfg.Theme, cfg.ThemeTemplatesDir()) |
| 95 | if available := availableThemes(cfg.ThemesDir); len(available) > 0 { |
| 96 | msg += fmt.Sprintf(" (available themes: %s)", strings.Join(available, ", ")) |
| 97 | } |
| 98 | return fmt.Errorf("%s", msg) |
| 99 | } |
| 100 | |
| 101 | func availableThemes(themesDir string) []string { |
| 102 | entries, err := os.ReadDir(themesDir) |
| 103 | if err != nil { |
| 104 | return nil |
| 105 | } |
| 106 | var themes []string |
| 107 | for _, e := range entries { |
| 108 | if !e.IsDir() { |
| 109 | continue |
| 110 | } |
| 111 | if info, err := os.Stat(filepath.Join(themesDir, e.Name(), "templates")); err == nil && info.IsDir() { |
| 112 | themes = append(themes, e.Name()) |
| 113 | } |
| 114 | } |
| 115 | sort.Strings(themes) |
| 116 | return themes |
| 117 | } |