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 8172ac9
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 222 deletions.
171 changes: 37 additions & 134 deletions vcs/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,23 @@ 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"
)

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,115 +32,56 @@ 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))
}

cmd := exec.Command(
"git",
"rev-parse",
targetRef)
cmd.Dir = dir
r, err := cmd.StdoutPipe()
func (g *GitDriver) Pull(dir string) (string, error) {
repo, err := gogit.PlainOpen(dir)
if err != nil {
return "", err
}
defer r.Close()

if err := cmd.Start(); err != nil {
return "", err
fetchTarget := "HEAD"
if g.Ref != "" {
fetchTarget = g.Ref
}

var buf bytes.Buffer

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) {
par, rep := filepath.Split(dir)

cmdArgs := []string{
"clone",
"--depth", "1",
}
if g.Bare {
cmdArgs = append(cmdArgs, "--bare")
}
cmdArgs = append(cmdArgs, url, rep)
cmd := exec.Command("git", cmdArgs...)
cmd.Dir = par
out, err := cmd.CombinedOutput()
_, err := gogit.PlainClone(dir, g.Bare, &gogit.CloneOptions{
Depth: 1,
URL: url,
})
if err != nil {
log.Printf("Failed to clone %s, see output below\n%sContinuing...", url, out)
return "", err
}

Expand All @@ -168,6 +97,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 +144,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.

3 changes: 0 additions & 3 deletions vcs/vcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,6 @@ type Driver interface {
// Pull new changes from the server and update the working directory.
Pull(dir string) (string, error)

// Return the revision at the head of the vcs directory.
HeadRev(dir string) (string, error)

// Return a list of special filenames that should not be indexed.
SpecialFiles() []string

Expand Down

0 comments on commit 8172ac9

Please sign in to comment.