package main import ( "embed" "flag" "fmt" "io" "io/fs" "log" "os" "path" "path/filepath" "strings" ) var ( Version string ) func main() { if len(os.Args) >= 2 { switch os.Args[1] { case "build": build() return case "new": if len(os.Args) < 3 { fmt.Println("usage: kiln new ") os.Exit(1) } newSite(os.Args[2]) return case "version": fmt.Println("kiln", Version) return } } fmt.Println("usage: kiln args...") os.Exit(1) } func build() { var ( task string config string ) flags := flag.NewFlagSet("kiln build", flag.ExitOnError) flags.StringVar(&task, "t", "", "the task to run") flags.StringVar(&config, "c", "config.toml", "the configuration file to use") flags.Parse(os.Args[2:]) // Load config cfg, err := LoadConfig(config) if err != nil { log.Fatal(err) } templateExts := []string{} for _, task := range cfg.Tasks { if task.TemplateExt != "" { templateExts = append(templateExts, task.TemplateExt) } } if err := cfg.LoadTemplates("templates", templateExts); err != nil { log.Fatal(err) } if err := run(cfg, task); err != nil { log.Fatal(err) } } func run(cfg *Config, taskName string) error { if taskName == "" { return runAll(cfg) } task, ok := cfg.Tasks[taskName] if !ok { return fmt.Errorf("run task %q: no such task", taskName) } return runTask(cfg, task) } func runAll(cfg *Config) error { for _, task := range cfg.Tasks { err := runTask(cfg, task) if err != nil { return err } } return nil } func runTask(cfg *Config, task *Task) error { // Read content dir := NewDir("") if err := dir.Read("content", task); err != nil { return err } dir.sort() // Process content if err := dir.Process(cfg, task); err != nil { return err } // Write content if err := dir.Write(task.OutputDir, task); err != nil { return err } // Copy static files if task.StaticDir != "" { err := copyAll(task.StaticDir, task.OutputDir) if err != nil { return err } } return nil } func copyAll(srcDir, dstDir string) error { return filepath.Walk(srcDir, func(path string, info fs.FileInfo, err error) error { if info.IsDir() { // Do nothing return nil } src, err := os.Open(path) if err != nil { return err } defer src.Close() dstPath := filepath.Join(dstDir, strings.TrimPrefix(path, srcDir)) os.MkdirAll(filepath.Dir(dstPath), 0755) dst, err := os.Create(dstPath) if err != nil { return err } defer dst.Close() if _, err := io.Copy(dst, src); err != nil { return err } return nil }) } //go:embed templates config.toml var builtin embed.FS func newSite(name string) { name = path.Clean(name) os.Mkdir(name, 0755) os.Mkdir(path.Join(name, "content"), 0755) os.Mkdir(path.Join(name, "templates"), 0755) os.Mkdir(path.Join(name, "templates/_default"), 0755) os.Mkdir(path.Join(name, "static"), 0755) config, _ := builtin.ReadFile("config.toml") os.WriteFile(path.Join(name, "config.toml"), config, 0644) index := []byte("# Hello, world!\n") os.WriteFile(path.Join(name, "content/index.gmi"), index, 0644) templates := []string{"atom.xml", "index.gmi", "page.gmi"} for _, template := range templates { b, _ := builtin.ReadFile(path.Join("templates", template)) os.WriteFile(path.Join(name, "templates/_default", template), b, 0644) } }