instrument git stuff with errs
This commit is contained in:
66
git/diff.go
66
git/diff.go
@@ -1,8 +1,6 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/bluekeyes/go-gitdiff/gitdiff"
|
||||
@@ -42,44 +40,37 @@ type NiceDiff struct {
|
||||
Diff []Diff
|
||||
}
|
||||
|
||||
func (g *GitRepo) Diff() (*NiceDiff, error) {
|
||||
c, err := g.r.CommitObject(g.h)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("commit object: %w", err)
|
||||
func (g *GitRepo) Diff() (nd *NiceDiff, err error) {
|
||||
var c *object.Commit
|
||||
if c, err = g.r.CommitObject(g.h); chk.E(err) {
|
||||
return nil, log.E.Err("commit object: %w", err)
|
||||
}
|
||||
|
||||
patch := &object.Patch{}
|
||||
commitTree, err := c.Tree()
|
||||
parent := &object.Commit{}
|
||||
if err == nil {
|
||||
var commitTree *object.Tree
|
||||
if commitTree, err = c.Tree(); chk.E(err) {
|
||||
parentTree := &object.Tree{}
|
||||
if c.NumParents() != 0 {
|
||||
parent, err = c.Parents().Next()
|
||||
if err == nil {
|
||||
parentTree, err = parent.Tree()
|
||||
if err == nil {
|
||||
patch, err = parentTree.Patch(commitTree)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("patch: %w", err)
|
||||
if parent, err = c.Parents().Next(); !chk.E(err) {
|
||||
if parentTree, err = parent.Tree(); !chk.E(err) {
|
||||
if patch, err = parentTree.Patch(commitTree); chk.E(err) {
|
||||
return nil, log.E.Err("patch: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
patch, err = parentTree.Patch(commitTree)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("patch: %w", err)
|
||||
if patch, err = parentTree.Patch(commitTree); chk.E(err) {
|
||||
return nil, log.E.Err("patch: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
diffs, _, err := gitdiff.Parse(strings.NewReader(patch.String()))
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
var diffs []*gitdiff.File
|
||||
if diffs, _, err = gitdiff.Parse(strings.NewReader(patch.String())); chk.E(err) {
|
||||
return
|
||||
}
|
||||
|
||||
nd := NiceDiff{}
|
||||
nd = &NiceDiff{}
|
||||
nd.Commit.This = c.Hash.String()
|
||||
|
||||
if parent.Hash.IsZero() {
|
||||
nd.Commit.Parent = ""
|
||||
} else {
|
||||
@@ -87,17 +78,15 @@ func (g *GitRepo) Diff() (*NiceDiff, error) {
|
||||
}
|
||||
nd.Commit.Author = c.Author
|
||||
nd.Commit.Message = c.Message
|
||||
|
||||
for _, d := range diffs {
|
||||
ndiff := Diff{}
|
||||
ndiff.Name.New = d.NewName
|
||||
ndiff.Name.Old = d.OldName
|
||||
ndiff.IsBinary = d.IsBinary
|
||||
ndiff.IsNew = d.IsNew
|
||||
ndiff.IsDelete = d.IsDelete
|
||||
|
||||
nDiff := Diff{}
|
||||
nDiff.Name.New = d.NewName
|
||||
nDiff.Name.Old = d.OldName
|
||||
nDiff.IsBinary = d.IsBinary
|
||||
nDiff.IsNew = d.IsNew
|
||||
nDiff.IsDelete = d.IsDelete
|
||||
for _, tf := range d.TextFragments {
|
||||
ndiff.TextFragments = append(ndiff.TextFragments, TextFragment{
|
||||
nDiff.TextFragments = append(nDiff.TextFragments, TextFragment{
|
||||
Header: tf.Header(),
|
||||
Lines: tf.Lines,
|
||||
})
|
||||
@@ -107,14 +96,13 @@ func (g *GitRepo) Diff() (*NiceDiff, error) {
|
||||
nd.Stat.Insertions += 1
|
||||
case gitdiff.OpDelete:
|
||||
nd.Stat.Deletions += 1
|
||||
default:
|
||||
panic("unhandled default case")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nd.Diff = append(nd.Diff, ndiff)
|
||||
nd.Diff = append(nd.Diff, nDiff)
|
||||
}
|
||||
|
||||
nd.Stat.FilesChanged = len(diffs)
|
||||
|
||||
return &nd, nil
|
||||
return
|
||||
}
|
||||
|
||||
178
git/git.go
178
git/git.go
@@ -2,13 +2,18 @@ package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
"github.com/go-git/go-git/v5/plumbing/storer"
|
||||
"mleku.dev/git/slog"
|
||||
)
|
||||
|
||||
var log, chk = slog.New(os.Stderr)
|
||||
|
||||
type GitRepo struct {
|
||||
r *git.Repository
|
||||
h plumbing.Hash
|
||||
@@ -16,141 +21,120 @@ type GitRepo struct {
|
||||
|
||||
type TagList []*object.Tag
|
||||
|
||||
func (self TagList) Len() int {
|
||||
return len(self)
|
||||
}
|
||||
func (t TagList) Len() int { return len(t) }
|
||||
func (t TagList) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
|
||||
func (t TagList) Less(i, j int) bool { return t[i].Tagger.When.After(t[j].Tagger.When) }
|
||||
|
||||
func (self TagList) Swap(i, j int) {
|
||||
self[i], self[j] = self[j], self[i]
|
||||
}
|
||||
|
||||
// sorting tags in reverse chronological order
|
||||
func (self TagList) Less(i, j int) bool {
|
||||
return self[i].Tagger.When.After(self[j].Tagger.When)
|
||||
}
|
||||
|
||||
func Open(path string, ref string) (*GitRepo, error) {
|
||||
var err error
|
||||
g := GitRepo{}
|
||||
g.r, err = git.PlainOpen(path)
|
||||
func Open(path string, ref string) (gr *GitRepo, err error) {
|
||||
gr = &GitRepo{}
|
||||
gr.r, err = git.PlainOpen(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("opening %s: %w", path, err)
|
||||
}
|
||||
|
||||
if ref == "" {
|
||||
head, err := g.r.Head()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting head of %s: %w", path, err)
|
||||
var head *plumbing.Reference
|
||||
if head, err = gr.r.Head(); chk.E(err) {
|
||||
err = log.E.Err("getting head of %s: %w", path, err)
|
||||
return
|
||||
}
|
||||
g.h = head.Hash()
|
||||
gr.h = head.Hash()
|
||||
} else {
|
||||
hash, err := g.r.ResolveRevision(plumbing.Revision(ref))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("resolving rev %s for %s: %w", ref, path, err)
|
||||
var h *plumbing.Hash
|
||||
if h, err = gr.r.ResolveRevision(plumbing.Revision(ref)); chk.E(err) {
|
||||
err = log.E.Err("resolving rev %s for %s: %w", ref, path, err)
|
||||
return
|
||||
}
|
||||
g.h = *hash
|
||||
gr.h = *h
|
||||
}
|
||||
return &g, nil
|
||||
return
|
||||
}
|
||||
|
||||
func (g *GitRepo) Commits() ([]*object.Commit, error) {
|
||||
ci, err := g.r.Log(&git.LogOptions{From: g.h})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("commits from ref: %w", err)
|
||||
func (g *GitRepo) Commits() (oc []*object.Commit, err error) {
|
||||
var ci object.CommitIter
|
||||
if ci, err = g.r.Log(&git.LogOptions{From: g.h}); chk.E(err) {
|
||||
err = log.E.Err("commits from ref: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
commits := []*object.Commit{}
|
||||
ci.ForEach(func(c *object.Commit) error {
|
||||
commits = append(commits, c)
|
||||
return nil
|
||||
})
|
||||
|
||||
return commits, nil
|
||||
oc = []*object.Commit{}
|
||||
chk.E(ci.ForEach(func(c *object.Commit) (err error) {
|
||||
oc = append(oc, c)
|
||||
return
|
||||
}))
|
||||
return
|
||||
}
|
||||
|
||||
func (g *GitRepo) LastCommit() (*object.Commit, error) {
|
||||
c, err := g.r.CommitObject(g.h)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("last commit: %w", err)
|
||||
}
|
||||
return c, nil
|
||||
func (g *GitRepo) LastCommit() (oc *object.Commit, err error) {
|
||||
return g.r.CommitObject(g.h)
|
||||
}
|
||||
|
||||
func (g *GitRepo) FileContent(path string) (string, error) {
|
||||
c, err := g.r.CommitObject(g.h)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("commit object: %w", err)
|
||||
func (g *GitRepo) FileContent(path string) (content string, err error) {
|
||||
var c *object.Commit
|
||||
if c, err = g.r.CommitObject(g.h); chk.E(err) {
|
||||
err = log.E.Err("commit object: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
tree, err := c.Tree()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("file tree: %w", err)
|
||||
var tree *object.Tree
|
||||
if tree, err = c.Tree(); chk.E(err) {
|
||||
err = log.E.Err("file tree: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
file, err := tree.File(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
var file *object.File
|
||||
if file, err = tree.File(path); chk.E(err) {
|
||||
err = log.E.Err("%s: %s", err, path)
|
||||
return
|
||||
}
|
||||
|
||||
isbin, _ := file.IsBinary()
|
||||
|
||||
if !isbin {
|
||||
return file.Contents()
|
||||
isBinary, _ := file.IsBinary()
|
||||
if !isBinary {
|
||||
content, err = file.Contents()
|
||||
} else {
|
||||
return "Not displaying binary file", nil
|
||||
content = "Not displaying binary file"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (g *GitRepo) Tags() ([]*object.Tag, error) {
|
||||
ti, err := g.r.TagObjects()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tag objects: %w", err)
|
||||
func (g *GitRepo) Tags() (tags []*object.Tag, err error) {
|
||||
var ti *object.TagIter
|
||||
if ti, err = g.r.TagObjects(); chk.E(err) {
|
||||
err = log.E.Err("tag objects: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
tags := []*object.Tag{}
|
||||
|
||||
_ = ti.ForEach(func(t *object.Tag) error {
|
||||
chk.E(ti.ForEach(func(t *object.Tag) (err error) {
|
||||
for i, existing := range tags {
|
||||
if existing.Name == t.Name {
|
||||
if t.Tagger.When.After(existing.Tagger.When) {
|
||||
tags[i] = t
|
||||
}
|
||||
return nil
|
||||
return
|
||||
}
|
||||
}
|
||||
tags = append(tags, t)
|
||||
return nil
|
||||
})
|
||||
|
||||
var tagList TagList
|
||||
tagList = tags
|
||||
sort.Sort(tagList)
|
||||
|
||||
return tags, nil
|
||||
return
|
||||
}))
|
||||
t := TagList(tags)
|
||||
sort.Sort(t)
|
||||
tags = t
|
||||
return
|
||||
}
|
||||
|
||||
func (g *GitRepo) Branches() ([]*plumbing.Reference, error) {
|
||||
bi, err := g.r.Branches()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("branchs: %w", err)
|
||||
func (g *GitRepo) Branches() (branches []*plumbing.Reference, err error) {
|
||||
var bi storer.ReferenceIter
|
||||
if bi, err = g.r.Branches(); chk.E(err) {
|
||||
err = log.E.Err("branches: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
branches := []*plumbing.Reference{}
|
||||
|
||||
_ = bi.ForEach(func(ref *plumbing.Reference) error {
|
||||
chk.E(bi.ForEach(func(ref *plumbing.Reference) (err error) {
|
||||
branches = append(branches, ref)
|
||||
return nil
|
||||
})
|
||||
|
||||
return branches, nil
|
||||
return
|
||||
}))
|
||||
return
|
||||
}
|
||||
|
||||
func (g *GitRepo) FindMainBranch(branches []string) (string, error) {
|
||||
for _, b := range branches {
|
||||
_, err := g.r.ResolveRevision(plumbing.Revision(b))
|
||||
if err == nil {
|
||||
return b, nil
|
||||
func (g *GitRepo) FindMainBranch(branches []string) (b string, err error) {
|
||||
for _, b = range branches {
|
||||
if _, err = g.r.ResolveRevision(plumbing.Revision(b)); !chk.E(err) {
|
||||
return
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("unable to find main branch")
|
||||
err = log.E.Err("unable to find main branch")
|
||||
return
|
||||
}
|
||||
|
||||
66
git/tree.go
66
git/tree.go
@@ -1,45 +1,46 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
)
|
||||
|
||||
func (g *GitRepo) FileTree(path string) ([]NiceTree, error) {
|
||||
c, err := g.r.CommitObject(g.h)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("commit object: %w", err)
|
||||
func (g *GitRepo) FileTree(path string) (files []NiceTree, err error) {
|
||||
var c *object.Commit
|
||||
if c, err = g.r.CommitObject(g.h); chk.E(err) {
|
||||
err = log.E.Err("commit object: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
files := []NiceTree{}
|
||||
tree, err := c.Tree()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("file tree: %w", err)
|
||||
var tree *object.Tree
|
||||
if tree, err = c.Tree(); chk.E(err) {
|
||||
err = log.E.Err("file tree: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
if path == "" {
|
||||
files = makeNiceTree(tree)
|
||||
} else {
|
||||
o, err := tree.FindEntry(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if files, err = makeNiceTree(tree); chk.E(err) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
var o *object.TreeEntry
|
||||
if o, err = tree.FindEntry(path); chk.E(err) {
|
||||
return
|
||||
}
|
||||
|
||||
if !o.Mode.IsFile() {
|
||||
subtree, err := tree.Tree(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var subtree *object.Tree
|
||||
if subtree, err = tree.Tree(path); chk.E(err) {
|
||||
return
|
||||
}
|
||||
if files, err = makeNiceTree(subtree); chk.E(err) {
|
||||
return
|
||||
}
|
||||
|
||||
files = makeNiceTree(subtree)
|
||||
}
|
||||
}
|
||||
|
||||
return files, nil
|
||||
return
|
||||
}
|
||||
|
||||
// A nicer git tree representation.
|
||||
|
||||
type NiceTree struct {
|
||||
Name string
|
||||
Mode string
|
||||
@@ -48,12 +49,16 @@ type NiceTree struct {
|
||||
IsSubtree bool
|
||||
}
|
||||
|
||||
func makeNiceTree(t *object.Tree) []NiceTree {
|
||||
nts := []NiceTree{}
|
||||
|
||||
func makeNiceTree(t *object.Tree) (nts []NiceTree, err error) {
|
||||
for _, e := range t.Entries {
|
||||
mode, _ := e.Mode.ToOSFileMode()
|
||||
sz, _ := t.Size(e.Name)
|
||||
var mode os.FileMode
|
||||
if mode, err = e.Mode.ToOSFileMode(); chk.E(err) {
|
||||
return
|
||||
}
|
||||
var sz int64
|
||||
if sz, err = t.Size(e.Name); chk.E(err) {
|
||||
return
|
||||
}
|
||||
nts = append(nts, NiceTree{
|
||||
Name: e.Name,
|
||||
Mode: mode.String(),
|
||||
@@ -61,6 +66,5 @@ func makeNiceTree(t *object.Tree) []NiceTree {
|
||||
Size: sz,
|
||||
})
|
||||
}
|
||||
|
||||
return nts
|
||||
return
|
||||
}
|
||||
|
||||
4
go.sum
4
go.sum
@@ -104,8 +104,6 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -157,8 +155,6 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
mleku.dev/git/atomic v1.11.5 h1:Y1lFQZl1yBKRrnSKm/9jTSJ0zwQwgOp1RcyovRvLEeI=
|
||||
mleku.dev/git/atomic v1.11.5/go.mod h1:Kt4gYG8niP33EVsiW+9iZJMF07a8H5ZSDIajAAOcRJE=
|
||||
mleku.dev/git/atomic v1.11.6 h1:KsqRZPMD9q74kynTMendU3dAQ1loOvizCNKJoc8tQiw=
|
||||
mleku.dev/git/atomic v1.11.6/go.mod h1:Kt4gYG8niP33EVsiW+9iZJMF07a8H5ZSDIajAAOcRJE=
|
||||
mleku.dev/git/slog v1.0.16 h1:ibfAo21AstzrKdc9b58S8QxhNXPsSgYeGOCbNGmv60M=
|
||||
|
||||
Reference in New Issue
Block a user