github.com/daixiang0/gci@v0.13.0/pkg/analyzer/analyzer.go (about)

     1  package analyzer
     2  
     3  import (
     4  	"fmt"
     5  	"go/token"
     6  	"strings"
     7  
     8  	"golang.org/x/tools/go/analysis"
     9  
    10  	"github.com/daixiang0/gci/pkg/config"
    11  	"github.com/daixiang0/gci/pkg/gci"
    12  	"github.com/daixiang0/gci/pkg/io"
    13  	"github.com/daixiang0/gci/pkg/log"
    14  )
    15  
    16  const (
    17  	NoInlineCommentsFlag  = "noInlineComments"
    18  	NoPrefixCommentsFlag  = "noPrefixComments"
    19  	SkipGeneratedFlag     = "skipGenerated"
    20  	SectionsFlag          = "Sections"
    21  	SectionSeparatorsFlag = "SectionSeparators"
    22  	SectionDelimiter      = ","
    23  )
    24  
    25  var (
    26  	noInlineComments     bool
    27  	noPrefixComments     bool
    28  	skipGenerated        bool
    29  	sectionsStr          string
    30  	sectionSeparatorsStr string
    31  )
    32  
    33  func init() {
    34  	Analyzer.Flags.BoolVar(&noInlineComments, NoInlineCommentsFlag, false, "If comments in the same line as the input should be present")
    35  	Analyzer.Flags.BoolVar(&noPrefixComments, NoPrefixCommentsFlag, false, "If comments above an input should be present")
    36  	Analyzer.Flags.BoolVar(&skipGenerated, SkipGeneratedFlag, false, "Skip generated files")
    37  	Analyzer.Flags.StringVar(&sectionsStr, SectionsFlag, "", "Specify the Sections format that should be used to check the file formatting")
    38  	Analyzer.Flags.StringVar(&sectionSeparatorsStr, SectionSeparatorsFlag, "", "Specify the Sections that are inserted as Separators between Sections")
    39  
    40  	log.InitLogger()
    41  	defer log.L().Sync()
    42  }
    43  
    44  var Analyzer = &analysis.Analyzer{
    45  	Name: "gci",
    46  	Doc:  "A tool that control Go package import order and make it always deterministic.",
    47  	Run:  runAnalysis,
    48  }
    49  
    50  func runAnalysis(pass *analysis.Pass) (interface{}, error) {
    51  	var fileReferences []*token.File
    52  	// extract file references for all files in the analyzer pass
    53  	for _, pkgFile := range pass.Files {
    54  		fileForPos := pass.Fset.File(pkgFile.Package)
    55  		if fileForPos != nil {
    56  			fileReferences = append(fileReferences, fileForPos)
    57  		}
    58  	}
    59  	expectedNumFiles := len(pass.Files)
    60  	foundNumFiles := len(fileReferences)
    61  	if expectedNumFiles != foundNumFiles {
    62  		return nil, InvalidNumberOfFilesInAnalysis{expectedNumFiles, foundNumFiles}
    63  	}
    64  
    65  	// read configuration options
    66  	gciCfg, err := parseGciConfiguration()
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  
    71  	for _, file := range fileReferences {
    72  		filePath := file.Name()
    73  		unmodifiedFile, formattedFile, err := gci.LoadFormatGoFile(io.File{FilePath: filePath}, *gciCfg)
    74  		if err != nil {
    75  			return nil, err
    76  		}
    77  		fix, err := GetSuggestedFix(file, unmodifiedFile, formattedFile)
    78  		if err != nil {
    79  			return nil, err
    80  		}
    81  		if fix == nil {
    82  			// no difference
    83  			continue
    84  		}
    85  		pass.Report(analysis.Diagnostic{
    86  			Pos:            fix.TextEdits[0].Pos,
    87  			Message:        fmt.Sprintf("fix by `%s %s`", generateCmdLine(*gciCfg), filePath),
    88  			SuggestedFixes: []analysis.SuggestedFix{*fix},
    89  		})
    90  	}
    91  	return nil, nil
    92  }
    93  
    94  func parseGciConfiguration() (*config.Config, error) {
    95  	fmtCfg := config.BoolConfig{
    96  		NoInlineComments: noInlineComments,
    97  		NoPrefixComments: noPrefixComments,
    98  		Debug:            false,
    99  		SkipGenerated:    skipGenerated,
   100  	}
   101  
   102  	var sectionStrings []string
   103  	if sectionsStr != "" {
   104  		sectionStrings = strings.Split(sectionsStr, SectionDelimiter)
   105  	}
   106  
   107  	var sectionSeparatorStrings []string
   108  	if sectionSeparatorsStr != "" {
   109  		sectionSeparatorStrings = strings.Split(sectionSeparatorsStr, SectionDelimiter)
   110  		fmt.Println(sectionSeparatorsStr)
   111  	}
   112  	return config.YamlConfig{Cfg: fmtCfg, SectionStrings: sectionStrings, SectionSeparatorStrings: sectionSeparatorStrings}.Parse()
   113  }
   114  
   115  func generateCmdLine(cfg config.Config) string {
   116  	result := "gci write"
   117  
   118  	if cfg.BoolConfig.NoInlineComments {
   119  		result += " --NoInlineComments "
   120  	}
   121  
   122  	if cfg.BoolConfig.NoPrefixComments {
   123  		result += " --NoPrefixComments "
   124  	}
   125  
   126  	if cfg.BoolConfig.SkipGenerated {
   127  		result += " --skip-generated "
   128  	}
   129  
   130  	if cfg.BoolConfig.CustomOrder {
   131  		result += " --custom-order "
   132  	}
   133  
   134  	for _, s := range cfg.Sections.String() {
   135  		result += fmt.Sprintf(" --Section \"%s\" ", s)
   136  	}
   137  	for _, s := range cfg.SectionSeparators.String() {
   138  		result += fmt.Sprintf(" --SectionSeparator %s ", s)
   139  	}
   140  	return result
   141  }