fix: Fix the issue of installation failure caused by abnormal number of dependencies and packages.

This commit is contained in:
X1a0He
2024-11-15 23:32:51 +08:00
parent 5fb265105d
commit 33daa8fef2
8 changed files with 114 additions and 62 deletions

View File

@@ -31,7 +31,7 @@
shouldAutocreateTestPlan = "YES"> shouldAutocreateTestPlan = "YES">
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Release"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0" launchStyle = "0"

View File

@@ -20,22 +20,6 @@
landmarkType = "7"> landmarkType = "7">
</BreakpointContent> </BreakpointContent>
</BreakpointProxy> </BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "A757ED7D-136A-4033-8710-3B3C60074969"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "Adobe Downloader/Utils/DownloadUtils.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "668"
endingLineNumber = "668"
landmarkName = "handleDownload(task:productInfo:allowedPlatform:saps:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy <BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent <BreakpointContent

View File

@@ -28,7 +28,12 @@ struct Adobe_DownloaderApp: App {
updaterController = SPUStandardUpdaterController(startingUpdater: true, updaterDelegate: nil, userDriverDelegate: nil) updaterController = SPUStandardUpdaterController(startingUpdater: true, updaterDelegate: nil, userDriverDelegate: nil)
if StorageData.shared.isFirstLaunch { if StorageData.shared.isFirstLaunch {
StorageData.shared.downloadAppleSilicon = AppStatics.isAppleSilicon let shouldDownloadAppleSilicon = AppStatics.isAppleSilicon
StorageData.shared.downloadAppleSilicon = shouldDownloadAppleSilicon
_downloadAppleSilicon.wrappedValue = shouldDownloadAppleSilicon
StorageData.shared.confirmRedownload = true
_confirmRedownload.wrappedValue = true
let systemLanguage = Locale.current.identifier let systemLanguage = Locale.current.identifier
let matchedLanguage = AppStatics.supportedLanguages.first { let matchedLanguage = AppStatics.supportedLanguages.first {

View File

@@ -65,7 +65,6 @@ class NetworkManager: ObservableObject {
loadingState = .loading loadingState = .loading
do { do {
let (saps, cdn, sapCodes) = try await networkService.fetchProductsData( let (saps, cdn, sapCodes) = try await networkService.fetchProductsData(
version: apiVersion,
platform: allowedPlatform.joined(separator: ",") platform: allowedPlatform.joined(separator: ",")
) )
await MainActor.run { await MainActor.run {
@@ -173,7 +172,7 @@ class NetworkManager: ObservableObject {
while retryCount < maxRetries { while retryCount < maxRetries {
do { do {
let (saps, cdn, sapCodes) = try await networkService.fetchProductsData(version: apiVersion, platform: allowedPlatform.joined(separator: ",")) let (saps, cdn, sapCodes) = try await networkService.fetchProductsData(platform: allowedPlatform.joined(separator: ","))
await MainActor.run { await MainActor.run {
self.saps = saps self.saps = saps

View File

@@ -0,0 +1,13 @@
#!/bin/bash
# clean-config.sh
# AdobeDownloader
#
# Created by X1a0He on 2024/11/15.
# Copyright © 2024 X1a0He. All rights reserved.
sudo /usr/bin/killall -u root -9 Adobe\ Downloader
sudo /bin/launchctl unload /Library/LaunchDaemons/com.x1a0he.macOS.Adobe-Downloader.helper.plist
sudo /bin/rm /Library/LaunchDaemons/com.x1a0he.macOS.Adobe-Downloader.helper.plist
sudo /bin/rm /Library/PrivilegedHelperTools/com.x1a0he.macOS.Adobe-Downloader.helper
sudo /bin/rm ~/Library/Preferences/com.x1a0he.macOS.Adobe-Downloader.plist
sudo /usr/bin/killall -u root -9 com.x1a0he.macOS.Adobe-Downloader.helper

View File

@@ -3,15 +3,14 @@ import Foundation
class NetworkService { class NetworkService {
typealias ProductsData = (products: [String: Sap], cdn: String, sapCodes: [SapCodes]) typealias ProductsData = (products: [String: Sap], cdn: String, sapCodes: [SapCodes])
private func makeProductsURL(version: String) throws -> URL { private func makeProductsURL() throws -> URL {
var components = URLComponents(string: NetworkConstants.productsXmlURL) var components = URLComponents(string: NetworkConstants.productsXmlURL)
components?.queryItems = [ components?.queryItems = [
URLQueryItem(name: "_type", value: "xml"), URLQueryItem(name: "_type", value: "xml"),
URLQueryItem(name: "channel", value: "ccm"), URLQueryItem(name: "channel", value: "ccm"),
URLQueryItem(name: "channel", value: "sti"), URLQueryItem(name: "channel", value: "sti"),
URLQueryItem(name: "platform", value: "osx10-64,osx10,macarm64,macuniversal"), URLQueryItem(name: "platform", value: "osx10-64,osx10,macarm64,macuniversal"),
URLQueryItem(name: "productType", value: "Desktop"), URLQueryItem(name: "productType", value: "Desktop")
URLQueryItem(name: "version", value: version)
] ]
guard let url = components?.url else { guard let url = components?.url else {
@@ -25,8 +24,8 @@ class NetworkService {
headers.forEach { request.setValue($0.value, forHTTPHeaderField: $0.key) } headers.forEach { request.setValue($0.value, forHTTPHeaderField: $0.key) }
} }
func fetchProductsData(version: String, platform: String) async throws -> ProductsData { func fetchProductsData(platform: String) async throws -> ProductsData {
let url = try makeProductsURL(version: version) let url = try makeProductsURL()
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"
configureRequest(&request, headers: NetworkConstants.adobeRequestHeaders) configureRequest(&request, headers: NetworkConstants.adobeRequestHeaders)

View File

@@ -83,6 +83,14 @@ final class StorageData: ObservableObject {
} }
private init() { private init() {
let isFirstLaunchKey = "isFirstLaunch"
if !UserDefaults.standard.contains(key: isFirstLaunchKey) {
self.isFirstLaunch = true
UserDefaults.standard.set(true, forKey: isFirstLaunchKey)
} else {
self.isFirstLaunch = UserDefaults.standard.bool(forKey: isFirstLaunchKey)
}
self.installedHelperBuild = UserDefaults.standard.string(forKey: "InstalledHelperBuild") ?? "0" self.installedHelperBuild = UserDefaults.standard.string(forKey: "InstalledHelperBuild") ?? "0"
self.downloadAppleSilicon = UserDefaults.standard.bool(forKey: "downloadAppleSilicon") self.downloadAppleSilicon = UserDefaults.standard.bool(forKey: "downloadAppleSilicon")
self.useDefaultLanguage = UserDefaults.standard.bool(forKey: "useDefaultLanguage") self.useDefaultLanguage = UserDefaults.standard.bool(forKey: "useDefaultLanguage")
@@ -91,7 +99,6 @@ final class StorageData: ObservableObject {
self.defaultDirectory = UserDefaults.standard.string(forKey: "defaultDirectory") ?? "" self.defaultDirectory = UserDefaults.standard.string(forKey: "defaultDirectory") ?? ""
self.confirmRedownload = UserDefaults.standard.bool(forKey: "confirmRedownload") self.confirmRedownload = UserDefaults.standard.bool(forKey: "confirmRedownload")
self.apiVersion = UserDefaults.standard.string(forKey: "apiVersion") ?? "6" self.apiVersion = UserDefaults.standard.string(forKey: "apiVersion") ?? "6"
self.isFirstLaunch = UserDefaults.standard.bool(forKey: "isFirstLaunch")
} }
} }
@@ -123,3 +130,9 @@ extension Notification.Name {
static let storageDidChange = Notification.Name("storageDidChange") static let storageDidChange = Notification.Name("storageDidChange")
} }
extension UserDefaults {
func contains(key: String) -> Bool {
return object(forKey: key) != nil
}
}

View File

@@ -658,28 +658,49 @@ class DownloadUtils {
for dependency in productInfo.dependencies { for dependency in productInfo.dependencies {
if let dependencyVersions = saps[dependency.sapCode]?.versions { if let dependencyVersions = saps[dependency.sapCode]?.versions {
var firstGuid: String?
var buildGuid: String?
let matchingVersions = dependencyVersions.filter { let sortedVersions = dependencyVersions.sorted { version1, version2 in
$0.value.baseVersion == dependency.version let v1Components = version1.key.split(separator: ".").compactMap { Int($0) }
let v2Components = version2.key.split(separator: ".").compactMap { Int($0) }
for i in 0..<min(v1Components.count, v2Components.count) {
if v1Components[i] != v2Components[i] {
return v1Components[i] > v2Components[i]
}
}
return v1Components.count > v2Components.count
} }
for version in sortedVersions {
if version.value.baseVersion == dependency.version {
if firstGuid == nil { firstGuid = version.value.buildGuid }
var selectedVersion: (key: String, value: Sap.Versions)? = matchingVersions.first { // print("\(version.value.sapCode), \(version.key), \(allowedPlatform), \(version.value.apPlatform), \(allowedPlatform.contains(version.value.apPlatform))")
allowedPlatform.contains($0.value.apPlatform)
if allowedPlatform.contains(version.value.apPlatform) {
buildGuid = version.value.buildGuid
break
}
}
} }
selectedVersion = selectedVersion ?? matchingVersions.first
if let version = selectedVersion { if buildGuid == nil { buildGuid = firstGuid }
if let finalBuildGuid = buildGuid {
productsToDownload.append(ProductsToDownload( productsToDownload.append(ProductsToDownload(
sapCode: dependency.sapCode, sapCode: dependency.sapCode,
version: dependency.version, version: dependency.version,
buildGuid: version.value.buildGuid buildGuid: finalBuildGuid
)) ))
} }
} }
} }
// for product in productsToDownload {
// print("\(product.sapCode), \(product.version), \(product.buildGuid)")
// }
for product in productsToDownload { for product in productsToDownload {
await MainActor.run { await MainActor.run {
task.setStatus(.preparing(DownloadStatus.PrepareInfo( task.setStatus(.preparing(DownloadStatus.PrepareInfo(
@@ -689,11 +710,11 @@ class DownloadUtils {
))) )))
} }
let jsonString = try await getApplicationInfo(buildGuid: product.buildGuid)
let productDir = task.directory.appendingPathComponent("\(product.sapCode)") let productDir = task.directory.appendingPathComponent("\(product.sapCode)")
if !FileManager.default.fileExists(atPath: productDir.path) { if !FileManager.default.fileExists(atPath: productDir.path) {
try FileManager.default.createDirectory(at: productDir, withIntermediateDirectories: true) try FileManager.default.createDirectory(at: productDir, withIntermediateDirectories: true)
} }
let jsonString = try await getApplicationInfo(buildGuid: product.buildGuid)
let jsonURL = productDir.appendingPathComponent("application.json") let jsonURL = productDir.appendingPathComponent("application.json")
try jsonString.write(to: jsonURL, atomically: true, encoding: .utf8) try jsonString.write(to: jsonURL, atomically: true, encoding: .utf8)
@@ -704,7 +725,15 @@ class DownloadUtils {
throw NetworkError.invalidData("无法解析产品信息") throw NetworkError.invalidData("无法解析产品信息")
} }
var corePackageCount = 0
var nonCorePackageCount = 0
for package in packageArray { for package in packageArray {
let packageType = package["Type"] as? String ?? "non-core"
let isCore = packageType == "core"
guard let downloadURL = package["Path"] as? String, !downloadURL.isEmpty else { continue }
let fullPackageName: String let fullPackageName: String
if let name = package["fullPackageName"] as? String, !name.isEmpty { if let name = package["fullPackageName"] as? String, !name.isEmpty {
fullPackageName = name fullPackageName = name
@@ -712,33 +741,18 @@ class DownloadUtils {
fullPackageName = "\(name).zip" fullPackageName = "\(name).zip"
} else { continue } } else { continue }
let packageType = package["Type"] as? String ?? "non-core" let downloadSize: Int64
let isLanguageSuitable: Bool if let sizeNumber = package["DownloadSize"] as? NSNumber {
if packageType == "core" { downloadSize = sizeNumber.int64Value
isLanguageSuitable = true } else if let sizeString = package["DownloadSize"] as? String,
} else { let parsedSize = Int64(sizeString) {
let condition = package["Condition"] as? String ?? "" downloadSize = parsedSize
let osLang = Locale.current.identifier } else if let sizeInt = package["DownloadSize"] as? Int {
isLanguageSuitable = ( downloadSize = Int64(sizeInt)
task.language == "ALL" || condition.isEmpty || } else { continue }
!condition.contains("[installLanguage]") || condition.contains("[installLanguage]==\(task.language)") ||
condition.contains("[installLanguage]==\(osLang)") if isCore {
) corePackageCount += 1
}
if isLanguageSuitable {
let downloadSize: Int64
if let sizeNumber = package["DownloadSize"] as? NSNumber {
downloadSize = sizeNumber.int64Value
} else if let sizeString = package["DownloadSize"] as? String,
let parsedSize = Int64(sizeString) {
downloadSize = parsedSize
} else if let sizeInt = package["DownloadSize"] as? Int {
downloadSize = Int64(sizeInt)
} else { continue }
guard let downloadURL = package["Path"] as? String, !downloadURL.isEmpty else { continue }
let newPackage = Package( let newPackage = Package(
type: packageType, type: packageType,
fullPackageName: fullPackageName, fullPackageName: fullPackageName,
@@ -746,6 +760,31 @@ class DownloadUtils {
downloadURL: downloadURL downloadURL: downloadURL
) )
product.packages.append(newPackage) product.packages.append(newPackage)
} else {
let languageIsSuitable: Bool
if task.language == "ALL" {
languageIsSuitable = true
} else if !package.keys.contains("Condition") {
languageIsSuitable = true
} else if let condition = package["Condition"] as? String {
let matchesTaskLang = condition.contains("[installLanguage]==\(task.language)")
let matchesOSLang = condition.contains("[installLanguage]==en_US")
languageIsSuitable = matchesTaskLang || matchesOSLang
} else {
languageIsSuitable = false
}
if languageIsSuitable {
nonCorePackageCount += 1
let newPackage = Package(
type: packageType,
fullPackageName: fullPackageName,
downloadSize: downloadSize,
downloadURL: downloadURL
)
product.packages.append(newPackage)
} else {
}
} }
} }
} }