func makeToolDir(g *Generator, apiName string) (toolDir string, err error) { codegen.OutputDir = filepath.Join(codegen.OutputDir, "client") if err = os.RemoveAll(codegen.OutputDir); err != nil { return } g.genfiles = append(g.genfiles, codegen.OutputDir) apiName = strings.Replace(apiName, " ", "-", -1) toolDir = filepath.Join(codegen.OutputDir, fmt.Sprintf("%s-cli", codegen.SnakeCase(apiName))) if err = os.MkdirAll(toolDir, 0755); err != nil { return } g.genfiles = append(g.genfiles, toolDir) return }
func (g *Generator) generateResourceClient(res *design.ResourceDefinition, funcs template.FuncMap) error { payloadTmpl := template.Must(template.New("payload").Funcs(funcs).Parse(payloadTmpl)) clientsTmpl := template.Must(template.New("clients").Funcs(funcs).Parse(clientsTmpl)) clientsWSTmpl := template.Must(template.New("clients").Funcs(funcs).Parse(clientsWSTmpl)) pathTmpl := template.Must(template.New("pathTemplate").Funcs(funcs).Parse(pathTmpl)) resFilename := codegen.SnakeCase(res.Name) if resFilename == typesFileName { // Avoid clash with datatypes.go resFilename += "_client" } filename := filepath.Join(codegen.OutputDir, resFilename+".go") file, err := codegen.SourceFileFor(filename) if err != nil { return err } imports := []*codegen.ImportSpec{ codegen.SimpleImport("bytes"), codegen.SimpleImport("encoding/json"), codegen.SimpleImport("fmt"), codegen.SimpleImport("io"), codegen.SimpleImport("net/http"), codegen.SimpleImport("net/url"), codegen.SimpleImport("strconv"), codegen.SimpleImport("strings"), codegen.SimpleImport("time"), codegen.SimpleImport("golang.org/x/net/context"), codegen.SimpleImport("golang.org/x/net/websocket"), codegen.NewImport("uuid", "github.com/satori/go.uuid"), } if err := file.WriteHeader("", "client", imports); err != nil { return err } g.genfiles = append(g.genfiles, filename) g.generatedTypes = make(map[string]bool) err = res.IterateActions(func(action *design.ActionDefinition) error { if action.Payload != nil { if err := payloadTmpl.Execute(file, action); err != nil { return err } g.generatedTypes[action.Payload.TypeName] = true } if action.Params != nil { params := make(design.Object, len(action.QueryParams.Type.ToObject())) for n, param := range action.QueryParams.Type.ToObject() { name := codegen.Goify(n, false) params[name] = param } action.QueryParams.Type = params } if action.Headers != nil { headers := make(design.Object, len(action.Headers.Type.ToObject())) for n, header := range action.Headers.Type.ToObject() { name := codegen.Goify(n, false) headers[name] = header } action.Headers.Type = headers } if action.WebSocket() { return clientsWSTmpl.Execute(file, action) } for i, r := range action.Routes { data := struct { Route *design.RouteDefinition Index int }{ Route: r, Index: i, } if err := pathTmpl.Execute(file, data); err != nil { return err } } return clientsTmpl.Execute(file, action) }) if err != nil { return err } return file.FormatCode() }
func (g *Generator) generateResourceTest(api *design.APIDefinition) error { if len(api.Resources) == 0 { return nil } testTmpl := template.Must(template.New("resources").Parse(testTmpl)) outDir, err := makeTestDir(g, api.Name) if err != nil { return err } appPkg, err := AppPackagePath() if err != nil { return err } imports := []*codegen.ImportSpec{ codegen.SimpleImport("bytes"), codegen.SimpleImport("fmt"), codegen.SimpleImport("net/http"), codegen.SimpleImport("net/http/httptest"), codegen.SimpleImport("testing"), codegen.SimpleImport(appPkg), codegen.SimpleImport("github.com/goadesign/goa"), codegen.SimpleImport("github.com/goadesign/goa/goatest"), codegen.SimpleImport("golang.org/x/net/context"), } return api.IterateResources(func(res *design.ResourceDefinition) error { filename := filepath.Join(outDir, codegen.SnakeCase(res.Name)+".go") file, err := codegen.SourceFileFor(filename) if err != nil { return err } if err := file.WriteHeader("", "test", imports); err != nil { return err } var methods = []TestMethod{} if err := res.IterateActions(func(action *design.ActionDefinition) error { if err := action.IterateResponses(func(response *design.ResponseDefinition) error { if response.Status == 101 { // SwitchingProtocols, Don't currently handle WebSocket endpoints return nil } for routeIndex, route := range action.Routes { mediaType := design.Design.MediaTypeWithIdentifier(response.MediaType) if mediaType == nil { methods = append(methods, createTestMethod(res, action, response, route, routeIndex, nil, nil)) } else { if err := mediaType.IterateViews(func(view *design.ViewDefinition) error { methods = append(methods, createTestMethod(res, action, response, route, routeIndex, mediaType, view)) return nil }); err != nil { return err } } } return nil }); err != nil { return err } return nil }); err != nil { return err } g.genfiles = append(g.genfiles, filename) err = testTmpl.Execute(file, methods) if err != nil { panic(err) } return file.FormatCode() }) }
// Generate produces the skeleton main. func (g *Generator) Generate() (_ []string, err error) { go utils.Catch(nil, func() { g.Cleanup() }) defer func() { if err != nil { g.Cleanup() } }() if g.Target == "" { g.Target = "app" } codegen.Reserved[g.Target] = true mainFile := filepath.Join(g.OutDir, "main.go") if g.Force { os.Remove(mainFile) } funcs := template.FuncMap{ "tempvar": tempvar, "okResp": g.okResp, "targetPkg": func() string { return g.Target }, } imp, err := codegen.PackagePath(g.OutDir) if err != nil { return nil, err } imp = path.Join(filepath.ToSlash(imp), "app") _, err = os.Stat(mainFile) if err != nil { if err = g.createMainFile(mainFile, funcs); err != nil { return nil, err } } imports := []*codegen.ImportSpec{ codegen.SimpleImport("io"), codegen.SimpleImport("github.com/goadesign/goa"), codegen.SimpleImport(imp), codegen.SimpleImport("golang.org/x/net/websocket"), } err = g.API.IterateResources(func(r *design.ResourceDefinition) error { filename := filepath.Join(g.OutDir, codegen.SnakeCase(r.Name)+".go") if g.Force { os.Remove(filename) } if _, e := os.Stat(filename); e != nil { g.genfiles = append(g.genfiles, filename) file, err2 := codegen.SourceFileFor(filename) if err2 != nil { return err } file.WriteHeader("", "main", imports) if err2 = file.ExecuteTemplate("controller", ctrlT, funcs, r); err2 != nil { return err } err2 = r.IterateActions(func(a *design.ActionDefinition) error { if a.WebSocket() { return file.ExecuteTemplate("actionWS", actionWST, funcs, a) } return file.ExecuteTemplate("action", actionT, funcs, a) }) if err2 != nil { return err } if err2 = file.FormatCode(); err2 != nil { return err2 } } return nil }) if err != nil { return } return g.genfiles, nil }
func (g *Generator) generateResourceTest() error { if len(g.API.Resources) == 0 { return nil } funcs := template.FuncMap{"isSlice": isSlice} testTmpl := template.Must(template.New("test").Funcs(funcs).Parse(testTmpl)) outDir, err := makeTestDir(g, g.API.Name) if err != nil { return err } appPkg, err := codegen.PackagePath(g.OutDir) if err != nil { return err } imports := []*codegen.ImportSpec{ codegen.SimpleImport("bytes"), codegen.SimpleImport("fmt"), codegen.SimpleImport("io"), codegen.SimpleImport("log"), codegen.SimpleImport("net/http"), codegen.SimpleImport("net/http/httptest"), codegen.SimpleImport("net/url"), codegen.SimpleImport("strconv"), codegen.SimpleImport("strings"), codegen.SimpleImport("time"), codegen.SimpleImport(appPkg), codegen.SimpleImport("github.com/goadesign/goa"), codegen.SimpleImport("github.com/goadesign/goa/goatest"), codegen.SimpleImport("golang.org/x/net/context"), codegen.NewImport("uuid", "github.com/satori/go.uuid"), } return g.API.IterateResources(func(res *design.ResourceDefinition) error { filename := filepath.Join(outDir, codegen.SnakeCase(res.Name)+"_testing.go") file, err := codegen.SourceFileFor(filename) if err != nil { return err } title := fmt.Sprintf("%s: %s TestHelpers", g.API.Context(), res.Name) if err := file.WriteHeader(title, "test", imports); err != nil { return err } var methods []*TestMethod if err := res.IterateActions(func(action *design.ActionDefinition) error { if err := action.IterateResponses(func(response *design.ResponseDefinition) error { if response.Status == 101 { // SwitchingProtocols, Don't currently handle WebSocket endpoints return nil } for routeIndex, route := range action.Routes { mediaType := design.Design.MediaTypeWithIdentifier(response.MediaType) if mediaType == nil { methods = append(methods, g.createTestMethod(res, action, response, route, routeIndex, nil, nil)) } else { if err := mediaType.IterateViews(func(view *design.ViewDefinition) error { methods = append(methods, g.createTestMethod(res, action, response, route, routeIndex, mediaType, view)) return nil }); err != nil { return err } } } return nil }); err != nil { return err } return nil }); err != nil { return err } g.genfiles = append(g.genfiles, filename) err = testTmpl.Execute(file, methods) if err != nil { panic(err) } return file.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() } }() mainFile := filepath.Join(codegen.OutputDir, "main.go") if Force { os.Remove(mainFile) } funcs := template.FuncMap{ "tempvar": tempvar, "generateSwagger": generateSwagger, "okResp": okResp, "targetPkg": func() string { return TargetPackage }, } imp, err := codegen.PackagePath(codegen.OutputDir) if err != nil { return nil, err } imp = path.Join(filepath.ToSlash(imp), "app") _, err = os.Stat(mainFile) if err != nil { g.genfiles = append(g.genfiles, mainFile) file, err2 := codegen.SourceFileFor(mainFile) if err2 != nil { return nil, err2 } var outPkg string outPkg, err2 = codegen.PackagePath(codegen.OutputDir) if err2 != nil { return nil, err2 } outPkg = strings.TrimPrefix(filepath.ToSlash(outPkg), "src/") appPkg := path.Join(outPkg, "app") swaggerPkg := path.Join(outPkg, "swagger") imports := []*codegen.ImportSpec{ codegen.SimpleImport("time"), codegen.SimpleImport("github.com/goadesign/goa"), codegen.SimpleImport("github.com/goadesign/goa/middleware"), codegen.SimpleImport(appPkg), codegen.SimpleImport(swaggerPkg), } 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 err2 = file.ExecuteTemplate("main", mainT, funcs, data); err2 != nil { return nil, err2 } if err2 = file.FormatCode(); err2 != nil { return nil, err2 } } imports := []*codegen.ImportSpec{ codegen.SimpleImport("io"), codegen.SimpleImport("github.com/goadesign/goa"), codegen.SimpleImport(imp), codegen.SimpleImport("golang.org/x/net/websocket"), } err = api.IterateResources(func(r *design.ResourceDefinition) error { filename := filepath.Join(codegen.OutputDir, codegen.SnakeCase(r.Name)+".go") if Force { if err2 := os.Remove(filename); err2 != nil { return err2 } } if _, e := os.Stat(filename); e != nil { g.genfiles = append(g.genfiles, filename) file, err2 := codegen.SourceFileFor(filename) if err2 != nil { return err } file.WriteHeader("", "main", imports) if err2 = file.ExecuteTemplate("controller", ctrlT, funcs, r); err2 != nil { return err } err2 = r.IterateActions(func(a *design.ActionDefinition) error { if a.WebSocket() { return file.ExecuteTemplate("actionWS", actionWST, funcs, a) } return file.ExecuteTemplate("action", actionT, funcs, a) }) if err2 != nil { return err } if err2 = file.FormatCode(); err2 != nil { return err2 } } return nil }) if err != nil { return } return g.genfiles, nil }
func (g *Generator) generateResourceClient(pkgDir string, res *design.ResourceDefinition, funcs template.FuncMap) error { payloadTmpl := template.Must(template.New("payload").Funcs(funcs).Parse(payloadTmpl)) pathTmpl := template.Must(template.New("pathTemplate").Funcs(funcs).Parse(pathTmpl)) resFilename := codegen.SnakeCase(res.Name) if resFilename == typesFileName { // Avoid clash with datatypes.go resFilename += "_client" } filename := filepath.Join(pkgDir, resFilename+".go") file, err := codegen.SourceFileFor(filename) if err != nil { return err } imports := []*codegen.ImportSpec{ codegen.SimpleImport("bytes"), codegen.SimpleImport("encoding/json"), codegen.SimpleImport("fmt"), codegen.SimpleImport("io"), codegen.SimpleImport("io/ioutil"), codegen.SimpleImport("net/http"), codegen.SimpleImport("net/url"), codegen.SimpleImport("os"), codegen.SimpleImport("path"), codegen.SimpleImport("strconv"), codegen.SimpleImport("strings"), codegen.SimpleImport("time"), codegen.SimpleImport("golang.org/x/net/context"), codegen.SimpleImport("golang.org/x/net/websocket"), codegen.NewImport("uuid", "github.com/goadesign/goa/uuid"), } if err := file.WriteHeader("", g.Target, imports); err != nil { return err } g.genfiles = append(g.genfiles, filename) err = res.IterateFileServers(func(fs *design.FileServerDefinition) error { return g.generateFileServer(file, fs, funcs) }) err = res.IterateActions(func(action *design.ActionDefinition) error { if action.Payload != nil { found := false typeName := action.Payload.TypeName for _, t := range design.Design.Types { if t.TypeName == typeName { found = true break } } if !found { if err := payloadTmpl.Execute(file, action); err != nil { return err } } } for i, r := range action.Routes { data := struct { Route *design.RouteDefinition Index int }{ Route: r, Index: i, } if err := pathTmpl.Execute(file, data); err != nil { return err } } return g.generateActionClient(action, file, funcs) }) if err != nil { return err } return file.FormatCode() }