github.com/golangci/go-tools@v0.0.0-20190318060251-af6baa5dc196/config/config.go (about) 1 package config 2 3 import ( 4 "os" 5 "path/filepath" 6 7 "github.com/BurntSushi/toml" 8 ) 9 10 func mergeLists(a, b []string) []string { 11 out := make([]string, 0, len(a)+len(b)) 12 for _, el := range b { 13 if el == "inherit" { 14 out = append(out, a...) 15 } else { 16 out = append(out, el) 17 } 18 } 19 20 return out 21 } 22 23 func normalizeList(list []string) []string { 24 if len(list) > 1 { 25 nlist := make([]string, 0, len(list)) 26 nlist = append(nlist, list[0]) 27 for i, el := range list[1:] { 28 if el != list[i] { 29 nlist = append(nlist, el) 30 } 31 } 32 list = nlist 33 } 34 35 for _, el := range list { 36 if el == "inherit" { 37 // This should never happen, because the default config 38 // should not use "inherit" 39 panic(`unresolved "inherit"`) 40 } 41 } 42 43 return list 44 } 45 46 func (cfg Config) Merge(ocfg Config) Config { 47 if ocfg.Checks != nil { 48 cfg.Checks = mergeLists(cfg.Checks, ocfg.Checks) 49 } 50 if ocfg.Initialisms != nil { 51 cfg.Initialisms = mergeLists(cfg.Initialisms, ocfg.Initialisms) 52 } 53 if ocfg.DotImportWhitelist != nil { 54 cfg.DotImportWhitelist = mergeLists(cfg.DotImportWhitelist, ocfg.DotImportWhitelist) 55 } 56 if ocfg.HTTPStatusCodeWhitelist != nil { 57 cfg.HTTPStatusCodeWhitelist = mergeLists(cfg.HTTPStatusCodeWhitelist, ocfg.HTTPStatusCodeWhitelist) 58 } 59 return cfg 60 } 61 62 type Config struct { 63 // TODO(dh): this implementation makes it impossible for external 64 // clients to add their own checkers with configuration. At the 65 // moment, we don't really care about that; we don't encourage 66 // that people use this package. In the future, we may. The 67 // obvious solution would be using map[string]interface{}, but 68 // that's obviously subpar. 69 70 Checks []string `toml:"checks"` 71 Initialisms []string `toml:"initialisms"` 72 DotImportWhitelist []string `toml:"dot_import_whitelist"` 73 HTTPStatusCodeWhitelist []string `toml:"http_status_code_whitelist"` 74 } 75 76 var defaultConfig = Config{ 77 Checks: []string{"all", "-ST1000", "-ST1003", "-ST1016"}, 78 Initialisms: []string{ 79 "ACL", "API", "ASCII", "CPU", "CSS", "DNS", 80 "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", 81 "IP", "JSON", "QPS", "RAM", "RPC", "SLA", 82 "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", 83 "UDP", "UI", "GID", "UID", "UUID", "URI", 84 "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", 85 "XSS", 86 }, 87 DotImportWhitelist: []string{}, 88 HTTPStatusCodeWhitelist: []string{"200", "400", "404", "500"}, 89 } 90 91 const configName = "staticcheck.conf" 92 93 func parseConfigs(dir string) ([]Config, error) { 94 var out []Config 95 96 // TODO(dh): consider stopping at the GOPATH/module boundary 97 for dir != "" { 98 f, err := os.Open(filepath.Join(dir, configName)) 99 if os.IsNotExist(err) { 100 ndir := filepath.Dir(dir) 101 if ndir == dir { 102 break 103 } 104 dir = ndir 105 continue 106 } 107 if err != nil { 108 return nil, err 109 } 110 var cfg Config 111 _, err = toml.DecodeReader(f, &cfg) 112 f.Close() 113 if err != nil { 114 return nil, err 115 } 116 out = append(out, cfg) 117 ndir := filepath.Dir(dir) 118 if ndir == dir { 119 break 120 } 121 dir = ndir 122 } 123 out = append(out, defaultConfig) 124 if len(out) < 2 { 125 return out, nil 126 } 127 for i := 0; i < len(out)/2; i++ { 128 out[i], out[len(out)-1-i] = out[len(out)-1-i], out[i] 129 } 130 return out, nil 131 } 132 133 func mergeConfigs(confs []Config) Config { 134 if len(confs) == 0 { 135 // This shouldn't happen because we always have at least a 136 // default config. 137 panic("trying to merge zero configs") 138 } 139 if len(confs) == 1 { 140 return confs[0] 141 } 142 conf := confs[0] 143 for _, oconf := range confs[1:] { 144 conf = conf.Merge(oconf) 145 } 146 return conf 147 } 148 149 func Load(dir string) (Config, error) { 150 confs, err := parseConfigs(dir) 151 if err != nil { 152 return Config{}, err 153 } 154 conf := mergeConfigs(confs) 155 156 conf.Checks = normalizeList(conf.Checks) 157 conf.Initialisms = normalizeList(conf.Initialisms) 158 conf.DotImportWhitelist = normalizeList(conf.DotImportWhitelist) 159 conf.HTTPStatusCodeWhitelist = normalizeList(conf.HTTPStatusCodeWhitelist) 160 161 return conf, nil 162 }