Add --project-directory option to generate command to easily use relative path
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit

This commit is contained in:
2022-08-31 16:42:22 +02:00
parent 3d60513c08
commit e9bc779da6
22 changed files with 136 additions and 67 deletions

View File

@ -246,4 +246,18 @@ tags: []
... ...
``` ```
### Usage
If you **don't** install ResgenSwift:
```sh
swift run -c release ResgenSwift generate path/to/configuration.yml --project-directory ${PROJECT_DIR}
```
If you install ResgenSwift:
```sh
resgen-swift generate path/to/configuration.yml --project-directory ${PROJECT_DIR}
```
> ⚠️ Every path in `configuration.yml` will be prepended by content of `--project-directory` if they are relative path (not starting with `/`)

View File

@ -92,7 +92,7 @@ struct Colors: ParsableCommand {
// MARK: - Helpers // MARK: - Helpers
private func deleteCurrentColors() { private func deleteCurrentColors() {
Shell.shell("rm", "-rf", "\(options.xcassetsPath)/Colors/*") Shell.shell(["rm", "-rf", "\(options.xcassetsPath)/Colors/*"])
} }
} }

View File

@ -17,7 +17,7 @@ struct ColorExtensionGenerator {
// Create file if not exists // Create file if not exists
let fileManager = FileManager() let fileManager = FileManager()
if fileManager.fileExists(atPath: extensionFilePath) == false { if fileManager.fileExists(atPath: extensionFilePath) == false {
Shell.shell("touch", "\(extensionFilePath)") Shell.shell(["touch", "\(extensionFilePath)"])
} }
// Create extension content // Create extension content

View File

@ -20,11 +20,12 @@ struct ColorXcassetHelper {
private static func generateColorSetAssets(from color: ParsedColor, to xcassetsPath: String) { private static func generateColorSetAssets(from color: ParsedColor, to xcassetsPath: String) {
// Create ColorSet // Create ColorSet
let colorSetPath = "\(xcassetsPath)/Colors/\(color.name).colorset" let colorSetPath = "\(xcassetsPath)/Colors/\(color.name).colorset"
Shell.shell("mkdir", "-p", "\(colorSetPath)") Shell.shell(["mkdir",
"-p", "\(colorSetPath)"])
// Create Contents.json in ColorSet // Create Contents.json in ColorSet
let contentsJsonPath = "\(colorSetPath)/Contents.json" let contentsJsonPath = "\(colorSetPath)/Contents.json"
Shell.shell("touch", "\(contentsJsonPath)") Shell.shell(["touch", "\(contentsJsonPath)"])
// Write content in Contents.json // Write content in Contents.json
let contentsJsonPathURL = URL(fileURLWithPath: contentsJsonPath) let contentsJsonPathURL = URL(fileURLWithPath: contentsJsonPath)

View File

@ -60,7 +60,7 @@ class FontsToolHelper {
private static func getFontName(atPath path: String) -> String { private static func getFontName(atPath path: String) -> String {
//print("fc-scan --format %{postscriptname} \(path)") //print("fc-scan --format %{postscriptname} \(path)")
// Get real font name // Get real font name
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 = FontsToolError.fcScan(path, task.terminationStatus, task.output) let error = FontsToolError.fcScan(path, task.terminationStatus, task.output)

View File

@ -14,7 +14,7 @@ class FontExtensionGenerator {
// Check file if not exists // Check file if not exists
let fileManager = FileManager() let fileManager = FileManager()
if fileManager.fileExists(atPath: extensionFilePath) == false { if fileManager.fileExists(atPath: extensionFilePath) == false {
Shell.shell("touch", "\(extensionFilePath)") Shell.shell(["touch", "\(extensionFilePath)"])
} }
// Create extension content // Create extension content

View File

@ -0,0 +1,18 @@
//
// StringExtensions.swift
//
//
// Created by Thibaut Schmitt on 31/08/2022.
//
import Foundation
extension String {
func prependIfRelativePath(_ prependPath: String) -> String {
if self.hasPrefix("/") {
return self
}
return prependPath + self
}
}

View File

@ -40,13 +40,17 @@ struct Generate: ParsableCommand {
print(" - \(configuration.strings.count) strings configuration") print(" - \(configuration.strings.count) strings configuration")
print(" - \(configuration.tags.count) tags configuration") print(" - \(configuration.tags.count) tags configuration")
print() print()
print("Input file: \(configuration.colors.first?.inputFile ?? "no input file")")
// Execute commands // Execute commands
configuration.runnableConfigurations configuration.runnableConfigurations
.forEach { .forEach {
$0.run(force: options.forceGeneration) $0.run(projectDirectory: options.projectDirectory,
force: options.forceGeneration)
print("\n") print("\n")
} }
print("[\(Self.toolName)] Resgen ended") print("[\(Self.toolName)] Resgen ended")
} }
} }

View File

@ -16,4 +16,13 @@ struct GenerateOptions: ParsableArguments {
@Argument(help: "Configuration file.", transform: { $0.replaceTiltWithHomeDirectoryPath() }) @Argument(help: "Configuration file.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
var configurationFile: String var configurationFile: String
@Option(help: "Project directory. It will be added to every relative path (path that does not start with `/`",
transform: {
if $0.last == "/" {
return $0
}
return $0 + "/"
})
var projectDirectory: String
} }

View File

@ -1,5 +1,5 @@
// //
// ColorsConfiguration+ShellCommandable.swift // ColorsConfiguration+Runnable.swift
// //
// //
// Created by Thibaut Schmitt on 30/08/2022. // Created by Thibaut Schmitt on 30/08/2022.
@ -8,7 +8,7 @@
import Foundation import Foundation
extension ColorsConfiguration: Runnable { extension ColorsConfiguration: Runnable {
func run(force: Bool) { func run(projectDirectory: String, force: Bool) {
var args = [String]() var args = [String]()
if force { if force {
@ -16,13 +16,13 @@ extension ColorsConfiguration: Runnable {
} }
args += [ args += [
inputFile, inputFile.prependIfRelativePath(projectDirectory),
"--style", "--style",
style, style,
"--xcassets-path", "--xcassets-path",
xcassetsPath, xcassetsPath.prependIfRelativePath(projectDirectory),
"--extension-output-path", "--extension-output-path",
extensionOutputPath, extensionOutputPath.prependIfRelativePath(projectDirectory),
"--static-members", "--static-members",
"\(staticMembersOptions)" "\(staticMembersOptions)"
] ]
@ -39,7 +39,8 @@ extension ColorsConfiguration: Runnable {
extensionSuffix extensionSuffix
] ]
} }
print("Colors args:")
Colors.main(args) dump(args)
//Colors.main(args)
} }
} }

View File

@ -1,5 +1,5 @@
// //
// FontsConfiguration+ShellCommandable.swift // FontsConfiguration+Runnable.swift
// //
// //
// Created by Thibaut Schmitt on 30/08/2022. // Created by Thibaut Schmitt on 30/08/2022.
@ -8,7 +8,7 @@
import Foundation import Foundation
extension FontsConfiguration: Runnable { extension FontsConfiguration: Runnable {
func run(force: Bool) { func run(projectDirectory: String, force: Bool) {
var args = [String]() var args = [String]()
if force { if force {
@ -18,7 +18,7 @@ extension FontsConfiguration: Runnable {
args += [ args += [
inputFile, inputFile,
"--extension-output-path", "--extension-output-path",
extensionOutputPath, extensionOutputPath.prependIfRelativePath(projectDirectory),
"--static-members", "--static-members",
"\(staticMembersOptions)" "\(staticMembersOptions)"
] ]

View File

@ -1,5 +1,5 @@
// //
// ImagesConfiguration+ShellCommandable.swift // ImagesConfiguration+Runnable.swift
// //
// //
// Created by Thibaut Schmitt on 30/08/2022. // Created by Thibaut Schmitt on 30/08/2022.
@ -8,7 +8,7 @@
import Foundation import Foundation
extension ImagesConfiguration: Runnable { extension ImagesConfiguration: Runnable {
func run(force: Bool) { func run(projectDirectory: String, force: Bool) {
var args = [String]() var args = [String]()
if force { if force {
@ -16,11 +16,11 @@ extension ImagesConfiguration: Runnable {
} }
args += [ args += [
inputFile, inputFile.prependIfRelativePath(projectDirectory),
"--xcassets-path", "--xcassets-path",
xcassetsPath, xcassetsPath.prependIfRelativePath(projectDirectory),
"--extension-output-path", "--extension-output-path",
extensionOutputPath, extensionOutputPath.prependIfRelativePath(projectDirectory),
"--static-members", "--static-members",
"\(staticMembersOptions)" "\(staticMembersOptions)"
] ]

View File

@ -8,6 +8,6 @@
import Foundation import Foundation
protocol Runnable { protocol Runnable {
func run(force: Bool) func run(projectDirectory: String, force: Bool)
} }

View File

@ -1,5 +1,5 @@
// //
// StringsConfiguration+ShellCommandable.swift // StringsConfiguration+Runnable.swift
// //
// //
// Created by Thibaut Schmitt on 30/08/2022. // Created by Thibaut Schmitt on 30/08/2022.
@ -8,7 +8,7 @@
import Foundation import Foundation
extension StringsConfiguration: Runnable { extension StringsConfiguration: Runnable {
func run(force: Bool) { func run(projectDirectory: String, force: Bool) {
var args = [String]() var args = [String]()
if force { if force {
@ -16,15 +16,15 @@ extension StringsConfiguration: Runnable {
} }
args += [ args += [
inputFile, inputFile.prependIfRelativePath(projectDirectory),
"--output-path", "--output-path",
outputPath, outputPath.prependIfRelativePath(projectDirectory),
"--langs", "--langs",
langs, langs,
"--default-lang", "--default-lang",
defaultLang, defaultLang,
"--extension-output-path", "--extension-output-path",
extensionOutputPath, extensionOutputPath.prependIfRelativePath(projectDirectory),
"--static-members", "--static-members",
"\(staticMembersOptions)" "\(staticMembersOptions)"
] ]

View File

@ -1,5 +1,5 @@
// //
// TagsConfiguration+ShellCommandable.swift // TagsConfiguration+Runnable.swift
// //
// //
// Created by Thibaut Schmitt on 30/08/2022. // Created by Thibaut Schmitt on 30/08/2022.
@ -8,7 +8,7 @@
import Foundation import Foundation
extension TagsConfiguration: Runnable { extension TagsConfiguration: Runnable {
func run(force: Bool) { func run(projectDirectory: String, force: Bool) {
var args = [String]() var args = [String]()
if force { if force {
@ -16,11 +16,11 @@ extension TagsConfiguration: Runnable {
} }
args += [ args += [
inputFile, inputFile.prependIfRelativePath(projectDirectory),
"--lang", "--lang",
lang, lang,
"--extension-output-path", "--extension-output-path",
extensionOutputPath, extensionOutputPath.prependIfRelativePath(projectDirectory),
"--static-members", "--static-members",
"\(staticMembersOptions)" "\(staticMembersOptions)"
] ]

View File

@ -34,7 +34,7 @@ class ImageExtensionGenerator {
// Create file if not exists // Create file if not exists
let fileManager = FileManager() let fileManager = FileManager()
if fileManager.fileExists(atPath: extensionFilePath) == false { if fileManager.fileExists(atPath: extensionFilePath) == false {
Shell.shell("touch", "\(extensionFilePath)") Shell.shell(["touch", "\(extensionFilePath)"])
} }
// Generate extension // Generate extension
@ -47,7 +47,7 @@ class ImageExtensionGenerator {
// Create file if not exists // Create file if not exists
let fileManager = FileManager() let fileManager = FileManager()
if fileManager.fileExists(atPath: extensionFilePath) == false { if fileManager.fileExists(atPath: extensionFilePath) == false {
Shell.shell("touch", "\(extensionFilePath)") Shell.shell(["touch", "\(extensionFilePath)"])
} }
// Create extension content // Create extension content

View File

@ -55,7 +55,7 @@ class XcassetsGenerator {
// Create imageset folder // Create imageset folder
let imagesetName = "\(parsedImage.name).imageset" let imagesetName = "\(parsedImage.name).imageset"
let imagesetPath = "\(xcassetsPath)/\(imagesetName)" let imagesetPath = "\(xcassetsPath)/\(imagesetName)"
Shell.shell("mkdir", "-p", imagesetPath) Shell.shell(["mkdir", "-p", imagesetPath])
// Store managed images path // Store managed images path
generatedAssetsPaths.append(imagesetName) generatedAssetsPaths.append(imagesetName)
@ -96,16 +96,22 @@ class XcassetsGenerator {
// convert path/to/image.png -resize 200x300 path/to/output.png // convert path/to/image.png -resize 200x300 path/to/output.png
// convert path/to/image.png -resize 200x path/to/output.png // convert path/to/image.png -resize 200x path/to/output.png
// convert path/to/image.png -resize x300 path/to/output.png // convert path/to/image.png -resize x300 path/to/output.png
Shell.shell("convert", "\(imageData.path)", "-resize", "\(convertArguments.x1.width ?? "")x\(convertArguments.x1.height ?? "")", output1x) Shell.shell(["convert", "\(imageData.path)",
Shell.shell("convert", "\(imageData.path)", "-resize", "\(convertArguments.x2.width ?? "")x\(convertArguments.x2.height ?? "")", output2x) "-resize", "\(convertArguments.x1.width ?? "")x\(convertArguments.x1.height ?? "")",
Shell.shell("convert", "\(imageData.path)", "-resize", "\(convertArguments.x3.width ?? "")x\(convertArguments.x3.height ?? "")", output3x) output1x])
Shell.shell(["convert", "\(imageData.path)",
"-resize", "\(convertArguments.x2.width ?? "")x\(convertArguments.x2.height ?? "")",
output2x])
Shell.shell(["convert", "\(imageData.path)",
"-resize", "\(convertArguments.x3.width ?? "")x\(convertArguments.x3.height ?? "")",
output3x])
} }
// Write Content.json // Write Content.json
let imagesetContentJson = parsedImage.contentJson let imagesetContentJson = parsedImage.contentJson
let contentJsonFilePath = "\(imagesetPath)/Contents.json" let contentJsonFilePath = "\(imagesetPath)/Contents.json"
if fileManager.fileExists(atPath: contentJsonFilePath) == false { if fileManager.fileExists(atPath: contentJsonFilePath) == false {
Shell.shell("touch", "\(contentJsonFilePath)") Shell.shell(["touch", "\(contentJsonFilePath)"])
} }
let contentJsonFilePathURL = URL(fileURLWithPath: contentJsonFilePath) let contentJsonFilePathURL = URL(fileURLWithPath: contentJsonFilePath)
@ -160,8 +166,8 @@ class XcassetsGenerator {
} }
// Info unavailable -> do not bypass // Info unavailable -> do not bypass
let taskWidth = Shell.shell("identify", "-format", "%w", xcassetImagePath) let taskWidth = Shell.shell(["identify", "-format", "%w", xcassetImagePath])
let taskHeight = Shell.shell("identify", "-format", "%h", xcassetImagePath) let taskHeight = Shell.shell(["identify", "-format", "%h", xcassetImagePath])
guard taskWidth.terminationStatus == 0, guard taskWidth.terminationStatus == 0,
taskHeight.terminationStatus == 0 else { taskHeight.terminationStatus == 0 else {
return false return false

View File

@ -95,7 +95,7 @@ struct Images: ParsableCommand {
@discardableResult @discardableResult
static func getSvgConverterPath() -> String { static func getSvgConverterPath() -> String {
let taskSvgConverter = Shell.shell("which", "rsvg-convert") let taskSvgConverter = Shell.shell(["which", "rsvg-convert"])
if taskSvgConverter.terminationStatus == 0 { if taskSvgConverter.terminationStatus == 0 {
return taskSvgConverter.output!.removeCharacters(from: CharacterSet.whitespacesAndNewlines) return taskSvgConverter.output!.removeCharacters(from: CharacterSet.whitespacesAndNewlines)
} }

View File

@ -118,7 +118,7 @@ class StringsFileGenerator {
// Create file if not exists // Create file if not exists
let fileManager = FileManager() let fileManager = FileManager()
if fileManager.fileExists(atPath: extensionFilePath) == false { if fileManager.fileExists(atPath: extensionFilePath) == false {
Shell.shell("touch", "\(extensionFilePath)") Shell.shell(["touch", "\(extensionFilePath)"])
} }
// Create extension content // Create extension content

View File

@ -38,7 +38,7 @@ class TagsGenerator {
// Create file if not exists // Create file if not exists
let fileManager = FileManager() let fileManager = FileManager()
if fileManager.fileExists(atPath: extensionFilePath) == false { if fileManager.fileExists(atPath: extensionFilePath) == false {
Shell.shell("touch", "\(extensionFilePath)") Shell.shell(["touch", "\(extensionFilePath)"])
} }
// Create extension content // Create extension content

View File

@ -40,20 +40,20 @@ struct Twine: ParsableCommand {
// Generate strings files (lproj files) // Generate strings files (lproj files)
for lang in options.langs { for lang in options.langs {
Shell.shell(Self.twineExecutable, Shell.shell([Self.twineExecutable,
"generate-localization-file", options.inputFile, "generate-localization-file", options.inputFile,
"--lang", "\(lang)", "--lang", "\(lang)",
"\(options.outputPath)/\(lang).lproj/\(options.inputFilenameWithoutExt).strings", "\(options.outputPath)/\(lang).lproj/\(options.inputFilenameWithoutExt).strings",
"--tags=ios,iosonly,iosOnly") "--tags=ios,iosonly,iosOnly"])
} }
// Generate extension // Generate extension
Shell.shell(Self.twineExecutable, Shell.shell([Self.twineExecutable,
"generate-localization-file", options.inputFile, "generate-localization-file", options.inputFile,
"--format", "apple-swift", "--format", "apple-swift",
"--lang", "\(options.defaultLang)", "--lang", "\(options.defaultLang)",
options.extensionFilePath, options.extensionFilePath,
"--tags=ios,iosonly,iosOnly") "--tags=ios,iosonly,iosOnly"])
print("[\(Self.toolName)] Strings generated") print("[\(Self.toolName)] Strings generated")
} }

View File

@ -9,32 +9,48 @@ import Foundation
public class Shell { public class Shell {
@discardableResult public static var environment: [String: String] {
public static func shell(launchPath: String = "/usr/bin/env", _ args: String...) -> (terminationStatus: Int32, output: String?) { ProcessInfo.processInfo.environment
let task = Process()
task.launchPath = launchPath
task.arguments = args
let pipe = Pipe()
task.standardOutput = pipe
try? task.run()
task.waitUntilExit()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
guard let output: String = String(data: data, encoding: .utf8) else {
return (terminationStatus: task.terminationStatus, output: nil)
}
return (terminationStatus: task.terminationStatus, output: output)
} }
// @discardableResult
// public static func shell(launchPath: String = "/usr/bin/env", _ args: String...) -> (terminationStatus: Int32, output: String?) {
// let task = Process()
// task.launchPath = launchPath
// task.arguments = args
//
// var currentEnv = ProcessInfo.processInfo.environment
// for (key, value) in environment {
// currentEnv[key] = value
// }
// task.environment = currentEnv
//
// let pipe = Pipe()
// task.standardOutput = pipe
// try? task.run()
// task.waitUntilExit()
//
// let data = pipe.fileHandleForReading.readDataToEndOfFile()
//
// guard let output: String = String(data: data, encoding: .utf8) else {
// return (terminationStatus: task.terminationStatus, output: nil)
// }
//
// return (terminationStatus: task.terminationStatus, output: output)
// }
@discardableResult @discardableResult
public static func shell(launchPath: String = "/usr/bin/env", _ 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 = launchPath task.launchPath = launchPath
task.arguments = args task.arguments = args
var currentEnv = ProcessInfo.processInfo.environment
for (key, value) in environment {
currentEnv[key] = value
}
task.environment = currentEnv
let pipe = Pipe() let pipe = Pipe()
task.standardOutput = pipe task.standardOutput = pipe
task.launch() task.launch()