You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

193 lines
4.0 KiB
Go

package giq
import (
"fmt"
"io"
"math/rand"
"os"
"path"
"path/filepath"
"strings"
gogit "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
)
func (g *Gogit) Whoami() string {
return "I am Gogit!"
}
func detectGitPath(path string) (string, error) {
path, err := filepath.Abs(path)
if err != nil {
return "", err
}
for {
fi, err := os.Stat(filepath.Join(path, ".git"))
if err == nil {
if !fi.IsDir() {
return "", fmt.Errorf(".git exist but is not a directory")
}
return filepath.Join(path, ".git"), nil
}
if !os.IsNotExist(err) {
return "", err
}
ok, err := isGitDir(path)
if err != nil {
return "", err
}
if ok {
return path, nil
}
if parent := filepath.Dir(path); parent == path {
return "", fmt.Errorf(".git not found")
} else {
path = parent
}
}
}
func isGitDir(path string) (bool, error) {
markers := []string{"HEAD", "objects", "refs"}
for _, marker := range markers {
_, err := os.Stat(filepath.Join(path, marker))
if err == nil {
continue
}
if !os.IsNotExist(err) {
return false, err
} else {
return false, nil
}
}
return true, nil
}
func isPublish(r gogit.Repository, prevCommit, lastCommit string) bool {
ret := false
pCommit, err := r.ResolveRevision(plumbing.Revision(prevCommit))
check(err)
lCommit, err := r.ResolveRevision(plumbing.Revision(lastCommit))
check(err)
// fileName := "README.md"
hashCommitRange, err := r.Log(&gogit.LogOptions{
From: *lCommit,
// FileName: &fileName,
// Order:
})
check(err)
hashCommitMap := make(map[string]bool)
err = hashCommitRange.ForEach(func(c *object.Commit) error {
// fmt.Println(c.Hash.String(), c.Message)
hashCommitMap[c.Hash.String()] = true
ok := strings.Contains(c.Message, "!publish!")
if ok {
ret = true
return io.EOF
} else if c.Hash == *pCommit {
// return storer.ErrStop
return io.EOF
}
return nil
})
if ret {
return true
}
fileName := "PUBLISH_TRIGGER.md"
fileNameCommitRange, err := r.Log(&gogit.LogOptions{
FileName: &fileName,
})
check(err)
err = fileNameCommitRange.ForEach(func(c *object.Commit) error {
_, ok := hashCommitMap[c.Hash.String()]
if ok {
// return storer.ErrStop
ret = true
return io.EOF
}
return nil
})
// fmt.Println(hashCommitMap)
if ret {
return true
}
return false
}
func (g *Gogit) AddBareWorktree(gitRepoPath, gitIndexPath, gitWorktree, gexe string) {
tmpRepoPath := filepath.Join(os.TempDir(), gitWorktree)
_, err := gogit.PlainClone(tmpRepoPath, false, &gogit.CloneOptions{
URL: gitRepoPath,
Depth: 1,
Tags: gogit.NoTags,
// NoCheckout: true,
})
check(err)
// fmt.Println("WORKTREE:", tmpRepoPath)
}
func (g *Gogit) RemoveBareWorktree(gitRepoPath, gitIndexPath, gitWorktree, gexe string) {
tmpRepoPath := filepath.Join(os.TempDir(), gitWorktree)
err := os.RemoveAll(tmpRepoPath)
check(err)
}
func (g *Gogit) GitStruct(hookPath, hookContext, hookStdinput, gexe string) Git {
var git Git
_ = gexe
gitBase, err := detectGitPath(hookPath)
check(err)
repoPath := gitBase
git.IsBare = true
base := path.Base(gitBase)
if base == ".git" {
git.IsBare = false
repoPath = strings.Replace(gitBase, ".git", "", 1)
}
r, err := gogit.PlainOpen(repoPath)
check(err)
gitPreviousCommit, err := r.ResolveRevision(plumbing.Revision("HEAD^"))
check(err)
headCommit, err := r.Head()
check(err)
prevCommit := gitPreviousCommit.String()
lastCommit := headCommit.Hash().String()
if hookContext == "PostReceive" {
revs := strings.Fields(hookStdinput)
prevCommit = revs[0]
lastCommit = revs[1]
}
git.Publish = isPublish(*r, prevCommit, lastCommit)
git.RepoPath = repoPath
git.PreviousCommit = prevCommit
git.LastCommit = lastCommit
git.Branch = headCommit.Name().Short()
git.IndexPath = filepath.Join("/", ".git", "index")
if git.IsBare {
git.IndexPath = filepath.Join("/", "index")
}
git.Worktree = fmt.Sprintf("sandpoints_repo_%06d", rand.Intn(100001))
git.TmpRepoPath = filepath.Join(os.TempDir(), git.Worktree)
return git
}