Skip to content

Commit 445b733

Browse files
authored
Merge branch 'master' into replace-scanner-with-substrings
2 parents cf4df99 + e523c14 commit 445b733

File tree

7 files changed

+135
-14
lines changed

7 files changed

+135
-14
lines changed

Sources/XCLogParser/activityparser/ActivityParser.swift

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -380,12 +380,27 @@ public class ActivityParser {
380380
}
381381

382382
if className == "IDEFoundation.\(String(describing: IDEActivityLogSectionAttachment.self))" {
383-
let jsonType = IDEActivityLogSectionAttachment.BuildOperationTaskMetrics.self
384-
return try IDEActivityLogSectionAttachment(identifier: try parseAsString(token: iterator.next()),
385-
majorVersion: try parseAsInt(token: iterator.next()),
386-
minorVersion: try parseAsInt(token: iterator.next()),
387-
metrics: try parseAsJson(token: iterator.next(),
388-
type: jsonType))
383+
let identifier = try parseAsString(token: iterator.next())
384+
switch identifier.components(separatedBy: "ActivityLogSectionAttachment.").last {
385+
case .some("TaskMetrics"):
386+
let jsonType = IDEActivityLogSectionAttachment.BuildOperationTaskMetrics.self
387+
return try IDEActivityLogSectionAttachment(identifier: identifier,
388+
majorVersion: try parseAsInt(token: iterator.next()),
389+
minorVersion: try parseAsInt(token: iterator.next()),
390+
metrics: try parseAsJson(token: iterator.next(),
391+
type: jsonType),
392+
backtrace: nil)
393+
case .some("TaskBacktrace"):
394+
let jsonType = IDEActivityLogSectionAttachment.BuildOperationTaskBacktrace.self
395+
return try IDEActivityLogSectionAttachment(identifier: identifier,
396+
majorVersion: try parseAsInt(token: iterator.next()),
397+
minorVersion: try parseAsInt(token: iterator.next()),
398+
metrics: nil,
399+
backtrace: try parseAsJson(token: iterator.next(),
400+
type: jsonType))
401+
default:
402+
throw XCLogParserError.parseError("Unexpected attachment identifier \(identifier)")
403+
}
389404
}
390405
throw XCLogParserError.parseError("Unexpected className found parsing IDEConsoleItem \(className)")
391406
}

