diff --git a/README.md b/README.md index 2de40a4..4ce729e 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ 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. Add a "X commits remaining" +- [X] 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. diff --git a/cmd.go b/cmd.go index 07856d8..5d7ede2 100644 --- a/cmd.go +++ b/cmd.go @@ -14,7 +14,7 @@ type repoCmd struct { } func (r *repoCmd) Run() error { - return generateRepo(r.Path) + return generateRepo(r.Path, r.LogLimit) } var cli struct { diff --git a/gitssg.go b/gitssg.go index 4c4b6a7..2e75034 100644 --- a/gitssg.go +++ b/gitssg.go @@ -3,8 +3,10 @@ package main import ( "bytes" "embed" + "errors" "fmt" "html/template" + "io" "log/slog" "os" "path/filepath" @@ -42,6 +44,14 @@ type CommitFile struct { Size int64 } +type FileStats struct { + Name string + Mode string // ToDo: is the name correct here? + Adds int + Dels int + Total int +} + type CommitInfo struct { Hash string ParentHash string @@ -52,6 +62,7 @@ type CommitInfo struct { Files int Adds int Dels int + FileStats []*FileStats } //go:embed templates @@ -90,6 +101,9 @@ var funcMap = template.FuncMap{ "timeLongFormat": func(t time.Time) string { return t.Format(timeLongFormatStr) }, + "repeatStr": func(s string, n int) string { + return strings.Repeat(s, n) + }, } func executeTemplate(name string, data any) ([]byte, error) { @@ -205,8 +219,8 @@ func generateIndex(args []string) error { return nil } -func generateRepo(path string) error { - slog.Debug("Generating repository", "path", path) +func generateRepo(path string, logLimit int) error { + slog.Debug("Generating repository", "path", path, "logLimit", logLimit) repoInfo := &RepoInfo{Name: strings.TrimSuffix(filepath.Base(path), ".git")} @@ -321,7 +335,6 @@ func generateRepo(path string) error { } // generate the files index file - // ToDo: bundle execute and write into a function filesData := map[string]any{"repoInfo": repoInfo, "files": files, "relpath": ""} filesDstpath := filepath.Join(repoInfo.Name, "files.html") if err := executeTemplateToFile("files", filesData, filesDstpath); err != nil { @@ -334,23 +347,52 @@ func generateRepo(path string) error { return fmt.Errorf("cannot get git log for repository: %w", err) } + i := 0 + remaining := 0 commits := []*CommitInfo{} - ciErr := cIter.ForEach(func(c *object.Commit) error { + for { + i++ + c, err := cIter.Next() + if errors.Is(err, io.EOF) { + break + } + if err != nil { + return fmt.Errorf("cannot get next commit while processing log: %w", err) + } + slog.Debug("Processing commit", "hash", c.Hash) + if i > logLimit { + remaining++ + slog.Debug("Limit reached while processing log", "iteration", i, "remaining", remaining) + continue + } + // 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) } + fileStats := make([]*FileStats, len(fstats)) + for i, fs := range fstats { + fileStats[i] = &FileStats{ + Name: fs.Name, + Mode: "", + Adds: fs.Addition, + Dels: fs.Deletion, + Total: fs.Addition + fs.Deletion, + } + } + 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), + Files: len(fstats), // ToDo: call len on FileStats + FileStats: fileStats, } if parent, _ := c.Parent(0); parent != nil { @@ -371,14 +413,14 @@ func generateRepo(path string) error { 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", ciErr) } - logData := map[string]any{"repoInfo": repoInfo, "commits": commits, "relpath": ""} + logData := map[string]any{ + "repoInfo": repoInfo, + "commits": commits, + "relpath": "", + "remaining": remaining, + } 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 index 30f0c22..61caf92 100644 --- a/templates/commit.html.tmpl +++ b/templates/commit.html.tmpl @@ -41,20 +41,15 @@ {{.commit.Msg}} Diffstat: + {{range $i, $fs := .commit.FileStats}} - - + + - - - - - - - - - + + + {{end}}
Mstagit-index.c{{$fs.Mode}}{{$fs.Name}} | 2+-
Mstagit.c | 2+-{{$fs.Total}}{{if gt $fs.Adds 0}}{{repeatStr "+" $fs.Adds}}{{end}}{{if gt $fs.Dels 0}}{{repeatStr "-" $fs.Dels}}{{end}}
{{.commit.Files}} file{{if ne .commit.Files 1}}s{{end}} changed, {{.commit.Adds}} insertion{{if ne .commit.Adds 1}}s{{end}}(+), {{.commit.Dels}} deletion{{if ne .commit.Dels 1}}s{{end}}(-)
 
diff --git a/stagit-index.c b/stagit-index.c @@ -179,7 +179,7 @@ main(int argc, char *argv[]) diff --git a/templates/log.html.tmpl b/templates/log.html.tmpl index a2e02bc..2708b47 100644 --- a/templates/log.html.tmpl +++ b/templates/log.html.tmpl @@ -54,6 +54,9 @@ -{{.Dels}} {{- end}} + {{if ne .remaining 0}} + {{.remaining}} more commit{{if ne .remaining 1}}s{{end}} remaining, fetch the repository + {{end}}