Example #1
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("net/http"),
		codegen.SimpleImport("golang.org/x/net/context"),
		codegen.SimpleImport("github.com/goadesign/goa"),
	}
	if !version.IsDefault() {
		appPkg, err := AppPackagePath()
		if err != nil {
			return err
		}
		imports = append(imports, codegen.SimpleImport(appPkg))
	}
	encoderMap, err := BuildEncoderMap(version.Produces, true)
	if err != nil {
		return err
	}
	decoderMap, err := BuildEncoderMap(version.Consumes, false)
	if err != nil {
		return err
	}
	encoderImports := make(map[string]bool)
	for _, data := range encoderMap {
		encoderImports[data.PackagePath] = true
	}
	for _, data := range decoderMap {
		encoderImports[data.PackagePath] = true
	}
	for packagePath := range encoderImports {
		if !design.IsGoaEncoder(packagePath) {
			imports = append(imports, codegen.SimpleImport(packagePath))
		}
	}
	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{API: design.Design, 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.EncoderMap = encoderMap
			data.DecoderMap = decoderMap
			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()
}
Example #2
0
// 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
}