Check dependencies and outputs
This commit is contained in:
parent
a8b328efce
commit
f52c3bc8b9
77
Sources/Generator/Processing/DependencyCheck.swift
Normal file
77
Sources/Generator/Processing/DependencyCheck.swift
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
func checkDependencies() -> Bool {
|
||||||
|
print("--- DEPENDENCIES -----------------------------------")
|
||||||
|
print(" ")
|
||||||
|
let result = checkImageOptimAvailability() && checkMagickAvailability() && checkCwebpAvailability() && checkAvifAvailability()
|
||||||
|
print(" Complete: \(result ? "Yes" : "No")")
|
||||||
|
print(" ")
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private func checkImageOptimAvailability() -> Bool {
|
||||||
|
do {
|
||||||
|
let output = try safeShell("imageoptim --version")
|
||||||
|
let version = output.components(separatedBy: ".").compactMap { Int($0.trimmed) }
|
||||||
|
if version.count > 1 {
|
||||||
|
print(" ImageOptim: \(version.map { "\($0)" }.joined(separator: "."))")
|
||||||
|
} else {
|
||||||
|
print(" ImageOptim: Not found")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print(" ImageOptim: Failed to get version (\(error))")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private func checkMagickAvailability() -> Bool {
|
||||||
|
do {
|
||||||
|
let output = try safeShell("magick --version")
|
||||||
|
guard let version = output.components(separatedBy: "ImageMagick ").dropFirst().first?
|
||||||
|
.components(separatedBy: " ").first else {
|
||||||
|
print(" Magick: Not found")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
print(" Magick: \(version)")
|
||||||
|
} catch {
|
||||||
|
print(" Magick: Failed to get version (\(error))")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private func checkCwebpAvailability() -> Bool {
|
||||||
|
do {
|
||||||
|
let output = try safeShell("cwebp -version")
|
||||||
|
let version = output.components(separatedBy: ".").compactMap { Int($0.trimmed) }
|
||||||
|
if version.count > 1 {
|
||||||
|
print(" cwebp: \(version.map { "\($0)" }.joined(separator: "."))")
|
||||||
|
} else {
|
||||||
|
print(" cwebp: Not found")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print(" cwebp: Failed to get version (\(error))")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private func checkAvifAvailability() -> Bool {
|
||||||
|
do {
|
||||||
|
let output = try safeShell("npx avif --version")
|
||||||
|
let version = output.components(separatedBy: ".").compactMap { Int($0.trimmed) }
|
||||||
|
if version.count > 1 {
|
||||||
|
print(" avif: \(version.map { "\($0)" }.joined(separator: "."))")
|
||||||
|
} else {
|
||||||
|
print(" avif: Not found")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print(" avif: Failed to get version (\(error))")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
@ -46,7 +46,7 @@ final class ImageGenerator {
|
|||||||
|
|
||||||
private let numberOfTotalImages: Int
|
private let numberOfTotalImages: Int
|
||||||
|
|
||||||
private lazy var numberImagesToCreate = jobs.reduce(0) { $0 + $1.images.count } + multiJobs.count * 2
|
private lazy var numberOfImagesToCreate = jobs.reduce(0) { $0 + $1.images.count } + multiJobs.count * 2
|
||||||
|
|
||||||
private var numberOfImagesToOptimize = 0
|
private var numberOfImagesToOptimize = 0
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ final class ImageGenerator {
|
|||||||
for (baseImage, source) in multiJobs {
|
for (baseImage, source) in multiJobs {
|
||||||
createMultiImages(from: baseImage, path: source)
|
createMultiImages(from: baseImage, path: source)
|
||||||
}
|
}
|
||||||
print(" Generated images: \(numberOfGeneratedImages)/\(numberImagesToCreate)")
|
print(" Generated images: \(numberOfGeneratedImages)/\(numberOfImagesToCreate)")
|
||||||
optimizeImages()
|
optimizeImages()
|
||||||
print(" Optimized images: \(numberOfOptimizedImages)/\(numberOfImagesToOptimize)")
|
print(" Optimized images: \(numberOfOptimizedImages)/\(numberOfImagesToOptimize)")
|
||||||
|
|
||||||
@ -219,14 +219,18 @@ final class ImageGenerator {
|
|||||||
generatedImages.insert(webpPath)
|
generatedImages.insert(webpPath)
|
||||||
didGenerateImage()
|
didGenerateImage()
|
||||||
|
|
||||||
compress(at: source)
|
compress(at: sourcePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func createAVIF(at destination: String, from source: String, quality: Int = 55, effort: Int = 5) {
|
private func createAVIF(at destination: String, from source: String, quality: Int = 55, effort: Int = 5) {
|
||||||
let folder = destination.dropAfterLast("/")
|
let folder = destination.dropAfterLast("/")
|
||||||
let command = "npx avif --input=\(source) --quality=\(quality) --effort=\(effort) --output=\(folder) --overwrite"
|
let command = "npx avif --input=\(source) --quality=\(quality) --effort=\(effort) --output=\(folder) --overwrite"
|
||||||
do {
|
do {
|
||||||
_ = try safeShell(command)
|
let output = try safeShell(command)
|
||||||
|
if output == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
markImageAsFailed(destination, error: "Failed to create AVIF image: \(output)")
|
||||||
} catch {
|
} catch {
|
||||||
markImageAsFailed(destination, error: "Failed to create AVIF image")
|
markImageAsFailed(destination, error: "Failed to create AVIF image")
|
||||||
}
|
}
|
||||||
@ -235,18 +239,26 @@ final class ImageGenerator {
|
|||||||
private func createWEBP(at destination: String, from source: String, quality: Int = 75) {
|
private func createWEBP(at destination: String, from source: String, quality: Int = 75) {
|
||||||
let command = "cwebp \(source) -q \(quality) -o \(destination)"
|
let command = "cwebp \(source) -q \(quality) -o \(destination)"
|
||||||
do {
|
do {
|
||||||
_ = try safeShell(command)
|
let output = try safeShell(command)
|
||||||
|
if !output.contains("Error") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
markImageAsFailed(destination, error: "Failed to create WEBP image: \(output)")
|
||||||
} catch {
|
} catch {
|
||||||
markImageAsFailed(destination, error: "Failed to create WEBP image")
|
markImageAsFailed(destination, error: "Failed to create WEBP image: \(error)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func compress(at destination: String, quality: Int = 70) {
|
private func compress(at destination: String, quality: Int = 70) {
|
||||||
let command = "magick convert \(destination) -quality \(quality)% \(destination)"
|
let command = "magick convert \(destination) -quality \(quality)% \(destination)"
|
||||||
do {
|
do {
|
||||||
_ = try safeShell(command)
|
let output = try safeShell(command)
|
||||||
|
if output == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
markImageAsFailed(destination, error: "Failed to compress image: \(output)")
|
||||||
} catch {
|
} catch {
|
||||||
markImageAsFailed(destination, error: "Failed to compress image")
|
markImageAsFailed(destination, error: "Failed to compress image: \(error)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,11 +279,18 @@ final class ImageGenerator {
|
|||||||
private func optimizeImageBatch(_ batch: ArraySlice<String>) -> Bool {
|
private func optimizeImageBatch(_ batch: ArraySlice<String>) -> Bool {
|
||||||
let command = "imageoptim " + batch.joined(separator: " ")
|
let command = "imageoptim " + batch.joined(separator: " ")
|
||||||
do {
|
do {
|
||||||
_ = try safeShell(command)
|
let output = try safeShell(command)
|
||||||
|
if output.contains("Finished") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for image in batch {
|
||||||
|
markImageAsFailed(image, error: "Failed to optimize image: \(output)")
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
} catch {
|
} catch {
|
||||||
for image in batch {
|
for image in batch {
|
||||||
markImageAsFailed(image, error: "Failed to optimize image")
|
markImageAsFailed(image, error: "Failed to optimize image: \(error)")
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -281,7 +300,7 @@ final class ImageGenerator {
|
|||||||
|
|
||||||
private func didGenerateImage(count: Int = 1) {
|
private func didGenerateImage(count: Int = 1) {
|
||||||
numberOfGeneratedImages += count
|
numberOfGeneratedImages += count
|
||||||
print(" Generated images: \(numberOfGeneratedImages)/\(numberImagesToCreate) \r", terminator: "")
|
print(" Generated images: \(numberOfGeneratedImages)/\(numberOfImagesToCreate) \r", terminator: "")
|
||||||
fflush(stdout)
|
fflush(stdout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ struct CHGenerator: ParsableCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func loadConfiguration(at configPath: String) -> Configuration? {
|
private func loadConfiguration(at configPath: String) -> Configuration? {
|
||||||
print(" ")
|
|
||||||
print("--- CONFIGURATION ----------------------------------")
|
print("--- CONFIGURATION ----------------------------------")
|
||||||
print(" ")
|
print(" ")
|
||||||
print(" Configuration file: \(configPath)")
|
print(" Configuration file: \(configPath)")
|
||||||
@ -128,6 +127,12 @@ private func finish(start: Date) {
|
|||||||
private func generate(configPath: String) throws {
|
private func generate(configPath: String) throws {
|
||||||
let start = Date()
|
let start = Date()
|
||||||
|
|
||||||
|
print(" ")
|
||||||
|
|
||||||
|
guard checkDependencies() else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 1. Load configuration
|
// 1. Load configuration
|
||||||
guard let configuration = loadConfiguration(at: configPath) else {
|
guard let configuration = loadConfiguration(at: configPath) else {
|
||||||
return
|
return
|
||||||
|
Loading…
Reference in New Issue
Block a user