internal/gitutil/gitutil.go

a831d1ab09705002f965fb91989e86d1638c0ed8
gitbay/internal/gitutil/gitutil.go history · blame · raw

76 lines · 2321 bytes

 1// Package gitutil wraps the system git binary. All repository access goes
 2// through git subprocesses; there is no in-process git implementation.
 3package gitutil
 4
 5import (
 6	"fmt"
 7	"io"
 8	"os"
 9	"os/exec"
10	"path/filepath"
11	"strings"
12)
13
14// InitBare creates a bare repository with the shared hooks directory wired
15// via core.hooksPath.
16func InitBare(path, defaultBranch, hooksPath string) error {
17	if err := os.MkdirAll(filepath.Dir(path), 0o750); err != nil {
18		return err
19	}
20	cmd := exec.Command("git", "init", "--bare", "--initial-branch="+defaultBranch, path)
21	if out, err := cmd.CombinedOutput(); err != nil {
22		return fmt.Errorf("git init: %v\n%s", err, out)
23	}
24	cmd = exec.Command("git", "-C", path, "config", "core.hooksPath", hooksPath)
25	if out, err := cmd.CombinedOutput(); err != nil {
26		return fmt.Errorf("git config core.hooksPath: %v\n%s", err, out)
27	}
28	return nil
29}
30
31// Transport streams one git transport service (upload-pack, receive-pack,
32// upload-archive) over rw. extraEnv entries are appended to the daemon's
33// environment; hooks read the FORGE_* variables from it.
34func Transport(service, repoPath string, rw io.ReadWriter, errW io.Writer, extraEnv []string) error {
35	var args []string
36	switch service {
37	case "git-upload-pack", "git-receive-pack", "git-upload-archive":
38		args = []string{strings.TrimPrefix(service, "git-"), repoPath}
39	default:
40		return fmt.Errorf("unknown service %q", service)
41	}
42	cmd := exec.Command("git", args...)
43	cmd.Env = append(os.Environ(), extraEnv...)
44	cmd.Stdin = rw
45	cmd.Stdout = rw
46	cmd.Stderr = errW
47	return cmd.Run()
48}
49
50// IsAncestor reports whether old is an ancestor of new in the repository at
51// dir. It must run with the caller's environment intact so that quarantined
52// objects during pre-receive remain visible.
53func IsAncestor(dir, old, new string) (bool, error) {
54	cmd := exec.Command("git", "-C", dir, "merge-base", "--is-ancestor", old, new)
55	err := cmd.Run()
56	if err == nil {
57		return true, nil
58	}
59	if ee, ok := err.(*exec.ExitError); ok && ee.ExitCode() == 1 {
60		return false, nil
61	}
62	return false, err
63}
64
65// ZeroSHA reports whether s is an all-zero object id (SHA-1 or SHA-256).
66func ZeroSHA(s string) bool {
67	if len(s) != 40 && len(s) != 64 {
68		return false
69	}
70	for i := 0; i < len(s); i++ {
71		if s[i] != '0' {
72			return false
73		}
74	}
75	return true
76}