202 lines
6.2 KiB
Swift
202 lines
6.2 KiB
Swift
//
|
|
// KissMatrix.swift
|
|
// KissMeMatrix
|
|
//
|
|
// Created by ened-book-m1 on 2023/06/20.
|
|
//
|
|
|
|
import Foundation
|
|
import KissMe
|
|
|
|
|
|
enum RunMode: String {
|
|
case simulator = "sim"
|
|
case runner = "run"
|
|
}
|
|
|
|
|
|
struct Model: Codable {
|
|
let indexSets: [IndexSet]
|
|
|
|
struct IndexSet: Codable {
|
|
let name: String
|
|
let memo: String
|
|
let config: String?
|
|
let runner: String
|
|
let weight: Double
|
|
|
|
func build(date: Date) -> (URL, [String])? {
|
|
guard let _ = name.kmiIndex else {
|
|
return nil
|
|
}
|
|
|
|
let command = URL.currentDirectory().appending(path: runner)
|
|
|
|
let day = date.yyyyMMdd
|
|
let time = date.HHmmss
|
|
var args: [String] = [name, day, time]
|
|
|
|
if let config = config {
|
|
args.append(config)
|
|
}
|
|
return (command, args)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
class KissMatrix {
|
|
|
|
func run() {
|
|
|
|
func printUsage() {
|
|
let appName = (CommandLine.arguments[0] as NSString).lastPathComponent
|
|
print("\(appName) [sim|run] model.json [yyyyMMdd] [HHmmss]")
|
|
}
|
|
|
|
guard CommandLine.argc >= 3 else {
|
|
printUsage()
|
|
return
|
|
}
|
|
|
|
|
|
let runDate: Date
|
|
let mode = RunMode(rawValue: CommandLine.arguments[1])
|
|
switch mode {
|
|
case .runner:
|
|
runDate = Date()
|
|
case .simulator:
|
|
guard CommandLine.argc == 5 else {
|
|
printUsage()
|
|
return
|
|
}
|
|
guard let (year, month, day) = CommandLine.arguments[3].yyyyMMdd else {
|
|
print("Invalid [yyyyMMdd] argument")
|
|
printUsage()
|
|
return
|
|
}
|
|
guard let (hour, min, sec) = CommandLine.arguments[4].HHmmss else {
|
|
print("Invalid [HHmmss] argument")
|
|
printUsage()
|
|
return
|
|
}
|
|
var date = Date(timeIntervalSince1970: 0)
|
|
date.change(year: year, month: month, day: day)
|
|
date.change(hour: hour, min: min, sec: sec)
|
|
runDate = date
|
|
default:
|
|
printUsage()
|
|
return
|
|
}
|
|
|
|
|
|
let modelJson = CommandLine.arguments[2]
|
|
guard let model = loadModel(modelJson) else { return }
|
|
print("Loaded \(model.indexSets.count) index set from \(modelJson)")
|
|
|
|
let semaphore = DispatchSemaphore(value: 0)
|
|
Task {
|
|
let indexResult = try await withThrowingTaskGroup(of: KissIndexResult?.self, returning: [KissIndexResult].self) { taskGroup in
|
|
for indexSet in model.indexSets {
|
|
guard let (runUrl, args) = indexSet.build(date: runDate) else {
|
|
print("Cannot get command from \(indexSet.name)")
|
|
continue
|
|
}
|
|
|
|
taskGroup.addTask {
|
|
do {
|
|
let result = try await self.runIndex(runUrl, args: args)
|
|
return result
|
|
} catch {
|
|
print(error)
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
var taskResult = [KissIndexResult]()
|
|
for try await result in taskGroup.compactMap( { $0 }) {
|
|
taskResult.append(result)
|
|
}
|
|
return taskResult
|
|
}
|
|
|
|
for result in indexResult {
|
|
print(result)
|
|
}
|
|
semaphore.signal()
|
|
}
|
|
semaphore.wait()
|
|
}
|
|
|
|
|
|
private func runIndex(_ runUrl: URL, args: [String]) async throws -> KissIndexResult {
|
|
assert(args.count >= 3)
|
|
return try await withUnsafeThrowingContinuation { continuation in
|
|
let kmi = args[0]
|
|
|
|
let output = Pipe()
|
|
//let output = FileHandle(forWritingTo: subPath.appending(path: fileName))
|
|
|
|
let task = Process()
|
|
task.currentDirectoryURL = URL.currentDirectory()
|
|
task.executableURL = runUrl
|
|
task.arguments = args
|
|
task.standardOutput = output
|
|
//task.standardError = error
|
|
//task.qualityOfService = .userInitiated
|
|
|
|
print("curPath: \(task.currentDirectoryPath)")
|
|
print("runPath: \(runUrl)")
|
|
print("args: \(args)")
|
|
|
|
do {
|
|
try task.run()
|
|
task.waitUntilExit()
|
|
} catch {
|
|
print("run error \(error)")
|
|
continuation.resume(throwing: error)
|
|
}
|
|
|
|
let data = output.fileHandleForReading.readDataToEndOfFile()
|
|
if data.isEmpty {
|
|
continuation.resume(throwing: GeneralError.emptyData(kmi))
|
|
return
|
|
}
|
|
|
|
do {
|
|
try data.write(to: indexLogFile(kmi))
|
|
|
|
let indexResult = try JSONDecoder().decode(KissIndexResult.self, from: data)
|
|
continuation.resume(returning: indexResult)
|
|
} catch {
|
|
print("jsonError \(kmi)")
|
|
continuation.resume(throwing: error)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private func indexLogFile(_ kmi: String) -> URL {
|
|
let subPath = URL.currentDirectory().appending(path: "log/index")
|
|
try? FileManager.default.createDirectory(at: subPath, withIntermediateDirectories: true)
|
|
|
|
let date = Date()
|
|
let fileName = "\(date.yyyyMMdd_HHmmssSSSS_forFile)-\(kmi).log"
|
|
return subPath.appending(path: fileName)
|
|
}
|
|
|
|
|
|
private func loadModel(_ jsonFile: String) -> Model? {
|
|
do {
|
|
let configUrl = URL.currentDirectory().appending(path: jsonFile)
|
|
let data = try Data(contentsOf: configUrl, options: .uncached)
|
|
let model = try JSONDecoder().decode(Model.self, from: data)
|
|
return model
|
|
} catch {
|
|
print(error)
|
|
return nil
|
|
}
|
|
}
|
|
}
|