fix(install): Copy embedded formulas to new installations
When `gt install` creates a new HQ, formulas were not being provisioned to `.beads/formulas/`. This embeds the formula library into the gt binary and copies them during installation. - Add go:generate directive to copy formulas from .beads/formulas/ - Add internal/formula/embed.go with ProvisionFormulas() function - Call ProvisionFormulas() from runInstall() after beads init - Add generate target to Makefile (build depends on it) - Add TestInstallFormulasProvisioned integration test - Log warning if formula stat fails with unexpected error 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
62
internal/formula/embed.go
Normal file
62
internal/formula/embed.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package formula
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Generate formulas directory from canonical source at .beads/formulas/
|
||||
//go:generate sh -c "rm -rf formulas && mkdir -p formulas && cp ../../.beads/formulas/*.formula.toml ../../.beads/formulas/*.formula.json formulas/ 2>/dev/null || cp ../../.beads/formulas/*.formula.toml formulas/"
|
||||
|
||||
//go:embed formulas/*.formula.toml formulas/*.formula.json
|
||||
var formulasFS embed.FS
|
||||
|
||||
// ProvisionFormulas creates the .beads/formulas/ directory with embedded formulas.
|
||||
// This ensures new installations have the standard formula library.
|
||||
// If a formula already exists, it is skipped (no overwrite).
|
||||
// Returns the number of formulas provisioned.
|
||||
func ProvisionFormulas(beadsPath string) (int, error) {
|
||||
entries, err := formulasFS.ReadDir("formulas")
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("reading formulas directory: %w", err)
|
||||
}
|
||||
|
||||
// Create .beads/formulas/ directory
|
||||
formulasDir := filepath.Join(beadsPath, ".beads", "formulas")
|
||||
if err := os.MkdirAll(formulasDir, 0755); err != nil {
|
||||
return 0, fmt.Errorf("creating formulas directory: %w", err)
|
||||
}
|
||||
|
||||
count := 0
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
destPath := filepath.Join(formulasDir, entry.Name())
|
||||
|
||||
// Skip if formula already exists (don't overwrite user customizations)
|
||||
if _, err := os.Stat(destPath); err == nil {
|
||||
continue
|
||||
} else if !os.IsNotExist(err) {
|
||||
// Log unexpected errors (e.g., permission denied) but continue
|
||||
log.Printf("warning: could not check formula %s: %v", entry.Name(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
content, err := formulasFS.ReadFile("formulas/" + entry.Name())
|
||||
if err != nil {
|
||||
return count, fmt.Errorf("reading %s: %w", entry.Name(), err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(destPath, content, 0644); err != nil {
|
||||
return count, fmt.Errorf("writing %s: %w", entry.Name(), err)
|
||||
}
|
||||
count++
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
Reference in New Issue
Block a user