routes/util.go (view raw)
1package routes
2
3import (
4 "io/fs"
5 "log"
6 "net/http"
7 "os"
8 "path/filepath"
9 "strings"
10
11 "git.icyphox.sh/legit/git"
12)
13
14func isGoModule(gr *git.GitRepo) bool {
15 _, err := gr.FileContent("go.mod")
16 return err == nil
17}
18
19func getDisplayName(name string) string {
20 return strings.TrimSuffix(name, ".git")
21}
22
23func getDescription(path string) (desc string) {
24 db, err := os.ReadFile(filepath.Join(path, "description"))
25 if err == nil {
26 desc = string(db)
27 } else {
28 desc = ""
29 }
30 return
31}
32
33func (d *deps) isUnlisted(name string) bool {
34 for _, i := range d.c.Repo.Unlisted {
35 if name == i {
36 return true
37 }
38 }
39
40 return false
41}
42
43func (d *deps) isIgnored(name string) bool {
44 for _, i := range d.c.Repo.Ignore {
45 if name == i {
46 return true
47 }
48 }
49
50 return false
51}
52
53type repoInfo struct {
54 Git *git.GitRepo
55 Path string
56 Category string
57}
58
59func (d *deps) getAllRepos() ([]repoInfo, error) {
60 repos := []repoInfo{}
61 seen := map[string]bool{}
62 max := strings.Count(d.c.Repo.ScanPath, string(os.PathSeparator)) + 2
63
64 err := filepath.WalkDir(d.c.Repo.ScanPath, func(path string, de fs.DirEntry, err error) error {
65 if err != nil {
66 return err
67 }
68
69 if de.IsDir() {
70 // Check if we've exceeded our recursion depth
71 if strings.Count(path, string(os.PathSeparator)) > max {
72 return fs.SkipDir
73 }
74
75 if d.isIgnored(path) {
76 return fs.SkipDir
77 }
78
79 // A bare repo should always have at least a HEAD file, if it
80 // doesn't we can continue recursing
81 if _, err := os.Lstat(filepath.Join(path, "HEAD")); err == nil {
82 repo, err := git.Open(path, "")
83 if err != nil {
84 log.Println(err)
85 } else {
86 relpath, _ := filepath.Rel(d.c.Repo.ScanPath, path)
87 repos = append(repos, repoInfo{
88 Git: repo,
89 Path: relpath,
90 Category: d.category(path),
91 })
92 // Since we found a Git repo, we don't want to recurse
93 // further
94 return fs.SkipDir
95 }
96 }
97 } else if de.Type()&fs.ModeSymlink != 0 {
98 if d.isIgnored(path) {
99 return nil
100 }
101
102 target, err := filepath.EvalSymlinks(path)
103 if err != nil {
104 log.Printf("failed to resolve symlink %s: %v", path, err)
105 return nil
106 }
107
108 // Avoid duplicates if multiple symlinks point to the same target
109 if seen[target] {
110 return nil
111 }
112 seen[target] = true
113
114 if _, err := os.Stat(filepath.Join(target, "HEAD")); err == nil {
115 repo, err := git.Open(target, "")
116 if err != nil {
117 log.Println(err)
118 } else {
119 relpath, _ := filepath.Rel(d.c.Repo.ScanPath, path)
120 repos = append(repos, repoInfo{
121 Git: repo,
122 Path: relpath,
123 Category: d.category(path),
124 })
125 }
126 }
127 }
128 return nil
129 })
130
131 return repos, err
132}
133
134func (d *deps) category(path string) string {
135 return strings.TrimPrefix(filepath.Dir(strings.TrimPrefix(path, d.c.Repo.ScanPath)), string(os.PathSeparator))
136}
137
138func setContentDisposition(w http.ResponseWriter, name string) {
139 h := "inline; filename=\"" + name + "\""
140 w.Header().Add("Content-Disposition", h)
141}
142
143func setGZipMIME(w http.ResponseWriter) {
144 setMIME(w, "application/gzip")
145}
146
147func setMIME(w http.ResponseWriter, mime string) {
148 w.Header().Add("Content-Type", mime)
149}