Skip to content

Conversation

@stefanadranca
Copy link
Collaborator

Motivation:

We need the parser to transform a FileDescriptor object into a CodeGenerationRequest objet which can be used as input in the new code generation process.

Modifications:

  • Created the parser struct
  • Created a test for the type

Result:

FileDescriptors can now be transformed into CodeGenerationRequest, which will
be useful in implementing the protoc-gen-grpc-swift v2.

Motivation:

We need the parser to transform a FileDescriptor object into a CodeGenerationRequest objet which can be used as input in the new code generation process.

Modifications:

- Created the parser struct
- Created a test for the type

Result:

FileDescriptors can now be transformed into CodeGenerationRequest, which will
be useful in implementing the `protoc-gen-grpc-swift` v2.
Comment on lines 29 to 41
var documentation = String()
// Field number used to collect .proto file comments.
let documentationPath = IndexPath(index: 12)
if let syntaxLocation = input.sourceCodeInfoLocation(path: documentationPath) {
documentation = syntaxLocation.asSourceComment(
commentPrefix: "///",
leadingDetachedPrefix: "//"
)
// If the was a leading or tailing comment it won't have a blank
// line, after it, so ensure there is one.
if !documentation.isEmpty && !documentation.hasSuffix("\n\n") {
documentation.append("\n")
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part is taken from here https://github.com/apple/swift-protobuf/blob/ea9ac1c4831d14118372ce7e1dcebd142c74e7f3/Sources/protoc-gen-swift/FileGenerator.swift#L71. Apparently there are fixed path numbers for different things that appear in a proto file - 12 is for the header. Should I add to NOTICES that I've used this small piece of code from SwiftProtobuf or should I add some link in the comment above the line containing the index?

@stefanadranca stefanadranca requested a review from glbrntt January 24, 2024 16:03
@stefanadranca stefanadranca marked this pull request as ready for review January 24, 2024 16:33
@stefanadranca stefanadranca requested a review from gjcairo January 24, 2024 16:34
@@ -0,0 +1,122 @@
/*
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be in this module, this module is for protobuf components which are used at runtime (i.e. when running a client or server). This is used at code generation time so should be in its own module.

import struct GRPCCodeGen.CodeGenerationRequest

/// Parses a ``FileDescriptor`` object into a ``CodeGenerationRequest`` object.
public struct InputParser {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can use a more specific name here.

Comment on lines 29 to 42
var header = String()
// Field number used to collect the .proto file header.
let headerPath = IndexPath(index: 12)
if let headerLocation = input.sourceCodeInfoLocation(path: headerPath) {
header = headerLocation.asSourceComment(
commentPrefix: "///",
leadingDetachedPrefix: "//"
)
// If the was a leading or tailing comment it won't have a blank
// line, after it, so ensure there is one.
if !header.isEmpty && !header.hasSuffix("\n\n") {
header.append("\n")
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would make more sense as an extension on FileDescriptor

Comment on lines 44 to 51
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: \(fileName)
//
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/\n\n
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is from Swift Protobuf and points to the protobuf docs which isn't right.

Comment on lines 53 to 55
let dependencies = input.dependencies.map {
CodeGenerationRequest.Dependency(module: $0.name)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dependencies should include GRPCProtobuf as well because that's where the serializer/deserializer are imported from.

)
}

fileprivate func createCodeGenerationServices(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use make instead of create (https://www.swift.org/documentation/api-design-guidelines/#strive-for-fluent-usage), also this creates service descriptors, not services

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general though, I think this is worth moving these to be conversion functions on the init of the descriptors, it makes them much easier to test in isolation:

extension CodeGenerationRequest.ServiceDescriptor {
  init(descriptor: ServiceDescriptor, package: String) {
    // ...
  }
}

extension CodeGenerationRequest.ServiceDescriptor.MethodDescriptor {
  init(descriptor: ServiceDescriptor.MethodDescriptor) {
    // ...
  }
}

Then this function boils down to something like:

let descriptors = input.services.map { descriptor in 
  CoreGenerationRequest.ServiceDescriptor(descriptor: descriptor, package: package)
}

Comment on lines 39 to 46
// Copyright 2015 gRPC authors.\n//\n// Licensed under the Apache License, \
Version 2.0 (the \"License\");\n// you may not use this file except in \
compliance with the License.\n// You may obtain a copy of the License \
at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by \
applicable law or agreed to in writing, software\n// distributed under \
the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES \
OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License \
for the specific language governing permissions and\n// limitations under the License.\n\n
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this somewhat misses the point of multiline string literals..., you don't need to put in "\n" manually, you just write the text as you'd like it. The \ at the end of each line stops the newline being inserted.

See https://docs.swift.org/swift-book/documentation/the-swift-programming-language/stringsandcharacters#Multiline-String-Literals

)
}

var dummyFileDescriptor: FileDescriptor {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not really a dummy file descriptor, it's the hello world file descriptor

Comment on lines 62 to 65
XCTAssertEqual(
parsedCodeGenRequest.services[0].methods[0].documentation,
"/// Sends a greeting.\n"
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we pull out the first service? I.e. guard let service = request.services.first else { return XCTFail() }

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also we should validate the number of services and methods is as expected

@stefanadranca stefanadranca requested a review from glbrntt January 25, 2024 17:18
Package.swift Outdated
static let reflectionService: Self = .target(name: "GRPCReflectionService")
static let grpcCodeGen: Self = .target(name: "GRPCCodeGen")
static let grpcProtobuf: Self = .target(name: "GRPCProtobuf")
static let grpcProtobufParser: Self = .target(name: "GRPCProtobufParser")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we call this GRPCProtobufCodeGen -- it will do more than parsing

// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Generated by the gRPC Swift generator plugin for the protocol buffer compiler.

// Source: \(input.name)
//
// For information on using the generated types, please see the documentation:
// https://github.com/grpc/grpc-swift\n\n
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// https://github.com/grpc/grpc-swift\n\n
// https://github.com/grpc/grpc-swift
```

}

extension FileDescriptor {
fileprivate func getHeader() -> String {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you have get in your name you probably want a computed property instead...

Comment on lines 115 to 118
// Ensuring there is a blank line after the header.
if !header.isEmpty && !header.hasSuffix("\n\n") {
header.append("\n")
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic is separate from getting the header, looks like it should be in parse

// 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,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// distributed under the License is distributed on an \"AS IS\" BASIS,
// distributed under the License is distributed on an "AS IS" BASIS,


return CodeGenerationRequest(
fileName: input.name,
leadingTrivia: leadingTrivia + header,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be the other way around, any copyright header etc. should come first

Comment on lines 55 to 56
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want all this whitespace in the leading trivia.

import struct GRPCCodeGen.CodeGenerationRequest

/// Parses a ``FileDescriptor`` object into a ``CodeGenerationRequest`` object.
public struct ProtobufToCodeGenParser {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given we now have this extra module we can put more of the logic in it when constructing protoc-gen-grpc-swift, and have protoc-gen-grpc-swift basically do nothing apart from parsing the options and calling the generator we provide in this module. The upshot of this is that I don't think this type needs to be public.

Comment on lines 48 to 50
let services = input.services.map {
CodeGenerationRequest.ServiceDescriptor(descriptor: $0, package: input.package)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole flow is much easier to follow!

@stefanadranca stefanadranca merged commit 373d9f4 into grpc:main Jan 29, 2024
glbrntt added a commit to glbrntt/grpc-swift that referenced this pull request Feb 5, 2024
…est (grpc#1772)

Motivation:

We need the parser to transform a FileDescriptor object into a CodeGenerationRequest objet which can be used as input in the new code generation process.

Modifications:

- Created the parser struct
- Created a test for the type

Result:

FileDescriptors can now be transformed into CodeGenerationRequest, which will
be useful in implementing the `protoc-gen-grpc-swift` v2.


---------

Co-authored-by: George Barnett <gbarnett@apple.com>
@glbrntt glbrntt added the version/v2 Relates to v2 label Feb 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

version/v2 Relates to v2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants