cerrado @ v0.0.4

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