| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- // +build codegen
- package api
- import (
- "encoding/json"
- "fmt"
- "os"
- "path/filepath"
- "sort"
- "strings"
- )
- // APIs provides a set of API models loaded by API package name.
- type APIs map[string]*API
- // LoadAPIs loads the API model files from disk returning the map of API
- // package. Returns error if multiple API model resolve to the same package
- // name.
- func LoadAPIs(modelPaths []string, baseImport string) (APIs, error) {
- apis := APIs{}
- for _, modelPath := range modelPaths {
- a, err := loadAPI(modelPath, baseImport)
- if err != nil {
- return nil, fmt.Errorf("failed to load API, %v, %v", modelPath, err)
- }
- importPath := a.ImportPath()
- if _, ok := apis[importPath]; ok {
- return nil, fmt.Errorf(
- "package names must be unique attempted to load %v twice. Second model file: %v",
- importPath, modelPath)
- }
- apis[importPath] = a
- }
- return apis, nil
- }
- func loadAPI(modelPath, baseImport string) (*API, error) {
- a := &API{
- BaseImportPath: baseImport,
- BaseCrosslinkURL: "https://docs.aws.amazon.com",
- }
- modelFile := filepath.Base(modelPath)
- modelDir := filepath.Dir(modelPath)
- err := attachModelFiles(modelDir,
- modelLoader{modelFile, a.Attach, true},
- modelLoader{"docs-2.json", a.AttachDocs, false},
- modelLoader{"paginators-1.json", a.AttachPaginators, false},
- modelLoader{"waiters-2.json", a.AttachWaiters, false},
- modelLoader{"examples-1.json", a.AttachExamples, false},
- modelLoader{"smoke.json", a.AttachSmokeTests, false},
- )
- if err != nil {
- return nil, err
- }
- a.Setup()
- return a, nil
- }
- type modelLoader struct {
- Filename string
- Loader func(string)
- Required bool
- }
- func attachModelFiles(modelPath string, modelFiles ...modelLoader) error {
- for _, m := range modelFiles {
- filepath := filepath.Join(modelPath, m.Filename)
- _, err := os.Stat(filepath)
- if os.IsNotExist(err) && !m.Required {
- continue
- } else if err != nil {
- return fmt.Errorf("failed to load model file %v, %v", m.Filename, err)
- }
- m.Loader(filepath)
- }
- return nil
- }
- // ExpandModelGlobPath returns a slice of model paths expanded from the glob
- // pattern passed in. Returns the path of the model file to be loaded. Includes
- // all versions of a service model.
- //
- // e.g:
- // models/apis/*/*/api-2.json
- //
- // Or with specific model file:
- // models/apis/service/version/api-2.json
- func ExpandModelGlobPath(globs ...string) ([]string, error) {
- modelPaths := []string{}
- for _, g := range globs {
- filepaths, err := filepath.Glob(g)
- if err != nil {
- return nil, err
- }
- for _, p := range filepaths {
- modelPaths = append(modelPaths, p)
- }
- }
- return modelPaths, nil
- }
- // TrimModelServiceVersions sorts the model paths by service version then
- // returns recent model versions, and model version excluded.
- //
- // Uses the third from last path element to determine unique service. Only one
- // service version will be included.
- //
- // models/apis/service/version/api-2.json
- func TrimModelServiceVersions(modelPaths []string) (include, exclude []string) {
- sort.Strings(modelPaths)
- // Remove old API versions from list
- m := map[string]struct{}{}
- for i := len(modelPaths) - 1; i >= 0; i-- {
- // service name is 2nd-to-last component
- parts := strings.Split(modelPaths[i], string(filepath.Separator))
- svc := parts[len(parts)-3]
- if _, ok := m[svc]; ok {
- // Removed unused service version
- exclude = append(exclude, modelPaths[i])
- continue
- }
- include = append(include, modelPaths[i])
- m[svc] = struct{}{}
- }
- return include, exclude
- }
- // Attach opens a file by name, and unmarshal its JSON data.
- // Will proceed to setup the API if not already done so.
- func (a *API) Attach(filename string) {
- a.path = filepath.Dir(filename)
- f, err := os.Open(filename)
- defer f.Close()
- if err != nil {
- panic(err)
- }
- if err := json.NewDecoder(f).Decode(a); err != nil {
- panic(fmt.Errorf("failed to decode %s, err: %v", filename, err))
- }
- }
- // AttachString will unmarshal a raw JSON string, and setup the
- // API if not already done so.
- func (a *API) AttachString(str string) {
- json.Unmarshal([]byte(str), a)
- if !a.initialized {
- a.Setup()
- }
- }
- // Setup initializes the API.
- func (a *API) Setup() {
- a.setServiceAliaseName()
- a.setMetadataEndpointsKey()
- a.writeShapeNames()
- a.resolveReferences()
- if !a.NoRemoveUnusedShapes {
- a.removeUnusedShapes()
- }
- a.fixStutterNames()
- a.renameExportable()
- a.applyShapeNameAliases()
- a.createInputOutputShapes()
- a.renameAPIPayloadShapes()
- a.renameCollidingFields()
- a.updateTopLevelShapeReferences()
- a.suppressHTTP2EventStreams()
- a.setupEventStreams()
- a.findEndpointDiscoveryOp()
- a.customizationPasses()
- if !a.NoRemoveUnusedShapes {
- a.removeUnusedShapes()
- }
- if !a.NoValidataShapeMethods {
- a.addShapeValidations()
- }
- a.initialized = true
- }
|