Skip to content

Commit 66c012b

Browse files
committed
Convert tabs to spaces to match project
1 parent d161a5e commit 66c012b

1 file changed

Lines changed: 160 additions & 160 deletions

File tree

Sources/XcodesKit/RuntimeInstaller.swift

Lines changed: 160 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -102,19 +102,19 @@ public class RuntimeInstaller {
102102
public func downloadAndInstallRuntime(identifier: String, to destinationDirectory: Path, with downloader: Downloader, shouldDelete: Bool) async throws {
103103
let matchedRuntime = try await getMatchingRuntime(identifier: identifier)
104104

105-
switch matchedRuntime.contentType {
106-
case .package:
107-
guard Current.shell.isRoot() else {
108-
throw Error.rootNeeded
109-
}
110-
let dmgUrl = try await downloadOrUseExistingArchive(runtime: matchedRuntime, to: destinationDirectory, downloader: downloader)
111-
try await installFromPackage(dmgUrl: dmgUrl, runtime: matchedRuntime)
112-
case .diskImage:
113-
let dmgUrl = try await downloadOrUseExistingArchive(runtime: matchedRuntime, to: destinationDirectory, downloader: downloader)
114-
try await installFromImage(dmgUrl: dmgUrl)
115-
case .cryptexDiskImage:
116-
try await downloadAndInstallUsingXcodeBuild(runtime: matchedRuntime)
117-
}
105+
switch matchedRuntime.contentType {
106+
case .package:
107+
guard Current.shell.isRoot() else {
108+
throw Error.rootNeeded
109+
}
110+
let dmgUrl = try await downloadOrUseExistingArchive(runtime: matchedRuntime, to: destinationDirectory, downloader: downloader)
111+
try await installFromPackage(dmgUrl: dmgUrl, runtime: matchedRuntime)
112+
case .diskImage:
113+
let dmgUrl = try await downloadOrUseExistingArchive(runtime: matchedRuntime, to: destinationDirectory, downloader: downloader)
114+
try await installFromImage(dmgUrl: dmgUrl)
115+
case .cryptexDiskImage:
116+
try await downloadAndInstallUsingXcodeBuild(runtime: matchedRuntime)
117+
}
118118
}
119119

120120
private func getMatchingRuntime(identifier: String) async throws -> DownloadableRuntime {
@@ -221,119 +221,119 @@ public class RuntimeInstaller {
221221
return result
222222
}
223223

224-
// MARK: Xcode 16.1 Runtime installation helpers
225-
/// Downloads and installs the runtime using xcodebuild, requires Xcode 16.1+ to download a runtime using a given directory
226-
/// - Parameters:
227-
/// - runtime: The runtime to download and install to identify the platform and version numbers
228-
private func downloadAndInstallUsingXcodeBuild(runtime: DownloadableRuntime) async throws {
229-
230-
// Make sure that we are using a version of xcode that supports this
231-
try await ensureSelectedXcodeVersionForDownload()
232-
233-
// Kick off the download/install process and get an async stream of the progress
234-
let downloadStream = createXcodebuildDownloadStream(runtime: runtime)
235-
236-
// Observe the progress and update the console from it
237-
for try await progress in downloadStream {
238-
let formatter = NumberFormatter(numberStyle: .percent)
239-
guard Current.shell.isatty() else { return }
240-
// These escape codes move up a line and then clear to the end
241-
Current.logging.log("\u{1B}[1A\u{1B}[KDownloading Runtime \(runtime.visibleIdentifier): \(formatter.string(from: progress.fractionCompleted)!)")
242-
}
243-
}
244-
245-
private func ensureSelectedXcodeVersionForDownload() async throws {
246-
let xcodeBuildPath = Path.root.usr.bin.join("xcodebuild")
247-
let versionString = try await Process.run(xcodeBuildPath, "-version").async()
248-
let versionPattern = #"Xcode (\d+\.\d+)"#
249-
let versionRegex = try NSRegularExpression(pattern: versionPattern)
250-
251-
// parse out the version string (e.g. 16.1) from the xcodebuild version command and convert it to a `Version`
252-
guard let match = versionRegex.firstMatch(in: versionString.out, range: NSRange(versionString.out.startIndex..., in: versionString.out)),
253-
let versionRange = Range(match.range(at: 1), in: versionString.out),
254-
let version = Version(tolerant: String(versionString.out[versionRange])) else {
255-
throw Error.noXcodeSelectedFound
256-
}
257-
258-
guard version >= Version(16, 1, 0) else {
259-
throw Error.xcode16_1OrGreaterRequired(version)
260-
}
261-
262-
// If we made it here, we're gucci and 16.1 or greater is selected
263-
}
264-
265-
private func createXcodebuildDownloadStream(runtime: DownloadableRuntime) -> AsyncThrowingStream<Progress, Swift.Error> {
266-
let platform = runtime.platform.shortName
267-
let version = runtime.simulatorVersion.buildUpdate
268-
269-
return AsyncThrowingStream<Progress, Swift.Error> { continuation in
270-
Task {
271-
// Assume progress will not have data races, so we manually opt-out isolation checks.
272-
let progress = Progress()
273-
progress.kind = .file
274-
progress.fileOperationKind = .downloading
275-
276-
let process = Process()
277-
let xcodeBuildPath = Path.root.usr.bin.join("xcodebuild").url
278-
279-
process.executableURL = xcodeBuildPath
280-
process.arguments = [
281-
"-downloadPlatform",
282-
"\(platform)",
283-
"-buildVersion",
284-
"\(version)"
285-
]
286-
287-
let stdOutPipe = Pipe()
288-
process.standardOutput = stdOutPipe
289-
let stdErrPipe = Pipe()
290-
process.standardError = stdErrPipe
291-
292-
let observer = NotificationCenter.default.addObserver(
293-
forName: .NSFileHandleDataAvailable,
294-
object: nil,
295-
queue: OperationQueue.main
296-
) { note in
297-
guard
298-
// This should always be the case for Notification.Name.NSFileHandleDataAvailable
299-
let handle = note.object as? FileHandle,
300-
handle === stdOutPipe.fileHandleForReading || handle === stdErrPipe.fileHandleForReading
301-
else { return }
302-
303-
defer { handle.waitForDataInBackgroundAndNotify() }
304-
305-
let string = String(decoding: handle.availableData, as: UTF8.self)
306-
progress.updateFromXcodebuild(text: string)
307-
continuation.yield(progress)
308-
}
309-
310-
stdOutPipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
311-
stdErrPipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
312-
313-
continuation.onTermination = { @Sendable _ in
314-
process.terminate()
315-
NotificationCenter.default.removeObserver(observer, name: .NSFileHandleDataAvailable, object: nil)
316-
}
317-
318-
do {
319-
try process.run()
320-
} catch {
321-
continuation.finish(throwing: error)
322-
}
323-
324-
process.waitUntilExit()
325-
326-
NotificationCenter.default.removeObserver(observer, name: .NSFileHandleDataAvailable, object: nil)
327-
328-
guard process.terminationReason == .exit, process.terminationStatus == 0 else {
329-
struct ProcessExecutionError: Swift.Error {}
330-
continuation.finish(throwing: ProcessExecutionError())
331-
return
332-
}
333-
continuation.finish()
334-
}
335-
}
336-
}
224+
// MARK: Xcode 16.1 Runtime installation helpers
225+
/// Downloads and installs the runtime using xcodebuild, requires Xcode 16.1+ to download a runtime using a given directory
226+
/// - Parameters:
227+
/// - runtime: The runtime to download and install to identify the platform and version numbers
228+
private func downloadAndInstallUsingXcodeBuild(runtime: DownloadableRuntime) async throws {
229+
230+
// Make sure that we are using a version of xcode that supports this
231+
try await ensureSelectedXcodeVersionForDownload()
232+
233+
// Kick off the download/install process and get an async stream of the progress
234+
let downloadStream = createXcodebuildDownloadStream(runtime: runtime)
235+
236+
// Observe the progress and update the console from it
237+
for try await progress in downloadStream {
238+
let formatter = NumberFormatter(numberStyle: .percent)
239+
guard Current.shell.isatty() else { return }
240+
// These escape codes move up a line and then clear to the end
241+
Current.logging.log("\u{1B}[1A\u{1B}[KDownloading Runtime \(runtime.visibleIdentifier): \(formatter.string(from: progress.fractionCompleted)!)")
242+
}
243+
}
244+
245+
private func ensureSelectedXcodeVersionForDownload() async throws {
246+
let xcodeBuildPath = Path.root.usr.bin.join("xcodebuild")
247+
let versionString = try await Process.run(xcodeBuildPath, "-version").async()
248+
let versionPattern = #"Xcode (\d+\.\d+)"#
249+
let versionRegex = try NSRegularExpression(pattern: versionPattern)
250+
251+
// parse out the version string (e.g. 16.1) from the xcodebuild version command and convert it to a `Version`
252+
guard let match = versionRegex.firstMatch(in: versionString.out, range: NSRange(versionString.out.startIndex..., in: versionString.out)),
253+
let versionRange = Range(match.range(at: 1), in: versionString.out),
254+
let version = Version(tolerant: String(versionString.out[versionRange])) else {
255+
throw Error.noXcodeSelectedFound
256+
}
257+
258+
guard version >= Version(16, 1, 0) else {
259+
throw Error.xcode16_1OrGreaterRequired(version)
260+
}
261+
262+
// If we made it here, we're gucci and 16.1 or greater is selected
263+
}
264+
265+
private func createXcodebuildDownloadStream(runtime: DownloadableRuntime) -> AsyncThrowingStream<Progress, Swift.Error> {
266+
let platform = runtime.platform.shortName
267+
let version = runtime.simulatorVersion.buildUpdate
268+
269+
return AsyncThrowingStream<Progress, Swift.Error> { continuation in
270+
Task {
271+
// Assume progress will not have data races, so we manually opt-out isolation checks.
272+
let progress = Progress()
273+
progress.kind = .file
274+
progress.fileOperationKind = .downloading
275+
276+
let process = Process()
277+
let xcodeBuildPath = Path.root.usr.bin.join("xcodebuild").url
278+
279+
process.executableURL = xcodeBuildPath
280+
process.arguments = [
281+
"-downloadPlatform",
282+
"\(platform)",
283+
"-buildVersion",
284+
"\(version)"
285+
]
286+
287+
let stdOutPipe = Pipe()
288+
process.standardOutput = stdOutPipe
289+
let stdErrPipe = Pipe()
290+
process.standardError = stdErrPipe
291+
292+
let observer = NotificationCenter.default.addObserver(
293+
forName: .NSFileHandleDataAvailable,
294+
object: nil,
295+
queue: OperationQueue.main
296+
) { note in
297+
guard
298+
// This should always be the case for Notification.Name.NSFileHandleDataAvailable
299+
let handle = note.object as? FileHandle,
300+
handle === stdOutPipe.fileHandleForReading || handle === stdErrPipe.fileHandleForReading
301+
else { return }
302+
303+
defer { handle.waitForDataInBackgroundAndNotify() }
304+
305+
let string = String(decoding: handle.availableData, as: UTF8.self)
306+
progress.updateFromXcodebuild(text: string)
307+
continuation.yield(progress)
308+
}
309+
310+
stdOutPipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
311+
stdErrPipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
312+
313+
continuation.onTermination = { @Sendable _ in
314+
process.terminate()
315+
NotificationCenter.default.removeObserver(observer, name: .NSFileHandleDataAvailable, object: nil)
316+
}
317+
318+
do {
319+
try process.run()
320+
} catch {
321+
continuation.finish(throwing: error)
322+
}
323+
324+
process.waitUntilExit()
325+
326+
NotificationCenter.default.removeObserver(observer, name: .NSFileHandleDataAvailable, object: nil)
327+
328+
guard process.terminationReason == .exit, process.terminationStatus == 0 else {
329+
struct ProcessExecutionError: Swift.Error {}
330+
continuation.finish(throwing: ProcessExecutionError())
331+
return
332+
}
333+
continuation.finish()
334+
}
335+
}
336+
}
337337
}
338338

339339
extension RuntimeInstaller {
@@ -342,8 +342,8 @@ extension RuntimeInstaller {
342342
case failedMountingDMG
343343
case rootNeeded
344344
case missingRuntimeSource(String)
345-
case xcode16_1OrGreaterRequired(Version)
346-
case noXcodeSelectedFound
345+
case xcode16_1OrGreaterRequired(Version)
346+
case noXcodeSelectedFound
347347

348348
public var errorDescription: String? {
349349
switch self {
@@ -410,36 +410,36 @@ extension Array {
410410

411411

412412
private extension Progress {
413-
func updateFromXcodebuild(text: String) {
414-
self.totalUnitCount = 100
415-
self.completedUnitCount = 0
416-
self.localizedAdditionalDescription = "" // to not show the addtional
417-
418-
do {
419-
420-
let downloadPattern = #"(\d+\.\d+)% \(([\d.]+ (?:MB|GB)) of ([\d.]+ GB)\)"#
421-
let downloadRegex = try NSRegularExpression(pattern: downloadPattern)
422-
423-
// Search for matches in the text
424-
if let match = downloadRegex.firstMatch(in: text, range: NSRange(text.startIndex..., in: text)) {
425-
// Extract the percentage - simpler then trying to extract size MB/GB and convert to bytes.
426-
if let percentRange = Range(match.range(at: 1), in: text), let percentDouble = Double(text[percentRange]) {
427-
let percent = Int64(percentDouble.rounded())
428-
self.completedUnitCount = percent
429-
}
430-
}
431-
432-
// "Downloading tvOS 18.1 Simulator (22J5567a): Installing..." or
433-
// "Downloading tvOS 18.1 Simulator (22J5567a): Installing (registering download)..."
434-
if text.range(of: "Installing") != nil {
435-
// sets the progress to indeterminite to show animating progress
436-
self.totalUnitCount = 0
437-
self.completedUnitCount = 0
438-
}
439-
440-
} catch {
441-
print("Invalid regular expression")
442-
}
443-
444-
}
413+
func updateFromXcodebuild(text: String) {
414+
self.totalUnitCount = 100
415+
self.completedUnitCount = 0
416+
self.localizedAdditionalDescription = "" // to not show the addtional
417+
418+
do {
419+
420+
let downloadPattern = #"(\d+\.\d+)% \(([\d.]+ (?:MB|GB)) of ([\d.]+ GB)\)"#
421+
let downloadRegex = try NSRegularExpression(pattern: downloadPattern)
422+
423+
// Search for matches in the text
424+
if let match = downloadRegex.firstMatch(in: text, range: NSRange(text.startIndex..., in: text)) {
425+
// Extract the percentage - simpler then trying to extract size MB/GB and convert to bytes.
426+
if let percentRange = Range(match.range(at: 1), in: text), let percentDouble = Double(text[percentRange]) {
427+
let percent = Int64(percentDouble.rounded())
428+
self.completedUnitCount = percent
429+
}
430+
}
431+
432+
// "Downloading tvOS 18.1 Simulator (22J5567a): Installing..." or
433+
// "Downloading tvOS 18.1 Simulator (22J5567a): Installing (registering download)..."
434+
if text.range(of: "Installing") != nil {
435+
// sets the progress to indeterminite to show animating progress
436+
self.totalUnitCount = 0
437+
self.completedUnitCount = 0
438+
}
439+
440+
} catch {
441+
print("Invalid regular expression")
442+
}
443+
444+
}
445445
}

0 commit comments

Comments
 (0)