gitee.com/lonely0422/gometalinter.git@v3.0.1-0.20190307123442-32416ab75314+incompatible/config.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "os" 6 "path/filepath" 7 "runtime" 8 "text/template" 9 "time" 10 ) 11 12 // Config for gometalinter. This can be loaded from a JSON file with --config. 13 type Config struct { // nolint: maligned 14 // A map from linter name -> <LinterConfig|string>. 15 // 16 // For backwards compatibility, the value stored in the JSON blob can also 17 // be a string of the form "<command>:<pattern>". 18 Linters map[string]StringOrLinterConfig 19 20 // The set of linters that should be enabled. 21 Enable []string 22 Disable []string 23 24 // A map of linter name to message that is displayed. This is useful when linters display text 25 // that is useful only in isolation, such as errcheck which just reports the construct. 26 MessageOverride map[string]string 27 Severity map[string]string 28 VendoredLinters bool 29 Format string 30 Fast bool 31 Install bool 32 Update bool 33 Force bool 34 DownloadOnly bool 35 Debug bool 36 Concurrency int 37 Exclude []string 38 Include []string 39 Skip []string 40 Vendor bool 41 Cyclo int 42 LineLength int 43 MisspellLocale string 44 MinConfidence float64 45 MinOccurrences int 46 MinConstLength int 47 DuplThreshold int 48 Sort []string 49 Test bool 50 Deadline jsonDuration 51 Errors bool 52 JSON bool 53 Checkstyle bool 54 EnableGC bool 55 Aggregate bool 56 EnableAll bool 57 58 // Warn if a nolint directive was never matched to a linter issue 59 WarnUnmatchedDirective bool 60 61 formatTemplate *template.Template 62 } 63 64 type StringOrLinterConfig LinterConfig 65 66 func (c *StringOrLinterConfig) UnmarshalJSON(raw []byte) error { 67 var linterConfig LinterConfig 68 // first try to un-marshall directly into struct 69 origErr := json.Unmarshal(raw, &linterConfig) 70 if origErr == nil { 71 *c = StringOrLinterConfig(linterConfig) 72 return nil 73 } 74 75 // i.e. bytes didn't represent the struct, treat them as a string 76 var linterSpec string 77 if err := json.Unmarshal(raw, &linterSpec); err != nil { 78 return origErr 79 } 80 linter, err := parseLinterConfigSpec("", linterSpec) 81 if err != nil { 82 return err 83 } 84 *c = StringOrLinterConfig(linter) 85 return nil 86 } 87 88 type jsonDuration time.Duration 89 90 func (td *jsonDuration) UnmarshalJSON(raw []byte) error { 91 var durationAsString string 92 if err := json.Unmarshal(raw, &durationAsString); err != nil { 93 return err 94 } 95 duration, err := time.ParseDuration(durationAsString) 96 *td = jsonDuration(duration) 97 return err 98 } 99 100 // Duration returns the value as a time.Duration 101 func (td *jsonDuration) Duration() time.Duration { 102 return time.Duration(*td) 103 } 104 105 var sortKeys = []string{"none", "path", "line", "column", "severity", "message", "linter"} 106 107 // Configuration defaults. 108 var config = &Config{ 109 Format: DefaultIssueFormat, 110 111 Linters: map[string]StringOrLinterConfig{}, 112 Severity: map[string]string{ 113 "gotype": "error", 114 "gotypex": "error", 115 "test": "error", 116 "testify": "error", 117 "vet": "error", 118 }, 119 MessageOverride: map[string]string{ 120 "errcheck": "error return value not checked ({message})", 121 "gocyclo": "cyclomatic complexity {cyclo} of function {function}() is high (> {mincyclo})", 122 "gofmt": "file is not gofmted with -s", 123 "goimports": "file is not goimported", 124 "safesql": "potentially unsafe SQL statement", 125 "structcheck": "unused struct field {message}", 126 "unparam": "parameter {message}", 127 "varcheck": "unused variable or constant {message}", 128 }, 129 Enable: defaultEnabled(), 130 VendoredLinters: true, 131 Concurrency: runtime.NumCPU(), 132 Cyclo: 10, 133 LineLength: 80, 134 MisspellLocale: "", 135 MinConfidence: 0.8, 136 MinOccurrences: 3, 137 MinConstLength: 3, 138 DuplThreshold: 50, 139 Sort: []string{"none"}, 140 Deadline: jsonDuration(time.Second * 30), 141 } 142 143 func loadConfigFile(filename string) error { 144 r, err := os.Open(filename) 145 if err != nil { 146 return err 147 } 148 defer r.Close() // nolint: errcheck 149 err = json.NewDecoder(r).Decode(config) 150 if err != nil { 151 return err 152 } 153 for _, disable := range config.Disable { 154 for i, enable := range config.Enable { 155 if enable == disable { 156 config.Enable = append(config.Enable[:i], config.Enable[i+1:]...) 157 break 158 } 159 } 160 } 161 return err 162 } 163 164 func findDefaultConfigFile() (fullPath string, found bool, err error) { 165 prevPath := "" 166 dirPath, err := os.Getwd() 167 if err != nil { 168 return "", false, err 169 } 170 171 for dirPath != prevPath { 172 fullPath, found, err = findConfigFileInDir(dirPath) 173 if err != nil || found { 174 return fullPath, found, err 175 } 176 prevPath, dirPath = dirPath, filepath.Dir(dirPath) 177 } 178 179 return "", false, nil 180 } 181 182 func findConfigFileInDir(dirPath string) (fullPath string, found bool, err error) { 183 fullPath = filepath.Join(dirPath, defaultConfigPath) 184 if _, err := os.Stat(fullPath); err != nil { 185 if os.IsNotExist(err) { 186 return "", false, nil 187 } 188 return "", false, err 189 } 190 191 return fullPath, true, nil 192 }