Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add features files to the set of standard imports #295

Merged
merged 4 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ lintfix: $(BIN)/golangci-lint ## Automatically fix some lint errors
cd internal/benchmarks && $(BIN)/golangci-lint run --fix

.PHONY: generate
generate: $(BIN)/license-header $(BIN)/goyacc test-descriptors ## Regenerate code and licenses
generate: $(BIN)/license-header $(BIN)/goyacc test-descriptors ext-features-descriptors ## Regenerate code and licenses
PATH="$(BIN)$(PATH_SEP)$(PATH)" $(GO) generate ./...
@# We want to operate on a list of modified and new files, excluding
@# deleted and ignored files. git-ls-files can't do this alone. comm -23 takes
Expand Down Expand Up @@ -183,3 +183,11 @@ test-descriptors: internal/testdata/options/options.protoset
test-descriptors: internal/testdata/options/test.protoset
test-descriptors: internal/testdata/options/test_proto3.protoset
test-descriptors: internal/testdata/options/test_editions.protoset

internal/featuresext/cpp_features.protoset: $(PROTOC)
cd $(@D) && $(PROTOC) --experimental_editions --descriptor_set_out=$(@F) google/protobuf/cpp_features.proto
internal/featuresext/java_features.protoset: $(PROTOC)
cd $(@D) && $(PROTOC) --experimental_editions --descriptor_set_out=$(@F) google/protobuf/java_features.proto

.PHONY: ext-features-descriptors
ext-features-descriptors: internal/featuresext/cpp_features.protoset internal/featuresext/java_features.protoset
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/google/go-cmp v0.6.0
github.com/stretchr/testify v1.9.0
golang.org/x/sync v0.7.0
google.golang.org/protobuf v1.33.1-0.20240408130810-98873a205002
google.golang.org/protobuf v1.33.1-0.20240422163739-e4ad8f9dfc8b
)

require (
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
google.golang.org/protobuf v1.33.1-0.20240408130810-98873a205002 h1:V7Da7qt0MkY3noVANIMVBk28nOnijADeOR3i5Hcvpj4=
google.golang.org/protobuf v1.33.1-0.20240408130810-98873a205002/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.33.1-0.20240422163739-e4ad8f9dfc8b h1:LtLYFcFBR7ZbrgFuP9p4Za5dPr/velw2v5t9Z9HFPiQ=
google.golang.org/protobuf v1.33.1-0.20240422163739-e4ad8f9dfc8b/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
7 changes: 7 additions & 0 deletions internal/featuresext/cpp_features.protoset
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

emcfarlane marked this conversation as resolved.
Show resolved Hide resolved
ì
"google/protobuf/cpp_features.protopb google/protobuf/descriptor.proto"_
CppFeaturesP
legacy_closed_enum (B"ˆ˜˜¢ trueæ¢
falseçRlegacyClosedEnum:?
cpp.google.protobuf.FeatureSetè ( 2.pb.CppFeaturesRcpp
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"))
}
Binary file added internal/featuresext/java_features.protoset
Binary file not shown.
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 generated 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
Loading