@@ -19,7 +19,6 @@ import (
1919 "io/ioutil"
2020 "os"
2121 "path"
22- "path/filepath"
2322 "runtime/debug"
2423 "strings"
2524
@@ -35,56 +34,67 @@ func errExit(format string, args ...interface{}) {
3534}
3635
3736var (
38- flagPackageName string
37+ flagOutputFile string
38+ flagConfigFile string
39+ flagOldConfigStyle bool
40+ flagOutputConfig bool
41+ flagPrintVersion bool
42+ flagPackageName string
43+
44+ // The options below are deprecated, and they will be removed in a future
45+ // release. Please use the new config file format.
3946 flagGenerate string
40- flagOutputFile string
4147 flagIncludeTags string
4248 flagExcludeTags string
4349 flagTemplatesDir string
4450 flagImportMapping string
4551 flagExcludeSchemas string
46- flagConfigFile string
4752 flagResponseTypeSuffix string
4853 flagAliasTypes bool
49- flagPrintVersion bool
50- flagOldAllOfOutput bool
51- flagOldEnumConflicts bool
52- flagOldAliasing bool
5354)
5455
5556type configuration struct {
56- PackageName string `yaml:"package"`
57- GenerateTargets []string `yaml:"generate"`
58- OutputFile string `yaml:"output"`
59- IncludeTags []string `yaml:"include-tags"`
60- ExcludeTags []string `yaml:"exclude-tags"`
61- TemplatesDir string `yaml:"templates"`
62- ImportMapping map [string ]string `yaml:"import-mapping"`
63- ExcludeSchemas []string `yaml:"exclude-schemas"`
64- OldAllOfOutput bool `yaml:"old-all-of-output"`
65- OldEnumConflicts bool `yaml:"old-enum-conflicts"`
66- OldAliasing bool `yaml:"old-aliasing"`
67- ResponseTypeSuffix string `yaml:"response-type-suffix"`
57+ codegen.Configuration `yaml:",inline"`
58+
59+ // OutputFile is the filename to output.
60+ OutputFile string `yaml:"output,omitempty"`
6861}
6962
70- func main () {
63+ // This structure is deprecated. Please add no more flags here. It is here
64+ // for backwards compatibility and it will be removed in the future.
65+ type oldConfiguration struct {
66+ PackageName string `yaml:"package"`
67+ GenerateTargets []string `yaml:"generate"`
68+ OutputFile string `yaml:"output"`
69+ IncludeTags []string `yaml:"include-tags"`
70+ ExcludeTags []string `yaml:"exclude-tags"`
71+ TemplatesDir string `yaml:"templates"`
72+ ImportMapping map [string ]string `yaml:"import-mapping"`
73+ ExcludeSchemas []string `yaml:"exclude-schemas"`
74+ ResponseTypeSuffix string `yaml:"response-type-suffix"`
75+ Compatibility codegen.CompatibilityOptions `yaml:"compatibility"`
76+ }
7177
78+ func main () {
79+ flag .StringVar (& flagOutputFile , "o" , "" , "Where to output generated code, stdout is default" )
80+ flag .BoolVar (& flagOldConfigStyle , "old-config-style" , false , "whether to use the older style config file format" )
81+ flag .BoolVar (& flagOutputConfig , "output-config" , false , "when true, outputs a configuration file for oapi-codegen using current settings" )
82+ flag .StringVar (& flagConfigFile , "config" , "" , "a YAML config file that controls oapi-codegen behavior" )
83+ flag .BoolVar (& flagPrintVersion , "version" , false , "when specified, print version and exit" )
7284 flag .StringVar (& flagPackageName , "package" , "" , "The package name for generated code" )
85+
86+ // All flags below are deprecated, and will be removed in a future release. Please do not
87+ // update their behavior.
7388 flag .StringVar (& flagGenerate , "generate" , "types,client,server,spec" ,
7489 `Comma-separated list of code to generate; valid options: "types", "client", "chi-server", "server", "gin", "spec", "skip-fmt", "skip-prune"` )
75- flag .StringVar (& flagOutputFile , "o" , "" , "Where to output generated code, stdout is default" )
7690 flag .StringVar (& flagIncludeTags , "include-tags" , "" , "Only include operations with the given tags. Comma-separated list of tags." )
7791 flag .StringVar (& flagExcludeTags , "exclude-tags" , "" , "Exclude operations that are tagged with the given tags. Comma-separated list of tags." )
7892 flag .StringVar (& flagTemplatesDir , "templates" , "" , "Path to directory containing user templates" )
7993 flag .StringVar (& flagImportMapping , "import-mapping" , "" , "A dict from the external reference to golang package path" )
8094 flag .StringVar (& flagExcludeSchemas , "exclude-schemas" , "" , "A comma separated list of schemas which must be excluded from generation" )
81- flag .StringVar (& flagConfigFile , "config" , "" , "a YAML config file that controls oapi-codegen behavior" )
8295 flag .StringVar (& flagResponseTypeSuffix , "response-type-suffix" , "" , "the suffix used for responses types" )
8396 flag .BoolVar (& flagAliasTypes , "alias-types" , false , "Alias type declarations of possible" )
84- flag .BoolVar (& flagPrintVersion , "version" , false , "when specified, print version and exit" )
85- flag .BoolVar (& flagOldAllOfOutput , "old-all-of-output" , false , "when true, old and incorrect AllOf implementation is used" )
86- flag .BoolVar (& flagOldEnumConflicts , "old-enum-conflicts" , false , "when true, use old style enum naming" )
87- flag .BoolVar (& flagOldAliasing , "old-aliasing" , false , "when true, generate older style redefined types" )
97+
8898 flag .Parse ()
8999
90100 if flagPrintVersion {
@@ -103,81 +113,70 @@ func main() {
103113 os .Exit (1 )
104114 }
105115
106- cfg := configFromFlags ()
107-
108- // If the package name has not been specified, we will use the name of the
109- // swagger file.
110- if cfg .PackageName == "" {
111- path := flag .Arg (0 )
112- baseName := filepath .Base (path )
113- // Split the base name on '.' to get the first part of the file.
114- nameParts := strings .Split (baseName , "." )
115- cfg .PackageName = codegen .ToCamelCase (nameParts [0 ])
116- }
117-
118- opts := codegen.Options {
119- AliasTypes : flagAliasTypes ,
120- ResponseTypeSuffix : flagResponseTypeSuffix ,
121- }
122- for _ , g := range cfg .GenerateTargets {
123- switch g {
124- case "client" :
125- opts .GenerateClient = true
126- case "chi-server" :
127- opts .GenerateChiServer = true
128- case "server" :
129- opts .GenerateEchoServer = true
130- case "gin" :
131- opts .GenerateGinServer = true
132- case "types" :
133- opts .GenerateTypes = true
134- case "spec" :
135- opts .EmbedSpec = true
136- case "skip-fmt" :
137- opts .SkipFmt = true
138- case "skip-prune" :
139- opts .SkipPrune = true
140- default :
141- fmt .Printf ("unknown generate option %s\n " , g )
142- flag .PrintDefaults ()
143- os .Exit (1 )
116+ var opts configuration
117+ if ! flagOldConfigStyle {
118+ // We simply read the configuration from disk.
119+ if flagConfigFile != "" {
120+ buf , err := ioutil .ReadFile (flagConfigFile )
121+ if err != nil {
122+ errExit ("error reading config file '%s': %v" , flagConfigFile , err )
123+ }
124+ err = yaml .Unmarshal (buf , & opts )
125+ if err != nil {
126+ errExit ("error parsing'%s' as YAML: %v" , flagConfigFile , err )
127+ }
128+ }
129+ var err error
130+ opts , err = updateConfigFromFlags (opts )
131+ if err != nil {
132+ errExit ("error processing flags: %v" , err )
133+ }
134+ } else {
135+ var oldConfig oldConfiguration
136+ if flagConfigFile != "" {
137+ buf , err := ioutil .ReadFile (flagConfigFile )
138+ if err != nil {
139+ errExit ("error reading config file '%s': %v" , flagConfigFile , err )
140+ }
141+ err = yaml .Unmarshal (buf , & oldConfig )
142+ if err != nil {
143+ errExit ("error parsing'%s' as YAML: %v" , flagConfigFile , err )
144+ }
144145 }
146+ opts = newConfigFromOldConfig (oldConfig )
145147 }
146148
147- opts . IncludeTags = cfg . IncludeTags
148- opts . ExcludeTags = cfg . ExcludeTags
149- opts .ExcludeSchemas = cfg . ExcludeSchemas
149+ // Ensure default values are set if user hasn't specified some needed
150+ // fields.
151+ opts .Configuration = opts . UpdateDefaults ()
150152
151- if opts .GenerateEchoServer && opts .GenerateChiServer {
152- errExit ("can not specify both server and chi-server targets simultaneously" )
153+ // Now, ensure that the config options are valid.
154+ if err := opts .Validate (); err != nil {
155+ errExit ("configuration error: %v" , err )
153156 }
154157
155- swagger , err := util .LoadSwagger (flag .Arg (0 ))
156- if err != nil {
157- errExit ("error loading swagger spec in %s\n : %s" , flag .Arg (0 ), err )
158+ // If the user asked to output configuration, output it to stdout and exit
159+ if flagOutputConfig {
160+ buf , err := yaml .Marshal (opts )
161+ if err != nil {
162+ errExit ("error YAML marshaling configuration: %v" , err )
163+ }
164+ fmt .Print (string (buf ))
165+ return
158166 }
159167
160- templates , err := loadTemplateOverrides ( cfg . TemplatesDir )
168+ swagger , err := util . LoadSwagger ( flag . Arg ( 0 ) )
161169 if err != nil {
162- errExit ("error loading template overrides: %s\n " , err )
170+ errExit ("error loading swagger spec in %s\n : %s" , flag . Arg ( 0 ) , err )
163171 }
164- opts .UserTemplates = templates
165-
166- opts .ImportMapping = cfg .ImportMapping
167-
168- opts .OldMergeSchemas = cfg .OldAllOfOutput
169172
170- opts .OldEnumConflicts = cfg .OldEnumConflicts
171-
172- opts .OldAliasing = cfg .OldAliasing
173-
174- code , err := codegen .Generate (swagger , cfg .PackageName , opts )
173+ code , err := codegen .Generate (swagger , opts .Configuration )
175174 if err != nil {
176175 errExit ("error generating code: %s\n " , err )
177176 }
178177
179- if cfg .OutputFile != "" {
180- err = ioutil .WriteFile (cfg .OutputFile , []byte (code ), 0644 )
178+ if opts .OutputFile != "" {
179+ err = ioutil .WriteFile (opts .OutputFile , []byte (code ), 0644 )
181180 if err != nil {
182181 errExit ("error writing generated code to file: %s" , err )
183182 }
@@ -222,25 +221,54 @@ func loadTemplateOverrides(templatesDir string) (map[string]string, error) {
222221 return templates , nil
223222}
224223
225- // configFromFlags parses the flags and the config file. Anything which is
226- // a zerovalue in the configuration file will be replaced with the flag
227- // value, this means that the config file overrides flag values.
228- func configFromFlags () * configuration {
229- var cfg configuration
224+ // updateConfigFromFlags updates a loaded configuration from flags. Flags
225+ // override anything in the file. We generate errors for command line options
226+ // associated with the old style configuration
227+ func updateConfigFromFlags (cfg configuration ) (configuration , error ) {
228+ if flagPackageName != "" {
229+ cfg .PackageName = flagPackageName
230+ }
230231
231- // Load the configuration file first.
232- if flagConfigFile != "" {
233- f , err := os .Open (flagConfigFile )
234- if err != nil {
235- errExit ("failed to open config file with error: %v\n " , err )
236- }
237- defer f .Close ()
238- err = yaml .NewDecoder (f ).Decode (& cfg )
239- if err != nil {
240- errExit ("error parsing config file: %v\n " , err )
241- }
232+ var unsupportedFlags []string
233+
234+ if flagGenerate != "types,client,server,spec" {
235+ unsupportedFlags = append (unsupportedFlags , "--generate" )
236+ }
237+ if flagIncludeTags != "" {
238+ unsupportedFlags = append (unsupportedFlags , "--include-tags" )
239+ }
240+ if flagExcludeTags != "" {
241+ unsupportedFlags = append (unsupportedFlags , "--exclude-tags" )
242+ }
243+ if flagTemplatesDir != "" {
244+ unsupportedFlags = append (unsupportedFlags , "--templates" )
245+ }
246+ if flagImportMapping != "" {
247+ unsupportedFlags = append (unsupportedFlags , "--import-mapping" )
248+ }
249+ if flagExcludeSchemas != "" {
250+ unsupportedFlags = append (unsupportedFlags , "--exclude-schemas" )
251+ }
252+ if flagResponseTypeSuffix != "" {
253+ unsupportedFlags = append (unsupportedFlags , "--response-type-suffix" )
254+ }
255+ if flagAliasTypes {
256+ unsupportedFlags = append (unsupportedFlags , "--alias-types" )
257+ }
258+
259+ if len (unsupportedFlags ) > 0 {
260+ return configuration {}, fmt .Errorf ("flags %s aren't supported in " +
261+ "new config style, please use --old-style-config or update your configuration" ,
262+ strings .Join (unsupportedFlags , ", " ))
242263 }
243264
265+ return cfg , nil
266+ }
267+
268+ // updateOldConfigFromFlags parses the flags and the config file. Anything which is
269+ // a zerovalue in the configuration file will be replaced with the flag
270+ // value, this means that the config file overrides flag values.
271+ func updateOldConfigFromFlags (cfg oldConfiguration ) oldConfiguration {
244272 if cfg .PackageName == "" {
245273 cfg .PackageName = flagPackageName
246274 }
@@ -269,18 +297,61 @@ func configFromFlags() *configuration {
269297 if cfg .OutputFile == "" {
270298 cfg .OutputFile = flagOutputFile
271299 }
300+ return cfg
301+ }
272302
273- if cfg .OldAllOfOutput == false {
274- cfg .OldAllOfOutput = flagOldAllOfOutput
303+ func newConfigFromOldConfig (c oldConfiguration ) configuration {
304+ // Take flags into account.
305+ cfg := updateOldConfigFromFlags (c )
306+
307+ // Now, copy over field by field, translating flags and old values as
308+ // necessary.
309+ opts := codegen.Configuration {
310+ PackageName : cfg .PackageName ,
275311 }
312+ opts .OutputOptions .ResponseTypeSuffix = flagResponseTypeSuffix
276313
277- if cfg .OldEnumConflicts == false {
278- cfg .OldEnumConflicts = flagOldEnumConflicts
314+ for _ , g := range cfg .GenerateTargets {
315+ switch g {
316+ case "client" :
317+ opts .Generate .Client = true
318+ case "chi-server" :
319+ opts .Generate .ChiServer = true
320+ case "server" :
321+ opts .Generate .EchoServer = true
322+ case "gin" :
323+ opts .Generate .GinServer = true
324+ case "types" :
325+ opts .Generate .Models = true
326+ case "spec" :
327+ opts .Generate .EmbeddedSpec = true
328+ case "skip-fmt" :
329+ opts .OutputOptions .SkipFmt = true
330+ case "skip-prune" :
331+ opts .OutputOptions .SkipPrune = true
332+ default :
333+ fmt .Printf ("unknown generate option %s\n " , g )
334+ flag .PrintDefaults ()
335+ os .Exit (1 )
336+ }
279337 }
280338
281- if cfg .OldAliasing == false {
282- cfg .OldAliasing = flagOldAliasing
339+ opts .OutputOptions .IncludeTags = cfg .IncludeTags
340+ opts .OutputOptions .ExcludeTags = cfg .ExcludeTags
341+ opts .OutputOptions .ExcludeSchemas = cfg .ExcludeSchemas
342+
343+ templates , err := loadTemplateOverrides (cfg .TemplatesDir )
344+ if err != nil {
345+ errExit ("error loading template overrides: %s\n " , err )
283346 }
347+ opts .OutputOptions .UserTemplates = templates
348+
349+ opts .ImportMapping = cfg .ImportMapping
350+
351+ opts .Compatibility = cfg .Compatibility
284352
285- return & cfg
353+ return configuration {
354+ Configuration : opts ,
355+ OutputFile : cfg .OutputFile ,
356+ }
286357}
0 commit comments