package main import ( "fmt" "log" "os" "os/exec" "path/filepath" "strings" "syscall" ) var logger *log.Logger var logf *os.File func main() { var err error logf, err = os.OpenFile("loggy.boi", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) if err != nil { log.Fatal(err) } defer logf.Close() logger = log.New(logf, "", log.LstdFlags) sshOriginalCommand := os.Getenv("SSH_ORIGINAL_COMMAND") if sshOriginalCommand == "" { log.Fatal("SSH_ORIGINAL_COMMAND is not set") } if err := Run(sshOriginalCommand); err != nil { logger.Fatal(err) } } type Mkdir func([]string) error func mkdir(path string) error { return os.MkdirAll(path, 0755) } func Run(sshCmd string) error { parts := strings.Split(sshCmd, " ") if len(parts) != 2 { return fmt.Errorf("expected 2 args: %s", sshCmd) } command := parts[0] repo := parts[1] remmappedRepo := RemapRepoPath(repo, "repos") // creates repos if they don't exist if _, err := os.Stat(remmappedRepo); os.IsNotExist(err) { if err := setupRepo(remmappedRepo); err != nil { return fmt.Errorf("failed to setup repo: %v", err) } } bin, err := exec.LookPath(command) if err != nil { return fmt.Errorf("failed to lookup %s:%v", command, err) } // Execute the git-shell command return syscall.Exec(bin, []string{command, remmappedRepo}, os.Environ()) } func setupRepo(repo string) error { // Create the directory (and any necessary parent directories) if err := mkdir(repo); err != nil { return fmt.Errorf("failed to create directory: %v", err) } cmd := exec.Command("git", "init", "--bare", "--initial-branch=main", repo) cmd.Stdout = logf cmd.Stderr = logf if err := cmd.Run(); err != nil { return fmt.Errorf("failed to run initialize git repository: %v", err) } if err := writeDescriptionHook(repo); err != nil { logger.Printf("failed to create description hook: %v\n", err) } return nil } // 'a73x/cgit.git' => repos/a73x/cgit.git func RemapRepoPath(repo string, path string) string { return filepath.Join(path, strings.Trim(repo, "'")) } var descriptionHook = `#!/bin/bash BRANCH="main" FILE=README while read oldrev newrev ref do # only checking out the master (or whatever branch you would like to deploy) if [ "$ref" = "refs/heads/$BRANCH" ]; then changed=$(git ls-tree $REV $FILE) if [ -n $changed ]; then echo "Ref $ref received. updating description" git show HEAD:README | head -n1 > description fi else echo "Ref $ref received. Doing nothing: only the ${BRANCH} branch may be deployed on this server." fi done` func writeDescriptionHook(path string) error { hooksDir := filepath.Join(path, "hooks") scriptPath := filepath.Join(hooksDir, "post-receive") err := os.MkdirAll(hooksDir, 0755) if err != nil { return fmt.Errorf("error creating hooks directory: %v", err) } file, err := os.Create(scriptPath) if err != nil { return fmt.Errorf("error creating post-receive file: %v", err) } defer file.Close() // Write the script to the file _, err = file.WriteString(descriptionHook) if err != nil { return fmt.Errorf("error writing script to file: %v", err) } // Set the file permissions to be executable err = os.Chmod(scriptPath, 0755) if err != nil { return fmt.Errorf("error setting file permissions: %v", err) } return nil }