package git import ( "bufio" "bytes" "errors" "os/exec" "regexp" ) type TreeEntry struct { Mode, Type, Object, Name string } var reTreeEntry = regexp.MustCompile("^(\\d+) (\\w+) ([0-9a-f]+)\t(.*)$") var ( ErrUnexpectedLsTreeOutput = errors.New("Unexpected git ls-tree output") ) func splitZero(data []byte, atEOF bool) (advance int, token []byte, err error) { if atEOF && len(data) == 0 { return 0, nil, nil } if i := bytes.IndexByte(data, '\x00'); i >= 0 { return i + 1, data[0:i], nil } if atEOF { return len(data), data, nil } return 0, nil, nil } func ReadTree(repoPath string, ref string) ([]TreeEntry, error) { cmd := exec.Command("git", "-C", repoPath, "ls-tree", "--full-tree", "-z", ref) var out bytes.Buffer cmd.Stdout = &out if err := cmd.Run(); err != nil { return nil, err } scanner := bufio.NewScanner(&out) scanner.Split(splitZero) entries := []TreeEntry{} for scanner.Scan() { line := scanner.Bytes() m := reTreeEntry.FindSubmatch(line) if m == nil { return nil, ErrUnexpectedLsTreeOutput } entries = append(entries, TreeEntry{ Mode: string(m[1]), Type: string(m[2]), Object: string(m[3]), Name: string(m[4]), }) } return entries, nil } func ReadBlob(repoPath string, ref string) ([]byte, error) { var buf bytes.Buffer cmd := exec.Command("git", "-C", repoPath, "cat-file", "blob", ref) cmd.Stdout = &buf if err := cmd.Run(); err != nil { return nil, err } return buf.Bytes(), nil }