func (g *Generator) generateClientResources(clientPkg string, funcs template.FuncMap, api *design.APIDefinition) error { clientsTmpl := template.Must(template.New("clients").Funcs(funcs).Parse(clientsTmpl)) imports := []*codegen.ImportSpec{ codegen.SimpleImport("bytes"), codegen.SimpleImport("encoding/json"), codegen.SimpleImport("fmt"), codegen.SimpleImport("net/http"), } return api.IterateResources(func(res *design.ResourceDefinition) error { filename := filepath.Join(codegen.OutputDir, snakeCase(res.Name)+".go") resGen := codegen.NewGoGenerator(filename) if err := resGen.WriteHeader("", "client", imports); err != nil { return err } g.genfiles = append(g.genfiles, filename) if err := res.IterateActions(func(action *design.ActionDefinition) error { return clientsTmpl.Execute(resGen, action) }); err != nil { return err } return resGen.FormatCode() }) }
// APISchema produces the API JSON hyper schema. func APISchema(api *design.APIDefinition) *JSONSchema { api.IterateResources(func(r *design.ResourceDefinition) error { GenerateResourceDefinition(api, r) return nil }) links := []*JSONLink{ &JSONLink{ Href: ServiceURL, Rel: "self", }, &JSONLink{ Href: "/schema", Method: "GET", Rel: "self", TargetSchema: &JSONSchema{ Schema: SchemaRef, AdditionalProperties: true, }, }, } s := JSONSchema{ ID: fmt.Sprintf("%s/schema", ServiceURL), Title: api.Title, Description: api.Description, Type: JSONObject, Definitions: Definitions, Properties: propertiesFromDefs(Definitions, "#/definitions/"), Links: links, } return &s }
func (g *Generator) generateJS(jsFile string, api *design.APIDefinition) (_ *design.ActionDefinition, err error) { file, err := codegen.SourceFileFor(jsFile) if err != nil { return } g.genfiles = append(g.genfiles, jsFile) if Scheme == "" && len(api.Schemes) > 0 { Scheme = api.Schemes[0] } data := map[string]interface{}{ "API": api, "Host": Host, "Scheme": Scheme, "Timeout": int64(Timeout / time.Millisecond), } if err = file.ExecuteTemplate("module", moduleT, nil, data); err != nil { return } actions := make(map[string][]*design.ActionDefinition) api.IterateResources(func(res *design.ResourceDefinition) error { return res.IterateActions(func(action *design.ActionDefinition) error { if as, ok := actions[action.Name]; ok { actions[action.Name] = append(as, action) } else { actions[action.Name] = []*design.ActionDefinition{action} } return nil }) }) var exampleAction *design.ActionDefinition keys := []string{} for n := range actions { keys = append(keys, n) } sort.Strings(keys) for _, n := range keys { for _, a := range actions[n] { if exampleAction == nil && a.Routes[0].Verb == "GET" { exampleAction = a } data := map[string]interface{}{ "Action": a, "Version": design.Design.APIVersionDefinition, } funcs := template.FuncMap{"params": params} if err = file.ExecuteTemplate("jsFuncs", jsFuncsT, funcs, data); err != nil { return } } } _, err = file.Write([]byte(moduleTend)) return exampleAction, err }
func (g *Generator) generateJS(jsFile string, funcs template.FuncMap, api *design.APIDefinition) (_ *design.ActionDefinition, err error) { file, err := os.Create(jsFile) if err != nil { return } defer file.Close() g.genfiles = append(g.genfiles, jsFile) moduleTmpl := template.Must(template.New("module").Funcs(funcs).Parse(moduleT)) jsFuncsTmpl := template.Must(template.New("jsFuncs").Funcs(funcs).Parse(jsFuncsT)) if Scheme == "" && len(api.Schemes) > 0 { Scheme = api.Schemes[0] } data := map[string]interface{}{ "API": api, "Host": Host, "Scheme": Scheme, "Timeout": int64(Timeout / time.Millisecond), } if err = moduleTmpl.Execute(file, data); err != nil { return } actions := make(map[string][]*design.ActionDefinition) api.IterateResources(func(res *design.ResourceDefinition) error { return res.IterateActions(func(action *design.ActionDefinition) error { if as, ok := actions[action.Name]; ok { actions[action.Name] = append(as, action) } else { actions[action.Name] = []*design.ActionDefinition{action} } return nil }) }) var exampleAction *design.ActionDefinition keys := []string{} for n := range actions { keys = append(keys, n) } sort.Strings(keys) for _, n := range keys { for _, a := range actions[n] { if exampleAction == nil && a.Routes[0].Verb == "GET" { exampleAction = a } if err = jsFuncsTmpl.Execute(file, a); err != nil { return } } } _, err = file.Write([]byte(moduleTend)) return exampleAction, err }
func (g *Generator) generateIndexHTML( htmlFile string, api *design.APIDefinition, exampleAction *design.ActionDefinition, funcs template.FuncMap, ) error { file, err := os.Create(htmlFile) if err != nil { return err } defer file.Close() g.genfiles = append(g.genfiles, htmlFile) htmlTmpl := template.Must(template.New("exampleHTML").Funcs(funcs).Parse(exampleT)) argNames := params(exampleAction) var args string if len(argNames) > 0 { query := exampleAction.QueryParams.Type.ToObject() argValues := make([]string, len(argNames)) for i, n := range argNames { q := query[n].Type.ToArray().ElemType // below works because we deal with simple types in query strings argValues[i] = fmt.Sprintf("%v", api.Example(q.Type)) } args = strings.Join(argValues, ", ") } examplePath := exampleAction.Routes[0].FullPath() pathParams := exampleAction.Routes[0].Params() if len(pathParams) > 0 { pathVars := exampleAction.AllParams().Type.ToObject() pathValues := make([]interface{}, len(pathParams)) for i, n := range pathParams { pathValues[i] = api.Example(pathVars[n].Type) } format := design.WildcardRegex.ReplaceAllLiteralString(examplePath, "/%v") examplePath = fmt.Sprintf(format, pathValues...) } if len(argNames) > 0 { args = ", " + args } exampleFunc := fmt.Sprintf( `%s%s ("%s"%s)`, exampleAction.Name, strings.Title(exampleAction.Parent.Name), examplePath, args, ) data := map[string]interface{}{ "API": api, "ExampleFunc": exampleFunc, } return htmlTmpl.Execute(file, data) }
// Generate the application code, implement codegen.Generator. func (g *Generator) Generate(api *design.APIDefinition) (_ []string, err error) { if api == nil { return nil, fmt.Errorf("missing API definition, make sure design.Design is properly initialized") } go utils.Catch(nil, func() { g.Cleanup() }) defer func() { if err != nil { g.Cleanup() } }() outdir := AppOutputDir() err = api.IterateVersions(func(v *design.APIVersionDefinition) error { verdir := outdir if v.Version != "" { verdir = filepath.Join(verdir, codegen.VersionPackage(v.Version)) } if err := os.MkdirAll(verdir, 0755); err != nil { return err } if err := g.generateContexts(verdir, api, v); err != nil { return err } if err := g.generateControllers(verdir, v); err != nil { return err } if err := g.generateHrefs(verdir, v); err != nil { return err } if err := g.generateMediaTypes(verdir, v); err != nil { return err } if err := g.generateUserTypes(verdir, v); err != nil { return err } return nil }) if err != nil { return nil, err } return g.genfiles, nil }
func (g *Generator) generateMain(mainFile string, clientPkg string, funcs template.FuncMap, api *design.APIDefinition) error { gg := codegen.NewGoGenerator(mainFile) mainTmpl := template.Must(template.New("main").Funcs(funcs).Parse(mainTmpl)) registerCmdsTmpl := template.Must(template.New("registerCmds").Funcs(funcs).Parse(registerCmdsT)) imports := []*codegen.ImportSpec{ codegen.SimpleImport("os"), codegen.SimpleImport(clientPkg), codegen.SimpleImport("gopkg.in/alecthomas/kingpin.v2"), } for _, pkg := range SignerPackages { imports = append(imports, codegen.SimpleImport(pkg)) } if err := gg.WriteHeader("", "main", imports); err != nil { return err } g.genfiles = append(g.genfiles, mainFile) data := map[string]interface{}{ "API": api, "Signers": Signers, "Version": Version, } if err := mainTmpl.Execute(gg, data); err != nil { return err } actions := make(map[string][]*design.ActionDefinition) api.IterateResources(func(res *design.ResourceDefinition) error { return res.IterateActions(func(action *design.ActionDefinition) error { if as, ok := actions[action.Name]; ok { actions[action.Name] = append(as, action) } else { actions[action.Name] = []*design.ActionDefinition{action} } return nil }) }) if err := registerCmdsTmpl.Execute(gg, actions); err != nil { return err } return gg.FormatCode() }
func (g *Generator) generateCommands(commandsFile string, clientPkg string, funcs template.FuncMap, api *design.APIDefinition) error { gg := codegen.NewGoGenerator(commandsFile) commandTypesTmpl := template.Must(template.New("commandTypes").Funcs(funcs).Parse(commandTypesTmpl)) commandsTmpl := template.Must(template.New("commands").Funcs(funcs).Parse(commandsTmpl)) imports := []*codegen.ImportSpec{ codegen.SimpleImport("github.com/raphael/goa"), codegen.SimpleImport(clientPkg), codegen.NewImport("log", "gopkg.in/inconshreveable/log15.v2"), codegen.SimpleImport("gopkg.in/alecthomas/kingpin.v2"), } if err := gg.WriteHeader("", "main", imports); err != nil { return err } g.genfiles = append(g.genfiles, commandsFile) gg.Write([]byte("type (\n")) if err := api.IterateResources(func(res *design.ResourceDefinition) error { return res.IterateActions(func(action *design.ActionDefinition) error { return commandTypesTmpl.Execute(gg, action) }) }); err != nil { return err } gg.Write([]byte(")\n\n")) if err := api.IterateResources(func(res *design.ResourceDefinition) error { return res.IterateActions(func(action *design.ActionDefinition) error { data := map[string]interface{}{ "Action": action, "Resource": action.Parent, "Version": design.Design.APIVersionDefinition, } return commandsTmpl.Execute(gg, data) }) }); err != nil { return err } return gg.FormatCode() }
// Generate produces the skeleton main. func (g *Generator) Generate(api *design.APIDefinition) ([]string, error) { mainFile := filepath.Join(codegen.OutputDir, "main.go") if Force { os.Remove(mainFile) } _, err := os.Stat(mainFile) funcs := template.FuncMap{ "tempvar": tempvar, "generateJSONSchema": generateJSONSchema, "goify": codegen.Goify, "okResp": okResp, } if err != nil { tmpl, err := template.New("main").Funcs(funcs).Parse(mainTmpl) if err != nil { panic(err.Error()) // bug } gg := codegen.NewGoGenerator(mainFile) g.genfiles = []string{mainFile} outPkg, err := filepath.Rel(os.Getenv("GOPATH"), codegen.OutputDir) if err != nil { return nil, err } outPkg = strings.TrimPrefix(outPkg, "src/") appPkg := filepath.Join(outPkg, "app") swaggerPkg := filepath.Join(outPkg, "swagger") imports := []*codegen.ImportSpec{ codegen.SimpleImport("github.com/raphael/goa"), codegen.SimpleImport(appPkg), codegen.SimpleImport(swaggerPkg), codegen.NewImport("log", "gopkg.in/inconshreveable/log15.v2"), } if generateJSONSchema() { jsonSchemaPkg := filepath.Join(outPkg, "schema") imports = append(imports, codegen.SimpleImport(jsonSchemaPkg)) } gg.WriteHeader("", "main", imports) data := map[string]interface{}{ "Name": AppName, "Resources": api.Resources, } err = tmpl.Execute(gg, data) if err != nil { g.Cleanup() return nil, err } if err := gg.FormatCode(); err != nil { g.Cleanup() return nil, err } } tmpl, err := template.New("ctrl").Funcs(funcs).Parse(ctrlTmpl) if err != nil { panic(err.Error()) // bug } imp, err := filepath.Rel(filepath.Join(os.Getenv("GOPATH"), "src"), codegen.OutputDir) if err != nil { return nil, err } imp = filepath.Join(imp, "app") imports := []*codegen.ImportSpec{codegen.SimpleImport(imp)} err = api.IterateResources(func(r *design.ResourceDefinition) error { filename := filepath.Join(codegen.OutputDir, snakeCase(r.Name)+".go") if Force { if err := os.Remove(filename); err != nil { return err } } if _, err := os.Stat(filename); err != nil { resGen := codegen.NewGoGenerator(filename) g.genfiles = append(g.genfiles, filename) resGen.WriteHeader("", "main", imports) err := tmpl.Execute(resGen, r) if err != nil { g.Cleanup() return err } if err := resGen.FormatCode(); err != nil { g.Cleanup() return err } } return nil }) if err != nil { g.Cleanup() return nil, err } return g.genfiles, nil }
// New creates a Swagger spec from an API definition. func New(api *design.APIDefinition) (*Swagger, error) { if api == nil { return nil, nil } tags, err := tagsFromDefinition(api.Metadata) if err != nil { return nil, err } params, err := paramsFromDefinition(api.BaseParams, api.BasePath) if err != nil { return nil, err } var paramMap map[string]*Parameter if len(params) > 0 { paramMap = make(map[string]*Parameter, len(params)) for _, p := range params { paramMap[p.Name] = p } } s := &Swagger{ Swagger: "2.0", Info: &Info{ Title: api.Title, Description: api.Description, TermsOfService: api.TermsOfService, Contact: api.Contact, License: api.License, Version: "", }, Host: api.Host, BasePath: api.BasePath, Paths: make(map[string]*Path), Schemes: api.Schemes, Consumes: []string{"application/json"}, Produces: []string{"application/json"}, Parameters: paramMap, Tags: tags, ExternalDocs: docsFromDefinition(api.Docs), } err = api.IterateResponses(func(r *design.ResponseDefinition) error { res, err := responseSpecFromDefinition(s, api, r) if err != nil { return err } if s.Responses == nil { s.Responses = make(map[string]*Response) } s.Responses[r.Name] = res return nil }) if err != nil { return nil, err } err = api.IterateResources(func(res *design.ResourceDefinition) error { return res.IterateActions(func(a *design.ActionDefinition) error { for _, route := range a.Routes { if err := buildPathFromDefinition(s, api, route); err != nil { return err } } return nil }) }) if err != nil { return nil, err } if len(genschema.Definitions) > 0 { s.Definitions = make(map[string]*genschema.JSONSchema) for n, d := range genschema.Definitions { // sad but swagger doesn't support these d.Media = nil d.Links = nil s.Definitions[n] = d } } return s, nil }
// Generate produces the skeleton main. func (g *Generator) Generate(api *design.APIDefinition) (_ []string, err error) { go utils.Catch(nil, func() { g.Cleanup() }) defer func() { if err != nil { g.Cleanup() } }() mainFile := filepath.Join(codegen.OutputDir, "main.go") if Force { os.Remove(mainFile) } g.genfiles = append(g.genfiles, mainFile) _, err = os.Stat(mainFile) funcs := template.FuncMap{ "tempvar": tempvar, "generateSwagger": generateSwagger, "goify": codegen.Goify, "okResp": okResp, "newControllerVersion": newControllerVersion, "versionPkg": codegen.VersionPackage, "targetPkg": func() string { return TargetPackage }, } gopath := filepath.SplitList(os.Getenv("GOPATH"))[0] if err != nil { var tmpl *template.Template tmpl, err = template.New("main").Funcs(funcs).Parse(mainTmpl) if err != nil { panic(err.Error()) // bug } gg := codegen.NewGoGenerator(mainFile) var outPkg string outPkg, err = filepath.Rel(gopath, codegen.OutputDir) if err != nil { return } outPkg = strings.TrimPrefix(filepath.ToSlash(outPkg), "src/") appPkg := path.Join(outPkg, "app") swaggerPkg := path.Join(outPkg, "swagger") imports := []*codegen.ImportSpec{ codegen.SimpleImport("github.com/raphael/goa"), codegen.SimpleImport(appPkg), codegen.SimpleImport(swaggerPkg), codegen.NewImport("log", "gopkg.in/inconshreveable/log15.v2"), } if generateSwagger() { jsonSchemaPkg := path.Join(outPkg, "schema") imports = append(imports, codegen.SimpleImport(jsonSchemaPkg)) } gg.WriteHeader("", "main", imports) data := map[string]interface{}{ "Name": AppName, "API": api, } if err = tmpl.Execute(gg, data); err != nil { return } if err = gg.FormatCode(); err != nil { return } } tmpl, err := template.New("ctrl").Funcs(funcs).Parse(ctrlTmpl) if err != nil { panic(err.Error()) // bug } imp, err := filepath.Rel(filepath.Join(gopath, "src"), codegen.OutputDir) if err != nil { return } imp = path.Join(filepath.ToSlash(imp), "app") imports := []*codegen.ImportSpec{codegen.SimpleImport(imp)} api.IterateVersions(func(v *design.APIVersionDefinition) error { if v.IsDefault() { return nil } imports = append(imports, codegen.SimpleImport(imp+"/"+codegen.Goify(v.Version, false))) return nil }) err = api.IterateResources(func(r *design.ResourceDefinition) error { filename := filepath.Join(codegen.OutputDir, snakeCase(r.Name)+".go") if Force { if err := os.Remove(filename); err != nil { return err } } g.genfiles = append(g.genfiles, filename) if _, err := os.Stat(filename); err != nil { resGen := codegen.NewGoGenerator(filename) resGen.WriteHeader("", "main", imports) err := tmpl.Execute(resGen, r) if err != nil { return err } if err := resGen.FormatCode(); err != nil { return err } } return nil }) if err != nil { return } return g.genfiles, nil }
// Generate the application code, implement codegen.Generator. func (g *Generator) Generate(api *design.APIDefinition) ([]string, error) { if api == nil { return nil, fmt.Errorf("missing API definition, make sure design.Design is properly initialized") } title := fmt.Sprintf("%s: Application Contexts", api.Name) imports := []*codegen.ImportSpec{ codegen.SimpleImport("github.com/raphael/goa"), codegen.SimpleImport("strconv"), } g.ContextsWriter.WriteHeader(title, TargetPackage, imports) err := api.IterateResources(func(r *design.ResourceDefinition) error { return r.IterateActions(func(a *design.ActionDefinition) error { ctxName := codegen.Goify(a.Name, true) + codegen.Goify(a.Parent.Name, true) + "Context" ctxData := ContextTemplateData{ Name: ctxName, ResourceName: r.Name, ActionName: a.Name, Payload: a.Payload, Params: a.AllParams(), Headers: r.Headers.Merge(a.Headers), Routes: a.Routes, Responses: MergeResponses(r.Responses, a.Responses), MediaTypes: api.MediaTypes, Types: api.Types, } return g.ContextsWriter.Execute(&ctxData) }) }) g.genfiles = append(g.genfiles, g.contextsFilename) if err != nil { g.Cleanup() return nil, err } if err := g.ContextsWriter.FormatCode(); err != nil { g.Cleanup() return nil, err } title = fmt.Sprintf("%s: Application Controllers", api.Name) imports = []*codegen.ImportSpec{ codegen.SimpleImport("github.com/julienschmidt/httprouter"), codegen.SimpleImport("github.com/raphael/goa"), } g.ControllersWriter.WriteHeader(title, TargetPackage, imports) var controllersData []*ControllerTemplateData api.IterateResources(func(r *design.ResourceDefinition) error { data := &ControllerTemplateData{Resource: codegen.Goify(r.Name, true)} err := r.IterateActions(func(a *design.ActionDefinition) error { context := fmt.Sprintf("%s%sContext", codegen.Goify(a.Name, true), codegen.Goify(r.Name, true)) action := map[string]interface{}{ "Name": codegen.Goify(a.Name, true), "Routes": a.Routes, "Context": context, } data.Actions = append(data.Actions, action) return nil }) if err != nil { return err } if len(data.Actions) > 0 { controllersData = append(controllersData, data) } return nil }) g.genfiles = append(g.genfiles, g.controllersFilename) if err := g.ControllersWriter.Execute(controllersData); err != nil { g.Cleanup() return nil, err } if err := g.ControllersWriter.FormatCode(); err != nil { g.Cleanup() return nil, err } title = fmt.Sprintf("%s: Application Resource Href Factories", api.Name) g.ResourcesWriter.WriteHeader(title, TargetPackage, nil) err = api.IterateResources(func(r *design.ResourceDefinition) error { m, ok := api.MediaTypes[r.MediaType] var identifier string if ok { identifier = m.Identifier } else { identifier = "application/text" } canoTemplate := r.URITemplate() canoTemplate = design.WildcardRegex.ReplaceAllLiteralString(canoTemplate, "/%v") var canoParams []string if ca := r.CanonicalAction(); ca != nil { if len(ca.Routes) > 0 { canoParams = ca.Routes[0].Params() } } data := ResourceData{ Name: codegen.Goify(r.Name, true), Identifier: identifier, Description: r.Description, Type: m, CanonicalTemplate: canoTemplate, CanonicalParams: canoParams, } return g.ResourcesWriter.Execute(&data) }) g.genfiles = append(g.genfiles, g.resourcesFilename) if err != nil { g.Cleanup() return nil, err } if err := g.ResourcesWriter.FormatCode(); err != nil { g.Cleanup() return nil, err } title = fmt.Sprintf("%s: Application Media Types", api.Name) imports = []*codegen.ImportSpec{ codegen.SimpleImport("github.com/raphael/goa"), codegen.SimpleImport("fmt"), } g.MediaTypesWriter.WriteHeader(title, TargetPackage, imports) err = api.IterateMediaTypes(func(mt *design.MediaTypeDefinition) error { if mt.Type.IsObject() || mt.Type.IsArray() { return g.MediaTypesWriter.Execute(mt) } return nil }) g.genfiles = append(g.genfiles, g.mediaTypesFilename) if err != nil { g.Cleanup() return nil, err } if err := g.MediaTypesWriter.FormatCode(); err != nil { g.Cleanup() return nil, err } title = fmt.Sprintf("%s: Application User Types", api.Name) g.UserTypesWriter.WriteHeader(title, TargetPackage, nil) err = api.IterateUserTypes(func(t *design.UserTypeDefinition) error { return g.UserTypesWriter.Execute(t) }) g.genfiles = append(g.genfiles, g.userTypesFilename) if err != nil { g.Cleanup() return nil, err } if err := g.UserTypesWriter.FormatCode(); err != nil { g.Cleanup() return nil, err } return g.genfiles, nil }
// Generate produces the skeleton main. func (g *Generator) Generate(api *design.APIDefinition) (_ []string, err error) { go utils.Catch(nil, func() { g.Cleanup() }) defer func() { if err != nil { g.Cleanup() } }() mainFile := filepath.Join(codegen.OutputDir, "main.go") if Force { os.Remove(mainFile) } g.genfiles = append(g.genfiles, mainFile) _, err = os.Stat(mainFile) funcs := template.FuncMap{ "tempvar": tempvar, "generateSwagger": generateSwagger, "okResp": okResp, "newControllerVersion": newControllerVersion, "targetPkg": func() string { return TargetPackage }, } if err != nil { file, err := codegen.SourceFileFor(mainFile) if err != nil { return nil, err } var outPkg string outPkg, err = codegen.PackagePath(codegen.OutputDir) if err != nil { return nil, err } outPkg = strings.TrimPrefix(filepath.ToSlash(outPkg), "src/") appPkg := path.Join(outPkg, "app") swaggerPkg := path.Join(outPkg, "swagger") imports := []*codegen.ImportSpec{ codegen.SimpleImport("github.com/raphael/goa"), codegen.SimpleImport(appPkg), codegen.SimpleImport(swaggerPkg), codegen.NewImport("log", "gopkg.in/inconshreveable/log15.v2"), } if generateSwagger() { jsonSchemaPkg := path.Join(outPkg, "schema") imports = append(imports, codegen.SimpleImport(jsonSchemaPkg)) } file.WriteHeader("", "main", imports) data := map[string]interface{}{ "Name": AppName, "API": api, } if err = file.ExecuteTemplate("main", mainT, funcs, data); err != nil { return nil, err } if err = file.FormatCode(); err != nil { return nil, err } } imp, err := codegen.PackagePath(codegen.OutputDir) if err != nil { return } imp = path.Join(filepath.ToSlash(imp), "app") imports := []*codegen.ImportSpec{codegen.SimpleImport(imp)} api.IterateVersions(func(v *design.APIVersionDefinition) error { if v.IsDefault() { return nil } imports = append(imports, codegen.SimpleImport(imp+"/"+codegen.VersionPackage(v.Version))) return nil }) err = api.IterateResources(func(r *design.ResourceDefinition) error { filename := filepath.Join(codegen.OutputDir, snakeCase(r.Name)+".go") if Force { if err := os.Remove(filename); err != nil { return err } } g.genfiles = append(g.genfiles, filename) if _, err := os.Stat(filename); err != nil { file, err := codegen.SourceFileFor(filename) if err != nil { return err } file.WriteHeader("", "main", imports) err = file.ExecuteTemplate("controller", ctrlT, funcs, r) if err != nil { return err } if err := file.FormatCode(); err != nil { return err } } return nil }) if err != nil { return } return g.genfiles, nil }