.
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
//func (h *RequestHandler) ProcessBranchList() []string {
|
||||
@@ -203,23 +206,223 @@ func (e *RequestHandler) GitExec(cwd string, params ...string) ExecStream {
|
||||
return e
|
||||
}
|
||||
|
||||
type writerFunc func([]byte) (int, error)
|
||||
|
||||
// Implement the Write method for the custom type
|
||||
func (f writerFunc) Write(p []byte) (int, error) {
|
||||
return f(p)
|
||||
type ChanIO struct {
|
||||
ch chan byte
|
||||
}
|
||||
|
||||
func (e *RequestHandler) GitSubmoduleCommitId(cwd, packageName string) (string, bool) {
|
||||
func (c *ChanIO) Write(p []byte) (int, error) {
|
||||
for i := range len(p) {
|
||||
c.ch <- p[i]
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// read at least 1 byte, but don't block if nothing in channel
|
||||
func (c *ChanIO) Read(p []byte) (int, error) {
|
||||
data, ok := <-c.ch
|
||||
for i := 0; i < cap(p); i++ {
|
||||
data, ok = <-c.ch
|
||||
|
||||
if !ok {
|
||||
return len(p), io.EOF
|
||||
}
|
||||
|
||||
p[i] = data
|
||||
if len(c.ch) < 1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
type gitMsg struct {
|
||||
hash string
|
||||
itemType string
|
||||
size int
|
||||
}
|
||||
|
||||
type commit struct {
|
||||
Tree string
|
||||
Msg string
|
||||
}
|
||||
|
||||
type tree_entry struct {
|
||||
name string
|
||||
mode int
|
||||
hash string
|
||||
}
|
||||
|
||||
type tree struct {
|
||||
items []tree_entry
|
||||
}
|
||||
|
||||
func parseGitMsg(data <-chan byte) (gitMsg, error) {
|
||||
var id []byte = make([]byte, 64)
|
||||
var msgType []byte = make([]byte, 16)
|
||||
var size int
|
||||
|
||||
pos := 0
|
||||
for c := <-data; c != ' '; c = <-data {
|
||||
if (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') {
|
||||
id[pos] = c
|
||||
pos++
|
||||
} else {
|
||||
return gitMsg{}, errors.New("Invalid character during object hash parse")
|
||||
}
|
||||
}
|
||||
id = id[:pos]
|
||||
|
||||
pos = 0
|
||||
for c := <-data; c != ' '; c = <-data {
|
||||
if c >= 'a' && c <= 'z' {
|
||||
msgType[pos] = c
|
||||
pos++
|
||||
} else {
|
||||
return gitMsg{}, errors.New("Invalid character during object type parse")
|
||||
}
|
||||
}
|
||||
msgType = msgType[:pos]
|
||||
|
||||
switch string(msgType) {
|
||||
case "commit", "tree":
|
||||
break
|
||||
default:
|
||||
return gitMsg{}, fmt.Errorf("Invalid object type: '%s'", string(msgType))
|
||||
}
|
||||
|
||||
for c := <-data; c != '\000'; c = <-data {
|
||||
if c >= '0' && c <= '9' {
|
||||
size = size*10 + (int(c) - '0')
|
||||
} else {
|
||||
return gitMsg{}, errors.New("Invalid character during commit size parse")
|
||||
}
|
||||
}
|
||||
|
||||
return gitMsg{
|
||||
hash: string(id[:]),
|
||||
itemType: string(msgType),
|
||||
size: size,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseGitCommitHdr(data <-chan byte) ([2]string, error) {
|
||||
hdr := make([]byte, 0, 60)
|
||||
val := make([]byte, 0, 1000)
|
||||
|
||||
c := <-data
|
||||
if c != '\n' { // end of header marker
|
||||
for ; c != ' '; c = <-data {
|
||||
hdr = append(hdr, c)
|
||||
}
|
||||
for c := <-data; c != '\n'; c = <-data {
|
||||
val = append(val, c)
|
||||
}
|
||||
}
|
||||
|
||||
return [2]string{string(hdr), string(val)}, nil
|
||||
}
|
||||
|
||||
func parseGitCommitMsg(data <-chan byte, l int) (string, error) {
|
||||
msg := make([]byte, 0, l)
|
||||
|
||||
for c := <-data; c != '\x00'; c = <-data {
|
||||
msg = append(msg, c)
|
||||
}
|
||||
|
||||
return string(msg), nil
|
||||
}
|
||||
|
||||
func parseGitCommit(data <-chan byte) (commit, error) {
|
||||
hdr, err := parseGitMsg(data)
|
||||
if err != nil {
|
||||
return commit{}, err
|
||||
} else if hdr.itemType != "commit" {
|
||||
return commit{}, fmt.Errorf("expected commit but parsed %s", hdr.itemType)
|
||||
}
|
||||
|
||||
var c commit
|
||||
l := hdr.size
|
||||
for {
|
||||
hdr, err := parseGitCommitHdr(data)
|
||||
if err != nil {
|
||||
return commit{}, nil
|
||||
}
|
||||
|
||||
if len(hdr[0])+len(hdr[1]) == 0 { // hdr end marker
|
||||
break
|
||||
}
|
||||
|
||||
switch hdr[0] {
|
||||
case "tree":
|
||||
c.Tree = hdr[1]
|
||||
}
|
||||
|
||||
l -= len(hdr[0]) + len(hdr[1]) + 2
|
||||
}
|
||||
l--
|
||||
|
||||
c.Msg, err = parseGitCommitMsg(data, l)
|
||||
return c, err
|
||||
}
|
||||
|
||||
func parseTreeEntry(data <-chan byte) (tree_entry, error) {
|
||||
var e tree_entry
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func parseGitTree(data <-chan byte) (tree, error) {
|
||||
|
||||
return tree{}, nil
|
||||
}
|
||||
|
||||
func (e *RequestHandler) GitSubmoduleCommitId(cwd, packageName, headId string) (string, bool) {
|
||||
if e.Error != nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
cmd := exec.Command("/usr/bin/git", "cat-file", "--batch")
|
||||
cmd.Dir = filepath.Join(e.GitPath, cwd)
|
||||
cmd.Stdout = writerFunc(func(p []byte) (int, error) {
|
||||
return len(p), nil
|
||||
})
|
||||
data_in, data_out := ChanIO{make(chan byte, 256)}, ChanIO{make(chan byte, 70)}
|
||||
var commitId string
|
||||
var foundLock sync.Mutex
|
||||
|
||||
return "", false
|
||||
foundLock.Lock()
|
||||
|
||||
go func() {
|
||||
defer foundLock.Unlock()
|
||||
defer close(data_out.ch)
|
||||
|
||||
data_out.Write([]byte("HEAD\n"))
|
||||
c, err := parseGitCommit(data_in.ch)
|
||||
if err != nil {
|
||||
e.Error = err
|
||||
e.LogError("Error parsing git commit: %v", err)
|
||||
return
|
||||
}
|
||||
data_out.Write([]byte(c.Tree))
|
||||
data_out.ch <- '\n'
|
||||
tree, err := parseGitTree(data_in.ch)
|
||||
|
||||
if err != nil {
|
||||
e.Error = err
|
||||
e.LogError("Error parsing git tree: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, te := range tree.items {
|
||||
if te.name == packageName {
|
||||
commitId = te.hash
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
cmd := exec.Command("/usr/bin/git", "cat-file", "--batch", "-Z")
|
||||
cmd.Dir = filepath.Join(e.GitPath, cwd)
|
||||
cmd.Stdout = &data_in
|
||||
cmd.Stdin = &data_out
|
||||
e.Log("command run: %v", cmd.Run())
|
||||
|
||||
foundLock.Lock()
|
||||
return commitId, len(commitId) == len(headId)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user