Generator/Sources/needle/GenerateCommand.swift (72 lines of code) (raw):

// // Copyright (c) 2018. Uber Technologies // // 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 CommandFramework import Foundation import NeedleFramework import SourceParsingFramework import TSCUtility /// The generate command provides the core functionality of needle. It parses /// Swift source files by recurively scan the directories starting from the /// specified source path, excluding files with specified suffixes. It then /// generates the necessary dependency provider code and export to the specified /// destination path. class GenerateCommand: AbstractCommand { /// Initializer. /// /// - parameter parser: The argument parser to use. init(parser: ArgumentParser) { super.init(name: "generate", overview: "Generate DI code based on Swift source files in a directory or listed in a single text file.", parser: parser) } /// Setup the arguments using the given parser. /// /// - parameter parser: The argument parser to use. override func setupArguments(with parser: ArgumentParser) { super.setupArguments(with: parser) destinationPath = parser.add(positional: "destinationPath", kind: String.self, usage: "Path to the destination file of generated Swift DI code.", completion: .filename) sourceRootPaths = parser.add(positional: "sourceRootPaths", kind: [String].self, strategy: ArrayParsingStrategy.upToNextOption, usage: "Paths to the root folders of Swift source files, or text files containing paths of Swift source files with specified format.", completion: .filename) sourcesListFormat = parser.add(option: "--sources-list-format", kind: String.self, usage: "The format of the Swift sources list file. See SourcesListFileFormat for supported format details", completion: .filename) excludeSuffixes = parser.add(option: "--exclude-suffixes", kind: [String].self, usage: "Filename suffix(es) without extensions to exclude from parsing.", completion: .filename) excludePaths = parser.add(option: "--exclude-paths", kind: [String].self, usage: "Paths components to exclude from parsing.") scanPlugins = parser.add(option: "--pluginized", kind: Bool.self, usage: "Whether or not to consider plugins when parsing.") additionalImports = parser.add(option: "--additional-imports", kind: [String].self, usage: "Additional modules to import in the generated file, in addition to the ones parsed from source files.", completion: ShellCompletion.none) headerDocPath = parser.add(option: "--header-doc", kind: String.self, usage: "Path to custom header doc file to be included at the top of the generated file.", completion: .filename) shouldCollectParsingInfo = parser.add(option: "--collect-parsing-info", shortName: "-cpi", kind: Bool.self, usage: "Whether or not to collect information for parsing execution timeout errors.") parsingTimeout = parser.add(option: "--parsing-timeout", kind: Int.self, usage: "The timeout value, in seconds, to use for waiting on parsing tasks.") exportingTimeout = parser.add(option: "--exporting-timeout", kind: Int.self, usage: "The timeout value, in seconds, to use for waiting on exporting tasks.") retryParsingOnTimeoutLimit = parser.add(option: "--retry-parsing-limit", kind: Int.self, usage: "The maximum number of times parsing Swift source files should be retried in case of timeouts.") concurrencyLimit = parser.add(option: "--concurrency-limit", kind: Int.self, usage: "The maximum number of tasks to execute concurrently.") emitInputsDepsFile = parser.add(option: "--emit-input-deps-file", kind: Bool.self, usage: "Emit a file that contains all inputs of the Needle generator invocation. This option only works if pluginized") } /// Execute the command. /// /// - parameter arguments: The command line arguments to execute the /// command with. override func execute(with arguments: ArgumentParser.Result) { super.execute(with: arguments) if let destinationPath = arguments.get(destinationPath) { if let sourceRootPaths = arguments.get(sourceRootPaths) { let sourcesListFormat = arguments.get(self.sourcesListFormat) ?? nil let excludeSuffixes = arguments.get(self.excludeSuffixes) ?? [] let excludePaths = arguments.get(self.excludePaths) ?? [] let additionalImports = arguments.get(self.additionalImports) ?? [] let scanPlugins = arguments.get(self.scanPlugins) ?? false let headerDocPath = arguments.get(self.headerDocPath) ?? nil let shouldCollectParsingInfo = arguments.get(self.shouldCollectParsingInfo) ?? false let parsingTimeout = arguments.get(self.parsingTimeout, withDefault: defaultTimeout) let exportingTimeout = arguments.get(self.exportingTimeout, withDefault: defaultTimeout) let retryParsingOnTimeoutLimit = arguments.get(self.retryParsingOnTimeoutLimit) ?? 0 let concurrencyLimit = arguments.get(self.concurrencyLimit) ?? nil let emitInputsDepsFile = arguments.get(self.emitInputsDepsFile) ?? false let generator: Generator = scanPlugins ? PluginizedGenerator() : Generator() do { try generator.generate(from: sourceRootPaths, withSourcesListFormat: sourcesListFormat, excludingFilesEndingWith: excludeSuffixes, excludingFilesWithPaths: excludePaths, with: additionalImports, headerDocPath, to: destinationPath, shouldCollectParsingInfo: shouldCollectParsingInfo, parsingTimeout: parsingTimeout, exportingTimeout: exportingTimeout, retryParsingOnTimeoutLimit: retryParsingOnTimeoutLimit, concurrencyLimit: concurrencyLimit, emitInputsDepsFile: emitInputsDepsFile) } catch GenericError.withMessage(let message) { error(message) } catch (let e) { error("Unknown error: \(e)") } } else { error("Missing source files root directories.") } } else { error("Missing destination path.") } } // MARK: - Private private var destinationPath: PositionalArgument<String>! private var sourceRootPaths: PositionalArgument<[String]>! private var sourcesListFormat: OptionArgument<String>! private var excludeSuffixes: OptionArgument<[String]>! private var excludePaths: OptionArgument<[String]>! private var additionalImports: OptionArgument<[String]>! private var scanPlugins: OptionArgument<Bool>! private var headerDocPath: OptionArgument<String>! private var shouldCollectParsingInfo: OptionArgument<Bool>! private var parsingTimeout: OptionArgument<Int>! private var exportingTimeout: OptionArgument<Int>! private var retryParsingOnTimeoutLimit: OptionArgument<Int>! private var concurrencyLimit: OptionArgument<Int>! private var emitInputsDepsFile: OptionArgument<Bool>! }