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.SimpleImport("github.com/goadesign/goa/dslengine"), 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 } }
// Generate compiles and runs the generator and returns the generated filenames. func (m *Generator) Generate() ([]string, error) { if codegen.OutputDir == "" { return nil, fmt.Errorf("missing output directory specification") } if codegen.DesignPackagePath == "" { return nil, fmt.Errorf("missing design package path specification") } if os.Getenv("GOPATH") == "" { return nil, fmt.Errorf("GOPATH not set") } // Create output directory if err := os.MkdirAll(codegen.OutputDir, 0755); err != nil { return nil, err } // Create temporary workspace used for generation w, err := codegen.NewWorkspace("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 { w.Delete() } }() if codegen.Debug { fmt.Printf("goagen source dir: %s\n", w.Path) } // Figure out design package name from its path path, err := codegen.PackageSourcePath(codegen.DesignPackagePath) if err != nil { return nil, err } pkgName, err := codegen.PackageName(path) if err != nil { return nil, err } // Generate tool source code. p, err := w.NewPackage(pkgName) if err != nil { return nil, err } m.generateToolSourceCode(p) // Compile and run generated tool. genbin, err := p.Compile("goagen") if err != nil { return nil, err } return m.spawn(genbin) }
func runGen(c *cobra.Command) ([]string, error) { pkgPath := c.Flag("pkg-path").Value.String() pkgSrcPath, err := codegen.PackageSourcePath(pkgPath) if err != nil { return nil, fmt.Errorf("invalid plugin package import path: %s", err) } pkgName, err := codegen.PackageName(pkgSrcPath) if err != nil { return nil, fmt.Errorf("invalid plugin package import path: %s", err) } return generate(pkgName, pkgPath, c) }
func run(pkg string, c *cobra.Command) ([]string, error) { pkgPath := fmt.Sprintf("github.com/goadesign/goa/goagen/gen_%s", pkg[3:]) pkgSrcPath, err := codegen.PackageSourcePath(pkgPath) if err != nil { return nil, fmt.Errorf("invalid plugin package import path: %s", err) } pkgName, err := codegen.PackageName(pkgSrcPath) if err != nil { return nil, fmt.Errorf("invalid package import path: %s", err) } return generate(pkgName, pkgPath, c) }
// BuildEncoders builds the template data needed to render the given encoding definitions. // This extra map is needed to handle the case where a single encoding definition maps to multiple // encoding packages. The data is indexed by mime type. func BuildEncoders(info []*design.EncodingDefinition, encoder bool) ([]*EncoderTemplateData, error) { if len(info) == 0 { return nil, nil } // knownStdPackages lists the stdlib packages known by BuildEncoders var knownStdPackages = map[string]string{ "encoding/json": "json", "encoding/xml": "xml", "encoding/gob": "gob", } encs := normalizeEncodingDefinitions(info) data := make([]*EncoderTemplateData, len(encs)) defaultMediaType := info[0].MIMETypes[0] for i, enc := range encs { var pkgName string if name, ok := knownStdPackages[enc.PackagePath]; ok { pkgName = name } else { srcPath, err := codegen.PackageSourcePath(enc.PackagePath) if err != nil { return nil, fmt.Errorf("failed to locate package source of %s (%s)", enc.PackagePath, err) } pkgName, err = codegen.PackageName(srcPath) if err != nil { return nil, fmt.Errorf("failed to load package %s (%s)", enc.PackagePath, err) } } isDefault := false for _, m := range enc.MIMETypes { if m == defaultMediaType { isDefault = true } } d := &EncoderTemplateData{ PackagePath: enc.PackagePath, PackageName: pkgName, Function: enc.Function, MIMETypes: enc.MIMETypes, Default: isDefault, } data[i] = d } return data, nil }
// BuildEncoderMap builds the template data needed to render the given encoding definitions. // This extra map is needed to handle the case where a single encoding definition maps to multiple // encoding packages. The data is indexed by encoder Go package path. func BuildEncoderMap(info []*design.EncodingDefinition, encoder bool) (map[string]*EncoderTemplateData, error) { if len(info) == 0 { return nil, nil } packages := make(map[string]map[string]bool) for _, enc := range info { supporting := enc.SupportingPackages() if supporting == nil { // shouldn't happen - DSL validation shouldn't allow it - be graceful continue } for ppath, mimeTypes := range supporting { if _, ok := packages[ppath]; !ok { packages[ppath] = make(map[string]bool) } for _, m := range mimeTypes { packages[ppath][m] = true } } } data := make(map[string]*EncoderTemplateData, len(packages)) if len(info[0].MIMETypes) == 0 { return nil, fmt.Errorf("No mime type associated with encoding info for package %s", info[0].PackagePath) } defaultMediaType := info[0].MIMETypes[0] for p, ms := range packages { pkgName := "goa" if !design.IsGoaEncoder(p) { srcPath, err := codegen.PackageSourcePath(p) if err == nil { pkgName, err = codegen.PackageName(srcPath) } if err != nil { return nil, fmt.Errorf("failed to load package %s (%s)", p, err) } } mimeTypes := make([]string, len(ms)) isDefault := false i := 0 for m := range ms { if m == defaultMediaType { isDefault = true } mimeTypes[i] = m i++ } first := mimeTypes[0] sort.Strings(mimeTypes) var factory string if encoder { if !design.IsGoaEncoder(p) { factory = "EncoderFactory" } else { factory = design.KnownEncoders[first][1] } } else { if !design.IsGoaEncoder(p) { factory = "DecoderFactory" } else { factory = design.KnownEncoders[first][2] } } d := &EncoderTemplateData{ PackagePath: p, PackageName: pkgName, Factory: factory, MIMETypes: mimeTypes, Default: isDefault, } data[p] = d } return data, nil }
// Generate compiles and runs the generator and returns the generated filenames. func (m *Generator) Generate() ([]string, error) { if codegen.OutputDir == "" { return nil, fmt.Errorf("missing output directory specification") } if codegen.DesignPackagePath == "" { return nil, fmt.Errorf("missing design package path specification") } if os.Getenv("GOPATH") == "" { return nil, fmt.Errorf("GOPATH not set") } // Create output directory if err := os.MkdirAll(codegen.OutputDir, 0755); err != nil { return nil, err } // Create temporary workspace used for generation wd, err := os.Getwd() if err != nil { return nil, err } tmpDir, err := ioutil.TempDir(wd, "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(tmpDir) } }() if codegen.Debug { fmt.Printf("** Code generator source dir: %s\n", tmpDir) } // Figure out design package name from its path path, err := codegen.PackageSourcePath(codegen.DesignPackagePath) if err != nil { return nil, err } pkgName, err := codegen.PackageName(path) if err != nil { return nil, err } // Generate tool source code. pkgPath := filepath.Join(tmpDir, pkgName) p, err := codegen.PackageFor(pkgPath) if err != nil { return nil, err } m.generateToolSourceCode(p) // Compile and run generated tool. if codegen.Debug { fmt.Printf("** Compiling with:\n%s", strings.Join(os.Environ(), "\n")) } genbin, err := p.Compile("goagen") if err != nil { return nil, err } return m.spawn(genbin) }