routes/util.go (view raw)
1package routes
2
3import (
4 "context"
5 "io/fs"
6 "log"
7 "os"
8 "path/filepath"
9 "sort"
10 "strings"
11
12 "git.icyphox.sh/legit/git"
13 "github.com/alexedwards/flow"
14 "github.com/dustin/go-humanize"
15)
16
17func isGoModule(gr *git.GitRepo) bool {
18 _, err := gr.FileContent("go.mod")
19 return err == nil
20}
21
22func getDescription(path string) (desc string) {
23 db, err := os.ReadFile(filepath.Join(path, "description"))
24 if err == nil {
25 desc = string(db)
26 } else {
27 desc = ""
28 }
29 return
30}
31
32func (d *deps) isIgnored(name string) bool {
33 for _, i := range d.c.Repo.Ignore {
34 if name == i {
35 return true
36 }
37 }
38
39 return false
40}
41
42type repository struct {
43 Name string
44 Category string
45 Path string
46 Slug string
47 Description string
48 LastCommit string
49}
50
51type entry struct {
52 Name string
53 Repositories []*repository
54}
55
56type entries struct {
57 Children []*entry
58 c map[string]*entry
59}
60
61func (ent *entries) Add(r repository) {
62 if r.Category == "" {
63 ent.Children = append(ent.Children, &entry{
64 Name: r.Name,
65 Repositories: []*repository{&r},
66 })
67 return
68 }
69 t, ok := ent.c[r.Category]
70 if !ok {
71 t := &entry{
72 Name: r.Category,
73 Repositories: []*repository{&r},
74 }
75 ent.c[r.Category] = t
76 ent.Children = append(ent.Children, t)
77 return
78 }
79 t.Repositories = append(t.Repositories, &r)
80}
81
82func (d *deps) getAllRepos() (*entries, error) {
83 entries := &entries{
84 Children: []*entry{},
85 c: map[string]*entry{},
86 }
87 max := strings.Count(d.c.Repo.ScanPath, string(os.PathSeparator)) + 2
88
89 err := filepath.WalkDir(d.c.Repo.ScanPath, func(path string, de fs.DirEntry, err error) error {
90 if err != nil {
91 return err
92 }
93
94 if de.IsDir() {
95 // Check if we've exceeded our recursion depth
96 if strings.Count(path, string(os.PathSeparator)) > max {
97 return fs.SkipDir
98 }
99
100 if d.isIgnored(path) {
101 return fs.SkipDir
102 }
103
104 // A bare repo should always have at least a HEAD file, if it
105 // doesn't we can continue recursing
106 if _, err := os.Lstat(filepath.Join(path, "HEAD")); err == nil {
107 repo, err := git.Open(path, "")
108 if err != nil {
109 log.Println(err)
110 } else {
111 relpath, _ := filepath.Rel(d.c.Repo.ScanPath, path)
112 category := strings.Split(relpath, string(os.PathSeparator))[0]
113 r := repository{
114 Name: filepath.Base(path),
115 Category: category,
116 Path: path,
117 Slug: relpath,
118 Description: getDescription(path),
119 }
120 if c, err := repo.LastCommit(); err == nil {
121 r.LastCommit = humanize.Time(c.Author.When)
122 }
123 entries.Add(r)
124 // Since we found a Git repo, we don't want to recurse
125 // further
126 return fs.SkipDir
127 }
128 }
129 }
130 return nil
131 })
132 sort.Slice(entries.Children, func(i, j int) bool {
133 return entries.Children[i].Name < entries.Children[j].Name
134 })
135 return entries, err
136}
137
138func repoPath(ctx context.Context) string {
139 return filepath.Join(
140 filepath.Clean(flow.Param(ctx, "category")),
141 filepath.Clean(flow.Param(ctx, "name")),
142 )
143}