Skip to content

Commit 8950b13

Browse files
pblazejclaude
andcommitted
refactor: clean up xcframework script
- Introduce PackageManifest struct to read Package.swift once - Merge duplicate switch cases for .swift/.m file extensions - Remove unused repoRoot parameter from addSources - Simplify archive failure counting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 91701a2 commit 8950b13

1 file changed

Lines changed: 52 additions & 53 deletions

File tree

scripts/xcframework.swift

Lines changed: 52 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -86,47 +86,51 @@ private let depLineRegex = #/url:\s*"(?<url>https://[^"]+)".*exact:\s*"(?<versio
8686
// Regex: checksum: "abc123..."
8787
private let checksumRegex = #/checksum:\s*"(?<hash>[0-9a-f]{64})"/#
8888

89-
/// Parse binary dependency URL + version from our Package.swift, then read checksum
90-
/// from the upstream Package.swift in the local SPM checkout.
91-
func parseBinaryDep(repoRoot: Path, spmDir: Path, pattern: String, xcfw: String) throws -> BinaryDep {
92-
let contents: String = try (repoRoot + "Package.swift").read()
93-
guard let line = contents.components(separatedBy: .newlines)
94-
.first(where: { $0.contains("github") && $0.contains(pattern) }),
95-
let match = line.firstMatch(of: depLineRegex)
96-
else {
97-
throw ValidationError("\(pattern) not found in Package.swift")
98-
}
99-
100-
let repo = String(match.url).replacingOccurrences(of: ".git", with: "")
101-
let ver = String(match.version)
102-
let zipURL = "\(repo)/releases/download/\(ver)/\(xcfw).xcframework.zip"
89+
/// Reads and caches the main Package.swift contents.
90+
struct PackageManifest {
91+
let lines: [String]
10392

104-
// Read checksum from local SPM checkout
105-
let repoName = repo.components(separatedBy: "/").last ?? pattern
106-
let checkoutPkg = spmDir + "checkouts" + repoName + "Package.swift"
107-
guard checkoutPkg.exists else {
108-
throw ValidationError("Upstream Package.swift not found at \(checkoutPkg). Run SPM resolve first.")
93+
init(repoRoot: Path) throws {
94+
let contents: String = try (repoRoot + "Package.swift").read()
95+
lines = contents.components(separatedBy: .newlines)
10996
}
110-
let upstreamContents: String = try checkoutPkg.read()
111-
guard let csMatch = upstreamContents.firstMatch(of: checksumRegex) else {
112-
throw ValidationError("Could not find checksum in \(checkoutPkg)")
97+
98+
/// Extract a full dependency line matching the given pattern.
99+
func dependencyLine(containing pattern: String) throws -> String {
100+
guard let line = lines.first(where: { $0.contains(pattern) && $0.contains(".package") })
101+
else { throw ValidationError("\(pattern) dependency not found in Package.swift") }
102+
return line
113103
}
114-
return BinaryDep(url: zipURL, checksum: String(csMatch.hash))
115-
}
116104

117-
func protobufDependencyLine(repoRoot: Path) throws -> String {
118-
let contents: String = try (repoRoot + "Package.swift").read()
119-
guard let line = contents.components(separatedBy: .newlines).first(where: { $0.contains("swift-protobuf") && $0.contains(".package") })
120-
else { throw ValidationError("swift-protobuf dependency not found in Package.swift") }
121-
return line
105+
/// Parse binary dependency URL + version, then read checksum from the local SPM checkout.
106+
func binaryDep(spmDir: Path, pattern: String, xcfw: String) throws -> BinaryDep {
107+
guard let line = lines.first(where: { $0.contains("github") && $0.contains(pattern) }),
108+
let match = line.firstMatch(of: depLineRegex)
109+
else { throw ValidationError("\(pattern) not found in Package.swift") }
110+
111+
let repo = String(match.url).replacingOccurrences(of: ".git", with: "")
112+
let ver = String(match.version)
113+
let zipURL = "\(repo)/releases/download/\(ver)/\(xcfw).xcframework.zip"
114+
115+
let repoName = repo.components(separatedBy: "/").last ?? pattern
116+
let checkoutPkg = spmDir + "checkouts" + repoName + "Package.swift"
117+
guard checkoutPkg.exists else {
118+
throw ValidationError("Upstream Package.swift not found at \(checkoutPkg). Run SPM resolve first.")
119+
}
120+
let upstreamContents: String = try checkoutPkg.read()
121+
guard let csMatch = upstreamContents.firstMatch(of: checksumRegex) else {
122+
throw ValidationError("Could not find checksum in \(checkoutPkg)")
123+
}
124+
return BinaryDep(url: zipURL, checksum: String(csMatch.hash))
125+
}
122126
}
123127

124128
// MARK: - Xcode project generation
125129

126130
/// Recursively add source files from a directory to an Xcode group and build phase.
127131
func addSources(
128132
dir: Path, group: PBXGroup, sourcesBP: PBXSourcesBuildPhase, resourcesBP: PBXResourcesBuildPhase,
129-
pbxProj: PBXProj, repoRoot: Path, excludes: [String] = []
133+
pbxProj: PBXProj, excludes: [String] = []
130134
) throws {
131135
for child in try dir.children().sorted(by: { $0.string < $1.string }) {
132136
let name = child.lastComponent
@@ -136,28 +140,23 @@ func addSources(
136140
let subgroup = PBXGroup(sourceTree: .group, name: name, path: name)
137141
pbxProj.add(object: subgroup)
138142
group.children.append(subgroup)
139-
try addSources(dir: child, group: subgroup, sourcesBP: sourcesBP, resourcesBP: resourcesBP, pbxProj: pbxProj, repoRoot: repoRoot)
143+
try addSources(dir: child, group: subgroup, sourcesBP: sourcesBP, resourcesBP: resourcesBP, pbxProj: pbxProj)
140144
} else {
141145
let ext = child.extension ?? ""
142146
let fileRef = PBXFileReference(sourceTree: .absolute, name: name, path: child.string)
143147
pbxProj.add(object: fileRef)
144148
group.children.append(fileRef)
145149

150+
let bf = PBXBuildFile(file: fileRef)
146151
switch ext {
147-
case "swift":
148-
let bf = PBXBuildFile(file: fileRef)
149-
pbxProj.add(object: bf)
150-
sourcesBP.files?.append(bf)
151-
case "m":
152-
let bf = PBXBuildFile(file: fileRef)
152+
case "swift", "m":
153153
pbxProj.add(object: bf)
154154
sourcesBP.files?.append(bf)
155155
case "xcprivacy":
156-
let bf = PBXBuildFile(file: fileRef)
157156
pbxProj.add(object: bf)
158157
resourcesBP.files?.append(bf)
159158
default:
160-
break // headers and other files are added to group but not to build phases
159+
break
161160
}
162161
}
163162
}
@@ -292,7 +291,7 @@ func generateFrameworkProject(at projectPath: Path, repoRoot: Path) throws {
292291
mainGroup.children.append(liveKitGroup)
293292
try addSources(
294293
dir: repoRoot + "Sources" + "LiveKit", group: liveKitGroup,
295-
sourcesBP: sourcesBP, resourcesBP: resourcesBP, pbxProj: pbxProj, repoRoot: repoRoot,
294+
sourcesBP: sourcesBP, resourcesBP: resourcesBP, pbxProj: pbxProj,
296295
excludes: ["NOTICE"]
297296
)
298297

@@ -302,7 +301,7 @@ func generateFrameworkProject(at projectPath: Path, repoRoot: Path) throws {
302301
mainGroup.children.append(objcGroup)
303302
try addSources(
304303
dir: repoRoot + "Sources" + "LKObjCHelpers", group: objcGroup,
305-
sourcesBP: sourcesBP, resourcesBP: resourcesBP, pbxProj: pbxProj, repoRoot: repoRoot
304+
sourcesBP: sourcesBP, resourcesBP: resourcesBP, pbxProj: pbxProj
306305
)
307306

308307
// Make ObjC headers public in the headers build phase
@@ -387,8 +386,9 @@ struct BuildXCFramework: AsyncParsableCommand {
387386

388387
// --- Parse binary dependency info from local checkouts ---
389388
step("Reading binary dependency info...")
390-
let webrtcDep = try parseBinaryDep(repoRoot: repoRoot, spmDir: spmDir, pattern: "webrtc-xcframework", xcfw: "LiveKitWebRTC")
391-
let uniffiDep = try parseBinaryDep(repoRoot: repoRoot, spmDir: spmDir, pattern: "uniffi-xcframework", xcfw: "RustLiveKitUniFFI")
389+
let manifest = try PackageManifest(repoRoot: repoRoot)
390+
let webrtcDep = try manifest.binaryDep(spmDir: spmDir, pattern: "webrtc-xcframework", xcfw: "LiveKitWebRTC")
391+
let uniffiDep = try manifest.binaryDep(spmDir: spmDir, pattern: "uniffi-xcframework", xcfw: "RustLiveKitUniFFI")
392392
print(" LiveKitWebRTC: \(webrtcDep.url)")
393393
print(" RustLiveKitUniFFI: \(uniffiDep.url)")
394394

@@ -428,13 +428,10 @@ struct BuildXCFramework: AsyncParsableCommand {
428428
return results.sorted { $0.0.archiveName < $1.0.archiveName }
429429
}
430430

431-
let archives = archiveResults.compactMap { p, r -> (Platform, Path)? in
432-
if case let .success(path) = r { return (p, path) }
433-
return nil
434-
}
435-
let failed = archiveResults.filter { if case .failure = $0.1 { return true }; return false }
436-
if !failed.isEmpty {
437-
print(" \(failed.count) platform(s) failed, \(archives.count) succeeded.".yellow)
431+
let archives = archiveResults.compactMap { p, r -> (Platform, Path)? in try? (p, r.get()) }
432+
let failedCount = archiveResults.count - archives.count
433+
if failedCount > 0 {
434+
print(" \(failedCount) platform(s) failed, \(archives.count) succeeded.".yellow)
438435
}
439436
guard !archives.isEmpty else {
440437
throw ValidationError("All platform archives failed.")
@@ -463,7 +460,8 @@ struct BuildXCFramework: AsyncParsableCommand {
463460
step("Generating Package.swift...")
464461
try generatePackageSwift(
465462
outputDir: outputDir, liveKitChecksum: liveKitChecksum,
466-
webrtcDep: webrtcDep, uniffiDep: uniffiDep, repoRoot: repoRoot
463+
webrtcDep: webrtcDep, uniffiDep: uniffiDep,
464+
manifest: manifest, repoRoot: repoRoot
467465
)
468466
print(" Written to \(outputDir)/Package.swift (local=\(local))")
469467

@@ -484,7 +482,8 @@ struct BuildXCFramework: AsyncParsableCommand {
484482

485483
func generatePackageSwift(
486484
outputDir: Path, liveKitChecksum: String,
487-
webrtcDep: BinaryDep, uniffiDep: BinaryDep, repoRoot: Path
485+
webrtcDep: BinaryDep, uniffiDep: BinaryDep,
486+
manifest: PackageManifest, repoRoot: Path
488487
) throws {
489488
let tmpl: String = try (repoRoot + "scripts" + "Package.swift.stencil").read()
490489
let baseURL = version.map {
@@ -500,7 +499,7 @@ struct BuildXCFramework: AsyncParsableCommand {
500499
"webrtcChecksum": webrtcDep.checksum,
501500
"uniffiURL": uniffiDep.url,
502501
"uniffiChecksum": uniffiDep.checksum,
503-
"protobufDependency": protobufDependencyLine(repoRoot: repoRoot),
502+
"protobufDependency": manifest.dependencyLine(containing: "swift-protobuf"),
504503
])
505504
try (outputDir + "Package.swift").write(rendered)
506505

0 commit comments

Comments
 (0)