From 4245cc9bf5ae00819c1c403cedae4339a338532f Mon Sep 17 00:00:00 2001 From: Wendy Liga Date: Thu, 2 Apr 2020 11:58:31 +0700 Subject: [PATCH] fix temp folder not created on setup env --- Makefile | 2 + Package.resolved | 4 +- Sources/mimiq/main.swift | 160 +++++++++++++++++++++++++++++++-------- 3 files changed, 133 insertions(+), 33 deletions(-) diff --git a/Makefile b/Makefile index 44694d7..09b90ce 100644 --- a/Makefile +++ b/Makefile @@ -13,5 +13,7 @@ uninstall: clean: rm -rf .build + # clear all cache and logging + rm -rf ~/.mimiq .PHONY: build install uninstall clean diff --git a/Package.resolved b/Package.resolved index 3648571..7d018b3 100644 --- a/Package.resolved +++ b/Package.resolved @@ -15,8 +15,8 @@ "repositoryURL": "https://github.com/wendyliga/Explorer.git", "state": { "branch": null, - "revision": "eee4f6224853f236490a8349b70553fd59876551", - "version": "0.0.3" + "revision": "c31815c61076122cab594249e1de9d5afd047d17", + "version": "0.0.4" } }, { diff --git a/Sources/mimiq/main.swift b/Sources/mimiq/main.swift index c4d4033..d910843 100644 --- a/Sources/mimiq/main.swift +++ b/Sources/mimiq/main.swift @@ -30,13 +30,55 @@ import Foundation // MARK: - Configuration private let appName = "mimiq" -private let version = "0.3.1" +private let version = "0.3.3" + +// Environment setup params private let defaultResultPath = "~/Desktop/" private let documentPath = "~/" private let mimiqFolder = documentPath + ".mimiq/" private let logFolder = mimiqFolder + "log/" private let tempFolder = mimiqFolder + "temp/" +// MARK: - Logging + +class Log { + static let `default` = Log() + + private let dateFormatter = DateFormatter() + private let logFileName: String + private let logFileExtension = "log" + private var logs: [String] = [] + + init() { + // Log file name + dateFormatter.dateFormat = "yyyyMMddHHmmss" + logFileName = dateFormatter.string(from: Date()) + } + + @discardableResult + func write(message: String, printOut: Bool = false) -> Result { + if printOut { + print(message) + } + + dateFormatter.dateFormat = "HH:mm:ss" + let newLog = "[\(dateFormatter.string(from: Date()))] \(message)" + logs.append(newLog) + + let file = File(name: logFileName, content: logs.joined(separator: "\n"), extension: logFileExtension) + let operation = SingleFileOperation(file: file, path: logFolder) + + let writeOperationResult = Explorer.default.write(operation: operation, writingStrategy: .overwrite) + guard writeOperationResult.successValue != nil else { + return .failure(writeOperationResult.failureValue!) + } + + return .success(true) + } +} + +// MARK: - Simulator List Struct + struct Runtime: Decodable { let identifier: String } @@ -46,6 +88,8 @@ struct Simulator: Decodable { let name: String } +// MARK: - Json Encoder Extension + extension JSONDecoder { func decode(_ type: T.Type, from data: Data, keyPath: String) throws -> T { let toplevel = try JSONSerialization.jsonObject(with: data) @@ -59,6 +103,8 @@ extension JSONDecoder { } } +// MARK: - String Extension + extension String { /** Remove file extension from filename @@ -85,14 +131,32 @@ extension String { } } -func explorableMimiqFilename(_ explorable: Explorable) -> String? { - guard let file = explorable as? File else { - return nil - } +// MARK: - Setup Environment + +func configureEnvironment() -> Result { + let tempFolder = Folder(name: "temp", contents: []) + let logFolder = Folder(name: "log", contents: []) + let mimiqFolder = Folder(name: ".mimiq", contents: [tempFolder, logFolder]) - return file.name.hasPrefix("mimiq") ? file.name : nil + let operation = SingleFolderOperation(folder: mimiqFolder, path: documentPath) + return Explorer.default.write(operation: operation, writingStrategy: .skippable) +} + +// MARK: - Remove Cache + +func removeCache() { + // delete created file + // TODO: convert it to Explorer + do { + try FileManager.default.removeItem(atPath: tempFolder) + Log.default.write(message: "success remove cache at \(tempFolder)") + } catch { + Log.default.write(message: "error remove because \(error.localizedDescription)") + } } +// MARK: - Shell Command + @discardableResult func shell(launchPath: String = "/usr/bin/env", arguments: [String]) -> (status: Int32, output: String?) { let task = Process() @@ -101,6 +165,7 @@ func shell(launchPath: String = "/usr/bin/env", arguments: [String]) -> (status: let pipe = Pipe() task.standardOutput = pipe + task.standardError = pipe task.launch() task.waitUntilExit() @@ -118,6 +183,7 @@ func mustInteruptShell(launchPath: String = "/usr/bin/env", arguments: [String], let pipe = Pipe() task.standardOutput = pipe + task.standardError = pipe DispatchQueue.global(qos: .background).async { task.launch() @@ -135,21 +201,6 @@ func mustInteruptShell(launchPath: String = "/usr/bin/env", arguments: [String], return (status: task.terminationStatus, output: output) } -func configureEnvironment() -> Result { - let movFolder = Folder(name: "mov", contents: []) - let logFolder = Folder(name: "log", contents: []) - let mimiqFolder = Folder(name: ".mimiq", contents: [movFolder, logFolder]) - - let operation = SingleFolderOperation(folder: mimiqFolder, path: documentPath) - return Explorer.default.write(operation: operation, writingStrategy: .skippable) -} - -func removeCache() { - // delete created file - // TODO: convert it to Explorer - try? FileManager.default.removeItem(atPath: tempFolder) -} - var isHomebrewInstalled: Bool { shell(arguments: [#"! homebrew_loc="$(type -p "brew")" || [[ -z $homebrew_loc ]];"#]).status == 1 } @@ -302,7 +353,13 @@ struct Mimiq: ParsableCommand { // get last increment number let fileWithMimiqPrefix = listFiles - .compactMap(explorableMimiqFilename) + .compactMap { explorable -> String? in + guard let file = explorable as? File else { + return nil + } + + return file.name.hasPrefix("mimiq") ? file.name : nil + } let lastMimiqIncrementNumber = fileWithMimiqPrefix .compactMap { Int($0.withoutPrefix("mimiq")) } @@ -339,66 +396,107 @@ struct Mimiq: ParsableCommand { } func run() throws { + log("mimiq start to run") + #if os(Linux) print("\(appName) is not support linux yet") + log("mimiq is running on linux", printOut: isVerbose) return #endif + log("mimiq is running on mac") + guard configureEnvironment().successValue != nil else { + log("failed setup environment") print("💥 Failed to Setup Enviroment"); return } + log("environment setup success") + guard isHomebrewInstalled else { + log("missing homebrew") print("💥 Missing Homebrew, please install Homebrew, for more visit https://brew.sh"); return } + log("Homebrew is installed") + if !isFFMpegInstalled { - print("⚙️ Missing ffmpeg, installing...(This may take a while)") + log("missing ffmpeg") + print("⚙️ Missing ffmpeg, installing...(This may take a while)") + + log("installing ffmpeg") + let command = "brew install ffmpeg" + let installFFMpegResult = shell(arguments: [command]) - let command = "brew install ffmpeg" + (isVerbose ? "" : " >/dev/null") - shell(arguments: [command]) + guard installFFMpegResult.status == 0 else { + log("error install mmpeg: \(installFFMpegResult.output as Optional)") + print("💥 failed install ffmpeg"); return + } + + log("success install ffmpeg: \(installFFMpegResult.output as Optional)") } guard let mimiqTarget = mimiqTarget else { + log("no available simulator") print("💥 No Available Simulator to mimiq"); return } + log("simulator target \(mimiqTarget)") + // Start Recording let movRawFileName = UUID().uuidString let movFileName = movRawFileName + ".mov" let movSource = tempFolder + movFileName + + log("simulator to record on \(movSource)") - let recordCommand = "xcrun simctl io \(mimiqTarget.udid.uuidString) recordVideo -f \(movSource)" + (isVerbose ? "" : " &> /dev/null") + let recordCommand = "xcrun simctl io \(mimiqTarget.udid.uuidString) recordVideo -f \(movSource)" let recordMessage = "🔨 Recording Simulator \(mimiqTarget.name) with UDID \(mimiqTarget.udid)... Press Enter to Stop.)" + log(#"start recording with command "\#(recordCommand)""#) let recordResult = mustInteruptShell(arguments: [recordCommand], message: recordMessage) + log("record simulator finish with status \(recordResult.status)") guard recordResult.status == 0 else { removeCache() + log("error record simulator: \(recordResult.output as Optional)") print("💥 Record Failed, Please Try Again"); return } - - print("⚙️ Creating GIF..") + + log("stop recording") + log("start creating GIF") + print("⚙️ Creating GIF..") let gifTargetPath = resultPath + mimiqFileName + ".gif" + log("GIF will be created on \(gifTargetPath)") let setPallete = #"palette="/tmp/palette.png""# let configureFilter = #"filters="fps=15,scale=320:-1:flags=lanczos""# let slicingVideo = #"ffmpeg -nostdin -v warning -i \#(movSource) -vf "$filters,palettegen=stats_mode=diff" -y $palette"# + (isVerbose ? "" : " &> /dev/null") - let createGIF = #"ffmpeg -nostdin -i \#(movSource) -i $palette -loglevel panic -lavfi "$filters,paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle" -y \#(gifTargetPath)"# + (isVerbose ? "" : " &> /dev/null") + let createGIF = #"ffmpeg -nostdin -i \#(movSource) -i $palette -loglevel panic -lavfi "$filters,paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle" -y \#(gifTargetPath)"# let generateGIFCommand = [setPallete, configureFilter , slicingVideo, createGIF].joined(separator: ";") + log(#"executing ffmpeg with command "\#(generateGIFCommand)""#) - guard shell(arguments: [generateGIFCommand]).status == 0 else { + let generateGIFResult = shell(arguments: [generateGIFCommand]) + + guard generateGIFResult.status == 0 else { // clear generated cache removeCache() + log("error generating GIF: \(generateGIFResult.output as Optional)") print("💥 Failed on Creating GIF, Please Try Again"); return } + log(#"success generating GIF: \#(generateGIFResult.output as Optional)"#) + // clear generated cache removeCache() + log("GIF generated at \(gifTargetPath)") print("✅ Grab your GIF at \(gifTargetPath)") - + } + + private func log(_ message: String) { + Log.default.write(message: message, printOut: isVerbose) } }