blob: 1f85b650e81721718d94d4c96ec6f7e52bf99378 [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001// Copyright 2017 Google Inc. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package compiler
16
17import (
18 "bytes"
19 "fmt"
20 "os/exec"
21
22 "strings"
23
24 "errors"
25
26 "github.com/golang/protobuf/proto"
27 "github.com/golang/protobuf/ptypes/any"
28 ext_plugin "github.com/googleapis/gnostic/extensions"
29 yaml "gopkg.in/yaml.v2"
30)
31
32// ExtensionHandler describes a binary that is called by the compiler to handle specification extensions.
33type ExtensionHandler struct {
34 Name string
35}
36
37// HandleExtension calls a binary extension handler.
38func HandleExtension(context *Context, in interface{}, extensionName string) (bool, *any.Any, error) {
39 handled := false
40 var errFromPlugin error
41 var outFromPlugin *any.Any
42
43 if context != nil && context.ExtensionHandlers != nil && len(*(context.ExtensionHandlers)) != 0 {
44 for _, customAnyProtoGenerator := range *(context.ExtensionHandlers) {
45 outFromPlugin, errFromPlugin = customAnyProtoGenerator.handle(in, extensionName)
46 if outFromPlugin == nil {
47 continue
48 } else {
49 handled = true
50 break
51 }
52 }
53 }
54 return handled, outFromPlugin, errFromPlugin
55}
56
57func (extensionHandlers *ExtensionHandler) handle(in interface{}, extensionName string) (*any.Any, error) {
58 if extensionHandlers.Name != "" {
59 binary, _ := yaml.Marshal(in)
60
61 request := &ext_plugin.ExtensionHandlerRequest{}
62
63 version := &ext_plugin.Version{}
64 version.Major = 0
65 version.Minor = 1
66 version.Patch = 0
67 request.CompilerVersion = version
68
69 request.Wrapper = &ext_plugin.Wrapper{}
70
71 request.Wrapper.Version = "v2"
72 request.Wrapper.Yaml = string(binary)
73 request.Wrapper.ExtensionName = extensionName
74
75 requestBytes, _ := proto.Marshal(request)
76 cmd := exec.Command(extensionHandlers.Name)
77 cmd.Stdin = bytes.NewReader(requestBytes)
78 output, err := cmd.Output()
79
80 if err != nil {
81 fmt.Printf("Error: %+v\n", err)
82 return nil, err
83 }
84 response := &ext_plugin.ExtensionHandlerResponse{}
85 err = proto.Unmarshal(output, response)
86 if err != nil {
87 fmt.Printf("Error: %+v\n", err)
88 fmt.Printf("%s\n", string(output))
89 return nil, err
90 }
91 if !response.Handled {
92 return nil, nil
93 }
94 if len(response.Error) != 0 {
95 message := fmt.Sprintf("Errors when parsing: %+v for field %s by vendor extension handler %s. Details %+v", in, extensionName, extensionHandlers.Name, strings.Join(response.Error, ","))
96 return nil, errors.New(message)
97 }
98 return response.Value, nil
99 }
100 return nil, nil
101}