ConfigurationArguments.swift 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*
  2. * Copyright 2024, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import Foundation
  17. import PackagePlugin
  18. struct CommandConfiguration {
  19. var common: CommonConfiguration
  20. var dryRun: Bool
  21. }
  22. extension CommandConfiguration {
  23. init(arguments: [String]) throws {
  24. self.common = CommonConfiguration()
  25. self.common.importPaths = []
  26. var dryRun: Bool?
  27. var arguments = arguments
  28. while arguments.count > 0 {
  29. let argument = arguments.removeFirst()
  30. if !argument.hasPrefix("-") {
  31. continue
  32. }
  33. let flag = try Flag(argument)
  34. guard argument.count > 0 else {
  35. throw PluginError.missingArgumentValue
  36. }
  37. let value = arguments.removeFirst()
  38. switch flag {
  39. case .visibility:
  40. switch value.lowercased() {
  41. case "internal":
  42. self.common.visibility = .`internal`
  43. case "public":
  44. self.common.visibility = .`public`
  45. case "package":
  46. self.common.visibility = .`package`
  47. default:
  48. Diagnostics.error("Unknown visibility \(value)")
  49. }
  50. case .server:
  51. self.common.server = .init(value)
  52. case .client:
  53. self.common.client = .init(value)
  54. case .message:
  55. self.common.message = .init(value)
  56. case .fileNaming:
  57. switch value.lowercased() {
  58. case "fullPath":
  59. self.common.fileNaming = .fullPath
  60. case "pathToUnderscores":
  61. self.common.fileNaming = .pathToUnderscores
  62. case "dropPath":
  63. self.common.fileNaming = .dropPath
  64. default:
  65. Diagnostics.error("Unknown file naming strategy \(value)")
  66. }
  67. case .protoPathModuleMappings:
  68. self.common.protoPathModuleMappings = value
  69. case .useAccessLevelOnImports:
  70. self.common.useAccessLevelOnImports = .init(value)
  71. case .importPath:
  72. // ! is safe because we set it to an empty array at the top of the method
  73. self.common.importPaths!.append(value)
  74. case .protocPath:
  75. self.common.protocPath = value
  76. case .output:
  77. self.common.outputPath = value
  78. case .dryRun:
  79. dryRun = .init(value)
  80. }
  81. }
  82. // defaults
  83. self.dryRun = dryRun ?? false
  84. }
  85. }
  86. func inputFiles(from arguments: [String]) -> [String] {
  87. var files: [String] = []
  88. var arguments = arguments
  89. while arguments.count > 0 {
  90. let argument = arguments.removeFirst()
  91. if argument.hasPrefix("-") {
  92. _ = arguments.removeFirst() // also discard the value
  93. continue // discard the flag
  94. }
  95. files.append(argument)
  96. }
  97. return files
  98. }
  99. extension Bool {
  100. private init(_ string: String) {
  101. switch string.lowercased() {
  102. case "true":
  103. self = true
  104. case "false":
  105. self = false
  106. default:
  107. Diagnostics.error("Unknown boolean \(string)")
  108. self = false
  109. }
  110. }
  111. }
  112. enum Flag: CaseIterable {
  113. case visibility
  114. case server
  115. case client
  116. case message
  117. case fileNaming
  118. case protoPathModuleMappings
  119. case useAccessLevelOnImports
  120. case importPath
  121. case protocPath
  122. case output
  123. case dryRun
  124. init(_ argument: String) throws {
  125. switch argument {
  126. case "--visibility":
  127. self = .visibility
  128. case "--server":
  129. self = .server
  130. case "--client":
  131. self = .client
  132. case "--message":
  133. self = .message
  134. case "--file-naming":
  135. self = .fileNaming
  136. case "--proto-path-module-mappings":
  137. self = .protoPathModuleMappings
  138. case "--use-access-level-on-imports":
  139. self = .useAccessLevelOnImports
  140. case "--import-path", "-I":
  141. self = .importPath
  142. case "--protoc-path":
  143. self = .protocPath
  144. case "--output":
  145. self = .output
  146. case "--dry-run":
  147. self = .dryRun
  148. case "--help":
  149. throw PluginError.helpRequested
  150. default:
  151. Diagnostics.error("Unknown flag \(argument)")
  152. throw PluginError.unknownOption(argument)
  153. }
  154. }
  155. }
  156. extension Flag {
  157. func usageDescription() -> String {
  158. switch self {
  159. case .visibility:
  160. return "--visibility The visibility of the generated files."
  161. case .server:
  162. return "--server Whether server code is generated."
  163. case .client:
  164. return "--client Whether client code is generated."
  165. case .message:
  166. return "--message Whether message code is generated."
  167. case .fileNaming:
  168. return
  169. "--file-naming The naming of output files with respect to the path of the source file."
  170. case .protoPathModuleMappings:
  171. return "--proto-path-module-mappings Path to module map .asciipb file."
  172. case .useAccessLevelOnImports:
  173. return "--use-access-level-on-imports Whether imports should have explicit access levels."
  174. case .importPath:
  175. return "--import-path The directory in which to search for imports."
  176. case .protocPath:
  177. return "--protoc-path The path to the `protoc` binary."
  178. case .dryRun:
  179. return "--dry-run Print but do not execute the protoc commands."
  180. case .output:
  181. return
  182. "--output The path into which the generated source files are created."
  183. }
  184. }
  185. static func printHelp() {
  186. print("Usage: swift package generate-grpc-code-from-protos [flags] [input files]")
  187. print("")
  188. print("Flags:")
  189. print("")
  190. for flag in Flag.allCases { print(" \(flag.usageDescription())") }
  191. print("")
  192. print(" --help Print this help.")
  193. }
  194. }