diff options
Diffstat (limited to 'pkg/handler/git/handler.go')
-rw-r--r-- | pkg/handler/git/handler.go | 193 |
1 files changed, 165 insertions, 28 deletions
diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go index 40fae24..cb202a2 100644 --- a/pkg/handler/git/handler.go +++ b/pkg/handler/git/handler.go @@ -2,6 +2,7 @@ package git import ( "bytes" + "compress/gzip" "errors" "fmt" "io" @@ -9,10 +10,13 @@ import ( "net/http" "os" "path/filepath" + "sort" "strings" + "git.gabrielgio.me/cerrado/pkg/config" "git.gabrielgio.me/cerrado/pkg/ext" "git.gabrielgio.me/cerrado/pkg/service" + "git.gabrielgio.me/cerrado/pkg/u" "git.gabrielgio.me/cerrado/templates" "github.com/alecthomas/chroma/v2" "github.com/alecthomas/chroma/v2/formatters/html" @@ -27,28 +31,38 @@ import ( type ( GitHandler struct { gitService *service.GitService - readmePath string + config configurationRepository } configurationRepository interface { GetRootReadme() string + GetSyntaxHighlight() string + GetOrderBy() config.OrderBy } ) func NewGitHandler(gitService *service.GitService, confRepo configurationRepository) *GitHandler { return &GitHandler{ gitService: gitService, - readmePath: confRepo.GetRootReadme(), + config: confRepo, } } -func (g *GitHandler) List(w http.ResponseWriter, _ *http.Request) error { +func (g *GitHandler) List(w http.ResponseWriter, r *ext.Request) error { + // this is the only handler that needs to handle authentication itself. + // everything else relay on name path parameter + logged := ext.IsLoggedIn(r.Context()) + repos, err := g.gitService.ListRepositories() if err != nil { return err } - f, err := os.Open(g.readmePath) + if !logged { + repos = u.Filter(repos, isPublic) + } + + f, err := os.Open(g.config.GetRootReadme()) if err != nil { return err } @@ -69,14 +83,14 @@ func (g *GitHandler) List(w http.ResponseWriter, _ *http.Request) error { bs = markdown.Render(doc, renderer) gitList := &templates.GitListPage{ - Respositories: repos, + Respositories: orderBy(repos, g.config.GetOrderBy()), About: bs, } - templates.WritePageTemplate(w, gitList) + templates.WritePageTemplate(w, gitList, r.Context()) return nil } -func (g *GitHandler) Archive(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) Archive(w http.ResponseWriter, r *ext.Request) error { ext.SetGZip(w) name := r.PathValue("name") file := r.PathValue("file") @@ -84,7 +98,7 @@ func (g *GitHandler) Archive(w http.ResponseWriter, r *http.Request) error { // TODO: remove it once we can support more than gzip if !strings.HasSuffix(file, ".tar.gz") { - ext.NotFound(w) + ext.NotFound(w, r) return nil } @@ -102,7 +116,51 @@ func (g *GitHandler) Archive(w http.ResponseWriter, r *http.Request) error { return nil } -func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) Multiplex(w http.ResponseWriter, r *ext.Request) error { + path := r.PathValue("rest") + name := r.PathValue("name") + + if r.URL.RawQuery == "service=git-receive-pack" { + ext.BadRequest(w, r, "no pushing allowed") + return nil + } + + if path == "info/refs" && r.URL.RawQuery == "service=git-upload-pack" && r.Method == "GET" { + w.Header().Set("content-type", "application/x-git-upload-pack-advertisement") + + err := g.gitService.WriteInfoRefs(r.Context(), name, w) + if err != nil { + slog.Error("Error WriteInfoRefs", "error", err) + } + } else if path == "git-upload-pack" && r.Method == "POST" { + w.Header().Set("content-type", "application/x-git-upload-pack-result") + w.Header().Set("Connection", "Keep-Alive") + w.Header().Set("Transfer-Encoding", "chunked") + w.WriteHeader(http.StatusOK) + + reader := r.Body + + if r.Header.Get("Content-Encoding") == "gzip" { + var err error + reader, err = gzip.NewReader(r.Body) + if err != nil { + return err + } + defer reader.Close() + } + + err := g.gitService.WriteUploadPack(r.Context(), name, reader, w) + if err != nil { + slog.Error("Error WriteUploadPack", "error", err) + } + } else if r.Method == "GET" { + return g.Summary(w, r) + } + + return nil +} + +func (g *GitHandler) Summary(w http.ResponseWriter, r *ext.Request) error { ext.SetHTML(w) name := r.PathValue("name") ref, err := g.gitService.GetHead(name) @@ -120,11 +178,15 @@ func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) error { return err } - commits, err := g.gitService.ListCommits(name, "", 10) + commits, _, err := g.gitService.ListCommits(name, "", "", 10) if err != nil { return err } + if len(tags) > 3 { + tags = tags[:3] + } + gitList := &templates.GitItemPage{ Name: name, Ref: ref.Name().Short(), @@ -134,11 +196,11 @@ func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) error { Commits: commits, }, } - templates.WritePageTemplate(w, gitList) + templates.WritePageTemplate(w, gitList, r.Context()) return nil } -func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) About(w http.ResponseWriter, r *ext.Request) error { ext.SetHTML(w) name := r.PathValue("name") ref, err := g.gitService.GetHead(name) @@ -154,7 +216,7 @@ func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) error { GitItemBase: &templates.GitItemAboutPage{ About: []byte("About file not configured properly"), }, - }) + }, r.Context()) return nil } if err != nil { @@ -178,11 +240,11 @@ func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) error { About: bs, }, } - templates.WritePageTemplate(w, gitList) + templates.WritePageTemplate(w, gitList, r.Context()) return nil } -func (g *GitHandler) Refs(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) Refs(w http.ResponseWriter, r *ext.Request) error { ext.SetHTML(w) name := r.PathValue("name") @@ -209,11 +271,11 @@ func (g *GitHandler) Refs(w http.ResponseWriter, r *http.Request) error { Branches: branches, }, } - templates.WritePageTemplate(w, gitList) + templates.WritePageTemplate(w, gitList, r.Context()) return nil } -func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) Tree(w http.ResponseWriter, r *ext.Request) error { ext.SetHTML(w) name := r.PathValue("name") ref := r.PathValue("ref") @@ -238,11 +300,11 @@ func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) error { Tree: tree, }, } - templates.WritePageTemplate(w, gitList) + templates.WritePageTemplate(w, gitList, r.Context()) return nil } -func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) Blob(w http.ResponseWriter, r *ext.Request) error { ext.SetHTML(w) name := r.PathValue("name") ref := r.PathValue("ref") @@ -269,7 +331,7 @@ func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) error { Content: []byte("Binary file"), }, } - templates.WritePageTemplate(w, gitList) + templates.WritePageTemplate(w, gitList, r.Context()) return nil } @@ -280,7 +342,8 @@ func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) error { filename := filepath.Base(rest) lexer := GetLexers(filename) - style := styles.Get("xcode") + style := styles.Get(g.config.GetSyntaxHighlight()) + formatter := html.New( html.WithLineNumbers(true), html.WithLinkableLineNumbers(true, "L"), @@ -305,16 +368,17 @@ func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) error { Content: code.Bytes(), }, } - templates.WritePageTemplate(w, gitList) + templates.WritePageTemplate(w, gitList, r.Context()) return nil } -func (g *GitHandler) Log(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) Log(w http.ResponseWriter, r *ext.Request) error { ext.SetHTML(w) name := r.PathValue("name") ref := r.PathValue("ref") + from := r.URL.Query().Get("from") - commits, err := g.gitService.ListCommits(name, ref, 1000) + commits, next, err := g.gitService.ListCommits(name, ref, from, 100) if err != nil { return err } @@ -324,13 +388,36 @@ func (g *GitHandler) Log(w http.ResponseWriter, r *http.Request) error { Ref: ref, GitItemBase: &templates.GitItemLogPage{ Commits: commits, + Next: next, + }, + } + templates.WritePageTemplate(w, gitList, r.Context()) + return nil +} + +func (g *GitHandler) Ref(w http.ResponseWriter, r *ext.Request) error { + ext.SetHTML(w) + name := r.PathValue("name") + ref := r.PathValue("ref") + + commit, tag, err := g.gitService.GetTag(ref, name) + if err != nil { + return err + } + + gitList := &templates.GitItemPage{ + Name: name, + Ref: ref, + GitItemBase: &templates.GitItemRefPage{ + Commit: commit, + Reference: tag, }, } - templates.WritePageTemplate(w, gitList) + templates.WritePageTemplate(w, gitList, r.Context()) return nil } -func (g *GitHandler) Commit(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) Commit(w http.ResponseWriter, r *ext.Request) error { ext.SetHTML(w) name := r.PathValue("name") ref := r.PathValue("ref") @@ -345,15 +432,34 @@ func (g *GitHandler) Commit(w http.ResponseWriter, r *http.Request) error { return err } + lexer := lexers.Get("diff") + style := styles.Get(g.config.GetSyntaxHighlight()) + + formatter := html.New( + html.WithLineNumbers(true), + html.WithLinkableLineNumbers(true, "L"), + ) + + iterator, err := lexer.Tokenise(nil, diff) + if err != nil { + return err + } + + var code bytes.Buffer + err = formatter.Format(&code, style, iterator) + if err != nil { + return err + } + gitList := &templates.GitItemPage{ Name: name, Ref: ref, GitItemBase: &templates.GitItemCommitPage{ Commit: commit, - Diff: diff, + Diff: code.Bytes(), }, } - templates.WritePageTemplate(w, gitList) + templates.WritePageTemplate(w, gitList, r.Context()) return nil } @@ -362,6 +468,10 @@ func GetLexers(filename string) chroma.Lexer { return lexers.Get("sh") } + if strings.HasSuffix(filename, ".qtpl") { + return lexers.Get("html") + } + lexer := lexers.Get(filename) if lexer == nil { @@ -369,3 +479,30 @@ func GetLexers(filename string) chroma.Lexer { } return lexer } + +func isPublic(r *service.Repository) bool { + return r.Public +} + +func orderBy(repos []*service.Repository, order config.OrderBy) []*service.Repository { + switch order { + case config.AlphabeticalAsc: + sort.Slice(repos, func(i, j int) bool { + return repos[i].Name < repos[j].Name + }) + case config.AlphabeticalDesc: + sort.Slice(repos, func(i, j int) bool { + return repos[i].Name > repos[j].Name + }) + case config.LastCommitAsc: + sort.Slice(repos, func(i, j int) bool { + return repos[i].LastCommit.Commit().Committer.When.Before(repos[j].LastCommit.Commit().Committer.When) + }) + case config.LastCommitDesc: + sort.Slice(repos, func(i, j int) bool { + return repos[i].LastCommit.Commit().Committer.When.After(repos[j].LastCommit.Commit().Committer.When) + }) + } + + return repos +} |