Commit template is halfway through
This commit is contained in:
parent
5cd7dd9dbb
commit
2282cdecfd
6 changed files with 117 additions and 35 deletions
|
@ -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.
|
||||||
|
|
63
gitssg.go
63
gitssg.go
|
@ -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)
|
||||||
|
|
57
templates/commit.html.tmpl
Normal file
57
templates/commit.html.tmpl
Normal 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}} <<a href="mailto:{{.commit.AuthorEmail}}">{{.commit.AuthorEmail}}</a>>
|
||||||
|
<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 <hiltjo@codemadness.org>
|
||||||
|
</a><a href="#h0-0-3" id="h0-0-3" class="i">+(c) 2015-2024 Hiltjo Posthuma <hiltjo@codemadness.org>
|
||||||
|
</a>
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue