Fixing ordering of commits on details page, refactor pass. - staticgit - A git static site generator, the site you are viewing now!
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
---
(DIR) commit e3b9e35e373c00b591b8907ce7d7c1d3d7d2ce71
(DIR) parent 2c17ce4ce5c99e093bcc742c8815e7ad64e3b233
(HTM) Author: Jay Scott <me@jay.scot>
Date: Sun, 14 Jul 2024 20:58:56 +0100
Fixing ordering of commits on details page, refactor pass.
Diffstat:
M main.go | 280 ++++++++++++++++----------------
1 file changed, 140 insertions(+), 140 deletions(-)
---
(DIR) diff --git a/main.go b/main.go
@@ -16,23 +16,23 @@ import (
"github.com/go-git/go-git/v5/plumbing/object"
)
-type CommitInfo struct {
+type Commit struct {
Hash string
Author string
Date string
- Message string
+ Msg string
Added int
Removed int
}
-type RepoInfo struct {
- Name string
- Description string
- LastCommitTime time.Time
+type Repo struct {
+ Name string
+ Desc string
+ LastMod time.Time
}
const (
- base = `
+ baseHtml = `
<!DOCTYPE html>
<html lang="en">
<head>
@@ -72,7 +72,7 @@ const (
</html>
`
- details = `
+ detailHtml = `
{{define "content"}}
<pre>{{.ReadmeContent}}</pre>
@@ -92,7 +92,7 @@ const (
{{range .Commits}}
<tr>
<td>{{.Date}}</td>
- <td>{{.Message}}</td>
+ <td>{{.Msg}}</td>
<td>{{.Author}}</td>
<td>{{.Hash}}</td>
<td>+{{.Added}}</td>
@@ -111,7 +111,7 @@ const (
{{end}}
`
- index = `
+ indexHtml = `
{{define "content"}}
<table>
<thead>
@@ -125,8 +125,8 @@ const (
{{range .Repos}}
<tr>
<td><a href="{{.Name}}/index.html">{{.Name}}</a></td>
- <td>{{.Description}}</td>
- <td>{{.LastCommitTime.Format "2006-01-02 15:04:05"}}</td>
+ <td>{{.Desc}}</td>
+ <td>{{.LastMod.Format "2006-01-02 15:04:05"}}</td>
</tr>
{{end}}
</tbody>
@@ -137,64 +137,64 @@ const (
var (
templates = map[string]*template.Template{
- "index": template.Must(template.New("base").Parse(base + index)),
- "details": template.Must(template.New("base").Parse(base + details)),
+ "index": template.Must(template.New("base").Parse(baseHtml + indexHtml)),
+ "details": template.Must(template.New("base").Parse(baseHtml + detailHtml)),
}
- reposPath string
- ignoreDirs map[string]bool
- outputRoot string
- commitLimit int
+ repoDir string
+ ignoreDirs map[string]bool
+ outDir string
+ maxCommits int
)
-func generateIndex(repoInfos []RepoInfo) error {
- sort.Slice(repoInfos, func(i, j int) bool {
- return repoInfos[i].LastCommitTime.After(repoInfos[j].LastCommitTime)
+func genIndex(repos []Repo) error {
+ sort.Slice(repos, func(i, j int) bool {
+ return repos[i].LastMod.After(repos[j].LastMod)
})
- indexOutputPath := filepath.Join(outputRoot, "index.html")
+ path := filepath.Join(outDir, "index.html")
- indexFile, err := os.Create(indexOutputPath)
+ f, err := os.Create(path)
if err != nil {
- return fmt.Errorf("failed to create index HTML file: %w", err)
+ return fmt.Errorf("create index HTML: %w", err)
}
- defer indexFile.Close()
+ defer f.Close()
- return templates["index"].Execute(indexFile, struct {
+ return templates["index"].Execute(f, struct {
Title string
- Repos []RepoInfo
+ Repos []Repo
}{
Title: "Repos for days!",
- Repos: repoInfos,
+ Repos: repos,
})
}
-func generateRepo(repoName, repoPath, outputDir string) error {
- repo, err := git.PlainOpen(repoPath)
+func genRepo(name, path, out string) error {
+ repo, err := git.PlainOpen(path)
if err != nil {
- return fmt.Errorf("failed to open git repository: %w", err)
+ return fmt.Errorf("open git repo: %w", err)
}
- readme, err := getReadme(repoPath)
+ readme, err := readme(path)
if err != nil {
- return fmt.Errorf("failed to get README: %w", err)
+ return fmt.Errorf("get README: %w", err)
}
- commits, err := getCommits(repo)
+ cs, err := commits(repo)
if err != nil {
- return fmt.Errorf("failed to get commit history: %w", err)
+ return fmt.Errorf("get commits: %w", err)
}
- files, err := getFiles(repo)
+ fs, err := files(repo)
if err != nil {
- return fmt.Errorf("failed to get repository files: %w", err)
+ return fmt.Errorf("get files: %w", err)
}
- outputPath := filepath.Join(outputDir, "index.html")
+ path = filepath.Join(out, "index.html")
- f, err := os.Create(outputPath)
+ f, err := os.Create(path)
if err != nil {
- return fmt.Errorf("failed to create details HTML file: %w", err)
+ return fmt.Errorf("create details HTML: %w", err)
}
defer f.Close()
@@ -202,130 +202,130 @@ func generateRepo(repoName, repoPath, outputDir string) error {
Title string
ReadmeContent string
Files []string
- Commits []CommitInfo
+ Commits []Commit
}{
- Title: "git clone git@git.jay.scot:" + repoName,
+ Title: "git clone git@git.jay.scot:" + name,
ReadmeContent: readme,
- Files: files,
- Commits: commits,
+ Files: fs,
+ Commits: cs,
})
}
-func getCommits(repo *git.Repository) ([]CommitInfo, error) {
- commitIter, err := repo.CommitObjects()
+func commits(repo *git.Repository) ([]Commit, error) {
+ iter, err := repo.CommitObjects()
if err != nil {
- return nil, fmt.Errorf("failed to get commit objects: %w", err)
+ return nil, fmt.Errorf("get commit objects: %w", err)
}
- var commitHistory []CommitInfo
+ var cs []Commit
count := 0
- reachedLimit := false
+ limit := false
- err = commitIter.ForEach(func(c *object.Commit) error {
- if reachedLimit {
+ err = iter.ForEach(func(c *object.Commit) error {
+ if limit {
return nil
}
stats, err := c.Stats()
if err != nil {
- return fmt.Errorf("failed to get commit stats: %w", err)
+ return fmt.Errorf("get commit stats: %w", err)
}
- added, removed := 0, 0
+ add, del := 0, 0
for _, stat := range stats {
- added += stat.Addition
- removed += stat.Deletion
+ add += stat.Addition
+ del += stat.Deletion
}
- commitHistory = append(commitHistory, CommitInfo{
+ cs = append(cs, Commit{
Hash: c.Hash.String()[:7],
Author: c.Author.Name,
Date: c.Author.When.Format("02 Jan 2006 15:04:05"),
- Message: strings.Split(c.Message, "\n")[0],
- Added: added,
- Removed: removed,
+ Msg: strings.Split(c.Message, "\n")[0],
+ Added: add,
+ Removed: del,
})
count++
- if count >= commitLimit {
- reachedLimit = true
+ if count >= maxCommits {
+ limit = true
}
return nil
})
if err != nil {
- return nil, fmt.Errorf("failed to iterate over commits: %w", err)
+ return nil, fmt.Errorf("iterate commits: %w", err)
}
- return commitHistory, nil
-}
+ sort.Slice(cs, func(i, j int) bool {
+ timeI, _ := time.Parse("02 Jan 2006 15:04:05", cs[i].Date)
+ timeJ, _ := time.Parse("02 Jan 2006 15:04:05", cs[j].Date)
+ return timeI.After(timeJ)
+ })
-func getDescription(repoPath string) string {
- descPath := filepath.Join(repoPath, "description")
- description, _ := os.ReadFile(descPath)
- return strings.TrimSpace(string(description))
+ return cs, nil
}
-func getFiles(repo *git.Repository) ([]string, error) {
+func files(repo *git.Repository) ([]string, error) {
ref, err := repo.Head()
if err != nil {
- return nil, fmt.Errorf("failed to get HEAD reference: %w", err)
+ return nil, fmt.Errorf("get HEAD: %w", err)
}
commit, err := repo.CommitObject(ref.Hash())
if err != nil {
- return nil, fmt.Errorf("failed to get commit object: %w", err)
+ return nil, fmt.Errorf("get commit object: %w", err)
}
tree, err := commit.Tree()
if err != nil {
- return nil, fmt.Errorf("failed to get tree: %w", err)
+ return nil, fmt.Errorf("get tree: %w", err)
}
- var files []string
+ var fs []string
err = tree.Files().ForEach(func(f *object.File) error {
- files = append(files, f.Name)
+ fs = append(fs, f.Name)
return nil
})
if err != nil {
- return nil, fmt.Errorf("failed to iterate over files: %w", err)
+ return nil, fmt.Errorf("iterate files: %w", err)
}
- sort.Strings(files)
- return files, nil
+ sort.Strings(fs)
+ return fs, nil
}
-func getReadme(repoPath string) (string, error) {
- readmeFiles := []string{"README.md", "README.txt", "README"}
- repo, err := git.PlainOpen(repoPath)
+func readme(path string) (string, error) {
+ names := []string{"README.md", "README.txt", "README"}
+ repo, err := git.PlainOpen(path)
if err != nil {
- return "", fmt.Errorf("failed to open git repository: %w", err)
+ return "", fmt.Errorf("open git repo: %w", err)
}
- headRef, err := repo.Head()
+ ref, err := repo.Head()
if err != nil {
- return "", fmt.Errorf("failed to get HEAD reference: %w", err)
+ return "", fmt.Errorf("get HEAD: %w", err)
}
- commit, err := repo.CommitObject(headRef.Hash())
+ commit, err := repo.CommitObject(ref.Hash())
if err != nil {
- return "", fmt.Errorf("failed to get commit object: %w", err)
+ return "", fmt.Errorf("get commit object: %w", err)
}
tree, err := commit.Tree()
if err != nil {
- return "", fmt.Errorf("failed to get tree: %w", err)
+ return "", fmt.Errorf("get tree: %w", err)
}
- for _, fileName := range readmeFiles {
- file, err := tree.File(fileName)
+ for _, name := range names {
+ file, err := tree.File(name)
if err != nil {
continue
}
content, err := file.Contents()
if err != nil {
- return "", fmt.Errorf("failed to read file contents: %w", err)
+ return "", fmt.Errorf("read file contents: %w", err)
}
return content, nil
@@ -334,100 +334,100 @@ func getReadme(repoPath string) (string, error) {
return "No README found!", nil
}
-func getRepo(repoPath string) (RepoInfo, error) {
- repo, err := git.PlainOpen(repoPath)
+func repoInfo(path string) (Repo, error) {
+ repo, err := git.PlainOpen(path)
if err != nil {
- return RepoInfo{}, fmt.Errorf("failed to open repository: %w", err)
+ return Repo{}, fmt.Errorf("open repo: %w", err)
}
- headRef, err := repo.Head()
+ ref, err := repo.Head()
if err != nil {
- return RepoInfo{}, fmt.Errorf("failed to get HEAD reference: %w", err)
+ return Repo{}, fmt.Errorf("get HEAD: %w", err)
}
- commit, err := repo.CommitObject(headRef.Hash())
+ commit, err := repo.CommitObject(ref.Hash())
if err != nil {
- return RepoInfo{}, fmt.Errorf("failed to get commit object: %w", err)
+ return Repo{}, fmt.Errorf("get commit object: %w", err)
}
- description := getDescription(repoPath)
+ content, _ := os.ReadFile(filepath.Join(path, "description"))
- return RepoInfo{
- Name: filepath.Base(repoPath),
- Description: description,
- LastCommitTime: commit.Committer.When,
+ return Repo{
+ Name: filepath.Base(path),
+ Desc: strings.TrimSpace(string(content)),
+ LastMod: commit.Committer.When,
}, nil
}
-func parseIgnored(ignoreDirs string) map[string]bool {
- ignoreMap := make(map[string]bool)
- for _, dir := range strings.Split(ignoreDirs, ",") {
- if trimmedDir := strings.TrimSpace(dir); trimmedDir != "" {
- ignoreMap[trimmedDir] = true
+func ignoreList(dirs string) map[string]bool {
+ ignore := make(map[string]bool)
+ for _, dir := range strings.Split(dirs, ",") {
+ if d := strings.TrimSpace(dir); d != "" {
+ ignore[d] = true
}
}
- return ignoreMap
+ return ignore
}
-func processRepos() error {
- repos, err := os.ReadDir(reposPath)
+func build() error {
+ dirs, err := os.ReadDir(repoDir)
if err != nil {
- return fmt.Errorf("failed to read repos directory: %w", err)
+ return fmt.Errorf("read repos dir: %w", err)
}
var wg sync.WaitGroup
- repoInfosChan := make(chan RepoInfo, len(repos))
- errorsChan := make(chan error, len(repos))
+ repoChan := make(chan Repo, len(dirs))
+ errChan := make(chan error, len(dirs))
- for _, r := range repos {
- if r.IsDir() && !ignoreDirs[r.Name()] {
+ for _, d := range dirs {
+ if d.IsDir() && !ignoreDirs[d.Name()] {
wg.Add(1)
- go func(r os.DirEntry) {
+ go func(d os.DirEntry) {
defer wg.Done()
- repoPath := filepath.Join(reposPath, r.Name())
- repoInfo, err := getRepo(repoPath)
+ path := filepath.Join(repoDir, d.Name())
+ repo, err := repoInfo(path)
if err != nil {
- errorsChan <- fmt.Errorf("failed to get info for repo %s: %w", r.Name(), err)
+ errChan <- fmt.Errorf("get info for %s: %w", d.Name(), err)
return
}
- repoInfosChan <- repoInfo
+ repoChan <- repo
- outputDir := filepath.Join(outputRoot, r.Name())
- if err := os.MkdirAll(outputDir, 0755); err != nil {
- errorsChan <- fmt.Errorf("failed to create output directory for repo %s: %w", r.Name(), err)
+ out := filepath.Join(outDir, d.Name())
+ if err := os.MkdirAll(out, 0755); err != nil {
+ errChan <- fmt.Errorf("create dir for %s: %w", d.Name(), err)
return
}
- if err := generateRepo(r.Name(), repoPath, outputDir); err != nil {
- errorsChan <- fmt.Errorf("failed to process repo %s: %w", r.Name(), err)
+ if err := genRepo(d.Name(), path, out); err != nil {
+ errChan <- fmt.Errorf("process %s: %w", d.Name(), err)
}
- }(r)
+ }(d)
}
}
go func() {
wg.Wait()
- close(repoInfosChan)
- close(errorsChan)
+ close(repoChan)
+ close(errChan)
}()
- var repoInfos []RepoInfo
- for repoInfo := range repoInfosChan {
- repoInfos = append(repoInfos, repoInfo)
+ var repos []Repo
+ for repo := range repoChan {
+ repos = append(repos, repo)
}
- for err := range errorsChan {
+ for err := range errChan {
fmt.Println(err)
}
- return generateIndex(repoInfos)
+ return genIndex(repos)
}
func main() {
- flag.StringVar(&reposPath, "p", "", "Path to the git repositories (required)")
- flag.StringVar(&outputRoot, "o", ".", "Root path where output directories will be created")
- flag.IntVar(&commitLimit, "c", 100, "Limit for the number of commits to display (default 100)")
- ignoreFlag := flag.String("i", "", "Directories to ignore (comma-separated)")
+ flag.StringVar(&repoDir, "p", "", "Path to git repos (required)")
+ flag.StringVar(&outDir, "o", ".", "Root path for output")
+ flag.IntVar(&maxCommits, "c", 100, "Max commits to display (default 100)")
+ ignore := flag.String("i", "", "Dirs to ignore (comma-separated)")
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: %s [options]\n\n", os.Args[0])
@@ -439,14 +439,14 @@ func main() {
flag.Parse()
- if reposPath == "" {
+ if repoDir == "" {
flag.Usage()
os.Exit(1)
}
- ignoreDirs = parseIgnored(*ignoreFlag)
+ ignoreDirs = ignoreList(*ignore)
- if err := processRepos(); err != nil {
- log.Fatalf("Error processing repositories: %v", err)
+ if err := build(); err != nil {
+ log.Fatalf("Error building site: %v", err)
}
}