From 46da424b565d1541e1874a7ac1d87ec5e09d8a82 Mon Sep 17 00:00:00 2001 From: Suman Cherukuri Date: Fri, 11 Jul 2025 14:48:01 -0700 Subject: [PATCH] Fix to parse xcresulttool version when the version string has major.minor format When testing Xcode 26 beta 2, when `xcrun xcresulttool version` is executed, the output comes in as "xcresulttool version 24038.1, schema version: 0.0.0 (legacy commands format version: 3.53)". xcresulttool() function is failing to create teh Version instance because of the unexpected format. As a result, --legacy flag is not getting added causing the parser to fail. Fix is to get the major version from version string. Tested with Xcode 26 beta 2 and beta 3 versions. --- Sources/XCParseCore/String+Tokenizer.swift | 26 ++++++++++++++++++++ Sources/XCParseCore/Version+XCPTooling.swift | 16 +++++++++--- xcparse.xcodeproj/project.pbxproj | 14 +++++++---- 3 files changed, 47 insertions(+), 9 deletions(-) create mode 100644 Sources/XCParseCore/String+Tokenizer.swift diff --git a/Sources/XCParseCore/String+Tokenizer.swift b/Sources/XCParseCore/String+Tokenizer.swift new file mode 100644 index 0000000..fccf1ea --- /dev/null +++ b/Sources/XCParseCore/String+Tokenizer.swift @@ -0,0 +1,26 @@ +// +// String+Tokenizer.swift +// xcparse +// +// Created by Suman Cherukuri on 7/11/25. +// + + +/// https://stackoverflow.com/a/64108233 +extension String { + func before(first delimiter: Character) -> String { + if let index = firstIndex(of: delimiter) { + let before = prefix(upTo: index) + return String(before) + } + return "" + } + + func after(first delimiter: Character) -> String { + if let index = firstIndex(of: delimiter) { + let after = suffix(from: index).dropFirst() + return String(after) + } + return "" + } +} diff --git a/Sources/XCParseCore/Version+XCPTooling.swift b/Sources/XCParseCore/Version+XCPTooling.swift index b9dc436..9622662 100644 --- a/Sources/XCParseCore/Version+XCPTooling.swift +++ b/Sources/XCParseCore/Version+XCPTooling.swift @@ -25,24 +25,32 @@ public extension Version { let xcresultVersionString = try xcresulttoolVersionResult.utf8Output() let components = xcresultVersionString.components(separatedBy: CharacterSet(charactersIn: ",\n")) + var xcresulttoolVersion: Version? + for string in components { let trimmedString = string.trimmingCharacters(in: .whitespacesAndNewlines) if trimmedString.hasPrefix("xcresulttool version ") { let xcresulttoolVersionString = trimmedString.replacingOccurrences(of: "xcresulttool version ", with: "") // Check to see if we can convert it to a number - var xcresulttoolVersion: Version? - if let xcresulttoolVersionInt = Int(xcresulttoolVersionString) { xcresulttoolVersion = Version(xcresulttoolVersionInt, 0, 0) } else { xcresulttoolVersion = Version(string: xcresulttoolVersionString) } - return xcresulttoolVersion + // on some Xcode versions (for example Xcode 26 beta 2),xcresulttoolVersion is coming in as 24038.1 + let cleanedVersionString = xcresulttoolVersionString.before(first: ".") + if let cleanedVersionInt = Int(cleanedVersionString) { + xcresulttoolVersion = Version(cleanedVersionInt, 0, 0) + } } } - return nil + if xcresulttoolVersion == nil { + print("Failed to parse xcresulttool version: \(xcresultVersionString)") + } + return xcresulttoolVersion + } catch { print("Failed to parse xcresulttool version with error: \(error)") return nil diff --git a/xcparse.xcodeproj/project.pbxproj b/xcparse.xcodeproj/project.pbxproj index deba745..7b6b0ac 100644 --- a/xcparse.xcodeproj/project.pbxproj +++ b/xcparse.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 254333312E21B41700E99D33 /* String+Tokenizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 254333302E21B41700E99D33 /* String+Tokenizer.swift */; }; 62525EAE2376350100472F82 /* Version+XCPTooling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62525EAD2376350100472F82 /* Version+XCPTooling.swift */; }; 62CC363E23553EA0003C7B68 /* XCResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62CC363D23553EA0003C7B68 /* XCResult.swift */; }; 62CC36592357C110003C7B68 /* AttachmentsCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62CC36582357C110003C7B68 /* AttachmentsCommand.swift */; }; @@ -328,6 +329,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 254333302E21B41700E99D33 /* String+Tokenizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Tokenizer.swift"; sourceTree = ""; }; 62525EAD2376350100472F82 /* Version+XCPTooling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Version+XCPTooling.swift"; sourceTree = ""; }; 62CC363D23553EA0003C7B68 /* XCResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCResult.swift; sourceTree = ""; }; 62CC36582357C110003C7B68 /* AttachmentsCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentsCommand.swift; sourceTree = ""; }; @@ -908,6 +910,9 @@ OBJ_13 /* ActionResult.swift */, OBJ_14 /* ActionRunDestinationRecord.swift */, OBJ_15 /* ActionSDKRecord.swift */, + OBJ_27 /* ActionsInvocationMetadata.swift */, + OBJ_28 /* ActionsInvocationRecord.swift */, + OBJ_26 /* ActionTestableSummary.swift */, OBJ_16 /* ActionTestActivitySummary.swift */, OBJ_17 /* ActionTestAttachment.swift */, OBJ_18 /* ActionTestFailureSummary.swift */, @@ -918,9 +923,6 @@ OBJ_23 /* ActionTestSummary.swift */, OBJ_24 /* ActionTestSummaryGroup.swift */, OBJ_25 /* ActionTestSummaryIdentifiableObject.swift */, - OBJ_26 /* ActionTestableSummary.swift */, - OBJ_27 /* ActionsInvocationMetadata.swift */, - OBJ_28 /* ActionsInvocationRecord.swift */, OBJ_29 /* ActivityLogAnalyzerControlFlowStep.swift */, OBJ_30 /* ActivityLogAnalyzerControlFlowStepEdge.swift */, OBJ_31 /* ActivityLogAnalyzerEventStep.swift */, @@ -944,12 +946,13 @@ OBJ_49 /* Reference.swift */, OBJ_50 /* ResultIssueSummaries.swift */, OBJ_51 /* ResultMetrics.swift */, + 254333302E21B41700E99D33 /* String+Tokenizer.swift */, OBJ_52 /* TestFailureIssueSummary.swift */, OBJ_53 /* TypeDefinition.swift */, - OBJ_54 /* XCPResultDecoding.swift */, 62525EAD2376350100472F82 /* Version+XCPTooling.swift */, - OBJ_55 /* XCResultToolCommand.swift */, + OBJ_54 /* XCPResultDecoding.swift */, 62CC363D23553EA0003C7B68 /* XCResult.swift */, + OBJ_55 /* XCResultToolCommand.swift */, ); name = XCParseCore; path = Sources/XCParseCore; @@ -1276,6 +1279,7 @@ OBJ_300 /* ActivityLogAnalyzerControlFlowStepEdge.swift in Sources */, OBJ_301 /* ActivityLogAnalyzerEventStep.swift in Sources */, OBJ_302 /* ActivityLogAnalyzerResultMessage.swift in Sources */, + 254333312E21B41700E99D33 /* String+Tokenizer.swift in Sources */, OBJ_303 /* ActivityLogAnalyzerStep.swift in Sources */, OBJ_304 /* ActivityLogAnalyzerWarningMessage.swift in Sources */, OBJ_305 /* ActivityLogCommandInvocationSection.swift in Sources */,