diff --git a/Plugins/SchemeGeneratorPlugin/SchemeGenerator.swift b/Plugins/SchemeGeneratorPlugin/SchemeGenerator.swift index c69a8b1..1459ddf 100644 --- a/Plugins/SchemeGeneratorPlugin/SchemeGenerator.swift +++ b/Plugins/SchemeGeneratorPlugin/SchemeGenerator.swift @@ -5,6 +5,10 @@ import CryptoKit public struct SchemeGenerator { // MARK: - Public public static func generateSchemes(_ packageDirectory: FileURL, _ arguments: [String], _ productNames: [String], _ packageTempFolder: FileURL) { + /// Load Tool Configuration + let toolConfigFileURL: FileURL = packageTempFolder.appendingPathComponent("config.json") + var toolConfig = getDefaultConfigurationName(toolConfigFileURL) + /// Prepare configuration let configurationFileURL = getConfigurationFileURL(packageDirectory, arguments) if FileManager.default.fileExists(atPath: configurationFileURL.path) == false { @@ -13,8 +17,12 @@ public struct SchemeGenerator { let config = loadConfiguration(configurationFileURL) validateConfiguration(config, configurationFileURL) + if config.verbose { print("toolConfigFileURL:", toolConfigFileURL.path) } + /// Prepare productNames - testProductNamesContent(productNames, packageTempFolder) + toolConfig = testProductNamesContent(productNames, packageTempFolder, toolConfig) + saveToolConfig(toolConfig, toolConfigFileURL) + let filteredProductNames = filterUsefullProducts(productNames, config) if config.verbose { print("Schemes that will be created:") @@ -22,12 +30,36 @@ public struct SchemeGenerator { } // Generate Schemes Files - generateSchemesFiles(filteredProductNames, config) + generateSchemesFiles(filteredProductNames, config) } // MARK: - Private // MARK: Configuration + private static func saveToolConfig(_ toolConfig: ToolConfiguration, _ toolConfigFileURL: FileURL) { + do { + let data = try JSONEncoder().encode(toolConfig) + try data.write(to: toolConfigFileURL, options: [.atomic]) + } catch { + Diagnostics.emit(.warning, "Failed to write ToolConfiguration file.") + } + } + + private static func getDefaultConfigurationName(_ toolConfigFileURL: FileURL) -> ToolConfiguration { + if FileManager.default.fileExists(atPath: toolConfigFileURL.path) { + do { + let data = try Data(contentsOf: toolConfigFileURL) + let toolConfig = try JSONDecoder().decode(ToolConfiguration.self, from: data) + return toolConfig + } catch { + Diagnostics.emit(.error, "Failed to load ToolConfiguration file.") + } + } + let toolConfig = ToolConfiguration() + saveToolConfig(toolConfig, toolConfigFileURL) + return toolConfig + } + private static func getConfigurationFileURL(_ packageDirectory: FileURL, _ arguments: [String]) -> FileURL { var configurationFileName = "schemeGenerator.json" if let cf = arguments.firstIndex(of: "--confFile") { @@ -54,7 +86,7 @@ public struct SchemeGenerator { fatalError(.error, "Failed to encode a default configuration.") } do { - try defaultConf.write(to: configurationFileURL) + try defaultConf.write(to: configurationFileURL, options: [.atomic]) } catch { fatalError(.error, "Failed to encode write a default configuration at \(configurationFileURL.path)") } @@ -80,7 +112,8 @@ public struct SchemeGenerator { } // MARK: Product Names - private static func testProductNamesContent(_ productNames: [String], _ packageTempFolder: FileURL) { + private static func testProductNamesContent(_ productNames: [String], _ packageTempFolder: FileURL, _ toolConfig: ToolConfiguration) -> ToolConfiguration { + var toolConfig = toolConfig if productNames.isEmpty { fatalError(.warning, "No products found.") } @@ -97,17 +130,12 @@ public struct SchemeGenerator { .compactMap { String(format: "%02x", $0) } .joined() - let productNamesFileURL = packageTempFolder.appendingPathComponent(hash) - - if FileManager.default.fileExists(atPath: productNamesFileURL.path) { + if toolConfig.lastProductNamesHash != hash { + toolConfig.lastProductNamesHash = hash + } else { fatalError(.remark, "There is no change in products list.") } - - do { - try Data().write(to: productNamesFileURL) - } catch { - fatalError(.error, "Failed to write temporary product list in \(productNamesFileURL.path).") - } + return toolConfig } private static func filterUsefullProducts(_ productNames: [String], _ config: SchemeGeneratorConfiguration) -> [String] { @@ -115,7 +143,7 @@ public struct SchemeGenerator { do { try FileManager.default.createDirectory(at: config.schemesDirectory!, withIntermediateDirectories: true) } catch { - fatalError(.error, "Schemes output directory(\(config.schemesDirectory)) don't exist and failed to created it.") + fatalError(.error, "Schemes output directory(\(String(describing: config.schemesDirectory))) don't exist and failed to created it.") } } @@ -132,7 +160,7 @@ public struct SchemeGenerator { }.map { $0.lastPathComponent.replacingOccurrences(of: ".\($0.pathExtension)", with: "") } var schemesSet = Set(schemes) - var productNamesSet = Set(productNames) + let productNamesSet = Set(productNames) // exclude from processing schemes that already exist schemesSet.subtract(config.excludedSchemes) diff --git a/Plugins/SchemeGeneratorPlugin/SchemeGeneratorPlugin.swift b/Plugins/SchemeGeneratorPlugin/SchemeGeneratorPlugin.swift index 6327c76..001a15e 100644 --- a/Plugins/SchemeGeneratorPlugin/SchemeGeneratorPlugin.swift +++ b/Plugins/SchemeGeneratorPlugin/SchemeGeneratorPlugin.swift @@ -17,5 +17,5 @@ struct SchemeGeneratorPlugin: CommandPlugin { public func fatalError(_ severity: PackagePlugin.Diagnostics.Severity, _ description: String, file: StaticString = #file, line: UInt = #line) -> Never { Diagnostics.emit(severity, description) - fatalError() + fatalError(file: file, line: line) } diff --git a/Plugins/SchemeGeneratorPlugin/ToolConfiguration.swift b/Plugins/SchemeGeneratorPlugin/ToolConfiguration.swift new file mode 100644 index 0000000..a3b0145 --- /dev/null +++ b/Plugins/SchemeGeneratorPlugin/ToolConfiguration.swift @@ -0,0 +1,11 @@ +import Foundation + +struct ToolConfiguration: Codable { + let defaultConfigFileName: String + var lastProductNamesHash: String? + + init(defaultConfigFileName: String = "schemeGenerator.json", lastProductNamesHash: String? = nil) { + self.defaultConfigFileName = defaultConfigFileName + self.lastProductNamesHash = lastProductNamesHash + } +} diff --git a/README.md b/README.md index 32e0d61..ca2b4a2 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,12 @@ This file contain theses keys: - schemesDirectory: A string that represent where the schemes will be saved - removeNotGeneratedSchemes: A bool that represent if it should remove schemes that are no longer in Package.swift - overwriteAlreadyGeneratedSchemes: A bool that represent if it should force the overwrite of schemes already present scheme +- excludedSchemes: A Array of String that represent the **name** of the schemes files that already exist and should not be processed - verbose: A bool that represent if it should print more information in the console ```json { "schemesDirectory": "", + "excludedSchemes": [], "removeNotGeneratedSchemes": true, "overwriteAlreadyGeneratedSchemes": false, "verbose": true @@ -25,7 +27,7 @@ This file contain theses keys: To run it right click on the package you want to run it on. ![Capture d’écran 2022-10-21 à 13 16 35](https://user-images.githubusercontent.com/661647/197189715-d810a52d-ce88-4371-9c9d-09d6d41fe883.png) -It will propose you to run it you can provide an optional argument that will allow you to change the name of the configuration file. +It will propose you to run it you can provide an optional argument(`--confFile newName.json`) that will allow you to change the name of the configuration file. ![Capture d’écran 2022-10-21 à 13 38 29](https://user-images.githubusercontent.com/661647/197189807-327b51b5-5f5b-4162-a433-a4c3215e67ec.png) At first lunch it will ask for permission to write files into the schemesDirectory in order for it to work you have to say yes.