1diff --git a/pkg/ext/mime.go b/pkg/ext/mime.go
2index 6da66e3db03709439e1a8731116081dd5fe738bb..c42d4de563775a21af2511f6b2dc18562f62626a 100644
3--- a/pkg/ext/mime.go
4+++ b/pkg/ext/mime.go
5@@ -5,7 +5,8 @@
6 type ContentType = string
7
8 const (
9- TextHTML ContentType = "text/html"
10+ TextHTML ContentType = "text/html"
11+ ApplicationGZip ContentType = "application/gzip"
12 )
13
14 func Html(next func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
15@@ -14,9 +15,17 @@ next(w, r)
16 }
17 }
18
19+func SetFileName(w http.ResponseWriter, name string) {
20+ h := "inline; filename=\"" + name + "\""
21+ w.Header().Add("Content-Disposition", h)
22+}
23+
24 func SetHTML(w http.ResponseWriter) {
25 SetMIME(w, TextHTML)
26+}
27
28+func SetGZip(w http.ResponseWriter) {
29+ SetMIME(w, ApplicationGZip)
30 }
31
32 func SetMIME(w http.ResponseWriter, mime ContentType) {
33diff --git a/pkg/git/git.go b/pkg/git/git.go
34index b725cd875a2615e043e4b15cad5b6bfc98860a85..591fafb069b141c9e7089f6b6982349b396feef4 100644
35--- a/pkg/git/git.go
36+++ b/pkg/git/git.go
37@@ -1,9 +1,13 @@
38 package git
39
40 import (
41+ "archive/tar"
42 "errors"
43 "fmt"
44 "io"
45+ "io/fs"
46+ "path"
47+ "time"
48
49 "github.com/go-git/go-git/v5"
50 "github.com/go-git/go-git/v5/plumbing"
51@@ -25,6 +29,13 @@
52 ref plumbing.Hash
53 // this is setRef when ref is setRef
54 setRef bool
55+ }
56+ infoWrapper struct {
57+ name string
58+ size int64
59+ mode fs.FileMode
60+ modTime time.Time
61+ isDir bool
62 }
63 )
64
65@@ -213,3 +224,110 @@ } else {
66 return "Binary file", nil
67 }
68 }
69+
70+func (g *GitRepository) WriteTar(w io.Writer, prefix string) error {
71+ tw := tar.NewWriter(w)
72+ defer tw.Close()
73+
74+ tree, err := g.Tree("")
75+ if err != nil {
76+ return err
77+ }
78+
79+ walker := object.NewTreeWalker(tree, true, nil)
80+ defer walker.Close()
81+
82+ name, entry, err := walker.Next()
83+ for ; err == nil; name, entry, err = walker.Next() {
84+ info, err := newInfoWrapper(name, prefix, &entry, tree)
85+ if err != nil {
86+ return err
87+ }
88+
89+ header, err := tar.FileInfoHeader(info, "")
90+ if err != nil {
91+ return err
92+ }
93+
94+ err = tw.WriteHeader(header)
95+ if err != nil {
96+ return err
97+ }
98+
99+ if !info.IsDir() {
100+ c, err := g.FileContent(name)
101+ if err != nil {
102+ return err
103+ }
104+
105+ _, err = tw.Write([]byte(c))
106+ if err != nil {
107+ return err
108+ }
109+ }
110+ }
111+
112+ return nil
113+}
114+
115+func newInfoWrapper(
116+ filename string,
117+ prefix string,
118+ entry *object.TreeEntry,
119+ tree *object.Tree,
120+) (*infoWrapper, error) {
121+ var (
122+ size int64
123+ mode fs.FileMode
124+ isDir bool
125+ )
126+
127+ if entry.Mode.IsFile() {
128+ file, err := tree.TreeEntryFile(entry)
129+ if err != nil {
130+ return nil, err
131+ }
132+ mode = fs.FileMode(file.Mode)
133+
134+ size, err = tree.Size(filename)
135+ if err != nil {
136+ return nil, err
137+ }
138+ } else {
139+ isDir = true
140+ mode = fs.ModeDir | fs.ModePerm
141+ }
142+
143+ fullname := path.Join(prefix, filename)
144+ return &infoWrapper{
145+ name: fullname,
146+ size: size,
147+ mode: mode,
148+ modTime: time.Unix(0, 0),
149+ isDir: isDir,
150+ }, nil
151+}
152+
153+func (i *infoWrapper) Name() string {
154+ return i.name
155+}
156+
157+func (i *infoWrapper) Size() int64 {
158+ return i.size
159+}
160+
161+func (i *infoWrapper) Mode() fs.FileMode {
162+ return i.mode
163+}
164+
165+func (i *infoWrapper) ModTime() time.Time {
166+ return i.modTime
167+}
168+
169+func (i *infoWrapper) IsDir() bool {
170+ return i.isDir
171+}
172+
173+func (i *infoWrapper) Sys() any {
174+ return nil
175+}
176diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go
177index 25505ba4c8ebfc520f69f9e21b87eef41752cd66..aed991747bb2e3d5054d2a0921321de6388f48d9 100644
178--- a/pkg/handler/git/handler.go
179+++ b/pkg/handler/git/handler.go
180@@ -2,10 +2,13 @@ package git
181
182 import (
183 "bytes"
184+ "fmt"
185 "io"
186+ "log/slog"
187 "net/http"
188 "os"
189 "path/filepath"
190+ "strings"
191
192 "git.gabrielgio.me/cerrado/pkg/ext"
193 "git.gabrielgio.me/cerrado/pkg/service"
194@@ -36,6 +39,7 @@ GetFileContent(name, ref, path string) (string, error)
195 GetAbout(name string) (string, error)
196 ListTags(name string) ([]*plumbing.Reference, error)
197 ListBranches(name string) ([]*plumbing.Reference, error)
198+ WriteTarGZip(w io.Writer, name, ref, filename string) error
199 }
200
201 configurationRepository interface {
202@@ -81,6 +85,38 @@ Respositories: repos,
203 About: bs,
204 }
205 templates.WritePageTemplate(w, gitList)
206+ return nil
207+}
208+
209+func (g *GitHandler) Archive(w http.ResponseWriter, r *http.Request) error {
210+ ext.SetGZip(w)
211+ name := r.PathValue("name")
212+ refs := r.PathValue("refs")
213+ ref := strings.TrimSuffix(refs, ".tar.gz")
214+
215+ // TODO: remove it once we can support more than gzip
216+ if !strings.HasSuffix(refs, ".tar.gz") {
217+ ext.NotFound(w)
218+ return nil
219+ }
220+
221+ filenameWithExt := fmt.Sprintf("%s-%s.tar.gz", name, ref)
222+ ext.SetFileName(w, filenameWithExt)
223+ filename := fmt.Sprintf("%s-%s", name, ref)
224+
225+ // writing to a buffer so we can run all the process before writing error
226+ var buf bytes.Buffer
227+ err := g.gitService.WriteTarGZip(&buf, name, ref, filename)
228+ if err != nil {
229+ return err
230+ }
231+
232+ // since that has write to w it cannot return a error.
233+ _, err = io.Copy(w, &buf)
234+ if err != nil {
235+ slog.Error("Error copying buffer", "error", err)
236+ }
237+
238 return nil
239 }
240
241diff --git a/pkg/handler/router.go b/pkg/handler/router.go
242index c8f89840effc9263911f7afc73b02722436b36f9..2293ab662f2e92a23bc3d3c953413ad00489cd58 100644
243--- a/pkg/handler/router.go
244+++ b/pkg/handler/router.go
245@@ -41,6 +41,7 @@ mux.HandleFunc("/{name}/refs/{$}", gitHandler.Refs)
246 mux.HandleFunc("/{name}/tree/{ref}/{rest...}", gitHandler.Tree)
247 mux.HandleFunc("/{name}/blob/{ref}/{rest...}", gitHandler.Blob)
248 mux.HandleFunc("/{name}/log/{ref}/", gitHandler.Log)
249+ mux.HandleFunc("/{name}/archive/{refs...}", gitHandler.Archive)
250 mux.HandleFunc("/config", configHandler)
251 mux.HandleFunc("/about", aboutHandler.About)
252 mux.HandleFunc("/", gitHandler.List)
253diff --git a/pkg/service/git.go b/pkg/service/git.go
254index 6bb6e9ebb7739ae025c124766ac402d19c429aad..cbee90a375721e07a0efea8b2653aa9a711d87ed 100644
255--- a/pkg/service/git.go
256+++ b/pkg/service/git.go
257@@ -1,7 +1,9 @@
258 package service
259
260 import (
261+ "compress/gzip"
262 "errors"
263+ "io"
264 "log/slog"
265
266 "git.gabrielgio.me/cerrado/pkg/config"
267@@ -90,6 +92,29 @@ if err != nil {
268 return nil, err
269 }
270 return repo.Commits(count)
271+}
272+
273+func (g *GitService) WriteTarGZip(w io.Writer, name, ref string, filename string) error {
274+ r := g.configRepo.GetByName(name)
275+ if r == nil {
276+ return RepositoryNotFoundErr
277+ }
278+
279+ repo, err := git.OpenRepository(r.Path)
280+ if err != nil {
281+ return err
282+ }
283+
284+ err = repo.SetRef(ref)
285+ if err != nil {
286+ return err
287+ }
288+
289+ gw := gzip.NewWriter(w)
290+ defer gw.Close()
291+
292+ return repo.WriteTar(gw, filename)
293+
294 }
295
296 func (g *GitService) GetTree(name, ref, path string) (*object.Tree, error) {
297diff --git a/templates/gititemrefs.qtpl b/templates/gititemrefs.qtpl
298index ff1561b7626970689ef318510c4610dbf20d5623..624408297c9680822ebf314fd7fb955e823ab606 100644
299--- a/templates/gititemrefs.qtpl
300+++ b/templates/gititemrefs.qtpl
301@@ -21,6 +21,7 @@ {%s t.Name().Short() %}
302 </div>
303 <div class="col-8">
304 <div class="float-end">
305+ <a href="/{%s name %}/archive/{%s t.Name().Short() %}.tar.gz">tar.gz</a>
306 <a href="/{%s name %}/tree/{%s t.Name().Short() %}/">tree</a>
307 <a href="/{%s name %}/log/{%s t.Name().Short() %}/">log</a>
308 </div>
309@@ -41,6 +42,7 @@ {%s b.Name().Short() %}
310 </div>
311 <div class="col-8">
312 <div class="float-end">
313+ <a href="/{%s name %}/archive/{%s b.Name().Short() %}.tar.gz">tar.gz</a>
314 <a href="/{%s name %}/tree/{%s b.Name().Short() %}/">tree</a>
315 <a href="/{%s name %}/log/{%s b.Name().Short() %}/">log</a>
316 </div>
317diff --git a/templates/gititemrefs.qtpl.go b/templates/gititemrefs.qtpl.go
318index b00736ecb57ca6d0fca34676cb9e455591c92d7a..da9bfe757f4d6bc91fb3d53c65dc2cd0faa36074 100644
319--- a/templates/gititemrefs.qtpl.go
320+++ b/templates/gititemrefs.qtpl.go
321@@ -90,113 +90,131 @@ <a href="/`)
322 //line gititemrefs.qtpl:24
323 qw422016.E().S(name)
324 //line gititemrefs.qtpl:24
325- qw422016.N().S(`/tree/`)
326+ qw422016.N().S(`/archive/`)
327 //line gititemrefs.qtpl:24
328 qw422016.E().S(t.Name().Short())
329 //line gititemrefs.qtpl:24
330- qw422016.N().S(`/">tree</a>
331+ qw422016.N().S(`.tar.gz">tar.gz</a>
332 <a href="/`)
333 //line gititemrefs.qtpl:25
334 qw422016.E().S(name)
335 //line gititemrefs.qtpl:25
336- qw422016.N().S(`/log/`)
337+ qw422016.N().S(`/tree/`)
338 //line gititemrefs.qtpl:25
339 qw422016.E().S(t.Name().Short())
340 //line gititemrefs.qtpl:25
341+ qw422016.N().S(`/">tree</a>
342+ <a href="/`)
343+//line gititemrefs.qtpl:26
344+ qw422016.E().S(name)
345+//line gititemrefs.qtpl:26
346+ qw422016.N().S(`/log/`)
347+//line gititemrefs.qtpl:26
348+ qw422016.E().S(t.Name().Short())
349+//line gititemrefs.qtpl:26
350 qw422016.N().S(`/">log</a>
351 </div>
352 </div>
353 </div>
354 `)
355-//line gititemrefs.qtpl:29
356+//line gititemrefs.qtpl:30
357 }
358-//line gititemrefs.qtpl:29
359+//line gititemrefs.qtpl:30
360 qw422016.N().S(`
361 </div>
362 `)
363-//line gititemrefs.qtpl:31
364+//line gititemrefs.qtpl:32
365 } else {
366-//line gititemrefs.qtpl:31
367+//line gititemrefs.qtpl:32
368 qw422016.N().S(`
369 <p> No tags </p>
370 `)
371-//line gititemrefs.qtpl:33
372+//line gititemrefs.qtpl:34
373 }
374-//line gititemrefs.qtpl:33
375+//line gititemrefs.qtpl:34
376 qw422016.N().S(`
377 </div>
378 <div class="col-md-4">
379 <div class="event-list">
380 `)
381-//line gititemrefs.qtpl:37
382+//line gititemrefs.qtpl:38
383 for _, b := range g.Branches {
384-//line gititemrefs.qtpl:37
385+//line gititemrefs.qtpl:38
386 qw422016.N().S(`
387 <div class="row event">
388 <div class="col-4">
389 `)
390-//line gititemrefs.qtpl:40
391+//line gititemrefs.qtpl:41
392 qw422016.E().S(b.Name().Short())
393-//line gititemrefs.qtpl:40
394+//line gititemrefs.qtpl:41
395 qw422016.N().S(`
396 </div>
397 <div class="col-8">
398 <div class="float-end">
399 <a href="/`)
400-//line gititemrefs.qtpl:44
401+//line gititemrefs.qtpl:45
402 qw422016.E().S(name)
403-//line gititemrefs.qtpl:44
404+//line gititemrefs.qtpl:45
405+ qw422016.N().S(`/archive/`)
406+//line gititemrefs.qtpl:45
407+ qw422016.E().S(b.Name().Short())
408+//line gititemrefs.qtpl:45
409+ qw422016.N().S(`.tar.gz">tar.gz</a>
410+ <a href="/`)
411+//line gititemrefs.qtpl:46
412+ qw422016.E().S(name)
413+//line gititemrefs.qtpl:46
414 qw422016.N().S(`/tree/`)
415-//line gititemrefs.qtpl:44
416+//line gititemrefs.qtpl:46
417 qw422016.E().S(b.Name().Short())
418-//line gititemrefs.qtpl:44
419+//line gititemrefs.qtpl:46
420 qw422016.N().S(`/">tree</a>
421 <a href="/`)
422-//line gititemrefs.qtpl:45
423+//line gititemrefs.qtpl:47
424 qw422016.E().S(name)
425-//line gititemrefs.qtpl:45
426+//line gititemrefs.qtpl:47
427 qw422016.N().S(`/log/`)
428-//line gititemrefs.qtpl:45
429+//line gititemrefs.qtpl:47
430 qw422016.E().S(b.Name().Short())
431-//line gititemrefs.qtpl:45
432+//line gititemrefs.qtpl:47
433 qw422016.N().S(`/">log</a>
434 </div>
435 </div>
436 </div>
437 `)
438-//line gititemrefs.qtpl:49
439+//line gititemrefs.qtpl:51
440 }
441-//line gititemrefs.qtpl:49
442+//line gititemrefs.qtpl:51
443 qw422016.N().S(`
444 </div>
445 </div>
446 </div>
447 `)
448-//line gititemrefs.qtpl:53
449+//line gititemrefs.qtpl:55
450 }
451
452-//line gititemrefs.qtpl:53
453+//line gititemrefs.qtpl:55
454 func (g *GitItemRefsPage) WriteGitContent(qq422016 qtio422016.Writer, name, ref string) {
455-//line gititemrefs.qtpl:53
456+//line gititemrefs.qtpl:55
457 qw422016 := qt422016.AcquireWriter(qq422016)
458-//line gititemrefs.qtpl:53
459+//line gititemrefs.qtpl:55
460 g.StreamGitContent(qw422016, name, ref)
461-//line gititemrefs.qtpl:53
462+//line gititemrefs.qtpl:55
463 qt422016.ReleaseWriter(qw422016)
464-//line gititemrefs.qtpl:53
465+//line gititemrefs.qtpl:55
466 }
467
468-//line gititemrefs.qtpl:53
469+//line gititemrefs.qtpl:55
470 func (g *GitItemRefsPage) GitContent(name, ref string) string {
471-//line gititemrefs.qtpl:53
472+//line gititemrefs.qtpl:55
473 qb422016 := qt422016.AcquireByteBuffer()
474-//line gititemrefs.qtpl:53
475+//line gititemrefs.qtpl:55
476 g.WriteGitContent(qb422016, name, ref)
477-//line gititemrefs.qtpl:53
478+//line gititemrefs.qtpl:55
479 qs422016 := string(qb422016.B)
480-//line gititemrefs.qtpl:53
481+//line gititemrefs.qtpl:55
482 qt422016.ReleaseByteBuffer(qb422016)
483-//line gititemrefs.qtpl:53
484+//line gititemrefs.qtpl:55
485 return qs422016
486-//line gititemrefs.qtpl:53
487+//line gititemrefs.qtpl:55
488 }
489diff --git a/templates/gititemsummary.qtpl b/templates/gititemsummary.qtpl
490index e3d3a0828874c51b78a70cc172d34a7fada73a1e..06a785ad74913ce89927a32daff49b18529e9159 100644
491--- a/templates/gititemsummary.qtpl
492+++ b/templates/gititemsummary.qtpl
493@@ -23,6 +23,7 @@ {%s t.Name().Short() %}
494 </div>
495 <div class="col-8">
496 <div class="float-end">
497+ <a href="/{%s name %}/archive/{%s t.Name().Short() %}.tar.gz">tar.gz</a>
498 <a href="/{%s name %}/tree/{%s t.Name().Short() %}/">tree</a>
499 <a href="/{%s name %}/log/{%s t.Name().Short() %}/">log</a>
500 </div>
501diff --git a/templates/gititemsummary.qtpl.go b/templates/gititemsummary.qtpl.go
502index ad025f7e8a8343850615d1c5e27c1f2cbf89d68c..4e48efd0da70a6301114cfd65ef9929f96804953 100644
503--- a/templates/gititemsummary.qtpl.go
504+++ b/templates/gititemsummary.qtpl.go
505@@ -94,83 +94,92 @@ <a href="/`)
506 //line gititemsummary.qtpl:26
507 qw422016.E().S(name)
508 //line gititemsummary.qtpl:26
509- qw422016.N().S(`/tree/`)
510+ qw422016.N().S(`/archive/`)
511 //line gititemsummary.qtpl:26
512 qw422016.E().S(t.Name().Short())
513 //line gititemsummary.qtpl:26
514- qw422016.N().S(`/">tree</a>
515+ qw422016.N().S(`.tar.gz">tar.gz</a>
516 <a href="/`)
517 //line gititemsummary.qtpl:27
518 qw422016.E().S(name)
519 //line gititemsummary.qtpl:27
520- qw422016.N().S(`/log/`)
521+ qw422016.N().S(`/tree/`)
522 //line gititemsummary.qtpl:27
523 qw422016.E().S(t.Name().Short())
524 //line gititemsummary.qtpl:27
525+ qw422016.N().S(`/">tree</a>
526+ <a href="/`)
527+//line gititemsummary.qtpl:28
528+ qw422016.E().S(name)
529+//line gititemsummary.qtpl:28
530+ qw422016.N().S(`/log/`)
531+//line gititemsummary.qtpl:28
532+ qw422016.E().S(t.Name().Short())
533+//line gititemsummary.qtpl:28
534 qw422016.N().S(`/">log</a>
535 </div>
536 </div>
537 </div>
538 `)
539-//line gititemsummary.qtpl:31
540+//line gititemsummary.qtpl:32
541 }
542-//line gititemsummary.qtpl:31
543+//line gititemsummary.qtpl:32
544 qw422016.N().S(`
545 </div>
546 `)
547-//line gititemsummary.qtpl:33
548+//line gititemsummary.qtpl:34
549 } else {
550-//line gititemsummary.qtpl:33
551+//line gititemsummary.qtpl:34
552 qw422016.N().S(`
553 <p> No tags </p>
554 `)
555-//line gititemsummary.qtpl:35
556+//line gititemsummary.qtpl:36
557 }
558-//line gititemsummary.qtpl:35
559+//line gititemsummary.qtpl:36
560 qw422016.N().S(`
561 </div>
562 <div class="col-md-4">
563 <div class="event-list">
564 `)
565-//line gititemsummary.qtpl:39
566+//line gititemsummary.qtpl:40
567 for _, b := range g.Branches {
568-//line gititemsummary.qtpl:39
569+//line gititemsummary.qtpl:40
570 qw422016.N().S(`
571 <div class="row event">
572 <div class="col-4">
573 `)
574-//line gititemsummary.qtpl:42
575+//line gititemsummary.qtpl:43
576 qw422016.E().S(b.Name().Short())
577-//line gititemsummary.qtpl:42
578+//line gititemsummary.qtpl:43
579 qw422016.N().S(`
580 </div>
581 <div class="col-8">
582 <div class="float-end">
583 <a href="/`)
584-//line gititemsummary.qtpl:46
585+//line gititemsummary.qtpl:47
586 qw422016.E().S(name)
587-//line gititemsummary.qtpl:46
588+//line gititemsummary.qtpl:47
589 qw422016.N().S(`/tree/`)
590-//line gititemsummary.qtpl:46
591+//line gititemsummary.qtpl:47
592 qw422016.E().S(b.Name().Short())
593-//line gititemsummary.qtpl:46
594+//line gititemsummary.qtpl:47
595 qw422016.N().S(`/">tree</a>
596 <a href="/`)
597-//line gititemsummary.qtpl:47
598+//line gititemsummary.qtpl:48
599 qw422016.E().S(name)
600-//line gititemsummary.qtpl:47
601+//line gititemsummary.qtpl:48
602 qw422016.N().S(`/log/`)
603-//line gititemsummary.qtpl:47
604+//line gititemsummary.qtpl:48
605 qw422016.E().S(b.Name().Short())
606-//line gititemsummary.qtpl:47
607+//line gititemsummary.qtpl:48
608 qw422016.N().S(`/">log</a>
609 </div>
610 </div>
611 </div>
612 `)
613-//line gititemsummary.qtpl:51
614+//line gititemsummary.qtpl:52
615 }
616-//line gititemsummary.qtpl:51
617+//line gititemsummary.qtpl:52
618 qw422016.N().S(`
619 </div>
620 </div>
621@@ -178,70 +187,70 @@ </div>
622 <div class="row">
623 <div class="event-list">
624 `)
625-//line gititemsummary.qtpl:57
626+//line gititemsummary.qtpl:58
627 for _, c := range g.Commits {
628-//line gititemsummary.qtpl:57
629+//line gititemsummary.qtpl:58
630 qw422016.N().S(`
631 <div class="row event">
632 <div class="col-xxl-2">
633 `)
634-//line gititemsummary.qtpl:60
635+//line gititemsummary.qtpl:61
636 qw422016.E().S(TimeFormat(c.Committer.When))
637-//line gititemsummary.qtpl:60
638+//line gititemsummary.qtpl:61
639 qw422016.N().S(`
640 </div>
641 <div class="col-xxl-7 code-view">
642 <pre>`)
643-//line gititemsummary.qtpl:63
644+//line gititemsummary.qtpl:64
645 qw422016.E().S(c.Message)
646-//line gititemsummary.qtpl:63
647+//line gititemsummary.qtpl:64
648 qw422016.N().S(`</pre>
649 </div>
650 <div class="col-xxl-3">
651 <small>`)
652-//line gititemsummary.qtpl:66
653+//line gititemsummary.qtpl:67
654 qw422016.E().S(c.Committer.Name)
655-//line gititemsummary.qtpl:66
656+//line gititemsummary.qtpl:67
657 qw422016.N().S(` <`)
658-//line gititemsummary.qtpl:66
659+//line gititemsummary.qtpl:67
660 qw422016.E().S(c.Committer.Email)
661-//line gititemsummary.qtpl:66
662+//line gititemsummary.qtpl:67
663 qw422016.N().S(`></small>
664 </div>
665 </div>
666 `)
667-//line gititemsummary.qtpl:69
668+//line gititemsummary.qtpl:70
669 }
670-//line gititemsummary.qtpl:69
671+//line gititemsummary.qtpl:70
672 qw422016.N().S(`
673 </div>
674 </div>
675 `)
676-//line gititemsummary.qtpl:72
677+//line gititemsummary.qtpl:73
678 }
679
680-//line gititemsummary.qtpl:72
681+//line gititemsummary.qtpl:73
682 func (g *GitItemSummaryPage) WriteGitContent(qq422016 qtio422016.Writer, name, ref string) {
683-//line gititemsummary.qtpl:72
684+//line gititemsummary.qtpl:73
685 qw422016 := qt422016.AcquireWriter(qq422016)
686-//line gititemsummary.qtpl:72
687+//line gititemsummary.qtpl:73
688 g.StreamGitContent(qw422016, name, ref)
689-//line gititemsummary.qtpl:72
690+//line gititemsummary.qtpl:73
691 qt422016.ReleaseWriter(qw422016)
692-//line gititemsummary.qtpl:72
693+//line gititemsummary.qtpl:73
694 }
695
696-//line gititemsummary.qtpl:72
697+//line gititemsummary.qtpl:73
698 func (g *GitItemSummaryPage) GitContent(name, ref string) string {
699-//line gititemsummary.qtpl:72
700+//line gititemsummary.qtpl:73
701 qb422016 := qt422016.AcquireByteBuffer()
702-//line gititemsummary.qtpl:72
703+//line gititemsummary.qtpl:73
704 g.WriteGitContent(qb422016, name, ref)
705-//line gititemsummary.qtpl:72
706+//line gititemsummary.qtpl:73
707 qs422016 := string(qb422016.B)
708-//line gititemsummary.qtpl:72
709+//line gititemsummary.qtpl:73
710 qt422016.ReleaseByteBuffer(qb422016)
711-//line gititemsummary.qtpl:72
712+//line gititemsummary.qtpl:73
713 return qs422016
714-//line gititemsummary.qtpl:72
715+//line gititemsummary.qtpl:73
716 }