cerrado @ e9098e00fb6339b759df5b0df2e086cef8a7ce83

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