func (m *Generator) generateToolSourceCode(pkg *codegen.Package) { file := pkg.CreateSourceFile("main.go") imports := append(m.Imports, codegen.SimpleImport("fmt"), codegen.SimpleImport("os"), codegen.SimpleImport("strings"), codegen.NewImport(".", "github.com/raphael/goa/design"), codegen.NewImport(".", "github.com/raphael/goa/design/dsl"), codegen.NewImport("_", filepath.ToSlash(codegen.DesignPackagePath)), ) file.WriteHeader("Code Generator", "main", imports) tmpl, err := template.New("generator").Parse(mainTmpl) if err != nil { panic(err) // bug } pkgName, err := codegen.PackageName(pkg.Abs()) if err != nil { panic(err) } context := map[string]string{ "Genfunc": m.Genfunc, "DesignPackage": codegen.DesignPackagePath, "PkgName": pkgName, } err = tmpl.Execute(file, context) if err != nil { panic(err) // bug } if codegen.Debug { src, _ := ioutil.ReadFile(file.Abs()) fmt.Printf("goagen source:\n%s\n", src) } }
// generateMediaTypes iterates through the media types and generate the data structures and // marshaling code. func (g *Generator) generateMediaTypes(verdir string, version *design.APIVersionDefinition) error { mtFile := filepath.Join(verdir, "media_types.go") mtWr, err := NewMediaTypesWriter(mtFile) if err != nil { panic(err) // bug } title := fmt.Sprintf("%s: Application Media Types", version.Context()) imports := []*codegen.ImportSpec{ codegen.SimpleImport("github.com/raphael/goa"), codegen.SimpleImport("fmt"), } mtWr.WriteHeader(title, packageName(version), imports) err = version.IterateMediaTypes(func(mt *design.MediaTypeDefinition) error { data := &MediaTypeTemplateData{ MediaType: mt, Versioned: version.Version != "", DefaultPkg: TargetPackage, } if mt.Type.IsObject() || mt.Type.IsArray() { return mtWr.Execute(data) } return nil }) g.genfiles = append(g.genfiles, mtFile) if err != nil { return err } return mtWr.FormatCode() }
// generateUserTypes iterates through the user types and generates the data structures and // marshaling code. func (g *Generator) generateUserTypes(verdir string, version *design.APIVersionDefinition) error { utFile := filepath.Join(verdir, "user_types.go") utWr, err := NewUserTypesWriter(utFile) if err != nil { panic(err) // bug } title := fmt.Sprintf("%s: Application User Types", version.Context()) imports := []*codegen.ImportSpec{ codegen.SimpleImport("github.com/raphael/goa"), codegen.SimpleImport("fmt"), } utWr.WriteHeader(title, packageName(version), imports) err = version.IterateUserTypes(func(t *design.UserTypeDefinition) error { data := &UserTypeTemplateData{ UserType: t, Versioned: version.Version != "", DefaultPkg: TargetPackage, } return utWr.Execute(data) }) g.genfiles = append(g.genfiles, utFile) if err != nil { return err } return utWr.FormatCode() }
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() }) }
func (m *Generator) generateToolSourceCode(gendir, pkgName string) { filename := filepath.Join(gendir, "main.go") m.GoGenerator = codegen.NewGoGenerator(filename) imports := append(m.Imports, codegen.SimpleImport("fmt"), codegen.SimpleImport("os"), codegen.SimpleImport("strings"), codegen.NewImport(".", "github.com/raphael/goa/design"), codegen.NewImport(".", "github.com/raphael/goa/design/dsl"), codegen.NewImport("_", codegen.DesignPackagePath), ) m.WriteHeader("Code Generator", "main", imports) tmpl, err := template.New("generator").Parse(mainTmpl) if err != nil { panic(err) // bug } context := map[string]string{ "Genfunc": m.Genfunc, "DesignPackage": codegen.DesignPackagePath, "PkgName": pkgName, } err = tmpl.Execute(m, context) if err != nil { panic(err) // bug } if codegen.Debug { src, _ := ioutil.ReadFile(filename) fmt.Printf("goagen source:\n%s\n", src) } }
// Generate is the generator entry point called by the meta generator. func Generate(api *design.APIDefinition) (_ []string, err error) { var genfiles []string cleanup := func() { for _, f := range genfiles { os.Remove(f) } } go utils.Catch(nil, cleanup) defer func() { if err != nil { cleanup() } }() app := kingpin.New("Swagger generator", "Swagger spec generator") codegen.RegisterFlags(app) _, err = app.Parse(os.Args[1:]) if err != nil { return nil, fmt.Errorf(`invalid command line: %s. Command line was "%s"`, err, strings.Join(os.Args, " ")) } s, err := New(api) if err != nil { return } b, err := json.Marshal(s) if err != nil { return } swaggerDir := filepath.Join(codegen.OutputDir, "swagger") os.RemoveAll(swaggerDir) if err = os.MkdirAll(swaggerDir, 0755); err != nil { return } genfiles = append(genfiles, swaggerDir) swaggerFile := filepath.Join(swaggerDir, "swagger.json") err = ioutil.WriteFile(swaggerFile, b, 0644) if err != nil { return } genfiles = append(genfiles, swaggerFile) controllerFile := filepath.Join(swaggerDir, "swagger.go") genfiles = append(genfiles, controllerFile) gg := codegen.NewGoGenerator(controllerFile) imports := []*codegen.ImportSpec{ codegen.SimpleImport("github.com/julienschmidt/httprouter"), codegen.SimpleImport("github.com/raphael/goa"), } gg.WriteHeader(fmt.Sprintf("%s Swagger Spec", api.Name), "swagger", imports) gg.Write([]byte(swagger)) if err = gg.FormatCode(); err != nil { return } return genfiles, nil }
// generateControllers iterates through the version resources and generates the low level // controllers. func (g *Generator) generateControllers(verdir string, version *design.APIVersionDefinition) error { ctlFile := filepath.Join(verdir, "controllers.go") ctlWr, err := NewControllersWriter(ctlFile) if err != nil { panic(err) // bug } title := fmt.Sprintf("%s: Application Controllers", version.Context()) imports := []*codegen.ImportSpec{ codegen.SimpleImport("github.com/julienschmidt/httprouter"), codegen.SimpleImport("github.com/raphael/goa"), } if !version.IsDefault() { appPkg, err := AppPackagePath() if err != nil { return err } imports = append(imports, codegen.SimpleImport(appPkg)) } ctlWr.WriteHeader(title, packageName(version), imports) var controllersData []*ControllerTemplateData version.IterateResources(func(r *design.ResourceDefinition) error { if !r.SupportsVersion(version.Version) { return nil } 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)) unmarshal := fmt.Sprintf("unmarshal%s%sPayload", 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, "Unmarshal": unmarshal, "Payload": a.Payload, } data.Actions = append(data.Actions, action) return nil }) if err != nil { return err } if len(data.Actions) > 0 { data.Version = version controllersData = append(controllersData, data) } return nil }) g.genfiles = append(g.genfiles, ctlFile) if err = ctlWr.Execute(controllersData); err != nil { return err } return ctlWr.FormatCode() }
// generateContexts iterates through the version resources and actions and generates the action // contexts. func (g *Generator) generateContexts(verdir string, api *design.APIDefinition, version *design.APIVersionDefinition) error { ctxFile := filepath.Join(verdir, "contexts.go") ctxWr, err := NewContextsWriter(ctxFile) if err != nil { panic(err) // bug } title := fmt.Sprintf("%s: Application Contexts", version.Context()) imports := []*codegen.ImportSpec{ codegen.SimpleImport("fmt"), codegen.SimpleImport("strconv"), codegen.SimpleImport("github.com/raphael/goa"), } if !version.IsDefault() { appPkg, err := AppPackagePath() if err != nil { return err } imports = append(imports, codegen.SimpleImport(filepath.ToSlash(appPkg))) } ctxWr.WriteHeader(title, packageName(version), imports) var appPackage string if !version.IsDefault() { appPackage = TargetPackage } err = version.IterateResources(func(r *design.ResourceDefinition) error { if !r.SupportsVersion(version.Version) { return nil } 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), API: api, Version: version, AppPackage: appPackage, } return ctxWr.Execute(&ctxData) }) }) g.genfiles = append(g.genfiles, ctxFile) if err != nil { return err } return ctxWr.FormatCode() }
// Run simply calls the meta generator. func (c *Command) Run() ([]string, error) { gen := meta.NewGenerator( "genjs.Generate", []*codegen.ImportSpec{codegen.SimpleImport("github.com/raphael/goa/goagen/gen_js")}, nil, ) return gen.Generate() }
// Run simply calls the meta generator. func (c *Command) Run() ([]string, error) { flags := map[string]string{"pkg": TargetPackage} gen := meta.NewGenerator( "genapp.Generate", []*codegen.ImportSpec{codegen.SimpleImport("github.com/raphael/goa/goagen/gen_app")}, flags, ) return gen.Generate() }
// Run simply calls the meta generator. func (c *Command) Run() ([]string, error) { flags := map[string]string{"url": ServiceURL} gen := meta.NewGenerator( "genschema.Generate", []*codegen.ImportSpec{codegen.SimpleImport("github.com/raphael/goa/goagen/gen_schema")}, flags, ) return gen.Generate() }
// Run simply calls the meta generator. func (c *Command) Run() ([]string, error) { flags := map[string]string{"name": AppName} gen := meta.NewGenerator( "genmain.Generate", []*codegen.ImportSpec{codegen.SimpleImport("github.com/raphael/goa/goagen/gen_main")}, flags, ) return gen.Generate() }
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() }
// 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() } }() os.RemoveAll(JSONSchemaDir()) os.MkdirAll(JSONSchemaDir(), 0755) g.genfiles = append(g.genfiles, JSONSchemaDir()) s := APISchema(api) js, err := s.JSON() if err != nil { return } schemaFile := filepath.Join(JSONSchemaDir(), "schema.json") if err = ioutil.WriteFile(schemaFile, js, 0644); err != nil { return } g.genfiles = append(g.genfiles, schemaFile) controllerFile := filepath.Join(JSONSchemaDir(), "schema.go") file, err := codegen.SourceFileFor(controllerFile) if err != nil { return } imports := []*codegen.ImportSpec{ codegen.SimpleImport("github.com/julienschmidt/httprouter"), codegen.SimpleImport("github.com/raphael/goa"), } g.genfiles = append(g.genfiles, controllerFile) file.WriteHeader(fmt.Sprintf("%s JSON Hyper-schema", api.Name), "schema", imports) file.Write([]byte(jsonSchemaCtrl)) if err = file.FormatCode(); err != nil { return } return g.genfiles, nil }
// Run simply calls the meta generator. func (c *Command) Run() ([]string, error) { if GenPkgName == "" { GenPkgName = filepath.ToSlash(filepath.Base(GenPkgPath)) } gen := meta.NewGenerator( fmt.Sprintf("%s.Generate", GenPkgName), []*codegen.ImportSpec{codegen.SimpleImport(GenPkgPath)}, nil, ) return gen.Generate() }
func (g *Generator) generateClient(clientFile string, clientPkg string, funcs template.FuncMap, api *design.APIDefinition) error { gg := codegen.NewGoGenerator(clientFile) clientTmpl := template.Must(template.New("client").Funcs(funcs).Parse(clientTmpl)) imports := []*codegen.ImportSpec{ codegen.SimpleImport("net/http"), codegen.SimpleImport("github.com/raphael/goa"), codegen.SimpleImport("gopkg.in/alecthomas/kingpin.v2"), } if err := gg.WriteHeader("", "client", imports); err != nil { return err } g.genfiles = append(g.genfiles, clientFile) if err := clientTmpl.Execute(gg, api); 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() }
func (g *Generator) generateExample(api *design.APIDefinition) error { controllerFile := filepath.Join(codegen.OutputDir, "example.go") file, err := codegen.SourceFileFor(controllerFile) if err != nil { return err } imports := []*codegen.ImportSpec{ codegen.SimpleImport("net/http"), codegen.SimpleImport("github.com/julienschmidt/httprouter"), codegen.SimpleImport("github.com/raphael/goa"), } if err := file.WriteHeader(fmt.Sprintf("%s JavaScript Client Example", api.Name), "js", imports); err != nil { return err } g.genfiles = append(g.genfiles, controllerFile) data := map[string]interface{}{"ServeDir": codegen.OutputDir} if err := file.ExecuteTemplate("examples", exampleCtrlT, nil, data); err != nil { return err } return file.FormatCode() }
func (g *Generator) generateExample(api *design.APIDefinition) error { exampleTmpl := template.Must(template.New("exampleController").Parse(exampleCtrlT)) controllerFile := filepath.Join(codegen.OutputDir, "example.go") gg := codegen.NewGoGenerator(controllerFile) imports := []*codegen.ImportSpec{ codegen.SimpleImport("net/http"), codegen.SimpleImport("github.com/julienschmidt/httprouter"), codegen.SimpleImport("github.com/raphael/goa"), } if err := gg.WriteHeader(fmt.Sprintf("%s JavaScript Client Example", api.Name), "js", imports); err != nil { return err } g.genfiles = append(g.genfiles, controllerFile) data := map[string]interface{}{ "ServeDir": codegen.OutputDir, } if err := exampleTmpl.Execute(gg, data); err != nil { return err } return gg.FormatCode() }
// Generate is the generator entry point called by the meta generator. func Generate(api *design.APIDefinition) ([]string, error) { app := kingpin.New("Swagger generator", "Swagger spec generator") codegen.RegisterFlags(app) _, err := app.Parse(os.Args[1:]) if err != nil { return nil, fmt.Errorf(`invalid command line: %s. Command line was "%s"`, err, strings.Join(os.Args, " ")) } s, err := New(api) if err != nil { return nil, err } b, err := json.Marshal(s) if err != nil { return nil, err } swaggerDir := filepath.Join(codegen.OutputDir, "swagger") os.RemoveAll(swaggerDir) if err = os.MkdirAll(swaggerDir, 0755); err != nil { return nil, err } swaggerFile := filepath.Join(swaggerDir, "swagger.json") err = ioutil.WriteFile(swaggerFile, b, 0644) if err != nil { return nil, err } controllerFile := filepath.Join(swaggerDir, "swagger.go") tmpl, err := template.New("swagger").Parse(swaggerTmpl) if err != nil { panic(err.Error()) // bug } gg := codegen.NewGoGenerator(controllerFile) imports := []*codegen.ImportSpec{ codegen.SimpleImport("github.com/raphael/goa"), } gg.WriteHeader(fmt.Sprintf("%s Swagger Spec", api.Name), "swagger", imports) data := map[string]interface{}{ "spec": string(b), } err = tmpl.Execute(gg, data) if err != nil { return nil, err } if err := gg.FormatCode(); err != nil { return nil, err } return []string{controllerFile, swaggerFile}, nil }
// Generate produces the skeleton main. func (g *Generator) Generate(api *design.APIDefinition) ([]string, error) { os.RemoveAll(JSONSchemaDir()) os.MkdirAll(JSONSchemaDir(), 0755) s := APISchema(api) js, err := s.JSON() if err != nil { return nil, err } schemaFile := filepath.Join(JSONSchemaDir(), "schema.json") if err := ioutil.WriteFile(schemaFile, js, 0755); err != nil { return nil, err } g.genfiles = append(g.genfiles, schemaFile) controllerFile := filepath.Join(JSONSchemaDir(), "schema.go") tmpl, err := template.New("schema").Parse(jsonSchemaTmpl) if err != nil { panic(err.Error()) // bug } gg := codegen.NewGoGenerator(controllerFile) imports := []*codegen.ImportSpec{ codegen.SimpleImport("github.com/raphael/goa"), } gg.WriteHeader(fmt.Sprintf("%s JSON Hyper-schema", api.Name), "schema", imports) data := map[string]interface{}{ "schema": string(js), } err = tmpl.Execute(gg, data) if err != nil { g.Cleanup() return nil, err } if err := gg.FormatCode(); err != nil { g.Cleanup() return nil, err } g.genfiles = []string{controllerFile, schemaFile} return g.genfiles, nil }
// 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 }
// Generate compiles and runs the generator and returns the generated filenames. func (m *Generator) Generate() ([]string, error) { // First make sure environment is setup correctly. if codegen.OutputDir == "" { return nil, fmt.Errorf("missing output directory specification") } if codegen.DesignPackagePath == "" { return nil, fmt.Errorf("missing design package path specification") } if err := os.MkdirAll(codegen.OutputDir, 0755); err != nil { return nil, err } gopath := os.Getenv("GOPATH") if gopath == "" { return nil, fmt.Errorf("$GOPATH not defined") } candidates := strings.Split(gopath, ":") for i, c := range candidates { candidates[i] = filepath.Join(c, "src", codegen.DesignPackagePath) } var designPath string for _, path := range candidates { if _, err := os.Stat(path); err == nil { designPath = path break } } if designPath == "" { if len(candidates) == 1 { return nil, fmt.Errorf(`cannot find design package at path "%s"`, candidates[0]) } return nil, fmt.Errorf(`cannot find design package in any of the paths %s`, strings.Join(candidates, ", ")) } _, err := exec.LookPath("go") if err != nil { return nil, fmt.Errorf(`failed to find a go compiler, looked in "%s"`, os.Getenv("PATH")) } // Create temporary directory used for generation under the output dir. gendir, err := ioutil.TempDir(codegen.OutputDir, "goagen") if err != nil { if _, ok := err.(*os.PathError); ok { err = fmt.Errorf(`invalid output directory path "%s"`, codegen.OutputDir) } return nil, err } defer func() { if !codegen.Debug { os.RemoveAll(gendir) } }() if codegen.Debug { fmt.Printf("goagen source dir: %s\n", gendir) } // Figure out design package name from its path fset := token.NewFileSet() pkgs, err := parser.ParseDir(fset, designPath, nil, parser.PackageClauseOnly) if err != nil { return nil, err } pkgNames := make([]string, len(pkgs)) i := 0 for n := range pkgs { pkgNames[i] = n i++ } if len(pkgs) > 1 { return nil, fmt.Errorf("more than one Go package found in %s (%s)", designPath, strings.Join(pkgNames, ",")) } if len(pkgs) == 0 { return nil, fmt.Errorf("no Go package found in %s", designPath) } pkgName := pkgNames[0] // Generate tool source code. filename := filepath.Join(gendir, "main.go") m.GoGenerator = codegen.NewGoGenerator(filename) imports := append(m.Imports, codegen.SimpleImport("fmt"), codegen.SimpleImport("os"), codegen.SimpleImport("strings"), codegen.NewImport(".", "github.com/raphael/goa/design"), codegen.NewImport(".", "github.com/raphael/goa/design/dsl"), codegen.NewImport("_", codegen.DesignPackagePath), ) m.WriteHeader("Code Generator", "main", imports) tmpl, err := template.New("generator").Parse(mainTmpl) if err != nil { panic(err) // bug } context := map[string]string{ "Genfunc": m.Genfunc, "DesignPackage": codegen.DesignPackagePath, "PkgName": pkgName, } err = tmpl.Execute(m, context) if err != nil { panic(err) // bug } if codegen.Debug { src, _ := ioutil.ReadFile(filename) fmt.Printf("goagen source:\n%s\n", src) } // Compile and run generated tool. genbin, err := m.compile(gendir) if err != nil { return nil, err } return m.spawn(genbin) }
// 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 }
gopath := filepath.SplitList(os.Getenv("GOPATH"))[0] designPackageDir = filepath.Join(gopath, "src", designPackage) compiledFiles = nil compileError = nil }) JustBeforeEach(func() { if designPackageDir != "" && designPackageSource != "" { err := os.MkdirAll(designPackageDir, 0777) Ω(err).ShouldNot(HaveOccurred()) err = ioutil.WriteFile(filepath.Join(designPackageDir, "design.go"), []byte(designPackageSource), 0655) Ω(err).ShouldNot(HaveOccurred()) } m = &meta.Generator{ Genfunc: genfunc, Imports: []*codegen.ImportSpec{codegen.SimpleImport(designPackage)}, } codegen.Debug = debug codegen.OutputDir = outputDir codegen.DesignPackagePath = designPackage compiledFiles, compileError = m.Generate() }) AfterEach(func() { if designPackageDir != "" { os.RemoveAll(designPackageDir) } }) Context("with no GOPATH environment variable", func() { var gopath string
// 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 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 }