Skip to content

Commit 8547650

Browse files
authored
Merge branch 'master' into hs/fix-wip
2 parents b9f1a85 + 49854bb commit 8547650

File tree

10 files changed

+291
-81
lines changed

10 files changed

+291
-81
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.39"
24+
public static let current = "0.2.43"
2525

2626
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (c) 2019 Spotify AB.
2+
//
3+
// Licensed to the Apache Software Foundation (ASF) under one
4+
// or more contributor license agreements. See the NOTICE file
5+
// distributed with this work for additional information
6+
// regarding copyright ownership. The ASF licenses this file
7+
// to you under the Apache License, Version 2.0 (the
8+
// "License"); you may not use this file except in compliance
9+
// with the License. You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing,
14+
// software distributed under the License is distributed on an
15+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
// KIND, either express or implied. See the License for the
17+
// specific language governing permissions and limitations
18+
// under the License.
19+
20+
import Foundation
21+
22+
extension String.Index {
23+
init(compilerSafeOffset offset: Int, in string: String) {
24+
#if swift(>=5.0)
25+
self = String.Index(utf16Offset: offset, in: string)
26+
#else
27+
self = String.Index(encodedOffset: offset)
28+
#endif
29+
}
30+
}

Sources/XCLogParser/lexer/Lexer.swift

