This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / hook / setup.go
3.2 kB 143 lines
1// heavily inspired by gitea's model 2 3package hook 4 5import ( 6 "errors" 7 "fmt" 8 "os" 9 "path/filepath" 10 "strings" 11 12 "github.com/go-git/go-git/v5" 13) 14 15var ErrNoGitRepo = errors.New("not a git repo") 16var ErrCreatingHookDir = errors.New("failed to create hooks directory") 17var ErrCreatingHook = errors.New("failed to create hook") 18var ErrCreatingDelegate = errors.New("failed to create delegate hook") 19 20type config struct { 21 scanPath string 22 internalApi string 23} 24 25type setupOpt func(*config) 26 27func WithScanPath(scanPath string) setupOpt { 28 return func(c *config) { 29 c.scanPath = scanPath 30 } 31} 32 33func WithInternalApi(api string) setupOpt { 34 return func(c *config) { 35 c.internalApi = api 36 } 37} 38 39func Config(opts ...setupOpt) config { 40 config := config{} 41 for _, o := range opts { 42 o(&config) 43 } 44 return config 45} 46 47// setup hooks for all users 48// 49// directory structure is typically like so: 50// 51// did:plc:repo1 52// did:plc:repo2 53// did:web:repo1 54func Setup(config config) error { 55 // iterate over all directories in current directory: 56 repoDirs, err := os.ReadDir(config.scanPath) 57 if err != nil { 58 return err 59 } 60 61 for _, repo := range repoDirs { 62 if !repo.IsDir() { 63 continue 64 } 65 66 did := repo.Name() 67 if !strings.HasPrefix(did, "did:") { 68 continue 69 } 70 71 userPath := filepath.Join(config.scanPath, did) 72 if err := SetupRepo(config, userPath); err != nil { 73 return err 74 } 75 } 76 77 return nil 78} 79 80// setup hook in /scanpath/did:plc:repo 81func SetupRepo(config config, path string) error { 82 if _, err := git.PlainOpen(path); err != nil { 83 return fmt.Errorf("%s: %w", path, ErrNoGitRepo) 84 } 85 86 preReceiveD := filepath.Join(path, "hooks", "post-receive.d") 87 if err := os.MkdirAll(preReceiveD, 0755); err != nil { 88 return fmt.Errorf("%s: %w", preReceiveD, ErrCreatingHookDir) 89 } 90 91 notify := filepath.Join(preReceiveD, "40-notify.sh") 92 if err := mkHook(config, notify); err != nil { 93 return fmt.Errorf("%s: %w", notify, ErrCreatingHook) 94 } 95 96 delegate := filepath.Join(path, "hooks", "post-receive") 97 if err := mkDelegate(delegate); err != nil { 98 return fmt.Errorf("%s: %w", delegate, ErrCreatingDelegate) 99 } 100 101 return nil 102} 103 104func mkHook(config config, hookPath string) error { 105 executablePath, err := os.Executable() 106 if err != nil { 107 return err 108 } 109 110 hookContent := fmt.Sprintf(`#!/usr/bin/env bash 111# AUTO GENERATED BY KNOT, DO NOT MODIFY 112push_options=() 113for ((i=0; i<GIT_PUSH_OPTION_COUNT; i++)); do 114 option_var="GIT_PUSH_OPTION_$i" 115 push_options+=(-push-option "${!option_var}") 116done 117%s hook -git-dir "$GIT_DIR" -user-did "$GIT_USER_DID" -user-handle "$GIT_USER_HANDLE" -internal-api "%s" "${push_options[@]}" post-receive 118 `, executablePath, config.internalApi) 119 120 return os.WriteFile(hookPath, []byte(hookContent), 0755) 121} 122 123func mkDelegate(path string) error { 124 content := fmt.Sprintf(`#!/usr/bin/env bash 125# AUTO GENERATED BY KNOT, DO NOT MODIFY 126data=$(cat) 127exitcodes="" 128hookname=$(basename $0) 129GIT_DIR="$PWD" 130 131for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do 132 test -x "${hook}" && test -f "${hook}" || continue 133 echo "${data}" | "${hook}" 134 exitcodes="${exitcodes} $?" 135done 136 137for i in ${exitcodes}; do 138 [ ${i} -eq 0 ] || exit ${i} 139done 140 `) 141 142 return os.WriteFile(path, []byte(content), 0755) 143}