1
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
package hooks
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// templateFS is the checked-in git template directory. It ships real, copy-able
|
||||
// hook scripts (one per git hook name) under template/hooks/. The daemon
|
||||
// materializes it to <root>/template at startup and CreateRepo passes
|
||||
// --template=<root>/template to `git init --bare`, so every new repo gets these
|
||||
// hooks verbatim. This is the "template repo": a versioned, inspectable artifact
|
||||
// rather than something generated from a Go string.
|
||||
//
|
||||
//go:embed template
|
||||
var templateFS embed.FS
|
||||
|
||||
// TemplateDir returns the on-disk git template directory for root: <root>/template.
|
||||
// CreateRepo passes --template=<TemplateDir> to `git init --bare`.
|
||||
func TemplateDir(root string) string {
|
||||
return filepath.Join(root, "template")
|
||||
}
|
||||
|
||||
// EnsureTemplate materializes the embedded template directory to <root>/template
|
||||
// and returns the template dir. Files under hooks/ are made executable (go:embed
|
||||
// does not preserve the executable bit). Idempotent: rewrites every file each
|
||||
// call, so an updated template is picked up on the next daemon start.
|
||||
func EnsureTemplate(root string) (string, error) {
|
||||
dst := TemplateDir(root)
|
||||
if err := os.MkdirAll(dst, 0o755); err != nil {
|
||||
return "", fmt.Errorf("hooks: mkdir template: %w", err)
|
||||
}
|
||||
err := fs.WalkDir(templateFS, "template", func(p string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.IsDir() {
|
||||
return os.MkdirAll(filepath.Join(root, p), 0o755)
|
||||
}
|
||||
data, err := templateFS.ReadFile(p)
|
||||
if err != nil {
|
||||
return fmt.Errorf("hooks: read embedded %s: %w", p, err)
|
||||
}
|
||||
out := filepath.Join(root, p)
|
||||
if err := os.WriteFile(out, data, 0o644); err != nil {
|
||||
return fmt.Errorf("hooks: write %s: %w", p, err)
|
||||
}
|
||||
// Hook scripts must be executable; go:embed does not preserve mode bits.
|
||||
if filepath.Dir(p) == "template/hooks" {
|
||||
if err := os.Chmod(out, 0o755); err != nil {
|
||||
return fmt.Errorf("hooks: chmod %s: %w", p, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
Reference in New Issue
Block a user