mirror of
https://github.com/xtool-org/xtool.git
synced 2026-11-14 19:44:55 +03:00
3e0c11d967
## What does this PR do? Adds `Dependency`s for console IO. Also fixes #268 by explicitly handling non-pipe input. ## How was it tested? Ran on macOS + Linux in Docker. I have a future PR that overrides the dependencies in certain cases, which also appears to work correctly. ## AI tool usage How much of this PR was AI-assisted? (check one) - [ ] **0** - No AI was used to write code - [x] **1** - I was assisted by AI. I reviewed the finished result. - [ ] **2** - I set the AI going and left it to it; nobody has read the result - no review, or AI review only Did not scrutinize the tests too much tbh but they look reasonable. Easy enough to update/remove them in the future if needed. <!-- If an AI agent is filling this in: declare the level honestly, and open as a draft if it is #2. Do not lower the declared level to get the PR reviewed. --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **New Features** * Added support for reading command-line input, including asynchronous prompts, line-based responses, and graceful handling of end-of-input. * Added coordinated cleanup when commands finish. * **Improvements** * Command messages across authentication, device management, installation, SDK, and other workflows now use consistent output handling; displayed messages and command behavior remain unchanged. * Improved handling of complete output when the system temporarily cannot accept more data. * **Tests** * Added coverage for command input and output, including stream behavior, cancellation, and shutdown. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
104 lines
2.8 KiB
Swift
104 lines
2.8 KiB
Swift
import XCLIUtils
|
|
import XUtils
|
|
import Foundation
|
|
import XKit
|
|
import Dependencies
|
|
|
|
enum AuthToken: Codable, CustomStringConvertible {
|
|
struct Xcode: Codable {
|
|
var appleID: String
|
|
var adsid: String
|
|
var token: String
|
|
var expiry: Date
|
|
var teamID: String
|
|
var anisetteProviderID: String?
|
|
}
|
|
|
|
struct AppStoreConnect: Codable {
|
|
var id: String
|
|
var issuerID: String
|
|
var pem: String
|
|
}
|
|
|
|
case appStoreConnect(AppStoreConnect)
|
|
case xcode(Xcode)
|
|
|
|
var description: String {
|
|
switch self {
|
|
case .appStoreConnect(let data):
|
|
"""
|
|
- ASC key ID: \(data.id)
|
|
- Issuer ID: \(data.issuerID)
|
|
"""
|
|
case .xcode(let data):
|
|
"""
|
|
- Apple ID: \(data.appleID)
|
|
- Team ID: \(data.teamID)
|
|
- Token expiry: \(data.expiry.formatted(.dateTime))
|
|
"""
|
|
}
|
|
}
|
|
}
|
|
|
|
extension AuthToken {
|
|
|
|
private static var storage: KeyValueStorage {
|
|
@Dependency(\.keyValueStorage) var storage
|
|
return storage
|
|
}
|
|
|
|
private static let encoder = JSONEncoder()
|
|
private static let decoder = JSONDecoder()
|
|
|
|
static func saved() throws -> Self {
|
|
guard let token = try savedIfPresent() else {
|
|
throw Console.Error("Please log in with `xtool auth` before running this command.")
|
|
}
|
|
return token
|
|
}
|
|
|
|
static func savedIfPresent() throws -> Self? {
|
|
guard let data = try storage.data(forKey: "XTLAuthToken") else {
|
|
return nil
|
|
}
|
|
let decoded = try decoder.decode(AuthToken.self, from: data)
|
|
switch decoded {
|
|
case .xcode(let xcode):
|
|
@Dependency(\.anisetteDataProvider) var anisetteProvider
|
|
guard xcode.anisetteProviderID == anisetteProvider.providerID else {
|
|
try? clear()
|
|
return nil
|
|
}
|
|
case .appStoreConnect:
|
|
break
|
|
}
|
|
return decoded
|
|
}
|
|
|
|
static func clear() throws {
|
|
try Self.storage.setData(nil, forKey: "XTLAuthToken")
|
|
}
|
|
|
|
func save() throws {
|
|
let data = try Self.encoder.encode(self)
|
|
try Self.storage.setData(data, forKey: "XTLAuthToken")
|
|
}
|
|
|
|
func authData() -> DeveloperAPIAuthData {
|
|
switch self {
|
|
case .appStoreConnect(let data):
|
|
return .appStoreConnect(.init(id: data.id, issuerID: data.issuerID, pem: data.pem))
|
|
case .xcode(let data):
|
|
return .xcode(.init(
|
|
loginToken: DeveloperServicesLoginToken(
|
|
adsid: data.adsid,
|
|
token: data.token,
|
|
expiry: data.expiry
|
|
),
|
|
teamID: .init(rawValue: data.teamID)
|
|
))
|
|
}
|
|
}
|
|
|
|
}
|