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				rf, err := c.File("README.md")
 92				if err == nil {
 93					rmd, err := rf.Contents()
 94					if err == nil {
 95						r.Readme = rmd
 96					}
 97				}
 98			}
 99			rs.commits = append(rs.commits, RepoCommit{Name: rn, Commit: c})
100			return nil
101		})
102		sort.Sort(rs.commits)
103		rs.repos = append(rs.repos, r)
104	}
105}