Skip to content
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
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ let products: [Product] = [
let dependencies: [Package.Dependency] = [
.package(
url: "https://github.com/grpc/grpc-swift.git",
from: "2.0.0"
from: "2.1.0"
),
.package(
url: "https://github.com/apple/swift-protobuf.git",
Expand Down
17 changes: 12 additions & 5 deletions Sources/GRPCProtobufCodeGen/ProtobufCodeGenParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,18 @@ package struct ProtobufCodeGenParser {
let extraModuleImports: [String]
let protoToModuleMappings: ProtoFileToModuleMappings
let accessLevel: CodeGenerator.Config.AccessLevel
let moduleNames: ProtobufCodeGenerator.Config.ModuleNames

package init(
protoFileModuleMappings: ProtoFileToModuleMappings,
extraModuleImports: [String],
accessLevel: CodeGenerator.Config.AccessLevel
accessLevel: CodeGenerator.Config.AccessLevel,
moduleNames: ProtobufCodeGenerator.Config.ModuleNames
) {
self.extraModuleImports = extraModuleImports
self.protoToModuleMappings = protoFileModuleMappings
self.accessLevel = accessLevel
self.moduleNames = moduleNames
}

package func parse(descriptor: FileDescriptor) throws -> CodeGenerationRequest {
Expand Down Expand Up @@ -86,10 +89,10 @@ package struct ProtobufCodeGenParser {
dependencies: self.codeDependencies(file: descriptor),
services: services,
makeSerializerCodeSnippet: { messageType in
"GRPCProtobuf.ProtobufSerializer<\(messageType)>()"
"\(self.moduleNames.grpcProtobuf).ProtobufSerializer<\(messageType)>()"
},
makeDeserializerCodeSnippet: { messageType in
"GRPCProtobuf.ProtobufDeserializer<\(messageType)>()"
"\(self.moduleNames.grpcProtobuf).ProtobufDeserializer<\(messageType)>()"
}
)
}
Expand All @@ -102,7 +105,7 @@ extension ProtobufCodeGenParser {
}

var codeDependencies: [Dependency] = [
Dependency(module: "GRPCProtobuf", accessLevel: .internal)
Dependency(module: self.moduleNames.grpcProtobuf, accessLevel: .internal)
]
// If there's a dependency on a bundled proto then add the SwiftProtobuf import.
//
Expand All @@ -113,7 +116,11 @@ extension ProtobufCodeGenParser {
}

if dependsOnBundledProto {
codeDependencies.append(Dependency(module: "SwiftProtobuf", accessLevel: self.accessLevel))
let dependency = Dependency(
module: self.moduleNames.swiftProtobuf,
accessLevel: self.accessLevel
)
codeDependencies.append(dependency)
}

// Adding as dependencies the modules containing generated code or types for
Expand Down
54 changes: 50 additions & 4 deletions Sources/GRPCProtobufCodeGen/ProtobufCodeGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ package import GRPCCodeGen
package import SwiftProtobufPluginLibrary

package struct ProtobufCodeGenerator {
internal var config: GRPCCodeGen.CodeGenerator.Config
internal var config: ProtobufCodeGenerator.Config

package init(
config: GRPCCodeGen.CodeGenerator.Config
config: ProtobufCodeGenerator.Config
) {
self.config = config
}
Expand All @@ -34,12 +34,58 @@ package struct ProtobufCodeGenerator {
let parser = ProtobufCodeGenParser(
protoFileModuleMappings: protoFileModuleMappings,
extraModuleImports: extraModuleImports,
accessLevel: self.config.accessLevel
accessLevel: self.config.accessLevel,
moduleNames: self.config.moduleNames
)
let codeGenerator = GRPCCodeGen.CodeGenerator(config: self.config)

var codeGeneratorConfig = GRPCCodeGen.CodeGenerator.Config(
accessLevel: self.config.accessLevel,
accessLevelOnImports: self.config.accessLevelOnImports,
client: self.config.generateClient,
server: self.config.generateServer,
indentation: self.config.indentation
)
codeGeneratorConfig.grpcCoreModuleName = self.config.moduleNames.grpcCore
let codeGenerator = GRPCCodeGen.CodeGenerator(config: codeGeneratorConfig)

let codeGenerationRequest = try parser.parse(descriptor: fileDescriptor)
let sourceFile = try codeGenerator.generate(codeGenerationRequest)
return sourceFile.contents
}
}

extension ProtobufCodeGenerator {
package struct Config {
package var accessLevel: GRPCCodeGen.CodeGenerator.Config.AccessLevel
package var accessLevelOnImports: Bool

package var generateClient: Bool
package var generateServer: Bool

package var indentation: Int
package var moduleNames: ModuleNames

package struct ModuleNames {
package var grpcCore: String
package var grpcProtobuf: String
package var swiftProtobuf: String

package static let defaults = Self(
grpcCore: "GRPCCore",
grpcProtobuf: "GRPCProtobuf",
swiftProtobuf: "SwiftProtobuf"
)
}

package static var defaults: Self {
Self(
accessLevel: .internal,
accessLevelOnImports: false,
generateClient: true,
generateServer: true,
indentation: 4,
moduleNames: .defaults
)
}
}
}
24 changes: 1 addition & 23 deletions Sources/protoc-gen-grpc-swift/GenerateGRPC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ final class GenerateGRPC: SwiftProtobufPluginLibrary.CodeGenerator {
fileNamingOption: options.fileNaming
)

let config = CodeGenerator.Config(options: options)
let fileGenerator = ProtobufCodeGenerator(config: config)
let fileGenerator = ProtobufCodeGenerator(config: options.config)
let contents = try fileGenerator.generateCode(
fileDescriptor: descriptor,
protoFileModuleMappings: options.protoToModuleMappings,
Expand Down Expand Up @@ -181,24 +180,3 @@ private func splitPath(pathname: String) -> (dir: String, base: String, suffix:
}
return (dir: dir, base: base, suffix: suffix)
}

extension GRPCCodeGen.CodeGenerator.Config {
init(options: GeneratorOptions) {
let accessLevel: GRPCCodeGen.CodeGenerator.Config.AccessLevel
switch options.visibility {
case .internal:
accessLevel = .internal
case .package:
accessLevel = .package
case .public:
accessLevel = .public
}

self.init(
accessLevel: accessLevel,
accessLevelOnImports: options.useAccessLevelOnImports,
client: options.generateClient,
server: options.generateServer
)
}
}
66 changes: 34 additions & 32 deletions Sources/protoc-gen-grpc-swift/Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
* limitations under the License.
*/

import GRPCCodeGen
import GRPCProtobufCodeGen
import SwiftProtobufPluginLibrary

enum GenerationError: Error, CustomStringConvertible {
Expand Down Expand Up @@ -43,35 +45,13 @@ enum FileNaming: String {
}

struct GeneratorOptions {
enum Visibility: String {
case `internal` = "Internal"
case `public` = "Public"
case `package` = "Package"

var sourceSnippet: String {
switch self {
case .internal:
return "internal"
case .public:
return "public"
case .package:
return "package"
}
}
}

private(set) var visibility = Visibility.internal

private(set) var generateServer = true
private(set) var generateClient = true

private(set) var protoToModuleMappings = ProtoFileToModuleMappings()
private(set) var fileNaming = FileNaming.fullPath
private(set) var extraModuleImports: [String] = []
private(set) var gRPCModuleName = "GRPC"
private(set) var swiftProtobufModuleName = "SwiftProtobuf"

private(set) var generateReflectionData = false
private(set) var useAccessLevelOnImports = false

private(set) var config: ProtobufCodeGenerator.Config = .defaults

init(parameter: any CodeGeneratorParameter) throws {
try self.init(pairs: parameter.parsedPairs)
Expand All @@ -81,22 +61,22 @@ struct GeneratorOptions {
for pair in pairs {
switch pair.key {
case "Visibility":
if let value = Visibility(rawValue: pair.value) {
self.visibility = value
if let value = GRPCCodeGen.CodeGenerator.Config.AccessLevel(protocOption: pair.value) {
self.config.accessLevel = value
} else {
throw GenerationError.invalidParameterValue(name: pair.key, value: pair.value)
}

case "Server":
if let value = Bool(pair.value.lowercased()) {
self.generateServer = value
self.config.generateServer = value
} else {
throw GenerationError.invalidParameterValue(name: pair.key, value: pair.value)
}

case "Client":
if let value = Bool(pair.value.lowercased()) {
self.generateClient = value
self.config.generateClient = value
} else {
throw GenerationError.invalidParameterValue(name: pair.key, value: pair.value)
}
Expand Down Expand Up @@ -129,14 +109,21 @@ struct GeneratorOptions {

case "GRPCModuleName":
if !pair.value.isEmpty {
self.gRPCModuleName = pair.value
self.config.moduleNames.grpcCore = pair.value
} else {
throw GenerationError.invalidParameterValue(name: pair.key, value: pair.value)
}

case "GRPCProtobufModuleName":
if !pair.value.isEmpty {
self.config.moduleNames.grpcProtobuf = pair.value
} else {
throw GenerationError.invalidParameterValue(name: pair.key, value: pair.value)
}

case "SwiftProtobufModuleName":
if !pair.value.isEmpty {
self.swiftProtobufModuleName = pair.value
self.config.moduleNames.swiftProtobuf = pair.value
} else {
throw GenerationError.invalidParameterValue(name: pair.key, value: pair.value)
}
Expand All @@ -150,7 +137,7 @@ struct GeneratorOptions {

case "UseAccessLevelOnImports":
if let value = Bool(pair.value.lowercased()) {
self.useAccessLevelOnImports = value
self.config.accessLevelOnImports = value
} else {
throw GenerationError.invalidParameterValue(name: pair.key, value: pair.value)
}
Expand Down Expand Up @@ -194,3 +181,18 @@ extension String.SubSequence {
return String(trimmed)
}
}

extension GRPCCodeGen.CodeGenerator.Config.AccessLevel {
fileprivate init?(protocOption value: String) {
switch value {
case "Internal":
self = .internal
case "Public":
self = .public
case "Package":
self = .package
default:
return nil
}
}
}
Binary file modified Tests/GRPCProtobufCodeGenTests/Generated/test-service.pb
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ struct ProtobufCodeGenParserTests {
@Test("Dependencies")
func dependencies() {
let expected: [GRPCCodeGen.Dependency] = [
.init(module: "GRPCProtobuf", accessLevel: .internal) // Always an internal import
.init(module: "GRPCProtobuf", accessLevel: .internal), // Always an internal import
.init(module: "SwiftProtobuf", accessLevel: .internal),
]
#expect(self.codeGen.dependencies == expected)
}
Expand Down
57 changes: 39 additions & 18 deletions Tests/GRPCProtobufCodeGenTests/ProtobufCodeGeneratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,10 @@ struct ProtobufCodeGeneratorTests {

@Test("Generate", arguments: [CodeGenerator.Config.AccessLevel.internal])
func generate(accessLevel: GRPCCodeGen.CodeGenerator.Config.AccessLevel) throws {
let generator = ProtobufCodeGenerator(
config: CodeGenerator.Config(
accessLevel: accessLevel,
accessLevelOnImports: false,
client: true,
server: true,
indentation: 2
)
)
var config = ProtobufCodeGenerator.Config.defaults
config.accessLevel = accessLevel
config.indentation = 2
let generator = ProtobufCodeGenerator(config: config)

let access: String
switch accessLevel {
Expand Down Expand Up @@ -69,6 +64,7 @@ struct ProtobufCodeGeneratorTests {

import GRPCCore
import GRPCProtobuf
import SwiftProtobuf

// MARK: - test.TestService

Expand Down Expand Up @@ -1062,6 +1058,35 @@ struct ProtobufCodeGeneratorTests {

#expect(generated == expected)
}

@Test("Generate with different module names")
func generateWithDifferentModuleNames() throws {
var config = ProtobufCodeGenerator.Config.defaults
let defaultNames = config.moduleNames

config.accessLevel = .public
config.indentation = 2
config.moduleNames.grpcCore = String(config.moduleNames.grpcCore.reversed())
config.moduleNames.grpcProtobuf = String(config.moduleNames.grpcProtobuf.reversed())
config.moduleNames.swiftProtobuf = String(config.moduleNames.swiftProtobuf.reversed())

let generator = ProtobufCodeGenerator(config: config)
let generated = try generator.generateCode(
fileDescriptor: Self.fileDescriptor,
protoFileModuleMappings: ProtoFileToModuleMappings(),
extraModuleImports: []
)

// Mustn't contain the default names.
#expect(!generated.contains(defaultNames.grpcCore))
#expect(!generated.contains(defaultNames.grpcProtobuf))
#expect(!generated.contains(defaultNames.swiftProtobuf))

// Must contain the configured names.
#expect(generated.contains(config.moduleNames.grpcCore))
#expect(generated.contains(config.moduleNames.grpcProtobuf))
#expect(generated.contains(config.moduleNames.swiftProtobuf))
}
}

@Suite("File-without-services (foo-messages.proto)")
Expand All @@ -1071,15 +1096,11 @@ struct ProtobufCodeGeneratorTests {

@Test("Generate")
func generate() throws {
let generator = ProtobufCodeGenerator(
config: CodeGenerator.Config(
accessLevel: .public,
accessLevelOnImports: false,
client: true,
server: true,
indentation: 2
)
)
var config: ProtobufCodeGenerator.Config = .defaults
config.accessLevel = .public
config.indentation = 2

let generator = ProtobufCodeGenerator(config: config)

let generated = try generator.generateCode(
fileDescriptor: Self.fileDescriptor,
Expand Down
Loading