@@ -47,7 +47,12 @@ extension AppState {
4747
4848 func downloadRuntime( runtime: DownloadableRuntime ) {
4949 Task {
50- try ? await downloadRunTimeFull ( runtime: runtime)
50+ do {
51+ try await downloadRunTimeFull ( runtime: runtime)
52+ }
53+ catch {
54+ Logger . appState. error ( " Error downloading runtime: \( error. localizedDescription) " )
55+ }
5156 }
5257
5358// self.runtimePublishers[runtime.identifier] = downloadRunTimeFull(runtime: runtime)
@@ -78,33 +83,20 @@ extension AppState {
7883 let downloader = Downloader ( rawValue: UserDefaults . standard. string ( forKey: " downloader " ) ?? " aria2 " ) ?? . aria2
7984 Logger . appState. info ( " Downloading \( runtime. visibleIdentifier) with \( downloader) " )
8085
81-
82- return validateADCSession ( path: runtime. downloadPath)
83- . flatMap { _ in
84- // we shouldn't have to be authenticated to download runtimes
85- let downloader = Downloader ( rawValue: UserDefaults . standard. string ( forKey: " downloader " ) ?? " aria2 " ) ?? . aria2
86- Logger . appState. info ( " Downloading \( runtime. visibleIdentifier) with \( downloader) " )
87-
88- return self . downloadRuntime ( for: runtime, downloader: downloader, progressChanged: { [ unowned self] progress in
89- DispatchQueue . main. async {
90- self . setInstallationStep ( of: runtime, to: . downloading( progress: progress) )
91- }
92- } )
93- . map { return ( runtime, $0) }
86+ let url = try await self . downloadRuntime ( for: runtime, downloader: downloader, progressChanged: { [ unowned self] progress in
87+ DispatchQueue . main. async {
88+ self . setInstallationStep ( of: runtime, to: . downloading( progress: progress) )
9489 }
95- . flatMap { runtime, url -> AnyPublisher < URL , Error > in
96- switch runtime. contentType {
97- case . package :
98- return self . installFromPackage ( dmgURL: url, runtime: runtime)
99- case . diskImage:
100- return self . installFromImage ( dmgURL: url)
101- }
102- }
103- . map { url in
104- // Done deleting
105- Logger . appState. debug ( " URL: \( url) " )
106- }
107- . eraseToAnyPublisher ( )
90+ } ) . async ( )
91+
92+ Logger . appState. debug ( " Done downloading: \( url) " )
93+ //self.setInstallationStep(of: runtime, to: .downloading(progress: progress))
94+ switch runtime. contentType {
95+ case . package :
96+ try await self . installFromPackage ( dmgURL: url, runtime: runtime)
97+ case . diskImage:
98+ try await self . installFromImage ( dmgURL: url)
99+ }
108100 }
109101
110102 func downloadRuntime( for runtime: DownloadableRuntime , downloader: Downloader , progressChanged: @escaping ( Progress ) -> Void ) -> AnyPublisher < URL , Error > {
@@ -142,7 +134,7 @@ extension AppState {
142134 progressChanged: progressChanged)
143135
144136 case . urlSession:
145-
137+ // TODO: Support runtime download via URL Session
146138 return Just ( runtime. url)
147139 . setFailureType ( to: Error . self)
148140 . eraseToAnyPublisher ( )
@@ -171,53 +163,56 @@ extension AppState {
171163 . eraseToAnyPublisher ( )
172164 }
173165
174- public func downloadRuntimeWithAria2( _ runtime: DownloadableRuntime , to destination: Path , aria2Path: Path , progressChanged: @escaping ( Progress ) -> Void ) async -> URL {
175-
176- }
177166
178- public func installFromImage( dmgURL: URL ) -> AnyPublisher < URL , Error > {
167+ public func installFromImage( dmgURL: URL ) async throws {
179168
180-
181- try ? self . runtimeService. installRuntimeImage ( dmgURL: dmgURL)
182-
183-
184- return Just ( dmgURL)
185- . setFailureType ( to: Error . self)
186- . eraseToAnyPublisher ( )
169+ try ? self . runtimeService. installRuntimeImage ( dmgURL: dmgURL)
187170
188171 }
189172
190- public func installFromPackage( dmgURL: URL , runtime: DownloadableRuntime ) -> AnyPublisher < URL , Error > {
173+ public func installFromPackage( dmgURL: URL , runtime: DownloadableRuntime ) async throws {
191174 Logger . appState. info ( " Mounting DMG " )
192- Task {
193- do {
194- let mountedUrl = try await self . runtimeService. mountDMG ( dmgUrl: dmgURL)
195-
196- // 2-Get the first path under the mounted path, should be a .pkg
197- let pkgPath = Path ( url: mountedUrl) !. ls ( ) . first!
198- try Path . xcodesCaches. mkdir ( ) . setCurrentUserAsOwner ( )
199-
200- let expandedPkgPath = Path . xcodesCaches/ runtime. identifier
201- //try expandedPkgPath.mkdir()
202- Logger . appState. info ( " PKG Path: \( pkgPath) " )
203- Logger . appState. info ( " Expanded PKG Path: \( expandedPkgPath) " )
204- //try? Current.files.removeItem(at: expandedPkgPath.url)
205-
206- // 5-Expand (not install) the pkg to temporary path
207- try await self . runtimeService. expand ( pkgPath: pkgPath, expandedPkgPath: expandedPkgPath)
208- //try await self.runtimeService.unmountDMG(mountedURL: mountedUrl)
209-
210- } catch {
211- Logger . appState. error ( " Error installing runtime: \( error. localizedDescription) " )
212- }
175+
176+ do {
177+ let mountedUrl = try await self . runtimeService. mountDMG ( dmgUrl: dmgURL)
213178
179+ // 2-Get the first path under the mounted path, should be a .pkg
180+ let pkgPath = Path ( url: mountedUrl) !. ls ( ) . first!
181+ try Path . xcodesCaches. mkdir ( ) . setCurrentUserAsOwner ( )
182+
183+ let expandedPkgPath = Path . xcodesCaches/ runtime. identifier
184+ //try expandedPkgPath.mkdir()
185+ Logger . appState. info ( " PKG Path: \( pkgPath) " )
186+ Logger . appState. info ( " Expanded PKG Path: \( expandedPkgPath) " )
187+ //try? Current.files.removeItem(at: expandedPkgPath.url)
188+
189+ // 5-Expand (not install) the pkg to temporary path
190+ try await self . runtimeService. expand ( pkgPath: pkgPath, expandedPkgPath: expandedPkgPath)
191+ //try await self.runtimeService.unmountDMG(mountedURL: mountedUrl)
192+
193+ } catch {
194+ Logger . appState. error ( " Error installing runtime: \( error. localizedDescription) " )
195+ }
196+ }
197+ }
198+
199+ extension AnyPublisher {
200+ func async ( ) async throws -> Output {
201+ try await withCheckedThrowingContinuation { continuation in
202+ var cancellable : AnyCancellable ?
203+
204+ cancellable = first ( )
205+ . sink { result in
206+ switch result {
207+ case . finished:
208+ break
209+ case let . failure( error) :
210+ continuation. resume ( throwing: error)
211+ }
212+ cancellable? . cancel ( )
213+ } receiveValue: { value in
214+ continuation. resume ( with: . success( value) )
215+ }
214216 }
215-
216-
217-
218- return Just ( dmgURL)
219- . setFailureType ( to: Error . self)
220- . eraseToAnyPublisher ( )
221217 }
222-
223218}
0 commit comments