Skip to content

Commit

Permalink
Add plugin development helpers and verbose flag for plugins. (#152)
Browse files Browse the repository at this point in the history
* Add plugin development helpers and --verbose flag for plugins.
  • Loading branch information
timburks committed Jan 6, 2020
1 parent b043406 commit 9938483
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 0 deletions.
22 changes: 22 additions & 0 deletions plugins/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,25 @@ This directory contains support code for building Gnostic plugins and associated
Plugins are used to process API descriptions and can perform tasks like documentation and
code generation. Plugins can be written in any language that is supported by the Protocol
Buffer tools.

This directory contains several sample plugins and two support tools that make it easier
to test plugins by running them standalone.

* `gnostic-plugin-request` is a plugin that captures a plugin request and writes it in
.json and binary .pb form. When the optional -verbose flag is provided, this plugin logs
the request to stdout.
* `gnostic-process-plugin-response` is a standalone tool that reads a plugin response on
stdin and handles the response in the same way that gnostic does.

For example, this writes the plugin request to local files `plugin-request.json` and
`plugin-request.pb`.

`% gnostic myapi.json --plugin-request-out=.`

Then a plugin can be run standalone:

`% gnostic-go-generator --plugin < plugin-request.pb > plugin-response.pb`

Then you can use the following to process the plugin response:

`% gnostic-process-plugin-response -output=. < plugin-response.pb`
3 changes: 3 additions & 0 deletions plugins/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Environment struct {
Response *Response // response message
Invocation string // string representation of call
RunningAsPlugin bool // true if app is being run as a plugin
Verbose bool // if true, plugin should log details to stderr
}

// NewEnvironment creates a plugin context from arguments and standard input.
Expand All @@ -38,9 +39,11 @@ func NewEnvironment() (env *Environment, err error) {
input := flag.String("input", "", "API description (in binary protocol buffer form)")
output := flag.String("output", "-", "Output file or directory")
plugin := flag.Bool("plugin", false, "Run as a gnostic plugin (other flags are ignored).")
verbose := flag.Bool("verbose", false, "Write details to stderr.")
flag.Parse()

env.RunningAsPlugin = *plugin
env.Verbose = *verbose
programName := path.Base(os.Args[0])

if (*input == "") && !*plugin {
Expand Down
79 changes: 79 additions & 0 deletions plugins/gnostic-plugin-request/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright 2020 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// gnostic-plugin-request is a development tool that captures and optionally
// displays the contents of the gnostic plugin interface.
package main

import (
"log"

"github.com/golang/protobuf/jsonpb"
"github.com/golang/protobuf/proto"
openapiv2 "github.com/googleapis/gnostic/OpenAPIv2"
openapiv3 "github.com/googleapis/gnostic/OpenAPIv3"
plugins "github.com/googleapis/gnostic/plugins"
surface "github.com/googleapis/gnostic/surface"
)

func main() {
env, err := plugins.NewEnvironment()
env.RespondAndExitIfError(err)

if env.Verbose {
for _, model := range env.Request.Models {
log.Printf("model %s", model.TypeUrl)
switch model.TypeUrl {
case "openapi.v2.Document":
document := &openapiv2.Document{}
err = proto.Unmarshal(model.Value, document)
if err == nil {
log.Printf("%+v", document)
}
case "openapi.v3.Document":
document := &openapiv3.Document{}
err = proto.Unmarshal(model.Value, document)
if err == nil {
log.Printf("%+v", document)
}
case "surface.v1.Model":
document := &surface.Model{}
err = proto.Unmarshal(model.Value, document)
if err == nil {
log.Printf("%+v", document)
}
}
}
}

// export the plugin request as JSON
{
file := &plugins.File{}
file.Name = "plugin-request.json"
m := jsonpb.Marshaler{Indent: " "}
s, err := m.MarshalToString(env.Request)
file.Data = []byte(s)
env.RespondAndExitIfError(err)
env.Response.Files = append(env.Response.Files, file)
}
// export the plugin request as binary protobuf
{
file := &plugins.File{}
file.Name = "plugin-request.pb"
file.Data, err = proto.Marshal(env.Request)
env.RespondAndExitIfError(err)
env.Response.Files = append(env.Response.Files, file)
}
env.RespondAndExit()
}
51 changes: 51 additions & 0 deletions plugins/gnostic-process-plugin-response/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2020 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// gnostic-process-plugin-response is a development tool that processes
// the output of a gnostic plugin in the same way that it would be handled
// by gnostic itself.
package main

import (
"flag"
"io/ioutil"
"log"
"os"

"github.com/golang/protobuf/proto"
plugins "github.com/googleapis/gnostic/plugins"
)

func exitIfError(err error) {
if err != nil {
log.Printf("%+v", err)
os.Exit(-1)
}
}

func main() {
output := flag.String("output", "-", "Output file or directory")
flag.Parse()

// Read the plugin response data from stdin.
pluginData, err := ioutil.ReadAll(os.Stdin)
exitIfError(err)
response := &plugins.Response{}
err = proto.Unmarshal(pluginData, response)
exitIfError(err)

// Handle the response in the standard (gnostic) way.
err = plugins.HandleResponse(response, *output)
exitIfError(err)
}

0 comments on commit 9938483

Please sign in to comment.