I'm tired, is late, log works

This commit is contained in:
Miguel de la Cruz 2024-06-30 01:05:12 +02:00
parent 809ab91837
commit 35ee56294b
4 changed files with 152 additions and 18 deletions

View file

@ -21,7 +21,8 @@ Project heavily inspired by the amazing
- [ ] Add a subcommand to dump the embedded templates so they can be
modified.
- [ ] Take binary files into account.
- [ ] Limit the output for large diffs.
- [ ] Limit the output for large diffs. Add a "X commits remaining"
message if necessary.
- [X] Allow to anchor lines.
- [ ] Check if the templates exist on a location and use them if
so. Allow to change that location through CLI flags or env vars.

View file

@ -9,7 +9,6 @@ import (
"os"
"path/filepath"
"strings"
"time"
"github.com/alecthomas/kong"
"github.com/go-git/go-git/v5"
@ -20,7 +19,7 @@ type RepoDir struct {
Name string
Description string
Owner string
LastCommit time.Time
LastCommit string
}
type RepoInfo struct {
@ -33,15 +32,28 @@ type RepoInfo struct {
}
type CommitFile struct {
Mode string
Path string
Name string
Lines int
Mode string
Path string
Name string
Lines int
IsBinary bool
Size int64
}
type CommitLog struct {
Hash string
Date string
Msg string
Author string
Files int
Adds int
Dels int
}
//go:embed templates
var embedTmpl embed.FS
var funcMap = template.FuncMap{"inc": func(i int) int { return i + 1 }}
var timeFormat = "2006-01-02 15:04"
// ToDo: add a map function to generate the menu
@ -128,7 +140,7 @@ func generateIndex(args []string) error {
if err != nil {
return fmt.Errorf("cannot get commit %q for repository %q: %w", head.Hash(), dirname, err)
}
repoDir.LastCommit = c.Author.When
repoDir.LastCommit = c.Author.When.Format(timeFormat)
repoDirs = append(repoDirs, repoDir)
}
@ -229,8 +241,10 @@ func generateRepo(path string) error {
}
data["isBinary"] = isBinary
var lines []string
if !isBinary {
lines, err := o.Lines()
var err error
lines, err = o.Lines()
if err != nil {
return fmt.Errorf("cannot get lines for %q: %w", o.Name, err)
}
@ -248,9 +262,12 @@ func generateRepo(path string) error {
}
file := &CommitFile{
Mode: o.Mode.String(), // ToDo: correctly calculate the mode string
Path: filepath.Join("file", fmt.Sprintf("%s.html", o.Name)),
Name: o.Name,
Mode: o.Mode.String(), // ToDo: correctly calculate the mode string
Path: filepath.Join("file", fmt.Sprintf("%s.html", o.Name)),
Name: o.Name,
Lines: len(lines),
IsBinary: isBinary,
Size: o.Size,
}
files = append(files, file)
@ -260,17 +277,66 @@ func generateRepo(path string) error {
return fmt.Errorf("error while processing tree: %w", iErr)
}
// generate the files index file
// ToDo: bundle execute and write into a function
data := map[string]any{"repoInfo": repoInfo, "files": files}
contents, err := executeTemplate("files", data)
filesData := map[string]any{"repoInfo": repoInfo, "files": files}
filesContents, err := executeTemplate("files", filesData)
if err != nil {
return fmt.Errorf("cannot execute files template for repository %q: %w", repoInfo.Name, err)
}
if err := os.WriteFile(filepath.Join(repoInfo.Name, "files.html"), contents, 0755); err != nil {
if err := os.WriteFile(filepath.Join(repoInfo.Name, "files.html"), filesContents, 0755); err != nil {
return fmt.Errorf("cannot write files contents to \"files.html\": %w", err)
}
// generate the log file
cIter, err := repo.Log(&git.LogOptions{All: true})
if err != nil {
return fmt.Errorf("cannot get git log for repository: %w", err)
}
loglines := []*CommitLog{}
ciErr := cIter.ForEach(func(c *object.Commit) error {
slog.Debug("Processing log commit", "hash", c.Hash)
// ToDo: is this the best way to get the number of files?
fstats, err := c.Stats()
if err != nil {
return fmt.Errorf("cannot get commit stats %s: %w", c.Hash, err)
}
commitLog := &CommitLog{
Hash: c.Hash.String(),
Date: c.Author.When.Format(timeFormat), // ToDo: author when vs commiter when?
Msg: strings.Split(c.Message, "\n")[0],
Author: c.Author.Name,
Files: len(fstats),
}
// ToDo: are there not global commit stats?
for _, fstat := range fstats {
commitLog.Adds += fstat.Addition
commitLog.Dels += fstat.Deletion
}
loglines = append(loglines, commitLog)
return nil
})
if ciErr != nil {
return fmt.Errorf("error while processing log: %w", iErr)
}
logData := map[string]any{"repoInfo": repoInfo, "loglines": loglines}
logContents, err := executeTemplate("log", logData)
if err != nil {
return fmt.Errorf("cannot execute logs template for repository %q: %w", repoInfo.Name, err)
}
if err := os.WriteFile(filepath.Join(repoInfo.Name, "log.html"), logContents, 0755); err != nil {
return fmt.Errorf("cannot write log contents to \"log.html\": %w", err)
}
return nil
}

View file

@ -14,11 +14,15 @@
<table>
<tr>
<td><a href="../"><img src="logo.png" alt="" width="32" height="32" /></a></td>
<td><h1>stagit</h1><span class="desc">static git page generator</span></td>
<td><h1>{{.repoInfo.Name}}</h1><span class="desc">{{.repoInfo.Description}}</span></td>
</tr>
<tr class="url">
<td></td>
<td>git clone <a href="git://git.codemadness.org/stagit">git://git.codemadness.org/stagit</a></td>
<td>
{{if ne .repoInfo.Url ""}}
git clone <a href="{{.repoInfo.Url}}">{{.repoInfo.Url}}</a>
{{end}}
</td>
</tr>
<tr>
<td></td>
@ -45,7 +49,7 @@
<tr>
<td>{{.Mode}}</td>
<td><a href="{{.Path}}">{{.Name}}</a></td>
<td class="num" align="right">{{.Lines}}L</td>
<td class="num" align="right">{{if .IsBinary}}{{.Size}}B{{else}}{{.Lines}}L{{end}}</td>
</tr>
{{end}}
</tbody>

63
templates/log.html.tmpl Normal file
View file

@ -0,0 +1,63 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Log - {{.repoInfo.Name}} - {{.repoInfo.Description}}</title>
<link rel="icon" type="image/png" href="favicon.png" />
<link rel="alternate" type="application/atom+xml" title="frontends Atom Feed" href="atom.xml" />
<link rel="alternate" type="application/atom+xml" title="frontends Atom Feed (tags)" href="tags.xml" />
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<table>
<tr>
<td><a href="../"><img src="logo.png" alt="" width="32" height="32" /></a></td>
<td><h1>{{.repoInfo.Name}}</h1><span class="desc">{{.repoInfo.Description}}</span></td>
</tr>
<tr class="url">
<td></td>
<td>
{{if ne .repoInfo.Url ""}}
git clone <a href="{{.repoInfo.Url}}">{{.repoInfo.Url}}</a>
{{end}}
</td>
</tr>
<tr>
<td></td>
<td>
<a href="log.html">Log</a>
| <a href="files.html">Files</a>
| <a href="refs.html">Refs</a>
| <a href="file/README.html">README</a>
| <a href="file/LICENSE.html">LICENSE</a>
</td>
</tr>
</table>
<hr/>
<div id="content">
<table id="log">
<thead>
<tr>
<td><b>Date</b></td>
<td><b>Commit message</b></td>
<td><b>Author</b></td>
<td class="num" align="right"><b>Files</b></td>
<td class="num" align="right"><b>+</b></td>
<td class="num" align="right"><b>-</b></td>
</tr>
</thead>
<tbody>
{{- range .loglines}}
<tr>
<td>{{.Date}}</td>
<td><a href="commit/{{.Hash}}.html">{{.Msg}}</a></td>
<td>{{.Author}}</td>
<td class="num" align="right">{{.Files}}</td>
<td class="num" align="right">+{{.Adds}}</td>
<td class="num" align="right">-{{.Dels}}</td>
</tr>
{{- end}}
</tbody></table></div>
</body>
</html>