github.com/Minish144/prototool-arm64@v1.3.0/internal/settings/settings.go (about) 1 // Copyright (c) 2018 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package settings 22 23 import ( 24 "fmt" 25 "strconv" 26 "strings" 27 28 "go.uber.org/zap" 29 ) 30 31 const ( 32 // DefaultConfigFilename is the default config filename. 33 DefaultConfigFilename = "prototool.yaml" 34 35 // GenPluginTypeNone says there is no specific plugin type. 36 GenPluginTypeNone GenPluginType = iota 37 // GenPluginTypeGo says the plugin is a Golang plugin that 38 // is or uses github.com/golang/protobuf. 39 // This will use GenGoPluginOptions. 40 GenPluginTypeGo 41 // GenPluginTypeGogo says the plugin is a Golang plugin that 42 // is or uses github.com/gogo/protobuf. 43 // This will use GenGoPluginOptions. 44 GenPluginTypeGogo 45 ) 46 47 var ( 48 // ConfigFilenames are all possible config filenames. 49 ConfigFilenames = []string{ 50 DefaultConfigFilename, 51 "prototool.json", 52 } 53 54 _genPluginTypeToString = map[GenPluginType]string{ 55 GenPluginTypeNone: "", 56 GenPluginTypeGo: "go", 57 GenPluginTypeGogo: "gogo", 58 } 59 _stringToGenPluginType = map[string]GenPluginType{ 60 "": GenPluginTypeNone, 61 "go": GenPluginTypeGo, 62 "gogo": GenPluginTypeGogo, 63 } 64 65 _genPluginTypeToIsGo = map[GenPluginType]bool{ 66 GenPluginTypeNone: false, 67 GenPluginTypeGo: true, 68 GenPluginTypeGogo: false, 69 } 70 _genPluginTypeToIsGogo = map[GenPluginType]bool{ 71 GenPluginTypeNone: false, 72 GenPluginTypeGo: false, 73 GenPluginTypeGogo: true, 74 } 75 ) 76 77 // GenPluginType is a type of protoc plugin. 78 type GenPluginType int 79 80 // String implements fmt.Stringer. 81 func (g GenPluginType) String() string { 82 if s, ok := _genPluginTypeToString[g]; ok { 83 return s 84 } 85 return strconv.Itoa(int(g)) 86 } 87 88 // The Is functions do not validate if the plugin type is known 89 // as this is supposed to be done in ConfigProvider. 90 // It's a lot easier if they just return a bool. 91 92 // IsGo returns true if the plugin type is associated with 93 // github.com/golang/protobuf. 94 func (g GenPluginType) IsGo() bool { 95 return _genPluginTypeToIsGo[g] 96 } 97 98 // IsGogo returns true if the plugin type is associated with 99 // github.com/gogo/protobuf. 100 func (g GenPluginType) IsGogo() bool { 101 return _genPluginTypeToIsGogo[g] 102 } 103 104 // ParseGenPluginType parses the GenPluginType from the given string. 105 // 106 // Input is case-insensitive. 107 func ParseGenPluginType(s string) (GenPluginType, error) { 108 genPluginType, ok := _stringToGenPluginType[strings.ToLower(s)] 109 if !ok { 110 return GenPluginTypeNone, fmt.Errorf("could not parse %s to a GenPluginType", s) 111 } 112 return genPluginType, nil 113 } 114 115 // Config is the main config. 116 // 117 // Configs are derived from ExternalConfigs, which represent the Config 118 // in a more palpable format for configuration via a config file 119 // or flags. 120 // 121 // String slices will be deduped and sorted if returned from this package. 122 // Configs will be validated if returned from this package. 123 // 124 // All paths returned should be absolute paths. Outside of this package, 125 // all other internal packages should verify that all given paths are 126 // absolute, except for the internal/text package. 127 type Config struct { 128 // The working directory path. 129 // Expected to be absolute path. 130 DirPath string 131 // The prefixes to exclude. 132 // Expected to be absolute paths. 133 // Expected to be unique. 134 ExcludePrefixes []string 135 // The compile config. 136 Compile CompileConfig 137 // The create config. 138 Create CreateConfig 139 // Lint is a special case. If nothing is set, the defaults are used. Either IDs, 140 // or Group/IncludeIDs/ExcludeIDs can be set, but not both. There can be no overlap 141 // between IncludeIDs and ExcludeIDs. 142 Lint LintConfig 143 // The gen config. 144 Gen GenConfig 145 } 146 147 // CompileConfig is the compile config. 148 type CompileConfig struct { 149 // The Protobuf version to use from https://github.com/protocolbuffers/protobuf/releases. 150 // Must have a valid protoc zip file asset, so for example 3.5.0 is a valid version 151 // but 3.5.0.1 is not. 152 ProtobufVersion string 153 // IncludePaths are the additional paths to include with -I to protoc. 154 // Expected to be absolute paths. 155 // Expected to be unique. 156 IncludePaths []string 157 // IncludeWellKnownTypes says to add the Google well-known types with -I to protoc. 158 IncludeWellKnownTypes bool 159 // AllowUnusedImports says to not error when an import is not used. 160 AllowUnusedImports bool 161 } 162 163 // CreateConfig is the create config. 164 type CreateConfig struct { 165 // The map from directory to the package to use as the base. 166 // Directories expected to be absolute paths. 167 DirPathToBasePackage map[string]string 168 } 169 170 // LintConfig is the lint config. 171 type LintConfig struct { 172 // NoDefault is set to exclude the default set of linters. 173 NoDefault bool 174 // IncludeIDs are the list of linter IDs to use in addition to the defaults. 175 // Expected to be all uppercase. 176 // Expected to be unique. 177 // Expected to have no overlap with ExcludeIDs. 178 IncludeIDs []string 179 // ExcludeIDs are the list of linter IDs to exclude from the defaults. 180 // Expected to be all uppercase. 181 // Expected to be unique. 182 // Expected to have no overlap with IncludeIDs. 183 ExcludeIDs []string 184 // IgnoreIDToFilePaths is the map of ID to absolute file path to ignore. 185 // IDs expected to be all upper-case. 186 // File paths expected to be absolute paths. 187 IgnoreIDToFilePaths map[string][]string 188 } 189 190 // GenConfig is the gen config. 191 type GenConfig struct { 192 // The go plugin options. 193 GoPluginOptions GenGoPluginOptions 194 // The plugins. 195 // These will be sorted by name if returned from this package. 196 Plugins []GenPlugin 197 } 198 199 // GenGoPluginOptions are options for go plugins. 200 // 201 // This will be used for plugin types go, gogo, gogrpc, gogogrpc. 202 type GenGoPluginOptions struct { 203 // The base import path. This should be the go path of the config file. 204 // This is required for go plugins. 205 ImportPath string 206 // ExtraModifiers to include with Mfile=package. 207 ExtraModifiers map[string]string 208 } 209 210 // GenPlugin is a plugin to use. 211 type GenPlugin struct { 212 // The name of the plugin. For example, if you want to use 213 // protoc-gen-gogoslick, the name is "gogoslick". 214 Name string 215 // The path to the executable. For example, if the name is "grpc-cpp" 216 // but the path to the executable "protoc-gen-grpc-cpp" is "/usr/local/bin/grpc_cpp_plugin", 217 // then this will be "/usr/local/bin/grpc_cpp_plugin". 218 Path string 219 // The type, if any. This will be GenPluginTypeNone if 220 // there is no specific type. 221 Type GenPluginType 222 // Extra flags to pass. 223 // If there is an associated type, some flags may be generated, 224 // for example plugins=grpc or Mfile=package modifiers. 225 Flags string 226 // The path to output to. 227 // Must be relative in a config file. 228 OutputPath OutputPath 229 } 230 231 // OutputPath is an output path. 232 // 233 // We need the relative path for go package references for generation. 234 // TODO: we might want all paths to have the given path and absolute path, 235 // see if we need this. 236 type OutputPath struct { 237 // Must be relative. 238 RelPath string 239 AbsPath string 240 } 241 242 // ExternalConfig is the external representation of Config. 243 // 244 // It is meant to be set by a YAML or JSON config file, or flags. 245 type ExternalConfig struct { 246 Excludes []string `json:"excludes,omitempty" yaml:"excludes,omitempty"` 247 Protoc struct { 248 AllowUnusedImports bool `json:"allow_unused_imports,omitempty" yaml:"allow_unused_imports,omitempty"` 249 Version string `json:"version,omitempty" yaml:"version,omitempty"` 250 Includes []string `json:"includes,omitempty" yaml:"includes,omitempty"` 251 } `json:"protoc,omitempty" yaml:"protoc,omitempty"` 252 Create struct { 253 Packages []struct { 254 Directory string `json:"directory,omitempty" yaml:"directory,omitempty"` 255 Name string `json:"name,omitempty" yaml:"name,omitempty"` 256 } `json:"packages,omitempty" yaml:"packages,omitempty"` 257 } `json:"create,omitempty" yaml:"create,omitempty"` 258 Lint struct { 259 Ignores []struct { 260 ID string `json:"id,omitempty" yaml:"id,omitempty"` 261 Files []string `json:"files,omitempty" yaml:"files,omitempty"` 262 } 263 Rules struct { 264 NoDefault bool `json:"no_default,omitempty" yaml:"no_default,omitempty"` 265 Add []string `json:"add" yaml:"add"` 266 Remove []string `json:"remove" yaml:"remove"` 267 } 268 } `json:"lint,omitempty" yaml:"lint,omitempty"` 269 Gen struct { 270 GoOptions struct { 271 ImportPath string `json:"import_path,omitempty" yaml:"import_path,omitempty"` 272 ExtraModifiers map[string]string `json:"extra_modifiers,omitempty" yaml:"extra_modifiers,omitempty"` 273 } `json:"go_options,omitempty" yaml:"go_options,omitempty"` 274 Plugins []struct { 275 Name string `json:"name,omitempty" yaml:"name,omitempty"` 276 Type string `json:"type,omitempty" yaml:"type,omitempty"` 277 Flags string `json:"flags,omitempty" yaml:"flags,omitempty"` 278 Output string `json:"output,omitempty" yaml:"output,omitempty"` 279 Path string `json:"path,omitempty" yaml:"path,omitempty"` 280 } `json:"plugins,omitempty" yaml:"plugins,omitempty"` 281 } `json:"generate,omitempty" yaml:"generate,omitempty"` 282 } 283 284 // ConfigProvider provides Configs. 285 type ConfigProvider interface { 286 // GetForDir tries to find a file named by one of the ConfigFilenames starting in the 287 // given directory, and going up a directory until hitting root. 288 // 289 // The directory must be an absolute path. 290 // 291 // If such a file is found, it is read as an ExternalConfig and converted to a Config. 292 // If no such file is found, Config{} is returned. 293 // If multiple files named by one of the ConfigFilenames are found in the same 294 // directory, error is returned. 295 GetForDir(dirPath string) (Config, error) 296 // Get tries to find a file named filePath with a config. 297 // 298 // The path must be an absolute path. 299 // The file must have either the extension .yaml or .json. 300 // 301 // If such a file is found, it is read as an ExternalConfig and converted to a Config. 302 // If no such file is found, Config{} is returned. 303 Get(filePath string) (Config, error) 304 // GetFilePathForDir tries to find a file named by one of the ConfigFilenames starting in the 305 // given directory, and going up a directory until hitting root. 306 // 307 // The directory must be an absolute path. 308 // 309 // If such a file is found, it is returned. 310 // If no such file is found, "" is returned. 311 // If multiple files named by one of the ConfigFilenames are found in the same 312 // directory, error is returned. 313 GetFilePathForDir(dirPath string) (string, error) 314 // GetForData returns a Config for the given ExternalConfigData in JSON format. 315 // The Config will be as if there was a configuration file at the given dirPath. 316 GetForData(dirPath string, externalConfigData string) (Config, error) 317 318 // GetExcludePrefixesForDir tries to find a file named by one of the ConfigFilenames in the given 319 // directory and returns the cleaned absolute exclude prefixes. Unlike other functions 320 // on ConfigProvider, this has no recursive functionality - if there is no 321 // config file, nothing is returned. 322 // If multiple files named by one of the ConfigFilenames are found in the same 323 // directory, error is returned. 324 GetExcludePrefixesForDir(dirPath string) ([]string, error) 325 // GetExcludePrefixesForData gets the exclude prefixes for the given ExternalConfigData in JSON format. 326 // The logic will act is if there was a configuration file at the given dirPath. 327 GetExcludePrefixesForData(dirPath string, externalConfigData string) ([]string, error) 328 } 329 330 // ConfigProviderOption is an option for a new ConfigProvider. 331 type ConfigProviderOption func(*configProvider) 332 333 // ConfigProviderWithLogger returns a ConfigProviderOption that uses the given logger. 334 // 335 // The default is to use zap.NewNop(). 336 func ConfigProviderWithLogger(logger *zap.Logger) ConfigProviderOption { 337 return func(configProvider *configProvider) { 338 configProvider.logger = logger 339 } 340 } 341 342 // NewConfigProvider returns a new ConfigProvider. 343 func NewConfigProvider(options ...ConfigProviderOption) ConfigProvider { 344 return newConfigProvider(options...) 345 }