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