mirror of
https://github.com/XcodesOrg/XcodesApp.git
synced 2026-03-25 08:55:46 +00:00
Merge pull request #38 from RobotsAndPencils/remove-promisekit
Remove PromiseKit
This commit is contained in:
commit
ba1c4fec0f
8 changed files with 47 additions and 232 deletions
|
|
@ -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" */;
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
import SwiftUI
|
||||
import Version
|
||||
import PromiseKit
|
||||
|
||||
struct XcodeListView: View {
|
||||
@EnvironmentObject var appState: AppState
|
||||
|
|
|
|||
|
|
@ -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\
|
||||
\
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue