autogits/bots-common/git_utils.go

755 lines
17 KiB
Go
Raw Normal View History

2024-07-07 21:08:41 +02:00
package common
2024-09-10 18:24:41 +02:00
/*
* This file is part of Autogits.
*
* Copyright © 2024 SUSE LLC
*
* Autogits is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 2 of the License, or (at your option) any later
* version.
*
* Autogits is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* Foobar. If not, see <https://www.gnu.org/licenses/>.
*/
2024-07-07 21:08:41 +02:00
import (
"fmt"
2024-07-14 23:56:37 +02:00
"io"
2024-08-28 12:39:32 +02:00
"log"
"net/url"
2024-07-07 21:08:41 +02:00
"os"
"os/exec"
"path/filepath"
"strings"
2024-07-14 23:56:37 +02:00
"sync"
2024-07-07 21:08:41 +02:00
)
2024-11-11 15:52:34 +01:00
//go:generate mockgen -source=git_utils.go -destination=mock/git_utils.go -typed
2024-12-15 13:00:20 +01:00
type GitSubmoduleLister interface {
GitSubmoduleList(gitPath, commitId string) (submoduleList map[string]string, err error)
GitSubmoduleCommitId(cwd, packageName, commitId string) (subCommitId string, valid bool)
}
type Git interface {
GetPath() string
CloneDevel(gitDir, outName, urlString string) error
GitBranchHead(gitDir, branchName string) (string, error)
io.Closer
GitSubmoduleLister
GitExecWithOutputOrPanic(cwd string, params ...string) string
GitExecOrPanic(cwd string, params ...string)
GitExec(cwd string, params ...string) error
GitExecWithOutput(cwd string, params ...string) (string, error)
}
type GitHandlerImpl struct {
2024-08-28 12:39:32 +02:00
DebugLogger bool
GitPath string
GitCommiter string
2024-09-04 14:04:13 +02:00
GitEmail string
2024-08-28 12:39:32 +02:00
}
2024-12-15 13:00:20 +01:00
func (s *GitHandlerImpl) GetPath() string {
return s.GitPath
2024-11-11 15:52:34 +01:00
}
2024-12-15 13:00:20 +01:00
type GitHandlerGenerator interface {
CreateGitHandler(git_author, email, prjName string) (Git, error)
ReadExistingPath(git_author, email, gitPath string) (Git, error)
}
2024-11-11 15:52:34 +01:00
2024-12-15 13:00:20 +01:00
type GitHandlerGeneratorImpl struct{}
2024-09-02 17:27:23 +02:00
2024-12-15 13:00:20 +01:00
func (s *GitHandlerGeneratorImpl) CreateGitHandler(git_author, email, prj_name string) (Git, error) {
gitPath, err := os.MkdirTemp("", prj_name)
2024-09-02 17:27:23 +02:00
if err != nil {
return nil, fmt.Errorf("Cannot create temp dir: %w", err)
}
2024-12-15 13:00:20 +01:00
if err = os.Chmod(gitPath, 0700); err != nil {
2024-09-02 17:27:23 +02:00
return nil, fmt.Errorf("Cannot fix permissions of temp dir: %w", err)
}
2024-12-15 13:00:20 +01:00
return s.ReadExistingPath(git_author, email, gitPath)
}
func (*GitHandlerGeneratorImpl) ReadExistingPath(git_author, email, gitPath string) (Git, error) {
git := &GitHandlerImpl{
GitCommiter: git_author,
GitPath: gitPath,
}
2024-09-02 17:27:23 +02:00
return git, nil
}
2024-08-28 12:39:32 +02:00
//func (h *GitHandler) ProcessBranchList() []string {
2024-07-07 21:08:41 +02:00
// if h.HasError() {
// return make([]string, 0)
// }
//
// trackedBranches, err := os.ReadFile(path.Join(h.GitPath, DefaultGitPrj, TrackedBranchesFile))
// if err != nil {
// if errors.Is(err, os.ErrNotExist) {
// trackedBranches = []byte("factory")
// } else {
// h.LogError("file error reading '%s' file in repo", TrackedBranchesFile)
// h.Error = err
// return make([]string, 0)
// }
// }
//
// return strings.Split(string(trackedBranches), "\n")
//}
type GitReference struct {
Branch string
Id string
}
type GitReferences struct {
refs []GitReference
}
func (refs *GitReferences) addReference(id, branch string) {
for _, ref := range refs.refs {
if ref.Id == id && ref.Branch == branch {
return
}
}
refs.refs = append(refs.refs, GitReference{Branch: branch, Id: id})
}
2024-12-15 13:00:20 +01:00
func (e *GitHandlerImpl) CloneDevel(gitDir, outName, urlString string) error {
url, err := url.Parse(urlString)
branch := url.Fragment
url.Fragment = ""
params := []string{"clone", "-o", "devel"}
if len(branch) > 0 {
params = append(params, "-b", branch)
}
params = append(params, url.String(), outName)
if err != nil {
return fmt.Errorf("error parsing SSH URL. %w", err)
}
out, err := e.GitExecWithOutput(gitDir, params...)
if err != nil {
return fmt.Errorf("error cloning %s.\n%s\nerr: %w", urlString, out, err)
}
return nil
}
2024-12-15 13:00:20 +01:00
func (e *GitHandlerImpl) GitBranchHead(gitDir, branchName string) (string, error) {
id, err := e.GitExecWithOutput(gitDir, "rev-list", "-1", branchName)
2024-07-07 21:08:41 +02:00
if err != nil {
return "", fmt.Errorf("Can't find default remote branch: %s", branchName)
2024-07-07 21:08:41 +02:00
}
2024-09-16 13:10:25 +02:00
return strings.TrimSpace(id), nil
2024-07-07 21:08:41 +02:00
}
2024-12-15 13:00:20 +01:00
func (e *GitHandlerImpl) Close() error {
2024-08-28 12:39:32 +02:00
if err := os.RemoveAll(e.GitPath); err != nil {
return err
2024-07-07 21:08:41 +02:00
}
e.GitPath = ""
2024-08-28 12:39:32 +02:00
return nil
2024-07-07 21:08:41 +02:00
}
type writeFunc func(data []byte) (int, error)
func (f writeFunc) Write(data []byte) (int, error) {
return f(data)
}
2024-07-26 16:53:09 +02:00
func (h writeFunc) UnmarshalText(text []byte) error {
_, err := h.Write(text)
return err
}
func (h writeFunc) Close() error {
_, err := h.Write(nil)
return err
}
2024-12-15 13:00:20 +01:00
func (e *GitHandlerImpl) GitExecWithOutputOrPanic(cwd string, params ...string) string {
2024-09-16 13:10:25 +02:00
out, err := e.GitExecWithOutput(cwd, params...)
if err != nil {
2024-09-19 19:00:56 +02:00
log.Panicln("git command failed:", params, "@", cwd, "err:", err)
2024-09-16 13:10:25 +02:00
}
return out
}
2024-12-15 13:00:20 +01:00
func (e *GitHandlerImpl) GitExecOrPanic(cwd string, params ...string) {
2024-09-16 13:10:25 +02:00
if err := e.GitExec(cwd, params...); err != nil {
2024-09-19 19:00:56 +02:00
log.Panicln("git command failed:", params, "@", cwd, "err:", err)
2024-09-16 13:10:25 +02:00
}
}
2024-12-15 13:00:20 +01:00
func (e *GitHandlerImpl) GitExec(cwd string, params ...string) error {
_, err := e.GitExecWithOutput(cwd, params...)
return err
}
2024-11-03 22:21:57 +01:00
var ExtraGitParams []string
2024-12-15 13:00:20 +01:00
func (e *GitHandlerImpl) GitExecWithOutput(cwd string, params ...string) (string, error) {
2024-07-07 21:08:41 +02:00
cmd := exec.Command("/usr/bin/git", params...)
cmd.Env = []string{
"GIT_CEILING_DIRECTORIES=" + e.GitPath,
"GIT_CONFIG_GLOBAL=/dev/null",
"GIT_AUTHOR_NAME=" + e.GitCommiter,
2024-09-04 14:04:13 +02:00
"GIT_COMMITTER_NAME=" + e.GitCommiter,
2024-07-07 21:08:41 +02:00
"EMAIL=not@exist@src.opensuse.org",
"GIT_LFS_SKIP_SMUDGE=1",
"GIT_SSH_COMMAND=/usr/bin/ssh -o StrictHostKeyChecking=yes",
}
2024-11-03 22:21:57 +01:00
if len(ExtraGitParams) > 0 {
cmd.Env = append(cmd.Env, ExtraGitParams...)
}
2024-07-07 21:08:41 +02:00
cmd.Dir = filepath.Join(e.GitPath, cwd)
cmd.Stdin = nil
2024-08-28 12:39:32 +02:00
if e.DebugLogger {
log.Printf("git execute: %#v\n", cmd.Args)
}
out, err := cmd.CombinedOutput()
2024-08-28 17:20:09 +02:00
if e.DebugLogger {
log.Println(string(out))
}
if err != nil {
if e.DebugLogger {
log.Printf(" *** error: %v\n", err)
}
return "", fmt.Errorf("error executing: git %#v \n%s\n err: %w", cmd.Args, out, err)
2024-08-28 17:20:09 +02:00
}
2024-07-07 21:08:41 +02:00
return string(out), nil
2024-07-07 21:08:41 +02:00
}
2024-07-11 16:45:49 +02:00
2024-07-14 23:56:37 +02:00
type ChanIO struct {
ch chan byte
}
func (c *ChanIO) Write(p []byte) (int, error) {
2024-07-16 06:56:57 +02:00
for _, b := range p {
c.ch <- b
2024-07-14 23:56:37 +02:00
}
return len(p), nil
}
2024-07-16 06:56:57 +02:00
// read at least 1 byte, but don't block if nothing more in channel
2024-07-16 07:14:12 +02:00
func (c *ChanIO) Read(data []byte) (idx int, err error) {
2024-07-16 06:56:57 +02:00
var ok bool
2024-07-14 23:56:37 +02:00
2024-07-16 06:56:57 +02:00
data[idx], ok = <-c.ch
if !ok {
2024-07-16 07:14:12 +02:00
err = io.EOF
return
2024-07-16 06:56:57 +02:00
}
idx++
for len(c.ch) > 0 && idx < len(data) {
2024-08-28 12:39:32 +02:00
data[idx], ok = <-c.ch
2024-07-14 23:56:37 +02:00
if !ok {
2024-07-16 07:14:12 +02:00
err = io.EOF
return
2024-07-14 23:56:37 +02:00
}
2024-07-16 06:56:57 +02:00
idx++
2024-07-14 23:56:37 +02:00
}
2024-07-16 07:14:12 +02:00
return
2024-07-14 23:56:37 +02:00
}
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
2024-07-15 19:19:34 +02:00
size int
2024-07-14 23:56:37 +02:00
}
type tree struct {
items []tree_entry
}
2024-07-15 19:19:34 +02:00
func (t *tree_entry) isSubmodule() bool {
return (t.mode & 0170000) == 0160000
}
func (t *tree_entry) isTree() bool {
return (t.mode & 0170000) == 0040000
}
func (t *tree_entry) isBlob() bool {
return !t.isTree() && !t.isSubmodule()
}
2024-07-14 23:56:37 +02:00
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 {
2024-07-15 21:22:58 +02:00
return gitMsg{}, fmt.Errorf("Invalid character during object hash parse '%c' at %d", c, pos)
2024-07-14 23:56:37 +02:00
}
}
id = id[:pos]
pos = 0
2024-07-29 15:28:03 +02:00
var c byte
for c = <-data; c != ' ' && c != '\x00'; c = <-data {
2024-07-14 23:56:37 +02:00
if c >= 'a' && c <= 'z' {
msgType[pos] = c
pos++
} else {
2024-07-15 21:14:09 +02:00
return gitMsg{}, fmt.Errorf("Invalid character during object type parse '%c' at %d", c, pos)
2024-07-14 23:56:37 +02:00
}
}
msgType = msgType[:pos]
switch string(msgType) {
2024-07-29 15:28:03 +02:00
case "commit", "tree", "blob":
2024-07-14 23:56:37 +02:00
break
2024-07-29 15:28:03 +02:00
case "missing":
if c != '\x00' {
return gitMsg{}, fmt.Errorf("Missing format weird")
}
return gitMsg{
2024-08-28 12:39:32 +02:00
hash: string(id[:]),
2024-07-29 15:28:03 +02:00
itemType: "missing",
2024-08-28 12:39:32 +02:00
size: 0,
2024-07-29 15:28:03 +02:00
}, fmt.Errorf("Object not found: '%s'", string(id))
2024-07-14 23:56:37 +02:00
default:
return gitMsg{}, fmt.Errorf("Invalid object type: '%s'", string(msgType))
}
2024-07-29 15:28:03 +02:00
for c = <-data; c != '\000'; c = <-data {
2024-07-14 23:56:37 +02:00
if c >= '0' && c <= '9' {
size = size*10 + (int(c) - '0')
} else {
2024-07-15 19:19:34 +02:00
return gitMsg{}, fmt.Errorf("Invalid character during object size parse: '%c'", c)
2024-07-14 23:56:37 +02:00
}
}
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)
}
}
2024-07-11 16:45:49 +02:00
2024-07-14 23:56:37 +02:00
return [2]string{string(hdr), string(val)}, nil
2024-07-11 16:45:49 +02:00
}
2024-07-14 23:56:37 +02:00
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)
2024-07-29 15:28:03 +02:00
l--
}
2024-08-28 12:39:32 +02:00
// l--
2024-07-29 15:28:03 +02:00
if l != 0 {
return "", fmt.Errorf("Unexpected data in the git commit msg: l=%d", l)
2024-07-14 23:56:37 +02:00
}
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
}
2024-07-15 19:19:34 +02:00
func parseTreeEntry(data <-chan byte, hashLen int) (tree_entry, error) {
2024-07-14 23:56:37 +02:00
var e tree_entry
2024-07-15 19:19:34 +02:00
for c := <-data; c != ' '; c = <-data {
e.mode = e.mode*8 + int(c-'0')
e.size++
}
e.size++
name := make([]byte, 0, 128)
for c := <-data; c != '\x00'; c = <-data {
name = append(name, c)
e.size++
2024-07-14 23:59:48 +02:00
}
2024-07-15 19:19:34 +02:00
e.size++
e.name = string(name)
const hexBinToAscii = "0123456789abcdef"
hash := make([]byte, 0, hashLen*2)
for range hashLen {
c := <-data
hash = append(hash, hexBinToAscii[((c&0xF0)>>4)], hexBinToAscii[c&0xF])
2024-07-14 23:59:48 +02:00
}
2024-07-15 19:19:34 +02:00
e.hash = string(hash)
e.size += hashLen
2024-07-14 23:59:48 +02:00
2024-07-14 23:56:37 +02:00
return e, nil
}
func parseGitTree(data <-chan byte) (tree, error) {
2024-07-15 19:19:34 +02:00
hdr, err := parseGitMsg(data)
if err != nil {
return tree{}, err
}
// max capacity to length of hash
t := tree{items: make([]tree_entry, 0, hdr.size/len(hdr.hash))}
2024-07-29 15:28:03 +02:00
parsedLen := 0
for parsedLen < hdr.size {
2024-07-15 19:19:34 +02:00
entry, err := parseTreeEntry(data, len(hdr.hash)/2)
if err != nil {
return tree{}, nil
}
t.items = append(t.items, entry)
parsedLen += entry.size
}
2024-07-29 15:28:03 +02:00
c := <-data // \0 read
if c != '\x00' {
return t, fmt.Errorf("Unexpected character during git tree data read")
}
if parsedLen != hdr.size {
return t, fmt.Errorf("Invalid size of git tree data")
}
2024-07-15 19:19:34 +02:00
return t, nil
2024-07-14 23:56:37 +02:00
}
2024-07-29 15:28:03 +02:00
func parseGitBlob(data <-chan byte) ([]byte, error) {
hdr, err := parseGitMsg(data)
if err != nil {
return []byte{}, err
}
d := make([]byte, hdr.size)
2024-08-28 12:39:32 +02:00
for l := 0; l < hdr.size; l++ {
2024-07-29 15:28:03 +02:00
d[l] = <-data
}
eob := <-data
if eob != '\x00' {
return d, fmt.Errorf("invalid byte read in parseGitBlob")
}
return d, nil
}
2024-12-15 13:00:20 +01:00
func (e *GitHandlerImpl) GitParseCommits(cwd string, commitIDs []string) (parsedCommits []commit, err error) {
var done sync.Mutex
done.Lock()
data_in, data_out := ChanIO{make(chan byte, 256)}, ChanIO{make(chan byte, 70)}
parsedCommits = make([]commit, 0, len(commitIDs))
go func() {
defer done.Unlock()
defer close(data_out.ch)
for _, id := range commitIDs {
data_out.Write([]byte(id))
data_out.ch <- '\x00'
c, e := parseGitCommit(data_in.ch)
if e != nil {
err = fmt.Errorf("Error parsing git commit: %w", e)
return
}
parsedCommits = append(parsedCommits, c)
}
}()
cmd := exec.Command("/usr/bin/git", "cat-file", "--batch", "-Z")
cmd.Env = []string{
"GIT_CEILING_DIRECTORIES=" + e.GitPath,
"GIT_CONFIG_GLOBAL=/dev/null",
}
cmd.Dir = filepath.Join(e.GitPath, cwd)
cmd.Stdout = &data_in
cmd.Stdin = &data_out
cmd.Stderr = writeFunc(func(data []byte) (int, error) {
if e.DebugLogger {
log.Printf(string(data))
}
return len(data), nil
})
if e.DebugLogger {
log.Printf("command run: %v\n", cmd.Args)
}
err = cmd.Run()
done.Lock()
return
}
2024-07-29 15:28:03 +02:00
// TODO: support sub-trees
2024-12-15 13:00:20 +01:00
func (e *GitHandlerImpl) GitCatFile(cwd, commitId, filename string) (data []byte, err error) {
2024-07-29 15:28:03 +02:00
var done sync.Mutex
done.Lock()
data_in, data_out := ChanIO{make(chan byte, 256)}, ChanIO{make(chan byte, 70)}
go func() {
defer done.Unlock()
defer close(data_out.ch)
data_out.Write([]byte(commitId))
data_out.ch <- '\x00'
c, err := parseGitCommit(data_in.ch)
if err != nil {
2024-08-28 12:39:32 +02:00
log.Printf("Error parsing git commit: %v\n", err)
2024-07-29 15:28:03 +02:00
return
}
data_out.Write([]byte(c.Tree))
data_out.ch <- '\x00'
tree, err := parseGitTree(data_in.ch)
if err != nil {
2024-08-28 12:39:32 +02:00
if e.DebugLogger {
log.Printf("Error parsing git tree: %v\n", err)
}
2024-07-29 15:28:03 +02:00
return
}
for _, te := range tree.items {
if te.isBlob() && te.name == filename {
data_out.Write([]byte(te.hash))
data_out.ch <- '\x00'
data, err = parseGitBlob(data_in.ch)
return
}
}
2024-08-28 12:39:32 +02:00
err = fmt.Errorf("file not found: '%s'", filename)
2024-07-29 15:28:03 +02:00
}()
cmd := exec.Command("/usr/bin/git", "cat-file", "--batch", "-Z")
cmd.Env = []string{
"GIT_CEILING_DIRECTORIES=" + e.GitPath,
"GIT_CONFIG_GLOBAL=/dev/null",
}
cmd.Dir = filepath.Join(e.GitPath, cwd)
cmd.Stdout = &data_in
cmd.Stdin = &data_out
cmd.Stderr = writeFunc(func(data []byte) (int, error) {
2024-08-28 17:20:09 +02:00
if e.DebugLogger {
log.Printf(string(data))
}
2024-07-29 15:28:03 +02:00
return len(data), nil
})
2024-08-28 17:20:09 +02:00
if e.DebugLogger {
2024-09-04 14:04:13 +02:00
log.Printf("command run: %v\n", cmd.Args)
2024-08-28 17:20:09 +02:00
}
err = cmd.Run()
2024-07-29 15:28:03 +02:00
done.Lock()
2024-08-28 12:39:32 +02:00
return
2024-07-29 15:28:03 +02:00
}
2024-09-02 17:27:23 +02:00
// return (filename) -> (hash) map for all submodules
// TODO: recursive? map different orgs, not just assume '.' for path
2024-12-15 13:00:20 +01:00
func (e *GitHandlerImpl) GitSubmoduleList(gitPath, commitId string) (submoduleList map[string]string, err error) {
2024-07-26 16:53:09 +02:00
var done sync.Mutex
2024-08-28 12:39:32 +02:00
submoduleList = make(map[string]string)
2024-07-31 16:52:02 +02:00
2024-07-26 16:53:09 +02:00
done.Lock()
data_in, data_out := ChanIO{make(chan byte, 256)}, ChanIO{make(chan byte, 70)}
go func() {
defer done.Unlock()
defer close(data_out.ch)
data_out.Write([]byte(commitId))
data_out.ch <- '\x00'
2024-08-28 17:20:09 +02:00
var c commit
c, err = parseGitCommit(data_in.ch)
2024-07-26 16:53:09 +02:00
if err != nil {
2024-08-28 17:20:09 +02:00
err = fmt.Errorf("Error parsing git commit. Err: %w", err)
2024-07-26 16:53:09 +02:00
return
}
data_out.Write([]byte(c.Tree))
data_out.ch <- '\x00'
2024-08-28 17:20:09 +02:00
var tree tree
tree, err = parseGitTree(data_in.ch)
2024-07-26 16:53:09 +02:00
if err != nil {
2024-08-28 17:20:09 +02:00
err = fmt.Errorf("Error parsing git tree: %w", err)
2024-07-26 16:53:09 +02:00
return
}
for _, te := range tree.items {
if te.isSubmodule() {
submoduleList[te.name] = te.hash
}
}
}()
cmd := exec.Command("/usr/bin/git", "cat-file", "--batch", "-Z")
cmd.Env = []string{
"GIT_CEILING_DIRECTORIES=" + e.GitPath,
"GIT_CONFIG_GLOBAL=/dev/null",
}
2024-12-15 13:00:20 +01:00
cmd.Dir = filepath.Join(e.GitPath, gitPath)
2024-09-04 14:04:13 +02:00
cmd.Stdout = &data_in
cmd.Stdin = &data_out
2024-07-26 16:53:09 +02:00
cmd.Stderr = writeFunc(func(data []byte) (int, error) {
2024-08-28 17:20:09 +02:00
if e.DebugLogger {
log.Println(string(data))
}
2024-07-26 16:53:09 +02:00
return len(data), nil
})
2024-08-28 17:20:09 +02:00
if e.DebugLogger {
2024-09-04 14:04:13 +02:00
log.Printf("command run: %v\n", cmd.Args)
2024-08-28 17:20:09 +02:00
}
err = cmd.Run()
2024-07-26 16:53:09 +02:00
done.Lock()
2024-08-28 17:20:09 +02:00
return submoduleList, err
2024-07-26 16:53:09 +02:00
}
2024-12-15 13:00:20 +01:00
func (e *GitHandlerImpl) GitSubmoduleCommitId(cwd, packageName, commitId string) (subCommitId string, valid bool) {
2024-08-28 12:39:32 +02:00
defer func() {
if recover() != nil {
commitId = ""
valid = false
}
}()
2024-07-11 16:45:49 +02:00
2024-07-14 23:56:37 +02:00
data_in, data_out := ChanIO{make(chan byte, 256)}, ChanIO{make(chan byte, 70)}
2024-08-28 12:39:32 +02:00
var wg sync.WaitGroup
2024-07-14 23:56:37 +02:00
2024-08-28 12:39:32 +02:00
wg.Add(1)
2024-07-14 23:56:37 +02:00
2024-08-28 12:39:32 +02:00
if e.DebugLogger {
log.Printf("getting commit id '%s' from git at '%s' with packageName: %s\n", commitId, cwd, packageName)
}
2024-07-15 21:16:01 +02:00
2024-07-14 23:56:37 +02:00
go func() {
2024-08-28 12:39:32 +02:00
defer wg.Done()
2024-07-14 23:56:37 +02:00
defer close(data_out.ch)
2024-07-15 19:19:34 +02:00
data_out.Write([]byte(commitId))
data_out.ch <- '\x00'
2024-07-14 23:56:37 +02:00
c, err := parseGitCommit(data_in.ch)
if err != nil {
2024-08-28 17:53:15 +02:00
log.Panicf("Error parsing git commit: %v\n", err)
2024-07-14 23:56:37 +02:00
}
data_out.Write([]byte(c.Tree))
2024-07-15 19:19:34 +02:00
data_out.ch <- '\x00'
2024-07-14 23:56:37 +02:00
tree, err := parseGitTree(data_in.ch)
if err != nil {
2024-08-28 12:39:32 +02:00
log.Panicf("Error parsing git tree: %v\n", err)
2024-07-14 23:56:37 +02:00
}
for _, te := range tree.items {
2024-07-15 19:19:34 +02:00
if te.name == packageName && te.isSubmodule() {
subCommitId = te.hash
2024-07-14 23:56:37 +02:00
return
}
}
}()
cmd := exec.Command("/usr/bin/git", "cat-file", "--batch", "-Z")
2024-07-15 21:20:33 +02:00
cmd.Env = []string{
"GIT_CEILING_DIRECTORIES=" + e.GitPath,
"GIT_CONFIG_GLOBAL=/dev/null",
}
2024-07-11 16:45:49 +02:00
cmd.Dir = filepath.Join(e.GitPath, cwd)
2024-07-14 23:56:37 +02:00
cmd.Stdout = &data_in
cmd.Stdin = &data_out
2024-07-15 21:20:33 +02:00
cmd.Stderr = writeFunc(func(data []byte) (int, error) {
2024-08-28 12:39:32 +02:00
log.Println(string(data))
2024-07-15 21:20:33 +02:00
return len(data), nil
})
2024-08-28 12:39:32 +02:00
if e.DebugLogger {
log.Printf("command run: %v\n", cmd.Args)
}
if err := cmd.Run(); err != nil {
log.Printf("Error running command %v, err: %v", cmd.Args, err)
}
2024-07-11 16:45:49 +02:00
2024-08-28 12:39:32 +02:00
wg.Wait()
2024-07-15 19:19:34 +02:00
return subCommitId, len(subCommitId) == len(commitId)
2024-07-11 16:45:49 +02:00
}