Merge pull request #38 from RobotsAndPencils/remove-promisekit

Remove PromiseKit
This commit is contained in:
Brandon Evans 2021-01-01 15:03:34 -07:00 committed by GitHub
commit ba1c4fec0f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 47 additions and 232 deletions

View file

@ -41,9 +41,8 @@
CAA1CB4D255A5CFD003FD669 /* SignInPhoneListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAA1CB4C255A5CFD003FD669 /* SignInPhoneListView.swift */; };
CABFA9BB2592EEEA00380FEE /* DateFormatter+.swift in Sources */ = {isa = PBXBuildFile; fileRef = CABFA9BA2592EEEA00380FEE /* DateFormatter+.swift */; };
CABFA9BD2592EEEA00380FEE /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = CABFA9A92592EEE900380FEE /* Environment.swift */; };
CABFA9BF2592EEEA00380FEE /* URLSession+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = CABFA9B32592EEEA00380FEE /* URLSession+Promise.swift */; };
CABFA9BF2592EEEA00380FEE /* URLSession+DownloadTaskPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = CABFA9B32592EEEA00380FEE /* URLSession+DownloadTaskPublisher.swift */; };
CABFA9C12592EEEA00380FEE /* Version+.swift in Sources */ = {isa = PBXBuildFile; fileRef = CABFA9A82592EEE900380FEE /* Version+.swift */; };
CABFA9C22592EEEA00380FEE /* Promise+.swift in Sources */ = {isa = PBXBuildFile; fileRef = CABFA9B02592EEEA00380FEE /* Promise+.swift */; };
CABFA9C32592EEEA00380FEE /* Downloads.swift in Sources */ = {isa = PBXBuildFile; fileRef = CABFA9B92592EEEA00380FEE /* Downloads.swift */; };
CABFA9C52592EEEA00380FEE /* FileManager+.swift in Sources */ = {isa = PBXBuildFile; fileRef = CABFA9B82592EEEA00380FEE /* FileManager+.swift */; };
CABFA9C72592EEEA00380FEE /* Entry+.swift in Sources */ = {isa = PBXBuildFile; fileRef = CABFA9B22592EEEA00380FEE /* Entry+.swift */; };
@ -55,9 +54,7 @@
CABFA9CF2592EEEA00380FEE /* Process.swift in Sources */ = {isa = PBXBuildFile; fileRef = CABFA9B42592EEEA00380FEE /* Process.swift */; };
CABFA9DF2592F07A00380FEE /* Path in Frameworks */ = {isa = PBXBuildFile; productRef = CABFA9DE2592F07A00380FEE /* Path */; };
CABFA9E42592F08E00380FEE /* Version in Frameworks */ = {isa = PBXBuildFile; productRef = CABFA9E32592F08E00380FEE /* Version */; };
CABFA9E92592F0B400380FEE /* PromiseKit in Frameworks */ = {isa = PBXBuildFile; productRef = CABFA9E82592F0B400380FEE /* PromiseKit */; };
CABFA9EE2592F0CC00380FEE /* SwiftSoup in Frameworks */ = {isa = PBXBuildFile; productRef = CABFA9ED2592F0CC00380FEE /* SwiftSoup */; };
CABFA9F32592F0E400380FEE /* PMKFoundation in Frameworks */ = {isa = PBXBuildFile; productRef = CABFA9F22592F0E400380FEE /* PMKFoundation */; };
CABFA9F82592F0F900380FEE /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = CABFA9F72592F0F900380FEE /* KeychainAccess */; };
CABFA9FD2592F13300380FEE /* LegibleError in Frameworks */ = {isa = PBXBuildFile; productRef = CABFA9FC2592F13300380FEE /* LegibleError */; };
CABFAA2C2592FBFC00380FEE /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CABFAA2A2592FBFC00380FEE /* SettingsView.swift */; };
@ -171,9 +168,8 @@
CABFA9AB2592EEE900380FEE /* URLRequest+Apple.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLRequest+Apple.swift"; sourceTree = "<group>"; };
CABFA9AC2592EEE900380FEE /* Foundation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Foundation.swift; sourceTree = "<group>"; };
CABFA9AE2592EEE900380FEE /* Path+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Path+.swift"; sourceTree = "<group>"; };
CABFA9B02592EEEA00380FEE /* Promise+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Promise+.swift"; sourceTree = "<group>"; };
CABFA9B22592EEEA00380FEE /* Entry+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Entry+.swift"; sourceTree = "<group>"; };
CABFA9B32592EEEA00380FEE /* URLSession+Promise.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLSession+Promise.swift"; sourceTree = "<group>"; };
CABFA9B32592EEEA00380FEE /* URLSession+DownloadTaskPublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLSession+DownloadTaskPublisher.swift"; sourceTree = "<group>"; };
CABFA9B42592EEEA00380FEE /* Process.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Process.swift; sourceTree = "<group>"; };
CABFA9B82592EEEA00380FEE /* FileManager+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+.swift"; sourceTree = "<group>"; };
CABFA9B92592EEEA00380FEE /* Downloads.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Downloads.swift; sourceTree = "<group>"; };
@ -218,11 +214,9 @@
buildActionMask = 2147483647;
files = (
CABFA9E42592F08E00380FEE /* Version in Frameworks */,
CABFA9E92592F0B400380FEE /* PromiseKit in Frameworks */,
CABFA9FD2592F13300380FEE /* LegibleError in Frameworks */,
CA9FF86D25951C6E00E47BAF /* XCModel in Frameworks */,
CABFA9F82592F0F900380FEE /* KeychainAccess in Frameworks */,
CABFA9F32592F0E400380FEE /* PMKFoundation in Frameworks */,
CAA1CB2D255A5262003FD669 /* AppleAPI in Frameworks */,
CABFA9DF2592F07A00380FEE /* Path in Frameworks */,
CABFA9EE2592F0CC00380FEE /* SwiftSoup in Frameworks */,
@ -339,10 +333,9 @@
CAE4248B259A68B800B8B246 /* Optional+IsNotNil.swift */,
CABFA9AE2592EEE900380FEE /* Path+.swift */,
CABFA9B42592EEEA00380FEE /* Process.swift */,
CABFA9B02592EEEA00380FEE /* Promise+.swift */,
CAFBDB902598FE80003DCC5A /* SelectedXcode.swift */,
CABFA9AB2592EEE900380FEE /* URLRequest+Apple.swift */,
CABFA9B32592EEEA00380FEE /* URLSession+Promise.swift */,
CABFA9B32592EEEA00380FEE /* URLSession+DownloadTaskPublisher.swift */,
CABFA9A82592EEE900380FEE /* Version+.swift */,
CA9FF876259528CC00E47BAF /* Version+XcodeReleases.swift */,
CABFA9A62592EEE900380FEE /* Version+Xcode.swift */,
@ -479,9 +472,7 @@
CAA1CB2C255A5262003FD669 /* AppleAPI */,
CABFA9DE2592F07A00380FEE /* Path */,
CABFA9E32592F08E00380FEE /* Version */,
CABFA9E82592F0B400380FEE /* PromiseKit */,
CABFA9ED2592F0CC00380FEE /* SwiftSoup */,
CABFA9F22592F0E400380FEE /* PMKFoundation */,
CABFA9F72592F0F900380FEE /* KeychainAccess */,
CABFA9FC2592F13300380FEE /* LegibleError */,
CA9FF86C25951C6E00E47BAF /* XCModel */,
@ -542,9 +533,7 @@
packageReferences = (
CABFA9DD2592F07A00380FEE /* XCRemoteSwiftPackageReference "Path" */,
CABFA9E22592F08E00380FEE /* XCRemoteSwiftPackageReference "Version" */,
CABFA9E72592F0B400380FEE /* XCRemoteSwiftPackageReference "PromiseKit" */,
CABFA9EC2592F0CC00380FEE /* XCRemoteSwiftPackageReference "SwiftSoup" */,
CABFA9F12592F0E400380FEE /* XCRemoteSwiftPackageReference "Foundation" */,
CABFA9F62592F0F900380FEE /* XCRemoteSwiftPackageReference "KeychainAccess" */,
CABFA9FB2592F13300380FEE /* XCRemoteSwiftPackageReference "LegibleError" */,
CA9FF86B25951C6E00E47BAF /* XCRemoteSwiftPackageReference "data" */,
@ -589,6 +578,8 @@
inputFileListPaths = (
);
inputPaths = (
"$(SRCROOT)/Xcodes.xcodeproj",
"$(SRCROOT)/**/*.LICENSE",
);
name = "Generate Acknowledgements";
outputFileListPaths = (
@ -629,7 +620,7 @@
CA9FF9362595B44700E47BAF /* HelperClient.swift in Sources */,
CABFA9CA2592EEEA00380FEE /* AppState+Update.swift in Sources */,
CA44901F2463AD34003D8213 /* Tag.swift in Sources */,
CABFA9BF2592EEEA00380FEE /* URLSession+Promise.swift in Sources */,
CABFA9BF2592EEEA00380FEE /* URLSession+DownloadTaskPublisher.swift in Sources */,
CABFA9BB2592EEEA00380FEE /* DateFormatter+.swift in Sources */,
CABFA9BD2592EEEA00380FEE /* Environment.swift in Sources */,
CABFA9C32592EEEA00380FEE /* Downloads.swift in Sources */,
@ -653,7 +644,6 @@
CA9FF8F525959CE000E47BAF /* HelperInstaller.swift in Sources */,
CA73510D257BFCEF00EA9CF8 /* NSAttributedString+.swift in Sources */,
CAFBDB952598FE96003DCC5A /* FocusedValues.swift in Sources */,
CABFA9C22592EEEA00380FEE /* Promise+.swift in Sources */,
CAFBDC68259A308B003DCC5A /* InfoPane.swift in Sources */,
CAA1CB4D255A5CFD003FD669 /* SignInPhoneListView.swift in Sources */,
CAFBDC6C259A3098003DCC5A /* View+Conditional.swift in Sources */,
@ -1145,14 +1135,6 @@
minimumVersion = 1.0.3;
};
};
CABFA9E72592F0B400380FEE /* XCRemoteSwiftPackageReference "PromiseKit" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/mxcl/PromiseKit";
requirement = {
kind = upToNextMinorVersion;
minimumVersion = 6.8.3;
};
};
CABFA9EC2592F0CC00380FEE /* XCRemoteSwiftPackageReference "SwiftSoup" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/scinfu/SwiftSoup";
@ -1161,14 +1143,6 @@
minimumVersion = 2.0.0;
};
};
CABFA9F12592F0E400380FEE /* XCRemoteSwiftPackageReference "Foundation" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/PromiseKit/Foundation";
requirement = {
kind = upToNextMinorVersion;
minimumVersion = 3.3.1;
};
};
CABFA9F62592F0F900380FEE /* XCRemoteSwiftPackageReference "KeychainAccess" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/kishikawakatsumi/KeychainAccess";
@ -1207,21 +1181,11 @@
package = CABFA9E22592F08E00380FEE /* XCRemoteSwiftPackageReference "Version" */;
productName = Version;
};
CABFA9E82592F0B400380FEE /* PromiseKit */ = {
isa = XCSwiftPackageProductDependency;
package = CABFA9E72592F0B400380FEE /* XCRemoteSwiftPackageReference "PromiseKit" */;
productName = PromiseKit;
};
CABFA9ED2592F0CC00380FEE /* SwiftSoup */ = {
isa = XCSwiftPackageProductDependency;
package = CABFA9EC2592F0CC00380FEE /* XCRemoteSwiftPackageReference "SwiftSoup" */;
productName = SwiftSoup;
};
CABFA9F22592F0E400380FEE /* PMKFoundation */ = {
isa = XCSwiftPackageProductDependency;
package = CABFA9F12592F0E400380FEE /* XCRemoteSwiftPackageReference "Foundation" */;
productName = PMKFoundation;
};
CABFA9F72592F0F900380FEE /* KeychainAccess */ = {
isa = XCSwiftPackageProductDependency;
package = CABFA9F62592F0F900380FEE /* XCRemoteSwiftPackageReference "KeychainAccess" */;

View file

@ -10,15 +10,6 @@
"version": null
}
},
{
"package": "PMKFoundation",
"repositoryURL": "https://github.com/PromiseKit/Foundation",
"state": {
"branch": null,
"revision": "1a276e598dac59489ed904887e0740fa75e571e0",
"version": "3.3.4"
}
},
{
"package": "KeychainAccess",
"repositoryURL": "https://github.com/kishikawakatsumi/KeychainAccess",
@ -46,15 +37,6 @@
"version": "0.16.3"
}
},
{
"package": "PromiseKit",
"repositoryURL": "https://github.com/mxcl/PromiseKit",
"state": {
"branch": null,
"revision": "1c296a8637838901d2b01e4c46875ee749506133",
"version": "6.8.5"
}
},
{
"package": "SwiftSoup",
"repositoryURL": "https://github.com/scinfu/SwiftSoup",

View file

@ -1,7 +1,5 @@
import Combine
import Foundation
import PromiseKit
import PMKFoundation
import Path
import AppleAPI
import KeychainAccess
@ -26,30 +24,13 @@ public struct Environment {
public var Current = Environment()
public struct Shell {
public var unxip: (URL) -> Promise<ProcessOutput> = { Process.run(Path.root.usr.bin.xip, workingDirectory: $0.deletingLastPathComponent(), "--expand", "\($0.path)") }
public var spctlAssess: (URL) -> Promise<ProcessOutput> = { Process.run(Path.root.usr.sbin.spctl, "--assess", "--verbose", "--type", "execute", "\($0.path)") }
public var codesignVerify: (URL) -> Promise<ProcessOutput> = { Process.run(Path.root.usr.bin.codesign, "-vv", "-d", "\($0.path)") }
public var devToolsSecurityEnable: (String?) -> Promise<ProcessOutput> = { Process.sudo(password: $0, Path.root.usr.sbin.DevToolsSecurity, "-enable") }
public var addStaffToDevelopersGroup: (String?) -> Promise<ProcessOutput> = { Process.sudo(password: $0, Path.root.usr.sbin.dseditgroup, "-o", "edit", "-t", "group", "-a", "staff", "_developer") }
public var acceptXcodeLicense: (InstalledXcode, String?) -> Promise<ProcessOutput> = { Process.sudo(password: $1, $0.path.join("/Contents/Developer/usr/bin/xcodebuild"), "-license", "accept") }
public var runFirstLaunch: (InstalledXcode, String?) -> Promise<ProcessOutput> = { Process.sudo(password: $1, $0.path.join("/Contents/Developer/usr/bin/xcodebuild"),"-runFirstLaunch") }
public var buildVersion: () -> Promise<ProcessOutput> = { Process.run(Path.root.usr.bin.sw_vers, "-buildVersion") }
public var xcodeBuildVersion: (InstalledXcode) -> Promise<ProcessOutput> = { Process.run(Path.root.usr.libexec.PlistBuddy, "-c", "Print :ProductBuildVersion", "\($0.path.string)/Contents/version.plist") }
public var getUserCacheDir: () -> Promise<ProcessOutput> = { Process.run(Path.root.usr.bin.getconf, "DARWIN_USER_CACHE_DIR") }
public var touchInstallCheck: (String, String, String) -> Promise<ProcessOutput> = { Process.run(Path.root.usr.bin/"touch", "\($0)com.apple.dt.Xcode.InstallCheckCache_\($1)_\($2)") }
public var validateSudoAuthentication: () -> Promise<ProcessOutput> = { Process.run(Path.root.usr.bin.sudo, "-nv") }
public var authenticateSudoerIfNecessary: (@escaping () -> Promise<String>) -> Promise<String?> = { passwordInput in
firstly { () -> Promise<String?> in
Current.shell.validateSudoAuthentication().map { _ in return nil }
}
.recover { _ -> Promise<String?> in
return passwordInput().map(Optional.init)
}
}
public func authenticateSudoerIfNecessary(passwordInput: @escaping () -> Promise<String>) -> Promise<String?> {
authenticateSudoerIfNecessary(passwordInput)
}
public var unxip: (URL) -> AnyPublisher<ProcessOutput, Error> = { Process.run(Path.root.usr.bin.xip, workingDirectory: $0.deletingLastPathComponent(), "--expand", "\($0.path)") }
public var spctlAssess: (URL) -> AnyPublisher<ProcessOutput, Error> = { Process.run(Path.root.usr.sbin.spctl, "--assess", "--verbose", "--type", "execute", "\($0.path)") }
public var codesignVerify: (URL) -> AnyPublisher<ProcessOutput, Error> = { Process.run(Path.root.usr.bin.codesign, "-vv", "-d", "\($0.path)") }
public var buildVersion: () -> AnyPublisher<ProcessOutput, Error> = { Process.run(Path.root.usr.bin.sw_vers, "-buildVersion") }
public var xcodeBuildVersion: (InstalledXcode) -> AnyPublisher<ProcessOutput, Error> = { Process.run(Path.root.usr.libexec.PlistBuddy, "-c", "Print :ProductBuildVersion", "\($0.path.string)/Contents/version.plist") }
public var getUserCacheDir: () -> AnyPublisher<ProcessOutput, Error> = { Process.run(Path.root.usr.bin.getconf, "DARWIN_USER_CACHE_DIR") }
public var touchInstallCheck: (String, String, String) -> AnyPublisher<ProcessOutput, Error> = { Process.run(Path.root.usr.bin/"touch", "\($0)com.apple.dt.Xcode.InstallCheckCache_\($1)_\($2)") }
public var xcodeSelectPrintPath: () -> AnyPublisher<ProcessOutput, Error> = { Process.run(Path.root.usr.bin.join("xcode-select"), "-p") }
}
@ -115,10 +96,10 @@ public struct Network {
dataTask(request)
}
public var downloadTask: (URLRequestConvertible, URL, Data?) -> (Progress, Promise<(saveLocation: URL, response: URLResponse)>) = { AppleAPI.Current.network.session.downloadTask(with: $0, to: $1, resumingWith: $2) }
public func downloadTask(with convertible: URLRequestConvertible, to saveLocation: URL, resumingWith resumeData: Data?) -> (progress: Progress, promise: Promise<(saveLocation: URL, response: URLResponse)>) {
return downloadTask(convertible, saveLocation, resumeData)
public var downloadTask: (URL, URL, Data?) -> (Progress, AnyPublisher<(saveLocation: URL, response: URLResponse), Error>) = { AppleAPI.Current.network.session.downloadTask(with: $0, to: $1, resumingWith: $2) }
public func downloadTask(with url: URL, to saveLocation: URL, resumingWith resumeData: Data?) -> (progress: Progress, publisher: AnyPublisher<(saveLocation: URL, response: URLResponse), Error>) {
return downloadTask(url, saveLocation, resumeData)
}
}

View file

@ -1,45 +1,10 @@
import Combine
import Foundation
import PromiseKit
import PMKFoundation
import Path
public typealias ProcessOutput = (status: Int32, out: String, err: String)
extension Process {
@discardableResult
static func sudo(password: String? = nil, _ executable: Path, workingDirectory: URL? = nil, _ arguments: String...) -> Promise<ProcessOutput> {
var arguments = [executable.string] + arguments
if password != nil {
arguments.insert("-S", at: 0)
}
return run(Path.root.usr.bin.sudo.url, workingDirectory: workingDirectory, input: password, arguments)
}
@discardableResult
static func run(_ executable: Path, workingDirectory: URL? = nil, input: String? = nil, _ arguments: String...) -> Promise<ProcessOutput> {
return run(executable.url, workingDirectory: workingDirectory, input: input, arguments)
}
@discardableResult
static func run(_ executable: URL, workingDirectory: URL? = nil, input: String? = nil, _ arguments: [String]) -> Promise<ProcessOutput> {
let process = Process()
process.currentDirectoryURL = workingDirectory ?? executable.deletingLastPathComponent()
process.executableURL = executable
process.arguments = arguments
if let input = input {
let inputPipe = Pipe()
process.standardInput = inputPipe.fileHandleForReading
inputPipe.fileHandleForWriting.write(Data(input.utf8))
inputPipe.fileHandleForWriting.closeFile()
}
return process.launch(.promise).map { std in
let output = String(data: std.out.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? ""
let error = String(data: std.err.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? ""
return (process.terminationStatus, output, error)
}
}
extension Process {
@discardableResult
static func run(_ executable: Path, workingDirectory: URL? = nil, input: String? = nil, _ arguments: String...) -> AnyPublisher<ProcessOutput, Error> {
return run(executable.url, workingDirectory: workingDirectory, input: input, arguments)
@ -71,6 +36,10 @@ extension Process {
let output = String(data: stdout.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? ""
let error = String(data: stderr.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? ""
guard process.terminationReason == .exit, process.terminationStatus == 0 else {
return promise(.failure(ProcessExecutionError(process: process, standardOutput: output, standardError: error)))
}
promise(.success((process.terminationStatus, output, error)))
} catch {
@ -83,3 +52,9 @@ extension Process {
.eraseToAnyPublisher()
}
}
struct ProcessExecutionError: Error {
let process: Process
let standardOutput: String
let standardError: String
}

View file

@ -1,40 +0,0 @@
import Foundation
import PromiseKit
/// Attempt and retry a task that fails with resume data up to `maximumRetryCount` times
func attemptResumableTask<T>(
maximumRetryCount: Int = 3,
delayBeforeRetry: DispatchTimeInterval = .seconds(2),
_ body: @escaping (Data?) -> Promise<T>
) -> Promise<T> {
var attempts = 0
func attempt(with resumeData: Data? = nil) -> Promise<T> {
attempts += 1
return body(resumeData).recover { error -> Promise<T> in
guard
attempts < maximumRetryCount,
let resumeData = (error as NSError).userInfo[NSURLSessionDownloadTaskResumeData] as? Data
else { throw error }
return after(delayBeforeRetry).then(on: nil) { attempt(with: resumeData) }
}
}
return attempt()
}
/// Attempt and retry a task up to `maximumRetryCount` times
func attemptRetryableTask<T>(
maximumRetryCount: Int = 3,
delayBeforeRetry: DispatchTimeInterval = .seconds(2),
_ body: @escaping () -> Promise<T>
) -> Promise<T> {
var attempts = 0
func attempt() -> Promise<T> {
attempts += 1
return body().recover { error -> Promise<T> in
guard attempts < maximumRetryCount else { throw error }
return after(delayBeforeRetry).then(on: nil) { attempt() }
}
}
return attempt()
}

View file

@ -1,6 +1,5 @@
import Combine
import Foundation
import PromiseKit
import PMKFoundation
extension URLSession {
/**
@ -8,40 +7,47 @@ extension URLSession {
- Parameter saveLocation: A URL to move the downloaded file to after it completes. Apple deletes the temporary file immediately after the underyling completion handler returns.
- Parameter resumeData: Data describing the state of a previously cancelled or failed download task. See the Discussion section for `downloadTask(withResumeData:completionHandler:)` https://developer.apple.com/documentation/foundation/urlsession/1411598-downloadtask#
- Returns: Tuple containing a Progress object for the task and a promise containing the save location and response.
- Returns: Tuple containing a Progress object for the task and a publisher of the save location and response.
- Note: We do not create the destination directory for you, because we move the file with FileManager.moveItem which changes its behavior depending on the directory status of the URL you provide. So create your own directory first!
*/
public func downloadTask(with convertible: URLRequestConvertible, to saveLocation: URL, resumingWith resumeData: Data?) -> (progress: Progress, promise: Promise<(saveLocation: URL, response: URLResponse)>) {
public func downloadTask(
with url: URL,
to saveLocation: URL,
resumingWith resumeData: Data?
) -> (progress: Progress, publisher: AnyPublisher<(saveLocation: URL, response: URLResponse), Error>) {
var progress: Progress!
let promise = Promise<(saveLocation: URL, response: URLResponse)> { seal in
// Intentionally not wrapping in Deferred because we need to return the Progress! immediately.
// Probably a sign that this should be implemented differently...
let promise = Future<(saveLocation: URL, response: URLResponse), Error> { promise in
let completionHandler = { (temporaryURL: URL?, response: URLResponse?, error: Error?) in
if let error = error {
seal.reject(error)
promise(.failure(error))
} else if let response = response, let temporaryURL = temporaryURL {
do {
try FileManager.default.moveItem(at: temporaryURL, to: saveLocation)
seal.fulfill((saveLocation, response))
promise(.success((saveLocation, response)))
} catch {
seal.reject(error)
promise(.failure(error))
}
} else {
seal.reject(PMKError.invalidCallingConvention)
fatalError("Expecting either a temporary URL and a response, or an error, but got neither.")
}
}
let task: URLSessionDownloadTask
if let resumeData = resumeData {
task = downloadTask(withResumeData: resumeData, completionHandler: completionHandler)
task = self.downloadTask(withResumeData: resumeData, completionHandler: completionHandler)
}
else {
task = downloadTask(with: convertible.pmkRequest, completionHandler: completionHandler)
task = self.downloadTask(with: url, completionHandler: completionHandler)
}
progress = task.progress
task.resume()
}
.eraseToAnyPublisher()
return (progress, promise)
}
}
}

View file

@ -1,6 +1,5 @@
import SwiftUI
import Version
import PromiseKit
struct XcodeListView: View {
@EnvironmentObject var appState: AppState

View file

@ -4,33 +4,7 @@
{\*\expandedcolortbl;;}
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
\f0\fs34 \cf0 PromiseKit\
\
\fs26 Copyright 2016-present, Max Howell; mxcl@me.com\
\
Permission is hereby granted, free of charge, to any person obtaining a\
copy of this software and associated documentation files (the\
"Software"), to deal in the Software without restriction, including\
without limitation the rights to use, copy, modify, merge, publish,\
distribute, sublicense, and/or sell copies of the Software, and to\
permit persons to whom the Software is furnished to do so, subject to\
the following conditions:\
\
The above copyright notice and this permission notice shall be included\
in all copies or substantial portions of the Software.\
\
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\
\
\
\fs34 SwiftSoup\
\f0\fs34 \cf0 SwiftSoup\
\
\fs26 MIT License\
@ -57,32 +31,6 @@ SOFTWARE.\
\
\
\fs34 Foundation\
\
\fs26 Copyright 2018-present, Max Howell; mxcl@me.com\
\
Permission is hereby granted, free of charge, to any person obtaining a\
copy of this software and associated documentation files (the\
"Software"), to deal in the Software without restriction, including\
without limitation the rights to use, copy, modify, merge, publish,\
distribute, sublicense, and/or sell copies of the Software, and to\
permit persons to whom the Software is furnished to do so, subject to\
the following conditions:\
\
The above copyright notice and this permission notice shall be included\
in all copies or substantial portions of the Software.\
\
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\
\
\
\fs34 Path.swift\
\