64 lines
2.6 KiB
Swift
64 lines
2.6 KiB
Swift
import Foundation
|
|
|
|
enum MediaToolLocator {
|
|
static func executable(named name: String) -> URL? {
|
|
guard let bundled = Bundle.main.resourceURL?.appendingPathComponent(name),
|
|
FileManager.default.isExecutableFile(atPath: bundled.path) else {
|
|
return nil
|
|
}
|
|
return bundled
|
|
}
|
|
|
|
static func javascriptRuntimeArguments() -> [String] {
|
|
guard let runtime = executable(named: "deno") else { return [] }
|
|
return ["--js-runtimes", "deno:\(runtime.path)"]
|
|
}
|
|
}
|
|
|
|
enum MediaToolError: LocalizedError {
|
|
case missing(String)
|
|
case failed(String, String)
|
|
|
|
var errorDescription: String? {
|
|
switch self {
|
|
case .missing(let tool): "\(tool) fehlt im App-Paket. Installiere eine App-Version mit gebündelten Werkzeugen."
|
|
case .failed(let tool, let detail): "\(tool) ist fehlgeschlagen: \(detail)"
|
|
}
|
|
}
|
|
}
|
|
|
|
enum MediaProcess {
|
|
static func run(_ executable: URL, arguments: [String]) throws -> Data {
|
|
let id = UUID().uuidString
|
|
let outputURL = FileManager.default.temporaryDirectory.appendingPathComponent("tonuino-tool-\(id).out")
|
|
let errorURL = FileManager.default.temporaryDirectory.appendingPathComponent("tonuino-tool-\(id).err")
|
|
FileManager.default.createFile(atPath: outputURL.path, contents: nil)
|
|
FileManager.default.createFile(atPath: errorURL.path, contents: nil)
|
|
defer {
|
|
try? FileManager.default.removeItem(at: outputURL)
|
|
try? FileManager.default.removeItem(at: errorURL)
|
|
}
|
|
|
|
let outputHandle = try FileHandle(forWritingTo: outputURL)
|
|
let errorHandle = try FileHandle(forWritingTo: errorURL)
|
|
defer { try? outputHandle.close(); try? errorHandle.close() }
|
|
|
|
let process = Process()
|
|
process.executableURL = executable
|
|
process.arguments = arguments
|
|
process.standardOutput = outputHandle
|
|
process.standardError = errorHandle
|
|
do { try process.run() }
|
|
catch { throw MediaToolError.failed(executable.lastPathComponent, error.localizedDescription) }
|
|
process.waitUntilExit()
|
|
|
|
let output = try Data(contentsOf: outputURL)
|
|
let errorOutput = String(data: try Data(contentsOf: errorURL), encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
guard process.terminationStatus == 0 else {
|
|
let detail = errorOutput.isEmpty ? "Prozesscode \(process.terminationStatus)" : String(errorOutput.suffix(1800))
|
|
throw MediaToolError.failed(executable.lastPathComponent, detail)
|
|
}
|
|
return output
|
|
}
|
|
}
|