-
Notifications
You must be signed in to change notification settings - Fork 4
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 sourceinfo plugin #22
Changes from 19 commits
b79a31e
c00a0cd
14d621d
a87ee39
f0d0ea7
7cd6b87
0790ed3
eb3a151
f26b23c
ca777e3
75dc2f1
72fc2b8
fc431ec
9c31ed9
d943794
2031d73
911c540
2c40417
dc81810
e8511c2
eb5b1d4
0792f84
e19188d
1b01549
e67d687
e0f253b
a116ab6
2aa6f75
c3976c8
15f80d5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// Copyright 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 main | ||
|
||
import ( | ||
"github.com/bufbuild/protoplugin" | ||
"github.com/bufbuild/protoschema-plugins/internal" | ||
"github.com/bufbuild/protoschema-plugins/internal/protoschema/plugin/pluginsourceinfo" | ||
) | ||
|
||
func main() { | ||
protoplugin.Main(protoplugin.HandlerFunc(pluginsourceinfo.Handle), protoplugin.WithVersion(internal.Version())) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// Copyright 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 main | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
_ "github.com/bufbuild/protoschema-plugins/internal/gen/proto/bufext/cel/expr/conformance/proto3" | ||
"github.com/bufbuild/protoschema-plugins/internal/protoschema/golden" | ||
"github.com/bufbuild/protoschema-plugins/internal/protoschema/plugin/pluginsourceinfo" | ||
"google.golang.org/protobuf/reflect/protoreflect" | ||
) | ||
|
||
func main() { | ||
if err := run(); err != nil { | ||
if errString := err.Error(); errString != "" { | ||
_, _ = fmt.Fprintln(os.Stderr, errString) | ||
} | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
func run() error { | ||
if len(os.Args) != 2 { | ||
return fmt.Errorf("usage: %s [output dir]", os.Args[0]) | ||
} | ||
outputDir := os.Args[1] | ||
// Make sure the directory exists | ||
if err := os.MkdirAll(outputDir, 0755); err != nil { | ||
return err | ||
} | ||
|
||
testFiles, err := golden.GetTestFiles("./internal/testdata") | ||
Alfus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if err != nil { | ||
return err | ||
} | ||
// TODO: Use normal the plugin to generate golden files | ||
includePrefixes := []string{ | ||
filepath.FromSlash("buf/protoschema/test/"), | ||
filepath.FromSlash("bufext/cel/expr/conformance/proto3/"), | ||
} | ||
err = nil | ||
Alfus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
testFiles.RangeFiles(func(testDesc protoreflect.FileDescriptor) bool { | ||
if !shouldIncludeFile(testDesc, includePrefixes) { | ||
return true | ||
} | ||
fileName := pluginsourceinfo.GetSourceInfoPath(testDesc) | ||
filePath := filepath.Join(outputDir, fileName) | ||
// Create any missing directories | ||
if err = os.MkdirAll(filepath.Dir(filePath), 0755); err != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is a lambda that is reporting the error to the outter scope, it cannot use := There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then it shouldn't be set inside of an |
||
err = fmt.Errorf("failed to create directory for %s: %w", filePath, err) | ||
return false | ||
} | ||
var data []byte | ||
data, err = pluginsourceinfo.GenFileContents(testDesc) | ||
if err != nil { | ||
err = fmt.Errorf("failed to generate source info for %s: %w", testDesc.FullName(), err) | ||
return false | ||
} | ||
if err = os.WriteFile(filePath, data, 0600); err != nil { | ||
Alfus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
err = fmt.Errorf("failed to write source info to %s: %w", filePath, err) | ||
return false | ||
} | ||
return true | ||
}) | ||
return err | ||
} | ||
|
||
func shouldIncludeFile(fileDesc protoreflect.FileDescriptor, includePrefixes []string) bool { | ||
for _, prefix := range includePrefixes { | ||
if strings.HasPrefix(fileDesc.Path(), prefix) { | ||
return true | ||
} | ||
} | ||
return false | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Copyright 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 pluginsourceinfo | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/bufbuild/protoplugin" | ||
"google.golang.org/protobuf/proto" | ||
"google.golang.org/protobuf/reflect/protodesc" | ||
"google.golang.org/protobuf/reflect/protoreflect" | ||
) | ||
|
||
const FileExtension = ".sourceinfo.binpb" | ||
Alfus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// GetSourceInfoPath returns the path to the source info file for the given file descriptor. | ||
func GetSourceInfoPath(fileDescriptor protoreflect.FileDescriptor) string { | ||
path := fileDescriptor.Path() | ||
path = strings.TrimSuffix(path, ".proto") | ||
return fmt.Sprintf("%s%s", path, FileExtension) | ||
} | ||
|
||
func GenFileContents(fileDescriptor protoreflect.FileDescriptor) ([]byte, error) { | ||
// Convert the file descriptor to a descriptorpb.FileDescriptorProto. | ||
fileDescProto := protodesc.ToFileDescriptorProto(fileDescriptor) | ||
return proto.Marshal(fileDescProto.SourceCodeInfo) | ||
} | ||
|
||
// Handle implements protoplugin.Handler and is the main entry point for the plugin. | ||
func Handle( | ||
_ context.Context, | ||
_ protoplugin.PluginEnv, | ||
responseWriter protoplugin.ResponseWriter, | ||
request protoplugin.Request, | ||
) error { | ||
fileDescriptors, err := request.FileDescriptorsToGenerate() | ||
if err != nil { | ||
return err | ||
} | ||
for _, fileDescriptor := range fileDescriptors { | ||
// Write the YAML string to the response. | ||
data, err := GenFileContents(fileDescriptor) | ||
if err != nil { | ||
return err | ||
} | ||
name := GetSourceInfoPath(fileDescriptor) | ||
responseWriter.AddFile(name, string(data)) | ||
} | ||
|
||
responseWriter.SetFeatureProto3Optional() | ||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no type called
google.protobuf.SourceInfo
. Do you meangoogle.protobuf.SourceCodeInfo
? If so, this calls into question the naming of a lot of things here (package, plugin, etc).Additionally, a
SourceCodeInfo
(if this is the intent) does not make a ton sense without an associatedFileDescriptorProto
- why not make the plugin provide the entireFileDescriptorProto/FileDescriptorSet
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice typo find! I was following @jhump's naming scheme, I am happy to switch it to source code info every where if you think that would provide more clarity.
The normal code gen already comes packed with the Descriptors for normal reflection, this plugin provides just the part that is stripped out. @jhump's sourceinfo library nicely glues everything together at runtime, they same could be done in other languages.