package main import ( "encoding/json" "github.com/urfave/cli" "log" "os" "text/template" ) type CliFlagInfo struct { PackageName string Flags []FlagType } type FlagType struct { Name string `json:"name"` Type string `json:"type"` Value bool `json:"value"` Destination bool `json:"dest"` Doctail string `json:"doctail"` ContextDefault string `json:"context_default"` ContextType string `json:"context_type"` Parser string `json:"parser"` ParserCast string `json:"parser_cast"` } var flagTemplate = `// Code generated by fg; DO NOT EDIT. package {{ .PackageName }} {{ if eq .PackageName "cli" }} import ( "flag" "strconv" "time" ) {{ range $i, $flag := .Flags }} // {{ $flag.Name }}Flag is a flag with type {{ $flag.Type }}{{ $flag.Doctail }} type {{ $flag.Name }}Flag struct { Name string Usage string EnvVar string FilePath string Required bool Hidden bool {{- if eq $flag.Value true }} Value {{ $flag.Type }} {{- end }} {{- if eq $flag.Destination true }} Destination *{{ $flag.Type }} {{- end }} } // String returns a readable representation of this value // (for usage defaults) func (f {{ $flag.Name }}Flag) String() string { return FlagStringer(f) } // GetName returns the name of the flag func (f {{ $flag.Name }}Flag) GetName() string { return f.Name } // IsRequired returns whether or not the flag is required func (f {{ $flag.Name }}Flag) IsRequired() bool { return f.Required } // {{ $flag.Name }} looks up the value of a local {{ $flag.Name }}Flag, returns // {{ $flag.ContextDefault }} if not found func (c *Context) {{ $flag.Name }}(name string) {{ if ne .ContextType "" }} {{ $flag.ContextType }} {{ else }} {{ $flag.Type }} {{- end }} { return lookup{{ $flag.Name }}(name, c.flagSet) } // Global{{ $flag.Name }} looks up the value of a global {{ $flag.Name }}Flag, returns // {{ $flag.ContextDefault }} if not found func (c *Context) Global{{ $flag.Name }}(name string) {{ if ne .ContextType "" }} {{ $flag.ContextType }} {{ else }} {{ $flag.Type }} {{- end }} { if fs := lookupGlobalFlagSet(name, c); fs != nil { return lookup{{ $flag.Name }}(name, fs) } return {{ $flag.ContextDefault }} } func lookup{{ $flag.Name }}(name string, set *flag.FlagSet) {{ if ne .ContextType "" }} {{ $flag.ContextType }} {{ else }} {{ $flag.Type }} {{- end }} { f := set.Lookup(name) if f != nil { {{ if ne .Parser "" }}parsed, err := {{ $flag.Parser }}{{ else }}parsed, err := f.Value, error(nil){{ end }} if err != nil { return {{ $flag.ContextDefault }} } {{ if ne .ParserCast "" }}return {{ $flag.ParserCast }}{{ else }}return parsed{{ end }} } return {{ $flag.ContextDefault }} } {{- end }} {{ else }} import ( "flag" "github.com/urfave/cli" ) {{ range $i, $flag := .Flags }} // {{ $flag.Name }}Flag is the flag type that wraps cli.{{ $flag.Name }}Flag to allow // for other values to be specified type {{ $flag.Name }}Flag struct { cli.{{ $flag.Name }}Flag set *flag.FlagSet } // New{{ $flag.Name }}Flag creates a new {{ $flag.Name }}Flag func New{{ $flag.Name }}Flag(fl cli.{{ $flag.Name }}Flag) *{{ $flag.Name }}Flag { return &{{ $flag.Name }}Flag{ {{ $flag.Name }}Flag: fl, set: nil } } // Apply saves the flagSet for later usage calls, then calls // the wrapped {{ $flag.Name }}Flag.Apply func (f *{{ $flag.Name }}Flag) Apply(set *flag.FlagSet) { f.set = set f.{{ $flag.Name }}Flag.Apply(set) } // ApplyWithError saves the flagSet for later usage calls, then calls // the wrapped {{ $flag.Name }}Flag.ApplyWithError func (f *{{ $flag.Name }}Flag) ApplyWithError(set *flag.FlagSet) error { f.set = set return f.{{ $flag.Name }}Flag.ApplyWithError(set) } {{- end }} {{- end }} ` func main() { var packageName, inputPath, outputPath string app := cli.NewApp() app.Name = "fg" app.Usage = "Generate flag type code!" app.Version = "v0.1.0" app.Flags = []cli.Flag{ cli.StringFlag{ Name: "package, p", Value: "cli", Usage: "`PACKAGE` for which the flag types will be generated", Destination: &packageName, }, cli.StringFlag{ Name: "input, i", Usage: "path to the `INPUT JSON FILE` which defines each type to be generated", Destination: &inputPath, }, cli.StringFlag{ Name: "output, o", Usage: "path to the `OUTPUT GO FILE` which will contain the flag types", Destination: &outputPath, }, } app.Action = func(c *cli.Context) error { var info CliFlagInfo var tpl *template.Template info.PackageName = packageName inFile, err := os.Open(inputPath) if err != nil { log.Fatal(err) } defer inFile.Close() decoder := json.NewDecoder(inFile) err = decoder.Decode(&info.Flags) if err != nil { log.Fatal(err) } tpl = template.Must(template.New("").Parse(flagTemplate)) outFile, err := os.Create(outputPath) if err != nil { log.Fatal(err) } defer outFile.Close() err = tpl.Execute(outFile, info) if err != nil { log.Fatal(err) } return nil } err := app.Run(os.Args) if err != nil { log.Fatal(err) } }