cerrado @ c7a8aa113a914e70e027fea93265c7232b865b5e

  1package git
  2
  3import (
  4	"bytes"
  5	"log/slog"
  6	"net/http"
  7	"path/filepath"
  8
  9	"git.gabrielgio.me/cerrado/pkg/ext"
 10	"git.gabrielgio.me/cerrado/pkg/service"
 11	"git.gabrielgio.me/cerrado/templates"
 12	"github.com/alecthomas/chroma/v2"
 13	"github.com/alecthomas/chroma/v2/formatters/html"
 14	"github.com/alecthomas/chroma/v2/lexers"
 15	"github.com/alecthomas/chroma/v2/styles"
 16	"github.com/go-git/go-git/v5/plumbing"
 17	"github.com/go-git/go-git/v5/plumbing/object"
 18)
 19
 20type (
 21	GitHandler struct {
 22		gitService gitService
 23	}
 24
 25	gitService interface {
 26		ListRepositories() ([]*service.Repository, error)
 27		ListCommits(name string, ref string) ([]*object.Commit, error)
 28		GetHead(name string) (*plumbing.Reference, error)
 29		GetTree(name, ref, path string) (*object.Tree, error)
 30		GetFileContent(name, ref, path string) (string, error)
 31		ListTags(name string) ([]*object.Tag, error)
 32		ListBranches(name string) ([]*plumbing.Reference, error)
 33	}
 34)
 35
 36func NewGitHandler(gitService gitService) *GitHandler {
 37	return &GitHandler{
 38		gitService: gitService,
 39	}
 40}
 41
 42func (g *GitHandler) List(w http.ResponseWriter, _ *http.Request) {
 43	repos, err := g.gitService.ListRepositories()
 44	if err != nil {
 45		slog.Error("Error listing repo", "error", err)
 46		return
 47	}
 48
 49	gitList := &templates.GitListPage{repos}
 50	templates.WritePageTemplate(w, gitList)
 51}
 52
 53func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) {
 54	ext.SetHTML(w)
 55	name := r.PathValue("name")
 56	ref, err := g.gitService.GetHead(name)
 57	if err != nil {
 58		slog.Error("Error loading head", "error", err)
 59		return
 60	}
 61
 62	gitList := &templates.GitItemPage{
 63		Name:        name,
 64		Ref:         ref.Name().Short(),
 65		GitItemBase: &templates.GitItemSummaryPage{},
 66	}
 67	templates.WritePageTemplate(w, gitList)
 68}
 69
 70func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) {
 71	ext.SetHTML(w)
 72	name := r.PathValue("name")
 73	ref, err := g.gitService.GetHead(name)
 74	if err != nil {
 75		slog.Error("Error loading head", "error", err)
 76		return
 77	}
 78	gitList := &templates.GitItemPage{
 79		Name:        name,
 80		Ref:         ref.Name().Short(),
 81		GitItemBase: &templates.GitItemAboutPage{},
 82	}
 83	templates.WritePageTemplate(w, gitList)
 84}
 85
 86func (g *GitHandler) Refs(w http.ResponseWriter, r *http.Request) {
 87	ext.SetHTML(w)
 88	name := r.PathValue("name")
 89
 90	tags, err := g.gitService.ListTags(name)
 91	if err != nil {
 92		slog.Error("Error loading tags", "error", err)
 93		return
 94	}
 95
 96	branches, err := g.gitService.ListBranches(name)
 97	if err != nil {
 98		slog.Error("Error loading branches", "error", err)
 99		return
100	}
101
102	ref, err := g.gitService.GetHead(name)
103	if err != nil {
104		slog.Error("Error loading head", "error", err)
105		return
106	}
107
108	gitList := &templates.GitItemPage{
109		Name: name,
110		Ref:  ref.Name().Short(),
111		GitItemBase: &templates.GitItemRefsPage{
112			Tags:     tags,
113			Branches: branches,
114		},
115	}
116	templates.WritePageTemplate(w, gitList)
117}
118
119func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) {
120	ext.SetHTML(w)
121	name := r.PathValue("name")
122	ref := r.PathValue("ref")
123	rest := r.PathValue("rest")
124
125	tree, err := g.gitService.GetTree(name, ref, rest)
126	if err != nil {
127		slog.Error("Error loading tree", "error", err)
128		return
129	}
130
131	gitList := &templates.GitItemPage{
132		Name: name,
133		Ref:  ref,
134		GitItemBase: &templates.GitItemTreePage{
135			CurrentPath: rest,
136			Tree:        tree,
137			Ref:         ref,
138			Name:        name,
139		},
140	}
141	templates.WritePageTemplate(w, gitList)
142}
143
144func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) {
145	ext.SetHTML(w)
146	name := r.PathValue("name")
147	ref := r.PathValue("ref")
148	rest := r.PathValue("rest")
149
150	file, err := g.gitService.GetFileContent(name, ref, rest)
151	if err != nil {
152		slog.Error("Error loading blob", "error", err)
153		return
154	}
155
156	filename := filepath.Base(rest)
157	lexer := GetLexers(filename)
158	style := styles.Get("xcode")
159	formatter := html.New(
160		html.WithLineNumbers(true),
161	)
162	iterator, err := lexer.Tokenise(nil, file)
163	if err != nil {
164		slog.Error("Error tokenise", "error", err)
165		return
166	}
167
168	var code bytes.Buffer
169	err = formatter.Format(&code, style, iterator)
170	if err != nil {
171		slog.Error("Error format", "error", err)
172		return
173	}
174
175	gitList := &templates.GitItemPage{
176		Name: name,
177		Ref:  ref,
178		GitItemBase: &templates.GitItemBlobPage{
179			File:    rest,
180			Content: code.Bytes(),
181		},
182	}
183	templates.WritePageTemplate(w, gitList)
184}
185
186func (g *GitHandler) Log(w http.ResponseWriter, r *http.Request) {
187	ext.SetHTML(w)
188	name := r.PathValue("name")
189	ref := r.PathValue("ref")
190
191	commits, err := g.gitService.ListCommits(name, ref)
192	if err != nil {
193		slog.Error("Error loading commits", "error", err)
194		return
195	}
196
197	gitList := &templates.GitItemPage{
198		Name: name,
199		Ref:  ref,
200		GitItemBase: &templates.GitItemLogPage{
201			Commits: commits,
202		},
203	}
204	templates.WritePageTemplate(w, gitList)
205}
206
207func GetLexers(filename string) chroma.Lexer {
208	if filename == "APKBUILD" {
209		return lexers.Get("sh")
210	}
211
212	lexer := lexers.Get(filename)
213
214	if lexer == nil {
215		lexer = lexers.Get("txt")
216	}
217	return lexer
218}