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 - [ ] Add a subcommand to dump the embedded templates so they can be
modified. modified.
- [ ] Take binary files into account. - [ ] 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. - [X] Allow to anchor lines.
- [ ] Check if the templates exist on a location and use them if - [ ] Check if the templates exist on a location and use them if
so. Allow to change that location through CLI flags or env vars. so. Allow to change that location through CLI flags or env vars.

View file

@ -9,7 +9,6 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"time"
"github.com/alecthomas/kong" "github.com/alecthomas/kong"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
@ -20,7 +19,7 @@ type RepoDir struct {
Name string Name string
Description string Description string
Owner string Owner string
LastCommit time.Time LastCommit string
} }
type RepoInfo struct { type RepoInfo struct {
@ -33,15 +32,28 @@ type RepoInfo struct {
} }
type CommitFile struct { type CommitFile struct {
Mode string Mode string
Path string Path string
Name string Name string
Lines int 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 //go:embed templates
var embedTmpl embed.FS var embedTmpl embed.FS
var funcMap = template.FuncMap{"inc": func(i int) int { return i + 1 }} 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 // ToDo: add a map function to generate the menu
@ -128,7 +140,7 @@ func generateIndex(args []string) error {
if err != nil { if err != nil {
return fmt.Errorf("cannot get commit %q for repository %q: %w", head.Hash(), dirname, err) 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) repoDirs = append(repoDirs, repoDir)
} }
@ -229,8 +241,10 @@ func generateRepo(path string) error {
} }
data["isBinary"] = isBinary data["isBinary"] = isBinary
var lines []string
if !isBinary { if !isBinary {
lines, err := o.Lines() var err error
lines, err = o.Lines()
if err != nil { if err != nil {
return fmt.Errorf("cannot get lines for %q: %w", o.Name, err) return fmt.Errorf("cannot get lines for %q: %w", o.Name, err)
} }
@ -248,9 +262,12 @@ func generateRepo(path string) error {
} }
file := &CommitFile{ file := &CommitFile{
Mode: o.Mode.String(), // ToDo: correctly calculate the mode string Mode: o.Mode.String(), // ToDo: correctly calculate the mode string
Path: filepath.Join("file", fmt.Sprintf("%s.html", o.Name)), Path: filepath.Join("file", fmt.Sprintf("%s.html", o.Name)),
Name: o.Name, Name: o.Name,
Lines: len(lines),
IsBinary: isBinary,
Size: o.Size,
} }
files = append(files, file) files = append(files, file)
@ -260,17 +277,66 @@ func generateRepo(path string) error {
return fmt.Errorf("error while processing tree: %w", iErr) return fmt.Errorf("error while processing tree: %w", iErr)
} }
// generate the files index file
// ToDo: bundle execute and write into a function // ToDo: bundle execute and write into a function
data := map[string]any{"repoInfo": repoInfo, "files": files} filesData := map[string]any{"repoInfo": repoInfo, "files": files}
contents, err := executeTemplate("files", data) filesContents, err := executeTemplate("files", filesData)
if err != nil { if err != nil {
return fmt.Errorf("cannot execute files template for repository %q: %w", repoInfo.Name, err) 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) 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 return nil
} }

View file

@ -14,11 +14,15 @@
<table> <table>
<tr> <tr>
<td><a href="../"><img src="logo.png" alt="" width="32" height="32" /></a></td> <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>
<tr class="url"> <tr class="url">
<td></td> <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>
<tr> <tr>
<td></td> <td></td>
@ -45,7 +49,7 @@
<tr> <tr>
<td>{{.Mode}}</td> <td>{{.Mode}}</td>
<td><a href="{{.Path}}">{{.Name}}</a></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> </tr>
{{end}} {{end}}
</tbody> </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>