blob: 1faf90bb633dda17163e29e1107b8c09eb33050a [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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.
package protogenutil
import (
"fmt"
"path"
"strings"
)
import (
"google.golang.org/protobuf/compiler/protogen"
)
const namedHelperGoPackageOptionKey = "named_go_package"
type namedHelper struct {
pluginNameToGoPackage map[string]string
}
func newNamedHelper() *namedHelper {
return &namedHelper{
pluginNameToGoPackage: make(map[string]string),
}
}
func (h *namedHelper) NewGoPackageName(
baseGoPackageName protogen.GoPackageName,
pluginName string,
) protogen.GoPackageName {
return protogen.GoPackageName(string(baseGoPackageName) + pluginName)
}
func (h *namedHelper) NewGoImportPath(
file *protogen.File,
pluginName string,
) (protogen.GoImportPath, error) {
return h.newGoImportPath(
path.Dir(file.GeneratedFilenamePrefix),
file.GoPackageName,
pluginName,
)
}
func (h *namedHelper) NewPackageGoImportPath(
goPackageFileSet *GoPackageFileSet,
pluginName string,
) (protogen.GoImportPath, error) {
return h.newGoImportPath(
goPackageFileSet.GeneratedDir,
goPackageFileSet.GoPackageName,
pluginName,
)
}
func (h *namedHelper) NewGlobalGoImportPath(
pluginName string,
) (protogen.GoImportPath, error) {
goPackage, ok := h.pluginNameToGoPackage[pluginName]
if !ok {
return "", fmt.Errorf("no %s specified for plugin %s", namedHelperGoPackageOptionKey, pluginName)
}
return protogen.GoImportPath(goPackage), nil
}
func (h *namedHelper) NewGeneratedFile(
plugin *protogen.Plugin,
file *protogen.File,
pluginName string,
) (*protogen.GeneratedFile, error) {
goImportPath, err := h.NewGoImportPath(file, pluginName)
if err != nil {
return nil, err
}
goPackageName := h.NewGoPackageName(file.GoPackageName, pluginName)
generatedFilePath := path.Dir(file.GeneratedFilenamePrefix) +
"/" + string(goPackageName) +
"/" + path.Base(file.GeneratedFilenamePrefix) +
".pb.go"
generatedFile := plugin.NewGeneratedFile(generatedFilePath, goImportPath)
printGeneratedFileNamedHelperHeader(generatedFile, goPackageName, pluginName)
return generatedFile, nil
}
func (h *namedHelper) NewPackageGeneratedFile(
plugin *protogen.Plugin,
goPackageFileSet *GoPackageFileSet,
pluginName string,
) (*protogen.GeneratedFile, error) {
goImportPath, err := h.NewPackageGoImportPath(goPackageFileSet, pluginName)
if err != nil {
return nil, err
}
goPackageName := h.NewGoPackageName(goPackageFileSet.GoPackageName, pluginName)
fileBaseName := string(goPackageName)
// make sure this file name would not overlap with any actual file name
for _, file := range goPackageFileSet.Files {
if path.Base(file.GeneratedFilenamePrefix) == fileBaseName {
fileBaseName = fileBaseName + "_pkg"
// do not break, just for the malicious case, where there is a file
// packagename_pkg.proto, packagename_pkg_pkg.proto, etc
}
}
generatedFilePath := goPackageFileSet.GeneratedDir +
"/" + string(goPackageName) +
"/" + fileBaseName +
".pb.go"
generatedFile := plugin.NewGeneratedFile(generatedFilePath, goImportPath)
printGeneratedFileNamedHelperHeader(generatedFile, goPackageName, pluginName)
return generatedFile, nil
}
func (h *namedHelper) NewGlobalGeneratedFile(
plugin *protogen.Plugin,
pluginName string,
) (*protogen.GeneratedFile, error) {
goImportPath, err := h.NewGlobalGoImportPath(pluginName)
if err != nil {
return nil, err
}
goPackageName := h.NewGoPackageName("", pluginName)
generatedFilePath := string(goPackageName) + ".pb.go"
generatedFile := plugin.NewGeneratedFile(generatedFilePath, goImportPath)
printGeneratedFileNamedHelperHeader(generatedFile, goPackageName, pluginName)
return generatedFile, nil
}
func (h *namedHelper) newGoImportPath(
generatedDir string,
baseGoPackageName protogen.GoPackageName,
pluginName string,
) (protogen.GoImportPath, error) {
goPackage, ok := h.pluginNameToGoPackage[pluginName]
if !ok {
return "", fmt.Errorf("no %s specified for plugin %s", namedHelperGoPackageOptionKey, pluginName)
}
return protogen.GoImportPath(goPackage +
"/" + generatedDir +
"/" + string(h.NewGoPackageName(baseGoPackageName, pluginName))), nil
}
func (h *namedHelper) handleOption(key string, value string) error {
if key != namedHelperGoPackageOptionKey {
return nil
}
split := strings.Split(value, "=")
if len(split) != 2 {
return fmt.Errorf("unknown value for %s: %s", namedHelperGoPackageOptionKey, value)
}
h.pluginNameToGoPackage[split[0]] = split[1]
return nil
}
func printGeneratedFileNamedHelperHeader(
generatedFile *protogen.GeneratedFile,
goPackageName protogen.GoPackageName,
pluginName string,
) {
generatedFile.P("// Code generated by protoc-gen-go-", pluginName, ". DO NOT EDIT.")
generatedFile.P()
generatedFile.P("package ", goPackageName)
generatedFile.P()
}