Monorepo for Tangled tangled.org

knotserver/git: refactor GitRepo.Branches to use `git for-each-ref`

Signed-off-by: oppiliappan <me@oppi.li>

Changed files
+112 -34
knotserver
+112
knotserver/git/branch.go
··· 1 + package git 2 + 3 + import ( 4 + "fmt" 5 + "slices" 6 + "strconv" 7 + "strings" 8 + "time" 9 + 10 + "github.com/go-git/go-git/v5/plumbing" 11 + "github.com/go-git/go-git/v5/plumbing/object" 12 + "tangled.sh/tangled.sh/core/types" 13 + ) 14 + 15 + func (g *GitRepo) Branches() ([]types.Branch, error) { 16 + fields := []string{ 17 + "refname:short", 18 + "objectname", 19 + "authorname", 20 + "authoremail", 21 + "authordate:unix", 22 + "committername", 23 + "committeremail", 24 + "committerdate:unix", 25 + "tree", 26 + "parent", 27 + "contents", 28 + } 29 + 30 + var outFormat strings.Builder 31 + outFormat.WriteString("--format=") 32 + for i, f := range fields { 33 + if i != 0 { 34 + outFormat.WriteString(fieldSeparator) 35 + } 36 + outFormat.WriteString(fmt.Sprintf("%%(%s)", f)) 37 + } 38 + outFormat.WriteString("") 39 + outFormat.WriteString(recordSeparator) 40 + 41 + output, err := g.forEachRef(outFormat.String(), "refs/heads") 42 + if err != nil { 43 + return nil, fmt.Errorf("failed to get branches: %w", err) 44 + } 45 + 46 + records := strings.Split(strings.TrimSpace(string(output)), recordSeparator) 47 + if len(records) == 1 && records[0] == "" { 48 + return nil, nil 49 + } 50 + 51 + branches := make([]types.Branch, 0, len(records)) 52 + 53 + // ignore errors here 54 + defaultBranch, _ := g.FindMainBranch() 55 + 56 + for _, line := range records { 57 + parts := strings.SplitN(strings.TrimSpace(line), fieldSeparator, len(fields)) 58 + if len(parts) < 6 { 59 + continue 60 + } 61 + 62 + branchName := parts[0] 63 + commitHash := plumbing.NewHash(parts[1]) 64 + authorName := parts[2] 65 + authorEmail := strings.TrimSuffix(strings.TrimPrefix(parts[3], "<"), ">") 66 + authorDate := parts[4] 67 + committerName := parts[5] 68 + committerEmail := strings.TrimSuffix(strings.TrimPrefix(parts[6], "<"), ">") 69 + committerDate := parts[7] 70 + treeHash := plumbing.NewHash(parts[8]) 71 + parentHash := plumbing.NewHash(parts[9]) 72 + message := parts[10] 73 + 74 + // parse creation time 75 + var authoredAt, committedAt time.Time 76 + if unix, err := strconv.ParseInt(authorDate, 10, 64); err == nil { 77 + authoredAt = time.Unix(unix, 0) 78 + } 79 + if unix, err := strconv.ParseInt(committerDate, 10, 64); err == nil { 80 + committedAt = time.Unix(unix, 0) 81 + } 82 + 83 + branch := types.Branch{ 84 + IsDefault: branchName == defaultBranch, 85 + Reference: types.Reference{ 86 + Name: branchName, 87 + Hash: commitHash.String(), 88 + }, 89 + Commit: &object.Commit{ 90 + Hash: commitHash, 91 + Author: object.Signature{ 92 + Name: authorName, 93 + Email: authorEmail, 94 + When: authoredAt, 95 + }, 96 + Committer: object.Signature{ 97 + Name: committerName, 98 + Email: committerEmail, 99 + When: committedAt, 100 + }, 101 + TreeHash: treeHash, 102 + ParentHashes: []plumbing.Hash{parentHash}, 103 + Message: message, 104 + }, 105 + } 106 + 107 + branches = append(branches, branch) 108 + } 109 + 110 + slices.Reverse(branches) 111 + return branches, nil 112 + }
-34
knotserver/git/git.go
··· 14 14 "github.com/go-git/go-git/v5" 15 15 "github.com/go-git/go-git/v5/plumbing" 16 16 "github.com/go-git/go-git/v5/plumbing/object" 17 - "tangled.sh/tangled.sh/core/types" 18 17 ) 19 18 20 19 var ( ··· 262 261 defer reader.Close() 263 262 264 263 return io.ReadAll(reader) 265 - } 266 - 267 - func (g *GitRepo) Branches() ([]types.Branch, error) { 268 - bi, err := g.r.Branches() 269 - if err != nil { 270 - return nil, fmt.Errorf("branchs: %w", err) 271 - } 272 - 273 - branches := []types.Branch{} 274 - 275 - defaultBranch, err := g.FindMainBranch() 276 - 277 - _ = bi.ForEach(func(ref *plumbing.Reference) error { 278 - b := types.Branch{} 279 - b.Hash = ref.Hash().String() 280 - b.Name = ref.Name().Short() 281 - 282 - // resolve commit that this branch points to 283 - commit, _ := g.Commit(ref.Hash()) 284 - if commit != nil { 285 - b.Commit = commit 286 - } 287 - 288 - if defaultBranch != "" && defaultBranch == b.Name { 289 - b.IsDefault = true 290 - } 291 - 292 - branches = append(branches, b) 293 - 294 - return nil 295 - }) 296 - 297 - return branches, nil 298 264 } 299 265 300 266 func (g *GitRepo) Branch(name string) (*plumbing.Reference, error) {