package common import ( "fmt" "io/fs" "os" "path/filepath" "strings" ) var gitHookNames = []string{ "pre-receive", "update", "post-receive", "post-update", "proc-receive", "push-to-checkout", "reference-transaction", "pre-applypatch", "post-applypatch", "pre-commit", "pre-merge-commit", "prepare-commit-msg", "commit-msg", "post-commit", "pre-rebase", "post-checkout", "post-merge", "pre-push", "pre-auto-gc", "post-rewrite", "sendemail-validate", "fsmonitor-watchman", "p4-pre-submit", "p4-post-changelist", "p4-prepare-changelist", "p4-changelist", } const hookWrapper = `#!/bin/sh # Generated by simplegit. The operator controls hook behavior with -hook-script. test -n "$SIMPLEGIT_HOOK_SCRIPT" || exit 0 repo_dir=$(pwd -P) repo=${repo_dir#"$SIMPLEGIT_REPO_ROOT"/} repo=${repo%%.git} exec "$SIMPLEGIT_HOOK_SCRIPT" %s "$repo" "$@" ` // EnsureHookTemplate creates the git-init template used for new repositories. // All hook entrypoints delegate to one environment-specific external script. func EnsureHookTemplate(root string) (string, error) { dir := filepath.Join(root, "template") hooksDir := filepath.Join(dir, "hooks") if err := os.MkdirAll(hooksDir, 0o755); err != nil { return "", fmt.Errorf("create hook template: %w", err) } for _, name := range gitHookNames { path := filepath.Join(hooksDir, name) if err := os.WriteFile(path, []byte(fmt.Sprintf(hookWrapper, name)), 0o755); err != nil { return "", fmt.Errorf("write hook %s: %w", name, err) } } if err := refreshRepositoryHooks(filepath.Join(root, "repos"), hooksDir); err != nil { return "", err } return dir, nil } // refreshRepositoryHooks updates repositories created with an older template. func refreshRepositoryHooks(reposRoot, templateHooks string) error { if _, err := os.Stat(reposRoot); os.IsNotExist(err) { return nil } return filepath.WalkDir(reposRoot, func(path string, entry fs.DirEntry, err error) error { if err != nil { return err } if !entry.IsDir() || !strings.HasSuffix(entry.Name(), ".git") { return nil } dst := filepath.Join(path, "hooks") if err := os.MkdirAll(dst, 0o755); err != nil { return err } for _, name := range gitHookNames { body, err := os.ReadFile(filepath.Join(templateHooks, name)) if err != nil { return err } if err := os.WriteFile(filepath.Join(dst, name), body, 0o755); err != nil { return err } } return filepath.SkipDir }) }