github.com/haya14busa/reviewdog@v0.0.0-20180723114510-ffb00ef78fd3/filter.go (about) 1 package reviewdog 2 3 import ( 4 "path/filepath" 5 "strings" 6 7 "github.com/haya14busa/reviewdog/diff" 8 ) 9 10 // FilteredCheck represents CheckResult with filtering info. 11 type FilteredCheck struct { 12 *CheckResult 13 InDiff bool 14 LnumDiff int 15 } 16 17 // FilterCheck filters check results by diff. It doesn't drop check which 18 // is not in diff but set FilteredCheck.InDiff field false. 19 func FilterCheck(results []*CheckResult, diff []*diff.FileDiff, strip int, wd string) []*FilteredCheck { 20 checks := make([]*FilteredCheck, 0, len(results)) 21 22 addedlines := addedDiffLines(diff, strip) 23 24 for _, result := range results { 25 check := &FilteredCheck{CheckResult: result} 26 27 addedline := addedlines.Get(result.Path, result.Lnum) 28 result.Path = CleanPath(result.Path, wd) 29 if addedline != nil { 30 check.InDiff = true 31 check.LnumDiff = addedline.LnumDiff 32 } 33 34 checks = append(checks, check) 35 } 36 37 return checks 38 } 39 40 // CleanPath clean up given path. If workdir is not empty, it returns relative 41 // path to the given workdir. 42 func CleanPath(path, workdir string) string { 43 p := path 44 if filepath.IsAbs(path) && workdir != "" { 45 relPath, err := filepath.Rel(workdir, path) 46 if err == nil { 47 p = relPath 48 } 49 } 50 p = filepath.Clean(p) 51 if p == "." { 52 return "" 53 } 54 return p 55 } 56 57 // addedLine represents added line in diff. 58 type addedLine struct { 59 Path string // path to new file 60 Lnum int // the line number in the new file 61 LnumDiff int // the line number of the diff (Same as Lnumdiff of diff.Line) 62 Content string // line content 63 } 64 65 // posToAddedLine is a hash table of normalized path to line number to addedLine. 66 type posToAddedLine map[string]map[int]*addedLine 67 68 func (p posToAddedLine) Get(path string, lnum int) *addedLine { 69 npath, err := normalizePath(path) 70 if err != nil { 71 return nil 72 } 73 ltodiff, ok := p[npath] 74 if !ok { 75 return nil 76 } 77 diffline, ok := ltodiff[lnum] 78 if !ok { 79 return nil 80 } 81 return diffline 82 } 83 84 // addedDiffLines traverse []*diff.FileDiff and returns posToAddedLine. 85 func addedDiffLines(filediffs []*diff.FileDiff, strip int) posToAddedLine { 86 r := make(posToAddedLine) 87 for _, filediff := range filediffs { 88 path := filediff.PathNew 89 ltodiff := make(map[int]*addedLine) 90 if strip > 0 { 91 ps := strings.Split(filepath.ToSlash(filediff.PathNew), "/") 92 if len(ps) > strip { 93 path = filepath.Join(ps[strip:]...) 94 } 95 } 96 np, err := normalizePath(path) 97 if err != nil { 98 // FIXME(haya14busa): log or return error? 99 continue 100 } 101 path = np 102 103 for _, hunk := range filediff.Hunks { 104 for _, line := range hunk.Lines { 105 if line.Type == diff.LineAdded { 106 ltodiff[line.LnumNew] = &addedLine{ 107 Path: path, 108 Lnum: line.LnumNew, 109 LnumDiff: line.LnumDiff, 110 Content: line.Content, 111 } 112 } 113 } 114 } 115 r[path] = ltodiff 116 } 117 return r 118 } 119 120 func normalizePath(p string) (string, error) { 121 if !filepath.IsAbs(p) { 122 path, err := filepath.Abs(p) 123 if err != nil { 124 return "", err 125 } 126 p = path 127 } 128 return filepath.ToSlash(p), nil 129 }