Skip to content

Commit 585e856

Browse files
committed
review comments, rethink config & imports
1 parent 87197c6 commit 585e856

File tree

5 files changed

+317
-201
lines changed

5 files changed

+317
-201
lines changed

Plugins/GRPCProtobufGenerator/BuildPluginConfig.swift

Lines changed: 167 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -18,110 +18,193 @@ import Foundation
1818

1919
let configFileName = "grpc-swift-proto-generator-config.json"
2020

21-
/// The configuration of the build plugin.
21+
/// The config of the build plugin.
2222
struct BuildPluginConfig: Codable {
23-
/// The visibility of the generated files.
24-
///
25-
/// Defaults to `Internal`.
26-
var visibility: GenerationConfig.Visibility
27-
/// Whether server code is generated.
28-
///
29-
/// Defaults to `true`.
30-
var server: Bool
31-
/// Whether client code is generated.
32-
///
33-
/// Defaults to `true`.
34-
var client: Bool
35-
/// Whether message code is generated.
36-
///
37-
/// Defaults to `true`.
38-
var message: Bool
39-
/// Whether imports should have explicit access levels.
40-
///
41-
/// Defaults to `false`.
42-
var useAccessLevelOnImports: Bool
43-
44-
/// Specify the directory in which to search for imports.
45-
///
46-
/// Paths are relative to the location of the specifying config file.
47-
/// Build plugins only have access to files within the target's source directory.
48-
/// May be specified multiple times; directories will be searched in order.
49-
/// The target source directory is always appended
50-
/// to the import paths.
51-
var importPaths: [String]
52-
53-
/// The path to the `protoc` binary.
54-
///
55-
/// If this is not set, Swift Package Manager will try to find the tool itself.
56-
var protocPath: String?
23+
/// Config defining which components should be considered when generating source.
24+
struct Generate {
25+
/// Whether server code is generated.
26+
///
27+
/// Defaults to `true`.
28+
var servers: Bool
29+
/// Whether client code is generated.
30+
///
31+
/// Defaults to `true`.
32+
var clients: Bool
33+
/// Whether message code is generated.
34+
///
35+
/// Defaults to `true`.
36+
var messages: Bool
37+
38+
static let defaults = Self(
39+
servers: true,
40+
clients: true,
41+
messages: true
42+
)
43+
44+
private init(servers: Bool, clients: Bool, messages: Bool) {
45+
self.servers = servers
46+
self.clients = clients
47+
self.messages = messages
48+
}
49+
}
50+
51+
/// Config relating to the generated code itself.
52+
struct GeneratedSource {
53+
/// The visibility of the generated files.
54+
///
55+
/// Defaults to `Internal`.
56+
var accessLevel: GenerationConfig.AccessLevel
57+
/// Whether imports should have explicit access levels.
58+
///
59+
/// Defaults to `false`.
60+
var useAccessLevelOnImports: Bool
61+
62+
static let defaults = Self(
63+
accessLevel: .internal,
64+
useAccessLevelOnImports: false
65+
)
66+
67+
private init(accessLevel: GenerationConfig.AccessLevel, useAccessLevelOnImports: Bool) {
68+
self.accessLevel = accessLevel
69+
self.useAccessLevelOnImports = useAccessLevelOnImports
70+
}
71+
}
72+
73+
/// Config relating to the protoc invocation.
74+
struct Protoc {
75+
/// Specify the directory in which to search for imports.
76+
///
77+
/// Paths are relative to the location of the specifying config file.
78+
/// Build plugins only have access to files within the target's source directory.
79+
/// May be specified multiple times; directories will be searched in order.
80+
/// The target source directory is always appended
81+
/// to the import paths.
82+
var importPaths: [String]
83+
84+
/// The path to the `protoc` executable binary.
85+
///
86+
/// If this is not set, Swift Package Manager will try to find the tool itself.
87+
var executablePath: String?
88+
89+
static let defaults = Self(
90+
importPaths: [],
91+
executablePath: nil
92+
)
93+
94+
private init(importPaths: [String], executablePath: String?) {
95+
self.importPaths = importPaths
96+
self.executablePath = executablePath
97+
}
98+
}
99+
100+
/// Config defining which components should be considered when generating source.
101+
var generate: Generate
102+
/// Config relating to the nature of the generated code.
103+
var generatedSource: GeneratedSource
104+
/// Config relating to the protoc invocation.
105+
var protoc: Protoc
106+
107+
static let defaults = Self(
108+
generate: Generate.defaults,
109+
generatedSource: GeneratedSource.defaults,
110+
protoc: Protoc.defaults
111+
)
112+
private init(generate: Generate, generatedSource: GeneratedSource, protoc: Protoc) {
113+
self.generate = generate
114+
self.generatedSource = generatedSource
115+
self.protoc = protoc
116+
}
57117

58118
// Codable conformance with defaults
59119
enum CodingKeys: String, CodingKey {
60-
case visibility
61-
case server
62-
case client
63-
case message
64-
case useAccessLevelOnImports
65-
case importPaths
66-
case protocPath
120+
case generate
121+
case generatedSource
122+
case protoc
123+
}
124+
125+
init(from decoder: any Decoder) throws {
126+
let container = try decoder.container(keyedBy: CodingKeys.self)
127+
128+
self.generate =
129+
try container.decodeIfPresent(Generate.self, forKey: .generate) ?? Self.defaults.generate
130+
self.generatedSource =
131+
try container.decodeIfPresent(GeneratedSource.self, forKey: .generatedSource)
132+
?? Self.defaults.generatedSource
133+
self.protoc =
134+
try container.decodeIfPresent(Protoc.self, forKey: .protoc) ?? Self.defaults.protoc
135+
}
136+
}
137+
138+
extension BuildPluginConfig.Generate: Codable {
139+
// Codable conformance with defaults
140+
enum CodingKeys: String, CodingKey {
141+
case servers
142+
case clients
143+
case messages
144+
}
145+
146+
init(from decoder: any Decoder) throws {
147+
let container = try decoder.container(keyedBy: CodingKeys.self)
148+
149+
self.servers =
150+
try container.decodeIfPresent(Bool.self, forKey: .servers) ?? Self.defaults.servers
151+
self.clients =
152+
try container.decodeIfPresent(Bool.self, forKey: .clients) ?? Self.defaults.clients
153+
self.messages =
154+
try container.decodeIfPresent(Bool.self, forKey: .messages) ?? Self.defaults.messages
67155
}
156+
}
68157

