diff options
| author | Anton Medvedev <anton@medv.io> | 2025-12-07 16:56:52 +0100 |
|---|---|---|
| committer | Anton Medvedev <anton@medv.io> | 2025-12-07 16:56:52 +0100 |
| commit | 1441fb29d93481f7bea76bbfa2a9f289ed1ac4f0 (patch) | |
| tree | 6d01f974638c519780406f67158c9160cf06e7cc | |
| parent | 20a5d07b2a4620ace14c6a5f622ca45e27f9c20d (diff) | |
Refactor code by introducing `Ref` type
| -rw-r--r-- | blob.go | 10 | ||||
| -rw-r--r-- | branches.go | 8 | ||||
| -rw-r--r-- | commit.go | 2 | ||||
| -rw-r--r-- | commits_list.go | 4 | ||||
| -rw-r--r-- | index.go | 4 | ||||
| -rw-r--r-- | list.go | 4 | ||||
| -rw-r--r-- | main.go | 12 | ||||
| -rw-r--r-- | pkg/git/git.go | 16 | ||||
| -rw-r--r-- | pkg/git/types.go | 24 | ||||
| -rw-r--r-- | pkg/git/utils.go | 15 | ||||
| -rw-r--r-- | pkg/git/utils_test.go | 24 | ||||
| -rw-r--r-- | readme.go | 9 | ||||
| -rw-r--r-- | utils.go | 16 | ||||
| -rw-r--r-- | utils_test.go | 31 |
14 files changed, 102 insertions, 77 deletions
@@ -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")), }) } @@ -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) { @@ -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), }) @@ -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)) @@ -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) + } + }) + } +} @@ -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 @@ -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) - } - }) - } -} |
