Skip to content

Commit 6f8f588

Browse files
authored
ENG-55520: On sourceTree decode error, log & continue (#88)
ENG-55520 * On sourceTree decode error, log & continue * SourceTree: refactor to class
1 parent 1bc6b8b commit 6f8f588

5 files changed

Lines changed: 131 additions & 92 deletions

File tree

PIF/Sources/PIFSupport/PIF.swift

Lines changed: 102 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ public enum PIF {
7272
required public init(from decoder: Decoder) throws {
7373
let container = try decoder.container(keyedBy: CodingKeys.self)
7474
type = try container.decode(String.self, forKey: .type)
75+
logger.trace(" ---> Decoded TypedObject \(String(describing: type))")
7576
}
7677
}
7778

@@ -95,13 +96,16 @@ public enum PIF {
9596
guid = try container.decode(GUID.self, forKey: .guid)
9697
name = try container.decode(String.self, forKey: .name)
9798
path = try container.decodeIfPresent(URL.self, forKey: .path)
98-
99+
logger.trace(" ---> Decoded Workspace: guid \(guid) name \(name) path \(path?.absoluteString ?? "<nil>" ) ")
99100
let projectPaths = try container.decode([String].self, forKey: .projects)
100101
.map {
101102
cachePath
102103
.appendingPathComponent("project")
103104
.appendingPathComponent("\($0)\(PIF.cacheFileExtension)")
104105
}
106+
projectPaths.forEach { URL in
107+
logger.trace("\t project path \(URL)")
108+
}
105109

106110
let projectContents = try projectPaths
107111
.map {
@@ -147,6 +151,7 @@ public enum PIF {
147151
projectDirectory = try container.decode(URL.self, forKey: .projectDirectory)
148152
developmentRegion = try container.decodeIfPresent(String.self, forKey: .developmentRegion)
149153
buildConfigurations = try container.decode([BuildConfiguration].self, forKey: .buildConfigurations)
154+
logger.trace(" ---> Decoded Project: guid \(guid) name \(projectName ?? "<nil>") path \(path?.absoluteString ?? "<nil>" ) ")
150155

151156
let targetContents = try container.decode([String].self, forKey: .targets)
152157
.map {
@@ -165,6 +170,7 @@ public enum PIF {
165170
targets = try targetContents.compactMap { targetData in
166171
let pifDecoder = PIFDecoder(cache: cachePath)
167172
let untypedTarget = try pifDecoder.decode(PIF.TypedObject.self, from: targetData)
173+
logger.trace("\t untyped target type: \(untypedTarget)")
168174
switch untypedTarget.type {
169175
case "aggregate":
170176
return try pifDecoder.decode(PIF.AggregateTarget.self, from: targetData)
@@ -182,26 +188,6 @@ public enum PIF {
182188
/// Abstract base class for all items in the group hierarchy.
183189
public class Reference: TypedObject {
184190
/// Determines the base path for a reference's relative path.
185-
public enum SourceTree: String, Decodable {
186-
/// Indicates that the path is relative to the source root (i.e. the "project directory").
187-
case sourceRoot = "SOURCE_ROOT"
188-
189-
/// Indicates that the path is relative to the path of the parent group.
190-
case group = "<group>"
191-
192-
/// Indicates that the path is relative to the effective build directory (which varies depending on active
193-
/// scheme, active run destination, or even an overridden build setting.
194-
case builtProductsDir = "BUILT_PRODUCTS_DIR"
195-
196-
/// Indicates that the path is an absolute path.
197-
case absolute = "<absolute>"
198-
199-
/// Indicates that the path is relative to the SDKROOT
200-
case sdkRoot = "SDKROOT"
201-
202-
/// Indicates that the path is relative to the DEVELOPER_DIR (normally in the Xcode.app bundle)
203-
case developerDir = "DEVELOPER_DIR"
204-
}
205191

206192
public let guid: GUID
207193

@@ -228,6 +214,77 @@ public enum PIF {
228214
name = try container.decodeIfPresent(String.self, forKey: .name)
229215

230216
try super.init(from: decoder)
217+
logger.trace(" ---> Decoded Reference guid \(guid) name \(name ?? "<nil>") path (\(path))")
218+
}
219+
}
220+
221+
public enum SourceTree: RawRepresentable, Decodable {
222+
223+
public typealias RawValue = String
224+
225+
/// Indicates that the path is relative to the source root (i.e. the "project directory").
226+
case sourceRoot
227+
228+
/// Indicates that the path is relative to the path of the parent group.
229+
case group
230+
231+
/// Indicates that the path is relative to the effective build directory (which varies depending on active
232+
/// scheme, active run destination, or even an overridden build setting.
233+
case builtProductsDir
234+
235+
/// Indicates that the path is an absolute path.
236+
case absolute
237+
238+
/// Indicates that the path is relative to the SDKROOT
239+
case sdkRoot
240+
241+
/// Indicates that the path is relative to the DEVELOPER_DIR (normally in the Xcode.app bundle)
242+
case developerDir
243+
244+
case unknown
245+
246+
public var rawValue: Self.RawValue {
247+
switch self {
248+
case .sourceRoot:
249+
return "SOURCE_ROOT"
250+
case .group:
251+
return "<group>"
252+
case .builtProductsDir:
253+
return "BUILT_PRODUCTS_DIR"
254+
case .absolute:
255+
return "<absolute>"
256+
case .sdkRoot:
257+
return "SDKROOT"
258+
case .developerDir:
259+
return "DEVELOPER_DIR"
260+
case .unknown:
261+
return "<unknown>"
262+
}
263+
}
264+
265+
public init(rawValue: Self.RawValue) {
266+
switch rawValue {
267+
case "SOURCE_ROOT":
268+
self = .sourceRoot
269+
case "<group>":
270+
self = .group
271+
case "BUILT_PRODUCTS_DIR":
272+
self = .builtProductsDir
273+
case "<absolute>":
274+
self = .absolute
275+
case "SDKROOT":
276+
self = .sdkRoot
277+
case "DEVELOPER_DIR":
278+
self = .developerDir
279+
default:
280+
self = .unknown
281+
}
282+
}
283+
284+
public init(from decoder: Decoder) throws {
285+
let container = try decoder.singleValueContainer()
286+
let rawValue = try container.decode(String.self)
287+
self = SourceTree(rawValue: rawValue)
231288
}
232289
}
233290

@@ -245,6 +302,7 @@ public enum PIF {
245302
let container = try decoder.container(keyedBy: CodingKeys.self)
246303

247304
fileType = try container.decode(String.self, forKey: .fileType)
305+
logger.trace(" ---> Decoded FileType \(fileType)")
248306

249307
try super.init(from: decoder)
250308
}
@@ -295,6 +353,7 @@ public enum PIF {
295353
var childrenContainer = try container.nestedUnkeyedContainer(forKey: .children)
296354

297355
children = try untypedChildren.compactMap { child in
356+
logger.trace(" ---> Decoded Group Type \(child.type ?? "<nil>")")
298357
switch child.type {
299358
case Group.type:
300359
return try childrenContainer.decode(Group.self)
@@ -334,6 +393,7 @@ public enum PIF {
334393

335394
targetGUID = try container.decode(String.self, forKey: .guid)
336395
platformFilters = try container.decodeIfPresent([PlatformFilter].self, forKey: .platformFilters) ?? []
396+
logger.trace("---> Decoded TargetDependency: \(targetGUID)")
337397
}
338398
}
339399

@@ -393,6 +453,7 @@ public enum PIF {
393453

394454
let dependencies = try container.decode([TargetDependency].self, forKey: .dependencies)
395455
let impartedBuildProperties = try container.decodeIfPresent(BuildSettings.self, forKey: .impartedBuildProperties)
456+
logger.trace("---> Decoded BaseTarget: guid \(guid) name \(name)")
396457

397458
super.init(
398459
guid: guid,
@@ -449,6 +510,8 @@ public enum PIF {
449510
public required init(from decoder: Decoder) throws {
450511
let container = try decoder.container(keyedBy: CodingKeys.self)
451512

513+
// The swift package manager drops the length of schemaVersion from the end of the guid-string. However,
514+
// this doesn't work for all guids, because some are names and not guid strings (PackageProduct?).
452515
let guid = try container.decode(GUID.self, forKey: .guid)
453516
let name = try container.decode(String.self, forKey: .name)
454517
let buildConfigurations = try container.decode([BuildConfiguration].self, forKey: .buildConfigurations)
@@ -457,6 +520,7 @@ public enum PIF {
457520

458521
let buildPhases: [BuildPhase]
459522
let impartedBuildProperties: ImpartedBuildProperties
523+
logger.trace("---> Decoded Target: guid \(guid) name \(name)")
460524

461525
if type == "packageProduct" {
462526
self.productType = .packageProduct
@@ -493,12 +557,14 @@ public enum PIF {
493557
dependencies: dependencies,
494558
impartedBuildSettings: impartedBuildProperties.buildSettings
495559
)
560+
logger.trace(" ---> Target \(name) with guid \(guid) and product type \(productType) and product name \(productName) decoded")
496561
}
497562
}
498563

499564
/// Abstract base class for all build phases in a target.
500565
public class BuildPhase: TypedObject {
501566
static func decode(container: inout UnkeyedDecodingContainer, type: String) throws -> BuildPhase? {
567+
logger.trace("---> Decoded BuildPhase: type \(type)")
502568
switch type {
503569
case HeadersBuildPhase.type:
504570
return try container.decode(HeadersBuildPhase.self)
@@ -508,15 +574,13 @@ public enum PIF {
508574
return try container.decode(FrameworksBuildPhase.self)
509575
case ResourcesBuildPhase.type:
510576
return try container.decode(ResourcesBuildPhase.self)
577+
case CopyFilesBuildPhase.type:
578+
return try container.decode(CopyFilesBuildPhase.self)
579+
case ShellScriptBuildPhase.type:
580+
return try container.decode(ShellScriptBuildPhase.self)
511581
default:
512582
logger.debug("Ignoring build phase: \(type)")
513583
return nil
514-
// TODO: we should probably handle these:
515-
/*
516-
case copyFiles = "com.apple.buildphase.copy-files"
517-
case shellScript = "com.apple.buildphase.shell-script"
518-
case sources = "com.apple.buildphase.sources"*/
519-
// throw Error.decodingError("unknown build phase \(type)")
520584
}
521585
}
522586

@@ -532,6 +596,7 @@ public enum PIF {
532596

533597
guid = try container.decode(GUID.self, forKey: .guid)
534598
buildFiles = try container.decode([BuildFile].self, forKey: .buildFiles)
599+
logger.trace("\tBuildPhase guid \(guid)")
535600

536601
try super.init(from: decoder)
537602
}
@@ -558,6 +623,14 @@ public enum PIF {
558623
override class var type: String { "com.apple.buildphase.resources" }
559624
}
560625

626+
public final class CopyFilesBuildPhase: BuildPhase {
627+
override class var type: String { "com.apple.buildphase.copy-files" }
628+
}
629+
630+
public final class ShellScriptBuildPhase: BuildPhase {
631+
override class var type: String { "com.apple.buildphase.shell-script" }
632+
}
633+
561634
/// A build file, representing the membership of either a file or target product reference in a build phase.
562635
public struct BuildFile: Decodable {
563636
public enum Reference {
@@ -585,6 +658,7 @@ public enum PIF {
585658
guid = try container.decode(GUID.self, forKey: .guid)
586659
platformFilters = try container.decodeIfPresent([PlatformFilter].self, forKey: .platformFilters) ?? []
587660
headerVisibility = try container.decodeIfPresent(HeaderVisibility.self, forKey: .headerVisibility) ?? nil
661+
logger.trace("---> Decoded BuildFile: guid \(guid) visibility \(headerVisibility?.rawValue ?? "<nil>")")
588662

589663
if container.allKeys.contains(.fileReference) {
590664
reference = try .file(guid: container.decode(GUID.self, forKey: .fileReference))
@@ -627,6 +701,7 @@ public enum PIF {
627701
name = try container.decode(String.self, forKey: .name)
628702
buildSettings = try container.decode(BuildSettings.self, forKey: .buildSettings)
629703
impartedBuildProperties = try container.decodeIfPresent(ImpartedBuildProperties.self, forKey: .impartedBuildProperties) ?? .init(buildSettings: .init())
704+
logger.trace("---> Decoded BuildConfiguration: guid \(guid) name \(name)")
630705
}
631706
}
632707

@@ -835,65 +910,6 @@ public struct XCBuildFileType: CaseIterable {
835910
}
836911
}
837912

838-
extension PIF.FileReference {
839-
// fileprivate static func fileTypeIdentifier(forPath path: String) -> String {
840-
// let pathExtension: String?
841-
// if let path = try? URL(validating: path) {
842-
// pathExtension = path.extension
843-
// } else if let path = try? RelativePath(validating: path) {
844-
// pathExtension = path.extension
845-
// } else {
846-
// pathExtension = nil
847-
// }
848-
849-
// switch pathExtension {
850-
// case "a":
851-
// return "archive.ar"
852-
// case "s", "S":
853-
// return "sourcecode.asm"
854-
// case "c":
855-
// return "sourcecode.c.c"
856-
// case "cl":
857-
// return "sourcecode.opencl"
858-
// case "cpp", "cp", "cxx", "cc", "c++", "C", "tcc":
859-
// return "sourcecode.cpp.cpp"
860-
// case "d":
861-
// return "sourcecode.dtrace"
862-
// case "defs", "mig":
863-
// return "sourcecode.mig"
864-
// case "m":
865-
// return "sourcecode.c.objc"
866-
// case "mm", "M":
867-
// return "sourcecode.cpp.objcpp"
868-
// case "metal":
869-
// return "sourcecode.metal"
870-
// case "l", "lm", "lmm", "lpp", "lp", "lxx":
871-
// return "sourcecode.lex"
872-
// case "swift":
873-
// return "sourcecode.swift"
874-
// case "y", "ym", "ymm", "ypp", "yp", "yxx":
875-
// return "sourcecode.yacc"
876-
877-
// case "xcassets":
878-
// return "folder.assetcatalog"
879-
// case "xcstrings":
880-
// return "text.json.xcstrings"
881-
// case "storyboard":
882-
// return "file.storyboard"
883-
// case "xib":
884-
// return "file.xib"
885-
886-
// case "xcframework":
887-
// return "wrapper.xcframework"
888-
889-
// default:
890-
// return pathExtension.flatMap({ pathExtension in
891-
// XCBuildFileType.allCases.first(where: ({ $0.fileTypes.contains(pathExtension) }))
892-
// })?.fileTypeIdentifier ?? "file"
893-
// }
894-
// }
895-
}
896-
897913
private struct UntypedTarget: Decodable {
898914
struct TargetContents: Decodable {
899915
let type: String

Sources/GenIR/GenIR.swift

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ let programName = CommandLine.arguments.first!
2626
Example with build log:
2727
$ xcodebuild clean && xcodebuild build -project MyProject.xcodeproj -configuration Debug -scheme MyScheme \
2828
DEBUG_INFOMATION_FORMAT=dwarf-with-dsym ENABLE_BITCODE=NO > log.txt
29-
$ \(programName) log.txt x.xcarchive
29+
$ \(programName) log.txt x.xcarchive
3030
3131
Example with pipe:
3232
$ xcodebuild clean && xcodebuild build -project MyProject.xcodeproj -configuration Debug -scheme MyScheme \
@@ -65,10 +65,15 @@ let programName = CommandLine.arguments.first!
6565
@Option(help: ArgumentHelp("Path to PIF cache. Use this in place of what is in the Xcode build log", visibility: .hidden))
6666
var pifCachePath: URL?
6767

68+
@Option(help: ArgumentHelp("Specifiy a logging level. The --debug flag will override this", visibility: .hidden))
69+
var logLevel: LogLevelArgument?
70+
6871
mutating func validate() throws {
6972
// This will run before run() so set this here
7073
if debug {
7174
logger.logLevel = .debug
75+
} else {
76+
logger.logLevel = logLevel?.level ?? .info
7277
}
7378

7479
if projectPath != nil {
@@ -97,7 +102,8 @@ let programName = CommandLine.arguments.first!
97102
archive: xcarchivePath,
98103
level: logger.logLevel,
99104
dryRun: dryRun,
100-
dumpDependencyGraph: dumpDependencyGraph
105+
dumpDependencyGraph: dumpDependencyGraph,
106+
pifCachePath: pifCachePath
101107
)
102108
}
103109

@@ -238,3 +244,15 @@ extension URL: ExpressibleByArgument {
238244
self = argument.fileURL.absoluteURL
239245
}
240246
}
247+
248+
struct LogLevelArgument: ExpressibleByArgument {
249+
let level: Logger.Level
250+
251+
init?(argument: String) {
252+
// Convert the argument to lowercase and attempt to create a Logger.Level
253+
guard let logLevel = Logger.Level(rawValue: argument.lowercased()) else {
254+
return nil // Return nil if the argument is invalid
255+
}
256+
self.level = logLevel
257+
}
258+
}

Sources/GenIR/OutputPostprocessor.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ class OutputPostprocessor {
6969
// folder. Otherwise we will create an empty directory and that will contain the artifacts
7070
// of the dependency chain.
7171
if manager.directoryExists(at: buildDirectory) {
72-
logger.debug("Copying \(node.value.guid) with name \(node.value.productName)")
72+
logger.debug("Copying \(node.value.guid) with name \(node.value.productName)")
7373
try manager.copyItem(at: buildDirectory, to: irDirectory)
7474
} else {
75-
logger.debug("Creating build directory for \(node.value.guid) with name \(node.value.productName)")
75+
logger.debug("Creating build directory for \(node.value.guid) with name \(node.value.productName)")
7676
try manager.createDirectory(at: irDirectory, withIntermediateDirectories: false)
7777
}
7878

0 commit comments

Comments
 (0)