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}