PluginUtils.swift 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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. /// Derive the path to the instance of `protoc` to be used.
  19. /// - Parameters:
  20. /// - config: The supplied config. If no path is supplied then one is discovered using the `PROTOC_PATH` environment variable or the `findTool`.
  21. /// - findTool: The context-supplied tool which is used to attempt to discover the path to a `protoc` binary.
  22. /// - Returns: The path to the instance of `protoc` to be used.
  23. func deriveProtocPath(
  24. using config: GenerationConfig,
  25. tool findTool: (String) throws -> PackagePlugin.PluginContext.Tool
  26. ) throws -> URL {
  27. if let configuredProtocPath = config.protocPath {
  28. return URL(fileURLWithPath: configuredProtocPath)
  29. } else if let environmentPath = ProcessInfo.processInfo.environment["PROTOC_PATH"] {
  30. // The user set the env variable, so let's take that
  31. return URL(fileURLWithPath: environmentPath)
  32. } else {
  33. // The user didn't set anything so let's try see if Swift Package Manager can find a binary for us
  34. return try findTool("protoc").url
  35. }
  36. }
  37. /// Construct the arguments to be passed to `protoc` when invoking the `protoc-gen-swift` `protoc` plugin.
  38. /// - Parameters:
  39. /// - config: The config for this operation.
  40. /// - fileNaming: The file naming scheme to be used.
  41. /// - inputFiles: The input `.proto` files.
  42. /// - protoDirectoryPaths: The directories in which `protoc` will look for imports.
  43. /// - protocGenSwiftPath: The path to the `protoc-gen-swift` `protoc` plugin.
  44. /// - outputDirectory: The directory in which generated source files are created.
  45. /// - Returns: The constructed arguments to be passed to `protoc` when invoking the `protoc-gen-swift` `protoc` plugin.
  46. func constructProtocGenSwiftArguments(
  47. config: GenerationConfig,
  48. fileNaming: GenerationConfig.FileNaming?,
  49. inputFiles: [URL],
  50. protoDirectoryPaths: [String],
  51. protocGenSwiftPath: URL,
  52. outputDirectory: URL
  53. ) -> [String] {
  54. var protocArgs = [
  55. "--plugin=protoc-gen-swift=\(protocGenSwiftPath.absoluteStringNoScheme)",
  56. "--swift_out=\(outputDirectory.absoluteStringNoScheme)",
  57. ]
  58. for path in protoDirectoryPaths {
  59. protocArgs.append("--proto_path=\(path)")
  60. }
  61. protocArgs.append("--swift_opt=Visibility=\(config.visibility.rawValue)")
  62. protocArgs.append("--swift_opt=FileNaming=\(config.fileNaming.rawValue)")
  63. protocArgs.append("--swift_opt=UseAccessLevelOnImports=\(config.accessLevelOnImports)")
  64. protocArgs.append(contentsOf: inputFiles.map { $0.absoluteStringNoScheme })
  65. return protocArgs
  66. }
  67. /// Construct the arguments to be passed to `protoc` when invoking the `protoc-gen-grpc-swift` `protoc` plugin.
  68. /// - Parameters:
  69. /// - config: The config for this operation.
  70. /// - fileNaming: The file naming scheme to be used.
  71. /// - inputFiles: The input `.proto` files.
  72. /// - protoDirectoryPaths: The directories in which `protoc` will look for imports.
  73. /// - protocGenGRPCSwiftPath: The path to the `protoc-gen-grpc-swift` `protoc` plugin.
  74. /// - outputDirectory: The directory in which generated source files are created.
  75. /// - Returns: The constructed arguments to be passed to `protoc` when invoking the `protoc-gen-grpc-swift` `protoc` plugin.
  76. func constructProtocGenGRPCSwiftArguments(
  77. config: GenerationConfig,
  78. fileNaming: GenerationConfig.FileNaming?,
  79. inputFiles: [URL],
  80. protoDirectoryPaths: [String],
  81. protocGenGRPCSwiftPath: URL,
  82. outputDirectory: URL
  83. ) -> [String] {
  84. var protocArgs = [
  85. "--plugin=protoc-gen-grpc-swift=\(protocGenGRPCSwiftPath.absoluteStringNoScheme)",
  86. "--grpc-swift_out=\(outputDirectory.absoluteStringNoScheme)",
  87. ]
  88. for path in protoDirectoryPaths {
  89. protocArgs.append("--proto_path=\(path)")
  90. }
  91. protocArgs.append("--grpc-swift_opt=Visibility=\(config.visibility.rawValue.capitalized)")
  92. protocArgs.append("--grpc-swift_opt=Server=\(config.server)")
  93. protocArgs.append("--grpc-swift_opt=Client=\(config.client)")
  94. protocArgs.append("--grpc-swift_opt=FileNaming=\(config.fileNaming.rawValue)")
  95. protocArgs.append("--grpc-swift_opt=UseAccessLevelOnImports=\(config.accessLevelOnImports)")
  96. protocArgs.append(contentsOf: inputFiles.map { $0.absoluteStringNoScheme })
  97. return protocArgs
  98. }
  99. extension URL {
  100. /// Returns `URL.absoluteString` with the `file://` scheme prefix removed
  101. ///
  102. /// Note: This method also removes percent-encoded UTF-8 characters
  103. var absoluteStringNoScheme: String {
  104. var absoluteString = self.absoluteString.removingPercentEncoding ?? self.absoluteString
  105. absoluteString.trimPrefix("file://")
  106. return absoluteString
  107. }
  108. }