| // 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() |
| } |