69-
let defaultVisibility: GenerationConfig.Visibility = .internal
70-
let defaultServer = true
71-
let defaultClient = true
72-
let defaultMessage = true
73-
let defaultUseAccessLevelOnImports = false
74-
let defaultImportPaths: [String] = []
158+
extension BuildPluginConfig.GeneratedSource: Codable {
159+
// Codable conformance with defaults
160+
enum CodingKeys: String, CodingKey {
161+
case accessLevel
162+
case useAccessLevelOnImports
163+
}
75164

76165
init(from decoder: any Decoder) throws {
77166
let container = try decoder.container(keyedBy: CodingKeys.self)
78167

79-
self.visibility =
80-
try container.decodeIfPresent(GenerationConfig.Visibility.self, forKey: .visibility)
81-
?? defaultVisibility
82-
self.server = try container.decodeIfPresent(Bool.self, forKey: .server) ?? defaultServer
83-
self.client = try container.decodeIfPresent(Bool.self, forKey: .client) ?? defaultClient
84-
self.message = try container.decodeIfPresent(Bool.self, forKey: .message) ?? defaultMessage
168+
self.accessLevel =
169+
try container.decodeIfPresent(GenerationConfig.AccessLevel.self, forKey: .accessLevel)
170+
?? Self.defaults.accessLevel
85171
self.useAccessLevelOnImports =
86172
try container.decodeIfPresent(Bool.self, forKey: .useAccessLevelOnImports)
87-
?? defaultUseAccessLevelOnImports
173+
?? Self.defaults.useAccessLevelOnImports
174+
}
175+
}
176+
177+
extension BuildPluginConfig.Protoc: Codable {
178+
// Codable conformance with defaults
179+
enum CodingKeys: String, CodingKey {
180+
case importPaths
181+
case executablePath
182+
}
183+
184+
init(from decoder: any Decoder) throws {
185+
let container = try decoder.container(keyedBy: CodingKeys.self)
186+
88187
self.importPaths =
89-
try container.decodeIfPresent([String].self, forKey: .importPaths) ?? defaultImportPaths
90-
self.protocPath = try container.decodeIfPresent(String.self, forKey: .protocPath)
188+
try container.decodeIfPresent([String].self, forKey: .importPaths)
189+
?? Self.defaults.importPaths
190+
self.executablePath = try container.decodeIfPresent(String.self, forKey: .executablePath)
91191
}
92192
}
93193

94194
extension GenerationConfig {
95-
init(configurationFile: BuildPluginConfig, configurationFilePath: URL, outputPath: URL) {
96-
self.visibility = configurationFile.visibility
97-
self.server = configurationFile.server
98-
self.client = configurationFile.client
99-
self.message = configurationFile.message
195+
init(buildPluginConfig: BuildPluginConfig, configFilePath: URL, outputPath: URL) {
196+
self.server = buildPluginConfig.generate.servers
197+
self.client = buildPluginConfig.generate.clients
198+
self.message = buildPluginConfig.generate.messages
100199
// hard-code full-path to avoid collisions since this goes into a temporary directory anyway
101200
self.fileNaming = .fullPath
102-
self.useAccessLevelOnImports = configurationFile.useAccessLevelOnImports
103-
self.importPaths = []
104-
201+
self.visibility = buildPluginConfig.generatedSource.accessLevel
202+
self.useAccessLevelOnImports = buildPluginConfig.generatedSource.useAccessLevelOnImports
105203
// Generate absolute paths for the imports relative to the config file in which they are specified
106-
self.importPaths = configurationFile.importPaths.map { relativePath in
107-
configurationFilePath.deletingLastPathComponent().relativePath + "/" + relativePath
108-
}
109-
self.protocPath = configurationFile.protocPath
110-
self.outputPath = outputPath.relativePath
111-
}
112-
}
113-
114-
extension GenerationConfig.Visibility: Codable {
115-
init?(rawValue: String) {
116-
switch rawValue.lowercased() {
117-
case "internal":
118-
self = .internal
119-
case "public":
120-
self = .public
121-
case "package":
122-
self = .package
123-
default:
124-
return nil
204+
self.importPaths = buildPluginConfig.protoc.importPaths.map { relativePath in
205+
configFilePath.deletingLastPathComponent().absoluteStringNoScheme + "/" + relativePath
125206
}
207+
self.protocPath = buildPluginConfig.protoc.executablePath
208+
self.outputPath = outputPath.absoluteStringNoScheme
126209
}
127210
}

0 commit comments

Comments
 (0)