all repos — elgit @ 487ebd62dd4784d7510f166d54b71aa64fce15a0

fork of legit: web frontend for git, written in go

routes/util.go (view raw)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package routes

import (
	"bytes"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"slices"
	"strings"

	securejoin "github.com/cyphar/filepath-securejoin"
	"github.com/dimfeld/httptreemux/v5"
	"go.alanpearce.eu/elgit/config"
	"go.alanpearce.eu/elgit/data"
	"go.alanpearce.eu/elgit/git"
)

func isGoModule(gr *git.GitRepo) bool {
	_, err := gr.FileContent("go.mod")
	return err == nil
}

func getDisplayName(name string) string {
	return strings.TrimSuffix(name, ".git")
}

func getDescription(path string) (desc string) {
	db, err := os.ReadFile(filepath.Join(path, "description"))
	if err == nil {
		desc = string(db)
	} else {
		desc = ""
	}
	return
}

func (d *deps) isUnlisted(name string) bool {
	return slices.Contains(d.c.Repo.Unlisted, name)
}

func (d *deps) isNotAllowed(name string) bool {
	return !slices.Contains(d.projects, name)
}

func (d *deps) GetCleanPath(name string) (string, error) {
	return securejoin.SecureJoin(
		filepath.Join(d.c.Repo.Root, "repositories"),
		httptreemux.Clean(name)+".git",
	)
}

func ReadProjectsList(c *config.Config) ([]string, error) {
	content, err := os.ReadFile(filepath.Join(c.Repo.Root, "projects.list"))
	if err != nil {
		return nil, err
	}
	lines := bytes.SplitSeq(content, []byte("\n"))

	projects := []string{}
	for line := range lines {
		projects = append(projects, strings.TrimSuffix(string(line), ".git"))
	}

	return projects, nil
}

func (d *deps) getAllRepos() *data.Entries {
	entries := &data.Entries{
		Children: []*data.Entry{},
		Map:      map[string]*data.Entry{},
	}

	for _, project := range d.projects {
		if project == "" || d.isUnlisted(project) {
			continue
		}
		fullPath := filepath.Join(d.c.Repo.Root, "repositories", project+".git")

		// A bare repo should always have at least a HEAD file
		if _, err := os.Lstat(filepath.Join(fullPath, "HEAD")); err == nil {
			repo, err := git.Open(fullPath, "")
			if err != nil {
				log.Println(err)
			} else {
				category, name, found := strings.Cut(project, string(os.PathSeparator))
				if !found {
					category = ""
					name = project
				}
				r := data.Repository{
					Name:        name,
					Category:    category,
					Path:        fullPath,
					Slug:        project,
					Description: getDescription(fullPath),
				}
				if cc, err := repo.LastCommit(); err == nil {
					r.LastCommit = cc.Author.When
				}
				entries.Add(r)
			}
		}
	}

	entries.Sort()

	return entries
}

func setContentDisposition(w http.ResponseWriter, name string) {
	h := "inline; filename=\"" + name + "\""
	w.Header().Add("Content-Disposition", h)
}

func setGZipMIME(w http.ResponseWriter) {
	setMIME(w, "application/gzip")
}

func setMIME(w http.ResponseWriter, mime string) {
	w.Header().Add("Content-Type", mime)
}