Skip to content

Commit

Permalink
add go_features.proto, cpp_features.proto, and java_features.proto to…
Browse files Browse the repository at this point in the history
… protocompile.WithStandardImports
  • Loading branch information
jhump committed Apr 26, 2024
1 parent d9c23d3 commit 4014fb1
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 1 deletion.
84 changes: 84 additions & 0 deletions internal/featuresext/featuresext.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright 2020-2024 Buf Technologies, Inc.
//
// 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.

// Package featuresext provides file descriptors for the
// "google/protobuf/cpp_features.proto" and "google/protobuf/java_features.proto"
// standard import files. Unlike the other standard/well-known
// imports, these files have no standard Go package in their
// runtime with generated code. So in order to make them available
// as "standard imports" to compiler users, we must embed these
// descriptors into a Go package.
package featuresext

import (
_ "embed"
"fmt"
"sync"

"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/types/descriptorpb"
)

var (
//go:embed cpp_features.protoset
cppFeatures []byte

//go:embed java_features.protoset
javaFeatures []byte

initOnce sync.Once
initCppFeatures protoreflect.FileDescriptor
initCppErr error
initJavaFeatures protoreflect.FileDescriptor
initJavaErr error
)

func initDescriptors() {
initOnce.Do(func() {
initCppFeatures, initCppErr = buildDescriptor("google/protobuf/cpp_features.proto", cppFeatures)
initJavaFeatures, initJavaErr = buildDescriptor("google/protobuf/java_features.proto", javaFeatures)
})
}

func CppFeaturesDescriptor() (protoreflect.FileDescriptor, error) {
initDescriptors()
return initCppFeatures, initCppErr
}

func JavaFeaturesDescriptor() (protoreflect.FileDescriptor, error) {
initDescriptors()
return initJavaFeatures, initJavaErr
}

func buildDescriptor(name string, data []byte) (protoreflect.FileDescriptor, error) {
var files descriptorpb.FileDescriptorSet
err := proto.Unmarshal(data, &files)
if err != nil {
return nil, fmt.Errorf("failed to load descriptor for %q: %w", name, err)
}
if len(files.File) != 1 {
return nil, fmt.Errorf("failed to load descriptor for %q: expected embedded descriptor set to contain exactly one file but it instead has %d", name, len(files.File))
}
if files.File[0].GetName() != name {
return nil, fmt.Errorf("failed to load descriptor for %q: embedded descriptor contains wrong file %q", name, files.File[0].GetName())
}
descriptor, err := protodesc.NewFile(files.File[0], protoregistry.GlobalFiles)
if err != nil {
return nil, fmt.Errorf("failed to load descriptor for %q: %w", name, err)
}
return descriptor, nil
}
37 changes: 37 additions & 0 deletions internal/featuresext/featuresext_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2020-2024 Buf Technologies, Inc.
//
// 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.

package featuresext

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/reflect/protoreflect"
)

func TestFeaturesExt(t *testing.T) {
t.Parallel()

file, err := CppFeaturesDescriptor()
require.NoError(t, err)
assert.Equal(t, protoreflect.FullName("pb"), file.Package())
assert.NotNil(t, file.Extensions().ByName("cpp"))

file, err = JavaFeaturesDescriptor()
require.NoError(t, err)
assert.Equal(t, protoreflect.FullName("pb"), file.Package())
assert.NotNil(t, file.Extensions().ByName("java"))
}
36 changes: 35 additions & 1 deletion std_imports.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ package protocompile
import (
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
_ "google.golang.org/protobuf/types/known/anypb" // link in packages that include the standard protos included with protoc.
_ "google.golang.org/protobuf/types/gofeaturespb" // link in packages that include the standard protos included with protoc.
_ "google.golang.org/protobuf/types/known/anypb"
_ "google.golang.org/protobuf/types/known/apipb"
_ "google.golang.org/protobuf/types/known/durationpb"
_ "google.golang.org/protobuf/types/known/emptypb"
Expand All @@ -28,6 +29,8 @@ import (
_ "google.golang.org/protobuf/types/known/typepb"
_ "google.golang.org/protobuf/types/known/wrapperspb"
_ "google.golang.org/protobuf/types/pluginpb"

"github.com/bufbuild/protocompile/internal/featuresext"
)

// All files that are included with protoc are also included with this package
Expand All @@ -44,6 +47,7 @@ func init() {
"google/protobuf/duration.proto",
"google/protobuf/empty.proto",
"google/protobuf/field_mask.proto",
"google/protobuf/go_features.proto",
"google/protobuf/source_context.proto",
"google/protobuf/struct.proto",
"google/protobuf/timestamp.proto",
Expand All @@ -59,4 +63,34 @@ func init() {
}
standardImports[fn] = fd
}

otherFeatures := []struct {
Name string
GetDescriptor func() (protoreflect.FileDescriptor, error)
}{
{
Name: "google/protobuf/cpp_features.proto",
GetDescriptor: featuresext.CppFeaturesDescriptor,
},
{
Name: "google/protobuf/java_features.proto",
GetDescriptor: featuresext.JavaFeaturesDescriptor,
},
}
for _, feature := range otherFeatures {
// First see if the program has gneerated Go code for this
// file linked in:
fd, err := protoregistry.GlobalFiles.FindFileByPath(feature.Name)
if err == nil {
standardImports[feature.Name] = fd
continue
}
fd, err = feature.GetDescriptor()
if err != nil {
// For these extensions to FeatureSet, we are lenient. If
// we can't load them, just ignore them.
continue
}
standardImports[feature.Name] = fd
}
}
1 change: 1 addition & 0 deletions std_imports_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func TestStdImports(t *testing.T) {
c := Compiler{Resolver: WithStandardImports(&SourceResolver{})}
ctx := context.Background()
for name, fileProto := range standardImports {
t.Log(name)
fds, err := c.Compile(ctx, name)
if err != nil {
t.Errorf("failed to compile %q: %v", name, err)
Expand Down

0 comments on commit 4014fb1

Please sign in to comment.