Example #1
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
}
Example #2
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()
		}
	}()

	// Make tool directory
	toolDir, err := makeToolDir(g, api.Name)
	if err != nil {
		return
	}

	funcs := template.FuncMap{
		"goify":        codegen.Goify,
		"gotypedef":    codegen.GoTypeDef,
		"gotyperefext": goTypeRefExt,
		"nativeType":   codegen.GoNativeType,
		"joinNames":    joinNames,
		"join":         join,
		"toString":     toString,
		"tempvar":      codegen.Tempvar,
		"title":        strings.Title,
		"flagType":     flagType,
		"enumOptions":  enumOptions,
		"defaultPath":  defaultPath,
	}
	gopath := filepath.SplitList(os.Getenv("GOPATH"))[0]
	clientPkg, err := filepath.Rel(gopath, codegen.OutputDir)
	if err != nil {
		return
	}
	clientPkg = strings.TrimPrefix(filepath.ToSlash(clientPkg), "src/")
	arrayToStringTmpl = template.Must(template.New("client").Funcs(funcs).Parse(arrayToStringT))

	// Generate client/client-cli/main.go
	if err = g.generateMain(filepath.Join(toolDir, "main.go"), clientPkg, funcs, api); err != nil {
		return
	}

	// Generate client/client-cli/commands.go
	if err = g.generateCommands(filepath.Join(toolDir, "commands.go"), clientPkg, funcs, api); err != nil {
		return
	}

	// Generate client/client.go
	if err = g.generateClient(filepath.Join(codegen.OutputDir, "client.go"), clientPkg, funcs, api); err != nil {
		return
	}

	// Generate client/$res.go
	if err = g.generateClientResources(clientPkg, funcs, api); err != nil {
		return
	}

	return g.genfiles, nil
}
Example #3
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()
		}
	}()

	if Host == "" {
		Host = api.Host
	}
	if Host == "" {
		return nil, fmt.Errorf("missing host value, specify it with --host")
	}

	if err = makeOutputDir(g); err != nil {
		return
	}

	funcs := template.FuncMap{
		"title":   strings.Title,
		"join":    strings.Join,
		"toLower": strings.ToLower,
		"params":  params,
	}

	// Generate client.js
	exampleAction, err := g.generateJS(filepath.Join(codegen.OutputDir, "client.js"), funcs, api)
	if err != nil {
		return
	}

	if exampleAction != nil {
		// Generate index.html
		if err = g.generateIndexHTML(filepath.Join(codegen.OutputDir, "index.html"), api, exampleAction, funcs); err != nil {
			return
		}

		// Generate axios.html
		if err = g.generateAxiosJS(); err != nil {
			return
		}

		// Generate example
		if err = g.generateExample(api); err != nil {
			return
		}
	}

	return g.genfiles, nil
}
Example #4
0
File: main.go Project: tylerb/goa
func main() {
	var (
		files            []string
		err              error
		terminatedByUser bool
	)

	// First check for the presence of `goimports`.
	_, err = exec.LookPath("goimports")
	if err != nil {
		fmt.Fprintln(os.Stderr, "Command goimports not found. Install with:\ngo get golang.org/x/tools/cmd/goimports")
		os.Exit(1)
	}

	// Now proceed with code generation
	cleanup := func() {
		for _, f := range files {
			os.RemoveAll(f)
		}
	}

	go utils.Catch(nil, func() {
		terminatedByUser = true
	})

	files, err = command().Run()

	if terminatedByUser {
		cleanup()
		return
	}

	if err != nil {
		cleanup()
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(1)
	}

	rels := make([]string, len(files))
	cwd, err := os.Getwd()
	for i, f := range files {
		r, err := filepath.Rel(cwd, f)
		if err == nil {
			rels[i] = r
		} else {
			rels[i] = f
		}
	}
	fmt.Println(strings.Join(rels, "\n"))
}
Example #5
0
// Generate the application code, implement codegen.Generator.
func (g *Generator) Generate(api *design.APIDefinition) (_ []string, err error) {
	if api == nil {
		return nil, fmt.Errorf("missing API definition, make sure design.Design is properly initialized")
	}

	go utils.Catch(nil, func() { g.Cleanup() })

	defer func() {
		if err != nil {
			g.Cleanup()
		}
	}()

	outdir := AppOutputDir()
	err = api.IterateVersions(func(v *design.APIVersionDefinition) error {
		verdir := outdir
		if v.Version != "" {
			verdir = filepath.Join(verdir, codegen.VersionPackage(v.Version))
		}
		if err := os.MkdirAll(verdir, 0755); err != nil {
			return err
		}
		if err := g.generateContexts(verdir, api, v); err != nil {
			return err
		}
		if err := g.generateControllers(verdir, v); err != nil {
			return err
		}
		if err := g.generateHrefs(verdir, v); err != nil {
			return err
		}
		if err := g.generateMediaTypes(verdir, v); err != nil {
			return err
		}
		if err := g.generateUserTypes(verdir, v); err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return nil, err
	}

	return g.genfiles, nil
}
Example #6
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
}
Example #7
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
}
Example #8
0
// Generate the application code, implement codegen.Generator.
func (g *Generator) Generate(api *design.APIDefinition) (_ []string, err error) {
	go utils.Catch(nil, func() { g.Cleanup() })

	defer func() {
		if err != nil {
			g.Cleanup()
		}
	}()

	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("fmt"),
		codegen.SimpleImport("strconv"),
		codegen.SimpleImport("github.com/raphael/goa"),
	}
	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),
				API:          api,
			}
			return g.ContextsWriter.Execute(&ctxData)
		})
	})
	g.genfiles = append(g.genfiles, g.contextsFilename)
	if err != nil {
		return
	}
	if err = g.ContextsWriter.FormatCode(); err != nil {
		return
	}

	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 {
		return
	}
	if err = g.ControllersWriter.FormatCode(); err != nil {
		return
	}

	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 := api.MediaTypeWithIdentifier(r.MediaType)
		var identifier string
		if m != nil {
			identifier = m.Identifier
		} else {
			identifier = "plain/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 {
		return
	}
	if err = g.ResourcesWriter.FormatCode(); err != nil {
		return
	}

	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 {
		return
	}
	if err = g.MediaTypesWriter.FormatCode(); err != nil {
		return
	}

	title = fmt.Sprintf("%s: Application User Types", api.Name)
	imports = []*codegen.ImportSpec{
		codegen.SimpleImport("github.com/raphael/goa"),
	}
	g.UserTypesWriter.WriteHeader(title, TargetPackage, imports)
	err = api.IterateUserTypes(func(t *design.UserTypeDefinition) error {
		return g.UserTypesWriter.Execute(t)
	})
	g.genfiles = append(g.genfiles, g.userTypesFilename)
	if err != nil {
		return
	}
	if err = g.UserTypesWriter.FormatCode(); err != nil {
		return
	}

	return g.genfiles, nil
}
Example #9
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
}