Refactor in one unique command with subcommand + add a new command to generate ressources from a configuration file
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit

This commit is contained in:
2022-08-30 17:02:11 +02:00
parent a99466f258
commit 264c221604
60 changed files with 825 additions and 235 deletions

View File

@ -160,6 +160,20 @@
ReferencedContainer = "container:"> ReferencedContainer = "container:">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ColorTool"
BuildableName = "ColorTool"
BlueprintName = "ColorTool"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries> </BuildActionEntries>
</BuildAction> </BuildAction>
<TestAction <TestAction

View File

@ -34,6 +34,34 @@
ReferencedContainer = "container:"> ReferencedContainer = "container:">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ToolCore"
BuildableName = "ToolCore"
BlueprintName = "ToolCore"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ResgenSwift_ResgenSwift"
BuildableName = "ResgenSwift_ResgenSwift"
BlueprintName = "ResgenSwift_ResgenSwift"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries> </BuildActionEntries>
</BuildAction> </BuildAction>
<TestAction <TestAction

View File

@ -9,6 +9,15 @@
"revision": "e1465042f195f374b94f915ba8ca49de24300a0d", "revision": "e1465042f195f374b94f915ba8ca49de24300a0d",
"version": "1.0.2" "version": "1.0.2"
} }
},
{
"package": "Yams",
"repositoryURL": "https://github.com/jpsim/Yams.git",
"state": {
"branch": null,
"revision": "01835dc202670b5bb90d07f3eae41867e9ed29f6",
"version": "5.0.1"
}
} }
] ]
}, },

View File

@ -1,56 +1,67 @@
// swift-tools-version:5.3 // swift-tools-version:5.6
// The swift-tools-version declares the minimum version of Swift required to build this package. // The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription import PackageDescription
let package = Package( let package = Package(
name: "ResgenSwift", name: "ResgenSwift",
platforms: [.macOS(.v10_12)], platforms: [.macOS(.v12)],
dependencies: [ dependencies: [
// Dependencies declare other packages that this package depends on. // Dependencies declare other packages that this package depends on.
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0") .package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0"),
.package(url: "https://github.com/jpsim/Yams.git", from: "5.0.1")
], ],
targets: [ targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on. // Targets can depend on other targets in this package, and on products in packages this package depends on.
.target( .executableTarget(
name: "ResgenSwift", name: "ResgenSwift",
dependencies: ["FontTool", "ColorTool", "Strings", "Imagium"]
),
.target(
name: "FontTool",
dependencies: [ dependencies: [
"ToolCore", "ToolCore",
.product(name: "ArgumentParser", package: "swift-argument-parser") .product(name: "ArgumentParser", package: "swift-argument-parser"),
] "Yams"
),
.target(
name: "ColorTool",
dependencies: [
"ToolCore",
.product(name: "ArgumentParser", package: "swift-argument-parser")
]
),
.target(
name: "Strings",
dependencies: [
"ToolCore",
.product(name: "ArgumentParser", package: "swift-argument-parser")
],
sources: ["."] // Force include all subdirectories
),
.target(
name: "Imagium",
dependencies: [
"ToolCore",
.product(name: "ArgumentParser", package: "swift-argument-parser")
] ]
), ),
// .executableTarget(
// name: "FontTool",
// dependencies: [
// "ToolCore",
// .product(name: "ArgumentParser", package: "swift-argument-parser")
// ]
// ),
//
// .executableTarget(
// name: "ColorTool",
// dependencies: [
// "ToolCore",
// .product(name: "ArgumentParser", package: "swift-argument-parser")
// ]
// ),
//
// .executableTarget(
// name: "Strings",
// dependencies: [
// "ToolCore",
// .product(name: "ArgumentParser", package: "swift-argument-parser")
// ],
// sources: ["."] // Force include all subdirectories
// ),
//
// .executableTarget(
// name: "Imagium",
// dependencies: [
// "ToolCore",
// .product(name: "ArgumentParser", package: "swift-argument-parser")
// ]
// ),
// Helper targets // Helper targets
.target(name: "ToolCore"), .target(name: "ToolCore"),
// Test targets // Test targets
.testTarget( // .testTarget(
name: "ResgenSwiftTests", // name: "ResgenSwiftTests",
dependencies: ["ResgenSwift"]), // dependencies: ["ResgenSwift"]),
] ]
) )

View File

@ -121,7 +121,7 @@ swift run -c release Strings tags $FORCE_FLAG "./Tags/tags.txt" \
5. `--extension-name` *(optional)* : name of class to add the extension 5. `--extension-name` *(optional)* : name of class to add the extension
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppTags+GreatApp.swift`) 6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppTags+GreatApp.swift`)
> ⚠️ If extension name is not set or is `Tags`, it will generate static property on `Tags`. This class may not exists in your project, just create an empty class named `Tags` is necessary. > ⚠️ If extension name is not set or is `Tags`, it will generate static property on `Tags`. `Tags` is a typealias of `String`.
# Images # Images
@ -148,4 +148,4 @@ swift run -c release Imagium $FORCE_FLAG "./Images/images.txt" \
# TODO # TODO
[ ] Allow static variable generation on custom extension [ ] Allow static variable generation on custom extension

View File

@ -1,35 +0,0 @@
//
// ColorToolError.swift
//
//
// Created by Thibaut Schmitt on 20/12/2021.
//
import Foundation
enum ColorToolError: Error {
case badFormat(String)
case writeAsset(String)
case writeExtension(String, String)
case fileNotExists(String)
case badColorDefinition(String, String)
var description: String {
switch self {
case .badFormat(let info):
return "error:[ColorTool] Bad line format: \(info). Accepted format are: colorName=\"#RGB/#ARGB\"; colorName \"#RGB/#ARGB\"; colorName \"#RGB/#ARGB\" \"#RGB/#ARGB\""
case .writeAsset(let info):
return "error:[ColorTool] An error occured while writing color in Xcasset: \(info)"
case .writeExtension(let filename, let info):
return "error:[ColorTool] An error occured while writing extension in \(filename): \(info)"
case .fileNotExists(let filename):
return "error:[ColorTool] File \(filename) does not exists"
case .badColorDefinition(let lightColor, let darkColor):
return "error:[ColorTool]One of these two colors has invalid synthax: -\(lightColor)- or -\(darkColor)-"
}
}
}

View File

