Skip to content

Commit f9ff939

Browse files
committed
make FindBlame cancellable via context, make ToDos sortable
1 parent 05682eb commit f9ff939

File tree

3 files changed

+78
-29
lines changed

3 files changed

+78
-29
lines changed

cmd/commands/todos.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package commands
22

33
import (
4+
"context"
45
"fmt"
56
"os"
67
"path/filepath"
8+
"sort"
79
"time"
810

911
"github.com/augmentable-dev/tickgit/pkg/comments"
@@ -57,10 +59,17 @@ var todosCmd = &cobra.Command{
5759

5860
t := todos.NewToDos(comments)
5961

60-
err = t.FindBlame(r, commit, func(commit *object.Commit, remaining int) {
62+
ctx := context.Background()
63+
// timeout after 30 seconds
64+
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
65+
defer cancel()
66+
_, err = t.FindBlame(ctx, r, commit, func(commit *object.Commit, remaining int) {
6167
total := len(t)
6268
s.Suffix = fmt.Sprintf(" (%d/%d) %s: %s", total-remaining, total, commit.Hash, commit.Author.When)
6369
})
70+
71+
sort.Sort(&t)
72+
6473
handleError(err)
6574

6675
s.Stop()

pkg/todos/report.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ const DefaultTemplate = `
1010
{{- range $index, $todo := . }}
1111
{{ print "\u001b[33m" }}TODO{{ print "\u001b[0m" }}: {{ .String }}
1212
=> {{ .Comment.FilePath }}:{{ .Comment.StartLocation.Line }}:{{ .Comment.StartLocation.Pos }}
13+
{{- if .Commit }}
1314
=> added {{ .TimeAgo }} by {{ .Commit.Author }} in {{ .Commit.Hash }}
15+
{{- end }}
1416
{{ else }}
1517
no todos 🎉
1618
{{- end }}

pkg/todos/todos.go

Lines changed: 66 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package todos
22

33
import (
4+
"context"
45
"regexp"
56
"strings"
67
"sync"
@@ -56,6 +57,38 @@ func NewToDos(comments comments.Comments) ToDos {
5657
return todos
5758
}
5859

60+
// Len returns the number of todos
61+
func (t *ToDos) Len() int {
62+
return len(*t)
63+
}
64+
65+
// Less compares two todos by their creation time
66+
func (t *ToDos) Less(i, j int) bool {
67+
first := (*t)[i]
68+
second := (*t)[j]
69+
if first.Commit == nil || second.Commit == nil {
70+
return false
71+
}
72+
return first.Commit.Author.When.Before(second.Commit.Author.When)
73+
}
74+
75+
// Swap swaps two todoss
76+
func (t *ToDos) Swap(i, j int) {
77+
temp := (*t)[i]
78+
(*t)[i] = (*t)[j]
79+
(*t)[j] = temp
80+
}
81+
82+
// CountWithCommits returns the number of todos with an associated commit (in which that todo was added)
83+
func (t *ToDos) CountWithCommits() (count int) {
84+
for _, todo := range *t {
85+
if todo.Commit != nil {
86+
count++
87+
}
88+
}
89+
return count
90+
}
91+
5992
func (t *ToDo) existsInCommit(commit *object.Commit) (bool, error) {
6093
f, err := commit.File(t.FilePath)
6194
if err != nil {
@@ -73,7 +106,7 @@ func (t *ToDo) existsInCommit(commit *object.Commit) (bool, error) {
73106
}
74107

75108
// FindBlame sets the blame information on each todo in a set of todos
76-
func (t *ToDos) FindBlame(repo *git.Repository, from *object.Commit, cb func(*object.Commit, int)) error {
109+
func (t *ToDos) FindBlame(ctx context.Context, repo *git.Repository, from *object.Commit, cb func(*object.Commit, int)) error {
77110
commitIter, err := repo.Log(&git.LogOptions{
78111
From: from.Hash,
79112
})
@@ -91,34 +124,39 @@ func (t *ToDos) FindBlame(repo *git.Repository, from *object.Commit, cb func(*ob
91124
if commit.NumParents() > 1 {
92125
return nil
93126
}
94-
newRemainingTodos := make(ToDos, 0)
95-
errs := make(chan error)
96-
var wg sync.WaitGroup
97-
var mux sync.Mutex
98-
for _, todo := range remainingTodos {
99-
wg.Add(1)
100-
go func(todo *ToDo, commit *object.Commit, errs chan error) {
101-
defer wg.Done()
102-
mux.Lock()
103-
exists, err := todo.existsInCommit(commit)
104-
if err != nil {
105-
errs <- err
106-
}
107-
mux.Unlock()
108-
if !exists { // if the todo doesn't exist in this commit, it was added in the previous commit (previous wrt the iterator, more recent in time)
109-
todo.Commit = prevCommit
110-
} else { // if the todo does exist in this commit, add it to the new list of remaining todos
111-
newRemainingTodos = append(newRemainingTodos, todo)
112-
}
113-
}(todo, commit, errs)
114-
}
115-
wg.Wait()
116-
if cb != nil {
117-
cb(commit, len(newRemainingTodos))
127+
select {
128+
case <-ctx.Done():
129+
return nil
130+
default:
131+
newRemainingTodos := make(ToDos, 0)
132+
errs := make(chan error)
133+
var wg sync.WaitGroup
134+
var mux sync.Mutex
135+
for _, todo := range remainingTodos {
136+
wg.Add(1)
137+
go func(todo *ToDo, commit *object.Commit, errs chan error) {
138+
defer wg.Done()
139+
mux.Lock()
140+
exists, err := todo.existsInCommit(commit)
141+
if err != nil {
142+
errs <- err
143+
}
144+
mux.Unlock()
145+
if !exists { // if the todo doesn't exist in this commit, it was added in the previous commit (previous wrt the iterator, more recent in time)
146+
todo.Commit = prevCommit
147+
} else { // if the todo does exist in this commit, add it to the new list of remaining todos
148+
newRemainingTodos = append(newRemainingTodos, todo)
149+
}
150+
}(todo, commit, errs)
151+
}
152+
wg.Wait()
153+
if cb != nil {
154+
cb(commit, len(newRemainingTodos))
155+
}
156+
prevCommit = commit
157+
remainingTodos = newRemainingTodos
158+
return nil
118159
}
119-
prevCommit = commit
120-
remainingTodos = newRemainingTodos
121-
return nil
122160
})
123161
if err != nil {
124162
return err

0 commit comments

Comments
 (0)