| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- /*
- * Copyright 2024, gRPC Authors All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- import Foundation
- import PackagePlugin
- struct CommandConfiguration {
- var common: CommonConfiguration
- var dryRun: Bool
- }
- extension CommandConfiguration {
- init(arguments: [String]) throws {
- self.common = CommonConfiguration()
- self.common.importPaths = []
- var dryRun: Bool?
- var arguments = arguments
- while arguments.count > 0 {
- let argument = arguments.removeFirst()
- if !argument.hasPrefix("-") {
- continue
- }
- let flag = try Flag(argument)
- guard argument.count > 0 else {
- throw PluginError.missingArgumentValue
- }
- let value = arguments.removeFirst()
- switch flag {
- case .visibility:
- switch value.lowercased() {
- case "internal":
- self.common.visibility = .`internal`
- case "public":
- self.common.visibility = .`public`
- case "package":
- self.common.visibility = .`package`
- default:
- Diagnostics.error("Unknown visibility \(value)")
- }
- case .server:
- self.common.server = .init(value)
- case .client:
- self.common.client = .init(value)
- case .message:
- self.common.message = .init(value)
- case .fileNaming:
- switch value.lowercased() {
- case "fullPath":
- self.common.fileNaming = .fullPath
- case "pathToUnderscores":
- self.common.fileNaming = .pathToUnderscores
- case "dropPath":
- self.common.fileNaming = .dropPath
- default:
- Diagnostics.error("Unknown file naming strategy \(value)")
- }
- case .protoPathModuleMappings:
- self.common.protoPathModuleMappings = value
- case .useAccessLevelOnImports:
- self.common.useAccessLevelOnImports = .init(value)
- case .importPath:
- // ! is safe because we set it to an empty array at the top of the method
- self.common.importPaths!.append(value)
- case .protocPath:
- self.common.protocPath = value
- case .output:
- self.common.outputPath = value
- case .dryRun:
- dryRun = .init(value)
- }
- }
- // defaults
- self.dryRun = dryRun ?? false
- }
- }
- func inputFiles(from arguments: [String]) -> [String] {
- var files: [String] = []
- var arguments = arguments
- while arguments.count > 0 {
- let argument = arguments.removeFirst()
- if argument.hasPrefix("-") {
- _ = arguments.removeFirst() // also discard the value
- continue // discard the flag
- }
- files.append(argument)
- }
- return files
- }
- extension Bool {
- private init(_ string: String) {
- switch string.lowercased() {
- case "true":
- self = true
- case "false":
- self = false
- default:
- Diagnostics.error("Unknown boolean \(string)")
- self = false
- }
- }
- }
- enum Flag: CaseIterable {
- case visibility
- case server
- case client
- case message
- case fileNaming
- case protoPathModuleMappings
- case useAccessLevelOnImports
- case importPath
- case protocPath
- case output
- case dryRun
- init(_ argument: String) throws {
- switch argument {
- case "--visibility":
- self = .visibility
- case "--server":
- self = .server
- case "--client":
- self = .client
- case "--message":
- self = .message
- case "--file-naming":
- self = .fileNaming
- case "--proto-path-module-mappings":
- self = .protoPathModuleMappings
- case "--use-access-level-on-imports":
- self = .useAccessLevelOnImports
- case "--import-path", "-I":
- self = .importPath
- case "--protoc-path":
- self = .protocPath
- case "--output":
- self = .output
- case "--dry-run":
- self = .dryRun
- case "--help":
- throw PluginError.helpRequested
- default:
- Diagnostics.error("Unknown flag \(argument)")
- throw PluginError.unknownOption(argument)
- }
- }
- }
- extension Flag {
- func usageDescription() -> String {
- switch self {
- case .visibility:
- return "--visibility The visibility of the generated files."
- case .server:
- return "--server Whether server code is generated."
- case .client:
- return "--client Whether client code is generated."
- case .message:
- return "--message Whether message code is generated."
- case .fileNaming:
- return
- "--file-naming The naming of output files with respect to the path of the source file."
- case .protoPathModuleMappings:
- return "--proto-path-module-mappings Path to module map .asciipb file."
- case .useAccessLevelOnImports:
- return "--use-access-level-on-imports Whether imports should have explicit access levels."
- case .importPath:
- return "--import-path The directory in which to search for imports."
- case .protocPath:
- return "--protoc-path The path to the `protoc` binary."
- case .dryRun:
- return "--dry-run Print but do not execute the protoc commands."
- case .output:
- return
- "--output The path into which the generated source files are created."
- }
- }
- static func printHelp() {
- print("Usage: swift package generate-grpc-code-from-protos [flags] [input files]")
- print("")
- print("Flags:")
- print("")
- for flag in Flag.allCases { print(" \(flag.usageDescription())") }
- print("")
- print(" --help Print this help.")
- }
- }
|