4
4
package covermerger
5
5
6
6
import (
7
+ "context"
7
8
"encoding/csv"
8
9
"fmt"
9
10
"io"
10
11
"log"
11
12
"strconv"
13
+ "sync"
12
14
13
15
"golang.org/x/exp/maps"
16
+ "golang.org/x/sync/errgroup"
14
17
)
15
18
16
19
const (
@@ -23,7 +26,6 @@ const (
23
26
)
24
27
25
28
type FileRecord map [string ]string
26
- type FileRecords []FileRecord
27
29
type RepoBranchCommit struct {
28
30
Repo string
29
31
Branch string
@@ -73,24 +75,15 @@ type FileCoverageMerger interface {
73
75
Result () * MergeResult
74
76
}
75
77
76
- func batchFileData (c * Config , targetFilePath string , records FileRecords , processedFiles map [string ]struct {},
77
- ) (* MergeResult , error ) {
78
+ func batchFileData (c * Config , targetFilePath string , records []FileRecord ) (* MergeResult , error ) {
78
79
log .Printf ("processing %d records for %s" , len (records ), targetFilePath )
79
- if _ , exists := processedFiles [targetFilePath ]; exists {
80
- return nil , fmt .Errorf ("file was already processed, check the input ordering" )
81
- }
82
- processedFiles [targetFilePath ] = struct {}{}
83
80
repoBranchCommitsMap := make (map [RepoBranchCommit ]bool )
84
81
for _ , record := range records {
85
82
repoBranchCommitsMap [record .RepoBranchCommit ()] = true
86
83
}
87
84
repoBranchCommitsMap [c .Base ] = true
88
85
repoBranchCommits := maps .Keys (repoBranchCommitsMap )
89
- getFiles := getFileVersions
90
- if c .getFileVersionsMock != nil {
91
- getFiles = c .getFileVersionsMock
92
- }
93
- fvs , err := getFiles (c , targetFilePath , repoBranchCommits )
86
+ fvs , err := c .FileVersProvider .GetFileVersions (c , targetFilePath , repoBranchCommits )
94
87
if err != nil {
95
88
return nil , fmt .Errorf ("failed to getFileVersions: %w" , err )
96
89
}
@@ -125,11 +118,11 @@ func makeRecord(fields, schema []string) FileRecord {
125
118
}
126
119
127
120
type Config struct {
128
- Workdir string
129
- skipRepoClone bool
130
- Base RepoBranchCommit
131
- getFileVersionsMock func ( * Config , string , [] RepoBranchCommit ) ( fileVersions , error )
132
- repoCache repoCache
121
+ Jobs int
122
+ Workdir string
123
+ skipRepoClone bool
124
+ Base RepoBranchCommit
125
+ FileVersProvider fileVersProvider
133
126
}
134
127
135
128
func isSchema (fields , schema []string ) bool {
@@ -182,32 +175,70 @@ func MergeCSVData(config *Config, reader io.Reader) (map[string]*MergeResult, er
182
175
return mergeResult , nil
183
176
}
184
177
185
- func mergeChanData (c * Config , recordsChan <- chan FileRecord ) (map [string ]* MergeResult , error ) {
178
+ type FileRecords struct {
179
+ fileName string
180
+ records []FileRecord
181
+ }
182
+
183
+ func mergeChanData (c * Config , recordChan <- chan FileRecord ) (map [string ]* MergeResult , error ) {
184
+ g , ctx := errgroup .WithContext (context .Background ())
185
+ frecordChan := groupFileRecords (recordChan , ctx )
186
186
stat := make (map [string ]* MergeResult )
187
- targetFile := ""
188
- var records []FileRecord
189
- processedFiles := map [string ]struct {}{}
190
- for record := range recordsChan {
191
- curTargetFile := record [KeyFilePath ]
192
- if targetFile == "" {
193
- targetFile = curTargetFile
194
- }
195
- if curTargetFile != targetFile {
196
- var err error
197
- if stat [targetFile ], err = batchFileData (c , targetFile , records , processedFiles ); err != nil {
198
- return nil , fmt .Errorf ("failed to batchFileData(%s): %w" , targetFile , err )
187
+ var mu sync.Mutex
188
+ for i := 0 ; i < c .Jobs ; i ++ {
189
+ g .Go (func () error {
190
+ for frecord := range frecordChan {
191
+ if mr , err := batchFileData (c , frecord .fileName , frecord .records ); err != nil {
192
+ return fmt .Errorf ("failed to batchFileData(%s): %w" , frecord .fileName , err )
193
+ } else {
194
+ mu .Lock ()
195
+ if _ , exist := stat [frecord .fileName ]; exist {
196
+ mu .Unlock ()
197
+ return fmt .Errorf ("file %s was already processed" , frecord .fileName )
198
+ }
199
+ stat [frecord .fileName ] = mr
200
+ mu .Unlock ()
201
+ }
199
202
}
200
- records = nil
201
- targetFile = curTargetFile
202
- }
203
- records = append (records , record )
203
+ return nil
204
+ })
204
205
}
205
- if records != nil {
206
- var err error
207
- if stat [targetFile ], err = batchFileData (c , targetFile , records , processedFiles ); err != nil {
208
- return nil , fmt .Errorf ("failed to batchFileData(%s): %w" , targetFile , err )
209
- }
206
+ if err := g .Wait (); err != nil {
207
+ return nil , err
210
208
}
211
-
212
209
return stat , nil
213
210
}
211
+
212
+ func groupFileRecords (recordChan <- chan FileRecord , ctx context.Context ) chan FileRecords {
213
+ frecordChan := make (chan FileRecords )
214
+ go func () {
215
+ defer close (frecordChan )
216
+ targetFile := ""
217
+ var records []FileRecord
218
+ for record := range recordChan {
219
+ select {
220
+ case <- ctx .Done ():
221
+ return
222
+ default :
223
+ }
224
+ curTargetFile := record [KeyFilePath ]
225
+ if targetFile == "" {
226
+ targetFile = curTargetFile
227
+ }
228
+ if curTargetFile != targetFile {
229
+ frecordChan <- FileRecords {
230
+ fileName : targetFile ,
231
+ records : records ,
232
+ }
233
+ records = nil
234
+ targetFile = curTargetFile
235
+ }
236
+ records = append (records , record )
237
+ }
238
+ frecordChan <- FileRecords {
239
+ fileName : targetFile ,
240
+ records : records ,
241
+ }
242
+ }()
243
+ return frecordChan
244
+ }
0 commit comments