summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Medvedev <anton@medv.io>2025-12-07 16:56:52 +0100
committerAnton Medvedev <anton@medv.io>2025-12-07 16:56:52 +0100
commit1441fb29d93481f7bea76bbfa2a9f289ed1ac4f0 (patch)
tree6d01f974638c519780406f67158c9160cf06e7cc
parent20a5d07b2a4620ace14c6a5f622ca45e27f9c20d (diff)
Refactor code by introducing `Ref` type
-rw-r--r--blob.go10
-rw-r--r--branches.go8
-rw-r--r--commit.go2
-rw-r--r--commits_list.go4
-rw-r--r--index.go4
-rw-r--r--list.go4
-rw-r--r--main.go12
-rw-r--r--pkg/git/git.go16
-rw-r--r--pkg/git/types.go24
-rw-r--r--pkg/git/utils.go15
-rw-r--r--pkg/git/utils_test.go24
-rw-r--r--readme.go9
-rw-r--r--utils.go16
-rw-r--r--utils_test.go31
14 files changed, 102 insertions, 77 deletions
diff --git a/blob.go b/blob.go
index 57f75c6..5da7944 100644
--- a/blob.go
+++ b/blob.go
@@ -57,7 +57,7 @@ func generateBlobs(files []git.Blob, params Params) error {
errCh := make(chan error, 1)
var wg sync.WaitGroup
- p := progress_bar.NewProgressBar("blobs for "+string(params.Ref), len(files))
+ p := progress_bar.NewProgressBar("blobs for "+params.Ref.Ref(), len(files))
workerFn := func() {
defer wg.Done()
@@ -98,7 +98,7 @@ func generateBlobs(files []git.Blob, params Params) error {
content = string(data)
}
- outPath := filepath.Join(params.OutputDir, "blob", string(params.Ref), blob.Path) + ".html"
+ outPath := filepath.Join(params.OutputDir, "blob", params.Ref.DirName(), blob.Path) + ".html"
if err := os.MkdirAll(filepath.Dir(outPath), 0o755); check(err) {
return
}
@@ -127,7 +127,7 @@ func generateBlobs(files []git.Blob, params Params) error {
b.String(),
blob.Path,
rootHref,
- string(params.Ref),
+ params.Ref.DirName(),
dirsSet,
filesSet,
)
@@ -170,7 +170,7 @@ func generateBlobs(files []git.Blob, params Params) error {
} else if isImg {
- rawPath := filepath.Join(params.OutputDir, "raw", string(params.Ref), blob.Path)
+ rawPath := filepath.Join(params.OutputDir, "raw", params.Ref.DirName(), blob.Path)
if err := os.MkdirAll(filepath.Dir(rawPath), 0o755); check(err) {
return
}
@@ -187,7 +187,7 @@ func generateBlobs(files []git.Blob, params Params) error {
return
}
- relativeRawPath := filepath.Join(rootHref, "raw", string(params.Ref), blob.Path)
+ relativeRawPath := filepath.Join(rootHref, "raw", params.Ref.DirName(), blob.Path)
contentHTML = template.HTML(fmt.Sprintf(`<img src="%s" alt="%s" />`, relativeRawPath, blob.FileName))
}
diff --git a/branches.go b/branches.go
index 00e9236..477f343 100644
--- a/branches.go
+++ b/branches.go
@@ -21,10 +21,10 @@ func generateBranches(branches []git.Ref, defaultBranch string, params Params) e
entries := make([]templates.BranchEntry, 0, len(branches))
for _, b := range branches {
entries = append(entries, templates.BranchEntry{
- Name: string(b),
- Href: filepath.ToSlash(filepath.Join("blob", string(b)) + "/index.html"),
- IsDefault: string(b) == defaultBranch,
- CommitsHref: filepath.ToSlash(filepath.Join("commits", string(b), "index.html")),
+ Name: b.Ref(),
+ Href: filepath.ToSlash(filepath.Join("blob", b.DirName()) + "/index.html"),
+ IsDefault: b.Ref() == defaultBranch,
+ CommitsHref: filepath.ToSlash(filepath.Join("commits", b.DirName(), "index.html")),
})
}
diff --git a/commit.go b/commit.go
index 571c8e2..ef18913 100644
--- a/commit.go
+++ b/commit.go
@@ -230,7 +230,7 @@ func generateCommitPage(commit git.Commit, params Params) error {
})
currentRef := params.DefaultRef
- if commit.Branch != "" {
+ if !commit.Branch.IsEmpty() {
currentRef = commit.Branch
}
diff --git a/commits_list.go b/commits_list.go
index bbb81e2..8649aa3 100644
--- a/commits_list.go
+++ b/commits_list.go
@@ -19,12 +19,12 @@ func generateLogForBranch(allCommits []git.Commit, params Params) error {
// RootHref from commits/<branch>/... => ../../
rootHref := "../../"
- outBase := filepath.Join(params.OutputDir, "commits", string(params.Ref))
+ outBase := filepath.Join(params.OutputDir, "commits", params.Ref.DirName())
if err := os.MkdirAll(outBase, 0o755); err != nil {
return err
}
- p := progress_bar.NewProgressBar("commits for "+string(params.Ref), totalPages)
+ p := progress_bar.NewProgressBar("commits for "+params.Ref.Ref(), totalPages)
page := 1
for pageCommits := range slices.Chunk(allCommits, commitsPerPage) {
diff --git a/index.go b/index.go
index 493b7f7..593eed6 100644
--- a/index.go
+++ b/index.go
@@ -72,7 +72,7 @@ func generateIndex(files []git.Blob, params Params) error {
for _, name := range dirNames {
subdirEntries = append(subdirEntries, templates.ListEntry{
Name: name + "/",
- Href: "blob/" + string(params.Ref) + "/" + name + "/index.html",
+ Href: "blob/" + params.Ref.DirName() + "/" + name + "/index.html",
IsDir: true,
})
}
@@ -81,7 +81,7 @@ func generateIndex(files []git.Blob, params Params) error {
for _, b := range di.files {
fileEntries = append(fileEntries, templates.ListEntry{
Name: b.FileName + "",
- Href: "blob/" + string(params.Ref) + "/" + b.FileName + ".html",
+ Href: "blob/" + params.Ref.DirName() + "/" + b.FileName + ".html",
Mode: b.Mode,
Size: humanizeSize(b.Size),
})
diff --git a/list.go b/list.go
index 21979aa..440188d 100644
--- a/list.go
+++ b/list.go
@@ -81,7 +81,7 @@ func generateLists(files []git.Blob, params Params) error {
errCh := make(chan error, 1)
var wg sync.WaitGroup
- p := progress_bar.NewProgressBar("lists for "+string(params.Ref), len(jobsSlice))
+ p := progress_bar.NewProgressBar("lists for "+params.Ref.Ref(), len(jobsSlice))
check := func(err error) bool {
if err != nil {
@@ -109,7 +109,7 @@ func generateLists(files []git.Blob, params Params) error {
dirPath := jb.dirPath
di := jb.di
- outDir := filepath.Join(params.OutputDir, "blob", string(params.Ref))
+ outDir := filepath.Join(params.OutputDir, "blob", params.Ref.DirName())
if dirPath != "" {
// convert forward slash path into OS path
outDir = filepath.Join(outDir, filepath.FromSlash(dirPath))
diff --git a/main.go b/main.go
index afdbfd7..c5e8baa 100644
--- a/main.go
+++ b/main.go
@@ -144,7 +144,7 @@ func main() {
OutputDir: outputDir,
Style: flagTheme,
Dark: themeColor == "dark",
- DefaultRef: git.Ref(flagDefaultBranch),
+ DefaultRef: git.NewRef(flagDefaultBranch),
}
commits := make(map[string]git.Commit)
@@ -165,13 +165,15 @@ func main() {
}
}
+ // Add commits from tags
for _, tag := range tags {
- commitsForTag, err := git.Commits(git.Ref(tag.Name), params.RepoDir)
+ commitsForTag, err := git.Commits(git.NewRef(tag.Name), params.RepoDir)
if err != nil {
panic(err)
}
for _, commit := range commitsForTag {
- if alreadyExisting, ok := commits[commit.Hash]; ok && alreadyExisting.Branch != "" {
+ // Only add new commits
+ if alreadyExisting, ok := commits[commit.Hash]; ok && !alreadyExisting.Branch.IsEmpty() {
continue
}
commits[commit.Hash] = commit
@@ -196,7 +198,7 @@ func main() {
panic(err)
}
- if branch == git.Ref(flagDefaultBranch) {
+ if branch.Ref() == flagDefaultBranch {
defaultBranchFiles = files
}
@@ -220,7 +222,7 @@ func main() {
}
// Back to the default branch
- params.Ref = git.Ref(flagDefaultBranch)
+ params.Ref = git.NewRef(flagDefaultBranch)
// Commits pages generation
echo("> generating commits...")
diff --git a/pkg/git/git.go b/pkg/git/git.go
index 9139261..7fc28fa 100644
--- a/pkg/git/git.go
+++ b/pkg/git/git.go
@@ -31,7 +31,7 @@ func Branches(repoDir string, filter *regexp.Regexp, defaultBranch string) ([]Re
if filter != nil && !filter.MatchString(line) && line != defaultBranch {
continue
}
- branches = append(branches, Ref(line))
+ branches = append(branches, NewRef(line))
}
return branches, nil
}
@@ -88,13 +88,13 @@ func Tags(repoDir string) ([]Tag, error) {
}
func Files(ref Ref, repoDir string) ([]Blob, error) {
- if ref == "" {
- ref = "HEAD"
+ if ref.IsEmpty() {
+ ref = NewRef("HEAD")
}
// -r: recurse into subtrees
// -l: include blob size
- cmd := exec.Command("git", "ls-tree", "--full-tree", "-r", "-l", string(ref))
+ cmd := exec.Command("git", "ls-tree", "--full-tree", "-r", "-l", ref.Ref())
if repoDir != "" {
cmd.Dir = repoDir
}
@@ -196,11 +196,11 @@ func Files(ref Ref, repoDir string) ([]Blob, error) {
}
func BlobContent(ref Ref, path string, repoDir string) ([]byte, bool, error) {
- if ref == "" {
- ref = "HEAD"
+ if ref.IsEmpty() {
+ ref = NewRef("HEAD")
}
// Use `git show ref:path` to get the blob content at that ref
- cmd := exec.Command("git", "show", string(ref)+":"+path)
+ cmd := exec.Command("git", "show", ref.Ref()+":"+path)
if repoDir != "" {
cmd.Dir = repoDir
}
@@ -233,7 +233,7 @@ func Commits(ref Ref, repoDir string) ([]Commit, error) {
"--date=unix",
"--pretty=format:" + strings.Join(format, "\x1F"),
"-z", // Separate the commits with NULs instead of newlines
- string(ref),
+ ref.Ref(),
}
cmd := exec.Command("git", args...)
diff --git a/pkg/git/types.go b/pkg/git/types.go
index 3c12f14..121c7d8 100644
--- a/pkg/git/types.go
+++ b/pkg/git/types.go
@@ -4,7 +4,29 @@ import (
"time"
)
-type Ref string
+type Ref struct {
+ ref string
+ dirName string
+}
+
+func NewRef(ref string) Ref {
+ return Ref{
+ ref: ref,
+ dirName: RefToFileName(ref),
+ }
+}
+
+func (r Ref) IsEmpty() bool {
+ return r.ref == ""
+}
+
+func (r Ref) Ref() string {
+ return r.ref
+}
+
+func (r Ref) DirName() string {
+ return r.dirName
+}
type Blob struct {
Ref Ref
diff --git a/pkg/git/utils.go b/pkg/git/utils.go
index 24a2b75..68e4497 100644
--- a/pkg/git/utils.go
+++ b/pkg/git/utils.go
@@ -3,6 +3,7 @@ package git
import (
"fmt"
"strconv"
+ "strings"
)
// ParseFileMode converts a git-style file mode (e.g. "100644")
@@ -74,3 +75,17 @@ func IsBinary(b []byte) bool {
// If more than 30% of sampled bytes are non-text, consider binary
return bad*100 > n*30
}
+
+func RefToFileName(ref string) string {
+ var result strings.Builder
+ for _, c := range ref {
+ if (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '.' {
+ result.WriteByte(byte(c))
+ } else if c >= 'A' && c <= 'Z' {
+ result.WriteByte(byte(c - 'A' + 'a'))
+ } else {
+ result.WriteByte('-')
+ }
+ }
+ return result.String()
+}
diff --git a/pkg/git/utils_test.go b/pkg/git/utils_test.go
index ecbe952..4dcebe8 100644
--- a/pkg/git/utils_test.go
+++ b/pkg/git/utils_test.go
@@ -54,3 +54,27 @@ func TestParseFileModeInvalid(t *testing.T) {
})
}
}
+
+func TestRefToFileName(t *testing.T) {
+ tests := []struct {
+ in string
+ want string
+ }{
+ {"main", "main"},
+ {"master", "master"},
+ {"release/v1.0", "release-v1.0"},
+ {"feature/add-login", "feature-add-login"},
+ {"bugfix\\windows\\path", "bugfix-windows-path"},
+ {"1.0.0", "1.0.0"},
+ {"1.x", "1.x"},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.in, func(t *testing.T) {
+ got := git.RefToFileName(tt.in)
+ if got != tt.want {
+ t.Fatalf("refToFileName(%q) = %q, want %q", tt.in, got, tt.want)
+ }
+ })
+ }
+}
diff --git a/readme.go b/readme.go
index a7d7887..a70146c 100644
--- a/readme.go
+++ b/readme.go
@@ -27,7 +27,14 @@ func readme(files []git.Blob, dirsSet, filesSet links.Set, params Params, rootHr
}
// Fix links/images relative to README location
- htmlStr := links.Resolve(buf.String(), b.Path, rootHref, string(params.Ref), dirsSet, filesSet)
+ htmlStr := links.Resolve(
+ buf.String(),
+ b.Path,
+ rootHref,
+ params.Ref.DirName(),
+ dirsSet,
+ filesSet,
+ )
readmeHTML = template.HTML(htmlStr)
break
diff --git a/utils.go b/utils.go
index 02a5091..d8e85d1 100644
--- a/utils.go
+++ b/utils.go
@@ -107,23 +107,9 @@ func isImage(path string) bool {
func containsBranch(branches []git.Ref, branch string) bool {
for _, b := range branches {
- if string(b) == branch {
+ if b.Ref() == branch {
return true
}
}
return false
}
-
-func refToFileName(ref git.Ref) string {
- var result strings.Builder
- for _, c := range string(ref) {
- if (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '.' {
- result.WriteByte(byte(c))
- } else if c >= 'A' && c <= 'Z' {
- result.WriteByte(byte(c - 'A' + 'a'))
- } else {
- result.WriteByte('-')
- }
- }
- return result.String()
-}
diff --git a/utils_test.go b/utils_test.go
deleted file mode 100644
index f883e1b..0000000
--- a/utils_test.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package main
-
-import (
- "testing"
-
- "github.com/antonmedv/gitmal/pkg/git"
-)
-
-func TestRefToFileName(t *testing.T) {
- tests := []struct {
- in string
- want string
- }{
- {"main", "main"},
- {"master", "master"},
- {"release/v1.0", "release-v1.0"},
- {"feature/add-login", "feature-add-login"},
- {"bugfix\\windows\\path", "bugfix-windows-path"},
- {"1.0.0", "1.0.0"},
- {"1.x", "1.x"},
- }
-
- for _, tt := range tests {
- t.Run(tt.in, func(t *testing.T) {
- got := refToFileName(git.Ref(tt.in))
- if got != tt.want {
- t.Fatalf("refToFileName(%q) = %q, want %q", tt.in, got, tt.want)
- }
- })
- }
-}