git.go

 1package git
 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 RepoCommit struct {
15	Name   string
16	Repo   *git.Repository
17	Commit *object.Commit
18}
19
20type CommitLog []RepoCommit
21
22func (cl CommitLog) Len() int      { return len(cl) }
23func (cl CommitLog) Swap(i, j int) { cl[i], cl[j] = cl[j], cl[i] }
24func (cl CommitLog) Less(i, j int) bool {
25	return cl[i].Commit.Author.When.After(cl[j].Commit.Author.When)
26}
27
28type RepoSource struct {
29	mtx     sync.Mutex
30	path    string
31	repos   []*git.Repository
32	commits CommitLog
33}
34
35func NewRepoSource(repoPath string) *RepoSource {
36	rs := &RepoSource{path: repoPath}
37	go func() {
38		for {
39			rs.loadRepos()
40			time.Sleep(time.Second * 10)
41		}
42	}()
43	return rs
44}
45
46func (rs *RepoSource) AllRepos() []*git.Repository {
47	rs.mtx.Lock()
48	defer rs.mtx.Unlock()
49	return rs.repos
50}
51
52func (rs *RepoSource) GetCommits(limit int) []RepoCommit {
53	rs.mtx.Lock()
54	defer rs.mtx.Unlock()
55	if limit > len(rs.commits) {
56		limit = len(rs.commits)
57	}
58	return rs.commits[:limit]
59}
60
61func (rs *RepoSource) loadRepos() {
62	rs.mtx.Lock()
63	defer rs.mtx.Unlock()
64	rd, err := os.ReadDir(rs.path)
65	if err != nil {
66		return
67	}
68	rs.repos = make([]*git.Repository, 0)
69	rs.commits = make([]RepoCommit, 0)
70	for _, rd := range rd {
71		r, err := git.PlainOpen(rs.path + string(os.PathSeparator) + rd.Name())
72		if err != nil {
73			log.Fatal(err)
74		}
75		l, err := r.Log(&git.LogOptions{All: true})
76		if err != nil {
77			log.Fatal(err)
78		}
79		l.ForEach(func(c *object.Commit) error {
80			rs.commits = append(rs.commits, RepoCommit{Name: rd.Name(), Repo: r, Commit: c})
81			return nil
82		})
83		sort.Sort(rs.commits)
84		rs.repos = append(rs.repos, r)
85	}
86}