diff --git a/README.md b/README.md index 5545309..9b1132a 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/gitssg.go b/gitssg.go index 8d1c000..7380b68 100644 --- a/gitssg.go +++ b/gitssg.go @@ -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 } diff --git a/templates/files.html.tmpl b/templates/files.html.tmpl index 123bfe0..1477a15 100644 --- a/templates/files.html.tmpl +++ b/templates/files.html.tmpl @@ -14,11 +14,15 @@ - + - + @@ -45,7 +49,7 @@ - + {{end}} diff --git a/templates/log.html.tmpl b/templates/log.html.tmpl new file mode 100644 index 0000000..26e4666 --- /dev/null +++ b/templates/log.html.tmpl @@ -0,0 +1,63 @@ + + + + + + Log - {{.repoInfo.Name}} - {{.repoInfo.Description}} + + + + + + +

stagit

static git page generator

{{.repoInfo.Name}}

{{.repoInfo.Description}}
git clone git://git.codemadness.org/stagit + {{if ne .repoInfo.Url ""}} + git clone {{.repoInfo.Url}} + {{end}} +
{{.Mode}} {{.Name}}{{.Lines}}L{{if .IsBinary}}{{.Size}}B{{else}}{{.Lines}}L{{end}}
+ + + + + + + + + + + + +

{{.repoInfo.Name}}

{{.repoInfo.Description}}
+ {{if ne .repoInfo.Url ""}} + git clone {{.repoInfo.Url}} + {{end}} +
+ Log + | Files + | Refs + | README + | LICENSE +
+
+
+ + + + + + + + + + + + + {{- range .loglines}} + + + + + + + + + {{- end}} +
DateCommit messageAuthorFiles+-
{{.Date}}{{.Msg}}{{.Author}}{{.Files}}+{{.Adds}}-{{.Dels}}
+ +