From a0cca774d418404de3bb2bab10fbd0115b1fc486 Mon Sep 17 00:00:00 2001 From: ened Date: Fri, 30 Jun 2023 16:23:08 +0900 Subject: [PATCH] Run golder using sub-process --- .../Common/Foundation+Extensions.swift | 8 + ...ndexResult.swift => KissIndexResult.swift} | 2 +- KissMe/Sources/Index/Runner.swift | 81 ++++++ KissMeGolder/Sources/KissGolder.swift | 238 +++++++++++++++++- KissMeGolder/Sources/main.swift | 2 +- KissMeMatrix/Sources/KissMatrix.swift | 113 +++++---- .../macos/KissMe.xcodeproj/project.pbxproj | 12 +- .../xcschemes/KissMeGolder.xcscheme | 6 + .../xcschemes/KissMeMatrix.xcscheme | 2 +- scripts/build.sh | 2 + 10 files changed, 403 insertions(+), 63 deletions(-) rename KissMe/Sources/Index/{IndexResult.swift => KissIndexResult.swift} (98%) create mode 100644 KissMe/Sources/Index/Runner.swift diff --git a/KissMe/Sources/Common/Foundation+Extensions.swift b/KissMe/Sources/Common/Foundation+Extensions.swift index cddbc08..b809db1 100644 --- a/KissMe/Sources/Common/Foundation+Extensions.swift +++ b/KissMe/Sources/Common/Foundation+Extensions.swift @@ -178,6 +178,14 @@ extension String { return dateFormatter.date(from: self) } + public var modelDate: Date? { + // ex) 20230628 120657 + let dateFormatter = DateFormatter() + dateFormatter.timeZone = TimeZone(abbreviation: "KST") + dateFormatter.dateFormat = "yyyyMMdd HHmmss" + return dateFormatter.date(from: self) + } + public var hasComma: Bool { return nil != rangeOfCharacter(from: commaCharSet) } diff --git a/KissMe/Sources/Index/IndexResult.swift b/KissMe/Sources/Index/KissIndexResult.swift similarity index 98% rename from KissMe/Sources/Index/IndexResult.swift rename to KissMe/Sources/Index/KissIndexResult.swift index 75b8cf7..31642b4 100644 --- a/KissMe/Sources/Index/IndexResult.swift +++ b/KissMe/Sources/Index/KissIndexResult.swift @@ -1,5 +1,5 @@ // -// IndexResult.swift +// KissIndexResult.swift // KissMe // // Created by ened-book-m1 on 2023/06/20. diff --git a/KissMe/Sources/Index/Runner.swift b/KissMe/Sources/Index/Runner.swift new file mode 100644 index 0000000..a61aac5 --- /dev/null +++ b/KissMe/Sources/Index/Runner.swift @@ -0,0 +1,81 @@ +// +// Runner.swift +// KissMe +// +// Created by ened-book-m1 on 2023/06/30. +// + +import Foundation + + +public protocol Runner { + associatedtype KResult: Decodable + + var currentDirectoryUrl: URL { get } + var executableUrl: URL { get } + + var outputUrl: URL? { get } + var errorUrl: URL? { get } + + func run() async throws +} + + +extension Runner { + + var currentDirectoryUrl: URL { URL.currentDirectory() } + + /* + func run() async throws { + return try await withUnsafeThrowingContinuation { continuation in + let model = args[0] + + let outputUrl = KissGolder.matrixLogFile(date: date) + FileManager.default.createFile(atPath: outputUrl.path, contents: nil) + let output = FileHandle(forWritingAtPath: outputUrl.path) + + if let outputUrl = outputUrl { + + } + + let task = Process() + task.currentDirectoryURL = currentDirectoryUrl + task.executableURL = executableUrl + task.arguments = args + task.standardOutput = output + task.standardError = FileHandle.standardError + + printError("curPath: \(task.currentDirectoryPath)") + printError("runPath: \(runUrl.path)") + printError("args: \(args)") + + do { + try task.run() + task.waitUntilExit() + } catch { + printError("run error \(error)") + continuation.resume(throwing: error) + } + + try? output?.close() + + guard let data = try? Data(contentsOf: outputUrl) else { + continuation.resume(throwing: GeneralError.emptyData(model)) + return + } + if data.isEmpty { + continuation.resume(throwing: GeneralError.emptyData(model)) + return + } + + do { + let matrixResult = try JSONDecoder().decode(KissMatrixResult.self, from: data) + continuation.resume(returning: matrixResult) + } catch { + printError("jsonError \(model)") + continuation.resume(throwing: error) + } + } + } + */ +} diff --git a/KissMeGolder/Sources/KissGolder.swift b/KissMeGolder/Sources/KissGolder.swift index 239538c..2e5edb7 100644 --- a/KissMeGolder/Sources/KissGolder.swift +++ b/KissMeGolder/Sources/KissGolder.swift @@ -6,11 +6,245 @@ // import Foundation +import KissMe -class KissMatrix { +class KissGolder { func run() { - print("hello..") + + func printUsage() { + let appName = (CommandLine.arguments[0] as NSString).lastPathComponent + printError("\(appName) [sim|run] golder.json") + } + + guard CommandLine.argc >= 3 else { + printUsage() + return + } + + let mode = RunMode(rawValue: CommandLine.arguments[1]) + + let golderJson = CommandLine.arguments[2] + guard let model = loadModel(golderJson) else { return } + printError("Loaded \(golderJson)") + + + switch mode { + case .runner: + runInterval(model: model) + case .simulator: + runSimulator(model: model) + default: break + } + } + + + private func runInterval(model: Model) { + let semaphore = DispatchSemaphore(value: 0) + Task { + while true { + let date = Date().addingTimeInterval(-59) + if let endDate = model.endDate, date > endDate { + break + } + + guard let (runUrl, args) = model.build(date: date, mode: .runner) else { + printError("Cannot get command from \(model.name)") + break + } + + do { + let result = try await self.runMatrix(runUrl, args: args, date: date) + runStrategy(result, date: date) + } catch { + printError(error) + } + + try await Task.sleep(nanoseconds: 1_000_000_000 * UInt64(model.balanceInterval)) + } + + semaphore.signal() + } + semaphore.wait() + } + + + private func runSimulator(model: Model) { + guard let startDate = model.startDate else { + printError("No startDate to simulate!") + return + } + guard let endDate = model.endDate else { + printError("No endDate to simulate!") + return + } + + let semaphore = DispatchSemaphore(value: 0) + Task { + do { + var date = startDate + while date <= endDate { + guard let (runUrl, args) = model.build(date: date, mode: .simulator) else { + printError("Cannot get command from \(model.name)") + return + } + + let result = try await self.runMatrix(runUrl, args: args, date: date) + runStrategy(result, date: date) + + date.addTimeInterval(TimeInterval(model.balanceInterval)) + } + } catch { + printError(error) + } + + semaphore.signal() + } + semaphore.wait() + } + + + private func runMatrix(_ runUrl: URL, args: [String], date: Date) async throws -> KissMatrixResult { + return try await withUnsafeThrowingContinuation { continuation in + let model = args[0] + + let outputUrl = KissGolder.matrixLogFile(date: date) + FileManager.default.createFile(atPath: outputUrl.path, contents: nil) + let output = FileHandle(forWritingAtPath: outputUrl.path) + + let task = Process() + task.currentDirectoryURL = URL.currentDirectory() + task.executableURL = runUrl + task.arguments = args + task.standardOutput = output + task.standardError = FileHandle.standardError + task.qualityOfService = .default + + printError("curPath: \(task.currentDirectoryPath)") + printError("runPath: \(runUrl.path)") + printError("args: \(args)") + + do { + try task.run() + task.waitUntilExit() + } catch { + printError("run error \(error)") + continuation.resume(throwing: error) + } + + try? output?.close() + + guard let data = try? Data(contentsOf: outputUrl) else { + continuation.resume(throwing: GeneralError.emptyData(model)) + return + } + if data.isEmpty { + continuation.resume(throwing: GeneralError.emptyData(model)) + return + } + + do { + let matrixResult = try JSONDecoder().decode(KissMatrixResult.self, from: data) + continuation.resume(returning: matrixResult) + } catch { + printError("jsonError \(model)") + continuation.resume(throwing: error) + } + } + } + + + 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 { + printError(error) + return nil + } + } + + + static private func matrixLogFile(date: Date) -> URL { + let subPath = "log/matrix" + let subFile = "\(subPath)/\(date.yyyyMMdd_HHmmssSSSS_forFile).log" + + let fileUrl = URL.currentDirectory().appending(path: subFile) + createSubpath(subPath) + return fileUrl + } + + + static func createSubpath(_ name: String) { + let subPath = URL.currentDirectory().appending(path: name) + try? FileManager.default.createDirectory(at: subPath, withIntermediateDirectories: true) + } + + + private func runStrategy(_ result: KissMatrixResult, date: Date) { + // TODO: work + printError("<<< RUN >>> ---------------- strategy \(result.output.count) \(date.yyyyMMdd_HHmmss_forTime)") + } +} + + +enum RunMode: String { + case simulator = "sim" + case runner = "run" +} + + +struct Model: Decodable { + /// Matrix 이름 + let name: String + /// Matrix 에 대한 설명 + let memo: String + /// Matrix 를 수행하는 Runner app + let runner: String + /// model.json 설정 + let model: String + /// Matrix 를 수행하는 Interval (초) + let balanceInterval: Int + /// Matrix 를 수행시작하는 시간. (설정되지 않으면 현재 시점부터) + let startDate: Date? + /// Matrix 를 종료하는 시간 + let endDate: Date? + + func build(date: Date, mode: RunMode) -> (URL, [String])? { + let command = URL.currentDirectory().appending(path: runner) + + let day = date.yyyyMMdd + let time = date.HHmmss + let args: [String] = [mode.rawValue, model, day, time] + + return (command, args) + } + + private enum CodingKeys: String, CodingKey, CaseIterable { + case name + case memo + case runner + case model + case balanceInterval + case startDate + case endDate + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.name = try container.decode(String.self, forKey: .name) + self.memo = try container.decode(String.self, forKey: .memo) + self.runner = try container.decode(String.self, forKey: .runner) + self.model = try container.decode(String.self, forKey: .model) + self.balanceInterval = try container.decode(Int.self, forKey: .balanceInterval) + + let startDate = try? container.decodeIfPresent(String.self, forKey: .startDate) + self.startDate = startDate?.modelDate + + let endDate = try? container.decodeIfPresent(String.self, forKey: .endDate) + self.endDate = endDate?.modelDate } } diff --git a/KissMeGolder/Sources/main.swift b/KissMeGolder/Sources/main.swift index 480b58e..2ec4e0d 100644 --- a/KissMeGolder/Sources/main.swift +++ b/KissMeGolder/Sources/main.swift @@ -7,4 +7,4 @@ import Foundation -KissMatrix().run() +KissGolder().run() diff --git a/KissMeMatrix/Sources/KissMatrix.swift b/KissMeMatrix/Sources/KissMatrix.swift index 951f1e8..64579ef 100644 --- a/KissMeMatrix/Sources/KissMatrix.swift +++ b/KissMeMatrix/Sources/KissMatrix.swift @@ -9,49 +9,13 @@ 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]") + printError("\(appName) [sim|run] model.json [yyyyMMdd] [HHmmss]") } guard CommandLine.argc >= 3 else { @@ -71,12 +35,12 @@ class KissMatrix { return } guard let (year, month, day) = CommandLine.arguments[3].yyyyMMdd else { - print("Invalid [yyyyMMdd] argument") + printError("Invalid [yyyyMMdd] argument") printUsage() return } guard let (hour, min, sec) = CommandLine.arguments[4].HHmmss else { - print("Invalid [HHmmss] argument") + printError("Invalid [HHmmss] argument") printUsage() return } @@ -92,23 +56,23 @@ class KissMatrix { let modelJson = CommandLine.arguments[2] guard let model = loadModel(modelJson) else { return } - print("Loaded \(model.indexSets.count) index set from \(modelJson)") + printError("Loaded \(model.indexSets.count) index set from \(modelJson)") let semaphore = DispatchSemaphore(value: 0) Task { let results = 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)") + printError("Cannot get command from \(indexSet.name)") continue } taskGroup.addTask { do { - let result = try await self.runIndex(runUrl, args: args) + let result = try await self.runIndex(runUrl, args: args, date: runDate) return result } catch { - print(error) + printError(error) return nil } } @@ -122,18 +86,19 @@ class KissMatrix { } mergeResult(results) + semaphore.signal() } semaphore.wait() } - private func runIndex(_ runUrl: URL, args: [String]) async throws -> KissIndexResult { + private func runIndex(_ runUrl: URL, args: [String], date: Date) async throws -> KissIndexResult { assert(args.count >= 3) return try await withUnsafeThrowingContinuation { continuation in let kmi = args[0] - let outputUrl = KissMatrix.indexLogFile(kmi) + let outputUrl = KissMatrix.indexLogFile(kmi, date: date) FileManager.default.createFile(atPath: outputUrl.path, contents: nil) let output = FileHandle(forWritingAtPath: outputUrl.path) @@ -143,17 +108,17 @@ class KissMatrix { task.arguments = args task.standardOutput = output task.standardError = FileHandle.standardError - //task.qualityOfService = .userInitiated + task.qualityOfService = .default - print("curPath: \(task.currentDirectoryPath)") - print("runPath: \(runUrl)") - print("args: \(args)") + printError("curPath: \(task.currentDirectoryPath)") + printError("runPath: \(runUrl.path)") + printError("args: \(args)") do { try task.run() task.waitUntilExit() } catch { - print("run error \(error)") + printError("run error \(error)") continuation.resume(throwing: error) } @@ -172,7 +137,7 @@ class KissMatrix { let indexResult = try JSONDecoder().decode(KissIndexResult.self, from: data) continuation.resume(returning: indexResult) } catch { - print("jsonError \(kmi)") + printError("jsonError \(kmi)") continuation.resume(throwing: error) } } @@ -220,15 +185,14 @@ class KissMatrix { let model = try JSONDecoder().decode(Model.self, from: data) return model } catch { - print(error) + printError(error) return nil } } - static func indexLogFile(_ kmi: String) -> URL { + static func indexLogFile(_ kmi: String, date: Date) -> URL { let subPath = "log/index" - let date = Date() let subFile = "\(subPath)/\(date.yyyyMMdd_HHmmssSSSS_forFile)-\(kmi).log" let fileUrl = URL.currentDirectory().appending(path: subFile) @@ -242,3 +206,44 @@ class KissMatrix { try? FileManager.default.createDirectory(at: subPath, withIntermediateDirectories: true) } } + + +enum RunMode: String { + case simulator = "sim" + case runner = "run" +} + + +struct Model: Decodable { + let indexSets: [IndexSet] + + struct IndexSet: Codable { + /// Index Set 이름 + let name: String + /// Index Set 에 대한 설명 + let memo: String + /// config.json 설정 + let config: String? + /// Index 수집을 수행하는 Runner app + 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) + } + } +} diff --git a/projects/macos/KissMe.xcodeproj/project.pbxproj b/projects/macos/KissMe.xcodeproj/project.pbxproj index 208947d..ed93229 100644 --- a/projects/macos/KissMe.xcodeproj/project.pbxproj +++ b/projects/macos/KissMe.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 340A4DBD2A4C34BE005A1FBA /* IndexContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340A4DBC2A4C34BE005A1FBA /* IndexContext.swift */; }; 340A4DC42A4E4345005A1FBA /* ArrayDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340A4DC32A4E4345005A1FBA /* ArrayDecodable.swift */; }; 340A4DC82A4E43C5005A1FBA /* GeneralError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340A4DC72A4E43C5005A1FBA /* GeneralError.swift */; }; + 340A4DCE2A4EA5D8005A1FBA /* Runner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340A4DCD2A4EA5D8005A1FBA /* Runner.swift */; }; 341F5EB02A0A80EC00962D48 /* KissMe.docc in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EAF2A0A80EC00962D48 /* KissMe.docc */; }; 341F5EB62A0A80EC00962D48 /* KissMe.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 341F5EAB2A0A80EC00962D48 /* KissMe.framework */; }; 341F5EBB2A0A80EC00962D48 /* KissMeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EBA2A0A80EC00962D48 /* KissMeTests.swift */; }; @@ -40,7 +41,7 @@ 349C26AB2A1EAE2400F3EC91 /* KissProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349C26AA2A1EAE2400F3EC91 /* KissProfile.swift */; }; 34D3680F2A2AA0BE005E6756 /* PropertyIterable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D3680E2A2AA0BE005E6756 /* PropertyIterable.swift */; }; 34E7B9112A49BD2800B3AB9F /* DomesticIndex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34E7B9102A49BD2800B3AB9F /* DomesticIndex.swift */; }; - 34F1900C2A41982A0068C697 /* IndexResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F1900B2A41982A0068C697 /* IndexResult.swift */; }; + 34F1900C2A41982A0068C697 /* KissIndexResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F1900B2A41982A0068C697 /* KissIndexResult.swift */; }; 34F1900F2A426D150068C697 /* ShopContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F1900E2A426D150068C697 /* ShopContext.swift */; }; 34F190112A4394EB0068C697 /* LocalContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F190102A4394EB0068C697 /* LocalContext.swift */; }; /* End PBXBuildFile section */ @@ -59,6 +60,7 @@ 340A4DBC2A4C34BE005A1FBA /* IndexContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndexContext.swift; sourceTree = ""; }; 340A4DC32A4E4345005A1FBA /* ArrayDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayDecodable.swift; sourceTree = ""; }; 340A4DC72A4E43C5005A1FBA /* GeneralError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralError.swift; sourceTree = ""; }; + 340A4DCD2A4EA5D8005A1FBA /* Runner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Runner.swift; sourceTree = ""; }; 341F5EAB2A0A80EC00962D48 /* KissMe.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = KissMe.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 341F5EAE2A0A80EC00962D48 /* KissMe.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KissMe.h; sourceTree = ""; }; 341F5EAF2A0A80EC00962D48 /* KissMe.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; name = KissMe.docc; path = ../KissMe.docc; sourceTree = ""; }; @@ -90,7 +92,7 @@ 349C26AA2A1EAE2400F3EC91 /* KissProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KissProfile.swift; sourceTree = ""; }; 34D3680E2A2AA0BE005E6756 /* PropertyIterable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PropertyIterable.swift; sourceTree = ""; }; 34E7B9102A49BD2800B3AB9F /* DomesticIndex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomesticIndex.swift; sourceTree = ""; }; - 34F1900B2A41982A0068C697 /* IndexResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndexResult.swift; sourceTree = ""; }; + 34F1900B2A41982A0068C697 /* KissIndexResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KissIndexResult.swift; sourceTree = ""; }; 34F1900E2A426D150068C697 /* ShopContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShopContext.swift; sourceTree = ""; }; 34F190102A4394EB0068C697 /* LocalContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalContext.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -240,7 +242,8 @@ 34F1900A2A41981A0068C697 /* Index */ = { isa = PBXGroup; children = ( - 34F1900B2A41982A0068C697 /* IndexResult.swift */, + 340A4DCD2A4EA5D8005A1FBA /* Runner.swift */, + 34F1900B2A41982A0068C697 /* KissIndexResult.swift */, ); path = Index; sourceTree = ""; @@ -367,6 +370,7 @@ 341F5EFB2A10909D00962D48 /* LoginResult.swift in Sources */, 340A4DC42A4E4345005A1FBA /* ArrayDecodable.swift in Sources */, 340A4DC82A4E43C5005A1FBA /* GeneralError.swift in Sources */, + 340A4DCE2A4EA5D8005A1FBA /* Runner.swift in Sources */, 341F5F0B2A15115400962D48 /* KissShop.swift in Sources */, 3435A7F72A35D82000D604F1 /* DomesticShortSelling.swift in Sources */, 341F5F072A14634F00962D48 /* Foundation+Extensions.swift in Sources */, @@ -378,7 +382,7 @@ 34F1900F2A426D150068C697 /* ShopContext.swift in Sources */, 341F5F0F2A15223A00962D48 /* SeibroRequest.swift in Sources */, 341F5EF02A0F886600962D48 /* ForeignFutures.swift in Sources */, - 34F1900C2A41982A0068C697 /* IndexResult.swift in Sources */, + 34F1900C2A41982A0068C697 /* KissIndexResult.swift in Sources */, 341F5EEC2A0F883900962D48 /* ForeignStock.swift in Sources */, 34F190112A4394EB0068C697 /* LocalContext.swift in Sources */, 341F5EFF2A10955D00962D48 /* OrderRequest.swift in Sources */, diff --git a/projects/macos/KissMeGolder.xcodeproj/xcshareddata/xcschemes/KissMeGolder.xcscheme b/projects/macos/KissMeGolder.xcodeproj/xcshareddata/xcschemes/KissMeGolder.xcscheme index b68b664..e43bbca 100644 --- a/projects/macos/KissMeGolder.xcodeproj/xcshareddata/xcschemes/KissMeGolder.xcscheme +++ b/projects/macos/KissMeGolder.xcodeproj/xcshareddata/xcschemes/KissMeGolder.xcscheme @@ -51,6 +51,12 @@ ReferencedContainer = "container:KissMeGolder.xcodeproj"> + + + + diff --git a/scripts/build.sh b/scripts/build.sh index 5d3ea23..6c68374 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -10,6 +10,8 @@ THIS_PATH=`dirname "$0"` ${THIS_PATH}/build_any.sh KissMeConsole ${THIS_PATH}/build_any.sh KissMeIndex ${THIS_PATH}/build_any.sh KissMeMatrix +${THIS_PATH}/build_any.sh KissMeGolder + #${THIS_PATH}/build_any.sh KissMeBatch #${THIS_PATH}/build_any.sh KissGram