Sources/XCLogParser/activityparser/IDEActivityModel.swift

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -658,16 +658,115 @@ public class IDEActivityLogSectionAttachment: Encodable {
658658
public let majorVersion: UInt64
659659
public let minorVersion: UInt64
660660
public let metrics: BuildOperationTaskMetrics?
661+
public let backtrace: BuildOperationTaskBacktrace?
661662

662663
public init(
663664
identifier: String,
664665
majorVersion: UInt64,
665666
minorVersion: UInt64,
666-
metrics: BuildOperationTaskMetrics?
667+
metrics: BuildOperationTaskMetrics?,
668+
backtrace: BuildOperationTaskBacktrace?
667669
) throws {
668670
self.identifier = identifier
669671
self.majorVersion = majorVersion
670672
self.minorVersion = minorVersion
671673
self.metrics = metrics
674+
self.backtrace = backtrace
675+
}
676+
677+
public struct BuildOperationTaskBacktrace: Codable {
678+
public let frames: [BuildOperationTaskBacktraceFrame]
679+
680+
public init(from decoder: any Decoder) throws {
681+
let container = try decoder.singleValueContainer()
682+
self.frames = try container.decode([BuildOperationTaskBacktraceFrame].self)
683+
}
684+
685+
public func encode(to encoder: any Encoder) throws {
686+
var container = encoder.singleValueContainer()
687+
try container.encode(frames)
688+
}
689+
}
690+
691+
public struct BuildOperationTaskBacktraceFrame: Codable {
692+
public let category: BuildOperationTaskBacktraceCategory
693+
public let description: String
694+
}
695+
696+
public enum BuildOperationTaskBacktraceCategory: String, Codable {
697+
case ruleHadInvalidValue
698+
case ruleSignatureChanged
699+
case ruleNeverBuilt
700+
case ruleInputRebuilt
701+
case ruleForced
702+
case dynamicTaskRegistration
703+
case dynamicTaskRequest
704+
case none
705+
706+
public init(from decoder: Decoder) throws {
707+
let container = try decoder.container(keyedBy: BuildOperationTaskBacktraceCategoryCodingKeys.self)
708+
709+
if container.contains(.ruleHadInvalidValue) {
710+
self = .ruleHadInvalidValue
711+
} else if container.contains(.ruleSignatureChanged) {
712+
self = .ruleSignatureChanged
713+
} else if container.contains(.ruleNeverBuilt) {
714+
self = .ruleNeverBuilt
715+
} else if container.contains(.ruleInputRebuilt) {
716+
self = .ruleInputRebuilt
717+
} else if container.contains(.ruleForced) {
718+
self = .ruleForced
719+
} else if container.contains(.dynamicTaskRegistration) {
720+
self = .dynamicTaskRegistration
721+
} else if container.contains(.dynamicTaskRequest) {
722+
self = .dynamicTaskRequest
723+
} else if container.contains(.none) {
724+
self = .none
725+
} else {
726+
throw DecodingError.dataCorrupted(
727+
DecodingError.Context(
728+
codingPath: decoder.codingPath,
729+
debugDescription: "Unknown task backtrace category"
730+
)
731+
)
732+
}
733+
}
734+
735+
public func encode(to encoder: Encoder) throws {
736+
var container = encoder.container(keyedBy: BuildOperationTaskBacktraceCategoryCodingKeys.self)
737+
switch self {
738+
case .ruleHadInvalidValue:
739+
try container.encode(EmptyObject(), forKey: .ruleHadInvalidValue)
740+
case .ruleSignatureChanged:
741+
try container.encode(EmptyObject(), forKey: .ruleSignatureChanged)
742+
case .ruleNeverBuilt:
743+
try container.encode(EmptyObject(), forKey: .ruleNeverBuilt)
744+
case .ruleInputRebuilt:
745+
try container.encode(EmptyObject(), forKey: .ruleInputRebuilt)
746+
case .ruleForced:
747+
try container.encode(EmptyObject(), forKey: .ruleForced)
748+
case .dynamicTaskRegistration:
749+
try container.encode(EmptyObject(), forKey: .dynamicTaskRegistration)
750+
case .dynamicTaskRequest:
751+
try container.encode(EmptyObject(), forKey: .dynamicTaskRequest)
752+
case .none:
753+
try container.encode(EmptyObject(), forKey: .none)
754+
}
755+
}
756+
}
757+
758+
private enum BuildOperationTaskBacktraceCategoryCodingKeys: String, CodingKey {
759+
case ruleHadInvalidValue
760+
case ruleSignatureChanged
761+
case ruleNeverBuilt
762+
case ruleInputRebuilt
763+
case ruleForced
764+
case dynamicTaskRegistration
765+
case dynamicTaskRequest
766+
case none
767+
}
768+
769+
private struct EmptyObject: Codable {
770+
// Empty struct for objects with no properties
672771
}
673772
}

Sources/XCLogParser/commands/Version.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@ import Foundation
2121

2222
public struct Version {
2323

24-
public static let current = "0.2.41"
24+
public static let current = "0.2.43"
2525

2626
}

