Files
draft/tools/sync_templates.go
T
FernandoJVideiraandClaude Fable 5.1 2f1ad93a74 Ship the client Dockerfile with generated Nuxt apps; bump to v0.2.0
A generated monorepo's docker-compose.yml already built apps/client from
apps/client/Dockerfile, but the client overlay only embedded app/ and
public/, so the file never existed and `docker compose build client`
failed on every fresh project. The client-nuxt sync job now embeds the
template's Dockerfile too, and the Nuxt scaffold rewrites its pnpm pin to
the locally detected version - the one that produces the generated
project's lockfile - the same way it already stamps packageManager.

Bumps the submodule to the template commit that mounts ~/.npmrc as a
build secret for the registry token, and the Makefile VERSION to v0.2.0
for the release.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-16 13:08:18 +01:00

132 lines
3.1 KiB
Go

//go:build ignore
package main
import (
"log"
"os"
"os/exec"
"path/filepath"
"strings"
)
const (
oldModuleName = "app_tmpl"
moduleTemplate = "{{ .ModuleName }}"
)
type syncJob struct {
templateName string // optional, for logging purposes
sourceDir string
targetDir string
excludePrefix string // relative-path prefix to skip, e.g. "apps/"; empty = sync everything
includePrefixes []string // if set, only paths with one of these prefixes sync; empty = sync everything
}
var jobs = []syncJob{
{
templateName: "api",
sourceDir: "assets/testdata/template/apps/api",
targetDir: "assets/embedded/api",
},
{
templateName: "monorepo-root",
sourceDir: "assets/testdata/template",
targetDir: "assets/embedded/monorepo-root",
excludePrefix: "apps/",
},
{
templateName: "client-nuxt",
sourceDir: "assets/testdata/template/apps/client",
targetDir: "assets/embedded/client-nuxt",
includePrefixes: []string{"app/", "public/", "Dockerfile"},
},
{
templateName: "client-vue",
sourceDir: "assets/testdata/template/apps/vue-client",
targetDir: "assets/embedded/client-vue",
includePrefixes: []string{
"src/App.vue",
"src/main.ts",
"src/router/",
"src/stores/",
"src/composables/",
"src/lib/api-client.ts",
"src/components/AppBrand.vue",
"src/components/AppLayout.vue",
"src/views/",
"src/shared/",
".env.example",
},
},
}
func main() {
log.Println("Syncing templates...")
for _, job := range jobs {
syncTemplates(job)
}
}
func syncTemplates(job syncJob) {
err := os.RemoveAll(job.targetDir)
if err != nil {
log.Fatalf("Error removing target directory: %v", err)
}
cmd := exec.Command("git", "-C", job.sourceDir, "ls-files")
output, err := cmd.Output()
if err != nil {
log.Fatalf("Error listing files in source directory: %v", err)
}
paths := strings.Split(strings.TrimSpace(string(output)), "\n")
for _, relPath := range paths {
if len(job.includePrefixes) > 0 {
included := false
for _, prefix := range job.includePrefixes {
if strings.HasPrefix(relPath, prefix) {
included = true
break
}
}
if !included {
continue
}
} else if job.excludePrefix != "" && strings.HasPrefix(relPath, job.excludePrefix) {
continue
}
srcPath := filepath.Join(job.sourceDir, relPath)
destPath := filepath.Join(job.targetDir, relPath)
if err := os.MkdirAll(filepath.Dir(destPath), 0755); err != nil {
log.Fatalf("Error creating destination directory: %v", err)
}
content, err := os.ReadFile(srcPath)
if err != nil {
log.Fatalf("Error reading source file: %v", err)
}
if filepath.Base(relPath) == "go.mod" || filepath.Base(relPath) == "go.sum" {
destPath += ".tmpl"
}
if filepath.Base(relPath) == "go.mod" {
strContent := string(content)
strContent = strings.Replace(strContent, oldModuleName, moduleTemplate, 1)
content = []byte(strContent)
}
if err := os.WriteFile(destPath, content, 0644); err != nil {
log.Fatalf("Error writing to destination file: %v", err)
}
}
log.Printf("Template %s synced successfully!", job.templateName)
}