diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..7d0d53f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,41 @@ + + +# Changelog + +## [Unreleased] + +### Features + +* [#82](https://github.com/cosmos/cosmos-proto/pull/82) generated code in `internal` go packages is not registered with the global protobuf registry allowing modules to have internal protobuf generated types that are not exposed in public APIs and do not affect global protobuf registration. \ No newline at end of file diff --git a/features/protoc/internal_test.go b/features/protoc/internal_test.go new file mode 100644 index 0000000..2657f4d --- /dev/null +++ b/features/protoc/internal_test.go @@ -0,0 +1,17 @@ +package protoc + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestIsInternalPackage(t *testing.T) { + require.True(t, isInternalPackage("internal")) + require.True(t, isInternalPackage("example/internal")) + require.True(t, isInternalPackage("example.com/internal")) + require.True(t, isInternalPackage("example.com/internal/foo")) + require.False(t, isInternalPackage("example")) + require.False(t, isInternalPackage("example.com")) + require.False(t, isInternalPackage("example.com/false")) +} diff --git a/features/protoc/main.go b/features/protoc/main.go index 3cc5a1a..95abdc6 100644 --- a/features/protoc/main.go +++ b/features/protoc/main.go @@ -7,26 +7,31 @@ package protoc import ( "fmt" - "github.com/cosmos/cosmos-proto/features/protoc/genid" - "github.com/cosmos/cosmos-proto/generator" "go/ast" "go/parser" "go/token" - "google.golang.org/protobuf/encoding/protowire" - "google.golang.org/protobuf/proto" "math" "strconv" "strings" "unicode" "unicode/utf8" + "golang.org/x/exp/slices" + + "google.golang.org/protobuf/encoding/protowire" + "google.golang.org/protobuf/proto" + + "github.com/cosmos/cosmos-proto/features/protoc/genid" + "github.com/cosmos/cosmos-proto/generator" + pref "google.golang.org/protobuf/reflect/protoreflect" - "github.com/cosmos/cosmos-proto/features/protoc/version" "google.golang.org/protobuf/compiler/protogen" "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/runtime/protoimpl" + "github.com/cosmos/cosmos-proto/features/protoc/version" + "google.golang.org/protobuf/types/descriptorpb" "google.golang.org/protobuf/types/pluginpb" ) @@ -60,6 +65,7 @@ var ( protojsonPackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/encoding/protojson") protoreflectPackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/reflect/protoreflect") protoregistryPackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/reflect/protoregistry") + runtimePackage = protogen.GoImportPath("github.com/cosmos/cosmos-proto/runtime") ) // GenerateFile generates the contents of a .pb.go file. @@ -360,6 +366,8 @@ func genReflectFileDescriptor(gen *protogen.Plugin, g *generator.GeneratedFile, } } + isInternal := isInternalPackage(f.GoImportPath.String()) + g.P("type x struct{}") g.P("out := ", protoimplPackage.Ident("TypeBuilder"), "{") g.P("File: ", protoimplPackage.Ident("DescBuilder"), "{") @@ -369,6 +377,9 @@ func genReflectFileDescriptor(gen *protogen.Plugin, g *generator.GeneratedFile, g.P("NumMessages: ", len(f.allMessages), ",") g.P("NumExtensions: ", len(f.allExtensions), ",") g.P("NumServices: ", len(f.Services), ",") + if isInternal { + g.P("FileRegistry: ", runtimePackage.Ident("NullRegistry"), "{},") + } g.P("},") g.P("GoTypes: ", goTypesVarName(f), ",") g.P("DependencyIndexes: ", depIdxsVarName(f), ",") @@ -381,6 +392,9 @@ func genReflectFileDescriptor(gen *protogen.Plugin, g *generator.GeneratedFile, if len(f.allExtensions) > 0 { g.P("ExtensionInfos: ", extensionTypesVarName(f), ",") } + if isInternal { + g.P("TypeRegistry: ", runtimePackage.Ident("NullRegistry"), "{},") + } g.P("}.Build()") g.P(f.GoDescriptorIdent, " = out.File") @@ -2287,3 +2301,9 @@ func newFileInfo(file *protogen.File) *fileInfo { return f } + +// checks whether the package path is an internal package +func isInternalPackage(pkg string) bool { + pathParts := strings.Split(pkg, "/") + return slices.Contains(pathParts, "internal") +} diff --git a/go.mod b/go.mod index dd5cd52..d8fd04d 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.18 require ( github.com/google/go-cmp v0.6.0 github.com/stretchr/testify v1.9.0 + golang.org/x/exp v0.0.0-20220907003533-145caa8ea1d0 google.golang.org/protobuf v1.34.0 gotest.tools/v3 v3.5.1 pgregory.net/rapid v1.1.0 diff --git a/go.sum b/go.sum index 5759b63..1eef86b 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/exp v0.0.0-20220907003533-145caa8ea1d0 h1:17k44ji3KFYG94XS5QEFC8pyuOlMh3IoR+vkmTZmJJs= +golang.org/x/exp v0.0.0-20220907003533-145caa8ea1d0/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= google.golang.org/protobuf v1.34.0 h1:Qo/qEd2RZPCf2nKuorzksSknv0d3ERwp1vFG38gSmH4= google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/internal/testprotos/test3/internal_test.go b/internal/testprotos/test3/internal_test.go new file mode 100644 index 0000000..aeb6635 --- /dev/null +++ b/internal/testprotos/test3/internal_test.go @@ -0,0 +1,16 @@ +package test3 + +import ( + "testing" + + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/reflect/protoregistry" +) + +func TestInternalNotRegistered(t *testing.T) { + _, err := protoregistry.GlobalTypes.FindMessageByName((&TestAllTypes{}).ProtoReflect().Descriptor().FullName()) + require.Error(t, err) + + _, err = protoregistry.GlobalFiles.FindFileByPath("internal/testprotos/test3/test_import.proto") + require.Error(t, err) +} diff --git a/internal/testprotos/test3/test.pulsar.go b/internal/testprotos/test3/test.pulsar.go index 1721a4a..2b0ee3e 100644 --- a/internal/testprotos/test3/test.pulsar.go +++ b/internal/testprotos/test3/test.pulsar.go @@ -12605,11 +12605,13 @@ func file_internal_testprotos_test3_test_proto_init() { NumMessages: 20, NumExtensions: 0, NumServices: 0, + FileRegistry: runtime.NullRegistry{}, }, GoTypes: file_internal_testprotos_test3_test_proto_goTypes, DependencyIndexes: file_internal_testprotos_test3_test_proto_depIdxs, EnumInfos: file_internal_testprotos_test3_test_proto_enumTypes, MessageInfos: file_internal_testprotos_test3_test_proto_msgTypes, + TypeRegistry: runtime.NullRegistry{}, }.Build() File_internal_testprotos_test3_test_proto = out.File file_internal_testprotos_test3_test_proto_rawDesc = nil diff --git a/internal/testprotos/test3/test_import.pulsar.go b/internal/testprotos/test3/test_import.pulsar.go index 06ba752..f9d5dfe 100644 --- a/internal/testprotos/test3/test_import.pulsar.go +++ b/internal/testprotos/test3/test_import.pulsar.go @@ -525,11 +525,13 @@ func file_internal_testprotos_test3_test_import_proto_init() { NumMessages: 1, NumExtensions: 0, NumServices: 0, + FileRegistry: runtime.NullRegistry{}, }, GoTypes: file_internal_testprotos_test3_test_import_proto_goTypes, DependencyIndexes: file_internal_testprotos_test3_test_import_proto_depIdxs, EnumInfos: file_internal_testprotos_test3_test_import_proto_enumTypes, MessageInfos: file_internal_testprotos_test3_test_import_proto_msgTypes, + TypeRegistry: runtime.NullRegistry{}, }.Build() File_internal_testprotos_test3_test_import_proto = out.File file_internal_testprotos_test3_test_import_proto_rawDesc = nil diff --git a/internal/testprotos/test3/test_nesting.pulsar.go b/internal/testprotos/test3/test_nesting.pulsar.go index 4547c29..52da9c7 100644 --- a/internal/testprotos/test3/test_nesting.pulsar.go +++ b/internal/testprotos/test3/test_nesting.pulsar.go @@ -2061,10 +2061,12 @@ func file_internal_testprotos_test3_test_nesting_proto_init() { NumMessages: 4, NumExtensions: 0, NumServices: 0, + FileRegistry: runtime.NullRegistry{}, }, GoTypes: file_internal_testprotos_test3_test_nesting_proto_goTypes, DependencyIndexes: file_internal_testprotos_test3_test_nesting_proto_depIdxs, MessageInfos: file_internal_testprotos_test3_test_nesting_proto_msgTypes, + TypeRegistry: runtime.NullRegistry{}, }.Build() File_internal_testprotos_test3_test_nesting_proto = out.File file_internal_testprotos_test3_test_nesting_proto_rawDesc = nil diff --git a/runtime/nullregistry.go b/runtime/nullregistry.go new file mode 100644 index 0000000..2933122 --- /dev/null +++ b/runtime/nullregistry.go @@ -0,0 +1,23 @@ +package runtime + +import ( + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" +) + +// NullRegistry is an implementation of the interfaces used to register generated +// types and file descriptors that does nothing. This is used to generated +// protobuf files in internal packages that are not registered with the global registry. +type NullRegistry struct{} + +func (NullRegistry) RegisterMessage(protoreflect.MessageType) error { return nil } +func (NullRegistry) RegisterEnum(protoreflect.EnumType) error { return nil } +func (NullRegistry) RegisterExtension(protoreflect.ExtensionType) error { return nil } +func (NullRegistry) RegisterFile(protoreflect.FileDescriptor) error { return nil } + +func (NullRegistry) FindFileByPath(path string) (protoreflect.FileDescriptor, error) { + return protoregistry.GlobalFiles.FindFileByPath(path) +} +func (NullRegistry) FindDescriptorByName(name protoreflect.FullName) (protoreflect.Descriptor, error) { + return protoregistry.GlobalFiles.FindDescriptorByName(name) +}