Skip to content

Commit 8abff74

Browse files
committed
Improve plugin to handle hierarchical package names (containing dots) and spurious mentions by protoc.
When .proto files import other .proto files, protoc can invoke the plugin multiple times for the same service, but usually only one of those invocations includes the body of the service description. The plugin now avoids generating files for empty services.
1 parent d5591ca commit 8abff74

File tree

4 files changed

+64
-27
lines changed

4 files changed

+64
-27
lines changed

Plugin/Sources/protoc-gen-swiftgrpc/main.swift

Lines changed: 57 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,33 @@ import PluginLibrary
3737
import Stencil
3838
import PathKit
3939

40+
extension String {
41+
var undotted : String {
42+
return self.replacingOccurrences(of:".", with:"_")
43+
}
44+
45+
var uppercasedFirst : String {
46+
var out = self.characters
47+
if let first = out.popFirst() {
48+
return String(first).uppercased() + String(out)
49+
} else {
50+
return self
51+
}
52+
}
53+
}
54+
4055
func protoMessageName(_ name :String?) -> String {
4156
guard let name = name else {
4257
return ""
4358
}
44-
let parts = name.components(separatedBy:".")
45-
if parts.count == 3 {
46-
return parts[1].capitalized + "_" + parts[2]
47-
} else {
48-
return name
59+
let parts = name.undotted.components(separatedBy:"_")
60+
var capitalizedParts : [String] = []
61+
for part in parts {
62+
if part != "" {
63+
capitalizedParts.append(part.uppercasedFirst)
64+
}
4965
}
66+
return capitalizedParts.joined(separator:"_")
5067
}
5168

5269
func pathName(_ arguments: [Any?]) throws -> String {
@@ -96,7 +113,7 @@ func packageServiceMethodName(_ arguments: [Any?]) throws -> String {
96113
"Google_Protobuf_MethodDescriptorProto" +
97114
" argument, received \(arguments[2])")
98115
}
99-
return protoFile.package!.capitalized + "_" + service.name! + method.name!
116+
return protoFile.package!.capitalized.undotted + "_" + service.name! + method.name!
100117
}
101118

102119
func packageServiceName(_ arguments: [Any?]) throws -> String {
@@ -115,7 +132,7 @@ func packageServiceName(_ arguments: [Any?]) throws -> String {
115132
"Google_Protobuf_ServiceDescriptorProto" +
116133
" argument, received \(arguments[1])")
117134
}
118-
return protoFile.package!.capitalized + "_" + service.name!
135+
return protoFile.package!.capitalized.undotted + "_" + service.name!
119136
}
120137

121138
// Code templates use "//-" prefixes to comment-out template operators
@@ -161,6 +178,9 @@ func main() throws {
161178
ext.registerFilter("clienterror") { (value: Any?, arguments: [Any?]) in
162179
return try packageServiceName(arguments) + "ClientError"
163180
}
181+
ext.registerFilter("serviceclass") { (value: Any?, arguments: [Any?]) in
182+
return try packageServiceName(arguments) + "Service"
183+
}
164184
ext.registerFilter("servererror") { (value: Any?, arguments: [Any?]) in
165185
return try packageServiceName(arguments) + "ServerError"
166186
}
@@ -193,6 +213,8 @@ func main() throws {
193213
let rawRequest = try Stdin.readall()
194214
let request = try Google_Protobuf_Compiler_CodeGeneratorRequest(protobuf: rawRequest)
195215

216+
var generatedFileNames = Set<String>()
217+
196218
// process each .proto file separately
197219
for protoFile in request.protoFile {
198220

@@ -216,26 +238,36 @@ func main() throws {
216238
log += " Options \(service.options)\n"
217239
}
218240

241+
if protoFile.service.count > 0 {
219242
// generate separate implementation files for client and server
220243
let context = ["protoFile": protoFile]
221244

222245
do {
223-
let clientcode = try templateEnvironment.renderTemplate(name:"client.pb.swift",
224-
context: context)
225-
var clientfile = Google_Protobuf_Compiler_CodeGeneratorResponse.File()
226-
clientfile.name = package + ".client.pb.swift"
227-
clientfile.content = stripMarkers(clientcode)
228-
response.file.append(clientfile)
229-
230-
let servercode = try templateEnvironment.renderTemplate(name:"server.pb.swift",
231-
context: context)
232-
var serverfile = Google_Protobuf_Compiler_CodeGeneratorResponse.File()
233-
serverfile.name = package + ".server.pb.swift"
234-
serverfile.content = stripMarkers(servercode)
235-
response.file.append(serverfile)
246+
let clientFileName = package + ".client.pb.swift"
247+
if !generatedFileNames.contains(clientFileName) {
248+
generatedFileNames.insert(clientFileName)
249+
let clientcode = try templateEnvironment.renderTemplate(name:"client.pb.swift",
250+
context: context)
251+
var clientfile = Google_Protobuf_Compiler_CodeGeneratorResponse.File()
252+
clientfile.name = clientFileName
253+
clientfile.content = stripMarkers(clientcode)
254+
response.file.append(clientfile)
255+
}
256+
257+
let serverFileName = package + ".server.pb.swift"
258+
if !generatedFileNames.contains(serverFileName) {
259+
generatedFileNames.insert(serverFileName)
260+
let servercode = try templateEnvironment.renderTemplate(name:"server.pb.swift",
261+
context: context)
262+
var serverfile = Google_Protobuf_Compiler_CodeGeneratorResponse.File()
263+
serverfile.name = serverFileName
264+
serverfile.content = stripMarkers(servercode)
265+
response.file.append(serverfile)
266+
}
236267
} catch (let error) {
237268
log += "ERROR: \(error)\n"
238269
}
270+
}
239271
}
240272

241273
log += "\(request)"
@@ -251,4 +283,8 @@ func main() throws {
251283
Stdout.write(bytes: serializedResponse)
252284
}
253285

254-
try main()
286+
do {
287+
try main()
288+
} catch (let error) {
289+
Log("ERROR: \(error)")
290+
}

0 commit comments

Comments
 (0)