aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel A. Giovanini <mail@gabrielgio.me>2024-06-08 00:01:44 +0200
committerGabriel A. Giovanini <mail@gabrielgio.me>2024-06-08 00:01:44 +0200
commit6079b1d963f34ada5c4b25363f2319901e283936 (patch)
treef7f93616eb3dacfcebee486fe7542ec3adfb3950
parente9098e00fb6339b759df5b0df2e086cef8a7ce83 (diff)
downloadcerrado-6079b1d963f34ada5c4b25363f2319901e283936.tar.gz
cerrado-6079b1d963f34ada5c4b25363f2319901e283936.tar.bz2
cerrado-6079b1d963f34ada5c4b25363f2319901e283936.zip
feat: Add error handling
-rw-r--r--pkg/ext/compression.go2
-rw-r--r--pkg/ext/log.go53
-rw-r--r--pkg/ext/router.go72
-rw-r--r--pkg/git/git.go3
-rw-r--r--pkg/handler/about/handler.go10
-rw-r--r--pkg/handler/config/handler.go16
-rw-r--r--pkg/handler/git/handler.go61
-rw-r--r--pkg/handler/router.go36
-rw-r--r--pkg/handler/static/handler.go6
-rw-r--r--pkg/service/git.go29
-rw-r--r--templates/error.qtpl16
-rw-r--r--templates/error.qtpl.go162
-rw-r--r--templates/gititem.qtpl2
-rw-r--r--templates/gititem.qtpl.go4
14 files changed, 390 insertions, 82 deletions
diff --git a/pkg/ext/compression.go b/pkg/ext/compression.go
index 92144b8..57ad49a 100644
--- a/pkg/ext/compression.go
+++ b/pkg/ext/compression.go
@@ -24,7 +24,7 @@ type CompressionResponseWriter struct {
compressWriter io.Writer
}
-func Compress(next func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
+func Compress(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if accept, ok := r.Header["Accept-Encoding"]; ok {
if compress, algo := GetCompressionWriter(u.FirstOrZero(accept), w); algo != "" {
diff --git a/pkg/ext/log.go b/pkg/ext/log.go
new file mode 100644
index 0000000..a9d26a9
--- /dev/null
+++ b/pkg/ext/log.go
@@ -0,0 +1,53 @@
+package ext
+
+import (
+ "log/slog"
+ "net/http"
+ "time"
+)
+
+type statusWraper struct {
+ statusCode int
+ innerWriter http.ResponseWriter
+}
+
+func (s *statusWraper) Header() http.Header {
+ return s.innerWriter.Header()
+}
+
+func (s *statusWraper) Write(b []byte) (int, error) {
+ return s.innerWriter.Write(b)
+}
+
+func (s *statusWraper) WriteHeader(statusCode int) {
+ s.statusCode = statusCode
+ s.innerWriter.WriteHeader(statusCode)
+}
+
+func (s *statusWraper) StatusCode() int {
+ if s.statusCode == 0 {
+ return 200
+ }
+ return s.statusCode
+}
+
+func wrap(w http.ResponseWriter) *statusWraper {
+ return &statusWraper{
+ innerWriter: w,
+ }
+}
+
+func Log(next http.HandlerFunc) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ t := time.Now()
+ s := wrap(w)
+ next(s, r)
+ slog.Info(
+ "Http request",
+ "method", r.Method,
+ "code", s.StatusCode(),
+ "path", r.URL,
+ "elapsed", time.Since(t),
+ )
+ }
+}
diff --git a/pkg/ext/router.go b/pkg/ext/router.go
new file mode 100644
index 0000000..5d22814
--- /dev/null
+++ b/pkg/ext/router.go
@@ -0,0 +1,72 @@
+package ext
+
+import (
+ "errors"
+ "fmt"
+ "net/http"
+
+ "git.gabrielgio.me/cerrado/pkg/service"
+ "git.gabrielgio.me/cerrado/templates"
+)
+
+type (
+ Router struct {
+ middlewares []Middleware
+ router *http.ServeMux
+ }
+ Middleware func(next http.HandlerFunc) http.HandlerFunc
+ ErrorRequestHandler func(w http.ResponseWriter, r *http.Request) error
+)
+
+func NewRouter() *Router {
+ return &Router{
+ router: http.NewServeMux(),
+ }
+}
+func (r *Router) Handler() http.Handler {
+ return r.router
+}
+
+func (r *Router) AddMiddleware(middleware Middleware) {
+ r.middlewares = append(r.middlewares, middleware)
+}
+
+func wrapError(next ErrorRequestHandler) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ if err := next(w, r); err != nil {
+ if errors.Is(err, service.RepositoryNotFoundErr) {
+ NotFound(w)
+ } else {
+ InternalServerError(w, err)
+ }
+ }
+ }
+}
+
+func (r *Router) run(next ErrorRequestHandler) http.HandlerFunc {
+ return func(w http.ResponseWriter, re *http.Request) {
+ req := wrapError(next)
+ for _, r := range r.middlewares {
+ req = r(req)
+ }
+ req(w, re)
+ }
+}
+
+func (r *Router) HandleFunc(path string, handler ErrorRequestHandler) {
+ r.router.HandleFunc(path, r.run(handler))
+}
+
+func NotFound(w http.ResponseWriter) {
+ w.WriteHeader(http.StatusNotFound)
+ templates.WritePageTemplate(w, &templates.ErrorPage{
+ Message: "Not Found",
+ })
+}
+
+func InternalServerError(w http.ResponseWriter, err error) {
+ w.WriteHeader(http.StatusInternalServerError)
+ templates.WritePageTemplate(w, &templates.ErrorPage{
+ Message: fmt.Sprintf("Internal Server Error:\n%s", err.Error()),
+ })
+}
diff --git a/pkg/git/git.go b/pkg/git/git.go
index 6a7b91f..ad5d3bc 100644
--- a/pkg/git/git.go
+++ b/pkg/git/git.go
@@ -99,9 +99,6 @@ func (g *GitRepository) Commits() ([]*object.Commit, error) {
}
commits = append(commits, c)
}
- if err != nil {
- return nil, err
- }
return commits, nil
}
diff --git a/pkg/handler/about/handler.go b/pkg/handler/about/handler.go
index 1acde60..ac3d314 100644
--- a/pkg/handler/about/handler.go
+++ b/pkg/handler/about/handler.go
@@ -2,7 +2,6 @@ package about
import (
"io"
- "log/slog"
"net/http"
"os"
@@ -27,17 +26,15 @@ func NewAboutHandler(configRepo configurationRepository) *AboutHandler {
return &AboutHandler{configRepo.GetRootReadme()}
}
-func (g *AboutHandler) About(w http.ResponseWriter, _ *http.Request) {
+func (g *AboutHandler) About(w http.ResponseWriter, _ *http.Request) error {
f, err := os.Open(g.readmePath)
if err != nil {
- slog.Error("Error loading readme file", "error", err)
- return
+ return err
}
bs, err := io.ReadAll(f)
if err != nil {
- slog.Error("Error reading readme file bytes", "error", err)
- return
+ return err
}
extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock
@@ -54,4 +51,5 @@ func (g *AboutHandler) About(w http.ResponseWriter, _ *http.Request) {
Body: bs,
}
templates.WritePageTemplate(w, gitList)
+ return nil
}
diff --git a/pkg/handler/config/handler.go b/pkg/handler/config/handler.go
index 30f4283..c43b54d 100644
--- a/pkg/handler/config/handler.go
+++ b/pkg/handler/config/handler.go
@@ -3,7 +3,6 @@ package config
import (
"bytes"
"encoding/json"
- "log/slog"
"net/http"
"github.com/alecthomas/chroma/v2/formatters/html"
@@ -11,6 +10,7 @@ import (
"github.com/alecthomas/chroma/v2/styles"
"git.gabrielgio.me/cerrado/pkg/config"
+ "git.gabrielgio.me/cerrado/pkg/ext"
"git.gabrielgio.me/cerrado/templates"
)
@@ -21,8 +21,8 @@ type (
}
)
-func ConfigFile(configRepo configurationRepository) func(http.ResponseWriter, *http.Request) {
- return func(w http.ResponseWriter, _ *http.Request) {
+func ConfigFile(configRepo configurationRepository) ext.ErrorRequestHandler {
+ return func(w http.ResponseWriter, _ *http.Request) error {
config := struct {
RootReadme string
@@ -34,8 +34,7 @@ func ConfigFile(configRepo configurationRepository) func(http.ResponseWriter, *h
b, err := json.MarshalIndent(config, "", " ")
if err != nil {
- slog.Error("Error parsing json", "error", err)
- return
+ return err
}
lexer := lexers.Get("json")
@@ -45,15 +44,13 @@ func ConfigFile(configRepo configurationRepository) func(http.ResponseWriter, *h
)
iterator, err := lexer.Tokenise(nil, string(b))
if err != nil {
- slog.Error("Error tokenise", "error", err)
- return
+ return err
}
var code bytes.Buffer
err = formatter.Format(&code, style, iterator)
if err != nil {
- slog.Error("Error format", "error", err)
- return
+ return err
}
hello := &templates.ConfigPage{
@@ -61,5 +58,6 @@ func ConfigFile(configRepo configurationRepository) func(http.ResponseWriter, *h
}
templates.WritePageTemplate(w, hello)
+ return nil
}
}
diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go
index 7bdf372..d952fef 100644
--- a/pkg/handler/git/handler.go
+++ b/pkg/handler/git/handler.go
@@ -3,7 +3,6 @@ package git
import (
"bytes"
"io"
- "log/slog"
"net/http"
"os"
"path/filepath"
@@ -50,23 +49,20 @@ func NewGitHandler(gitService gitService, confRepo configurationRepository) *Git
}
}
-func (g *GitHandler) List(w http.ResponseWriter, _ *http.Request) {
+func (g *GitHandler) List(w http.ResponseWriter, _ *http.Request) error {
repos, err := g.gitService.ListRepositories()
if err != nil {
- slog.Error("Error listing repo", "error", err)
- return
+ return err
}
f, err := os.Open(g.readmePath)
if err != nil {
- slog.Error("Error loading readme file", "error", err)
- return
+ return err
}
bs, err := io.ReadAll(f)
if err != nil {
- slog.Error("Error reading readme file bytes", "error", err)
- return
+ return err
}
extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock
@@ -84,15 +80,15 @@ func (g *GitHandler) List(w http.ResponseWriter, _ *http.Request) {
About: bs,
}
templates.WritePageTemplate(w, gitList)
+ return nil
}
-func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) {
+func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) error {
ext.SetHTML(w)
name := r.PathValue("name")
ref, err := g.gitService.GetHead(name)
if err != nil {
- slog.Error("Error loading head", "error", err)
- return
+ return err
}
gitList := &templates.GitItemPage{
@@ -101,15 +97,15 @@ func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) {
GitItemBase: &templates.GitItemSummaryPage{},
}
templates.WritePageTemplate(w, gitList)
+ return nil
}
-func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) {
+func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) error {
ext.SetHTML(w)
name := r.PathValue("name")
ref, err := g.gitService.GetHead(name)
if err != nil {
- slog.Error("Error loading head", "error", err)
- return
+ return err
}
gitList := &templates.GitItemPage{
Name: name,
@@ -117,28 +113,26 @@ func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) {
GitItemBase: &templates.GitItemAboutPage{},
}
templates.WritePageTemplate(w, gitList)
+ return nil
}
-func (g *GitHandler) Refs(w http.ResponseWriter, r *http.Request) {
+func (g *GitHandler) Refs(w http.ResponseWriter, r *http.Request) error {
ext.SetHTML(w)
name := r.PathValue("name")
tags, err := g.gitService.ListTags(name)
if err != nil {
- slog.Error("Error loading tags", "error", err)
- return
+ return err
}
branches, err := g.gitService.ListBranches(name)
if err != nil {
- slog.Error("Error loading branches", "error", err)
- return
+ return err
}
ref, err := g.gitService.GetHead(name)
if err != nil {
- slog.Error("Error loading head", "error", err)
- return
+ return err
}
gitList := &templates.GitItemPage{
@@ -150,9 +144,10 @@ func (g *GitHandler) Refs(w http.ResponseWriter, r *http.Request) {
},
}
templates.WritePageTemplate(w, gitList)
+ return nil
}
-func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) {
+func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) error {
ext.SetHTML(w)
name := r.PathValue("name")
ref := r.PathValue("ref")
@@ -160,8 +155,7 @@ func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) {
tree, err := g.gitService.GetTree(name, ref, rest)
if err != nil {
- slog.Error("Error loading tree", "error", err)
- return
+ return err
}
gitList := &templates.GitItemPage{
@@ -175,9 +169,10 @@ func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) {
},
}
templates.WritePageTemplate(w, gitList)
+ return nil
}
-func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) {
+func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) error {
ext.SetHTML(w)
name := r.PathValue("name")
ref := r.PathValue("ref")
@@ -185,8 +180,7 @@ func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) {
file, err := g.gitService.GetFileContent(name, ref, rest)
if err != nil {
- slog.Error("Error loading blob", "error", err)
- return
+ return err
}
filename := filepath.Base(rest)
@@ -197,15 +191,13 @@ func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) {
)
iterator, err := lexer.Tokenise(nil, file)
if err != nil {
- slog.Error("Error tokenise", "error", err)
- return
+ return err
}
var code bytes.Buffer
err = formatter.Format(&code, style, iterator)
if err != nil {
- slog.Error("Error format", "error", err)
- return
+ return err
}
gitList := &templates.GitItemPage{
@@ -217,17 +209,17 @@ func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) {
},
}
templates.WritePageTemplate(w, gitList)
+ return nil
}
-func (g *GitHandler) Log(w http.ResponseWriter, r *http.Request) {
+func (g *GitHandler) Log(w http.ResponseWriter, r *http.Request) error {
ext.SetHTML(w)
name := r.PathValue("name")
ref := r.PathValue("ref")
commits, err := g.gitService.ListCommits(name, ref)
if err != nil {
- slog.Error("Error loading commits", "error", err)
- return
+ return err
}
gitList := &templates.GitItemPage{
@@ -238,6 +230,7 @@ func (g *GitHandler) Log(w http.ResponseWriter, r *http.Request) {
},
}
templates.WritePageTemplate(w, gitList)
+ return nil
}
func GetLexers(filename string) chroma.Lexer {
diff --git a/pkg/handler/router.go b/pkg/handler/router.go
index bf13ad5..3da812f 100644
--- a/pkg/handler/router.go
+++ b/pkg/handler/router.go
@@ -20,9 +20,9 @@ func MountHandler(
configRepo *serverconfig.ConfigurationRepository,
) (http.Handler, error) {
var (
- gitHandler = git.NewGitHandler(gitService, configRepo)
- aboutHandler = about.NewAboutHandler(configRepo)
- configHander = config.ConfigFile(configRepo)
+ gitHandler = git.NewGitHandler(gitService, configRepo)
+ aboutHandler = about.NewAboutHandler(configRepo)
+ configHandler = config.ConfigFile(configRepo)
)
staticHandler, err := static.ServeStaticHandler()
@@ -30,21 +30,19 @@ func MountHandler(
return nil, err
}
- mux := http.NewServeMux()
+ mux := ext.NewRouter()
+ mux.AddMiddleware(ext.Compress)
+ mux.AddMiddleware(ext.Log)
- mux.HandleFunc("/static/{file}", m(staticHandler))
- mux.HandleFunc("/{name}/about/{$}", m(gitHandler.About))
- mux.HandleFunc("/{name}", m(gitHandler.Summary))
- mux.HandleFunc("/{name}/refs/{$}", m(gitHandler.Refs))
- mux.HandleFunc("/{name}/tree/{ref}/{rest...}", m(gitHandler.Tree))
- mux.HandleFunc("/{name}/blob/{ref}/{rest...}", m(gitHandler.Blob))
- mux.HandleFunc("/{name}/log/{ref}", m(gitHandler.Log))
- mux.HandleFunc("/config", m(configHander))
- mux.HandleFunc("/about", m(aboutHandler.About))
- mux.HandleFunc("/", m(gitHandler.List))
- return mux, nil
-}
-
-func m(next func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
- return ext.Compress(next)
+ mux.HandleFunc("/static/{file}", staticHandler)
+ mux.HandleFunc("/{name}/about/{$}", gitHandler.About)
+ mux.HandleFunc("/{name}", gitHandler.Summary)
+ mux.HandleFunc("/{name}/refs/{$}", gitHandler.Refs)
+ mux.HandleFunc("/{name}/tree/{ref}/{rest...}", gitHandler.Tree)
+ mux.HandleFunc("/{name}/blob/{ref}/{rest...}", gitHandler.Blob)
+ mux.HandleFunc("/{name}/log/{ref}", gitHandler.Log)
+ mux.HandleFunc("/config", configHandler)
+ mux.HandleFunc("/about", aboutHandler.About)
+ mux.HandleFunc("/", gitHandler.List)
+ return mux.Handler(), nil
}
diff --git a/pkg/handler/static/handler.go b/pkg/handler/static/handler.go
index 5155068..0973d75 100644
--- a/pkg/handler/static/handler.go
+++ b/pkg/handler/static/handler.go
@@ -10,19 +10,21 @@ import (
"git.gabrielgio.me/cerrado/static"
)
-func ServeStaticHandler() (func(w http.ResponseWriter, r *http.Request), error) {
+func ServeStaticHandler() (ext.ErrorRequestHandler, error) {
staticFs, err := fs.Sub(static.Static, ".")
if err != nil {
return nil, err
}
- return func(w http.ResponseWriter, r *http.Request) {
+ return func(w http.ResponseWriter, r *http.Request) error {
var (
f = r.PathValue("file")
e = filepath.Ext(f)
m = mime.TypeByExtension(e)
)
ext.SetMIME(w, m)
+ w.Header().Add("Cache-Control", "immutable")
http.ServeFileFS(w, r, staticFs, f)
+ return nil
}, nil
}
diff --git a/pkg/service/git.go b/pkg/service/git.go
index 31a1cbb..94e2adc 100644
--- a/pkg/service/git.go
+++ b/pkg/service/git.go
@@ -1,6 +1,7 @@
package service
import (
+ "errors"
"log/slog"
"os"
"path"
@@ -31,6 +32,10 @@ type (
}
)
+var (
+ RepositoryNotFoundErr = errors.New("Repository not found")
+)
+
// TODO: make it configurable
const timeFormat = "2006.01.02 15:04:05"
@@ -84,8 +89,10 @@ func (g *GitService) ListRepositories() ([]*Repository, error) {
}
func (g *GitService) ListCommits(name, ref string) ([]*object.Commit, error) {
- // TODO: handle nil
r := g.configRepo.GetByName(name)
+ if r == nil {
+ return nil, RepositoryNotFoundErr
+ }
repo, err := git.OpenRepository(r.Path)
if err != nil {
@@ -100,8 +107,10 @@ func (g *GitService) ListCommits(name, ref string) ([]*object.Commit, error) {
}
func (g *GitService) GetTree(name, ref, path string) (*object.Tree, error) {
- // TODO: handle nil
r := g.configRepo.GetByName(name)
+ if r == nil {
+ return nil, RepositoryNotFoundErr
+ }
repo, err := git.OpenRepository(r.Path)
if err != nil {
@@ -116,8 +125,10 @@ func (g *GitService) GetTree(name, ref, path string) (*object.Tree, error) {
}
func (g *GitService) GetFileContent(name, ref, path string) (string, error) {
- // TODO: handle nil
r := g.configRepo.GetByName(name)
+ if r == nil {
+ return "", RepositoryNotFoundErr
+ }
repo, err := git.OpenRepository(r.Path)
if err != nil {
@@ -132,8 +143,10 @@ func (g *GitService) GetFileContent(name, ref, path string) (string, error) {
}
func (g *GitService) ListTags(name string) ([]*object.Tag, error) {
- // TODO: handle nil
r := g.configRepo.GetByName(name)
+ if r == nil {
+ return nil, RepositoryNotFoundErr
+ }
repo, err := git.OpenRepository(r.Path)
if err != nil {
@@ -143,8 +156,10 @@ func (g *GitService) ListTags(name string) ([]*object.Tag, error) {
}
func (g *GitService) ListBranches(name string) ([]*plumbing.Reference, error) {
- // TODO: handle nil
r := g.configRepo.GetByName(name)
+ if r == nil {
+ return nil, RepositoryNotFoundErr
+ }
repo, err := git.OpenRepository(r.Path)
if err != nil {
@@ -154,8 +169,10 @@ func (g *GitService) ListBranches(name string) ([]*plumbing.Reference, error) {
}
func (g *GitService) GetHead(name string) (*plumbing.Reference, error) {
- // TODO: handle nil
r := g.configRepo.GetByName(name)
+ if r == nil {
+ return nil, RepositoryNotFoundErr
+ }
repo, err := git.OpenRepository(r.Path)
if err != nil {
diff --git a/templates/error.qtpl b/templates/error.qtpl
new file mode 100644
index 0000000..771d533
--- /dev/null
+++ b/templates/error.qtpl
@@ -0,0 +1,16 @@
+{% code
+type ErrorPage struct {
+ Message string
+}
+%}
+
+{% func (p *ErrorPage) Title() %}Error{% endfunc %}
+
+{% func (p *ErrorPage) Navbar() %}{%= Navbar(Git) %}{% endfunc %}
+
+{% func (p *ErrorPage) Content() %}
+{%s p.Message %}
+{% endfunc %}
+
+{% func (p *ErrorPage) Script() %}
+{% endfunc %}
diff --git a/templates/error.qtpl.go b/templates/error.qtpl.go
new file mode 100644
index 0000000..099395f
--- /dev/null
+++ b/templates/error.qtpl.go
@@ -0,0 +1,162 @@
+// Code generated by qtc from "error.qtpl". DO NOT EDIT.
+// See https://github.com/valyala/quicktemplate for details.
+
+//line error.qtpl:1
+package templates
+
+//line error.qtpl:1
+import (
+ qtio422016 "io"
+
+ qt422016 "github.com/valyala/quicktemplate"
+)
+
+//line error.qtpl:1
+var (
+ _ = qtio422016.Copy
+ _ = qt422016.AcquireByteBuffer
+)
+
+//line error.qtpl:2
+type ErrorPage struct {
+ Message string
+}
+
+//line error.qtpl:7
+func (p *ErrorPage) StreamTitle(qw422016 *qt422016.Writer) {
+//line error.qtpl:7
+ qw422016.N().S(`Error`)
+//line error.qtpl:7
+}
+
+//line error.qtpl:7
+func (p *ErrorPage) WriteTitle(qq422016 qtio422016.Writer) {
+//line error.qtpl:7
+ qw422016 := qt422016.AcquireWriter(qq422016)
+//line error.qtpl:7
+ p.StreamTitle(qw422016)
+//line error.qtpl:7
+ qt422016.ReleaseWriter(qw422016)
+//line error.qtpl:7
+}
+
+//line error.qtpl:7
+func (p *ErrorPage) Title() string {
+//line error.qtpl:7
+ qb422016 := qt422016.AcquireByteBuffer()
+//line error.qtpl:7
+ p.WriteTitle(qb422016)
+//line error.qtpl:7
+ qs422016 := string(qb422016.B)
+//line error.qtpl:7
+ qt422016.ReleaseByteBuffer(qb422016)
+//line error.qtpl:7
+ return qs422016
+//line error.qtpl:7
+}
+
+//line error.qtpl:9
+func (p *ErrorPage) StreamNavbar(qw422016 *qt422016.Writer) {
+//line error.qtpl:9
+ StreamNavbar(qw422016, Git)
+//line error.qtpl:9
+}
+
+//line error.qtpl:9
+func (p *ErrorPage) WriteNavbar(qq422016 qtio422016.Writer) {
+//line error.qtpl:9
+ qw422016 := qt422016.AcquireWriter(qq422016)
+//line error.qtpl:9
+ p.StreamNavbar(qw422016)
+//line error.qtpl:9
+ qt422016.ReleaseWriter(qw422016)
+//line error.qtpl:9
+}
+
+//line error.qtpl:9
+func (p *ErrorPage) Navbar() string {
+//line error.qtpl:9
+ qb422016 := qt422016.AcquireByteBuffer()
+//line error.qtpl:9
+ p.WriteNavbar(qb422016)
+//line error.qtpl:9
+ qs422016 := string(qb422016.B)
+//line error.qtpl:9
+ qt422016.ReleaseByteBuffer(qb422016)
+//line error.qtpl:9
+ return qs422016
+//line error.qtpl:9
+}
+
+//line error.qtpl:11
+func (p *ErrorPage) StreamContent(qw422016 *qt422016.Writer) {
+//line error.qtpl:11
+ qw422016.N().S(`
+`)
+//line error.qtpl:12
+ qw422016.E().S(p.Message)
+//line error.qtpl:12
+ qw422016.N().S(`
+`)
+//line error.qtpl:13
+}
+
+//line error.qtpl:13
+func (p *ErrorPage) WriteContent(qq422016 qtio422016.Writer) {
+//line error.qtpl:13
+ qw422016 := qt422016.AcquireWriter(qq422016)
+//line error.qtpl:13
+ p.StreamContent(qw422016)
+//line error.qtpl:13
+ qt422016.ReleaseWriter(qw422016)
+//line error.qtpl:13
+}
+
+//line error.qtpl:13
+func (p *ErrorPage) Content() string {
+//line error.qtpl:13
+ qb422016 := qt422016.AcquireByteBuffer()
+//line error.qtpl:13
+ p.WriteContent(qb422016)
+//line error.qtpl:13
+ qs422016 := string(qb422016.B)
+//line error.qtpl:13
+ qt422016.ReleaseByteBuffer(qb422016)
+//line error.qtpl:13
+ return qs422016
+//line error.qtpl:13
+}
+
+//line error.qtpl:15
+func (p *ErrorPage) StreamScript(qw422016 *qt422016.Writer) {
+//line error.qtpl:15
+ qw422016.N().S(`
+`)
+//line error.qtpl:16
+}
+
+//line error.qtpl:16
+func (p *ErrorPage) WriteScript(qq422016 qtio422016.Writer) {
+//line error.qtpl:16
+ qw422016 := qt422016.AcquireWriter(qq422016)
+//line error.qtpl:16
+ p.StreamScript(qw422016)
+//line error.qtpl:16
+ qt422016.ReleaseWriter(qw422016)
+//line error.qtpl:16
+}
+
+//line error.qtpl:16
+func (p *ErrorPage) Script() string {
+//line error.qtpl:16
+ qb422016 := qt422016.AcquireByteBuffer()
+//line error.qtpl:16
+ p.WriteScript(qb422016)
+//line error.qtpl:16
+ qs422016 := string(qb422016.B)
+//line error.qtpl:16
+ qt422016.ReleaseByteBuffer(qb422016)
+//line error.qtpl:16
+ return qs422016
+//line error.qtpl:16
+}
diff --git a/templates/gititem.qtpl b/templates/gititem.qtpl
index 3e2dd4e..d695782 100644
--- a/templates/gititem.qtpl
+++ b/templates/gititem.qtpl
@@ -13,7 +13,7 @@ type GitItemPage struct {
}
%}
-{% func (p *GitItemPage) Title() %}Git | List{% endfunc %}
+{% func (p *GitItemPage) Title() %}Git | {%s p.Name %}{% endfunc %}
{% func (p *GitItemPage) Navbar() %}{%= Navbar(Git) %}{% endfunc %}
diff --git a/templates/gititem.qtpl.go b/templates/gititem.qtpl.go
index 2c46104..a7ed659 100644
--- a/templates/gititem.qtpl.go
+++ b/templates/gititem.qtpl.go
@@ -44,7 +44,9 @@ type GitItemPage struct {
//line gititem.qtpl:16
func (p *GitItemPage) StreamTitle(qw422016 *qt422016.Writer) {
//line gititem.qtpl:16
- qw422016.N().S(`Git | List`)
+ qw422016.N().S(`Git | `)
+//line gititem.qtpl:16
+ qw422016.E().S(p.Name)
//line gititem.qtpl:16
}