From 5e36c7399744991809ea412562f592e1cb8b2ec6 Mon Sep 17 00:00:00 2001 From: Danny Gilbert Date: Wed, 2 Feb 2022 09:42:26 -0600 Subject: [PATCH 01/11] Updates Package Dependencies CryptoSwift: 1.3.3 -> 1.4.2 ArgumentParser: 0.3.1 -> 1.0.3 Signed-off-by: Danny Gilbert --- Package.resolved | 8 ++++---- Package.swift | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Package.resolved b/Package.resolved index aaf765e..ed8e38a 100644 --- a/Package.resolved +++ b/Package.resolved @@ -6,8 +6,8 @@ "repositoryURL": "https://github.com/krzyzanowskim/CryptoSwift.git", "state": { "branch": null, - "revision": "e2bc81be54d71d566a52ca17c3983d141c30aa70", - "version": "1.3.3" + "revision": "4b0565384d3c4c588af09e660535b2c7c9bf5b39", + "version": "1.4.2" } }, { @@ -42,8 +42,8 @@ "repositoryURL": "https://github.com/apple/swift-argument-parser", "state": { "branch": null, - "revision": "92646c0cdbaca076c8d3d0207891785b3379cbff", - "version": "0.3.1" + "revision": "e394bf350e38cb100b6bc4172834770ede1b7232", + "version": "1.0.3" } } ] diff --git a/Package.swift b/Package.swift index f5fe066..5ce6285 100644 --- a/Package.swift +++ b/Package.swift @@ -12,9 +12,9 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/1024jp/GzipSwift", from: "5.1.0"), - .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .exact("1.3.3")), + .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", from: "1.3.3"), .package(url: "https://github.com/kylef/PathKit.git", from: "1.0.1"), - .package(url: "https://github.com/apple/swift-argument-parser", .upToNextMinor(from: "0.3.0")), + .package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0"), ], targets: [ .target( From 90d7fabaf6f8bb2ac2e3c1420ce5684cf45a79a7 Mon Sep 17 00:00:00 2001 From: Danny Gilbert Date: Wed, 2 Feb 2022 09:44:53 -0600 Subject: [PATCH 02/11] Fixes Typo Signed-off-by: Danny Gilbert --- Sources/XCLogParser/loglocation/LogFinder.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/XCLogParser/loglocation/LogFinder.swift b/Sources/XCLogParser/loglocation/LogFinder.swift index e317c1c..b4b31d3 100644 --- a/Sources/XCLogParser/loglocation/LogFinder.swift +++ b/Sources/XCLogParser/loglocation/LogFinder.swift @@ -32,7 +32,7 @@ public struct LogFinder { let logManifestFile = "LogStoreManifest.plist" - let emmptyDirResponseMessage = """ + let emptyDirResponseMessage = """ Error. Couldn't find the derived data directory. Please use the --filePath option to specify the path to the xcactivitylog file you want to parse. """ @@ -199,7 +199,7 @@ public struct LogFinder { if let result = try executeXcodeBuild(args: arguments) { return try parseXcodeBuildDir(result) } - throw LogError.xcodeBuildError(emmptyDirResponseMessage) + throw LogError.xcodeBuildError(emptyDirResponseMessage) } /// Gets the latest xcactivitylog file path for the given projectFolder @@ -248,7 +248,7 @@ public struct LogFinder { if let result = try executeXcodeBuild(args: arguments) { return try parseXcodeBuildDir(result) } - throw LogError.xcodeBuildError(emmptyDirResponseMessage) + throw LogError.xcodeBuildError(emptyDirResponseMessage) } /// Returns the latest xcactivitylog file path in the given directory @@ -317,6 +317,6 @@ public struct LogFinder { .replacingOccurrences(of: buildDirSettingsPrefix, with: "") .replacingOccurrences(of: "Build/Products", with: logsDir) } - throw LogError.xcodeBuildError(emmptyDirResponseMessage) + throw LogError.xcodeBuildError(emptyDirResponseMessage) } } From 09562231f37304bea62587fed136edf07f289dac Mon Sep 17 00:00:00 2001 From: Danny Gilbert Date: Wed, 2 Feb 2022 09:47:28 -0600 Subject: [PATCH 03/11] Open up public init for LogFinder Allow consumers to specify different logsDir Signed-off-by: Danny Gilbert --- .../XCLogParser/loglocation/LogFinder.swift | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Sources/XCLogParser/loglocation/LogFinder.swift b/Sources/XCLogParser/loglocation/LogFinder.swift index b4b31d3..08cd38b 100644 --- a/Sources/XCLogParser/loglocation/LogFinder.swift +++ b/Sources/XCLogParser/loglocation/LogFinder.swift @@ -24,13 +24,13 @@ import XcodeHasher /// Helper methods to locate Xcode's Log directory and its content public struct LogFinder { - let buildDirSettingsPrefix = "BUILD_DIR = " + let buildDirSettingsPrefix: String - let xcodebuildPath = "/usr/bin/xcodebuild" + let xcodebuildPath: String - let logsDir = "/Logs/Build/" + let logsDir: String - let logManifestFile = "LogStoreManifest.plist" + let logManifestFile: String let emptyDirResponseMessage = """ Error. Couldn't find the derived data directory. @@ -44,7 +44,17 @@ public struct LogFinder { return homeDirURL.appendingPathComponent("Library/Developer/Xcode/DerivedData", isDirectory: true) } - public init() {} + public init( + buildDirSettingsPrefix: String = "BUILD_DIR = ", + xcodebuildPath: String = "/usr/bin/xcodebuild", + logsDir: String = "/Logs/Build/", + logManifestFile: String = "LogStoreManifest.plist" + ) { + self.buildDirSettingsPrefix = buildDirSettingsPrefix + self.xcodebuildPath = xcodebuildPath + self.logsDir = logsDir + self.logManifestFile = logManifestFile + } public func findLatestLogWithLogOptions(_ logOptions: LogOptions) throws -> URL { guard logOptions.xcactivitylogPath.isEmpty else { From 9c94d5d80341bc8189de04fee4e8cc9b0ccd48ad Mon Sep 17 00:00:00 2001 From: Danny Gilbert Date: Wed, 2 Feb 2022 09:48:30 -0600 Subject: [PATCH 04/11] Open up public init for LogFinder Allow consumers to inject modified LogFinders Signed-off-by: Danny Gilbert --- Sources/XCLogParser/commands/CommandHandler.swift | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Sources/XCLogParser/commands/CommandHandler.swift b/Sources/XCLogParser/commands/CommandHandler.swift index dab1c2d..c97b507 100644 --- a/Sources/XCLogParser/commands/CommandHandler.swift +++ b/Sources/XCLogParser/commands/CommandHandler.swift @@ -21,10 +21,16 @@ import Foundation public struct CommandHandler { - let logFinder = LogFinder() - let activityLogParser = ActivityParser() + let logFinder: LogFinder + let activityLogParser: ActivityParser - public init() { } + public init( + logFinder: LogFinder = .init(), + activityLogParser: ActivityParser = .init() + ) { + self.logFinder = logFinder + self.activityLogParser = activityLogParser + } public func handle(command: Command) throws { switch command.action { From b3237738cd3550962ecfdf9fbb0fa2a5f5b85958 Mon Sep 17 00:00:00 2001 From: Danny Gilbert Date: Wed, 2 Feb 2022 09:58:38 -0600 Subject: [PATCH 05/11] LogType Allow consumers to specify which logs they would like to parse. By default this will still apply to build logs. Allows consumers to parse things like Package resolution logs. Signed-off-by: Danny Gilbert --- .../XCLogParser/loglocation/LogFinder.swift | 16 +++++------ Sources/XCLogParser/loglocation/LogType.swift | 27 +++++++++++++++++++ .../commands/ParseCommand.swift | 7 ++++- .../XCLogParserApp/extensions/LogType+.swift | 11 ++++++++ 4 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 Sources/XCLogParser/loglocation/LogType.swift create mode 100644 Sources/XCLogParserApp/extensions/LogType+.swift diff --git a/Sources/XCLogParser/loglocation/LogFinder.swift b/Sources/XCLogParser/loglocation/LogFinder.swift index 08cd38b..5aff35e 100644 --- a/Sources/XCLogParser/loglocation/LogFinder.swift +++ b/Sources/XCLogParser/loglocation/LogFinder.swift @@ -28,7 +28,7 @@ public struct LogFinder { let xcodebuildPath: String - let logsDir: String + let logType: LogType let logManifestFile: String @@ -47,12 +47,12 @@ public struct LogFinder { public init( buildDirSettingsPrefix: String = "BUILD_DIR = ", xcodebuildPath: String = "/usr/bin/xcodebuild", - logsDir: String = "/Logs/Build/", + logType: LogType = .build, logManifestFile: String = "LogStoreManifest.plist" ) { self.buildDirSettingsPrefix = buildDirSettingsPrefix self.xcodebuildPath = xcodebuildPath - self.logsDir = logsDir + self.logType = logType self.logManifestFile = logManifestFile } @@ -121,8 +121,8 @@ public struct LogFinder { // when xcodebuild is run with -derivedDataPath the logs are at the root level if logOptions.derivedDataPath.isEmpty == false { if FileManager.default.fileExists(atPath: - derivedData.appendingPathComponent(logsDir).path) { - return derivedData.appendingPathComponent(logsDir) + derivedData.appendingPathComponent(logType.path).path) { + return derivedData.appendingPathComponent(logType.path) } } if logOptions.projectLocation.isEmpty == false { @@ -195,7 +195,7 @@ public struct LogFinder { with --file or the right DerivedData folder with --derived_data """) } - return match.appendingPathComponent(logsDir) + return match.appendingPathComponent(logType.path) } /// Gets the full path of the Build/Logs directory for the given project @@ -294,7 +294,7 @@ public struct LogFinder { .replacingOccurrences(of: ".xcworkspace", with: "") .replacingOccurrences(of: ".xcodeproj", with: "") let hash = try XcodeHasher.hashString(for: path.string) - return "\(projectName)-\(hash)".appending(logsDir) + return "\(projectName)-\(hash)".appending(logType.path) } private func executeXcodeBuild(args: [String]) throws -> String? { @@ -325,7 +325,7 @@ public struct LogFinder { if let settings = buildDirSettings.first { return settings.trimmingCharacters(in: .whitespacesAndNewlines) .replacingOccurrences(of: buildDirSettingsPrefix, with: "") - .replacingOccurrences(of: "Build/Products", with: logsDir) + .replacingOccurrences(of: "Build/Products", with: logType.path) } throw LogError.xcodeBuildError(emptyDirResponseMessage) } diff --git a/Sources/XCLogParser/loglocation/LogType.swift b/Sources/XCLogParser/loglocation/LogType.swift new file mode 100644 index 0000000..edeefbe --- /dev/null +++ b/Sources/XCLogParser/loglocation/LogType.swift @@ -0,0 +1,27 @@ +// +// LogType.swift +// +// +// Created by Danny Gilbert on 2/2/22. +// + +import Foundation + +public enum LogType: String { + case build = "Build" + case indexBuild = "Index Build" + case install = "Install" + case issues = "Issues" + case package = "Package" + case run = "Run" + case test = "Test" + case updateSigning = "Update Signing" +} + +// MARK: - Log Location +public extension LogType { + + var path: String { + "/Logs/\(self)/" + } +} diff --git a/Sources/XCLogParserApp/commands/ParseCommand.swift b/Sources/XCLogParserApp/commands/ParseCommand.swift index 3b9124f..25a70d4 100644 --- a/Sources/XCLogParserApp/commands/ParseCommand.swift +++ b/Sources/XCLogParserApp/commands/ParseCommand.swift @@ -26,6 +26,9 @@ struct ParseCommand: ParsableCommand { commandName: "parse", abstract: "Parses the content of an xcactivitylog file" ) + + @Option(name: .long, help: "Type of .xactivitylog file to look for.") + var logs: LogType = .build @Option(name: .long, help: "The path to a .xcactivitylog file.") var file: String? @@ -157,7 +160,9 @@ struct ParseCommand: ParsableCommand { guard let xclReporter = Reporter(rawValue: reporter) else { return } - let commandHandler = CommandHandler() + let commandHandler = CommandHandler( + logFinder: .init(logType: logs) + ) let logOptions = LogOptions(projectName: project ?? "", xcworkspacePath: workspace ?? "", xcodeprojPath: xcodeproj ?? "", diff --git a/Sources/XCLogParserApp/extensions/LogType+.swift b/Sources/XCLogParserApp/extensions/LogType+.swift new file mode 100644 index 0000000..423d994 --- /dev/null +++ b/Sources/XCLogParserApp/extensions/LogType+.swift @@ -0,0 +1,11 @@ +// +// LogType+.swift +// +// +// Created by Danny Gilbert on 2/2/22. +// + +import XCLogParser +import ArgumentParser + +extension LogType: ExpressibleByArgument { } From b1c638d20ce62afad6ad1701a6af435de82c1b4c Mon Sep 17 00:00:00 2001 From: Danny Gilbert Date: Wed, 2 Feb 2022 11:57:08 -0600 Subject: [PATCH 06/11] Revert "Updates Package Dependencies" This reverts commit 5e36c7399744991809ea412562f592e1cb8b2ec6. --- Package.resolved | 8 ++++---- Package.swift | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Package.resolved b/Package.resolved index ed8e38a..aaf765e 100644 --- a/Package.resolved +++ b/Package.resolved @@ -6,8 +6,8 @@ "repositoryURL": "https://github.com/krzyzanowskim/CryptoSwift.git", "state": { "branch": null, - "revision": "4b0565384d3c4c588af09e660535b2c7c9bf5b39", - "version": "1.4.2" + "revision": "e2bc81be54d71d566a52ca17c3983d141c30aa70", + "version": "1.3.3" } }, { @@ -42,8 +42,8 @@ "repositoryURL": "https://github.com/apple/swift-argument-parser", "state": { "branch": null, - "revision": "e394bf350e38cb100b6bc4172834770ede1b7232", - "version": "1.0.3" + "revision": "92646c0cdbaca076c8d3d0207891785b3379cbff", + "version": "0.3.1" } } ] diff --git a/Package.swift b/Package.swift index 5ce6285..f5fe066 100644 --- a/Package.swift +++ b/Package.swift @@ -12,9 +12,9 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/1024jp/GzipSwift", from: "5.1.0"), - .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", from: "1.3.3"), + .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .exact("1.3.3")), .package(url: "https://github.com/kylef/PathKit.git", from: "1.0.1"), - .package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0"), + .package(url: "https://github.com/apple/swift-argument-parser", .upToNextMinor(from: "0.3.0")), ], targets: [ .target( From 8ede14e25b2ee66da8ef8ba63cf770fe97ee4fe0 Mon Sep 17 00:00:00 2001 From: Danny Gilbert Date: Wed, 2 Feb 2022 13:00:47 -0600 Subject: [PATCH 07/11] obfuscate logManifestFile / buildDirSettingsPrefix Signed-off-by: Danny Gilbert --- Sources/XCLogParser/loglocation/LogFinder.swift | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Sources/XCLogParser/loglocation/LogFinder.swift b/Sources/XCLogParser/loglocation/LogFinder.swift index 5aff35e..f30da7a 100644 --- a/Sources/XCLogParser/loglocation/LogFinder.swift +++ b/Sources/XCLogParser/loglocation/LogFinder.swift @@ -24,13 +24,13 @@ import XcodeHasher /// Helper methods to locate Xcode's Log directory and its content public struct LogFinder { - let buildDirSettingsPrefix: String + let buildDirSettingsPrefix = "BUILD_DIR = " let xcodebuildPath: String let logType: LogType - let logManifestFile: String + let logManifestFile = "LogStoreManifest.plist" let emptyDirResponseMessage = """ Error. Couldn't find the derived data directory. @@ -45,15 +45,11 @@ public struct LogFinder { } public init( - buildDirSettingsPrefix: String = "BUILD_DIR = ", xcodebuildPath: String = "/usr/bin/xcodebuild", - logType: LogType = .build, - logManifestFile: String = "LogStoreManifest.plist" + logType: LogType = .build ) { - self.buildDirSettingsPrefix = buildDirSettingsPrefix self.xcodebuildPath = xcodebuildPath self.logType = logType - self.logManifestFile = logManifestFile } public func findLatestLogWithLogOptions(_ logOptions: LogOptions) throws -> URL { From 3774b90d83921a5310fdbd58b47d7cf68ee1e5b3 Mon Sep 17 00:00:00 2001 From: Danny Gilbert Date: Mon, 7 Feb 2022 13:43:32 -0600 Subject: [PATCH 08/11] getLatestLogsInDir Return list of file URLs for log dir. Signed-off-by: Danny Gilbert --- .../XCLogParser/loglocation/LogFinder.swift | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/Sources/XCLogParser/loglocation/LogFinder.swift b/Sources/XCLogParser/loglocation/LogFinder.swift index f30da7a..ba1c422 100644 --- a/Sources/XCLogParser/loglocation/LogFinder.swift +++ b/Sources/XCLogParser/loglocation/LogFinder.swift @@ -60,10 +60,17 @@ public struct LogFinder { let projectDir = try getProjectDirWithLogOptions(logOptions) // get latestLog - return try URL(fileURLWithPath: getLatestLogInDir(projectDir)) } + + public func findLatestLogsWithLogOptions(_ logOptions: LogOptions) throws -> [URL] { + // get project dir + let projectDir = try getProjectDirWithLogOptions(logOptions) + + // get latestLog + return try getLatestLogsInDir(projectDir) + } public func findLogManifestWithLogOptions(_ logOptions: LogOptions) throws -> URL { let logManifestURL = try findLogManifestURLWithLogOptions(logOptions) @@ -279,6 +286,31 @@ public struct LogFinder { } return logPath.path } + + /// Returns the latest xcactivitylog file path in the given directory + /// - parameter dir: The full path for the directory + /// - returns: The paths of the latest xcactivitylog file in it since given date. + /// - throws: An `Error` if the directory doesn't exist or if there are no xcactivitylog files in it. + public func getLatestLogsInDir(_ dir: URL) throws -> [URL] { + let fileManager = FileManager.default + let files = try fileManager.contentsOfDirectory(at: dir, + includingPropertiesForKeys: [.contentModificationDateKey], + options: .skipsHiddenFiles) + let sorted = try files + .filter { $0.path.hasSuffix(".xcactivitylog") } + .sorted { + let lhv = try $0.resourceValues(forKeys: [.contentModificationDateKey]) + let rhv = try $1.resourceValues(forKeys: [.contentModificationDateKey]) + guard let lhDate = lhv.contentModificationDate, let rhDate = rhv.contentModificationDate else { + return false + } + return lhDate.compare(rhDate) == .orderedDescending + } + guard !sorted.isEmpty else { + throw LogError.noLogFound(dir: dir.path) + } + return sorted + } /// Generates the Derived Data Build Logs Folder name for the given project path /// - parameter projectFilePath: A path (relative or absolut) to an .xcworkspace or an .xcodeproj directory From 9aa08bf468e1fa2830f591cb1b0c254dbb51b6d1 Mon Sep 17 00:00:00 2001 From: Danny Gilbert Date: Mon, 7 Feb 2022 13:45:08 -0600 Subject: [PATCH 09/11] LogOptions - ModifiedAfter Offer filtering for logs newer than specifed date Signed-off-by: Danny Gilbert --- Sources/XCLogParser/commands/LogOptions.swift | 11 +++++++++-- Sources/XCLogParser/loglocation/LogFinder.swift | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Sources/XCLogParser/commands/LogOptions.swift b/Sources/XCLogParser/commands/LogOptions.swift index da21f0e..6b9eb5a 100644 --- a/Sources/XCLogParser/commands/LogOptions.swift +++ b/Sources/XCLogParser/commands/LogOptions.swift @@ -41,6 +41,9 @@ public struct LogOptions { /// Use strict Xcode project naming. let strictProjectName: Bool + + /// Timestamp to check + let newerThan: Date? /// Computed property, return the xcworkspacePath if not empty or /// the xcodeprojPath if xcworkspacePath is empty @@ -53,7 +56,8 @@ public struct LogOptions { xcodeprojPath: String, derivedDataPath: String, xcactivitylogPath: String, - strictProjectName: Bool = false) { + strictProjectName: Bool = false, + newerThan: Date? = nil) { self.projectName = projectName self.xcworkspacePath = xcworkspacePath self.xcodeprojPath = xcodeprojPath @@ -61,6 +65,7 @@ public struct LogOptions { self.xcactivitylogPath = xcactivitylogPath self.logManifestPath = String() self.strictProjectName = strictProjectName + self.newerThan = newerThan } public init(projectName: String, @@ -68,7 +73,8 @@ public struct LogOptions { xcodeprojPath: String, derivedDataPath: String, logManifestPath: String, - strictProjectName: Bool = false) { + strictProjectName: Bool = false, + newerThan: Date? = nil) { self.projectName = projectName self.xcworkspacePath = xcworkspacePath self.xcodeprojPath = xcodeprojPath @@ -76,6 +82,7 @@ public struct LogOptions { self.logManifestPath = logManifestPath self.xcactivitylogPath = String() self.strictProjectName = strictProjectName + self.newerThan = newerThan } } diff --git a/Sources/XCLogParser/loglocation/LogFinder.swift b/Sources/XCLogParser/loglocation/LogFinder.swift index ba1c422..22ec98a 100644 --- a/Sources/XCLogParser/loglocation/LogFinder.swift +++ b/Sources/XCLogParser/loglocation/LogFinder.swift @@ -69,7 +69,7 @@ public struct LogFinder { let projectDir = try getProjectDirWithLogOptions(logOptions) // get latestLog - return try getLatestLogsInDir(projectDir) + return try getLatestLogsInDir(projectDir, since: logOptions.newerThan) } public func findLogManifestWithLogOptions(_ logOptions: LogOptions) throws -> URL { @@ -291,13 +291,20 @@ public struct LogFinder { /// - parameter dir: The full path for the directory /// - returns: The paths of the latest xcactivitylog file in it since given date. /// - throws: An `Error` if the directory doesn't exist or if there are no xcactivitylog files in it. - public func getLatestLogsInDir(_ dir: URL) throws -> [URL] { + public func getLatestLogsInDir(_ dir: URL, since date: Date?) throws -> [URL] { let fileManager = FileManager.default let files = try fileManager.contentsOfDirectory(at: dir, includingPropertiesForKeys: [.contentModificationDateKey], options: .skipsHiddenFiles) let sorted = try files .filter { $0.path.hasSuffix(".xcactivitylog") } + .filter { + guard let timestamp = date else { return true } + guard + let lastModified = try? $0.resourceValues(forKeys: [.contentModificationDateKey]).contentModificationDate + else { return false } + return lastModified > timestamp + } .sorted { let lhv = try $0.resourceValues(forKeys: [.contentModificationDateKey]) let rhv = try $1.resourceValues(forKeys: [.contentModificationDateKey]) From b290ba845153a930a9c28292d3870dab58f8924d Mon Sep 17 00:00:00 2001 From: Danny Gilbert Date: Mon, 7 Feb 2022 14:19:21 -0600 Subject: [PATCH 10/11] LogType - Fixes Tests Path is case sensitive for tests but not in real world use Signed-off-by: Danny Gilbert --- Sources/XCLogParser/loglocation/LogType.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/XCLogParser/loglocation/LogType.swift b/Sources/XCLogParser/loglocation/LogType.swift index edeefbe..6b4e296 100644 --- a/Sources/XCLogParser/loglocation/LogType.swift +++ b/Sources/XCLogParser/loglocation/LogType.swift @@ -22,6 +22,6 @@ public enum LogType: String { public extension LogType { var path: String { - "/Logs/\(self)/" + "/Logs/\(self.rawValue)/" } } From 12ebe8bf80bd38d4f1839619345392ad05c93a4c Mon Sep 17 00:00:00 2001 From: Danny Gilbert Date: Mon, 7 Feb 2022 14:20:38 -0600 Subject: [PATCH 11/11] Moves LogType into LogOptions Signed-off-by: Danny Gilbert --- Sources/XCLogParser/commands/LogOptions.swift | 7 ++++ .../XCLogParser/loglocation/LogFinder.swift | 34 +++++++++---------- .../XCLogParserApp/commands/DumpCommand.swift | 4 +++ .../commands/ManifestCommand.swift | 4 +++ .../commands/ParseCommand.swift | 5 ++- Tests/XCLogParserTests/LogFinderTests.swift | 10 ++++-- Tests/XCLogParserTests/LogManifestTests.swift | 1 + 7 files changed, 42 insertions(+), 23 deletions(-) diff --git a/Sources/XCLogParser/commands/LogOptions.swift b/Sources/XCLogParser/commands/LogOptions.swift index 6b9eb5a..5f2182b 100644 --- a/Sources/XCLogParser/commands/LogOptions.swift +++ b/Sources/XCLogParser/commands/LogOptions.swift @@ -38,6 +38,9 @@ public struct LogOptions { /// The path to a LogManifest.plist file let logManifestPath: String + + /// Type of logs to search for + let logType: LogType /// Use strict Xcode project naming. let strictProjectName: Bool @@ -56,6 +59,7 @@ public struct LogOptions { xcodeprojPath: String, derivedDataPath: String, xcactivitylogPath: String, + logType: LogType, strictProjectName: Bool = false, newerThan: Date? = nil) { self.projectName = projectName @@ -63,6 +67,7 @@ public struct LogOptions { self.xcodeprojPath = xcodeprojPath self.derivedDataPath = derivedDataPath self.xcactivitylogPath = xcactivitylogPath + self.logType = logType self.logManifestPath = String() self.strictProjectName = strictProjectName self.newerThan = newerThan @@ -72,6 +77,7 @@ public struct LogOptions { xcworkspacePath: String, xcodeprojPath: String, derivedDataPath: String, + logType: LogType, logManifestPath: String, strictProjectName: Bool = false, newerThan: Date? = nil) { @@ -80,6 +86,7 @@ public struct LogOptions { self.xcodeprojPath = xcodeprojPath self.derivedDataPath = derivedDataPath self.logManifestPath = logManifestPath + self.logType = logType self.xcactivitylogPath = String() self.strictProjectName = strictProjectName self.newerThan = newerThan diff --git a/Sources/XCLogParser/loglocation/LogFinder.swift b/Sources/XCLogParser/loglocation/LogFinder.swift index 22ec98a..a6595d2 100644 --- a/Sources/XCLogParser/loglocation/LogFinder.swift +++ b/Sources/XCLogParser/loglocation/LogFinder.swift @@ -28,8 +28,6 @@ public struct LogFinder { let xcodebuildPath: String - let logType: LogType - let logManifestFile = "LogStoreManifest.plist" let emptyDirResponseMessage = """ @@ -45,11 +43,9 @@ public struct LogFinder { } public init( - xcodebuildPath: String = "/usr/bin/xcodebuild", - logType: LogType = .build + xcodebuildPath: String = "/usr/bin/xcodebuild" ) { self.xcodebuildPath = xcodebuildPath - self.logType = logType } public func findLatestLogWithLogOptions(_ logOptions: LogOptions) throws -> URL { @@ -124,17 +120,18 @@ public struct LogFinder { // when xcodebuild is run with -derivedDataPath the logs are at the root level if logOptions.derivedDataPath.isEmpty == false { if FileManager.default.fileExists(atPath: - derivedData.appendingPathComponent(logType.path).path) { - return derivedData.appendingPathComponent(logType.path) + derivedData.appendingPathComponent(logOptions.logType.path).path) { + return derivedData.appendingPathComponent(logOptions.logType.path) } } if logOptions.projectLocation.isEmpty == false { - let folderName = try getProjectFolderWithHash(logOptions.projectLocation) + let folderName = try getProjectFolderWithHash(logOptions.projectLocation, logType: logOptions.logType) return derivedData.appendingPathComponent(folderName) } if logOptions.projectName.isEmpty == false { return try findDerivedDataForProject(logOptions.projectName, inDir: derivedData, + logType: logOptions.logType, strictProjectName: logOptions.strictProjectName) } throw LogError.noLogFound(dir: derivedData.path) @@ -156,9 +153,12 @@ public struct LogFinder { /// - parameter name: Name of the project /// - parameter inDir: URL of the derived data directory /// - returns: The path to the derived data of the project or nil if it is not found. - public func findDerivedDataForProject(_ name: String, - inDir derivedDataDir: URL, - strictProjectName: Bool) throws -> URL { + public func findDerivedDataForProject( + _ name: String, + inDir derivedDataDir: URL, + logType: LogType, + strictProjectName: Bool + ) throws -> URL { let fileManager = FileManager.default @@ -207,10 +207,10 @@ public struct LogFinder { /// - parameter projectPath: The path to the .xcodeproj folder /// - returns: The full path to the `Build/Logs` directory /// - throws: An error if the derived data directory couldn't be found - public func logsDirectoryForXcodeProject(projectPath: String) throws -> String { + public func logsDirectoryForXcodeProject(projectPath: String, logType: LogType) throws -> String { let arguments = ["-project", projectPath, "-showBuildSettings"] if let result = try executeXcodeBuild(args: arguments) { - return try parseXcodeBuildDir(result) + return try parseXcodeBuildDir(result, logType: logType) } throw LogError.xcodeBuildError(emptyDirResponseMessage) } @@ -256,10 +256,10 @@ public struct LogFinder { /// - parameter andScheme: The name of the scheme /// - returns: The full path to the `Build/Logs` directory /// - throws: An error if the derived data directory can't be found. - public func logsDirectoryForWorkspace(_ workspace: String, andScheme scheme: String) throws -> String { + public func logsDirectoryForWorkspace(_ workspace: String, andScheme scheme: String, logType: LogType) throws -> String { let arguments = ["-workspace", workspace, "-scheme", scheme, "-showBuildSettings"] if let result = try executeXcodeBuild(args: arguments) { - return try parseXcodeBuildDir(result) + return try parseXcodeBuildDir(result, logType: logType) } throw LogError.xcodeBuildError(emptyDirResponseMessage) } @@ -323,7 +323,7 @@ public struct LogFinder { /// - parameter projectFilePath: A path (relative or absolut) to an .xcworkspace or an .xcodeproj directory /// - returns The name of the folder with the same hash Xcode generates. /// For instance MyApp-dtpdmwoqyxcbrmauwqvycvmftqah/Logs/Build - public func getProjectFolderWithHash(_ projectFilePath: String) throws -> String { + public func getProjectFolderWithHash(_ projectFilePath: String, logType: LogType) throws -> String { let path = Path(projectFilePath).absolute() let projectName = path.lastComponent .replacingOccurrences(of: ".xcworkspace", with: "") @@ -350,7 +350,7 @@ public struct LogFinder { return String(data: data, encoding: .utf8) } - private func parseXcodeBuildDir(_ response: String) throws -> String { + private func parseXcodeBuildDir(_ response: String, logType: LogType) throws -> String { guard !response.starts(with: "xcodebuild: error: ") else { throw LogError.xcodeBuildError(response.replacingOccurrences(of: "xcodebuild: ", with: "")) } diff --git a/Sources/XCLogParserApp/commands/DumpCommand.swift b/Sources/XCLogParserApp/commands/DumpCommand.swift index 8996503..ae466a6 100644 --- a/Sources/XCLogParserApp/commands/DumpCommand.swift +++ b/Sources/XCLogParserApp/commands/DumpCommand.swift @@ -26,6 +26,9 @@ struct DumpCommand: ParsableCommand { commandName: "dump", abstract: "Dumps the xcactivitylog file into a JSON document" ) + + @Option(name: .long, help: "Type of .xactivitylog file to look for.") + var logs: LogType = .build @Option(name: .long, help: "The path to a .xcactivitylog file.") var file: String? @@ -104,6 +107,7 @@ struct DumpCommand: ParsableCommand { xcodeprojPath: xcodeproj ?? "", derivedDataPath: derivedData ?? "", xcactivitylogPath: file ?? "", + logType: logs, strictProjectName: strictProjectName) let actionOptions = ActionOptions(reporter: .json, outputPath: output ?? "", diff --git a/Sources/XCLogParserApp/commands/ManifestCommand.swift b/Sources/XCLogParserApp/commands/ManifestCommand.swift index 4976134..6e1ad19 100644 --- a/Sources/XCLogParserApp/commands/ManifestCommand.swift +++ b/Sources/XCLogParserApp/commands/ManifestCommand.swift @@ -26,6 +26,9 @@ struct ManifestCommand: ParsableCommand { commandName: "manifest", abstract: "Shows the content of a LogManifest plist file as a JSON document." ) + + @Option(name: .long, help: "Type of .xactivitylog file to look for.") + var logs: LogType = .build @Option(name: .customLong("long_manifest"), help: "The path to an existing LogStoreManifest.plist.") var logManifest: String? @@ -89,6 +92,7 @@ struct ManifestCommand: ParsableCommand { xcworkspacePath: workspace ?? "", xcodeprojPath: xcodeproj ?? "", derivedDataPath: derivedData ?? "", + logType: logs, logManifestPath: logManifest ?? "", strictProjectName: strictProjectName) diff --git a/Sources/XCLogParserApp/commands/ParseCommand.swift b/Sources/XCLogParserApp/commands/ParseCommand.swift index 25a70d4..3a69fbe 100644 --- a/Sources/XCLogParserApp/commands/ParseCommand.swift +++ b/Sources/XCLogParserApp/commands/ParseCommand.swift @@ -160,14 +160,13 @@ struct ParseCommand: ParsableCommand { guard let xclReporter = Reporter(rawValue: reporter) else { return } - let commandHandler = CommandHandler( - logFinder: .init(logType: logs) - ) + let commandHandler = CommandHandler() let logOptions = LogOptions(projectName: project ?? "", xcworkspacePath: workspace ?? "", xcodeprojPath: xcodeproj ?? "", derivedDataPath: derivedData ?? "", xcactivitylogPath: file ?? "", + logType: logs, strictProjectName: strictProjectName) let actionOptions = ActionOptions(reporter: xclReporter, outputPath: output ?? "", diff --git a/Tests/XCLogParserTests/LogFinderTests.swift b/Tests/XCLogParserTests/LogFinderTests.swift index be1d02f..b7dd087 100644 --- a/Tests/XCLogParserTests/LogFinderTests.swift +++ b/Tests/XCLogParserTests/LogFinderTests.swift @@ -74,7 +74,7 @@ class LogFinderTests: XCTestCase { XCTFail("Unable to create test directories.") return } - let projectFolder = try logFinder.getProjectFolderWithHash("/Users/user/projects/MyProject.xcworkspace") + let projectFolder = try logFinder.getProjectFolderWithHash("/Users/user/projects/MyProject.xcworkspace", logType: .build) let logsFolder = projectFolder.appending("/Logs/Build") let projectLogFolder = derivedDataDir.appendingPathComponent(logsFolder, isDirectory: true) _ = try TestUtils.createSubdir(logsFolder, in: derivedDataDir) @@ -97,13 +97,13 @@ class LogFinderTests: XCTestCase { return } // since there is not a valid xcodeproj in the path, it should fail - XCTAssertThrowsError(try logFinder.logsDirectoryForXcodeProject(projectPath: dirWithProject.path)) + XCTAssertThrowsError(try logFinder.logsDirectoryForXcodeProject(projectPath: dirWithProject.path, logType: .build)) } func testGetProjectFolderWithHash() throws { let projectPath = "/tmp/MyWorkspace.xcworkspace" let expectedProjectFolder = "MyWorkspace-fvaxjdltriwevoggjzpmzcohhhxf/Logs/Build/" - let projectFolder = try logFinder.getProjectFolderWithHash(projectPath) + let projectFolder = try logFinder.getProjectFolderWithHash(projectPath, logType: .build) XCTAssertEqual(expectedProjectFolder, projectFolder) } @@ -116,6 +116,7 @@ class LogFinderTests: XCTestCase { xcworkspacePath: "/tmp/MyWorkspace.xcworkspace", xcodeprojPath: "", derivedDataPath: derivedDataDir.path, + logType: .build, logManifestPath: "") let logManifestURL = try logFinder.findLogManifestURLWithLogOptions(logOptions) let expectedPathPattern = "\(derivedDataDir.path)/MyWorkspace-fvaxjdltriwevoggjzpmzcohhhxf" + @@ -128,6 +129,7 @@ class LogFinderTests: XCTestCase { xcworkspacePath: "", xcodeprojPath: "/tmp/MyApp.xcodeproj", derivedDataPath: "/projects/DerivedData", + logType: .build, logManifestPath: "") let logManifestURL = try logFinder.findLogManifestURLWithLogOptions(logOptions) let expectedPathPattern = "/projects/DerivedData/" + @@ -140,6 +142,7 @@ class LogFinderTests: XCTestCase { xcworkspacePath: "", xcodeprojPath: "/tmp/MyApp.xcodeproj", derivedDataPath: "/projects/DerivedData", + logType: .build, logManifestPath: "") XCTAssertThrowsError(try logFinder.findLogManifestWithLogOptions(logOptions)) } @@ -154,6 +157,7 @@ class LogFinderTests: XCTestCase { xcworkspacePath: "", xcodeprojPath: "/tmp/MyApp.xcodeproj", derivedDataPath: customDerivedDataDir.path, + logType: .build, logManifestPath: "") let latestLog = try logFinder.findLatestLogWithLogOptions(logOptions) diff --git a/Tests/XCLogParserTests/LogManifestTests.swift b/Tests/XCLogParserTests/LogManifestTests.swift index 3e2f164..0c0f713 100644 --- a/Tests/XCLogParserTests/LogManifestTests.swift +++ b/Tests/XCLogParserTests/LogManifestTests.swift @@ -78,6 +78,7 @@ class LogManifestTests: XCTestCase { xcworkspacePath: "", xcodeprojPath: "", derivedDataPath: "", + logType: .build, logManifestPath: logURL.path) let logEntries = try LogManifest().getWithLogOptions(logOptions) XCTAssertEqual(1, logEntries.count)