Esempio n. 1
0
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/goadesign/goa/design"),
		codegen.NewImport(".", "github.com/goadesign/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
	}
}
Esempio n. 2
0
// generateMediaTypes iterates through the media types and generate the data structures and
// marshaling code.
func (g *Generator) generateMediaTypes() error {
	mtFile := filepath.Join(g.OutDir, "media_types.go")
	mtWr, err := NewMediaTypesWriter(mtFile)
	if err != nil {
		panic(err) // bug
	}
	title := fmt.Sprintf("%s: Application Media Types", g.API.Context())
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport("github.com/goadesign/goa"),
		codegen.SimpleImport("fmt"),
		codegen.SimpleImport("time"),
		codegen.SimpleImport("unicode/utf8"),
		codegen.NewImport("uuid", "github.com/satori/go.uuid"),
	}
	mtWr.WriteHeader(title, g.Target, imports)
	err = g.API.IterateMediaTypes(func(mt *design.MediaTypeDefinition) error {
		if mt.IsError() {
			return nil
		}
		if mt.Type.IsObject() || mt.Type.IsArray() {
			return mtWr.Execute(mt)
		}
		return nil
	})
	g.genfiles = append(g.genfiles, mtFile)
	if err != nil {
		return err
	}
	return mtWr.FormatCode()
}
Esempio n. 3
0
// generateContexts iterates through the API resources and actions and generates the action
// contexts.
func (g *Generator) generateContexts() error {
	ctxFile := filepath.Join(g.OutDir, "contexts.go")
	ctxWr, err := NewContextsWriter(ctxFile)
	if err != nil {
		panic(err) // bug
	}
	title := fmt.Sprintf("%s: Application Contexts", g.API.Context())
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport("fmt"),
		codegen.SimpleImport("golang.org/x/net/context"),
		codegen.SimpleImport("strconv"),
		codegen.SimpleImport("strings"),
		codegen.SimpleImport("time"),
		codegen.SimpleImport("unicode/utf8"),
		codegen.SimpleImport("github.com/goadesign/goa"),
		codegen.NewImport("uuid", "github.com/satori/go.uuid"),
	}
	g.genfiles = append(g.genfiles, ctxFile)
	ctxWr.WriteHeader(title, g.Target, imports)
	err = g.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"
			headers := r.Headers.Merge(a.Headers)
			if headers != nil && len(headers.Type.ToObject()) == 0 {
				headers = nil // So that {{if .Headers}} returns false in templates
			}
			params := a.AllParams()
			if params != nil && len(params.Type.ToObject()) == 0 {
				params = nil // So that {{if .Params}} returns false in templates
			}

			non101 := make(map[string]*design.ResponseDefinition)
			for k, v := range a.Responses {
				if v.Status != 101 {
					non101[k] = v
				}
			}
			ctxData := ContextTemplateData{
				Name:         ctxName,
				ResourceName: r.Name,
				ActionName:   a.Name,
				Payload:      a.Payload,
				Params:       params,
				Headers:      headers,
				Routes:       a.Routes,
				Responses:    non101,
				API:          g.API,
				DefaultPkg:   g.Target,
				Security:     a.Security,
			}
			return ctxWr.Execute(&ctxData)
		})
	})
	if err != nil {
		return err
	}
	return ctxWr.FormatCode()
}
Esempio n. 4
0
// generateUserTypes iterates through the user types and generates the data structures and
// marshaling code.
func (g *Generator) generateUserTypes(outdir string, api *design.APIDefinition) error {
	var modelname, filename string
	err := GormaDesign.IterateStores(func(store *RelationalStoreDefinition) error {
		err := store.IterateModels(func(model *RelationalModelDefinition) error {
			modelname = strings.ToLower(codegen.Goify(model.ModelName, false))

			filename = fmt.Sprintf("%s.go", modelname)
			utFile := filepath.Join(outdir, filename)
			err := os.RemoveAll(utFile)
			if err != nil {
				fmt.Println(err)
			}
			utWr, err := NewUserTypesWriter(utFile)
			if err != nil {
				panic(err) // bug
			}
			title := fmt.Sprintf("%s: Models", api.Context())
			imports := []*codegen.ImportSpec{
				codegen.SimpleImport(g.appPkgPath),
				codegen.SimpleImport("time"),
				codegen.SimpleImport("github.com/goadesign/goa"),
				codegen.SimpleImport("github.com/jinzhu/gorm"),
				codegen.SimpleImport("golang.org/x/net/context"),
				codegen.SimpleImport("golang.org/x/net/context"),
				codegen.SimpleImport("github.com/goadesign/goa/uuid"),
			}

			if model.Cached {
				imp := codegen.NewImport("cache", "github.com/patrickmn/go-cache")
				imports = append(imports, imp)
				imp = codegen.SimpleImport("strconv")
				imports = append(imports, imp)
			}
			utWr.WriteHeader(title, g.target, imports)
			data := &UserTypeTemplateData{
				APIDefinition: api,
				UserType:      model,
				DefaultPkg:    g.target,
				AppPkg:        g.appPkgPath,
			}
			err = utWr.Execute(data)
			g.genfiles = append(g.genfiles, utFile)
			if err != nil {
				fmt.Println(err)
				return err
			}
			err = utWr.FormatCode()
			if err != nil {
				fmt.Println(err)
			}
			return err
		})
		return err
	})
	return err
}
Esempio n. 5
0
// generateContexts iterates through the API resources and actions and generates the action
// contexts.
func (g *Generator) generateContexts(api *design.APIDefinition) error {
	ctxFile := filepath.Join(AppOutputDir(), "contexts.go")
	ctxWr, err := NewContextsWriter(ctxFile)
	if err != nil {
		panic(err) // bug
	}
	title := fmt.Sprintf("%s: Application Contexts", api.Context())
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport("fmt"),
		codegen.SimpleImport("golang.org/x/net/context"),
		codegen.SimpleImport("strconv"),
		codegen.SimpleImport("strings"),
		codegen.SimpleImport("time"),
		codegen.SimpleImport("github.com/goadesign/goa"),
		codegen.NewImport("uuid", "github.com/satori/go.uuid"),
	}
	ctxWr.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"
			headers := r.Headers.Merge(a.Headers)
			if headers != nil && len(headers.Type.ToObject()) == 0 {
				headers = nil // So that {{if .Headers}} returns false in templates
			}
			params := a.AllParams()
			if params != nil && len(params.Type.ToObject()) == 0 {
				params = nil // So that {{if .Params}} returns false in templates
			}

			ctxData := ContextTemplateData{
				Name:         ctxName,
				ResourceName: r.Name,
				ActionName:   a.Name,
				Payload:      a.Payload,
				Params:       params,
				Headers:      headers,
				Routes:       a.Routes,
				Responses:    BuildResponses(r.Responses, a.Responses),
				API:          api,
				DefaultPkg:   TargetPackage,
				Security:     a.Security,
			}
			return ctxWr.Execute(&ctxData)
		})
	})
	g.genfiles = append(g.genfiles, ctxFile)
	if err != nil {
		return err
	}
	return ctxWr.FormatCode()
}
Esempio n. 6
0
func (g *Generator) generateCommands(commandsFile string, clientPkg string, funcs template.FuncMap, api *design.APIDefinition) error {
	file, err := codegen.SourceFileFor(commandsFile)
	if err != nil {
		return err
	}
	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("encoding/json"),
		codegen.SimpleImport("fmt"),
		codegen.SimpleImport(clientPkg),
		codegen.SimpleImport("github.com/goadesign/goa"),
		codegen.SimpleImport("github.com/spf13/cobra"),
		codegen.NewImport("log", "gopkg.in/inconshreveable/log15.v2"),
	}
	if err := file.WriteHeader("", "main", imports); err != nil {
		return err
	}
	g.genfiles = append(g.genfiles, commandsFile)

	file.Write([]byte("type (\n"))
	if err := api.IterateResources(func(res *design.ResourceDefinition) error {
		return res.IterateActions(func(action *design.ActionDefinition) error {
			return commandTypesTmpl.Execute(file, action)
		})
	}); err != nil {
		return err
	}
	file.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(file, data)
		})
	}); err != nil {
		return err
	}

	return file.FormatCode()
}
Esempio n. 7
0
// generateMediaTypes iterates through the media types and generate the data structures and
// marshaling code.
func (g *Generator) generateMediaTypes(pkgDir string, funcs template.FuncMap) error {
	funcs["decodegotyperef"] = decodeGoTypeRef
	funcs["decodegotypename"] = decodeGoTypeName
	typeDecodeTmpl := template.Must(template.New("typeDecode").Funcs(funcs).Parse(typeDecodeTmpl))
	mtFile := filepath.Join(pkgDir, "media_types.go")
	mtWr, err := genapp.NewMediaTypesWriter(mtFile)
	if err != nil {
		panic(err) // bug
	}
	title := fmt.Sprintf("%s: Application Media Types", g.API.Context())
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport("github.com/goadesign/goa"),
		codegen.SimpleImport("fmt"),
		codegen.SimpleImport("net/http"),
		codegen.SimpleImport("time"),
		codegen.SimpleImport("unicode/utf8"),
		codegen.NewImport("uuid", "github.com/goadesign/goa/uuid"),
	}
	mtWr.WriteHeader(title, g.Target, imports)
	err = g.API.IterateMediaTypes(func(mt *design.MediaTypeDefinition) error {
		if (mt.Type.IsObject() || mt.Type.IsArray()) && !mt.IsError() {
			if err := mtWr.Execute(mt); err != nil {
				return err
			}
		}
		err := mt.IterateViews(func(view *design.ViewDefinition) error {
			p, _, err := mt.Project(view.Name)
			if err != nil {
				return err
			}
			if err := typeDecodeTmpl.Execute(mtWr.SourceFile, p); err != nil {
				return err
			}
			return nil
		})
		return err
	})
	g.genfiles = append(g.genfiles, mtFile)
	if err != nil {
		return err
	}
	return mtWr.FormatCode()
}
Esempio n. 8
0
func (g *Generator) generateClient(clientFile string, clientPkg string, funcs template.FuncMap, api *design.APIDefinition) error {
	file, err := codegen.SourceFileFor(clientFile)
	if err != nil {
		return err
	}
	clientTmpl := template.Must(template.New("client").Funcs(funcs).Parse(clientTmpl))

	imports := []*codegen.ImportSpec{
		codegen.SimpleImport("net/http"),
		codegen.NewImport("goaclient", "github.com/goadesign/goa/client"),
	}
	if err := file.WriteHeader("", "client", imports); err != nil {
		return err
	}
	g.genfiles = append(g.genfiles, clientFile)

	if err := clientTmpl.Execute(file, api); err != nil {
		return err
	}

	return file.FormatCode()
}
Esempio n. 9
0
// generateUserTypes iterates through the user types and generates the data structures and
// marshaling code.
func (g *Generator) generateUserTypes() error {
	utFile := filepath.Join(g.OutDir, "user_types.go")
	utWr, err := NewUserTypesWriter(utFile)
	if err != nil {
		panic(err) // bug
	}
	title := fmt.Sprintf("%s: Application User Types", g.API.Context())
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport("fmt"),
		codegen.SimpleImport("time"),
		codegen.SimpleImport("unicode/utf8"),
		codegen.SimpleImport("github.com/goadesign/goa"),
		codegen.NewImport("uuid", "github.com/satori/go.uuid"),
	}
	utWr.WriteHeader(title, g.Target, imports)
	err = g.API.IterateUserTypes(func(t *design.UserTypeDefinition) error {
		return utWr.Execute(t)
	})
	g.genfiles = append(g.genfiles, utFile)
	if err != nil {
		return err
	}
	return utWr.FormatCode()
}
Esempio n. 10
0
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()
}
Esempio n. 11
0
// 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/goadesign/goa"),
			codegen.SimpleImport("github.com/goadesign/middleware"),
			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
}
Esempio n. 12
0
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()
}
Esempio n. 13
0
func (g *Generator) generateCommands(commandsFile string, clientPkg string, funcs template.FuncMap) error {
	file, err := codegen.SourceFileFor(commandsFile)
	if err != nil {
		return err
	}

	funcs["defaultRouteParams"] = defaultRouteParams
	funcs["defaultRouteTemplate"] = defaultRouteTemplate
	funcs["joinNames"] = joinNames
	funcs["joinRouteParams"] = joinRouteParams
	funcs["routes"] = routes
	funcs["flagType"] = flagType
	funcs["cmdFieldType"] = cmdFieldTypeString
	funcs["formatExample"] = formatExample
	funcs["shouldAddExample"] = shouldAddExample

	commandTypesTmpl := template.Must(template.New("commandTypes").Funcs(funcs).Parse(commandTypesTmpl))
	commandsTmpl := template.Must(template.New("commands").Funcs(funcs).Parse(commandsTmpl))
	commandsTmplWS := template.Must(template.New("commandsWS").Funcs(funcs).Parse(commandsTmplWS))
	downloadCommandTmpl := template.Must(template.New("download").Funcs(funcs).Parse(downloadCommandTmpl))
	registerTmpl := template.Must(template.New("register").Funcs(funcs).Parse(registerTmpl))

	imports := []*codegen.ImportSpec{
		codegen.SimpleImport("encoding/json"),
		codegen.SimpleImport("fmt"),
		codegen.SimpleImport("log"),
		codegen.SimpleImport("net/url"),
		codegen.SimpleImport("os"),
		codegen.SimpleImport("path"),
		codegen.SimpleImport("path/filepath"),
		codegen.SimpleImport("strings"),
		codegen.SimpleImport("strconv"),
		codegen.SimpleImport("time"),
		codegen.SimpleImport("github.com/goadesign/goa"),
		codegen.SimpleImport("github.com/spf13/cobra"),
		codegen.SimpleImport(clientPkg),
		codegen.SimpleImport("golang.org/x/net/context"),
		codegen.SimpleImport("golang.org/x/net/websocket"),
		codegen.NewImport("uuid", "github.com/goadesign/goa/uuid"),
	}
	if len(g.API.Resources) > 0 {
		imports = append(imports, codegen.NewImport("goaclient", "github.com/goadesign/goa/client"))
	}
	if err := file.WriteHeader("", "cli", imports); err != nil {
		return err
	}
	g.genfiles = append(g.genfiles, commandsFile)

	file.Write([]byte("type (\n"))
	var fs []*design.FileServerDefinition
	if err := g.API.IterateResources(func(res *design.ResourceDefinition) error {
		fs = append(fs, res.FileServers...)
		return res.IterateActions(func(action *design.ActionDefinition) error {
			return commandTypesTmpl.Execute(file, action)
		})
	}); err != nil {
		return err
	}
	if len(fs) > 0 {
		file.Write([]byte(downloadCommandType))
	}
	file.Write([]byte(")\n\n"))

	actions := make(map[string][]*design.ActionDefinition)
	hasDownloads := false
	g.API.IterateResources(func(res *design.ResourceDefinition) error {
		if len(res.FileServers) > 0 {
			hasDownloads = true
		}
		return res.IterateActions(func(action *design.ActionDefinition) error {
			name := codegen.Goify(action.Name, false)
			if as, ok := actions[name]; ok {
				actions[name] = append(as, action)
			} else {
				actions[name] = []*design.ActionDefinition{action}
			}
			return nil
		})
	})
	data := struct {
		Actions      map[string][]*design.ActionDefinition
		Package      string
		HasDownloads bool
	}{
		Actions:      actions,
		Package:      g.Target,
		HasDownloads: hasDownloads,
	}
	if err := file.ExecuteTemplate("registerCmds", registerCmdsT, funcs, data); err != nil {
		return err
	}

	var fsdata []map[string]interface{}
	g.API.IterateResources(func(res *design.ResourceDefinition) error {
		if res.FileServers != nil {
			res.IterateFileServers(func(fs *design.FileServerDefinition) error {
				wcs := design.ExtractWildcards(fs.RequestPath)
				isDir := len(wcs) > 0
				var reqDir, filename string
				if isDir {
					reqDir, _ = path.Split(fs.RequestPath)
				} else {
					_, filename = filepath.Split(fs.FilePath)
				}
				fsdata = append(fsdata, map[string]interface{}{
					"IsDir":       isDir,
					"RequestPath": fs.RequestPath,
					"FilePath":    fs.FilePath,
					"FileName":    filename,
					"Name":        g.fileServerMethod(fs),
					"RequestDir":  reqDir,
				})
				return nil
			})
		}
		return nil
	})
	if fsdata != nil {
		data := struct {
			Package     string
			FileServers []map[string]interface{}
		}{
			Package:     g.Target,
			FileServers: fsdata,
		}
		if err := downloadCommandTmpl.Execute(file, data); err != nil {
			return err
		}
	}
	err = g.API.IterateResources(func(res *design.ResourceDefinition) error {
		return res.IterateActions(func(action *design.ActionDefinition) error {
			data := map[string]interface{}{
				"Action":          action,
				"Resource":        action.Parent,
				"Package":         g.Target,
				"HasMultiContent": len(g.API.Consumes) > 1,
			}
			var err error
			if action.WebSocket() {
				err = commandsTmplWS.Execute(file, data)
			} else {
				err = commandsTmpl.Execute(file, data)

			}
			if err != nil {
				return err
			}
			err = registerTmpl.Execute(file, data)
			return err
		})
	})
	if err != nil {
		return err
	}

	return file.FormatCode()
}
Esempio n. 14
0
func (g *Generator) generateMain(mainFile string, clientPkg, cliPkg string, funcs template.FuncMap) error {
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport("encoding/json"),
		codegen.SimpleImport("fmt"),
		codegen.SimpleImport("io/ioutil"),
		codegen.SimpleImport("net/http"),
		codegen.SimpleImport("os"),
		codegen.SimpleImport("time"),
		codegen.SimpleImport(clientPkg),
		codegen.SimpleImport(cliPkg),
		codegen.SimpleImport("github.com/spf13/cobra"),
		codegen.NewImport("goaclient", "github.com/goadesign/goa/client"),
		codegen.NewImport("uuid", "github.com/goadesign/goa/uuid"),
	}

	funcs["defaultRouteParams"] = defaultRouteParams
	funcs["defaultRouteTemplate"] = defaultRouteTemplate
	funcs["joinNames"] = joinNames
	funcs["signerSignature"] = signerSignature
	funcs["signerArgs"] = signerArgs

	file, err := codegen.SourceFileFor(mainFile)
	if err != nil {
		return err
	}
	if err := file.WriteHeader("", "main", imports); err != nil {
		return err
	}
	g.genfiles = append(g.genfiles, mainFile)
	version := design.Design.Version
	if version == "" {
		version = "0"
	}

	hasSigners := false
	hasBasicAuthSigners := false
	hasAPIKeySigners := false
	hasTokenSigners := false
	for _, s := range g.API.SecuritySchemes {
		if signerType(s) != "" {
			hasSigners = true
			switch s.Type {
			case "basic":
				hasBasicAuthSigners = true
			case "apiKey":
				hasAPIKeySigners = true
			case "jwt", "oauth2":
				hasTokenSigners = true
			}
		}
	}

	data := struct {
		API                 *design.APIDefinition
		Version             string
		Package             string
		HasSigners          bool
		HasBasicAuthSigners bool
		HasAPIKeySigners    bool
		HasTokenSigners     bool
	}{
		API:                 g.API,
		Version:             version,
		Package:             g.Target,
		HasSigners:          hasSigners,
		HasBasicAuthSigners: hasBasicAuthSigners,
		HasAPIKeySigners:    hasAPIKeySigners,
		HasTokenSigners:     hasTokenSigners,
	}
	if err := file.ExecuteTemplate("main", mainTmpl, funcs, data); err != nil {
		return err
	}

	return file.FormatCode()
}
Esempio n. 15
0
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()
	})
}
Esempio n. 16
0
func (g *Generator) generateCommands(commandsFile string, clientPkg string, funcs template.FuncMap, api *design.APIDefinition) error {
	file, err := codegen.SourceFileFor(commandsFile)
	if err != nil {
		return err
	}
	commandTypesTmpl := template.Must(template.New("commandTypes").Funcs(funcs).Parse(commandTypesTmpl))
	commandsTmpl := template.Must(template.New("commands").Funcs(funcs).Parse(commandsTmpl))
	commandsTmplWS := template.Must(template.New("commandsWS").Funcs(funcs).Parse(commandsTmplWS))
	registerTmpl := template.Must(template.New("register").Funcs(funcs).Parse(registerTmpl))

	imports := []*codegen.ImportSpec{
		codegen.SimpleImport("encoding/json"),
		codegen.SimpleImport("fmt"),
		codegen.SimpleImport("log"),
		codegen.SimpleImport("os"),
		codegen.SimpleImport("time"),
		codegen.SimpleImport("github.com/goadesign/goa"),
		codegen.SimpleImport("github.com/spf13/cobra"),
		codegen.SimpleImport(clientPkg),
		codegen.SimpleImport("golang.org/x/net/context"),
		codegen.SimpleImport("golang.org/x/net/websocket"),
	}
	if len(api.Resources) > 0 {
		imports = append(imports, codegen.NewImport("goaclient", "github.com/goadesign/goa/client"))
	}
	if err := file.WriteHeader("", "main", imports); err != nil {
		return err
	}
	g.genfiles = append(g.genfiles, commandsFile)

	file.Write([]byte("type (\n"))
	if err := api.IterateResources(func(res *design.ResourceDefinition) error {
		return res.IterateActions(func(action *design.ActionDefinition) error {
			return commandTypesTmpl.Execute(file, action)
		})
	}); err != nil {
		return err
	}
	file.Write([]byte(")\n\n"))

	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,
			}
			var err error
			if action.WebSocket() {
				err = commandsTmplWS.Execute(file, data)
			} else {
				err = commandsTmpl.Execute(file, data)

			}
			if err != nil {
				return err
			}
			err = registerTmpl.Execute(file, data)
			return err
		})
	})
	if err != nil {
		return err
	}

	return file.FormatCode()
}
Esempio n. 17
0
func (g *Generator) generateClientResources(clientPkg string, funcs template.FuncMap, api *design.APIDefinition) error {
	userTypeTmpl := template.Must(template.New("userType").Funcs(funcs).Parse(userTypeTmpl))
	typeDecodeTmpl := template.Must(template.New("typeDecode").Funcs(funcs).Parse(typeDecodeTmpl))

	err := api.IterateResources(func(res *design.ResourceDefinition) error {
		return g.generateResourceClient(res, funcs)
	})
	if err != nil {
		return err
	}
	types := make(map[string]*design.UserTypeDefinition)
	for _, res := range api.Resources {
		for n, ut := range res.UserTypes() {
			types[n] = ut
		}
	}
	filename := filepath.Join(codegen.OutputDir, typesFileName+".go")
	file, err := codegen.SourceFileFor(filename)
	if err != nil {
		return err
	}
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport("github.com/goadesign/goa"),
		codegen.SimpleImport("fmt"),
		codegen.SimpleImport("io"),
		codegen.SimpleImport("time"),
		codegen.NewImport("uuid", "github.com/satori/go.uuid"),
	}
	if err := file.WriteHeader("User Types", "client", imports); err != nil {
		return err
	}
	g.genfiles = append(g.genfiles, filename)

	// Generate user and media types used by action payloads and parameters
	err = api.IterateUserTypes(func(userType *design.UserTypeDefinition) error {
		if _, ok := g.generatedTypes[userType.TypeName]; ok {
			return nil
		}
		if _, ok := types[userType.TypeName]; ok {
			g.generatedTypes[userType.TypeName] = true
			return userTypeTmpl.Execute(file, userType)
		}
		return nil
	})
	if err != nil {
		return err
	}

	// Generate media types used by action responses and their load helpers
	err = api.IterateResources(func(res *design.ResourceDefinition) error {
		return res.IterateActions(func(a *design.ActionDefinition) error {
			return a.IterateResponses(func(r *design.ResponseDefinition) error {
				if mt := api.MediaTypeWithIdentifier(r.MediaType); mt != nil {
					if _, ok := g.generatedTypes[mt.TypeName]; !ok {
						g.generatedTypes[mt.TypeName] = true
						if !mt.IsBuiltIn() {
							if err := userTypeTmpl.Execute(file, mt); err != nil {
								return err
							}
						}
						typeName := mt.TypeName
						if mt.IsBuiltIn() {
							elems := strings.Split(typeName, ".")
							typeName = elems[len(elems)-1]
						}
						if err := typeDecodeTmpl.Execute(file, mt); err != nil {
							return err
						}
					}
				}
				return nil
			})
		})
	})
	if err != nil {
		return err
	}

	// Generate media types used in payloads but not in responses
	err = api.IterateMediaTypes(func(mediaType *design.MediaTypeDefinition) error {
		if mediaType.IsBuiltIn() {
			return nil
		}
		if _, ok := g.generatedTypes[mediaType.TypeName]; ok {
			return nil
		}
		if _, ok := types[mediaType.TypeName]; ok {
			g.generatedTypes[mediaType.TypeName] = true
			return userTypeTmpl.Execute(file, mediaType)
		}
		return nil
	})
	if err != nil {
		return err
	}

	return file.FormatCode()
}
Esempio n. 18
0
func (g *Generator) generateClient(clientFile string, clientPkg string, funcs template.FuncMap) error {
	file, err := codegen.SourceFileFor(clientFile)
	if err != nil {
		return err
	}
	clientTmpl := template.Must(template.New("client").Funcs(funcs).Parse(clientTmpl))

	// Compute list of encoders and decoders
	encoders, err := genapp.BuildEncoders(g.API.Produces, true)
	if err != nil {
		return err
	}
	decoders, err := genapp.BuildEncoders(g.API.Consumes, false)
	if err != nil {
		return err
	}
	im := make(map[string]bool)
	for _, data := range encoders {
		im[data.PackagePath] = true
	}
	for _, data := range decoders {
		im[data.PackagePath] = true
	}
	var packagePaths []string
	for packagePath := range im {
		if packagePath != "github.com/goadesign/goa" {
			packagePaths = append(packagePaths, packagePath)
		}
	}
	sort.Strings(packagePaths)

	// Setup codegen
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport("net/http"),
		codegen.SimpleImport("github.com/goadesign/goa"),
		codegen.NewImport("goaclient", "github.com/goadesign/goa/client"),
		codegen.NewImport("uuid", "github.com/goadesign/goa/uuid"),
	}
	for _, packagePath := range packagePaths {
		imports = append(imports, codegen.SimpleImport(packagePath))
	}
	if err := file.WriteHeader("", g.Target, imports); err != nil {
		return err
	}
	g.genfiles = append(g.genfiles, clientFile)

	// Generate
	data := struct {
		API      *design.APIDefinition
		Encoders []*genapp.EncoderTemplateData
		Decoders []*genapp.EncoderTemplateData
	}{
		API:      g.API,
		Encoders: encoders,
		Decoders: decoders,
	}
	if err := clientTmpl.Execute(file, data); err != nil {
		return err
	}

	return file.FormatCode()
}