Lines changed: 43 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public final class Lexer {
2323

2424
static let SLFHeader = "SLF"
2525

26-
let typeDelimiters: CharacterSet
26+
let typeDelimiters: Set<Character>
2727
let filePath: String
2828
var classNames = [String]()
2929
var userDirToRedact: String? {
@@ -38,7 +38,7 @@ public final class Lexer {
3838

3939
public init(filePath: String) {
4040
self.filePath = filePath
41-
self.typeDelimiters = CharacterSet(charactersIn: TokenType.all())
41+
self.typeDelimiters = Set(TokenType.all())
4242
self.redactor = LexRedactor()
4343
}
4444

@@ -53,15 +53,18 @@ public final class Lexer {
5353
redacted: Bool,
5454
withoutBuildSpecificInformation: Bool) throws -> [Token] {
5555
let scanner = Scanner(string: contents)
56+
5657
guard scanSLFHeader(scanner: scanner) else {
5758
throw XCLogParserError.invalidLogHeader(filePath)
5859
}
60+
5961
var tokens = [Token]()
6062
while !scanner.isAtEnd {
63+
6164
guard let logTokens = scanSLFType(scanner: scanner,
6265
redacted: redacted,
6366
withoutBuildSpecificInformation: withoutBuildSpecificInformation),
64-
logTokens.isEmpty == false else {
67+
logTokens.isEmpty == false else {
6568
print(tokens)
6669
throw XCLogParserError.invalidLine(scanner.approximateLine)
6770
}
@@ -71,20 +74,15 @@ public final class Lexer {
7174
}
7275

7376
private func scanSLFHeader(scanner: Scanner) -> Bool {
74-
#if os(Linux)
75-
var format: String?
76-
#else
77-
var format: NSString?
78-
#endif
79-
return scanner.scanString(Lexer.SLFHeader, into: &format)
77+
return scanner.scan(string: Lexer.SLFHeader)
8078
}
8179

82-
private func scanSLFType(scanner: Scanner, redacted: Bool, withoutBuildSpecificInformation: Bool) -> [Token]? {
80+
private func scanSLFType(scanner: Scanner,
81+
redacted: Bool,
82+
withoutBuildSpecificInformation: Bool) -> [Token]? {
83+
let payload = self.scanPayload(scanner: scanner)
8384

84-
guard let payload = scanPayload(scanner: scanner) else {
85-
return nil
86-
}
87-
guard let tokenTypes = scanTypeDelimiter(scanner: scanner), tokenTypes.count > 0 else {
85+
guard let tokenTypes = self.scanTypeDelimiter(scanner: scanner), tokenTypes.count > 0 else {
8886
return nil
8987
}
9088

@@ -97,44 +95,30 @@ public final class Lexer {
9795
}
9896
}
9997

100-
private func scanPayload(scanner: Scanner) -> String? {
101-
var payload: String = ""
102-
#if os(Linux)
103-
var char: String?
104-
#else
105-
var char: NSString?
106-
#endif
98+
private func scanPayload(scanner: Scanner) -> String {
10799
let hexChars = "abcdef0123456789"
108-
while scanner.scanCharacters(from: CharacterSet(charactersIn: hexChars), into: &char),
109-
let char = char as String? {
110-
payload.append(char)
111-
}
112-
return payload
100+
let characterSet = Set(hexChars)
101+
return scanner.scanCharacters(from: characterSet) ?? ""
113102
}
114103

115104
private func scanTypeDelimiter(scanner: Scanner) -> [TokenType]? {
116-
#if os(Linux)
117-
var delimiters: String?
118-
#else
119-
var delimiters: NSString?
120-
#endif
121-
if scanner.scanCharacters(from: typeDelimiters, into: &delimiters), let delimiters = delimiters {
122-
let delimiters = String(delimiters)
123-
if delimiters.count > 1 {
124-
// if we found a string, we discard other type delimiters because there are part of the string
125-
let tokenString = TokenType.string
126-
if let char = delimiters.first, tokenString.rawValue == String(char) {
127-
scanner.scanLocation -= delimiters.count - 1
128-
return [tokenString]
129-
}
130-
}
131-
// sometimes we found one or more nil list (-) next to the type delimiter
132-
// in that case we'll return the delimiter and one or more `Token.null`
133-
return delimiters.compactMap { character -> TokenType? in
134-
TokenType(rawValue: String(character))
105+
guard let delimiters = scanner.scanCharacters(from: self.typeDelimiters) else {
106+
return nil
107+
}
108+
109+
if delimiters.count > 1 {
110+
// if we found a string, we discard other type delimiters because there are part of the string
111+
let tokenString = TokenType.string
112+
if let char = delimiters.first, tokenString.rawValue == String(char) {
113+
scanner.moveOffset(by: -(delimiters.count - 1))
114+
return [tokenString]
135115
}
136116
}
137-
return nil
117+
// sometimes we found one or more nil list (-) next to the type delimiter
118+
// in that case we'll return the delimiter and one or more `Token.null`
119+
return delimiters.compactMap { character -> TokenType? in
120+
TokenType(rawValue: String(character))
121+
}
138122
}
139123

140124
private func scanToken(scanner: Scanner,
@@ -252,19 +236,12 @@ public final class Lexer {
252236
scanner: Scanner,
253237
redacted: Bool,
254238
withoutBuildSpecificInformation: Bool) -> String? {
255-
guard let value = Int(length) else {
239+
guard let value = Int(length), let scannedResult = scanner.scan(count: value) else {
256240
print("error parsing string")
257241
return nil
258242
}
259-
#if swift(>=5.0)
260-
let start = String.Index(utf16Offset: scanner.scanLocation, in: scanner.string)
261-
let end = String.Index(utf16Offset: scanner.scanLocation + value, in: scanner.string)
262-
#else
263-
let start = String.Index(encodedOffset: scanner.scanLocation)
264-
let end = String.Index(encodedOffset: scanner.scanLocation + value)
265-
#endif
266-
scanner.scanLocation += value
267-
var result = String(scanner.string[start..<end])
243+
244+
var result = scannedResult
268245
if redacted {
269246
result = redactor.redactUserDir(string: result)
270247
}
@@ -285,19 +262,18 @@ public final class Lexer {
285262
}
286263
}
287264

288-
extension Scanner {
265+
private extension Scanner {
289266
var approximateLine: String {
290-
let endCount = string.count - scanLocation > 21 ? scanLocation + 21 : string.count - scanLocation
291-
#if swift(>=5.0)
292-
let start = String.Index(utf16Offset: scanLocation, in: self.string)
293-
let end = String.Index(utf16Offset: endCount, in: self.string)
294-
#else
295-
let start = String.Index(encodedOffset: scanLocation)
296-
let end = String.Index(encodedOffset: endCount)
297-
#endif
267+
let currentLocation = self.offset
268+
let contentSize = self.string.count
269+
270+
let start = String.Index(compilerSafeOffset: currentLocation, in: self.string)
271+
let endCount = contentSize - currentLocation > 21 ? currentLocation + 21 : contentSize - currentLocation
272+
let end = String.Index(compilerSafeOffset: endCount, in: self.string)
273+
298274
if end <= start {
299-
return String(string[start..<string.endIndex])
275+
return String(self.string[start..<self.stringEndIndex])
300276
}
301-
return String(string[start..<end])
277+
return String(self.string[start..<end])
302278
}
303279
}

0 commit comments

Comments
 (0)