diff --git a/.golangci.yml b/.golangci.yml index 2e72bba..3bc8296 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -4,7 +4,7 @@ run: concurrency: 4 # timeout for analysis, e.g. 30s, 5m, default is 1m - deadline: 10m + timeout: 10m # exit code when at least one issue was found, default is 1 issues-exit-code: 1 @@ -12,26 +12,12 @@ run: # include test files or not, default is true tests: true - # list of build tags, all linters use it. Default is empty list. - build-tags: - - # which dirs to skip: they won't be analyzed; - # can use regexp here: generated.*, regexp is applied on full path; - # default value is empty list, but next dirs are always skipped independently - # from this option's value: - # third_party$, testdata$, examples$, Godeps$, builtin$ - skip-dirs: - - # which files to skip: they will be analyzed, but issues from them - # won't be reported. Default value is empty list, but there is - # no need to include all autogenerated files, we confidently recognize - # autogenerated files. If it's not please let us know. - skip-files: # output configuration options output: # colored-line-number|line-number|json|tab|checkstyle, default is "colored-line-number" - format: tab + formats: + - format: tab # print lines of code with issue, default is true print-issued-lines: true @@ -73,13 +59,9 @@ linters-settings: local-prefixes: github.com/daixiang0/gci linters: - fast: false + disable-all: true enable: - gofmt - gofumpt - goimports - gci - disable-all: true - -issues: - exclude: diff --git a/pkg/analyzer/analyzer.go b/pkg/analyzer/analyzer.go index 5685ac2..82856be 100644 --- a/pkg/analyzer/analyzer.go +++ b/pkg/analyzer/analyzer.go @@ -1,7 +1,6 @@ package analyzer import ( - "fmt" "go/token" "strings" @@ -21,39 +20,56 @@ const ( SkipGeneratedFlag = "skipGenerated" SectionsFlag = "Sections" SectionSeparatorsFlag = "SectionSeparators" - SectionDelimiter = "," + NoLexOrderFlag = "NoLexOrder" + CustomOrderFlag = "CustomOrder" + PrefixDelimiterFlag = "PrefixDelimiter" ) +const SectionDelimiter = "," + var ( noInlineComments bool noPrefixComments bool skipGenerated bool sectionsStr string sectionSeparatorsStr string + noLexOrder bool + customOrder bool + prefixDelimiter string ) -func init() { - Analyzer.Flags.BoolVar(&noInlineComments, NoInlineCommentsFlag, false, "If comments in the same line as the input should be present") - Analyzer.Flags.BoolVar(&noPrefixComments, NoPrefixCommentsFlag, false, "If comments above an input should be present") - Analyzer.Flags.BoolVar(&skipGenerated, SkipGeneratedFlag, false, "Skip generated files") - Analyzer.Flags.StringVar(§ionsStr, SectionsFlag, "", "Specify the Sections format that should be used to check the file formatting") - Analyzer.Flags.StringVar(§ionSeparatorsStr, SectionSeparatorsFlag, "", "Specify the Sections that are inserted as Separators between Sections") - +func NewAnalyzer() *analysis.Analyzer { log.InitLogger() - defer log.L().Sync() -} + _ = log.L().Sync() -var Analyzer = &analysis.Analyzer{ - Name: "gci", - Doc: "A tool that control Go package import order and make it always deterministic.", - Run: runAnalysis, - Requires: []*analysis.Analyzer{ - inspect.Analyzer, - modinfo.Analyzer, - }, + a := &analysis.Analyzer{ + Name: "gci", + Doc: "A tool that control Go package import order and make it always deterministic.", + Run: runAnalysis, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + } + + a.Flags.BoolVar(&noInlineComments, NoInlineCommentsFlag, false, + "If comments in the same line as the input should be present") + a.Flags.BoolVar(&noPrefixComments, NoPrefixCommentsFlag, false, + "If comments above an input should be present") + a.Flags.BoolVar(&skipGenerated, SkipGeneratedFlag, false, + "Skip generated files") + a.Flags.StringVar(§ionsStr, SectionsFlag, "", + "Specify the Sections format that should be used to check the file formatting") + a.Flags.StringVar(§ionSeparatorsStr, SectionSeparatorsFlag, "", + "Specify the Sections that are inserted as Separators between Sections") + a.Flags.BoolVar(&noLexOrder, NoLexOrderFlag, false, + "Drops lexical ordering for custom sections") + a.Flags.BoolVar(&customOrder, CustomOrderFlag, false, + "Enable custom order of sections") + + a.Flags.StringVar(&prefixDelimiter, PrefixDelimiterFlag, SectionDelimiter, "") + + return a } -func runAnalysis(pass *analysis.Pass) (interface{}, error) { +func runAnalysis(pass *analysis.Pass) (any, error) { var fileReferences []*token.File // extract file references for all files in the analyzer pass for _, pkgFile := range pass.Files { @@ -79,25 +95,28 @@ func runAnalysis(pass *analysis.Pass) (interface{}, error) { } for _, file := range fileReferences { - filePath := file.Name() - unmodifiedFile, formattedFile, err := gci.LoadFormatGoFile(io.File{FilePath: filePath}, *gciCfg) + unmodifiedFile, formattedFile, err := gci.LoadFormatGoFile(io.File{FilePath: file.Name()}, *gciCfg) if err != nil { return nil, err } + fix, err := GetSuggestedFix(file, unmodifiedFile, formattedFile) if err != nil { return nil, err } + if fix == nil { // no difference continue } + pass.Report(analysis.Diagnostic{ Pos: fix.TextEdits[0].Pos, - Message: fmt.Sprintf("fix by `%s %s`", generateCmdLine(*gciCfg), filePath), + Message: "File is not properly formatted", SuggestedFixes: []analysis.SuggestedFix{*fix}, }) } + return nil, nil } @@ -107,50 +126,22 @@ func generateGciConfiguration(modPath string) *config.YamlConfig { NoPrefixComments: noPrefixComments, Debug: false, SkipGenerated: skipGenerated, + CustomOrder: customOrder, + NoLexOrder: noLexOrder, } var sectionStrings []string if sectionsStr != "" { - sectionStrings = strings.Split(sectionsStr, SectionDelimiter) + s := strings.Split(sectionsStr, SectionDelimiter) + for _, a := range s { + sectionStrings = append(sectionStrings, strings.ReplaceAll(a, prefixDelimiter, SectionDelimiter)) + } } var sectionSeparatorStrings []string if sectionSeparatorsStr != "" { sectionSeparatorStrings = strings.Split(sectionSeparatorsStr, SectionDelimiter) - fmt.Println(sectionSeparatorsStr) } return &config.YamlConfig{Cfg: fmtCfg, SectionStrings: sectionStrings, SectionSeparatorStrings: sectionSeparatorStrings, ModPath: modPath} } - -func generateCmdLine(cfg config.Config) string { - result := "gci write" - - if cfg.BoolConfig.NoInlineComments { - result += " --NoInlineComments " - } - - if cfg.BoolConfig.NoPrefixComments { - result += " --NoPrefixComments " - } - - if cfg.BoolConfig.SkipGenerated { - result += " --skip-generated " - } - - if cfg.BoolConfig.CustomOrder { - result += " --custom-order " - } - - if cfg.BoolConfig.NoLexOrder { - result += " --no-lex-order" - } - - for _, s := range cfg.Sections.String() { - result += fmt.Sprintf(" --Section \"%s\" ", s) - } - for _, s := range cfg.SectionSeparators.String() { - result += fmt.Sprintf(" --SectionSeparator %s ", s) - } - return result -}