gshr
git static host repo -- generates static html for repos
git clone https://git.vogt.world/gshr.git
Log | Files | README.md | LICENSE
← All files
name: commit.go
-rw-r--r--
3282
  1package main
  2
  3import (
  4	"errors"
  5	"html/template"
  6	"os"
  7	"os/exec"
  8	"path"
  9	"strings"
 10
 11	"github.com/go-git/go-git/v5"
 12	"github.com/go-git/go-git/v5/plumbing/object"
 13)
 14
 15type commitPage struct {
 16	RepoData        repoData
 17	Author          string
 18	AuthorEmail     string
 19	Date            string
 20	Hash            string
 21	Message         string
 22	FileChangeCount int
 23	LinesAdded      int
 24	LinesDeleted    int
 25	FilesChanged    []string
 26	DiffContent     template.HTML
 27}
 28
 29func (c *commitPage) renderPage(t *template.Template) {
 30	debug("commit %v %v", c.RepoData.Name, c.Hash)
 31	err := os.MkdirAll(path.Join(args.OutputDir, c.RepoData.Name, "commit", c.Hash), 0755)
 32	checkErr(err)
 33	output, err := os.Create(path.Join(args.OutputDir, c.RepoData.Name, "commit", c.Hash, "index.html"))
 34	checkErr(err)
 35	err = t.Execute(output, c)
 36	checkErr(err)
 37}
 38
 39func renderAllCommitPages(data repoData, r *git.Repository) {
 40	t, err := template.ParseFS(htmlTemplates, "template.commit.html", "template.partials.html")
 41	checkErr(err)
 42	ref, err := r.Head()
 43	checkErr(err)
 44	cIter, err := r.Log(&git.LogOptions{From: ref.Hash()})
 45	checkErr(err)
 46	err = cIter.ForEach(func(c *object.Commit) error {
 47		parent, err := c.Parent(0)
 48		if err != nil && errors.Is(err, object.ErrParentNotFound) {
 49			// ok
 50		} else if err != nil {
 51			checkErr(err)
 52		}
 53		diffContent := template.HTML("")
 54		filesChangedMap := make(map[string]bool)
 55		filesChanged := []string{}
 56		if parent != nil {
 57			patch, err := parent.Patch(c)
 58			// NOTE: Seems to be a bug in go-git that gives us diff patches that are wrong. Could be my
 59			//       usage, but something tells me no. Fixing it by shelling out for now, since we
 60			//       require git to be installed for `git update-server-info` anyway.
 61			cmd := exec.Command("git", "diff", parent.Hash.String(), c.Hash.String())
 62			cmd.Dir = path.Join(args.OutputDir, data.Name, "git")
 63			var out strings.Builder
 64			cmd.Stdout = &out
 65			err = cmd.Run()
 66			checkErr(err)
 67			patchString := out.String()
 68			highlighted := highlight("x.diff", &patchString)
 69			diffContent = template.HTML(highlighted)
 70			checkErr(err)
 71			patch, err = parent.Patch(c)
 72			checkErr(err)
 73			for _, fp := range patch.FilePatches() {
 74				from, to := fp.Files()
 75				if from != nil {
 76					filePath := from.Path()
 77					if _, found := filesChangedMap[filePath]; !found {
 78						filesChangedMap[filePath] = true
 79						filesChanged = append(filesChanged, filePath)
 80					}
 81				}
 82				if to != nil {
 83					filePath := to.Path()
 84					if _, found := filesChangedMap[filePath]; !found {
 85						filesChangedMap[filePath] = true
 86						filesChanged = append(filesChanged, filePath)
 87					}
 88				}
 89			}
 90		}
 91		stats, err := c.Stats()
 92		added := 0
 93		deleted := 0
 94		for i := 0; i < len(stats); i++ {
 95			stat := stats[i]
 96			added += stat.Addition
 97			deleted += stat.Deletion
 98		}
 99		checkErr(err)
100		(&commitPage{
101			RepoData:        data,
102			Author:          c.Author.Name,
103			AuthorEmail:     c.Author.Email,
104			Message:         c.Message,
105			Date:            c.Author.When.UTC().Format("2006-01-02 15:04:05"),
106			Hash:            c.Hash.String(),
107			FileChangeCount: len(stats),
108			LinesAdded:      added,
109			LinesDeleted:    deleted,
110			FilesChanged:    filesChanged,
111			DiffContent:     diffContent,
112		}).renderPage(t)
113		return nil
114	})
115	checkErr(err)
116}