Sources/XCLogParser/logmanifest/LogManifest.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public struct LogManifest {
2525

2626
public init() {}
2727

28-
public func getWithLogOptions(_ logOptions: LogOptions) throws -> [LogManifestEntry] {
28+
public func getWithLogOptions(_ logOptions: LogOptions) throws -> [LogManifestEntry] {
2929
let logFinder = LogFinder()
3030
let logManifestURL = try logFinder.findLogManifestWithLogOptions(logOptions)
3131
let logManifestDictionary = try getDictionaryFromURL(logManifestURL)

Sources/XCLogParser/parser/IDEActivityLogSection+Parsing.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ extension IDEActivityLogSection {
4242
func groupedByTarget() -> IDEActivityLogSection {
4343
// The only way to know if the structure is flatten is to check the first elements
4444
// for the `(in target 'ABC' from project Project)` string
45-
let firstElements = subSections.prefix(15) // we only analyze up to the first 15 subsections
46-
let isFlatten = firstElements.contains { $0.getTargetFromCommand() != nil }
45+
let isFlatten = subSections.contains { $0.getTargetFromCommand() != nil }
4746
if isFlatten {
4847
let mainTarget = "$MainTarget"
4948
let targetsDictionary = subSections.reduce(

Tests/XCLogParserTests/ActivityParserTests.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,13 @@ class ActivityParserTests: XCTestCase {
9797
Token.string("501796C4-6BE4-4F80-9F9D-3269617ECC17"),
9898
Token.string("localizedResultString"),
9999
Token.string("xcbuildSignature"),
100-
Token.list(1),
100+
Token.list(2),
101+
Token.classNameRef("IDEFoundation.IDEActivityLogSectionAttachment"),
102+
Token.string("com.apple.dt.ActivityLogSectionAttachment.TaskBacktrace"),
103+
Token.int(1),
104+
Token.int(0),
105+
// swiftlint:disable:next line_length
106+
Token.json(#"[{"description":"'Planning Swift module ConcurrencyExtras (arm64)' had never run","category":{"ruleNeverBuilt":{}},"identifier":{"storage":{"task":{"_0":[0,80,50,58,116,97,114,103,101,116,45,67,111,110,99,117,114,114,101,110,99,121,69,120,116,114,97,115,45,101,102,52,50,51,48,52,53,57,52,98,102,56,53,50,102,52,51,56,101,102,55,99,51,97,49,51,54,98,50,99,57,48,100,102,56,55,49,56,97,102,50,98,57,100,51,97,97,99,48,100,48,100,99,97,50,50,98,52,99,50,57,99,50,45,58,66,101,116,97,32,68,101,98,117,103,58,51,99,57,97,99,57,53,50,98,52,99,56,49,100,57,99,99,49,55,100,49,97,102,52,55,49,97,48,52,53,101,56]}}},"frameKind":{"genericTask":{}}}]"#),
101107
Token.classNameRef("IDEFoundation.IDEActivityLogSectionAttachment"),
102108
Token.string("com.apple.dt.ActivityLogSectionAttachment.TaskMetrics"),
103109
Token.int(1),
@@ -339,7 +345,9 @@ class ActivityParserTests: XCTestCase {
339345
XCTAssertEqual("501796C4-6BE4-4F80-9F9D-3269617ECC17", logSection.uniqueIdentifier)
340346
XCTAssertEqual("localizedResultString", logSection.localizedResultString)
341347
XCTAssertEqual("xcbuildSignature", logSection.xcbuildSignature)
342-
XCTAssertEqual(1, logSection.attachments.count)
348+
XCTAssertEqual(2, logSection.attachments.count)
349+
XCTAssertEqual(logSection.attachments[0].backtrace?.frames.first?.category, .ruleNeverBuilt)
350+
XCTAssertEqual(logSection.attachments[1].metrics?.wcDuration, 1)
343351
XCTAssertEqual(0, logSection.unknown)
344352
}
345353

docs/Xcactivitylog Format.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,4 +155,4 @@ Inside the logs you can find these classes:
155155

156156
If you search for them, you will find that they belong to the IDEFoundation.framework. A private framework part of Xcode. You can class dump it to get the headers of those classes. Once you have the headers, you will have the name and type of the properties that belong to the class. Now, you can match them to the tokens you got from the log. Some of them are in the same order than in the headers, but for others it will be about trial and error.
157157

158-
In the project you can find those classes with their properties in the order in which they appear in the log in the file (IDEActivityModel.swift)[https://github.com/MobileNativeFoundation/XCLogParser/blob/master/Sources/XCLogParser/activityparser/IDEActivityModel.swift].
158+
In the project you can find those classes with their properties in the order in which they appear in the log in the file [IDEActivityModel.swift](../Sources/XCLogParser/activityparser/IDEActivityModel.swift).

0 commit comments

Comments
 (0)