Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

Phase 6 slice 1: the tree is the site

d3296cda0c18f78097e37373822292707113d245 · Keenan Nemetz · 18d ago · parent 64ac5071

Phase 6 slice 1: the tree is the site

A repository's `pages` branch is served at <repo>.<pages_domain>, straight out
of git. No export step, no build to drift: the push moves the branch and the
next request reads the new tree.

- internal/pages: a pool of `git cat-file --batch` processes per active
  repository (closed after two idle minutes), an LRU keyed by (commit, path),
  and tree parsing in git's binary format with the object-id width detected
  rather than assumed
- ETag is the blob sha, Last-Modified the commit time, Content-Type from the
  extension or a sniff; If-None-Match and If-Modified-Since answer 304
- directories serve index.html and redirect to add the trailing slash; path
  resolution walks trees, so a traversal-shaped request is a missing page
- repository and ACL are resolved once per one-second memo window together with
  the branch tip, which is what makes the read path fast: doing it per request
  spawned three git processes and cost 3.8 ms, against 6.7 µs warm
- sites follow clone visibility, so a private repository answers 404; the repo
  page links to the site when pages_domain is configured

Measured: a site pushed over SSH is live in 1.4 s (the phase criterion is 5 s);
warm requests 6.7 µs, cold 144 µs. Custom domains and their TLS certificates are
the remaining Phase 6 work.

internal/web/web.go +8

@@ -140,6 +140,12 @@ func (w *Web) Repo(rw http.ResponseWriter, r *http.Request) {
140 140 if w.Runs != nil {
141 141 recentRuns, _ = w.Runs.Recent(m.Name, 8)
142 142 }
143 // A site is a branch, so the page can link to it whether or not the branch
144 // exists yet: pushing it makes the link true, and until then it 404s.
145 site := ""
146 if w.Cfg.PagesDomain != "" {
147 site = "http://" + m.Name + "." + w.Cfg.PagesDomain
148 }
143 149 branches, _ := g.ListRefs("refs/heads/")
144 150 names := make([]string, 0, len(branches))
145 151 for k := range branches {
@@ -158,6 +164,7 @@ func (w *Web) Repo(rw http.ResponseWriter, r *http.Request) {
158 164 Count int
159 165 Branches []string
160 166 IssueCount int
167 Site string
161 168 Runs []*runs.Run
162 169 }{
163 170 Page: w.base(m.Name),
@@ -172,6 +179,7 @@ func (w *Web) Repo(rw http.ResponseWriter, r *http.Request) {
172 179 Count: count,
173 180 Branches: names,
174 181 IssueCount: issueCount,
182 Site: site,
175 183 Runs: recentRuns,
176 184 }, 0)
177 185 }