mirror of
https://github.com/XcodesOrg/XcodesApp.git
synced 2026-03-25 08:55:46 +00:00
refactor: replace Process-based unxip with libunxip async API
This commit is contained in:
parent
7f66abf0e8
commit
b1a367809d
2 changed files with 51 additions and 6 deletions
|
|
@ -293,9 +293,10 @@ extension AppState {
|
|||
|
||||
func unxipOrUnxipExperiment(_ source: URL) -> AnyPublisher<ProcessOutput, Error> {
|
||||
if unxipExperiment {
|
||||
// All hard work done by https://github.com/saagarjha/unxip
|
||||
// Compiled to binary with `swiftc -parse-as-library -O unxip.swift`
|
||||
return Current.shell.unxipExperiment(source)
|
||||
// Native libunxip integration - no subprocess needed
|
||||
// https://github.com/saagarjha/unxip
|
||||
let destination = source.deletingLastPathComponent()
|
||||
return Current.shell.unxipNative(source, destination)
|
||||
} else {
|
||||
return Current.shell.unxip(source)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import Path
|
|||
import AppleAPI
|
||||
import KeychainAccess
|
||||
import XcodesKit
|
||||
import libunxip
|
||||
/**
|
||||
Lightweight dependency injection using global mutable state :P
|
||||
|
||||
|
|
@ -191,9 +192,52 @@ public struct Shell {
|
|||
}
|
||||
|
||||
|
||||
public var unxipExperiment: (URL) -> AnyPublisher<ProcessOutput, Error> = { url in
|
||||
let unxipPath = Path(url: Bundle.main.url(forAuxiliaryExecutable: "unxip")!)!
|
||||
return Process.run(unxipPath.url, workingDirectory: url.deletingLastPathComponent(), ["\(url.path)"])
|
||||
/// Extracts a .xip archive using libunxip natively (no subprocess).
|
||||
/// The source URL is the .xip file path; the destination URL is the output directory.
|
||||
public var unxipNative: (URL, URL) -> AnyPublisher<ProcessOutput, Error> = { source, destination in
|
||||
Future<ProcessOutput, Error> { promise in
|
||||
Task {
|
||||
do {
|
||||
let handle = try FileHandle(forReadingFrom: source)
|
||||
defer { try? handle.close() }
|
||||
|
||||
// Open the output directory as a file descriptor for libunxip
|
||||
let outputFd = open(destination.path, O_RDONLY | O_DIRECTORY)
|
||||
guard outputFd >= 0 else {
|
||||
throw NSError(
|
||||
domain: NSPOSIXErrorDomain,
|
||||
code: Int(errno),
|
||||
userInfo: [NSLocalizedDescriptionKey: "Failed to open output directory: \(destination.path)"]
|
||||
)
|
||||
}
|
||||
defer { close(outputFd) }
|
||||
|
||||
let data = DataReader(descriptor: handle.fileDescriptor)
|
||||
let filesOptions = libunxip.Files.Options(
|
||||
compress: true,
|
||||
dryRun: false,
|
||||
output: outputFd
|
||||
)
|
||||
|
||||
// Run the full XIP -> Chunks -> Files -> Disk pipeline
|
||||
for try await _ in Unxip.makeStream(
|
||||
from: .xip(),
|
||||
to: .disk(),
|
||||
input: data,
|
||||
nil,
|
||||
nil,
|
||||
filesOptions
|
||||
) {
|
||||
// Each yielded File has been written to disk
|
||||
}
|
||||
|
||||
promise(.success((0, "", "")))
|
||||
} catch {
|
||||
promise(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
public var downloadRuntime: (String, String, String?) -> AsyncThrowingStream<Progress, Error> = { platform, version, architecture in
|
||||
|
|
|
|||
Loading…
Reference in a new issue