Skip to content

Commit b2d7f2e

Browse files
authored
Fix parsing failing due to new TaskBacktrace activity log attachment (#235)
* Fix parsing failing due to new TaskBacktrace activity log attachment Signed-off-by: fortmarek <marekfort@me.com> * Align backtrace with swift-build Signed-off-by: fortmarek <marekfort@me.com> --------- Signed-off-by: fortmarek <marekfort@me.com>
1 parent 5facacc commit b2d7f2e

4 files changed

Lines changed: 132 additions & 10 deletions

File tree

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/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)

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

0 commit comments

Comments
 (0)