diff --git a/README.md b/README.md index 06715d1..2de40a4 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Project heavily inspired by the amazing - [X] Embed templates mechanism. - [ ] Embed style.css -- [ ] Correctly manage relative links. +- [X] Correctly manage relative links. - [ ] Add a base url to avoid relative links if provided. - [X] Generate the index html file for the `index` subcommand. - [X] Generate the log html file for a repository. @@ -23,6 +23,8 @@ Project heavily inspired by the amazing - [ ] Take binary files into account. - [ ] Limit the output for large diffs. Add a "X commits remaining" message if necessary. +- [ ] Generate files in temporal directory and replace the final one + when everything is ready. - [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. diff --git a/gitssg.go b/gitssg.go index ca97c80..4c4b6a7 100644 --- a/gitssg.go +++ b/gitssg.go @@ -9,6 +9,7 @@ import ( "os" "path/filepath" "strings" + "time" "github.com/alecthomas/kong" "github.com/go-git/go-git/v5" @@ -19,7 +20,7 @@ type RepoDir struct { Name string Description string Owner string - LastCommit string + LastCommit time.Time } // ToDo: replace has* with the filename, as it can be bare or .md @@ -41,19 +42,22 @@ type CommitFile struct { Size int64 } -type CommitLog struct { - Hash string - Date string - Msg string - Author string - Files int - Adds int - Dels int +type CommitInfo struct { + Hash string + ParentHash string + Date time.Time + Msg string + AuthorName string + AuthorEmail string + Files int + Adds int + Dels int } //go:embed templates 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{ "inc": func(i int) int { return i + 1 @@ -77,10 +81,17 @@ var funcMap = template.FuncMap{ 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) { path := filepath.Join("templates", fmt.Sprintf("%s.html.tmpl", name)) b, err := embedTmpl.ReadFile(path) @@ -181,7 +192,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.Format(timeFormat) + repoDir.LastCommit = c.Author.When 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) } } - 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) } @@ -323,9 +334,9 @@ func generateRepo(path string) error { return fmt.Errorf("cannot get git log for repository: %w", err) } - loglines := []*CommitLog{} + commits := []*CommitInfo{} 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? 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) } - 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), + commit := &CommitInfo{ + Hash: c.Hash.String(), + Date: c.Author.When, // ToDo: author when vs commiter when? + Msg: c.Message, + AuthorName: c.Author.Name, + AuthorEmail: c.Author.Email, + Files: len(fstats), + } + + if parent, _ := c.Parent(0); parent != nil { + commit.ParentHash = parent.Hash.String() } // ToDo: are there not global commit stats? for _, fstat := range fstats { - commitLog.Adds += fstat.Addition - commitLog.Dels += fstat.Deletion + commit.Adds += fstat.Addition + 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 }) 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") if err := executeTemplateToFile("log", logData, logDstpath); err != nil { return fmt.Errorf("cannot execute template %q to file %q: %w", "file", logDstpath, err) diff --git a/templates/commit.html.tmpl b/templates/commit.html.tmpl new file mode 100644 index 0000000..162d423 --- /dev/null +++ b/templates/commit.html.tmpl @@ -0,0 +1,57 @@ + + + + + + {{.commit.Msg}} - {{.repoInfo.Name}} - {{.repoInfo.Description}} + + + + + + + + + + + + + + + + + + + + +

{{.repoInfo.Name}}

{{.repoInfo.Description}}
+ {{if ne .repoInfo.Url ""}} + git clone {{.repoInfo.Url}} + {{end}} +
+ {{menu .repoInfo .relpath}} +
+
+
+
commit {{.commit.Hash}}
+parent {{.commit.ParentHash}}
+Author: {{.commit.AuthorName}} <{{.commit.AuthorEmail}}>
+Date:   {{timeLongFormat .commit.Date}}
+
+{{.commit.Msg}}
+Diffstat:
+
MLICENSE | 2+-
+
1 file changed, 1 insertion(+), 1 deletion(-)
+        
diff --git a/LICENSE b/LICENSE + @@ -1,6 +1,6 @@ + MIT/X Consortium License + + -(c) 2015-2022 Hiltjo Posthuma <hiltjo@codemadness.org> + +(c) 2015-2024 Hiltjo Posthuma <hiltjo@codemadness.org> + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), +
+
+ + diff --git a/templates/files.html.tmpl b/templates/files.html.tmpl index f482a12..ef8f2b0 100644 --- a/templates/files.html.tmpl +++ b/templates/files.html.tmpl @@ -41,13 +41,13 @@ - {{range .files}} + {{- range .files}} {{.Mode}} {{.Name}} {{if .IsBinary}}{{.Size}}B{{else}}{{.Lines}}L{{end}} - {{end}} + {{- end}} diff --git a/templates/index.html.tmpl b/templates/index.html.tmpl index 3c962b1..ca11e40 100644 --- a/templates/index.html.tmpl +++ b/templates/index.html.tmpl @@ -28,7 +28,7 @@ {{.Name}} {{.Description}} {{.Owner}} - {{.LastCommit}} + {{timeShortFormat .LastCommit}} {{- end}} diff --git a/templates/log.html.tmpl b/templates/log.html.tmpl index fa48b06..a2e02bc 100644 --- a/templates/log.html.tmpl +++ b/templates/log.html.tmpl @@ -44,11 +44,11 @@ - {{- range .loglines}} + {{- range .commits}} - {{.Date}} - {{.Msg}} - {{.Author}} + {{timeShortFormat .Date}} + {{firstLine .Msg}} + {{.AuthorName}} {{.Files}} +{{.Adds}} -{{.Dels}}