Commit template is halfway through

This commit is contained in:
Miguel de la Cruz 2024-06-30 12:09:40 +02:00
parent 5cd7dd9dbb
commit 2282cdecfd
6 changed files with 117 additions and 35 deletions

View file

@ -9,7 +9,7 @@ Project heavily inspired by the amazing
- [X] Embed templates mechanism. - [X] Embed templates mechanism.
- [ ] Embed style.css - [ ] Embed style.css
- [ ] Correctly manage relative links. - [X] Correctly manage relative links.
- [ ] Add a base url to avoid relative links if provided. - [ ] Add a base url to avoid relative links if provided.
- [X] Generate the index html file for the `index` subcommand. - [X] Generate the index html file for the `index` subcommand.
- [X] Generate the log html file for a repository. - [X] Generate the log html file for a repository.
@ -23,6 +23,8 @@ Project heavily inspired by the amazing
- [ ] Take binary files into account. - [ ] Take binary files into account.
- [ ] Limit the output for large diffs. Add a "X commits remaining" - [ ] Limit the output for large diffs. Add a "X commits remaining"
message if necessary. message if necessary.
- [ ] Generate files in temporal directory and replace the final one
when everything is ready.
- [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,6 +9,7 @@ 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"
@ -19,7 +20,7 @@ type RepoDir struct {
Name string Name string
Description string Description string
Owner string Owner string
LastCommit string LastCommit time.Time
} }
// ToDo: replace has* with the filename, as it can be bare or .md // ToDo: replace has* with the filename, as it can be bare or .md
@ -41,11 +42,13 @@ type CommitFile struct {
Size int64 Size int64
} }
type CommitLog struct { type CommitInfo struct {
Hash string Hash string
Date string ParentHash string
Date time.Time
Msg string Msg string
Author string AuthorName string
AuthorEmail string
Files int Files int
Adds int Adds int
Dels int Dels int
@ -53,7 +56,8 @@ type CommitLog struct {
//go:embed templates //go:embed templates
var embedTmpl embed.FS var embedTmpl embed.FS
var timeFormat = "2006-01-02 15:04" var timeShortFormatStr = "2006-01-02 15:04"
var timeLongFormatStr = time.RFC1123
var funcMap = template.FuncMap{ var funcMap = template.FuncMap{
"inc": func(i int) int { "inc": func(i int) int {
return i + 1 return i + 1
@ -77,10 +81,17 @@ var funcMap = template.FuncMap{
return template.HTML(menu) return template.HTML(menu)
}, },
"firstLine": func(msg string) string {
return strings.Split(msg, "\n")[0]
},
"timeShortFormat": func(t time.Time) string {
return t.Format(timeShortFormatStr)
},
"timeLongFormat": func(t time.Time) string {
return t.Format(timeLongFormatStr)
},
} }
// ToDo: add a map function to generate the menu
func executeTemplate(name string, data any) ([]byte, error) { func executeTemplate(name string, data any) ([]byte, error) {
path := filepath.Join("templates", fmt.Sprintf("%s.html.tmpl", name)) path := filepath.Join("templates", fmt.Sprintf("%s.html.tmpl", name))
b, err := embedTmpl.ReadFile(path) b, err := embedTmpl.ReadFile(path)
@ -181,7 +192,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.Format(timeFormat) repoDir.LastCommit = c.Author.When
repoDirs = append(repoDirs, repoDir) repoDirs = append(repoDirs, repoDir)
} }
@ -212,7 +223,7 @@ func generateRepo(path string) error {
return fmt.Errorf("cannot delete directory for %q: %w", repoInfo.Name, err) return fmt.Errorf("cannot delete directory for %q: %w", repoInfo.Name, err)
} }
} }
if err := os.Mkdir(repoInfo.Name, 0755); err != nil { if err := os.MkdirAll(filepath.Join(repoInfo.Name, "commit"), 0755); err != nil {
return fmt.Errorf("cannot create directory for %q: %w", repoInfo.Name, err) return fmt.Errorf("cannot create directory for %q: %w", repoInfo.Name, err)
} }
@ -323,9 +334,9 @@ func generateRepo(path string) error {
return fmt.Errorf("cannot get git log for repository: %w", err) return fmt.Errorf("cannot get git log for repository: %w", err)
} }
loglines := []*CommitLog{} commits := []*CommitInfo{}
ciErr := cIter.ForEach(func(c *object.Commit) error { ciErr := cIter.ForEach(func(c *object.Commit) error {
slog.Debug("Processing log commit", "hash", c.Hash) slog.Debug("Processing commit", "hash", c.Hash)
// ToDo: is this the best way to get the number of files? // ToDo: is this the best way to get the number of files?
fstats, err := c.Stats() fstats, err := c.Stats()
@ -333,29 +344,41 @@ func generateRepo(path string) error {
return fmt.Errorf("cannot get commit stats %s: %w", c.Hash, err) return fmt.Errorf("cannot get commit stats %s: %w", c.Hash, err)
} }
commitLog := &CommitLog{ commit := &CommitInfo{
Hash: c.Hash.String(), Hash: c.Hash.String(),
Date: c.Author.When.Format(timeFormat), // ToDo: author when vs commiter when? Date: c.Author.When, // ToDo: author when vs commiter when?
Msg: strings.Split(c.Message, "\n")[0], Msg: c.Message,
Author: c.Author.Name, AuthorName: c.Author.Name,
AuthorEmail: c.Author.Email,
Files: len(fstats), Files: len(fstats),
} }
if parent, _ := c.Parent(0); parent != nil {
commit.ParentHash = parent.Hash.String()
}
// ToDo: are there not global commit stats? // ToDo: are there not global commit stats?
for _, fstat := range fstats { for _, fstat := range fstats {
commitLog.Adds += fstat.Addition commit.Adds += fstat.Addition
commitLog.Dels += fstat.Deletion commit.Dels += fstat.Deletion
} }
loglines = append(loglines, commitLog) commits = append(commits, commit)
// generate commit file
data := map[string]any{"repoInfo": repoInfo, "commit": commit, "relpath": "../"}
dstpath := filepath.Join(repoInfo.Name, "commit", fmt.Sprintf("%s.html", commit.Hash))
if err := executeTemplateToFile("commit", data, dstpath); err != nil {
return fmt.Errorf("cannot execute template %q to file %q: %w", "commit", dstpath, err)
}
return nil return nil
}) })
if ciErr != nil { if ciErr != nil {
return fmt.Errorf("error while processing log: %w", iErr) return fmt.Errorf("error while processing log: %w", ciErr)
} }
logData := map[string]any{"repoInfo": repoInfo, "loglines": loglines, "relpath": ""} logData := map[string]any{"repoInfo": repoInfo, "commits": commits, "relpath": ""}
logDstpath := filepath.Join(repoInfo.Name, "log.html") logDstpath := filepath.Join(repoInfo.Name, "log.html")
if err := executeTemplateToFile("log", logData, logDstpath); err != nil { if err := executeTemplateToFile("log", logData, logDstpath); err != nil {
return fmt.Errorf("cannot execute template %q to file %q: %w", "file", logDstpath, err) return fmt.Errorf("cannot execute template %q to file %q: %w", "file", logDstpath, err)

View file

@ -0,0 +1,57 @@
<!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>{{.commit.Msg}} - {{.repoInfo.Name}} - {{.repoInfo.Description}}
</title>
<link rel="icon" type="image/png" href="{{.relpath}}favicon.png" />
<link rel="alternate" type="application/atom+xml" title="stagit Atom Feed" href="{{.relpath}}atom.xml" />
<link rel="alternate" type="application/atom+xml" title="stagit Atom Feed (tags)" href="{{.relpath}}tags.xml" />
<link rel="stylesheet" type="text/css" href="{{.relpath}}style.css" />
</head>
<body>
<table>
<tr>
<td><a href="{{.relpath}}../"><img src="{{.relpath}}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>
{{menu .repoInfo .relpath}}
</td>
</tr>
</table>
<hr/>
<div id="content">
<pre><b>commit</b> <a href="{{.relpath}}commit/{{.commit.Hash}}.html">{{.commit.Hash}}</a>
<b>parent</b> <a href="{{.relpath}}commit/{{.commit.ParentHash}}.html">{{.commit.ParentHash}}</a>
<b>Author:</b> {{.commit.AuthorName}} &lt;<a href="mailto:{{.commit.AuthorEmail}}">{{.commit.AuthorEmail}}</a>&gt;
<b>Date:</b> {{timeLongFormat .commit.Date}}
{{.commit.Msg}}
<b>Diffstat:</b>
<table><tr><td class="M">M</td><td><a href="#h0">LICENSE</a></td><td> | </td><td class="num">2</td><td><span class="i">+</span><span class="d">-</span></td></tr></table></pre>
<pre>1 file changed, 1 insertion(+), 1 deletion(-)
<hr/><b>diff --git a/<a id="h0" href="../file/LICENSE.html">LICENSE</a> b/<a href="../file/LICENSE.html">LICENSE</a></b>
<a href="#h0-0" id="h0-0" class="h">@@ -1,6 +1,6 @@
</a> MIT/X Consortium License
<a href="#h0-0-2" id="h0-0-2" class="d">-(c) 2015-2022 Hiltjo Posthuma &lt;hiltjo@codemadness.org&gt;
</a><a href="#h0-0-3" id="h0-0-3" class="i">+(c) 2015-2024 Hiltjo Posthuma &lt;hiltjo@codemadness.org&gt;
</a>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the &quot;Software&quot;),
</pre>
</div>
</body>
</html>

View file

@ -41,13 +41,13 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{{range .files}} {{- range .files}}
<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">{{if .IsBinary}}{{.Size}}B{{else}}{{.Lines}}L{{end}}</td> <td class="num" align="right">{{if .IsBinary}}{{.Size}}B{{else}}{{.Lines}}L{{end}}</td>
</tr> </tr>
{{end}} {{- end}}
</tbody> </tbody>
</table> </table>
</div> </div>

View file

@ -28,7 +28,7 @@
<td><a href="{{.Name}}/log.html">{{.Name}}</a></td> <td><a href="{{.Name}}/log.html">{{.Name}}</a></td>
<td>{{.Description}}</td> <td>{{.Description}}</td>
<td>{{.Owner}}</td> <td>{{.Owner}}</td>
<td>{{.LastCommit}}</td> <td>{{timeShortFormat .LastCommit}}</td>
</tr> </tr>
{{- end}} {{- end}}
</tbody> </tbody>

View file

@ -44,11 +44,11 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{{- range .loglines}} {{- range .commits}}
<tr> <tr>
<td>{{.Date}}</td> <td>{{timeShortFormat .Date}}</td>
<td><a href="commit/{{.Hash}}.html">{{.Msg}}</a></td> <td><a href="commit/{{.Hash}}.html">{{firstLine .Msg}}</a></td>
<td>{{.Author}}</td> <td>{{.AuthorName}}</td>
<td class="num" align="right">{{.Files}}</td> <td class="num" align="right">{{.Files}}</td>
<td class="num" align="right">+{{.Adds}}</td> <td class="num" align="right">+{{.Adds}}</td>
<td class="num" align="right">-{{.Dels}}</td> <td class="num" align="right">-{{.Dels}}</td>