gshr
git static host repo -- generates static html for repos
git clone https://git.vogt.world/gshr.git
Log | Files | README.md | LICENSE
← Commit log
commit
message
Splitting go files by page
author
Ben Vogt <[email protected]>
date
2023-04-04 18:51:50
stats
6 file(s) changed, 296 insertions(+), 268 deletions(-)
files
Makefile
commit.go
file.go
files.go
log.go
main.go
  1diff --git a/Makefile b/Makefile
  2index 1129aa9..7653b76 100644
  3--- a/Makefile
  4+++ b/Makefile
  5@@ -20,7 +20,7 @@ clean:
  6 	rm -rf target/*
  7 
  8 target/gshr-${OS}-${ARCH}-${ENVIRONMENT}.bin:
  9-	go build -o target/gshr-${OS}-${ARCH}-${ENVIRONMENT}.bin main.go
 10+	go build -o target/gshr-${OS}-${ARCH}-${ENVIRONMENT}.bin $(wildcard *.go)
 11 
 12 dev: target output cloning target/gshr-${OS}-${ARCH}-${ENVIRONMENT}.bin
 13 	./target/gshr-${OS}-${ARCH}-${ENVIRONMENT}.bin \
 14diff --git a/commit.go b/commit.go
 15new file mode 100644
 16index 0000000..f7a2d06
 17--- /dev/null
 18+++ b/commit.go
 19@@ -0,0 +1,65 @@
 20+package main
 21+
 22+import (
 23+	"html/template"
 24+	"os"
 25+	"path"
 26+
 27+	"github.com/go-git/go-git/v5"
 28+	"github.com/go-git/go-git/v5/plumbing/object"
 29+)
 30+
 31+type CommitDetail struct {
 32+	BaseURL         string
 33+	Author          string
 34+	AuthorEmail     string
 35+	Date            string
 36+	Hash            string
 37+	Message         string
 38+	FileChangeCount int
 39+	LinesAdded      int
 40+	LinesDeleted    int
 41+}
 42+
 43+func (c *CommitDetail) Render(t *template.Template) {
 44+	err := os.MkdirAll(path.Join(config.OutputDir, "commit", c.Hash), 0755)
 45+	checkErr(err)
 46+	output, err := os.Create(path.Join(config.OutputDir, "commit", c.Hash, "index.html"))
 47+	checkErr(err)
 48+	err = t.Execute(output, c)
 49+	checkErr(err)
 50+}
 51+
 52+func RenderAllCommitPages(r *git.Repository) {
 53+	t, err := template.ParseFS(htmlTemplates, "templates/commit.html", "templates/partials.html")
 54+	checkErr(err)
 55+	ref, err := r.Head()
 56+	checkErr(err)
 57+	cIter, err := r.Log(&git.LogOptions{From: ref.Hash()})
 58+	checkErr(err)
 59+	err = cIter.ForEach(func(c *object.Commit) error {
 60+		stats, err := c.Stats()
 61+		added := 0
 62+		deleted := 0
 63+		for i := 0; i < len(stats); i++ {
 64+			stat := stats[i]
 65+			added += stat.Addition
 66+			deleted += stat.Deletion
 67+		}
 68+		checkErr(err)
 69+		commitDetail := CommitDetail{
 70+			BaseURL:         config.BaseURL,
 71+			Author:          c.Author.Name,
 72+			AuthorEmail:     c.Author.Email,
 73+			Message:         c.Message,
 74+			Date:            c.Author.When.UTC().Format("2006-01-02 15:04:05"),
 75+			Hash:            c.Hash.String(),
 76+			FileChangeCount: len(stats),
 77+			LinesAdded:      added,
 78+			LinesDeleted:    deleted,
 79+		}
 80+		commitDetail.Render(t)
 81+		return nil
 82+	})
 83+	checkErr(err)
 84+}
 85diff --git a/file.go b/file.go
 86new file mode 100644
 87index 0000000..2845f46
 88--- /dev/null
 89+++ b/file.go
 90@@ -0,0 +1,93 @@
 91+package main
 92+
 93+import (
 94+	"bytes"
 95+	"html/template"
 96+	"io/fs"
 97+	"os"
 98+	"path"
 99+	"path/filepath"
100+	"strings"
101+
102+	"github.com/alecthomas/chroma/formatters/html"
103+	"github.com/alecthomas/chroma/lexers"
104+	"github.com/alecthomas/chroma/styles"
105+)
106+
107+type TrackedFile struct {
108+	BaseURL        string
109+	Mode           string
110+	Name           string
111+	Size           string
112+	Origin         string
113+	Extension      string
114+	CanRender      bool
115+	Destination    string
116+	DestinationDir string
117+	Content        template.HTML
118+}
119+
120+func (f *TrackedFile) Render(t *template.Template) {
121+	lexer := lexers.Match(f.DestinationDir)
122+	if lexer == nil {
123+		lexer = lexers.Fallback
124+	}
125+	style := styles.Get("borland")
126+	if style == nil {
127+		style = styles.Fallback
128+	}
129+	err := os.MkdirAll(f.DestinationDir, 0775)
130+	checkErr(err)
131+	if f.CanRender {
132+		fileBytes, err := os.ReadFile(f.Origin)
133+		checkErr(err)
134+		fileStr := string(fileBytes)
135+		iterator, err := lexer.Tokenise(nil, fileStr)
136+		formatter := html.New(
137+			html.WithClasses(true),
138+			html.WithLineNumbers(true),
139+			html.LinkableLineNumbers(true, ""),
140+		)
141+		s := ""
142+		buf := bytes.NewBufferString(s)
143+		err = formatter.Format(buf, style, iterator)
144+		checkErr(err)
145+		f.Content = template.HTML(buf.String())
146+	}
147+	err = os.MkdirAll(filepath.Dir(f.Destination), 0775)
148+	checkErr(err)
149+	output, err := os.Create(f.Destination)
150+	checkErr(err)
151+	err = t.Execute(output, f)
152+	checkErr(err)
153+}
154+
155+func RenderSingleFilePages() {
156+	t, err := template.ParseFS(htmlTemplates, "templates/file.html", "templates/partials.html")
157+	checkErr(err)
158+	err = filepath.Walk(config.CloneDir, func(filename string, info fs.FileInfo, err error) error {
159+		if info.IsDir() && info.Name() == ".git" {
160+			return filepath.SkipDir
161+		}
162+
163+		if !info.IsDir() {
164+			ext := filepath.Ext(filename)
165+			_, canRenderExtension := config.TextExtensions[ext]
166+			_, canRenderByFullName := config.PlainFiles[filepath.Base(filename)]
167+			partialPath, _ := strings.CutPrefix(filename, config.CloneDir)
168+			outputName := path.Join(config.OutputDir, "files", partialPath, "index.html")
169+			debug("reading = %v", partialPath)
170+			tf := TrackedFile{
171+				BaseURL:        config.BaseURL,
172+				Extension:      ext,
173+				CanRender:      canRenderExtension || canRenderByFullName,
174+				Origin:         filename,
175+				Destination:    outputName,
176+				DestinationDir: path.Join(config.OutputDir, "files", partialPath),
177+			}
178+			tf.Render(t)
179+		}
180+		return nil
181+	})
182+	checkErr(err)
183+}
184diff --git a/files.go b/files.go
185new file mode 100644
186index 0000000..613bb4c
187--- /dev/null
188+++ b/files.go
189@@ -0,0 +1,64 @@
190+package main
191+
192+import (
193+	"fmt"
194+	"html/template"
195+	"io/fs"
196+	"os"
197+	"path"
198+	"path/filepath"
199+	"strings"
200+)
201+
202+type TrackedFileMetaData struct {
203+	BaseURL string
204+	Mode    string
205+	Name    string
206+	Size    string
207+	Origin  string
208+}
209+
210+type FilesIndex struct {
211+	BaseURL string
212+	Files   []TrackedFileMetaData
213+}
214+
215+func (fi *FilesIndex) Render(t *template.Template) {
216+	output, err := os.Create(path.Join(config.OutputDir, "files.html"))
217+	checkErr(err)
218+	err = t.Execute(output, fi)
219+	checkErr(err)
220+}
221+
222+func RenderAllFilesPage() {
223+	t, err := template.ParseFS(htmlTemplates, "templates/files.html", "templates/partials.html")
224+	checkErr(err)
225+	trackedFiles := make([]TrackedFileMetaData, 0)
226+	err = filepath.Walk(config.CloneDir, func(filename string, info fs.FileInfo, err error) error {
227+		if info.IsDir() && info.Name() == ".git" {
228+			return filepath.SkipDir
229+		}
230+
231+		if !info.IsDir() {
232+			info, err := os.Stat(filename)
233+			checkErr(err)
234+			Name, _ := strings.CutPrefix(filename, config.CloneDir)
235+			Name, _ = strings.CutPrefix(Name, "/")
236+			tf := TrackedFileMetaData{
237+				BaseURL: config.BaseURL,
238+				Origin:  filename,
239+				Name:    Name,
240+				Mode:    info.Mode().String(),
241+				Size:    fmt.Sprintf("%v", info.Size()),
242+			}
243+			trackedFiles = append(trackedFiles, tf)
244+		}
245+		return nil
246+	})
247+	checkErr(err)
248+	index := FilesIndex{
249+		BaseURL: config.BaseURL,
250+		Files:   trackedFiles,
251+	}
252+	index.Render(t)
253+}
254diff --git a/log.go b/log.go
255new file mode 100644
256index 0000000..c885902
257--- /dev/null
258+++ b/log.go
259@@ -0,0 +1,73 @@
260+package main
261+
262+import (
263+	"html/template"
264+	"os"
265+	"path"
266+
267+	"github.com/go-git/go-git/v5"
268+	"github.com/go-git/go-git/v5/plumbing/object"
269+)
270+
271+type Commit struct {
272+	BaseURL         string
273+	Author          string
274+	Date            string
275+	Hash            string
276+	Message         string
277+	FileChangeCount int
278+	LinesAdded      int
279+	LinesDeleted    int
280+}
281+
282+type LogPage struct {
283+	BaseURL string
284+	Commits []Commit
285+}
286+
287+func (mi *LogPage) Render(t *template.Template) {
288+	output, err := os.Create(path.Join(config.OutputDir, "log.html"))
289+	checkErr(err)
290+	err = t.Execute(output, mi)
291+	checkErr(err)
292+}
293+
294+func RenderLogPage(r *git.Repository) {
295+	t, err := template.ParseFS(htmlTemplates, "templates/log.html", "templates/partials.html")
296+	checkErr(err)
297+	commits := make([]Commit, 0)
298+	ref, err := r.Head()
299+	checkErr(err)
300+	cIter, err := r.Log(&git.LogOptions{From: ref.Hash()})
301+	checkErr(err)
302+
303+	err = cIter.ForEach(func(c *object.Commit) error {
304+		stats, err := c.Stats()
305+		added := 0
306+		deleted := 0
307+		for i := 0; i < len(stats); i++ {
308+			stat := stats[i]
309+			added += stat.Addition
310+			deleted += stat.Deletion
311+		}
312+		checkErr(err)
313+		commits = append(commits, Commit{
314+			BaseURL:         config.BaseURL,
315+			Author:          c.Author.Name,
316+			Message:         c.Message,
317+			Date:            c.Author.When.UTC().Format("2006-01-02 15:04:05"),
318+			Hash:            c.Hash.String(),
319+			FileChangeCount: len(stats),
320+			LinesAdded:      added,
321+			LinesDeleted:    deleted,
322+		})
323+		return nil
324+	})
325+
326+	checkErr(err)
327+	m := LogPage{
328+		BaseURL: config.BaseURL,
329+		Commits: commits,
330+	}
331+	m.Render(t)
332+}
333diff --git a/main.go b/main.go
334index 1505d6e..54fdc37 100644
335--- a/main.go
336+++ b/main.go
337@@ -1,25 +1,16 @@
338 package main
339 
340 import (
341-	"bytes"
342 	"embed"
343 	_ "embed"
344 	"errors"
345 	"flag"
346 	"fmt"
347-	"html/template"
348-	"io/fs"
349 	"math/rand"
350 	"os"
351 	"path"
352-	"path/filepath"
353-	"strings"
354 
355-	"github.com/alecthomas/chroma/formatters/html"
356-	"github.com/alecthomas/chroma/lexers"
357-	"github.com/alecthomas/chroma/styles"
358 	"github.com/go-git/go-git/v5"
359-	"github.com/go-git/go-git/v5/plumbing/object"
360 )
361 
362 //go:embed templates/*
363@@ -127,118 +118,6 @@ func main() {
364 	RenderSingleFilePages()
365 }
366 
367-type TrackedFile struct {
368-	BaseURL        string
369-	Mode           string
370-	Name           string
371-	Size           string
372-	Origin         string
373-	Extension      string
374-	CanRender      bool
375-	Destination    string
376-	DestinationDir string
377-	Content        template.HTML
378-}
379-
380-func (f *TrackedFile) Render(t *template.Template) {
381-	lexer := lexers.Match(f.DestinationDir)
382-	if lexer == nil {
383-		lexer = lexers.Fallback
384-	}
385-	style := styles.Get("borland")
386-	if style == nil {
387-		style = styles.Fallback
388-	}
389-	err := os.MkdirAll(f.DestinationDir, 0775)
390-	checkErr(err)
391-	if f.CanRender {
392-		fileBytes, err := os.ReadFile(f.Origin)
393-		checkErr(err)
394-		fileStr := string(fileBytes)
395-		iterator, err := lexer.Tokenise(nil, fileStr)
396-		formatter := html.New(
397-			html.WithClasses(true),
398-			html.WithLineNumbers(true),
399-			html.LinkableLineNumbers(true, ""),
400-		)
401-		s := ""
402-		buf := bytes.NewBufferString(s)
403-		err = formatter.Format(buf, style, iterator)
404-		checkErr(err)
405-		f.Content = template.HTML(buf.String())
406-	}
407-	err = os.MkdirAll(filepath.Dir(f.Destination), 0775)
408-	checkErr(err)
409-	output, err := os.Create(f.Destination)
410-	checkErr(err)
411-	err = t.Execute(output, f)
412-	checkErr(err)
413-}
414-
415-type Commit struct {
416-	BaseURL         string
417-	Author          string
418-	Date            string
419-	Hash            string
420-	Message         string
421-	FileChangeCount int
422-	LinesAdded      int
423-	LinesDeleted    int
424-}
425-
426-type LogPage struct {
427-	BaseURL string
428-	Commits []Commit
429-}
430-
431-func (mi *LogPage) Render(t *template.Template) {
432-	output, err := os.Create(path.Join(config.OutputDir, "log.html"))
433-	checkErr(err)
434-	err = t.Execute(output, mi)
435-	checkErr(err)
436-}
437-
438-type TrackedFileMetaData struct {
439-	BaseURL string
440-	Mode    string
441-	Name    string
442-	Size    string
443-	Origin  string
444-}
445-
446-type FilesIndex struct {
447-	BaseURL string
448-	Files   []TrackedFileMetaData
449-}
450-
451-func (fi *FilesIndex) Render(t *template.Template) {
452-	output, err := os.Create(path.Join(config.OutputDir, "files.html"))
453-	checkErr(err)
454-	err = t.Execute(output, fi)
455-	checkErr(err)
456-}
457-
458-type CommitDetail struct {
459-	BaseURL         string
460-	Author          string
461-	AuthorEmail     string
462-	Date            string
463-	Hash            string
464-	Message         string
465-	FileChangeCount int
466-	LinesAdded      int
467-	LinesDeleted    int
468-}
469-
470-func (c *CommitDetail) Render(t *template.Template) {
471-	err := os.MkdirAll(path.Join(config.OutputDir, "commit", c.Hash), 0755)
472-	checkErr(err)
473-	output, err := os.Create(path.Join(config.OutputDir, "commit", c.Hash, "index.html"))
474-	checkErr(err)
475-	err = t.Execute(output, c)
476-	checkErr(err)
477-}
478-
479 func CloneAndInfo() *git.Repository {
480 	r, err := git.PlainClone(config.CloneDir, false, &git.CloneOptions{
481 		URL: config.Repo,
482@@ -247,143 +126,6 @@ func CloneAndInfo() *git.Repository {
483 	return r
484 }
485 
486-func RenderAllCommitPages(r *git.Repository) {
487-	t, err := template.ParseFS(htmlTemplates, "templates/commit.html", "templates/partials.html")
488-	checkErr(err)
489-	ref, err := r.Head()
490-	checkErr(err)
491-	cIter, err := r.Log(&git.LogOptions{From: ref.Hash()})
492-	checkErr(err)
493-	err = cIter.ForEach(func(c *object.Commit) error {
494-		stats, err := c.Stats()
495-		added := 0
496-		deleted := 0
497-		for i := 0; i < len(stats); i++ {
498-			stat := stats[i]
499-			added += stat.Addition
500-			deleted += stat.Deletion
501-		}
502-		checkErr(err)
503-		commitDetail := CommitDetail{
504-			BaseURL:         config.BaseURL,
505-			Author:          c.Author.Name,
506-			AuthorEmail:     c.Author.Email,
507-			Message:         c.Message,
508-			Date:            c.Author.When.UTC().Format("2006-01-02 15:04:05"),
509-			Hash:            c.Hash.String(),
510-			FileChangeCount: len(stats),
511-			LinesAdded:      added,
512-			LinesDeleted:    deleted,
513-		}
514-		commitDetail.Render(t)
515-		return nil
516-	})
517-	checkErr(err)
518-}
519-
520-func RenderLogPage(r *git.Repository) {
521-	t, err := template.ParseFS(htmlTemplates, "templates/log.html", "templates/partials.html")
522-	checkErr(err)
523-	commits := make([]Commit, 0)
524-	ref, err := r.Head()
525-	checkErr(err)
526-	cIter, err := r.Log(&git.LogOptions{From: ref.Hash()})
527-	checkErr(err)
528-
529-	err = cIter.ForEach(func(c *object.Commit) error {
530-		stats, err := c.Stats()
531-		added := 0
532-		deleted := 0
533-		for i := 0; i < len(stats); i++ {
534-			stat := stats[i]
535-			added += stat.Addition
536-			deleted += stat.Deletion
537-		}
538-		checkErr(err)
539-		commits = append(commits, Commit{
540-			BaseURL:         config.BaseURL,
541-			Author:          c.Author.Name,
542-			Message:         c.Message,
543-			Date:            c.Author.When.UTC().Format("2006-01-02 15:04:05"),
544-			Hash:            c.Hash.String(),
545-			FileChangeCount: len(stats),
546-			LinesAdded:      added,
547-			LinesDeleted:    deleted,
548-		})
549-		return nil
550-	})
551-
552-	checkErr(err)
553-	m := LogPage{
554-		BaseURL: config.BaseURL,
555-		Commits: commits,
556-	}
557-	m.Render(t)
558-}
559-
560-func RenderAllFilesPage() {
561-	t, err := template.ParseFS(htmlTemplates, "templates/files.html", "templates/partials.html")
562-	checkErr(err)
563-	trackedFiles := make([]TrackedFileMetaData, 0)
564-	err = filepath.Walk(config.CloneDir, func(filename string, info fs.FileInfo, err error) error {
565-		if info.IsDir() && info.Name() == ".git" {
566-			return filepath.SkipDir
567-		}
568-
569-		if !info.IsDir() {
570-			info, err := os.Stat(filename)
571-			checkErr(err)
572-			Name, _ := strings.CutPrefix(filename, config.CloneDir)
573-			Name, _ = strings.CutPrefix(Name, "/")
574-			tf := TrackedFileMetaData{
575-				BaseURL: config.BaseURL,
576-				Origin:  filename,
577-				Name:    Name,
578-				Mode:    info.Mode().String(),
579-				Size:    fmt.Sprintf("%v", info.Size()),
580-			}
581-			trackedFiles = append(trackedFiles, tf)
582-		}
583-		return nil
584-	})
585-	checkErr(err)
586-	index := FilesIndex{
587-		BaseURL: config.BaseURL,
588-		Files:   trackedFiles,
589-	}
590-	index.Render(t)
591-}
592-
593-func RenderSingleFilePages() {
594-	t, err := template.ParseFS(htmlTemplates, "templates/file.html", "templates/partials.html")
595-	checkErr(err)
596-	err = filepath.Walk(config.CloneDir, func(filename string, info fs.FileInfo, err error) error {
597-		if info.IsDir() && info.Name() == ".git" {
598-			return filepath.SkipDir
599-		}
600-
601-		if !info.IsDir() {
602-			ext := filepath.Ext(filename)
603-			_, canRenderExtension := config.TextExtensions[ext]
604-			_, canRenderByFullName := config.PlainFiles[filepath.Base(filename)]
605-			partialPath, _ := strings.CutPrefix(filename, config.CloneDir)
606-			outputName := path.Join(config.OutputDir, "files", partialPath, "index.html")
607-			debug("reading = %v", partialPath)
608-			tf := TrackedFile{
609-				BaseURL:        config.BaseURL,
610-				Extension:      ext,
611-				CanRender:      canRenderExtension || canRenderByFullName,
612-				Origin:         filename,
613-				Destination:    outputName,
614-				DestinationDir: path.Join(config.OutputDir, "files", partialPath),
615-			}
616-			tf.Render(t)
617-		}
618-		return nil
619-	})
620-	checkErr(err)
621-}
622-
623 func checkErr(err error) {
624 	if err != nil {
625 		fmt.Printf("ERROR: %v\n", err)