Beispiel #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/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)
	}
}
Beispiel #2
0
// 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()
}
Beispiel #3
0
// 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()
}
Beispiel #4
0
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()
	})
}
Beispiel #5
0
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)
	}
}
Beispiel #6
0
// 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
}
Beispiel #7
0
// 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()
}
Beispiel #8
0
// 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()
}
Beispiel #9
0
// 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()
}
Beispiel #10
0
// 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()
}
Beispiel #11
0
// 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()
}
Beispiel #12
0
// 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()
}
Beispiel #13
0
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()
}
Beispiel #14
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()
		}
	}()

	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
}
Beispiel #15
0
// 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()
}
Beispiel #16
0
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()
}
Beispiel #17
0
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()
}
Beispiel #18
0
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()
}
Beispiel #19
0
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()
}
Beispiel #20
0
// 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
}
Beispiel #21
0
// 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
}
Beispiel #22
0
// 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
}
Beispiel #23
0
// 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)
}
Beispiel #24
0
// 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
}
Beispiel #25
0
		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
Beispiel #26
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,
		"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
}
Beispiel #27
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/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
}