git: one generator per app, multiple instances
this allows locking for access for each org
This commit is contained in:
@@ -25,12 +25,10 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
@@ -48,7 +46,7 @@ type GitStatusLister interface {
|
||||
|
||||
type Git interface {
|
||||
// error if git, but wrong remote
|
||||
GitClone(remoteUrl string) (string, error) // clone, or chekc if path is already checked out remote and pulls, error otherwise. Return relative path
|
||||
GitClone(repo, branch, remoteName, remoteUrl string) error // clone, or chekc if path is already checked out remote and force pulls, error otherwise. Return relative path
|
||||
|
||||
GitParseCommits(cwd string, commitIDs []string) (parsedCommits []GitCommit, err error)
|
||||
GitCatFile(cwd, commitId, filename string) (data []byte, err error)
|
||||
@@ -81,45 +79,41 @@ func (s *GitHandlerImpl) GetPath() string {
|
||||
}
|
||||
|
||||
type GitHandlerGenerator interface {
|
||||
CreateGitHandler(repo string) (Git, error)
|
||||
ReadExistingPath(repo string) (Git, error)
|
||||
CreateGitHandler(org, branch string) (Git, error)
|
||||
ReadExistingPath(org, branch string) (Git, error)
|
||||
|
||||
ReleaseLock(path string)
|
||||
}
|
||||
|
||||
type GitHandlerGeneratorImpl struct {
|
||||
type gitHandlerGeneratorImpl struct {
|
||||
// TODO: add mutex to lock paths so only one workflow per path and others wait
|
||||
path string
|
||||
org, branch string
|
||||
git_author string
|
||||
email string
|
||||
path string
|
||||
git_author string
|
||||
email string
|
||||
|
||||
lock_lock sync.Mutex
|
||||
lock map[string]sync.Mutex
|
||||
}
|
||||
|
||||
func AllocateGitWorkTree(basePath, org, branch, gitAuthor, email string) (GitHandlerGenerator, error) {
|
||||
func AllocateGitWorkTree(basePath, gitAuthor, email string) (GitHandlerGenerator, error) {
|
||||
if fi, err := os.Stat(basePath); err != nil || !fi.IsDir() {
|
||||
return nil, fmt.Errorf("Git basepath not a valid directory: %s %w", basePath, err)
|
||||
}
|
||||
|
||||
path := path.Join(basePath, org, branch)
|
||||
if fi, err := os.Stat(path); err != nil {
|
||||
if fi, err := os.Stat(basePath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(path, 0o700); err != nil {
|
||||
return nil, fmt.Errorf("Cannot create git directory structure: %s: %w", path, err)
|
||||
if err = os.MkdirAll(basePath, 0o700); err != nil {
|
||||
return nil, fmt.Errorf("Cannot create git directory structure: %s: %w", basePath, err)
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("Error checking git directory strcture: %s: %w", path, err)
|
||||
return nil, fmt.Errorf("Error checking git directory strcture: %s: %w", basePath, err)
|
||||
}
|
||||
} else if !fi.IsDir() {
|
||||
return nil, fmt.Errorf("Invalid git directory structure: %s != directory", path)
|
||||
return nil, fmt.Errorf("Invalid git directory structure: %s != directory", basePath)
|
||||
}
|
||||
|
||||
return &GitHandlerGeneratorImpl{
|
||||
return &gitHandlerGeneratorImpl{
|
||||
path: basePath,
|
||||
org: org,
|
||||
branch: branch,
|
||||
git_author: gitAuthor,
|
||||
email: email,
|
||||
|
||||
@@ -127,27 +121,30 @@ func AllocateGitWorkTree(basePath, org, branch, gitAuthor, email string) (GitHan
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *GitHandlerGeneratorImpl) CreateGitHandler(repoName string) (Git, error) {
|
||||
func (s *gitHandlerGeneratorImpl) CreateGitHandler(org, branch string) (Git, error) {
|
||||
|
||||
path := path.Join(s.path, repoName)
|
||||
if err := os.Mkdir(path, 0o777); err != nil {
|
||||
path := path.Join(s.path, org, branch)
|
||||
if fs, err := os.Stat(s.path); err != nil || !fs.IsDir() {
|
||||
return nil, err
|
||||
}
|
||||
if err := os.MkdirAll(path, 0o777); err != nil && !os.IsExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.ReadExistingPath(repoName)
|
||||
return s.ReadExistingPath(org, branch)
|
||||
}
|
||||
|
||||
func (s *GitHandlerGeneratorImpl) ReadExistingPath(repo string) (Git, error) {
|
||||
func (s *gitHandlerGeneratorImpl) ReadExistingPath(org, branch string) (Git, error) {
|
||||
git := &GitHandlerImpl{
|
||||
GitCommiter: s.git_author,
|
||||
GitEmail: s.email,
|
||||
GitPath: path.Join(s.path, s.org, s.branch, repo),
|
||||
GitPath: path.Join(s.path, org, branch),
|
||||
}
|
||||
|
||||
return git, nil
|
||||
}
|
||||
|
||||
func (s *GitHandlerGeneratorImpl) ReleaseLock(repo string) {
|
||||
func (s *gitHandlerGeneratorImpl) ReleaseLock(repo string) {
|
||||
|
||||
}
|
||||
|
||||
@@ -189,45 +186,26 @@ func (refs *GitReferences) addReference(id, branch string) {
|
||||
refs.refs = append(refs.refs, GitReference{Branch: branch, Id: id})
|
||||
}
|
||||
|
||||
var sshStyleUrl = regexp.MustCompile("^([\\w\\.]+@)?[\\w\\.]+:.*$")
|
||||
func GitClonePathFromUrl(remoteUrl string) (string, error) {
|
||||
if sshStyleUrl.MatchString(remoteUrl) {
|
||||
remoteUrl = "ssh://" + strings.Replace(remoteUrl, ":", "/", 1)
|
||||
}
|
||||
u, err := url.Parse(remoteUrl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
idx := strings.LastIndex(u.Path, "/")
|
||||
p := strings.TrimSuffix(u.Path[idx+1:], ".git")
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (e *GitHandlerImpl) GitClone(remoteUrl string) (string, error) {
|
||||
p, err := GitClonePathFromUrl(remoteUrl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if fi, err := os.Stat(path.Join(e.GitPath, p)); os.IsNotExist(err) {
|
||||
return p, e.GitExec("", "clone", remoteUrl, p)
|
||||
func (e *GitHandlerImpl) GitClone(repo, branch, remoteName, remoteUrl string) error {
|
||||
if fi, err := os.Stat(path.Join(e.GitPath, repo)); os.IsNotExist(err) {
|
||||
return e.GitExec("", "clone", remoteUrl, repo)
|
||||
} else if err != nil || !fi.IsDir() {
|
||||
return p, fmt.Errorf("Clone location not a directory or Stat error: %w", err)
|
||||
return fmt.Errorf("Clone location not a directory or Stat error: %w", err)
|
||||
}
|
||||
|
||||
clonedRemote:= strings.TrimSpace(e.GitExecWithOutputOrPanic(p, "remote", "get-url", "origin"))
|
||||
clonedRemote := strings.TrimSpace(e.GitExecWithOutputOrPanic(repo, "remote", "get-url", remoteName))
|
||||
if clonedRemote != remoteUrl {
|
||||
return p, fmt.Errorf("Path at '%s' remote %s != %s", p, clonedRemote, remoteUrl)
|
||||
e.GitExecOrPanic(repo, "remote", "set-url", remoteName, remoteUrl)
|
||||
}
|
||||
|
||||
return p, err
|
||||
e.GitExecOrPanic(repo, "fetch", remoteName)
|
||||
return e.GitExec(repo, "checkout", "-B", branch, remoteName+"/"+branch)
|
||||
}
|
||||
|
||||
func (e *GitHandlerImpl) GitBranchHead(gitDir, branchName string) (string, error) {
|
||||
id, err := e.GitExecWithOutput(gitDir, "rev-list", "-1", branchName)
|
||||
id, err := e.GitExecWithOutput(gitDir, "show-ref", "-s", branchName)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Can't find default remote branch: %s", branchName)
|
||||
return "", fmt.Errorf("Can't find default branch: %s", branchName)
|
||||
}
|
||||
|
||||
return strings.TrimSpace(id), nil
|
||||
|
||||
Reference in New Issue
Block a user