11package todos
22
33import (
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+
5992func (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