diff --git a/Docs/Images/screenshots_logs.png b/Docs/Images/screenshots_logs.png new file mode 100644 index 0000000..7c9e055 Binary files /dev/null and b/Docs/Images/screenshots_logs.png differ diff --git a/README.md b/README.md index 20d6605..fa80784 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,10 @@ This will export the action.xccovreport & action.xccovarchive into your output d xcparse logs /path/to/Test.xcresult /path/to/exportLogFiles ``` +This will export logs & diagnostic files into a per-action folder structure similar to Xcode 10's xcresult format. + +![Logs exported into folders](Docs/Images/screenshots_logs.png?raw=true) + ### Help ``` diff --git a/Sources/XCParseCore/Console.swift b/Sources/XCParseCore/Console.swift index 7a50a65..1e1d7e5 100644 --- a/Sources/XCParseCore/Console.swift +++ b/Sources/XCParseCore/Console.swift @@ -37,17 +37,6 @@ open class Console { } } - public func printInteractiveUsage() { - writeMessage("usage (interactive mode): xcparse\n") - writeMessage("Interactive Mode only accepts a single option at a time.\n") - writeMessage(" -s, --screenshots : Extracts screenshots from xcresult file at xcresultPath and saves it in destination folder.") - writeMessage(" -x, --xcov : Extracts coverage from xcresult file at xcresultPath and saves it in destination folder.") - writeMessage(" -l, --logs : Extracts logs from xcresult file at xcresultPath and saves them to destination folder.") - writeMessage(" -v, --verbose : Run in verbose mode.") - writeMessage(" -h, --help : Prints usage message.") - writeMessage(" -q, --quit : Exits interactive mode. Cannot be used in static mode.") - } - // MARK: - // MARK: Shell @discardableResult public func shellCommand(_ command: [String]) -> String { diff --git a/Sources/xcparse/LogsCommand.swift b/Sources/xcparse/LogsCommand.swift index 1f02ef5..a2749fe 100644 --- a/Sources/xcparse/LogsCommand.swift +++ b/Sources/xcparse/LogsCommand.swift @@ -12,7 +12,7 @@ import SPMUtility struct LogsCommand: Command { let command = "logs" - let overview = "Extracts logs from xcresult and saves it in output folder." + let overview = "Extracts logs & diagnostics from xcresult and saves it in output folder." let usage = "[OPTIONS] xcresult [outputDirectory]" var path: PositionalArgument diff --git a/Sources/xcparse/XCPParser.swift b/Sources/xcparse/XCPParser.swift index 2a179fb..a1cb1a3 100644 --- a/Sources/xcparse/XCPParser.swift +++ b/Sources/xcparse/XCPParser.swift @@ -11,7 +11,7 @@ import Foundation import SPMUtility import XCParseCore -let xcparseCurrentVersion = Version(1, 0, 1) +let xcparseCurrentVersion = Version(2, 0, 0) extension Foundation.URL { func fileExistsAsDirectory() -> Bool { @@ -303,6 +303,12 @@ class XCPParser { guard let invocationRecord = xcresult.invocationRecord else { return } + + // Let's make sure the destinations is available + let destinationURL = URL.init(fileURLWithPath: destination) + if destinationURL.createDirectoryIfNecessary() != true { + return + } var coverageReferenceIDs: [String] = [] var coverageArchiveIDs: [String] = [] @@ -331,7 +337,33 @@ class XCPParser { return } + let xcresulttoolCompatability = self.checkXCResultToolCompatability(destination: destination) + if xcresulttoolCompatability.supportsExport != true { + return + } + + // Let's make sure the destinations is available + let destinationURL = URL.init(fileURLWithPath: destination) + if destinationURL.createDirectoryIfNecessary() != true { + return + } + for (index, actionRecord) in invocationRecord.actions.enumerated() { + let actionRecordDestinationURL = destinationURL.appendingPathComponent("\(index + 1)_\(actionRecord.schemeCommandName)") + if actionRecordDestinationURL.createDirectoryIfNecessary(createIntermediates: false, console: self.console) != true { + return + } + + if let buildDiagnosticsRef = actionRecord.buildResult.diagnosticsRef { + let buildDiagnosticsURL = actionRecordDestinationURL.appendingPathComponent("Diagnostics") + XCResultToolCommand.Export(withXCResult: xcresult, id: buildDiagnosticsRef.id, outputPath: buildDiagnosticsURL.path, type: .directory).run() + } + + if let actionDiagnosticsRef = actionRecord.actionResult.diagnosticsRef { + let actionDiagnosticsURL = actionRecordDestinationURL.appendingPathComponent("Diagnostics") + XCResultToolCommand.Export(withXCResult: xcresult, id: actionDiagnosticsRef.id, outputPath: actionDiagnosticsURL.path, type: .directory).run() + } + // TODO: Alex - note that these aren't actually log files but ActivityLogSection objects. User from StackOverflow was just exporting those // out as text files as for the most party they can be human readable, but it won't match what Xcode exports if you open the XCResult // and attempt to export out the log. That seems like it may involve having to create our own pretty printer similar to Xcode's to export @@ -342,15 +374,15 @@ class XCPParser { if let buildResultLogRef = actionRecord.buildResult.logRef { // let activityLogSectionJSON = XCResultToolCommand.Get(withXCResult: xcresult, id: buildResultLogRef.id, outputPath: "", format: .json).run() // let activityLogSection = try decoder.decode(ActivityLogSection.self, from: Data(activityLogSectionJSON.utf8)) - - XCResultToolCommand.Export(withXCResult: xcresult, id: buildResultLogRef.id, outputPath: "\(destination)/\(index + 1)_build.txt", type: .file).run() + let buildLogURL = actionRecordDestinationURL.appendingPathComponent("build.txt") + XCResultToolCommand.Export(withXCResult: xcresult, id: buildResultLogRef.id, outputPath: buildLogURL.path, type: .file).run() } if let actionResultLogRef = actionRecord.actionResult.logRef { // let activityLogSectionJSON = XCResultToolCommand.Get(withXCResult: xcresult, id: actionResultLogRef.id, outputPath: "", format: .json).run() // let activityLogSection = try decoder.decode(ActivityLogSection.self, from: Data(activityLogSectionJSON.utf8)) - - XCResultToolCommand.Export(withXCResult: xcresult, id: actionResultLogRef.id, outputPath: "\(destination)/\(index + 1)_action.txt", type: .file).run() + let actionLogURL = actionRecordDestinationURL.appendingPathComponent("action.txt") + XCResultToolCommand.Export(withXCResult: xcresult, id: actionResultLogRef.id, outputPath: actionLogURL.path, type: .file).run() } } }