mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-12-22 21:10:22 +00:00
258 lines
7.7 KiB
Go
258 lines
7.7 KiB
Go
|
// Copyright 2017 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.
|
||
|
|
||
|
// generator generates Protocol Buffer models and support code from
|
||
|
// JSON Schemas. It is used to generate representations of the
|
||
|
// OpenAPI Specification and vendor and specification extensions
|
||
|
// that are added by third-party OpenAPI authors.
|
||
|
package main
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"io/ioutil"
|
||
|
"log"
|
||
|
"os"
|
||
|
"os/exec"
|
||
|
"path"
|
||
|
"runtime"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/googleapis/gnostic/jsonschema"
|
||
|
)
|
||
|
|
||
|
// License is the software license applied to generated code.
|
||
|
const License = "" +
|
||
|
"// Copyright 2017 Google Inc. All Rights Reserved.\n" +
|
||
|
"//\n" +
|
||
|
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n" +
|
||
|
"// you may not use this file except in compliance with the License.\n" +
|
||
|
"// You may obtain a copy of the License at\n" +
|
||
|
"//\n" +
|
||
|
"// http://www.apache.org/licenses/LICENSE-2.0\n" +
|
||
|
"//\n" +
|
||
|
"// Unless required by applicable law or agreed to in writing, software\n" +
|
||
|
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n" +
|
||
|
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
|
||
|
"// See the License for the specific language governing permissions and\n" +
|
||
|
"// limitations under the License.\n"
|
||
|
|
||
|
func protoOptions(packageName string) []ProtoOption {
|
||
|
return []ProtoOption{
|
||
|
ProtoOption{
|
||
|
Name: "java_multiple_files",
|
||
|
Value: "true",
|
||
|
Comment: "// This option lets the proto compiler generate Java code inside the package\n" +
|
||
|
"// name (see below) instead of inside an outer class. It creates a simpler\n" +
|
||
|
"// developer experience by reducing one-level of name nesting and be\n" +
|
||
|
"// consistent with most programming languages that don't support outer classes.",
|
||
|
},
|
||
|
|
||
|
ProtoOption{
|
||
|
Name: "java_outer_classname",
|
||
|
Value: "OpenAPIProto",
|
||
|
Comment: "// The Java outer classname should be the filename in UpperCamelCase. This\n" +
|
||
|
"// class is only used to hold proto descriptor, so developers don't need to\n" +
|
||
|
"// work with it directly.",
|
||
|
},
|
||
|
|
||
|
ProtoOption{
|
||
|
Name: "java_package",
|
||
|
Value: "org." + packageName,
|
||
|
Comment: "// The Java package name must be proto package name with proper prefix.",
|
||
|
},
|
||
|
|
||
|
ProtoOption{
|
||
|
Name: "objc_class_prefix",
|
||
|
Value: "OAS",
|
||
|
Comment: "// A reasonable prefix for the Objective-C symbols generated from the package.\n" +
|
||
|
"// It should at a minimum be 3 characters long, all uppercase, and convention\n" +
|
||
|
"// is to use an abbreviation of the package name. Something short, but\n" +
|
||
|
"// hopefully unique enough to not conflict with things that may come along in\n" +
|
||
|
"// the future. 'GPB' is reserved for the protocol buffer implementation itself.",
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func generateOpenAPIModel(version string) error {
|
||
|
var input string
|
||
|
var filename string
|
||
|
var protoPackageName string
|
||
|
|
||
|
switch version {
|
||
|
case "v2":
|
||
|
input = "openapi-2.0.json"
|
||
|
filename = "OpenAPIv2"
|
||
|
protoPackageName = "openapi.v2"
|
||
|
case "v3":
|
||
|
input = "openapi-3.0.json"
|
||
|
filename = "OpenAPIv3"
|
||
|
protoPackageName = "openapi.v3"
|
||
|
case "discovery":
|
||
|
input = "discovery.json"
|
||
|
filename = "discovery"
|
||
|
protoPackageName = "discovery.v1"
|
||
|
default:
|
||
|
return fmt.Errorf("Unknown OpenAPI version %s", version)
|
||
|
}
|
||
|
|
||
|
goPackageName := strings.Replace(protoPackageName, ".", "_", -1)
|
||
|
|
||
|
projectRoot := os.Getenv("GOPATH") + "/src/github.com/googleapis/gnostic/"
|
||
|
|
||
|
baseSchema, err := jsonschema.NewSchemaFromFile(projectRoot + "jsonschema/schema.json")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
baseSchema.ResolveRefs()
|
||
|
baseSchema.ResolveAllOfs()
|
||
|
|
||
|
openapiSchema, err := jsonschema.NewSchemaFromFile(projectRoot + filename + "/" + input)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
openapiSchema.ResolveRefs()
|
||
|
openapiSchema.ResolveAllOfs()
|
||
|
|
||
|
// build a simplified model of the types described by the schema
|
||
|
cc := NewDomain(openapiSchema, version)
|
||
|
// generators will map these patterns to the associated property names
|
||
|
// these pattern names are a bit of a hack until we find a more automated way to obtain them
|
||
|
|
||
|
switch version {
|
||
|
case "v2":
|
||
|
cc.TypeNameOverrides = map[string]string{
|
||
|
"VendorExtension": "Any",
|
||
|
}
|
||
|
cc.PropertyNameOverrides = map[string]string{
|
||
|
"PathItem": "Path",
|
||
|
"ResponseValue": "ResponseCode",
|
||
|
}
|
||
|
case "v3":
|
||
|
cc.TypeNameOverrides = map[string]string{
|
||
|
"SpecificationExtension": "Any",
|
||
|
}
|
||
|
cc.PropertyNameOverrides = map[string]string{
|
||
|
"PathItem": "Path",
|
||
|
"ResponseValue": "ResponseCode",
|
||
|
}
|
||
|
case "discovery":
|
||
|
cc.TypeNameOverrides = map[string]string{}
|
||
|
cc.PropertyNameOverrides = map[string]string{}
|
||
|
default:
|
||
|
return fmt.Errorf("Unknown OpenAPI version %s", version)
|
||
|
}
|
||
|
|
||
|
err = cc.Build()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if true {
|
||
|
log.Printf("Type Model:\n%s", cc.Description())
|
||
|
}
|
||
|
|
||
|
// ensure that the target directory exists
|
||
|
err = os.MkdirAll(projectRoot+filename, 0755)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// generate the protocol buffer description
|
||
|
log.Printf("Generating protocol buffer description")
|
||
|
proto := cc.generateProto(protoPackageName, License,
|
||
|
protoOptions(goPackageName), []string{"google/protobuf/any.proto"})
|
||
|
protoFileName := projectRoot + filename + "/" + filename + ".proto"
|
||
|
err = ioutil.WriteFile(protoFileName, []byte(proto), 0644)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// generate the compiler
|
||
|
log.Printf("Generating compiler support code")
|
||
|
compiler := cc.GenerateCompiler(goPackageName, License, []string{
|
||
|
"fmt",
|
||
|
"gopkg.in/yaml.v2",
|
||
|
"strings",
|
||
|
"regexp",
|
||
|
"github.com/googleapis/gnostic/compiler",
|
||
|
})
|
||
|
goFileName := projectRoot + filename + "/" + filename + ".go"
|
||
|
err = ioutil.WriteFile(goFileName, []byte(compiler), 0644)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
// format the compiler
|
||
|
log.Printf("Formatting compiler support code")
|
||
|
return exec.Command(runtime.GOROOT()+"/bin/gofmt", "-w", goFileName).Run()
|
||
|
}
|
||
|
|
||
|
func usage() string {
|
||
|
return fmt.Sprintf(`
|
||
|
Usage: %s [OPTIONS]
|
||
|
Options:
|
||
|
--v2
|
||
|
Generate Protocol Buffer representation and support code for OpenAPI v2.
|
||
|
Files are read from and written to appropriate locations in the gnostic
|
||
|
project directory.
|
||
|
--v3
|
||
|
Generate Protocol Buffer representation and support code for OpenAPI v3
|
||
|
Files are read from and written to appropriate locations in the gnostic
|
||
|
project directory.
|
||
|
--extension EXTENSION_SCHEMA [EXTENSIONOPTIONS]
|
||
|
Generate a gnostic extension that reads a set of OpenAPI extensions.
|
||
|
EXTENSION_SCHEMA is the json schema for the OpenAPI extensions to be
|
||
|
supported.
|
||
|
EXTENSION_OPTIONS
|
||
|
--out_dir=PATH: Location for writing extension models and support code.
|
||
|
`, path.Base(os.Args[0]))
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
var openapiVersion = ""
|
||
|
var generateExtensions = false
|
||
|
|
||
|
for i, arg := range os.Args {
|
||
|
if i == 0 {
|
||
|
continue // skip the tool name
|
||
|
}
|
||
|
if arg == "--v2" {
|
||
|
openapiVersion = "v2"
|
||
|
} else if arg == "--v3" {
|
||
|
openapiVersion = "v3"
|
||
|
} else if arg == "--discovery" {
|
||
|
openapiVersion = "discovery"
|
||
|
} else if arg == "--extension" {
|
||
|
generateExtensions = true
|
||
|
break
|
||
|
} else {
|
||
|
fmt.Printf("Unknown option: %s.\n%s\n", arg, usage())
|
||
|
os.Exit(-1)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if openapiVersion != "" {
|
||
|
err := generateOpenAPIModel(openapiVersion)
|
||
|
if err != nil {
|
||
|
fmt.Printf("%+v\n", err)
|
||
|
}
|
||
|
} else if generateExtensions {
|
||
|
err := processExtensionGenCommandline(usage())
|
||
|
if err != nil {
|
||
|
fmt.Printf("%+v\n", err)
|
||
|
}
|
||
|
} else {
|
||
|
fmt.Printf("%s\n", usage())
|
||
|
}
|
||
|
}
|