Skip to content

Commit

Permalink
Add default flag support
Browse files Browse the repository at this point in the history
  • Loading branch information
hisunwei committed Sep 25, 2019
1 parent c49ea4c commit aaaa868
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 50 deletions.
4 changes: 3 additions & 1 deletion cmd/swagger/commands/generate/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type Server struct {
ExcludeSpec bool `long:"exclude-spec" description:"don't embed the swagger specification"`
WithContext bool `long:"with-context" description:"handlers get a context as first arg (deprecated)"`
DumpData bool `long:"dump-data" description:"when present dumps the json for the template generator instead of generating files"`
FlagStrategy string `long:"flag-strategy" description:"the strategy to provide flags for the server" default:"go-flags" choice:"go-flags" choice:"pflag"`
FlagStrategy string `long:"flag-strategy" description:"the strategy to provide flags for the server" default:"go-flags" choice:"go-flags" choice:"pflag" choice:"flag"`
CompatibilityMode string `long:"compatibility-mode" description:"the compatibility mode for the tls server" default:"modern" choice:"modern" choice:"intermediate"`
SkipValidation bool `long:"skip-validation" description:"skips validation of spec prior to generation"`
RegenerateConfigureAPI bool `long:"regenerate-configureapi" description:"Force regeneration of configureapi.go"`
Expand Down Expand Up @@ -98,6 +98,8 @@ func (s *Server) log(rp string) {
var flagsPackage string
if strings.HasPrefix(s.FlagStrategy, "pflag") {
flagsPackage = "github.com/spf13/pflag"
} else if strings.HasPrefix(s.FlagStrategy, "flag") {
flagsPackage = "flag"
} else {
flagsPackage = "github.com/jessevdk/go-flags"
}
Expand Down
3 changes: 2 additions & 1 deletion docs/faq/faq_server.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Basically, here are the required packages:
And depending on your generation options, a command line flags handling package:
- [`github.com/jessevdk/go-flags`](https://www.github.com/jessevdk/go-flags), or
- [`github.com/spf13/pflags`](https://www.github.com/spf13/pflags)
- [`flag`](flag)

This dependency used to be necessary up to release 0.14:
- [`github.com/tylerb/graceful`](https://www.github.com/tylerb/graceful)
Expand All @@ -25,7 +26,7 @@ These packages may of course be *vendored* with your own source.
Originally from issue [#1085](https://github.com/go-swagger/go-swagger/issues/1085).

### How to add custom flags?
`go-swagger` ships with an option to select a flag management package: `swagger generate server --flag-strategy=[go-flags|pflag]`
`go-swagger` ships with an option to select a flag management package: `swagger generate server --flag-strategy=[go-flags|pflag|flag]`

You may of course customize your server to accept arbitrary flags the way you prefer.
This should be normally done with the generated main.go. For customization, you may either skip the generation of the main package (`--skip-main`)
Expand Down
2 changes: 1 addition & 1 deletion docs/generate/server.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Help Options:
--exclude-spec don't embed the swagger specification
--with-context handlers get a context as first arg (deprecated)
--dump-data when present dumps the json for the template generator instead of generating files
--flag-strategy=[go-flags|pflag] the strategy to provide flags for the server (default: go-flags)
--flag-strategy=[go-flags|pflag|flag] the strategy to provide flags for the server (default: go-flags)
--compatibility-mode=[modern|intermediate] the compatibility mode for the tls server (default: modern)
--skip-validation skips validation of spec prior to generation
--regenerate-configureapi Force regeneration of configureapi.go
Expand Down
76 changes: 38 additions & 38 deletions generator/bindata.go

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions generator/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,11 @@ func (g *GenApp) UsePFlags() bool {
return g.GenOpts != nil && strings.HasPrefix(g.GenOpts.FlagStrategy, "pflag")
}

// UseFlags returns true when the flag strategy is set to flag
func (g *GenApp) UseFlags() bool {
return g.GenOpts != nil && strings.HasPrefix(g.GenOpts.FlagStrategy, "flag")
}

// UseIntermediateMode for https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29
func (g *GenApp) UseIntermediateMode() bool {
return g.GenOpts != nil && g.GenOpts.CompatibilityMode == "intermediate"
Expand Down
49 changes: 48 additions & 1 deletion generator/templates/server/main.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import (
{{ end -}}
{{ if .UsePFlags }}flag "github.com/spf13/pflag"
{{ end -}}
{{ if .UseFlags }}"flag"
{{ end -}}


{{range .DefaultImports}}{{printf "%q" .}}
Expand Down Expand Up @@ -75,7 +77,8 @@ func main() {
if err := server.Serve(); err != nil {
log.Fatalln(err)
}
{{ else }}{{ if .ExcludeSpec }}
{{ end }}
{{ if .UseGoStructFlags}}{{ if .ExcludeSpec }}
server := {{ .APIPackage }}.NewServer(nil){{ else }}
swaggerSpec, err := loads.Embedded({{ .APIPackage }}.SwaggerJSON, {{ .APIPackage }}.FlatSwaggerJSON)
if err != nil {
Expand Down Expand Up @@ -125,4 +128,48 @@ func main() {
log.Fatalln(err)
}
{{ end }}
{{ if .UseFlags}}{{ if not .ExcludeSpec }}
swaggerSpec, err := loads.Embedded({{ .APIPackage }}.SwaggerJSON, {{ .APIPackage }}.FlatSwaggerJSON)
if err != nil {
log.Fatalln(err)
}
{{ end }}
var server *{{ .APIPackage }}.Server // make sure init is called

flag.Usage = func() {
fmt.Fprint(os.Stderr, "Usage:\n")
fmt.Fprint(os.Stderr, " {{ dasherize .Name }}-server [OPTIONS]\n\n")

title := {{ if .Info }}{{ if .Info.Title }}{{ printf "%q" .Info.Title }}{{ else }}{{ if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Title{{ end }}{{ end }}{{ else }}{{ if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Title{{ end }}{{ end}}
fmt.Fprint(os.Stderr, title+"\n\n")
desc := {{ if .Info }}{{ if .Info.Description }}{{ printf "%q" .Info.Description }}{{ else }}{{ if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Description{{ end }}{{ end }}{{ else }}{{ if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Description{{ end }}{{ end}}
if desc != "" {
fmt.Fprintf(os.Stderr, desc+"\n\n")
}
flag.CommandLine.SetOutput(os.Stderr)
flag.PrintDefaults()
}
// parse the CLI flags
flag.Parse()

{{ if .ExcludeSpec }}
server = {{ .APIPackage }}.NewServer(nil)
swaggerSpec, err := loads.Spec(string(server.Spec))
if err != nil {
log.Fatalln(err)
}
api := {{.Package}}.New{{ pascalize .Name }}API(swaggerSpec)
server.SetAPI(api)
{{ else }}
api :={{.Package}}.New{{ pascalize .Name }}API(swaggerSpec)
// get server with flag values filled out
server = {{ .APIPackage }}.NewServer(api)
{{ end }}
defer server.Shutdown()

server.ConfigureAPI()
if err := server.Serve(); err != nil {
log.Fatalln(err)
}
{{ end }}
}
43 changes: 35 additions & 8 deletions generator/templates/server/server.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ import (
"github.com/go-openapi/runtime/flagext"
{{ if .UsePFlags }}flag "github.com/spf13/pflag"
{{ end -}}
{{ if .UseFlags }}"flag"
"strings"
{{ end -}}
"golang.org/x/net/netutil"

{{ range .DefaultImports }}{{ printf "%q" . }}
Expand All @@ -52,7 +55,7 @@ func init() {
}
}

{{ if .UsePFlags }}
{{ if not .UseGoStructFlags}}
var ({{ if .ExcludeSpec }}
specFile string
{{ end }}enabledListeners []string
Expand Down Expand Up @@ -80,12 +83,36 @@ var ({{ if .ExcludeSpec }}
tlsCACertificate string
)

{{ if .UseFlags}}
// StringSliceVar support for flag
type sliceValue []string

func newSliceValue(vals []string, p *[]string) *sliceValue {
*p = vals
return (*sliceValue)(p)
}

func (s *sliceValue) Set(val string) error {
*s = sliceValue(strings.Split(val, ","))
return nil
}

func (s *sliceValue) Get() interface{} { return []string(*s) }

func (s *sliceValue) String() string { return strings.Join([]string(*s), ",") }
// end StringSliceVar support for flag
{{ end }}

func init() {
maxHeaderSize = flagext.ByteSize(1000000){{ if .ExcludeSpec }}
flag.StringVarP(&specFile, "spec", "", "", "the swagger specification to serve")
{{ end }}

{{ if .UseFlags }}
flag.Var(newSliceValue(defaultSchemes, &enabledListeners), "schema", "the listeners to enable, this can be repeated and defaults to the schemes in the swagger spec")
{{ end }}
{{ if .UsePFlags }}
flag.StringSliceVar(&enabledListeners, "scheme", defaultSchemes, "the listeners to enable, this can be repeated and defaults to the schemes in the swagger spec")
{{ end }}
flag.DurationVar(&cleanupTimeout, "cleanup-timeout", 10*time.Second, "grace period for which to wait before killing idle connections")
flag.DurationVar(&gracefulTimeout, "graceful-timeout", 15*time.Second, "grace period for which to wait before shutting down the server")
flag.Var(&maxHeaderSize, "max-header-size", "controls the maximum number of bytes the server will read parsing the request header's keys and values, including the request line. It does not limit the size of the request body")
Expand Down Expand Up @@ -143,7 +170,7 @@ func intEnvOverride(orig int, def int, keys ...string) int {
// NewServer creates a new api {{ humanize .Name }} server but does not configure it
func NewServer(api *{{ .Package }}.{{ pascalize .Name }}API) *Server {
s := new(Server)
{{ if .UsePFlags }}
{{ if not .UseGoStructFlags }}
s.EnabledListeners = enabledListeners
s.CleanupTimeout = cleanupTimeout
s.GracefulTimeout = gracefulTimeout
Expand Down Expand Up @@ -195,7 +222,7 @@ type Server struct {
GracefulTimeout time.Duration{{ if .UseGoStructFlags }} `long:"graceful-timeout" description:"grace period for which to wait before shutting down the server" default:"15s"`{{ end }}
MaxHeaderSize flagext.ByteSize{{ if .UseGoStructFlags }} `long:"max-header-size" description:"controls the maximum number of bytes the server will read parsing the request header's keys and values, including the request line. It does not limit the size of the request body." default:"1MiB"`{{ end }}

SocketPath {{ if .UsePFlags }}string{{ else }}flags.Filename `long:"socket-path" description:"the unix socket to listen on" default:"/var/run/{{ dasherize .Name }}.sock"`{{ end }}
SocketPath {{ if not .UseGoStructFlags }}string{{ else }}flags.Filename `long:"socket-path" description:"the unix socket to listen on" default:"/var/run/{{ dasherize .Name }}.sock"`{{ end }}
domainSocketL net.Listener

Host string{{ if .UseGoStructFlags }} `long:"host" description:"the IP to listen on" default:"localhost" env:"HOST"`{{ end }}
Expand All @@ -208,16 +235,16 @@ type Server struct {

TLSHost string{{ if .UseGoStructFlags }} `long:"tls-host" description:"the IP to listen on for tls, when not specified it's the same as --host" env:"TLS_HOST"`{{ end }}
TLSPort int{{ if .UseGoStructFlags }} `long:"tls-port" description:"the port to listen on for secure connections, defaults to a random value" env:"TLS_PORT"`{{ end }}
TLSCertificate {{ if .UsePFlags }}string{{ else }}flags.Filename `long:"tls-certificate" description:"the certificate to use for secure connections" env:"TLS_CERTIFICATE"`{{ end }}
TLSCertificateKey {{ if .UsePFlags }}string{{ else }}flags.Filename `long:"tls-key" description:"the private key to use for secure connections" env:"TLS_PRIVATE_KEY"`{{ end }}
TLSCACertificate {{ if .UsePFlags }}string{{ else }}flags.Filename `long:"tls-ca" description:"the certificate authority file to be used with mutual tls auth" env:"TLS_CA_CERTIFICATE"`{{ end }}
TLSCertificate {{ if not .UseGoStructFlags }}string{{ else }}flags.Filename `long:"tls-certificate" description:"the certificate to use for secure connections" env:"TLS_CERTIFICATE"`{{ end }}
TLSCertificateKey {{ if not .UseGoStructFlags }}string{{ else }}flags.Filename `long:"tls-key" description:"the private key to use for secure connections" env:"TLS_PRIVATE_KEY"`{{ end }}
TLSCACertificate {{ if not .UseGoStructFlags }}string{{ else }}flags.Filename `long:"tls-ca" description:"the certificate authority file to be used with mutual tls auth" env:"TLS_CA_CERTIFICATE"`{{ end }}
TLSListenLimit int{{ if .UseGoStructFlags }} `long:"tls-listen-limit" description:"limit the number of outstanding requests"`{{ end }}
TLSKeepAlive time.Duration{{ if .UseGoStructFlags }} `long:"tls-keep-alive" description:"sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download)"`{{ end }}
TLSReadTimeout time.Duration{{ if .UseGoStructFlags }} `long:"tls-read-timeout" description:"maximum duration before timing out read of the request"`{{ end }}
TLSWriteTimeout time.Duration{{ if .UseGoStructFlags }} `long:"tls-write-timeout" description:"maximum duration before timing out write of the response"`{{ end }}
httpsServerL net.Listener

{{ if .ExcludeSpec }}Spec {{ if .UsePFlags }}string{{ else }}flags.Filename `long:"spec" description:"the swagger specification to serve"`{{ end }}{{ end }}
{{ if .ExcludeSpec }}Spec {{ if not .UseGoStructFlags }}string{{ else }}flags.Filename `long:"spec" description:"the swagger specification to serve"`{{ end }}{{ end }}
api *{{ .Package }}.{{ pascalize .Name }}API
handler http.Handler
hasListeners bool
Expand Down

0 comments on commit aaaa868

Please sign in to comment.