cmd/tilstream/cmd/init.go

package cmd

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/spf13/cobra"
)

var initForce bool

var initCmd = &cobra.Command{
	Use:   "init [dir]",
	Short: "Bootstrap a new tilstream site",
	Args:  cobra.MaximumNArgs(1),
	RunE:  runInit,
}

func init() {
	initCmd.Flags().BoolVar(&initForce, "force", false, "overwrite existing files")
}

func runInit(cmd *cobra.Command, args []string) error {
	dir := "."
	if len(args) == 1 {
		dir = args[0]
	}
	if err := os.MkdirAll(dir, 0o755); err != nil {
		return err
	}
	files := map[string]string{
		"tilstream.yaml": defaultConfig,
		"content/hello.md": "---\ntitle: Hello\ndate: 2025-01-01\n---\n\nFirst TIL!\n",
		"templates/index.tmpl": defaultIndexTmpl,
		"templates/post.tmpl":  defaultPostTmpl,
		".gitignore":           "public/\n",
	}
	for name, body := range files {
		full := filepath.Join(dir, name)
		if err := os.MkdirAll(filepath.Dir(full), 0o755); err != nil {
			return err
		}
		if _, err := os.Stat(full); err == nil && !initForce {
			fmt.Fprintf(cmd.ErrOrStderr(), "skip existing %s\n", full)
			continue
		}
		if err := os.WriteFile(full, []byte(body), 0o644); err != nil {
			return err
		}
		fmt.Printf("wrote %s\n", full)
	}
	fmt.Println("done. next: tilstream build && tilstream serve")
	return nil
}

const defaultConfig = `title: "My TIL"
baseURL: "https://example.com"
author: "me"
language: "en-us"
`

const defaultIndexTmpl = `{{ define "index" }}
<!doctype html>
<html lang="en"><head><meta charset="utf-8"><title>{{ .Title }}</title></head>
<body>
  <h1>{{ .Title }}</h1>
  <ul>
  {{ range .Posts }}
    <li><a href="{{ .URL }}">{{ .Title }}</a></li>
  {{ end }}
  </ul>
</body></html>
{{ end }}
`

const defaultPostTmpl = `{{ define "post" }}
<!doctype html>
<html lang="en"><head><meta charset="utf-8"><title>{{ .Title }}</title></head>
<body>
  <article>
    <h1>{{ .Title }}</h1>
    {{ .HTML }}
  </article>
</body></html>
{{ end }}
`