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 }