github.com/rzurga/go-swagger@v0.28.1-0.20211109195225-5d1f453ffa3a/cmd/swagger/commands/generate/shared.go (about) 1 package generate 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "log" 7 "os" 8 "path/filepath" 9 "strings" 10 11 "github.com/go-openapi/analysis" 12 "github.com/go-openapi/swag" 13 "github.com/go-swagger/go-swagger/generator" 14 flags "github.com/jessevdk/go-flags" 15 "github.com/spf13/viper" 16 ) 17 18 // FlattenCmdOptions determines options to the flatten spec preprocessing 19 type FlattenCmdOptions struct { 20 WithExpand bool `long:"with-expand" description:"expands all $ref's in spec prior to generation (shorthand to --with-flatten=expand)" group:"shared"` 21 WithFlatten []string `long:"with-flatten" description:"flattens all $ref's in spec prior to generation" choice:"minimal" choice:"full" choice:"expand" choice:"verbose" choice:"noverbose" choice:"remove-unused" default:"minimal" default:"verbose" group:"shared"` // nolint: staticcheck 22 } 23 24 // SetFlattenOptions builds flatten options from command line args 25 func (f *FlattenCmdOptions) SetFlattenOptions(dflt *analysis.FlattenOpts) (res *analysis.FlattenOpts) { 26 res = &analysis.FlattenOpts{} 27 if dflt != nil { 28 *res = *dflt 29 } 30 if f == nil { 31 return 32 } 33 verboseIsSet := false 34 minimalIsSet := false 35 expandIsSet := false 36 if f.WithExpand { 37 res.Expand = true 38 expandIsSet = true 39 } 40 for _, opt := range f.WithFlatten { 41 switch opt { 42 case "verbose": 43 res.Verbose = true 44 verboseIsSet = true 45 case "noverbose": 46 if !verboseIsSet { 47 // verbose flag takes precedence 48 res.Verbose = false 49 verboseIsSet = true 50 } 51 case "remove-unused": 52 res.RemoveUnused = true 53 case "expand": 54 res.Expand = true 55 expandIsSet = true 56 case "full": 57 if !minimalIsSet && !expandIsSet { 58 // minimal flag takes precedence 59 res.Minimal = false 60 minimalIsSet = true 61 } 62 case "minimal": 63 if !expandIsSet { 64 // expand flag takes precedence 65 res.Minimal = true 66 minimalIsSet = true 67 } 68 } 69 } 70 return 71 } 72 73 type sharedCommand interface { 74 apply(*generator.GenOpts) 75 getConfigFile() string 76 generate(*generator.GenOpts) error 77 log(string) 78 } 79 80 type schemeOptions struct { 81 Principal string `short:"P" long:"principal" description:"the model to use for the security principal"` 82 DefaultScheme string `long:"default-scheme" description:"the default scheme for this API" default:"http"` 83 84 PrincipalIface bool `long:"principal-is-interface" description:"the security principal provided is an interface, not a struct"` 85 } 86 87 func (so schemeOptions) apply(opts *generator.GenOpts) { 88 opts.Principal = so.Principal 89 opts.PrincipalCustomIface = so.PrincipalIface 90 opts.DefaultScheme = so.DefaultScheme 91 } 92 93 type mediaOptions struct { 94 DefaultProduces string `long:"default-produces" description:"the default mime type that API operations produce" default:"application/json"` 95 DefaultConsumes string `long:"default-consumes" description:"the default mime type that API operations consume" default:"application/json"` 96 } 97 98 func (m mediaOptions) apply(opts *generator.GenOpts) { 99 opts.DefaultProduces = m.DefaultProduces 100 opts.DefaultConsumes = m.DefaultConsumes 101 102 const xmlIdentifier = "xml" 103 opts.WithXML = strings.Contains(opts.DefaultProduces, xmlIdentifier) || strings.Contains(opts.DefaultConsumes, xmlIdentifier) 104 } 105 106 // WithShared adds the shared options group 107 type WithShared struct { 108 Shared sharedOptions `group:"Options common to all code generation commands"` 109 } 110 111 func (w WithShared) getConfigFile() string { 112 return string(w.Shared.ConfigFile) 113 } 114 115 type sharedOptions struct { 116 Spec flags.Filename `long:"spec" short:"f" description:"the spec file to use (default swagger.{json,yml,yaml})" group:"shared"` 117 Target flags.Filename `long:"target" short:"t" default:"./" description:"the base directory for generating the files" group:"shared"` 118 Template string `long:"template" description:"load contributed templates" choice:"stratoscale" group:"shared"` 119 TemplateDir flags.Filename `long:"template-dir" short:"T" description:"alternative template override directory" group:"shared"` 120 ConfigFile flags.Filename `long:"config-file" short:"C" description:"configuration file to use for overriding template options" group:"shared"` 121 CopyrightFile flags.Filename `long:"copyright-file" short:"r" description:"copyright file used to add copyright header" group:"shared"` 122 AdditionalInitialisms []string `long:"additional-initialism" description:"consecutive capitals that should be considered intialisms" group:"shared"` 123 AllowTemplateOverride bool `long:"allow-template-override" description:"allows overriding protected templates" group:"shared"` 124 SkipValidation bool `long:"skip-validation" description:"skips validation of spec prior to generation" group:"shared"` 125 DumpData bool `long:"dump-data" description:"when present dumps the json for the template generator instead of generating files" group:"shared"` 126 StrictResponders bool `long:"strict-responders" description:"Use strict type for the handler return value"` 127 FlattenCmdOptions 128 } 129 130 func (s sharedOptions) apply(opts *generator.GenOpts) { 131 opts.Spec = string(s.Spec) 132 opts.Target = string(s.Target) 133 opts.Template = s.Template 134 opts.TemplateDir = string(s.TemplateDir) 135 opts.AllowTemplateOverride = s.AllowTemplateOverride 136 opts.ValidateSpec = !s.SkipValidation 137 opts.DumpData = s.DumpData 138 opts.FlattenOpts = s.FlattenCmdOptions.SetFlattenOptions(opts.FlattenOpts) 139 opts.Copyright = string(s.CopyrightFile) 140 opts.StrictResponders = s.StrictResponders 141 142 swag.AddInitialisms(s.AdditionalInitialisms...) 143 } 144 145 func setCopyright(copyrightFile string) (string, error) { 146 // read the Copyright from file path in opts 147 if copyrightFile == "" { 148 return "", nil 149 } 150 bytebuffer, err := ioutil.ReadFile(copyrightFile) 151 if err != nil { 152 return "", err 153 } 154 return string(bytebuffer), nil 155 } 156 157 func createSwagger(s sharedCommand) error { 158 cfg, err := readConfig(s.getConfigFile()) 159 if err != nil { 160 return err 161 } 162 setDebug(cfg) // viper config Debug 163 164 opts := new(generator.GenOpts) 165 s.apply(opts) 166 167 opts.Copyright, err = setCopyright(opts.Copyright) 168 if err != nil { 169 return fmt.Errorf("could not load copyright file: %v", err) 170 } 171 172 if opts.Template != "" { 173 contribOptionsOverride(opts) 174 } 175 176 if err = opts.EnsureDefaults(); err != nil { 177 return err 178 } 179 180 if err = configureOptsFromConfig(cfg, opts); err != nil { 181 return err 182 } 183 184 if err = s.generate(opts); err != nil { 185 return err 186 } 187 188 basepath, err := filepath.Abs(".") 189 if err != nil { 190 return err 191 } 192 193 targetAbs, err := filepath.Abs(opts.Target) 194 if err != nil { 195 return err 196 } 197 rp, err := filepath.Rel(basepath, targetAbs) 198 if err != nil { 199 return err 200 } 201 202 s.log(rp) 203 204 return nil 205 } 206 207 func readConfig(filename string) (*viper.Viper, error) { 208 if filename == "" { 209 return nil, nil 210 } 211 212 abspath, err := filepath.Abs(filename) 213 if err != nil { 214 return nil, err 215 } 216 log.Println("trying to read config from", abspath) 217 return generator.ReadConfig(abspath) 218 } 219 220 func configureOptsFromConfig(cfg *viper.Viper, opts *generator.GenOpts) error { 221 if cfg == nil { 222 return nil 223 } 224 225 var def generator.LanguageDefinition 226 if err := cfg.Unmarshal(&def); err != nil { 227 return err 228 } 229 return def.ConfigureOpts(opts) 230 } 231 232 func setDebug(cfg *viper.Viper) { 233 // viper config debug 234 if os.Getenv("DEBUG") != "" || os.Getenv("SWAGGER_DEBUG") != "" { 235 if cfg != nil { 236 cfg.Debug() 237 } else { 238 log.Println("No config read") 239 } 240 } 241 }