knotserver/git: refactor GitRepo.Tags to use git for-each-ref #309

merged
opened by oppi.li targeting master from push-rqxyyurmpkps
Changed files
+118 -44
knotserver
-33
knotserver/git/git.go
···
return io.ReadAll(reader)
}
-
func (g *GitRepo) Tags() ([]*TagReference, error) {
-
iter, err := g.r.Tags()
-
if err != nil {
-
return nil, fmt.Errorf("tag objects: %w", err)
-
}
-
-
tags := make([]*TagReference, 0)
-
-
if err := iter.ForEach(func(ref *plumbing.Reference) error {
-
obj, err := g.r.TagObject(ref.Hash())
-
switch err {
-
case nil:
-
tags = append(tags, &TagReference{
-
ref: ref,
-
tag: obj,
-
})
-
case plumbing.ErrObjectNotFound:
-
tags = append(tags, &TagReference{
-
ref: ref,
-
})
-
default:
-
return err
-
}
-
return nil
-
}); err != nil {
-
return nil, err
-
}
-
-
tagList := &TagList{r: g.r, refs: tags}
-
sort.Sort(tagList)
-
return tags, nil
-
}
-
func (g *GitRepo) Branches() ([]types.Branch, error) {
bi, err := g.r.Branches()
if err != nil {
···
return io.ReadAll(reader)
}
func (g *GitRepo) Branches() ([]types.Branch, error) {
bi, err := g.r.Branches()
if err != nil {
+99
knotserver/git/tag.go
···
···
+
package git
+
+
import (
+
"fmt"
+
"slices"
+
"strconv"
+
"strings"
+
"time"
+
+
"github.com/go-git/go-git/v5/plumbing"
+
"github.com/go-git/go-git/v5/plumbing/object"
+
)
+
+
func (g *GitRepo) Tags() ([]object.Tag, error) {
+
fields := []string{
+
"refname:short",
+
"objectname",
+
"objecttype",
+
"*objectname",
+
"*objecttype",
+
"taggername",
+
"taggeremail",
+
"taggerdate:unix",
+
"contents",
+
}
+
+
var outFormat strings.Builder
+
outFormat.WriteString("--format=")
+
for i, f := range fields {
+
if i != 0 {
+
outFormat.WriteString(fieldSeparator)
+
}
+
outFormat.WriteString(fmt.Sprintf("%%(%s)", f))
+
}
+
outFormat.WriteString("")
+
outFormat.WriteString(recordSeparator)
+
+
output, err := g.forEachRef(outFormat.String(), "refs/tags")
+
if err != nil {
+
return nil, fmt.Errorf("failed to get tags: %w", err)
+
}
+
+
records := strings.Split(strings.TrimSpace(string(output)), recordSeparator)
+
if len(records) == 1 && records[0] == "" {
+
return nil, nil
+
}
+
+
tags := make([]object.Tag, 0, len(records))
+
+
for _, line := range records {
+
parts := strings.SplitN(strings.TrimSpace(line), fieldSeparator, len(fields))
+
if len(parts) < 6 {
+
continue
+
}
+
+
tagName := parts[0]
+
objectHash := parts[1]
+
objectType := parts[2]
+
targetHash := parts[3] // dereferenced object hash (empty for lightweight tags)
+
// targetType := parts[4] // dereferenced object type (empty for lightweight tags)
+
taggerName := parts[5]
+
taggerEmail := parts[6]
+
taggerDate := parts[7]
+
message := parts[8]
+
+
// parse creation time
+
var createdAt time.Time
+
if unix, err := strconv.ParseInt(taggerDate, 10, 64); err == nil {
+
createdAt = time.Unix(unix, 0)
+
}
+
+
// parse object type
+
typ, err := plumbing.ParseObjectType(objectType)
+
if err != nil {
+
return nil, err
+
}
+
+
// strip email separators
+
taggerEmail = strings.TrimSuffix(strings.TrimPrefix(taggerEmail, "<"), ">")
+
+
tag := object.Tag{
+
Hash: plumbing.NewHash(objectHash),
+
Name: tagName,
+
Tagger: object.Signature{
+
Name: taggerName,
+
Email: taggerEmail,
+
When: createdAt,
+
},
+
Message: message,
+
TargetType: typ,
+
Target: plumbing.NewHash(targetHash),
+
}
+
+
tags = append(tags, tag)
+
}
+
+
slices.Reverse(tags)
+
return tags, nil
+
}
+19 -11
knotserver/routes.go
···
total int
branches []types.Branch
files []types.NiceTree
-
tags []*git.TagReference
)
var wg sync.WaitGroup
···
rtags := []*types.TagReference{}
for _, tag := range tags {
tr := types.TagReference{
-
Tag: tag.TagObject(),
}
tr.Reference = types.Reference{
-
Name: tag.Name(),
-
Hash: tag.Hash().String(),
}
-
if tag.Message() != "" {
-
tr.Message = tag.Message()
}
rtags = append(rtags, &tr)
···
rtags := []*types.TagReference{}
for _, tag := range tags {
tr := types.TagReference{
-
Tag: tag.TagObject(),
}
tr.Reference = types.Reference{
-
Name: tag.Name(),
-
Hash: tag.Hash().String(),
}
-
if tag.Message() != "" {
-
tr.Message = tag.Message()
}
rtags = append(rtags, &tr)
···
total int
branches []types.Branch
files []types.NiceTree
+
tags []object.Tag
)
var wg sync.WaitGroup
···
rtags := []*types.TagReference{}
for _, tag := range tags {
+
var target *object.Tag
+
if tag.Target != plumbing.ZeroHash {
+
target = &tag
+
}
tr := types.TagReference{
+
Tag: target,
}
tr.Reference = types.Reference{
+
Name: tag.Name,
+
Hash: tag.Hash.String(),
}
+
if tag.Message != "" {
+
tr.Message = tag.Message
}
rtags = append(rtags, &tr)
···
rtags := []*types.TagReference{}
for _, tag := range tags {
+
var target *object.Tag
+
if tag.Target != plumbing.ZeroHash {
+
target = &tag
+
}
tr := types.TagReference{
+
Tag: target,
}
tr.Reference = types.Reference{
+
Name: tag.Name,
+
Hash: tag.Hash.String(),
}
+
if tag.Message != "" {
+
tr.Message = tag.Message
}
rtags = append(rtags, &tr)