git.go

 1package tui
 2
 3import (
 4	"log"
 5	"os"
 6	"sort"
 7	"sync"
 8	"time"
 9
10	"github.com/go-git/go-git/v5"
11	"github.com/go-git/go-git/v5/plumbing/object"
12)
13
14type commitLog []*object.Commit
15
16func (cl commitLog) Len() int           { return len(cl) }
17func (cl commitLog) Swap(i, j int)      { cl[i], cl[j] = cl[j], cl[i] }
18func (cl commitLog) Less(i, j int) bool { return cl[i].Author.When.After(cl[j].Author.When) }
19
20type repoSource struct {
21	mtx     sync.Mutex
22	path    string
23	repos   []*git.Repository
24	commits commitLog
25}
26
27func newRepoSource(repoPath string) *repoSource {
28	rs := &repoSource{path: repoPath}
29	go func() {
30		for {
31			rs.loadRepos()
32			time.Sleep(time.Second * 10)
33		}
34	}()
35	return rs
36}
37
38func (rs *repoSource) allRepos() []*git.Repository {
39	rs.mtx.Lock()
40	defer rs.mtx.Unlock()
41	return rs.repos
42}
43
44func (rs *repoSource) getCommits(limit int) []*object.Commit {
45	rs.mtx.Lock()
46	defer rs.mtx.Unlock()
47	if limit > len(rs.commits) {
48		limit = len(rs.commits)
49	}
50	return rs.commits[:limit]
51}
52
53func (rs *repoSource) loadRepos() {
54	rs.mtx.Lock()
55	defer rs.mtx.Unlock()
56	rd, err := os.ReadDir(rs.path)
57	if err != nil {
58		return
59	}
60	rs.repos = make([]*git.Repository, 0)
61	rs.commits = make([]*object.Commit, 0)
62	for _, rd := range rd {
63		r, err := git.PlainOpen(rs.path + string(os.PathSeparator) + rd.Name())
64		if err != nil {
65			log.Fatal(err)
66		}
67		l, err := r.Log(&git.LogOptions{All: true})
68		if err != nil {
69			log.Fatal(err)
70		}
71		l.ForEach(func(c *object.Commit) error {
72			rs.commits = append(rs.commits, c)
73			return nil
74		})
75		sort.Sort(rs.commits)
76		rs.repos = append(rs.repos, r)
77	}
78}