main.swift 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /*
  2. * Copyright 2017, 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 SwiftProtobuf
  18. import SwiftProtobufPluginLibrary
  19. func Log(_ message: String) {
  20. FileHandle.standardError.write((message + "\n").data(using: .utf8)!)
  21. }
  22. // from apple/swift-protobuf/Sources/protoc-gen-swift/StringUtils.swift
  23. func splitPath(pathname: String) -> (dir: String, base: String, suffix: String) {
  24. var dir = ""
  25. var base = ""
  26. var suffix = ""
  27. #if swift(>=3.2)
  28. let pathnameChars = pathname
  29. #else
  30. let pathnameChars = pathname.characters
  31. #endif
  32. for c in pathnameChars {
  33. if c == "/" {
  34. dir += base + suffix + String(c)
  35. base = ""
  36. suffix = ""
  37. } else if c == "." {
  38. base += suffix
  39. suffix = String(c)
  40. } else {
  41. suffix += String(c)
  42. }
  43. }
  44. #if swift(>=3.2)
  45. let validSuffix = suffix.isEmpty || suffix.first == "."
  46. #else
  47. let validSuffix = suffix.isEmpty || suffix.characters.first == "."
  48. #endif
  49. if !validSuffix {
  50. base += suffix
  51. suffix = ""
  52. }
  53. return (dir: dir, base: base, suffix: suffix)
  54. }
  55. enum FileNaming: String {
  56. case FullPath
  57. case PathToUnderscores
  58. case DropPath
  59. }
  60. func outputFileName(
  61. component: String,
  62. fileDescriptor: FileDescriptor,
  63. fileNamingOption: FileNaming,
  64. extension: String
  65. ) -> String {
  66. let ext = "." + component + "." + `extension`
  67. let pathParts = splitPath(pathname: fileDescriptor.name)
  68. switch fileNamingOption {
  69. case .FullPath:
  70. return pathParts.dir + pathParts.base + ext
  71. case .PathToUnderscores:
  72. let dirWithUnderscores =
  73. pathParts.dir.replacingOccurrences(of: "/", with: "_")
  74. return dirWithUnderscores + pathParts.base + ext
  75. case .DropPath:
  76. return pathParts.base + ext
  77. }
  78. }
  79. func uniqueOutputFileName(
  80. component: String,
  81. fileDescriptor: FileDescriptor,
  82. fileNamingOption: FileNaming,
  83. generatedFiles: inout [String: Int],
  84. extension: String = "swift"
  85. ) -> String {
  86. let defaultName = outputFileName(
  87. component: component,
  88. fileDescriptor: fileDescriptor,
  89. fileNamingOption: fileNamingOption,
  90. extension: `extension`
  91. )
  92. if let count = generatedFiles[defaultName] {
  93. generatedFiles[defaultName] = count + 1
  94. return outputFileName(
  95. component: "\(count)." + component,
  96. fileDescriptor: fileDescriptor,
  97. fileNamingOption: fileNamingOption,
  98. extension: `extension`
  99. )
  100. } else {
  101. generatedFiles[defaultName] = 1
  102. return defaultName
  103. }
  104. }
  105. func printVersion(args: [String]) {
  106. // Stip off the file path
  107. let program = args.first?.split(separator: "/").last ?? "protoc-gen-grpc-swift"
  108. print("\(program) \(Version.versionString)")
  109. }
  110. func main(args: [String]) throws {
  111. if args.dropFirst().contains("--version") {
  112. printVersion(args: args)
  113. return
  114. }
  115. // initialize responses
  116. var response = Google_Protobuf_Compiler_CodeGeneratorResponse(
  117. files: [],
  118. supportedFeatures: [.proto3Optional]
  119. )
  120. // read plugin input
  121. let rawRequest = FileHandle.standardInput.readDataToEndOfFile()
  122. let request = try Google_Protobuf_Compiler_CodeGeneratorRequest(serializedData: rawRequest)
  123. let options = try GeneratorOptions(parameter: request.parameter)
  124. // Build the SwiftProtobufPluginLibrary model of the plugin input
  125. let descriptorSet = DescriptorSet(protos: request.protoFile)
  126. // A count of generated files by desired name (actual name may differ to avoid collisions).
  127. var generatedFiles: [String: Int] = [:]
  128. // Only generate output for services.
  129. for name in request.fileToGenerate {
  130. if let fileDescriptor = descriptorSet.fileDescriptor(named: name) {
  131. if (options.generateReflectionData) {
  132. var binaryFile = Google_Protobuf_Compiler_CodeGeneratorResponse.File()
  133. let binaryFileName = uniqueOutputFileName(
  134. component: "grpc.reflection",
  135. fileDescriptor: fileDescriptor,
  136. fileNamingOption: options.fileNaming,
  137. generatedFiles: &generatedFiles,
  138. extension: "txt"
  139. )
  140. let serializedFileDescriptorProto = try fileDescriptor.proto.serializedData()
  141. .base64EncodedString()
  142. binaryFile.name = binaryFileName
  143. binaryFile.content = serializedFileDescriptorProto
  144. response.file.append(binaryFile)
  145. }
  146. if (
  147. !fileDescriptor.services
  148. .isEmpty && (options.generateClient || options.generateServer)
  149. ) {
  150. var grpcFile = Google_Protobuf_Compiler_CodeGeneratorResponse.File()
  151. let grpcFileName = uniqueOutputFileName(
  152. component: "grpc",
  153. fileDescriptor: fileDescriptor,
  154. fileNamingOption: options.fileNaming,
  155. generatedFiles: &generatedFiles
  156. )
  157. let grpcGenerator = Generator(fileDescriptor, options: options)
  158. grpcFile.name = grpcFileName
  159. grpcFile.content = grpcGenerator.code
  160. response.file.append(grpcFile)
  161. }
  162. }
  163. }
  164. // return everything to the caller
  165. let serializedResponse = try response.serializedData()
  166. FileHandle.standardOutput.write(serializedResponse)
  167. }
  168. do {
  169. try main(args: CommandLine.arguments)
  170. } catch {
  171. Log("ERROR: \(error)")
  172. }