@ -1,43 +0,0 @@
//
// ImagiumError.swift
//
//
// Created by Thibaut Schmitt on 24/01/2022.
//
import Foundation
enum ImagiumError: Error {
case inputFolderNotFound(String)
case fileNotExists(String)
case unknownImageExtension(String)
case getFileAttributed(String, String)
case rsvgConvertNotFound
case writeFile(String, String)
case unknown(String)
var localizedDescription: String {
switch self {
case .inputFolderNotFound(let inputFolder):
return " error:[\(Imagium.toolName)] Input folder not found: \(inputFolder)"
case .fileNotExists(let filename):
return " error:[\(Imagium.toolName)] File \(filename) does not exists"
case .unknownImageExtension(let filename):
return " error:[\(Imagium.toolName)] File \(filename) have an unhandled file extension. Cannot generate image."
case .getFileAttributed(let filename, let errorDescription):
return " error:[\(Imagium.toolName)] Getting file attributes of \(filename) failed with error: \(errorDescription)"
case .rsvgConvertNotFound:
return " error:[\(Imagium.toolName)] Can't find rsvg-convert (can be installed with 'brew remove imagemagick && brew install imagemagick --with-librsvg')"
case .writeFile(let subErrorDescription, let filename):
return " error:[\(Imagium.toolName)] An error occured while writing content to \(filename): \(subErrorDescription)"
case .unknown(let errorDescription):
return " error:[\(Imagium.toolName)] Unknown error: \(errorDescription)"
}
}
}

View File

