Skip to content

Commit

Permalink
git: implement git on top of go-git
Browse files Browse the repository at this point in the history
Code is simpler, faster, and we can get rid of ref detection (could
previously already have done that, just need to pull HEAD).
  • Loading branch information
TvdW committed Aug 28, 2024
1 parent 69ff895 commit 6c7b5b9
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 199 deletions.
157 changes: 43 additions & 114 deletions vcs/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,25 @@ import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"os/exec"
"path/filepath"
"regexp"
"strings"

gogit "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/plumbing"
)

const defaultRef = "master"
const indexRef = "localindex"
const autoGeneratedAttribute = "linguist-generated"

var headBranchRegexp = regexp.MustCompile(`HEAD branch: (?P<branch>.+)`)

func init() {
Register(newGit, "git")
}

type GitDriver struct {
DetectRef bool `json:"detect-ref"`
Ref string `json:"ref"`
Bare bool `json:"bare"`
refDetetector refDetetector
}

type refDetetector interface {
detectRef(dir string) string
}

type headBranchDetector struct {
Ref string `json:"ref"`
Bare bool `json:"bare"`
}

func newGit(b []byte) (Driver, error) {
Expand All @@ -44,97 +34,62 @@ func newGit(b []byte) (Driver, error) {
}
}

d.refDetetector = &headBranchDetector{}

return &d, nil
}

func (g *GitDriver) HeadRev(dir string) (string, error) {
targetRef := "HEAD"
if g.Bare {
targetRef = fmt.Sprintf("origin/%s", g.targetRef(dir))
repo, err := gogit.PlainOpen(dir)
if err != nil {
return "", nil
}

cmd := exec.Command(
"git",
"rev-parse",
targetRef)
cmd.Dir = dir
r, err := cmd.StdoutPipe()
h, err := repo.ResolveRevision(plumbing.Revision(indexRef))
if err != nil {
return "", err
}
defer r.Close()

if err := cmd.Start(); err != nil {
return h.String(), nil
}

func (g *GitDriver) Pull(dir string) (string, error) {
repo, err := gogit.PlainOpen(dir)
if err != nil {
return "", err
}

var buf bytes.Buffer
fetchTarget := "HEAD"
if g.Ref != "" {
fetchTarget = g.Ref
}

if _, err := io.Copy(&buf, r); err != nil {
if err = repo.Fetch(&gogit.FetchOptions{
Depth: 1,
Prune: true,
Tags: gogit.NoTags,
RefSpecs: []config.RefSpec{
config.RefSpec(fmt.Sprintf("+%s:refs/heads/%s", fetchTarget, indexRef)),
},
}); err != nil {
return "", err
}

return strings.TrimSpace(buf.String()), cmd.Wait()
}

func run(desc, dir, cmd string, args ...string) (string, error) {
c := exec.Command(cmd, args...)
c.Dir = dir
out, err := c.CombinedOutput()
newHead, err := repo.ResolveRevision(indexRef)
if err != nil {
log.Printf(
"Failed to %s %v at %q, see output below\n%s: %+v\nContinuing...",
desc,
c.Args, c.Dir,
out, err)
}

return string(out), nil
}

func (g *GitDriver) Pull(dir string) (string, error) {
targetRef := g.targetRef(dir)

if _, err := run("git fetch", dir,
"git",
"fetch",
"--prune",
"--no-tags",
"--depth", "1",
"origin",
fmt.Sprintf("+%s:remotes/origin/%s", targetRef, targetRef)); err != nil {
return "", err
}

if !g.Bare {
// XXX(tvdw) Check if this works without fetch?
if _, err := run("git reset", dir,
"git",
"reset",
"--hard",
fmt.Sprintf("origin/%s", targetRef)); err != nil {
worktree, err := repo.Worktree()
if err != nil {
return "", err
}
worktree.Reset(&gogit.ResetOptions{
Mode: gogit.HardReset,
Commit: *newHead,
})
}

return g.HeadRev(dir)
}

func (g *GitDriver) targetRef(dir string) string {
var targetRef string
if g.Ref != "" {
targetRef = g.Ref
} else if g.DetectRef {
targetRef = g.refDetetector.detectRef(dir)
}

if targetRef == "" {
targetRef = defaultRef
}

return targetRef
return newHead.String(), nil
}

func (g *GitDriver) Clone(dir, url string) (string, error) {
Expand Down Expand Up @@ -168,6 +123,11 @@ func (g *GitDriver) SpecialFiles() []string {
func (g *GitDriver) AutoGeneratedFiles(dir string) []string {
var files []string

// XXX(tvdw): broken under Bare
if g.Bare {
return nil
}

filesCmd := exec.Command("git", "ls-files", "-z")
filesCmd.Dir = dir
pipe, err := filesCmd.StdoutPipe()
Expand Down Expand Up @@ -210,40 +170,9 @@ func (g *GitDriver) AutoGeneratedFiles(dir string) []string {
return files
}

func (d *headBranchDetector) detectRef(dir string) string {
output, err := run("git show remote info", dir,
"git",
"remote",
"show",
"origin",
)

if err != nil {
log.Printf(
"error occured when fetching info to determine target ref in %s: %s. Will fall back to default ref %s",
dir,
err,
defaultRef,
)
return ""
}

matches := headBranchRegexp.FindStringSubmatch(output)
if len(matches) != 2 {
log.Printf(
"could not determine target ref in %s. Will fall back to default ref %s",
dir,
defaultRef,
)
return ""
}

return matches[1]
}

func (g *GitDriver) FileSystem(dir string) (FileSystem, error) {
if g.Bare {
return NewGitFilesystem(dir, fmt.Sprintf("origin/%s", g.targetRef(dir)))
return NewGitFilesystem(dir, indexRef)
} else {
return NewDirFilesystem(dir)
}
Expand Down
85 changes: 0 additions & 85 deletions vcs/git_test.go

This file was deleted.

0 comments on commit 6c7b5b9

Please sign in to comment.