github.com/elek/golangci-lint@v1.42.2-0.20211208090441-c05b7fcb3a9a/pkg/golinters/gci.go (about) 1 package golinters 2 3 import ( 4 "bytes" 5 "fmt" 6 "sync" 7 8 "github.com/daixiang0/gci/pkg/gci" 9 "github.com/pkg/errors" 10 "github.com/shazow/go-diff/difflib" 11 "golang.org/x/tools/go/analysis" 12 13 "github.com/elek/golangci-lint/pkg/golinters/goanalysis" 14 "github.com/elek/golangci-lint/pkg/lint/linter" 15 ) 16 17 const gciName = "gci" 18 19 func NewGci() *goanalysis.Linter { 20 var mu sync.Mutex 21 var resIssues []goanalysis.Issue 22 differ := difflib.New() 23 24 analyzer := &analysis.Analyzer{ 25 Name: gciName, 26 Doc: goanalysis.TheOnlyanalyzerDoc, 27 } 28 return goanalysis.NewLinter( 29 gciName, 30 "Gci control golang package import order and make it always deterministic.", 31 []*analysis.Analyzer{analyzer}, 32 nil, 33 ).WithContextSetter(func(lintCtx *linter.Context) { 34 localFlag := lintCtx.Settings().Gci.LocalPrefixes 35 goimportsFlag := lintCtx.Settings().Goimports.LocalPrefixes 36 if localFlag == "" && goimportsFlag != "" { 37 localFlag = goimportsFlag 38 } 39 40 analyzer.Run = func(pass *analysis.Pass) (interface{}, error) { 41 var fileNames []string 42 for _, f := range pass.Files { 43 pos := pass.Fset.PositionFor(f.Pos(), false) 44 fileNames = append(fileNames, pos.Filename) 45 } 46 47 var issues []goanalysis.Issue 48 49 flagSet := gci.FlagSet{ 50 LocalFlag: gci.ParseLocalFlag(localFlag), 51 } 52 53 for _, f := range fileNames { 54 source, result, err := gci.Run(f, &flagSet) 55 if err != nil { 56 return nil, err 57 } 58 if result == nil { 59 continue 60 } 61 62 diff := bytes.Buffer{} 63 _, err = diff.WriteString(fmt.Sprintf("--- %[1]s\n+++ %[1]s\n", f)) 64 if err != nil { 65 return nil, fmt.Errorf("can't write diff header: %v", err) 66 } 67 68 err = differ.Diff(&diff, bytes.NewReader(source), bytes.NewReader(result)) 69 if err != nil { 70 return nil, fmt.Errorf("can't get gci diff output: %v", err) 71 } 72 73 is, err := extractIssuesFromPatch(diff.String(), lintCtx.Log, lintCtx, gciName) 74 if err != nil { 75 return nil, errors.Wrapf(err, "can't extract issues from gci diff output %q", diff.String()) 76 } 77 78 for i := range is { 79 issues = append(issues, goanalysis.NewIssue(&is[i], pass)) 80 } 81 } 82 83 if len(issues) == 0 { 84 return nil, nil 85 } 86 87 mu.Lock() 88 resIssues = append(resIssues, issues...) 89 mu.Unlock() 90 91 return nil, nil 92 } 93 }).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { 94 return resIssues 95 }).WithLoadMode(goanalysis.LoadModeSyntax) 96 }