@ -9,7 +9,7 @@ import ToolCore
import Foundation import Foundation
import ArgumentParser import ArgumentParser
struct ColorTool: ParsableCommand { struct Colors: ParsableCommand {
// MARK: - CommandConfiguration // MARK: - CommandConfiguration
@ -20,7 +20,7 @@ struct ColorTool: ParsableCommand {
// MARK: - Static // MARK: - Static
static let toolName = "ColorTool" static let toolName = "Color"
static let defaultExtensionName = "UIColor" static let defaultExtensionName = "UIColor"
static let assetsColorsFolderName = "Colors" static let assetsColorsFolderName = "Colors"
@ -39,7 +39,7 @@ struct ColorTool: ParsableCommand {
// MARK: - Command options // MARK: - Command options
@OptionGroup var options: ColorToolOptions @OptionGroup var options: ColorsToolOptions
// MARK: - Run // MARK: - Run
@ -79,16 +79,16 @@ struct ColorTool: ParsableCommand {
// Check if input file exists // Check if input file exists
guard fileManager.fileExists(atPath: options.inputFile) else { guard fileManager.fileExists(atPath: options.inputFile) else {
let error = ColorToolError.fileNotExists(options.inputFile) let error = ColorsToolError.fileNotExists(options.inputFile)
print(error.localizedDescription) print(error.localizedDescription)
ColorTool.exit(withError: error) Colors.exit(withError: error)
} }
// Check if xcassets file exists // Check if xcassets file exists
guard fileManager.fileExists(atPath: options.xcassetsPath) else { guard fileManager.fileExists(atPath: options.xcassetsPath) else {
let error = ColorToolError.fileNotExists(options.xcassetsPath) let error = ColorsToolError.fileNotExists(options.xcassetsPath)
print(error.localizedDescription) print(error.localizedDescription)
ColorTool.exit(withError: error) Colors.exit(withError: error)
} }
// Check if needed to regenerate // Check if needed to regenerate
@ -107,8 +107,6 @@ struct ColorTool: ParsableCommand {
} }
} }
ColorTool.main()
/* /*
Command samples: Command samples:

View File

@ -0,0 +1,35 @@
//
// ColorsToolError.swift
//
//
// Created by Thibaut Schmitt on 20/12/2021.
//
import Foundation
enum ColorsToolError: Error {
case badFormat(String)
case writeAsset(String)
case writeExtension(String, String)
case fileNotExists(String)
case badColorDefinition(String, String)
var description: String {
switch self {
case .badFormat(let info):
return "error:[\(Colors.toolName)] Bad line format: \(info). Accepted format are: colorName=\"#RGB/#ARGB\"; colorName \"#RGB/#ARGB\"; colorName \"#RGB/#ARGB\" \"#RGB/#ARGB\""
case .writeAsset(let info):
return "error:[\(Colors.toolName)] An error occured while writing color in Xcasset: \(info)"
case .writeExtension(let filename, let info):
return "error:[\(Colors.toolName)] An error occured while writing extension in \(filename): \(info)"
case .fileNotExists(let filename):
return "error:[\(Colors.toolName)] File \(filename) does not exists"
case .badColorDefinition(let lightColor, let darkColor):
return "error:[\(Colors.toolName)]One of these two colors has invalid synthax: -\(lightColor)- or -\(darkColor)-"
}
}
}

View File

@ -1,5 +1,5 @@
// //
// ColorToolOptions.swift // ColorsToolOptions.swift
// //
// //
// Created by Thibaut Schmitt on 17/01/2022. // Created by Thibaut Schmitt on 17/01/2022.
@ -8,7 +8,7 @@
import Foundation import Foundation
import ArgumentParser import ArgumentParser
struct ColorToolOptions: ParsableArguments { struct ColorsToolOptions: ParsableArguments {
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation") @Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
var forceGeneration = false var forceGeneration = false
@ -25,13 +25,13 @@ struct ColorToolOptions: ParsableArguments {
var extensionOutputPath: String var extensionOutputPath: String
@Option(help: "Extension name. If not specified, it will generate an UIColor extension. Using default extension name will generate static property.") @Option(help: "Extension name. If not specified, it will generate an UIColor extension. Using default extension name will generate static property.")
var extensionName: String = ColorTool.defaultExtensionName var extensionName: String = Colors.defaultExtensionName
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+ColorsMyApp.swift") @Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+ColorsMyApp.swift")
var extensionSuffix: String = "" var extensionSuffix: String = ""
} }
extension ColorToolOptions { extension ColorsToolOptions {
var colorStyle: ColorStyle { var colorStyle: ColorStyle {
ColorStyle(rawValue: style) ?? .all ColorStyle(rawValue: style) ?? .all
} }

View File

@ -33,15 +33,15 @@ struct ColorExtensionGenerator {
do { do {
try extensionContent.write(to: extensionFilePathURL, atomically: true, encoding: .utf8) try extensionContent.write(to: extensionFilePathURL, atomically: true, encoding: .utf8)
} catch (let error) { } catch (let error) {
let error = ColorToolError.writeExtension(extensionFilePath, error.localizedDescription) let error = ColorsToolError.writeExtension(extensionFilePath, error.localizedDescription)
print(error.localizedDescription) print(error.localizedDescription)
ColorTool.exit(withError: error) Colors.exit(withError: error)
} }
} }
private static func getHeader(extensionClassname: String) -> String { private static func getHeader(extensionClassname: String) -> String {
""" """
// Generated by ResgenSwift.\(ColorTool.toolName) \(ResgenSwiftVersion) // Generated by ResgenSwift.\(Colors.toolName) \(ResgenSwiftVersion)
import UIKit import UIKit

View File

@ -31,9 +31,9 @@ struct ColorXcassetHelper {
do { do {
try color.contentsJSON().write(to: contentsJsonPathURL, atomically: true, encoding: .utf8) try color.contentsJSON().write(to: contentsJsonPathURL, atomically: true, encoding: .utf8)
} catch (let error) { } catch (let error) {
let error = ColorToolError.writeAsset(error.localizedDescription) let error = ColorsToolError.writeAsset(error.localizedDescription)
print(error.localizedDescription) print(error.localizedDescription)
ColorTool.exit(withError: error) Colors.exit(withError: error)
} }
} }
} }

View File

@ -1,5 +1,5 @@
// //
// File.swift // ColorStyle.swift
// //
// //
// Created by Thibaut Schmitt on 29/08/2022. // Created by Thibaut Schmitt on 29/08/2022.

View File

@ -25,9 +25,9 @@ struct ParsedColor {
} }
guard allComponents.contains(true) == false else { guard allComponents.contains(true) == false else {
let error = ColorToolError.badColorDefinition(light, dark) let error = ColorsToolError.badColorDefinition(light, dark)
print(error.localizedDescription) print(error.localizedDescription)
ColorTool.exit(withError: error) Colors.exit(withError: error)
} }
return """ return """

View File

@ -1,5 +1,5 @@
// //
// File.swift // ColorFileParser.swift
// //
// //
// Created by Thibaut Schmitt on 29/08/2022. // Created by Thibaut Schmitt on 29/08/2022.
@ -22,16 +22,16 @@ class ColorFileParser {
.replacingOccurrences(of: "=", with: "") // Keep compat with current file format .replacingOccurrences(of: "=", with: "") // Keep compat with current file format
guard colorLineCleanedUp.hasPrefix("#") == false, colorLineCleanedUp.isEmpty == false else { guard colorLineCleanedUp.hasPrefix("#") == false, colorLineCleanedUp.isEmpty == false else {
print("[\(ColorTool.toolName)] ⚠️ BadFormat or empty line (line number: \(lineNumber + 1)). Skip this line") print("[\(Colors.toolName)] ⚠️ BadFormat or empty line (line number: \(lineNumber + 1)). Skip this line")
return nil return nil
} }
let colorContent = colorLineCleanedUp.split(separator: " ") let colorContent = colorLineCleanedUp.split(separator: " ")
guard colorContent.count >= 2 else { guard colorContent.count >= 2 else {
let error = ColorToolError.badFormat(colorLine) let error = ColorsToolError.badFormat(colorLine)
print(error.localizedDescription) print(error.localizedDescription)
ColorTool.exit(withError: error) Colors.exit(withError: error)
} }
switch colorStyle { switch colorStyle {

View File

@ -1,5 +1,5 @@
// //
// FontOptions.swift // FontsOptions.swift
// //
// //
// Created by Thibaut Schmitt on 17/01/2022. // Created by Thibaut Schmitt on 17/01/2022.
@ -8,7 +8,7 @@
import Foundation import Foundation
import ArgumentParser import ArgumentParser
struct FontOptions: ParsableArguments { struct FontsOptions: ParsableArguments {
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation") @Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
var forceGeneration = false var forceGeneration = false
@ -19,8 +19,25 @@ struct FontOptions: ParsableArguments {
var extensionOutputPath: String var extensionOutputPath: String
@Option(help: "Extension name. If not specified, it will generate an UIFont extension. Using default extension name will generate static property.") @Option(help: "Extension name. If not specified, it will generate an UIFont extension. Using default extension name will generate static property.")
var extensionName: String = FontTool.defaultExtensionName var extensionName: String = Fonts.defaultExtensionName
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+FontsMyApp.swift") @Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+FontsMyApp.swift")
var extensionSuffix: String = "" var extensionSuffix: String = ""
} }
extension FontsOptions {
var extensionFileName: String {
if extensionSuffix.isEmpty == false {
return "\(extensionName)+\(extensionSuffix).swift"
}
return "\(extensionName).swift"
}
var extensionFilePath: String {
"\(extensionOutputPath)/\(extensionFileName)"
}
var generateStaticVariable: Bool {
extensionName == Fonts.defaultExtensionName
}
}

View File

@ -1,5 +1,5 @@
// //
// FontTool.swift // Fonts.swift
// //
// //
// Created by Thibaut Schmitt on 13/12/2021. // Created by Thibaut Schmitt on 13/12/2021.
@ -9,7 +9,7 @@ import ToolCore
import Foundation import Foundation
import ArgumentParser import ArgumentParser
struct FontTool: ParsableCommand { struct Fonts: ParsableCommand {
// MARK: - CommandConfiguration // MARK: - CommandConfiguration
@ -20,7 +20,7 @@ struct FontTool: ParsableCommand {
// MARK: - Static // MARK: - Static
static let toolName = "FontTool" static let toolName = "Fonts"
static let defaultExtensionName = "UIFont" static let defaultExtensionName = "UIFont"
// MARK: - Properties // MARK: - Properties
@ -38,7 +38,7 @@ struct FontTool: ParsableCommand {
// MARK: - Command Options // MARK: - Command Options
@OptionGroup var options: FontOptions @OptionGroup var options: FontsOptions
// MARK: - Run // MARK: - Run
@ -55,7 +55,7 @@ struct FontTool: ParsableCommand {
// Get real font names // Get real font names
let inputFolder = URL(fileURLWithPath: options.inputFile).deletingLastPathComponent().relativePath let inputFolder = URL(fileURLWithPath: options.inputFile).deletingLastPathComponent().relativePath
let fontsNames = FontToolHelper.getFontPostScriptName(for: fontsToGenerate, let fontsNames = FontsToolHelper.getFontPostScriptName(for: fontsToGenerate,
inputFolder: inputFolder) inputFolder: inputFolder)
// Generate extension // Generate extension
@ -77,9 +77,9 @@ struct FontTool: ParsableCommand {
// Check input file exists // Check input file exists
guard fileManager.fileExists(atPath: options.inputFile) else { guard fileManager.fileExists(atPath: options.inputFile) else {
let error = FontToolError.fileNotExists(options.inputFile) let error = FontsToolError.fileNotExists(options.inputFile)
print(error.localizedDescription) print(error.localizedDescription)
FontTool.exit(withError: error) Fonts.exit(withError: error)
} }
// Check if needed to regenerate // Check if needed to regenerate
@ -91,5 +91,3 @@ struct FontTool: ParsableCommand {
return true return true
} }
} }
FontTool.main()

View File

@ -1,5 +1,5 @@
// //
// FontToolError.swift // FontsToolError.swift
// //
// //
// Created by Thibaut Schmitt on 13/12/2021. // Created by Thibaut Schmitt on 13/12/2021.
@ -7,7 +7,7 @@
import Foundation import Foundation
enum FontToolError: Error { enum FontsToolError: Error {
case fcScan(String, Int32, String?) case fcScan(String, Int32, String?)
case inputFolderNotFound(String) case inputFolderNotFound(String)
case fileNotExists(String) case fileNotExists(String)
@ -16,16 +16,16 @@ enum FontToolError: Error {
var localizedDescription: String { var localizedDescription: String {
switch self { switch self {
case .fcScan(let path, let code, let output): case .fcScan(let path, let code, let output):
return "error:[\(FontTool.toolName)] Error while getting fontName (fc-scan --format %{postscriptname} \(path). fc-scan exit with \(code) and output is: \(output ?? "no output")" return "error:[\(Fonts.toolName)] Error while getting fontName (fc-scan --format %{postscriptname} \(path). fc-scan exit with \(code) and output is: \(output ?? "no output")"
case .inputFolderNotFound(let inputFolder): case .inputFolderNotFound(let inputFolder):
return " error:[\(FontTool.toolName)] Input folder not found: \(inputFolder)" return " error:[\(Fonts.toolName)] Input folder not found: \(inputFolder)"
case .fileNotExists(let filename): case .fileNotExists(let filename):
return " error:[\(FontTool.toolName)] File \(filename) does not exists" return " error:[\(Fonts.toolName)] File \(filename) does not exists"
case .writeExtension(let filename, let info): case .writeExtension(let filename, let info):
return "error:[\(FontTool.toolName)] An error occured while writing extension in \(filename): \(info)" return "error:[\(Fonts.toolName)] An error occured while writing extension in \(filename): \(info)"
} }
} }
} }

View File

@ -1,5 +1,5 @@
// //
// FontToolHelper.swift // FontsToolHelper.swift
// //
// //
// Created by Thibaut Schmitt on 13/12/2021. // Created by Thibaut Schmitt on 13/12/2021.
@ -8,7 +8,7 @@
import Foundation import Foundation
import ToolCore import ToolCore
class FontToolHelper { class FontsToolHelper {
static func getFontPostScriptName(for fonts: [String], inputFolder: String) -> [FontName] { static func getFontPostScriptName(for fonts: [String], inputFolder: String) -> [FontName] {
let fontsFilenames = Self.getFontsFilenames(fromInputFolder: inputFolder) let fontsFilenames = Self.getFontsFilenames(fromInputFolder: inputFolder)
@ -38,9 +38,9 @@ class FontToolHelper {
// Get a enumerator for all files // Get a enumerator for all files
let fileManager = FileManager() let fileManager = FileManager()
guard fileManager.fileExists(atPath: inputFolder) else { guard fileManager.fileExists(atPath: inputFolder) else {
let error = FontToolError.inputFolderNotFound(inputFolder) let error = FontsToolError.inputFolderNotFound(inputFolder)
print(error.localizedDescription) print(error.localizedDescription)
FontTool.exit(withError: error) Fonts.exit(withError: error)
} }
let enumerator: FileManager.DirectoryEnumerator = fileManager.enumerator(atPath: inputFolder)! let enumerator: FileManager.DirectoryEnumerator = fileManager.enumerator(atPath: inputFolder)!
@ -63,9 +63,9 @@ class FontToolHelper {
let task = Shell.shell("fc-scan", "--format", "%{postscriptname}", path) let task = Shell.shell("fc-scan", "--format", "%{postscriptname}", path)
guard let fontName = task.output, task.terminationStatus == 0 else { guard let fontName = task.output, task.terminationStatus == 0 else {
let error = FontToolError.fcScan(path, task.terminationStatus, task.output) let error = FontsToolError.fcScan(path, task.terminationStatus, task.output)
print(error.localizedDescription) print(error.localizedDescription)
FontTool.exit(withError: error) Fonts.exit(withError: error)
} }
return fontName return fontName

View File

@ -1,5 +1,5 @@
// //
// File.swift // FontPlistGenerator.swift
// //
// //
// Created by Thibaut Schmitt on 29/08/2022. // Created by Thibaut Schmitt on 29/08/2022.

View File

@ -31,15 +31,15 @@ class FontExtensionGenerator {
do { do {
try extensionContent.write(to: extensionFilePathURL, atomically: true, encoding: .utf8) try extensionContent.write(to: extensionFilePathURL, atomically: true, encoding: .utf8)
} catch (let error) { } catch (let error) {
let error = FontToolError.writeExtension(extensionFilePath, error.localizedDescription) let error = FontsToolError.writeExtension(extensionFilePath, error.localizedDescription)
print(error.localizedDescription) print(error.localizedDescription)
FontTool.exit(withError: error) Fonts.exit(withError: error)
} }
} }
private static func getHeader(extensionClassname: String) -> String { private static func getHeader(extensionClassname: String) -> String {
""" """
// Generated by ResgenSwift.\(FontTool.toolName) \(ResgenSwiftVersion) // Generated by ResgenSwift.\(Fonts.toolName) \(ResgenSwiftVersion)
import UIKit import UIKit
@ -48,18 +48,18 @@ class FontExtensionGenerator {
} }
private static func getFontNameEnum(fontsNames: [String]) -> String { private static func getFontNameEnum(fontsNames: [String]) -> String {
var enumDefinition = "\tenum FontName: String {\n" var enumDefinition = " enum FontName: String {\n"
fontsNames.forEach { fontsNames.forEach {
enumDefinition += "\t\tcase \($0.removeCharacters(from: "[]+-_")) = \"\($0)\"\n" enumDefinition += " case \($0.removeCharacters(from: "[]+-_")) = \"\($0)\"\n"
} }
enumDefinition += "\t}\n" enumDefinition += " }\n"
return enumDefinition return enumDefinition
} }
private static func getFontMethods(fontsNames: [FontName], staticVar: Bool) -> String { private static func getFontMethods(fontsNames: [FontName], staticVar: Bool) -> String {
let pragma = "\t// MARK: - Getter" let pragma = " // MARK: - Getter"
var propertiesOrMethods: [String] = fontsNames var propertiesOrMethods: [String] = fontsNames
.unique() .unique()

View File

@ -1,5 +1,5 @@
// //
// File.swift // FontName.swift
// //
// //
// Created by Thibaut Schmitt on 29/08/2022. // Created by Thibaut Schmitt on 29/08/2022.

View File

@ -1,5 +1,5 @@
// //
// File.swift // FontFileParser.swift
// //
// //
// Created by Thibaut Schmitt on 29/08/2022. // Created by Thibaut Schmitt on 29/08/2022.

View File

@ -0,0 +1,51 @@
//
// Generate.swift
//
//
// Created by Thibaut Schmitt on 30/08/2022.
//
import ToolCore
import Foundation
import ArgumentParser
struct Generate: ParsableCommand {
// MARK: - CommandConfiguration
static var configuration = CommandConfiguration(
abstract: "A utility to generate ressources based on a configuration file",
version: ResgenSwiftVersion
)
// MARK: - Static
static let toolName = "Generate"
// MARK: - Command Options
@OptionGroup var options: GenerateOptions
// MARK: - Run
public func run() throws {
print("[\(Self.toolName)] Starting Resgen with configuration: \(options.configurationFile)")
// Parse
let configuration = ConfigurationFileParser.parse(options.configurationFile)
print("Found configurations :")
print(" - \(configuration.colors.count) colors configuration")
print(" - \(configuration.fonts.count) fonts configuration")
print(" - \(configuration.images.count) images configuration")
print(" - \(configuration.strings.count) strings configuration")
print(" - \(configuration.tags.count) tags configuration")
print()
// Execute commands
configuration.runnableConfigurations
.forEach {
$0.run(force: options.forceGeneration)
}
print("[\(Self.toolName)] Resgen ended")
}
}

View File

@ -0,0 +1,30 @@
//
// ResgenSwiftError.swift
//
//
// Created by Thibaut Schmitt on 30/08/2022.
//
import Foundation
enum GenerateError: Error {
case fileNotExists(String)
case invalidConfigurationFile(String)
case commandError([String], String)
var localizedDescription: String {
switch self {
case .fileNotExists(let filename):
return " error:[\(Generate.toolName)] File \(filename) does not exists"
case .invalidConfigurationFile(let filename):
return " error:[\(Generate.toolName)] File \(filename) is not a valid configuration file"
case .commandError(let command, let terminationStatus):
let readableCommand = command
.map { $0 }
.joined(separator: " ")
return "error:[\(Generate.toolName)] An error occured while running command '\(readableCommand)'. Command terminate with status code: \(terminationStatus)"
}
}
}

View File

@ -0,0 +1,19 @@
//
// GenerateOptions.swift
//
//
// Created by Thibaut Schmitt on 30/08/2022.
//
import Foundation
import Foundation
import ArgumentParser
struct GenerateOptions: ParsableArguments {
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
var forceGeneration = false
@Argument(help: "Configuration file.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
var configurationFile: String
}

View File

@ -0,0 +1,140 @@
//
// ConfigurationFile.swift
//
//
// Created by Thibaut Schmitt on 30/08/2022.
//
import Foundation
struct ConfigurationFile: Codable, CustomDebugStringConvertible {
var colors: [ColorsConfiguration]
var fonts: [FontsConfiguration]
var images: [ImagesConfiguration]
var strings: [StringsConfiguration]
var tags: [TagsConfiguration]
var runnableConfigurations: [Runnable] {
let runnables: [[Runnable]] = [colors, fonts, images, strings, tags]
return Array(runnables.joined())
}
var debugDescription: String {
"""
\(colors)
-----------
-----------
\(fonts)
-----------
-----------
\(images)
-----------
-----------
\(strings)
-----------
-----------
\(tags)
"""
}
}
struct ColorsConfiguration: Codable, CustomDebugStringConvertible {
let inputFile: String
let style: String
let xcassetsPath: String
let extensionOutputPath: String
let extensionName: String?
let extensionSuffix: String?
var debugDescription: String {
"""
Colors configuration:
- Input file: \(inputFile)
- Style: \(style)
- Xcassets path: \(xcassetsPath)
- Extension output path: \(extensionOutputPath)
- Extension name: \(extensionName ?? "-")
- Extension suffix: \(extensionSuffix ?? "-")
"""
}
}
struct FontsConfiguration: Codable, CustomDebugStringConvertible {
let inputFile: String
let extensionOutputPath: String
let extensionName: String?
let extensionSuffix: String?
var debugDescription: String {
"""
Fonts configuration:
- Input file: \(inputFile)
- Extension output path: \(extensionOutputPath)
- Extension name: \(extensionName ?? "-")
- Extension suffix: \(extensionSuffix ?? "-")
"""
}
}
struct ImagesConfiguration: Codable, CustomDebugStringConvertible {
let inputFile: String
let xcassetsPath: String
let extensionOutputPath: String
let extensionName: String?
let extensionSuffix: String?
var debugDescription: String {
"""
Images configuration:
- Input file: \(inputFile)
- Xcassets path: \(xcassetsPath)
- Extension output path: \(extensionOutputPath)
- Extension name: \(extensionName ?? "-")
- Extension suffix: \(extensionSuffix ?? "-")
"""
}
}
struct StringsConfiguration: Codable, CustomDebugStringConvertible {
let inputFile: String
let outputPath: String
let langs: String
let defaultLang: String
let extensionOutputPath: String
let extensionName: String?
let extensionSuffix: String?
var debugDescription: String {
"""
Strings configuration:
- Input file: \(inputFile)
- Output path: \(outputPath)
- Langs: \(langs)
- Default lang: \(defaultLang)
- Extension output path: \(extensionOutputPath)
- Extension name: \(extensionName ?? "-")
- Extension suffix: \(extensionSuffix ?? "-")
"""
}
}
struct TagsConfiguration: Codable, CustomDebugStringConvertible {
let inputFile: String
let lang: String
let extensionOutputPath: String
let extensionName: String?
let extensionSuffix: String?
var debugDescription: String {
"""
Tags configuration:
- Input file: \(inputFile)
- Lang: \(lang)
- Extension output path: \(extensionOutputPath)
- Extension name: \(extensionName ?? "-")
- Extension suffix: \(extensionSuffix ?? "-")
"""
}
}

View File

@ -0,0 +1,27 @@
//
// ConfigurationFileParser.swift
//
//
// Created by Thibaut Schmitt on 30/08/2022.
//
import Foundation
import Yams
class ConfigurationFileParser {
static func parse(_ configurationFile: String) -> ConfigurationFile {
guard let data = FileManager().contents(atPath: configurationFile) else {
let error = GenerateError.fileNotExists(configurationFile)
print(error.localizedDescription)
Generate.exit(withError: error)
}
guard let configuration = try? YAMLDecoder().decode(ConfigurationFile.self, from: data) else {
let error = GenerateError.invalidConfigurationFile(configurationFile)
print(error.localizedDescription)
Generate.exit(withError: error)
}
return configuration
}
}

View File

@ -0,0 +1,43 @@
//
// ColorsConfiguration+ShellCommandable.swift
//
//
// Created by Thibaut Schmitt on 30/08/2022.
//
import Foundation
extension ColorsConfiguration: Runnable {
func run(force: Bool) {
var args = [String]()
if force {
args += ["-f"]
}
args += [
inputFile,
"--style",
style,
"--xcassets-path",
xcassetsPath,
"--extension-output-path",
extensionOutputPath
]
if let extensionName = extensionName {
args += [
"--extension-name",
extensionName
]
}
if let extensionSuffix = extensionSuffix {
args += [
"--extension-suffix",
extensionSuffix
]
}
Colors.main(args)
}
}

View File

@ -0,0 +1,40 @@
//
// FontsConfiguration+ShellCommandable.swift
//
//
// Created by Thibaut Schmitt on 30/08/2022.
//
import Foundation
extension FontsConfiguration: Runnable {
func run(force: Bool) {
var args = [String]()
if force {
args += ["-f"]
}
args += [
inputFile,
"--extension-output-path",
extensionOutputPath
]
if let extensionName = extensionName {
args += [
"--extension-name",
extensionName
]
}
if let extensionSuffix = extensionSuffix {
args += [
"--extension-suffix",
extensionSuffix
]
}
Fonts.main(args)
}
}

View File

@ -0,0 +1,41 @@
//
// ImagesConfiguration+ShellCommandable.swift
//
//
// Created by Thibaut Schmitt on 30/08/2022.
//
import Foundation
extension ImagesConfiguration: Runnable {
func run(force: Bool) {
var args = [String]()
if force {
args += ["-f"]
}
args += [
inputFile,
"--xcassets-path",
xcassetsPath,
"--extension-output-path",
extensionOutputPath
]
if let extensionName = extensionName {
args += [
"--extension-name",
extensionName
]
}
if let extensionSuffix = extensionSuffix {
args += [
"--extension-suffix",
extensionSuffix
]
}
Images.main(args)
}
}

View File

@ -0,0 +1,13 @@
//
// ShellCommandable.swift
//
//
// Created by Thibaut Schmitt on 30/08/2022.
//
import Foundation
protocol Runnable {
func run(force: Bool)
}

View File

@ -0,0 +1,46 @@
//
// StringsConfiguration+ShellCommandable.swift
//
//
// Created by Thibaut Schmitt on 30/08/2022.
//
import Foundation
extension StringsConfiguration: Runnable {
func run(force: Bool) {
var args = [String]()
if force {
args += ["-f"]
}
args += [
inputFile,
"--output-path",
outputPath,
"--langs",
langs,
"--default-lang",
defaultLang,
"--extension-output-path",
extensionOutputPath
]
if let extensionName = extensionName {
args += [
"--extension-name",
extensionName
]
}
if let extensionSuffix = extensionSuffix {
args += [
"--extension-suffix",
extensionSuffix
]
}
Stringium.main(args)
}
}

View File

@ -0,0 +1,41 @@
//
// TagsConfiguration+ShellCommandable.swift
//
//
// Created by Thibaut Schmitt on 30/08/2022.
//
import Foundation
extension TagsConfiguration: Runnable {
func run(force: Bool) {
var args = [String]()
if force {
args += ["-f"]
}
args += [
inputFile,
"--lang",
lang,
"--extension-output-path",
extensionOutputPath
]
if let extensionName = extensionName {
args += [
"--extension-name",
extensionName
]
}
if let extensionSuffix = extensionSuffix {
args += [
"--extension-suffix",
extensionSuffix
]
}
Tags.main(args)
}
}

View File

@ -11,9 +11,9 @@ extension FileManager {
func getAllRegularFileIn(directory: String) -> [String] { func getAllRegularFileIn(directory: String) -> [String] {
var files = [String]() var files = [String]()
guard let enumerator = self.enumerator(at: URL(string: directory)!, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) else { guard let enumerator = self.enumerator(at: URL(string: directory)!, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) else {
let error = ImagiumError.unknown("Cannot enumerate file in \(directory)") let error = ImagesError.unknown("Cannot enumerate file in \(directory)")
print(error.localizedDescription) print(error.localizedDescription)
Imagium.exit(withError: error) Images.exit(withError: error)
} }
for case let fileURL as URL in enumerator { for case let fileURL as URL in enumerator {
@ -23,9 +23,9 @@ extension FileManager {
files.append(fileURL.relativePath) files.append(fileURL.relativePath)
} }
} catch { } catch {
let error = ImagiumError.getFileAttributed(fileURL.relativePath, error.localizedDescription) let error = ImagesError.getFileAttributed(fileURL.relativePath, error.localizedDescription)
print(error.localizedDescription) print(error.localizedDescription)
Imagium.exit(withError: error) Images.exit(withError: error)
} }
} }
return files return files
@ -34,9 +34,9 @@ extension FileManager {
func getAllImageSetFolderIn(directory: String) -> [String] { func getAllImageSetFolderIn(directory: String) -> [String] {
var files = [String]() var files = [String]()
guard let enumerator = self.enumerator(at: URL(string: directory)!, includingPropertiesForKeys: [.isDirectoryKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) else { guard let enumerator = self.enumerator(at: URL(string: directory)!, includingPropertiesForKeys: [.isDirectoryKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) else {
let error = ImagiumError.unknown("Cannot enumerate imageset directory in \(directory)") let error = ImagesError.unknown("Cannot enumerate imageset directory in \(directory)")
print(error.localizedDescription) print(error.localizedDescription)
Imagium.exit(withError: error) Images.exit(withError: error)
} }
for case let fileURL as URL in enumerator { for case let fileURL as URL in enumerator {
@ -46,9 +46,9 @@ extension FileManager {
files.append(fileURL.lastPathComponent) files.append(fileURL.lastPathComponent)
} }
} catch { } catch {
let error = ImagiumError.getFileAttributed(fileURL.relativePath, error.localizedDescription) let error = ImagesError.getFileAttributed(fileURL.relativePath, error.localizedDescription)
print(error.localizedDescription) print(error.localizedDescription)
Imagium.exit(withError: error) Images.exit(withError: error)
} }
} }
return files return files

View File

@ -58,9 +58,9 @@ class ImageExtensionGenerator {
do { do {
try extensionContent.write(to: extensionFilePathURL, atomically: true, encoding: .utf8) try extensionContent.write(to: extensionFilePathURL, atomically: true, encoding: .utf8)
} catch (let error) { } catch (let error) {
let error = ImagiumError.writeFile(extensionFilePath, error.localizedDescription) let error = ImagesError.writeFile(extensionFilePath, error.localizedDescription)
print(error.localizedDescription) print(error.localizedDescription)
Imagium.exit(withError: error) Images.exit(withError: error)
} }
} }

View File

@ -1,5 +1,5 @@
// //
// File.swift // XcassetsGenerator.swift
// //
// //
// Created by Thibaut Schmitt on 24/01/2022. // Created by Thibaut Schmitt on 24/01/2022.
@ -24,7 +24,7 @@ class XcassetsGenerator {
func generateXcassets(inputPath: String, imagesToGenerate: [ParsedImage], xcassetsPath: String) { func generateXcassets(inputPath: String, imagesToGenerate: [ParsedImage], xcassetsPath: String) {
let fileManager = FileManager() let fileManager = FileManager()
let svgConverter = Imagium.getSvgConverterPath() let svgConverter = Images.getSvgConverterPath()
let allSubFiles = fileManager.getAllRegularFileIn(directory: inputPath) let allSubFiles = fileManager.getAllRegularFileIn(directory: inputPath)
var generatedAssetsPaths = [String]() var generatedAssetsPaths = [String]()
@ -47,9 +47,9 @@ class XcassetsGenerator {
return (subfile, "jepg") return (subfile, "jepg")
} }
} }
let error = ImagiumError.unknownImageExtension(parsedImage.name) let error = ImagesError.unknownImageExtension(parsedImage.name)
print(error.localizedDescription) print(error.localizedDescription)
Imagium.exit(withError: error) Images.exit(withError: error)
}() }()
// Create imageset folder // Create imageset folder

View File

@ -1,5 +1,5 @@
// //
// Imagium.swift // Images.swift
// //
// //
// Created by Thibaut Schmitt on 24/01/2022. // Created by Thibaut Schmitt on 24/01/2022.
@ -9,7 +9,7 @@ import ToolCore
import Foundation import Foundation
import ArgumentParser import ArgumentParser
struct Imagium: ParsableCommand { struct Images: ParsableCommand {
// MARK: - CommandConfiguration // MARK: - CommandConfiguration
@ -20,7 +20,7 @@ struct Imagium: ParsableCommand {
// MARK: - Static // MARK: - Static
static let toolName = "Imagium" static let toolName = "Images"
static let defaultExtensionName = "UIImage" static let defaultExtensionName = "UIImage"
// MARK: - Properties // MARK: - Properties
@ -35,7 +35,7 @@ struct Imagium: ParsableCommand {
// MARK: - Command Options // MARK: - Command Options
@OptionGroup var options: ImagiumOptions @OptionGroup var options: ImagesOptions
// MARK: - Run // MARK: - Run
@ -81,13 +81,13 @@ struct Imagium: ParsableCommand {
// Input file // Input file
guard fileManager.fileExists(atPath: options.inputFile) else { guard fileManager.fileExists(atPath: options.inputFile) else {
let error = ImagiumError.fileNotExists(options.inputFile) let error = ImagesError.fileNotExists(options.inputFile)
print(error.localizedDescription) print(error.localizedDescription)
Imagium.exit(withError: error) Images.exit(withError: error)
} }
// RSVG-Converter // RSVG-Converter
_ = Imagium.getSvgConverterPath() _ = Images.getSvgConverterPath()
// Check if needed to regenerate // Check if needed to regenerate
guard GeneratorChecker.shouldGenerate(force: options.forceExecution, inputFilePath: options.inputFile, extensionFilePath: extensionFilePath) else { guard GeneratorChecker.shouldGenerate(force: options.forceExecution, inputFilePath: options.inputFile, extensionFilePath: extensionFilePath) else {
@ -107,10 +107,8 @@ struct Imagium: ParsableCommand {
return taskSvgConverter.output!.removeCharacters(from: CharacterSet.whitespacesAndNewlines) return taskSvgConverter.output!.removeCharacters(from: CharacterSet.whitespacesAndNewlines)
} }
let error = ImagiumError.rsvgConvertNotFound let error = ImagesError.rsvgConvertNotFound
print(error.localizedDescription) print(error.localizedDescription)
Imagium.exit(withError: error) Images.exit(withError: error)
} }
} }
Imagium.main()

View File

@ -0,0 +1,43 @@
//
// ImagesError.swift
//
//
// Created by Thibaut Schmitt on 24/01/2022.
//
import Foundation
enum ImagesError: Error {
case inputFolderNotFound(String)
case fileNotExists(String)
case unknownImageExtension(String)
case getFileAttributed(String, String)
case rsvgConvertNotFound
case writeFile(String, String)
case unknown(String)
var localizedDescription: String {
switch self {
case .inputFolderNotFound(let inputFolder):
return " error:[\(Images.toolName)] Input folder not found: \(inputFolder)"
case .fileNotExists(let filename):
return " error:[\(Images.toolName)] File \(filename) does not exists"
case .unknownImageExtension(let filename):
return " error:[\(Images.toolName)] File \(filename) have an unhandled file extension. Cannot generate image."
case .getFileAttributed(let filename, let errorDescription):
return " error:[\(Images.toolName)] Getting file attributes of \(filename) failed with error: \(errorDescription)"
case .rsvgConvertNotFound:
return " error:[\(Images.toolName)] Can't find rsvg-convert (can be installed with 'brew remove imagemagick && brew install imagemagick --with-librsvg')"
case .writeFile(let subErrorDescription, let filename):
return " error:[\(Images.toolName)] An error occured while writing content to \(filename): \(subErrorDescription)"
case .unknown(let errorDescription):
return " error:[\(Images.toolName)] Unknown error: \(errorDescription)"
}
}
}

View File

@ -8,7 +8,7 @@
import Foundation import Foundation
import ArgumentParser import ArgumentParser
struct ImagiumOptions: ParsableArguments { struct ImagesOptions: ParsableArguments {
@Flag(name: .customShort("f"), help: "Should force script execution") @Flag(name: .customShort("f"), help: "Should force script execution")
var forceExecution = false var forceExecution = false
@ -25,7 +25,7 @@ struct ImagiumOptions: ParsableArguments {
var extensionOutputPath: String var extensionOutputPath: String
@Option(help: "Extension name. If not specified, it will generate an UIImage extension. Using default extension name will generate static property.") @Option(help: "Extension name. If not specified, it will generate an UIImage extension. Using default extension name will generate static property.")
var extensionName: String = Imagium.defaultExtensionName var extensionName: String = Images.defaultExtensionName
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+Image{extensionSuffix}.swift") @Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+Image{extensionSuffix}.swift")
var extensionSuffix: String = "" var extensionSuffix: String = ""

View File

@ -11,7 +11,7 @@ import CoreVideo
class TagsGenerator { class TagsGenerator {
static func writeExtensionFiles(sections: [Section], lang: String, tags: [String], staticVar: Bool, extensionName: String, extensionFilePath: String) { static func writeExtensionFiles(sections: [Section], lang: String, tags: [String], staticVar: Bool, extensionName: String, extensionFilePath: String) {
let extensionHeader = Self.getHeader(extensionClassname: extensionName) let extensionHeader = Self.getHeader(extensionClassname: extensionName, staticVar: staticVar)
let extensionFooter = Self.getFooter() let extensionFooter = Self.getFooter()
let extensionContent: String = { let extensionContent: String = {
@ -22,7 +22,7 @@ class TagsGenerator {
return // Go to next section return // Go to next section
} }
content += "\n\t// MARK: - \(section.name)" content += "\n // MARK: - \(section.name)"
section.definitions.forEach { definition in section.definitions.forEach { definition in
if staticVar { if staticVar {
content += "\n\n\(definition.getStaticProperty(forLang: lang))" content += "\n\n\(definition.getStaticProperty(forLang: lang))"
@ -55,21 +55,19 @@ class TagsGenerator {
} }
} }
private static func getHeader(extensionClassname: String) -> String { private static func getHeader(extensionClassname: String, staticVar: Bool) -> String {
""" """
// Generated by ResgenSwift.Strings.Tags \(ResgenSwiftVersion) // Generated by ResgenSwift.Strings.Tags \(ResgenSwiftVersion)
// typelias Tags = String \(staticVar ? "typelias Tags = String\n\n" : "")import UIKit
import UIKit extension \(extensionClassname) {
"""
extension \(extensionClassname) {
"""
} }
private static func getFooter() -> String { private static func getFooter() -> String {
""" """
} }
""" """
} }
} }

View File

@ -27,8 +27,8 @@ struct Stringium: ParsableCommand {
// MARK: - Properties // MARK: - Properties
var extensionFileName: String { var extensionFileName: String {
if options.extensionSuffix.isEmpty == false { if let extensionSuffix = options.extensionSuffix {
return "\(options.extensionName)+\(options.extensionSuffix).swift" return "\(options.extensionName)+\(extensionSuffix).swift"
} }
return "\(options.extensionName).swift" return "\(options.extensionName).swift"
} }
@ -47,8 +47,6 @@ struct Stringium: ParsableCommand {
// MARK: - Command options // MARK: - Command options
// The `@OptionGroup` attribute includes the flags, options, and
// arguments defined by another `ParsableArguments` type.
@OptionGroup var options: StringiumOptions @OptionGroup var options: StringiumOptions
// MARK: - Run // MARK: - Run

View File

@ -34,7 +34,7 @@ struct StringiumOptions: ParsableArguments {
var extensionName: String = Stringium.defaultExtensionName var extensionName: String = Stringium.defaultExtensionName
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+{extensionSuffix}.swift") @Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+{extensionSuffix}.swift")
var extensionSuffix: String = "" var extensionSuffix: String?
} }
extension StringiumOptions { extension StringiumOptions {

View File

@ -26,5 +26,5 @@ struct Strings: ParsableCommand {
) )
} }
Strings.main() //Strings.main()

View File

@ -28,8 +28,8 @@ struct Tags: ParsableCommand {
// MARK: - Properties // MARK: - Properties
var extensionFileName: String { var extensionFileName: String {
if options.extensionSuffix.isEmpty == false { if let extensionSuffix = options.extensionSuffix {
return "\(options.extensionName)+\(options.extensionSuffix).swift" return "\(options.extensionName)+\(extensionSuffix).swift"
} }
return "\(options.extensionName).swift" return "\(options.extensionName).swift"
} }
@ -40,8 +40,6 @@ struct Tags: ParsableCommand {
// MARK: - Command Options // MARK: - Command Options
// The `@OptionGroup` attribute includes the flags, options, and
// arguments defined by another `ParsableArguments` type.
@OptionGroup var options: TagsOptions @OptionGroup var options: TagsOptions
// MARK: - Run // MARK: - Run

View File

@ -25,5 +25,5 @@ struct TagsOptions: ParsableArguments {
var extensionName: String = Tags.defaultExtensionName var extensionName: String = Tags.defaultExtensionName
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+Tag{extensionSuffix}.swift") @Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+Tag{extensionSuffix}.swift")
var extensionSuffix: String = "" var extensionSuffix: String?
} }

View File

@ -33,8 +33,6 @@ struct Twine: ParsableCommand {
// MARK: - Command Options // MARK: - Command Options
// The `@OptionGroup` attribute includes the flags, options, and
// arguments defined by another `ParsableArguments` type.
@OptionGroup var options: TwineOptions @OptionGroup var options: TwineOptions
// MARK: - Run // MARK: - Run

View File

@ -1,5 +1,5 @@
// //
// File.swift // TwineOptions.swift
// //
// //
// Created by Thibaut Schmitt on 10/01/2022. // Created by Thibaut Schmitt on 10/01/2022.

View File

@ -1 +1,35 @@
print("Welcome ResgenSwift") //
// ResgenSwift.swift
//
//
// Created by Thibaut Schmitt on 13/12/2021.
//
import ToolCore
import Foundation
import ArgumentParser
struct ResgenSwift: ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "A utility for generate ressources.",
version: ResgenSwiftVersion,
// Pass an array to `subcommands` to set up a nested tree of subcommands.
// With language support for type-level introspection, this could be
// provided by automatically finding nested `ParsableCommand` types.
subcommands: [
Colors.self,
Fonts.self,
Images.self,
Strings.self,
Generate.self
]
// A default subcommand, when provided, is automatically selected if a
// subcommand is not given on the command line.
//defaultSubcommand: Twine.self
)
}
ResgenSwift.main()

View File

@ -10,14 +10,14 @@ import Foundation
public class Shell { public class Shell {
@discardableResult @discardableResult
public static func shell(_ args: String...) -> (terminationStatus: Int32, output: String?) { public static func shell(launchPath: String = "/usr/bin/env", _ args: String...) -> (terminationStatus: Int32, output: String?) {
let task = Process() let task = Process()
task.launchPath = "/usr/bin/env" task.launchPath = launchPath
task.arguments = args task.arguments = args
let pipe = Pipe() let pipe = Pipe()
task.standardOutput = pipe task.standardOutput = pipe
task.launch() try? task.run()
task.waitUntilExit() task.waitUntilExit()
let data = pipe.fileHandleForReading.readDataToEndOfFile() let data = pipe.fileHandleForReading.readDataToEndOfFile()
@ -30,9 +30,9 @@ public class Shell {
} }
@discardableResult @discardableResult
public static func shell(_ args: [String]) -> (terminationStatus: Int32, output: String?) { public static func shell(launchPath: String = "/usr/bin/env", _ args: [String]) -> (terminationStatus: Int32, output: String?) {
let task = Process() let task = Process()
task.launchPath = "/usr/bin/env" task.launchPath = launchPath
task.arguments = args task.arguments = args
let pipe = Pipe() let pipe = Pipe()