mirror of
https://github.com/XcodesOrg/XcodesApp.git
synced 2026-03-25 08:55:46 +00:00
runtime clean up
This commit is contained in:
parent
6ffce23616
commit
ec4dc2b3d0
9 changed files with 107 additions and 62 deletions
|
|
@ -101,6 +101,7 @@
|
|||
CAFFFED8259CDA5000903F81 /* XcodeListViewRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFFFED7259CDA5000903F81 /* XcodeListViewRow.swift */; };
|
||||
E689540325BE8C64000EBCEA /* DockProgress in Frameworks */ = {isa = PBXBuildFile; productRef = E689540225BE8C64000EBCEA /* DockProgress */; };
|
||||
E81D7EA02805250100A205FC /* Collection+.swift in Sources */ = {isa = PBXBuildFile; fileRef = E81D7E9F2805250100A205FC /* Collection+.swift */; };
|
||||
E832EAF82B0FBCF4001B570D /* RuntimeInstallationStepDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E832EAF72B0FBCF4001B570D /* RuntimeInstallationStepDetailView.swift */; };
|
||||
E872EE4E2808D4F100D3DD8B /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E872EE502808D4F100D3DD8B /* Localizable.strings */; };
|
||||
E87AB3C52939B65E00D72F43 /* Hardware.swift in Sources */ = {isa = PBXBuildFile; fileRef = E87AB3C42939B65E00D72F43 /* Hardware.swift */; };
|
||||
E87DD6EB25D053FA00D86808 /* Progress+.swift in Sources */ = {isa = PBXBuildFile; fileRef = E87DD6EA25D053FA00D86808 /* Progress+.swift */; };
|
||||
|
|
@ -300,6 +301,7 @@
|
|||
CAFFFEEE259CEAC400903F81 /* RingProgressViewStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RingProgressViewStyle.swift; sourceTree = "<group>"; };
|
||||
E2AFDCCA28F024D000864ADD /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
E81D7E9F2805250100A205FC /* Collection+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection+.swift"; sourceTree = "<group>"; };
|
||||
E832EAF72B0FBCF4001B570D /* RuntimeInstallationStepDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeInstallationStepDetailView.swift; sourceTree = "<group>"; };
|
||||
E856BB73291EDD3D00DC438B /* XcodesKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = XcodesKit; path = Xcodes/XcodesKit; sourceTree = "<group>"; };
|
||||
E872EE4F2808D4F100D3DD8B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
E87AB3C42939B65E00D72F43 /* Hardware.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Hardware.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -623,6 +625,7 @@
|
|||
children = (
|
||||
CAFBDC67259A308B003DCC5A /* InfoPane.swift */,
|
||||
E8E98A9525D863D700EC89A0 /* InstallationStepDetailView.swift */,
|
||||
E832EAF72B0FBCF4001B570D /* RuntimeInstallationStepDetailView.swift */,
|
||||
);
|
||||
path = InfoPane;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -875,6 +878,7 @@
|
|||
CA452BB0259FD9770072DFA4 /* ProgressIndicator.swift in Sources */,
|
||||
CAFE4AB425B7D3AF0064FE51 /* AdvancedPreferencePane.swift in Sources */,
|
||||
CA9FF84E2595079F00E47BAF /* ScrollingTextView.swift in Sources */,
|
||||
E832EAF82B0FBCF4001B570D /* RuntimeInstallationStepDetailView.swift in Sources */,
|
||||
CABFA9C12592EEEA00380FEE /* Version+.swift in Sources */,
|
||||
E8D655C0288DD04700A139C2 /* SelectedActionType.swift in Sources */,
|
||||
36741BFD291E4FDB00A85AAE /* DownloadPreferencePane.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -499,9 +499,9 @@ extension AppState {
|
|||
Current.notificationManager.scheduleNotification(title: xcode.id.appleDescription, body: step.description, category: .normal)
|
||||
}
|
||||
}
|
||||
|
||||
func setInstallationStep(of runtime: DownloadableRuntime, to step: RuntimeInstallationStep) {
|
||||
DispatchQueue.main.async {
|
||||
|
||||
guard let index = self.downloadableRuntimes.firstIndex(where: { $0.identifier == runtime.identifier }) else { return }
|
||||
self.downloadableRuntimes[index].installState = .installing(step)
|
||||
|
||||
|
|
|
|||
|
|
@ -49,9 +49,18 @@ extension AppState {
|
|||
Task {
|
||||
do {
|
||||
try await downloadRunTimeFull(runtime: runtime)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
guard let index = self.downloadableRuntimes.firstIndex(where: { $0.identifier == runtime.identifier }) else { return }
|
||||
self.downloadableRuntimes[index].installState = .installed
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Logger.appState.error("Error downloading runtime: \(error.localizedDescription)")
|
||||
DispatchQueue.main.async {
|
||||
self.error = error
|
||||
self.presentedAlert = .generic(title: localizeString("Alert.Install.Error.Title"), message: error.legibleLocalizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -83,6 +92,7 @@ extension AppState {
|
|||
let downloader = Downloader(rawValue: UserDefaults.standard.string(forKey: "downloader") ?? "aria2") ?? .aria2
|
||||
Logger.appState.info("Downloading \(runtime.visibleIdentifier) with \(downloader)")
|
||||
|
||||
|
||||
let url = try await self.downloadRuntime(for: runtime, downloader: downloader, progressChanged: { [unowned self] progress in
|
||||
DispatchQueue.main.async {
|
||||
self.setInstallationStep(of: runtime, to: .downloading(progress: progress))
|
||||
|
|
@ -90,15 +100,23 @@ extension AppState {
|
|||
}).async()
|
||||
|
||||
Logger.appState.debug("Done downloading: \(url)")
|
||||
//self.setInstallationStep(of: runtime, to: .downloading(progress: progress))
|
||||
DispatchQueue.main.async {
|
||||
self.setInstallationStep(of: runtime, to: .installing)
|
||||
}
|
||||
switch runtime.contentType {
|
||||
case .package:
|
||||
try await self.installFromPackage(dmgURL: url, runtime: runtime)
|
||||
// not supported yet (do we need to for old packages?)
|
||||
throw "Installing via package not support - please install manually from \(url.description)"
|
||||
case .diskImage:
|
||||
try await self.installFromImage(dmgURL: url)
|
||||
DispatchQueue.main.async {
|
||||
self.setInstallationStep(of: runtime, to: .trashingArchive)
|
||||
}
|
||||
try Current.files.removeItem(at: url)
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func downloadRuntime(for runtime: DownloadableRuntime, downloader: Downloader, progressChanged: @escaping (Progress) -> Void) -> AnyPublisher<URL, Error> {
|
||||
// Check to see if the dmg is in the expected path in case it was downloaded but failed to install
|
||||
|
||||
|
|
@ -139,9 +157,9 @@ extension AppState {
|
|||
.setFailureType(to: Error.self)
|
||||
.eraseToAnyPublisher()
|
||||
|
||||
// return downloadXcodeWithURLSession(
|
||||
// availableXcode,
|
||||
// to: destination,
|
||||
// return downloadRuntimeWithURLSession(
|
||||
// runtime,
|
||||
// to: expectedRuntimePath,
|
||||
// progressChanged: progressChanged
|
||||
// )
|
||||
}
|
||||
|
|
@ -163,36 +181,8 @@ extension AppState {
|
|||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
|
||||
public func installFromImage(dmgURL: URL) async throws {
|
||||
|
||||
try? self.runtimeService.installRuntimeImage(dmgURL: dmgURL)
|
||||
|
||||
}
|
||||
|
||||
public func installFromPackage(dmgURL: URL, runtime: DownloadableRuntime) async throws {
|
||||
Logger.appState.info("Mounting DMG")
|
||||
|
||||
do {
|
||||
let mountedUrl = try await self.runtimeService.mountDMG(dmgUrl: dmgURL)
|
||||
|
||||
// 2-Get the first path under the mounted path, should be a .pkg
|
||||
let pkgPath = Path(url: mountedUrl)!.ls().first!
|
||||
try Path.xcodesCaches.mkdir().setCurrentUserAsOwner()
|
||||
|
||||
let expandedPkgPath = Path.xcodesCaches/runtime.identifier
|
||||
//try expandedPkgPath.mkdir()
|
||||
Logger.appState.info("PKG Path: \(pkgPath)")
|
||||
Logger.appState.info("Expanded PKG Path: \(expandedPkgPath)")
|
||||
//try? Current.files.removeItem(at: expandedPkgPath.url)
|
||||
|
||||
// 5-Expand (not install) the pkg to temporary path
|
||||
try await self.runtimeService.expand(pkgPath: pkgPath, expandedPkgPath: expandedPkgPath)
|
||||
//try await self.runtimeService.unmountDMG(mountedURL: mountedUrl)
|
||||
|
||||
} catch {
|
||||
Logger.appState.error("Error installing runtime: \(error.localizedDescription)")
|
||||
}
|
||||
try await self.runtimeService.installRuntimeImage(dmgURL: dmgURL)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -240,6 +240,12 @@ public struct Files {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public var write: (Data, URL) throws -> Void = { try $0.write(to: $1) }
|
||||
|
||||
public func write(_ data: Data, to url: URL) throws {
|
||||
try write(data, url)
|
||||
}
|
||||
}
|
||||
|
||||
private func _installedXcodes(destination: Path) -> [InstalledXcode] {
|
||||
|
|
|
|||
|
|
@ -288,8 +288,7 @@ struct InfoPane: View {
|
|||
switch runtime.installState {
|
||||
|
||||
case .installing(let installationStep):
|
||||
Text("INSTALLING")
|
||||
InstallationStepDetailView(installationStep: installationStep)
|
||||
RuntimeInstallationStepDetailView(installationStep: installationStep)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
default:
|
||||
EmptyView()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
//
|
||||
// RuntimeInstallationStepDetailView.swift
|
||||
// Xcodes
|
||||
//
|
||||
// Created by Matt Kiazyk on 2023-11-23.
|
||||
// Copyright © 2023 Robots and Pencils. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import XcodesKit
|
||||
|
||||
struct RuntimeInstallationStepDetailView: View {
|
||||
let installationStep: RuntimeInstallationStep
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
Text(String(format: localizeString("InstallationStepDescription"), installationStep.stepNumber, installationStep.stepCount, installationStep.message))
|
||||
|
||||
switch installationStep {
|
||||
case let .downloading(progress):
|
||||
ObservingProgressIndicator(
|
||||
progress,
|
||||
controlSize: .regular,
|
||||
style: .bar,
|
||||
showsAdditionalDescription: true
|
||||
)
|
||||
|
||||
case .installing, .trashingArchive:
|
||||
ProgressView()
|
||||
.scaleEffect(0.5)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview("Downloading") {
|
||||
RuntimeInstallationStepDetailView(
|
||||
installationStep: .downloading(
|
||||
progress: configure(Progress()) {
|
||||
$0.kind = .file
|
||||
$0.fileOperationKind = .downloading
|
||||
$0.estimatedTimeRemaining = 123
|
||||
$0.totalUnitCount = 11944848484
|
||||
$0.completedUnitCount = 848444920
|
||||
$0.throughput = 9211681
|
||||
}
|
||||
))
|
||||
}
|
||||
#Preview("Installing") {
|
||||
RuntimeInstallationStepDetailView(
|
||||
installationStep: .installing
|
||||
)
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ import Path
|
|||
public enum RuntimeInstallState: Equatable {
|
||||
case notInstalled
|
||||
case installing(RuntimeInstallationStep)
|
||||
case installed(Path)
|
||||
case installed
|
||||
|
||||
var notInstalled: Bool {
|
||||
switch self {
|
||||
|
|
|
|||
|
|
@ -9,11 +9,8 @@ import Foundation
|
|||
|
||||
public enum RuntimeInstallationStep: Equatable, CustomStringConvertible {
|
||||
case downloading(progress: Progress)
|
||||
case unarchiving
|
||||
case moving(destination: String)
|
||||
case installing
|
||||
case trashingArchive
|
||||
case checkingSecurity
|
||||
case finishing
|
||||
|
||||
public var description: String {
|
||||
"(\(stepNumber)/\(stepCount)) \(message)"
|
||||
|
|
@ -23,29 +20,20 @@ public enum RuntimeInstallationStep: Equatable, CustomStringConvertible {
|
|||
switch self {
|
||||
case .downloading:
|
||||
return localizeString("Downloading")
|
||||
case .unarchiving:
|
||||
return localizeString("Unarchiving")
|
||||
case .moving(let destination):
|
||||
return String(format: localizeString("Moving"), destination)
|
||||
case .installing:
|
||||
return localizeString("Installing")
|
||||
case .trashingArchive:
|
||||
return localizeString("TrashingArchive")
|
||||
case .checkingSecurity:
|
||||
return localizeString("CheckingSecurity")
|
||||
case .finishing:
|
||||
return localizeString("Finishing")
|
||||
}
|
||||
}
|
||||
|
||||
public var stepNumber: Int {
|
||||
switch self {
|
||||
case .downloading: return 1
|
||||
case .unarchiving: return 2
|
||||
case .moving: return 3
|
||||
case .trashingArchive: return 4
|
||||
case .checkingSecurity: return 5
|
||||
case .finishing: return 6
|
||||
case .installing: return 2
|
||||
case .trashingArchive: return 3
|
||||
}
|
||||
}
|
||||
|
||||
public var stepCount: Int { 6 }
|
||||
public var stepCount: Int { 3 }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,10 +54,8 @@ public struct RuntimeService {
|
|||
}
|
||||
}
|
||||
|
||||
public func installRuntimeImage(dmgURL: URL) throws {
|
||||
Task {
|
||||
_ = try await Current.shell.installRuntimeImage(dmgURL)
|
||||
}
|
||||
public func installRuntimeImage(dmgURL: URL) async throws {
|
||||
_ = try await Current.shell.installRuntimeImage(dmgURL)
|
||||
}
|
||||
|
||||
public func mountDMG(dmgUrl: URL) async throws -> URL {
|
||||
|
|
@ -72,13 +70,20 @@ public struct RuntimeService {
|
|||
}
|
||||
|
||||
public func unmountDMG(mountedURL: URL) async throws {
|
||||
let url = try await Current.shell.unmountDmg(mountedURL)
|
||||
_ = try await Current.shell.unmountDmg(mountedURL)
|
||||
}
|
||||
|
||||
public func expand(pkgPath: Path, expandedPkgPath: Path) async throws {
|
||||
_ = try await Current.shell.expandPkg(pkgPath.url, expandedPkgPath.url)
|
||||
}
|
||||
|
||||
|
||||
public func createPkg(pkgPath: Path, expandedPkgPath: Path) async throws {
|
||||
_ = try await Current.shell.createPkg(pkgPath.url, expandedPkgPath.url)
|
||||
}
|
||||
|
||||
public func installPkg(pkgPath: Path, expandedPkgPath: Path) async throws {
|
||||
_ = try await Current.shell.installPkg(pkgPath.url, expandedPkgPath.url.absoluteString)
|
||||
}
|
||||
}
|
||||
|
||||
extension String: Error {}
|
||||
|
|
|
|||
Loading…
Reference in a new issue