226 lines
4.9 KiB
Go
226 lines
4.9 KiB
Go
package common
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
//func (h *RequestHandler) ProcessBranchList() []string {
|
|
// 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})
|
|
}
|
|
|
|
func processRefs(gitDir string) ([]GitReference, error) {
|
|
packedRefsPath := path.Join(gitDir, "packed-refs")
|
|
stat, err := os.Stat(packedRefsPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if stat.Size() > 10000 || stat.IsDir() {
|
|
return nil, fmt.Errorf("Funny business with 'packed-refs' in '%s'", gitDir)
|
|
}
|
|
|
|
data, err := os.ReadFile(packedRefsPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var references GitReferences
|
|
for _, line := range strings.Split(string(data), "\n") {
|
|
if len(line) < 1 || line[0] == '#' {
|
|
continue
|
|
}
|
|
|
|
splitLine := strings.Split(line, " ")
|
|
if len(splitLine) != 2 {
|
|
return nil, fmt.Errorf("Unexpected packaged-refs entry '%#v' in '%s'", splitLine, packedRefsPath)
|
|
}
|
|
id, ref := splitLine[0], splitLine[1]
|
|
const remoteRefPrefix = "refs/remotes/origin/"
|
|
if ref[0:len(remoteRefPrefix)] != remoteRefPrefix {
|
|
continue
|
|
}
|
|
|
|
references.addReference(id, ref[len(remoteRefPrefix):])
|
|
}
|
|
|
|
return references.refs, nil
|
|
}
|
|
|
|
func findGitDir(p string) (string, error) {
|
|
gitFile := path.Join(p, ".git")
|
|
stat, err := os.Stat(gitFile)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if stat.IsDir() {
|
|
return path.Join(p, ".git"), nil
|
|
}
|
|
|
|
data, err := os.ReadFile(gitFile)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
for _, line := range strings.Split(string(data), "\n") {
|
|
refs := strings.Split(line, ":")
|
|
if len(refs) != 2 {
|
|
return "", fmt.Errorf("Unknown format of .git file: '%s'\n", line)
|
|
}
|
|
|
|
if refs[0] != "gitdir" {
|
|
return "", fmt.Errorf("Unknown header of .git file: '%s'\n", refs[0])
|
|
}
|
|
|
|
return path.Join(p, strings.TrimSpace(refs[1])), nil
|
|
}
|
|
|
|
return "", fmt.Errorf("Can't find git subdirectory in '%s'", p)
|
|
}
|
|
|
|
func (e *RequestHandler) GitBranchHead(gitDir, branchName string) (string, error) {
|
|
if e.HasError() {
|
|
return "", e.Error
|
|
}
|
|
|
|
path, err := findGitDir(path.Join(e.GitPath, gitDir))
|
|
if err != nil {
|
|
e.LogError("Error identifying gitdir in `%s`: %#v", gitDir, err)
|
|
e.Error = err
|
|
}
|
|
|
|
refs, err := processRefs(path)
|
|
if err != nil {
|
|
e.LogError("Error finding branches (%s): %#v", branchName, err)
|
|
e.Error = err
|
|
return "", e.Error
|
|
}
|
|
|
|
for _, ref := range refs {
|
|
if ref.Branch == branchName {
|
|
return ref.Id, nil
|
|
}
|
|
}
|
|
|
|
e.Error = fmt.Errorf("Can't find default remote branch: %s", branchName)
|
|
e.LogError("%s", e.Error.Error())
|
|
return "", e.Error
|
|
}
|
|
|
|
type ExecStream interface {
|
|
Close()
|
|
HasError() bool
|
|
GitExec(cwd string, param ...string) ExecStream
|
|
}
|
|
|
|
func (e *RequestHandler) Close() {
|
|
if e.GitPath == "" {
|
|
return
|
|
}
|
|
|
|
e.Error = os.RemoveAll(e.GitPath)
|
|
e.GitPath = ""
|
|
return
|
|
}
|
|
|
|
func (e *RequestHandler) HasError() bool {
|
|
return e.Error != nil
|
|
}
|
|
|
|
type writeFunc func(data []byte) (int, error)
|
|
|
|
func (f writeFunc) Write(data []byte) (int, error) {
|
|
return f(data)
|
|
}
|
|
|
|
func (e *RequestHandler) GitExec(cwd string, params ...string) ExecStream {
|
|
if e.Error != nil {
|
|
return e
|
|
}
|
|
|
|
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,
|
|
"EMAIL=not@exist@src.opensuse.org",
|
|
"GIT_LFS_SKIP_SMUDGE=1",
|
|
"GIT_SSH_COMMAND=/usr/bin/ssh -o StrictHostKeyChecking=yes",
|
|
}
|
|
cmd.Dir = filepath.Join(e.GitPath, cwd)
|
|
cmd.Stdout = writeFunc(func(data []byte) (int, error) {
|
|
e.Logger.Log("%s", data)
|
|
return len(data), nil
|
|
})
|
|
cmd.Stderr = writeFunc(func(data []byte) (int, error) {
|
|
e.Logger.LogError("%s", data)
|
|
return len(data), nil
|
|
})
|
|
cmd.Stdin = nil
|
|
|
|
e.Log("git execute: %#v", cmd.Args)
|
|
e.Error = cmd.Run()
|
|
|
|
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)
|
|
}
|
|
|
|
func (e *RequestHandler) GitSubmoduleCommitId(cwd, packageName 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
|
|
})
|
|
|
|
return "", false
|
|
}
|