Files
Leeksov 4647310322 GLEGram 12.5 — Initial public release
Based on Swiftgram 12.5 (Telegram iOS 12.5).
All GLEGram features ported and organized in GLEGram/ folder.

Features: Ghost Mode, Saved Deleted Messages, Content Protection Bypass,
Font Replacement, Fake Profile, Chat Export, Plugin System, and more.

See CHANGELOG_12.5.md for full details.
2026-04-06 09:48:12 +03:00

1017 lines
40 KiB
Swift

import Foundation
import JSONUtilities
import PathKit
import XcodeProj
public typealias BuildType = XCScheme.BuildAction.Entry.BuildFor
public struct Scheme: Equatable {
public var name: String
public var build: Build
public var run: Run?
public var archive: Archive?
public var analyze: Analyze?
public var test: Test?
public var profile: Profile?
public var management: Management?
public init(
name: String,
build: Build,
run: Run? = nil,
test: Test? = nil,
profile: Profile? = nil,
analyze: Analyze? = nil,
archive: Archive? = nil,
management: Management? = nil
) {
self.name = name
self.build = build
self.run = run
self.test = test
self.profile = profile
self.analyze = analyze
self.archive = archive
self.management = management
}
public struct Management: Equatable {
public static let sharedDefault = true
public var shared: Bool
public var orderHint: Int?
public var isShown: Bool?
public init?(
shared: Bool = Scheme.Management.sharedDefault,
orderHint: Int? = nil,
isShown: Bool? = nil
) {
if shared == Scheme.Management.sharedDefault, orderHint == nil, isShown == nil {
return nil
}
self.shared = shared
self.orderHint = orderHint
self.isShown = isShown
}
}
public struct SimulateLocation: Equatable {
public enum ReferenceType: String {
case predefined = "1"
case gpx = "0"
}
public var allow: Bool
public var defaultLocation: String?
public var referenceType: ReferenceType? {
guard let defaultLocation = self.defaultLocation else {
return nil
}
if defaultLocation.contains(".gpx") {
return .gpx
}
return .predefined
}
public init(allow: Bool, defaultLocation: String) {
self.allow = allow
self.defaultLocation = defaultLocation
}
}
public struct ExecutionAction: Equatable {
public var script: String
public var name: String
public var settingsTarget: String?
public var shell: String?
public init(name: String, script: String, shell: String? = nil, settingsTarget: String? = nil) {
self.script = script
self.name = name
self.settingsTarget = settingsTarget
self.shell = shell
}
}
public struct Build: Equatable {
public static let parallelizeBuildDefault = true
public static let buildImplicitDependenciesDefault = true
public static let runPostActionsOnFailureDefault = false
public var targets: [BuildTarget]
public var parallelizeBuild: Bool
public var buildImplicitDependencies: Bool
public var preActions: [ExecutionAction]
public var postActions: [ExecutionAction]
public var runPostActionsOnFailure: Bool
public init(
targets: [BuildTarget],
parallelizeBuild: Bool = parallelizeBuildDefault,
buildImplicitDependencies: Bool = buildImplicitDependenciesDefault,
preActions: [ExecutionAction] = [],
postActions: [ExecutionAction] = [],
runPostActionsOnFailure: Bool = false
) {
self.targets = targets
self.parallelizeBuild = parallelizeBuild
self.buildImplicitDependencies = buildImplicitDependencies
self.preActions = preActions
self.postActions = postActions
self.runPostActionsOnFailure = runPostActionsOnFailure
}
}
public struct Run: BuildAction {
public static let disableMainThreadCheckerDefault = false
public static let stopOnEveryMainThreadCheckerIssueDefault = false
public static let disableThreadPerformanceCheckerDefault = false
public static let debugEnabledDefault = true
public static let enableGPUValidationModeDefault = true
public var config: String?
public var commandLineArguments: [String: Bool]
public var preActions: [ExecutionAction]
public var postActions: [ExecutionAction]
public var environmentVariables: [XCScheme.EnvironmentVariable]
public var enableGPUFrameCaptureMode: XCScheme.LaunchAction.GPUFrameCaptureMode
public var enableGPUValidationMode: Bool
public var disableMainThreadChecker: Bool
public var stopOnEveryMainThreadCheckerIssue: Bool
public var disableThreadPerformanceChecker: Bool
public var language: String?
public var region: String?
public var askForAppToLaunch: Bool?
public var launchAutomaticallySubstyle: String?
public var debugEnabled: Bool
public var simulateLocation: SimulateLocation?
public var executable: String?
public var storeKitConfiguration: String?
public var customLLDBInit: String?
public var macroExpansion: String?
public init(
config: String? = nil,
executable: String? = nil,
commandLineArguments: [String: Bool] = [:],
preActions: [ExecutionAction] = [],
postActions: [ExecutionAction] = [],
environmentVariables: [XCScheme.EnvironmentVariable] = [],
enableGPUFrameCaptureMode: XCScheme.LaunchAction.GPUFrameCaptureMode = XCScheme.LaunchAction.defaultGPUFrameCaptureMode,
enableGPUValidationMode: Bool = enableGPUValidationModeDefault,
disableMainThreadChecker: Bool = disableMainThreadCheckerDefault,
stopOnEveryMainThreadCheckerIssue: Bool = stopOnEveryMainThreadCheckerIssueDefault,
disableThreadPerformanceChecker: Bool = disableThreadPerformanceCheckerDefault,
language: String? = nil,
region: String? = nil,
askForAppToLaunch: Bool? = nil,
launchAutomaticallySubstyle: String? = nil,
debugEnabled: Bool = debugEnabledDefault,
simulateLocation: SimulateLocation? = nil,
storeKitConfiguration: String? = nil,
customLLDBInit: String? = nil,
macroExpansion: String? = nil
) {
self.config = config
self.commandLineArguments = commandLineArguments
self.preActions = preActions
self.postActions = postActions
self.environmentVariables = environmentVariables
self.disableMainThreadChecker = disableMainThreadChecker
self.enableGPUFrameCaptureMode = enableGPUFrameCaptureMode
self.enableGPUValidationMode = enableGPUValidationMode
self.stopOnEveryMainThreadCheckerIssue = stopOnEveryMainThreadCheckerIssue
self.disableThreadPerformanceChecker = disableThreadPerformanceChecker
self.language = language
self.region = region
self.askForAppToLaunch = askForAppToLaunch
self.launchAutomaticallySubstyle = launchAutomaticallySubstyle
self.debugEnabled = debugEnabled
self.simulateLocation = simulateLocation
self.storeKitConfiguration = storeKitConfiguration
self.customLLDBInit = customLLDBInit
self.macroExpansion = macroExpansion
}
}
public struct Test: BuildAction {
public static let gatherCoverageDataDefault = false
public static let disableMainThreadCheckerDefault = false
public static let debugEnabledDefault = true
public static let captureScreenshotsAutomaticallyDefault = true
public static let deleteScreenshotsWhenEachTestSucceedsDefault = true
public static let preferredScreenCaptureFormatDefault = XCScheme.TestAction.ScreenCaptureFormat.screenRecording
public var config: String?
public var gatherCoverageData: Bool
public var coverageTargets: [TestableTargetReference]
public var disableMainThreadChecker: Bool
public var commandLineArguments: [String: Bool]
public var targets: [TestTarget]
public var preActions: [ExecutionAction]
public var postActions: [ExecutionAction]
public var environmentVariables: [XCScheme.EnvironmentVariable]
public var language: String?
public var region: String?
public var debugEnabled: Bool
public var customLLDBInit: String?
public var captureScreenshotsAutomatically: Bool
public var deleteScreenshotsWhenEachTestSucceeds: Bool
public var testPlans: [TestPlan]
public var macroExpansion: String?
public var preferredScreenCaptureFormat: XCScheme.TestAction.ScreenCaptureFormat
public struct TestTarget: Equatable, ExpressibleByStringLiteral {
public static let randomExecutionOrderDefault = false
public static let parallelizableDefault = false
public var name: String { targetReference.name }
public let targetReference: TestableTargetReference
public var randomExecutionOrder: Bool
public var parallelizable: Bool
public var location: String?
public var skipped: Bool
public var skippedTests: [String]
public var selectedTests: [String]
public init(
targetReference: TestableTargetReference,
randomExecutionOrder: Bool = randomExecutionOrderDefault,
parallelizable: Bool = parallelizableDefault,
location: String? = nil,
skipped: Bool = false,
skippedTests: [String] = [],
selectedTests: [String] = []
) {
self.targetReference = targetReference
self.randomExecutionOrder = randomExecutionOrder
self.parallelizable = parallelizable
self.location = location
self.skipped = skipped
self.skippedTests = skippedTests
self.selectedTests = selectedTests
}
public init(stringLiteral value: String) {
do {
targetReference = try TestableTargetReference(value)
randomExecutionOrder = false
parallelizable = false
location = nil
skipped = false
skippedTests = []
selectedTests = []
} catch {
fatalError(SpecParsingError.invalidTargetReference(value).description)
}
}
}
public init(
config: String? = nil,
gatherCoverageData: Bool = gatherCoverageDataDefault,
coverageTargets: [TestableTargetReference] = [],
disableMainThreadChecker: Bool = disableMainThreadCheckerDefault,
randomExecutionOrder: Bool = false,
parallelizable: Bool = false,
commandLineArguments: [String: Bool] = [:],
targets: [TestTarget] = [],
preActions: [ExecutionAction] = [],
postActions: [ExecutionAction] = [],
environmentVariables: [XCScheme.EnvironmentVariable] = [],
testPlans: [TestPlan] = [],
language: String? = nil,
region: String? = nil,
debugEnabled: Bool = debugEnabledDefault,
customLLDBInit: String? = nil,
captureScreenshotsAutomatically: Bool = captureScreenshotsAutomaticallyDefault,
deleteScreenshotsWhenEachTestSucceeds: Bool = deleteScreenshotsWhenEachTestSucceedsDefault,
macroExpansion: String? = nil,
preferredScreenCaptureFormat: XCScheme.TestAction.ScreenCaptureFormat = preferredScreenCaptureFormatDefault
) {
self.config = config
self.gatherCoverageData = gatherCoverageData
self.coverageTargets = coverageTargets
self.disableMainThreadChecker = disableMainThreadChecker
self.commandLineArguments = commandLineArguments
self.targets = targets
self.preActions = preActions
self.postActions = postActions
self.environmentVariables = environmentVariables
self.testPlans = testPlans
self.language = language
self.region = region
self.debugEnabled = debugEnabled
self.customLLDBInit = customLLDBInit
self.captureScreenshotsAutomatically = captureScreenshotsAutomatically
self.deleteScreenshotsWhenEachTestSucceeds = deleteScreenshotsWhenEachTestSucceeds
self.macroExpansion = macroExpansion
self.preferredScreenCaptureFormat = preferredScreenCaptureFormat
}
public var shouldUseLaunchSchemeArgsEnv: Bool {
commandLineArguments.isEmpty && environmentVariables.isEmpty
}
}
public struct Analyze: BuildAction {
public var config: String?
public init(config: String) {
self.config = config
}
}
public struct Profile: BuildAction {
public var config: String?
public var commandLineArguments: [String: Bool]
public var preActions: [ExecutionAction]
public var postActions: [ExecutionAction]
public var environmentVariables: [XCScheme.EnvironmentVariable]
public var askForAppToLaunch: Bool?
public init(
config: String? = nil,
commandLineArguments: [String: Bool] = [:],
preActions: [ExecutionAction] = [],
postActions: [ExecutionAction] = [],
environmentVariables: [XCScheme.EnvironmentVariable] = [],
askForAppToLaunch: Bool? = nil
) {
self.config = config
self.commandLineArguments = commandLineArguments
self.preActions = preActions
self.postActions = postActions
self.environmentVariables = environmentVariables
self.askForAppToLaunch = askForAppToLaunch
}
public var shouldUseLaunchSchemeArgsEnv: Bool {
commandLineArguments.isEmpty && environmentVariables.isEmpty
}
}
public struct Archive: BuildAction {
public static let revealArchiveInOrganizerDefault = true
public var config: String?
public var customArchiveName: String?
public var revealArchiveInOrganizer: Bool
public var preActions: [ExecutionAction]
public var postActions: [ExecutionAction]
public init(
config: String? = nil,
customArchiveName: String? = nil,
revealArchiveInOrganizer: Bool = revealArchiveInOrganizerDefault,
preActions: [ExecutionAction] = [],
postActions: [ExecutionAction] = []
) {
self.config = config
self.customArchiveName = customArchiveName
self.revealArchiveInOrganizer = revealArchiveInOrganizer
self.preActions = preActions
self.postActions = postActions
}
}
public struct BuildTarget: Equatable, Hashable {
public var target: TestableTargetReference
public var buildTypes: [BuildType]
public init(target: TestableTargetReference, buildTypes: [BuildType] = BuildType.all) {
self.target = target
self.buildTypes = buildTypes
}
}
}
extension Scheme: PathContainer {
static var pathProperties: [PathProperty] {
[
.dictionary([
.object("test", Test.pathProperties),
]),
]
}
}
protocol BuildAction: Equatable {
var config: String? { get }
}
extension Scheme.ExecutionAction: JSONObjectConvertible {
public init(jsonDictionary: JSONDictionary) throws {
script = try jsonDictionary.json(atKeyPath: "script")
name = jsonDictionary.json(atKeyPath: "name") ?? "Run Script"
settingsTarget = jsonDictionary.json(atKeyPath: "settingsTarget")
shell = jsonDictionary.json(atKeyPath: "shell")
}
}
extension Scheme.ExecutionAction: JSONEncodable {
public func toJSONValue() -> Any {
[
"script": script,
"name": name,
"settingsTarget": settingsTarget,
"shell": shell
]
}
}
extension Scheme.SimulateLocation: JSONObjectConvertible {
public init(jsonDictionary: JSONDictionary) throws {
allow = try jsonDictionary.json(atKeyPath: "allow")
defaultLocation = jsonDictionary.json(atKeyPath: "defaultLocation")
}
}
extension Scheme.SimulateLocation: JSONEncodable {
public func toJSONValue() -> Any {
var dict: [String: Any] = [
"allow": allow,
]
if let defaultLocation = defaultLocation {
dict["defaultLocation"] = defaultLocation
}
return dict
}
}
extension Scheme.Management: JSONObjectConvertible {
public init(jsonDictionary: JSONDictionary) throws {
shared = jsonDictionary.json(atKeyPath: "shared") ?? Scheme.Management.sharedDefault
orderHint = jsonDictionary.json(atKeyPath: "orderHint")
isShown = jsonDictionary.json(atKeyPath: "isShown")
}
}
extension Scheme.Management: JSONEncodable {
public func toJSONValue() -> Any {
var dict: [String: Any?] = [:]
if shared != Scheme.Management.sharedDefault {
dict["shared"] = shared
}
if let isShown = isShown {
dict["isShown"] = isShown
}
if let orderHint = orderHint {
dict["orderHint"] = orderHint
}
return dict
}
}
extension Scheme.Run: JSONObjectConvertible {
public init(jsonDictionary: JSONDictionary) throws {
config = jsonDictionary.json(atKeyPath: "config")
commandLineArguments = jsonDictionary.json(atKeyPath: "commandLineArguments") ?? [:]
preActions = jsonDictionary.json(atKeyPath: "preActions") ?? []
postActions = jsonDictionary.json(atKeyPath: "postActions") ?? []
environmentVariables = try XCScheme.EnvironmentVariable.parseAll(jsonDictionary: jsonDictionary)
if let gpuFrameCaptureMode: String = jsonDictionary.json(atKeyPath: "enableGPUFrameCaptureMode") {
enableGPUFrameCaptureMode = XCScheme.LaunchAction.GPUFrameCaptureMode.fromJSONValue(gpuFrameCaptureMode)
} else {
enableGPUFrameCaptureMode = XCScheme.LaunchAction.defaultGPUFrameCaptureMode
}
// support deprecated gpuValidationMode enum that was removed from XcodeProj
if let gpuValidationMode: String = jsonDictionary.json(atKeyPath: "enableGPUValidationMode") {
switch gpuValidationMode {
case "enabled", "extended": enableGPUValidationMode = true
case "disabled": enableGPUValidationMode = false
default: enableGPUValidationMode = Scheme.Run.enableGPUValidationModeDefault
}
} else {
enableGPUValidationMode = jsonDictionary.json(atKeyPath: "enableGPUValidationMode") ?? Scheme.Run.enableGPUValidationModeDefault
}
disableMainThreadChecker = jsonDictionary.json(atKeyPath: "disableMainThreadChecker") ?? Scheme.Run.disableMainThreadCheckerDefault
stopOnEveryMainThreadCheckerIssue = jsonDictionary.json(atKeyPath: "stopOnEveryMainThreadCheckerIssue") ?? Scheme.Run.stopOnEveryMainThreadCheckerIssueDefault
disableThreadPerformanceChecker = jsonDictionary.json(atKeyPath: "disableThreadPerformanceChecker") ?? Scheme.Run.disableThreadPerformanceCheckerDefault
language = jsonDictionary.json(atKeyPath: "language")
region = jsonDictionary.json(atKeyPath: "region")
debugEnabled = jsonDictionary.json(atKeyPath: "debugEnabled") ?? Scheme.Run.debugEnabledDefault
simulateLocation = jsonDictionary.json(atKeyPath: "simulateLocation")
storeKitConfiguration = jsonDictionary.json(atKeyPath: "storeKitConfiguration")
executable = jsonDictionary.json(atKeyPath: "executable")
// launchAutomaticallySubstyle is defined as a String in XcodeProj but its value is often
// an integer. Parse both to be nice.
if let int: Int = jsonDictionary.json(atKeyPath: "launchAutomaticallySubstyle") {
launchAutomaticallySubstyle = String(int)
} else if let string: String = jsonDictionary.json(atKeyPath: "launchAutomaticallySubstyle") {
launchAutomaticallySubstyle = string
}
if let askLaunch: Bool = jsonDictionary.json(atKeyPath: "askForAppToLaunch") {
askForAppToLaunch = askLaunch
}
customLLDBInit = jsonDictionary.json(atKeyPath: "customLLDBInit")
macroExpansion = jsonDictionary.json(atKeyPath: "macroExpansion")
}
}
extension Scheme.Run: JSONEncodable {
public func toJSONValue() -> Any {
var dict: [String: Any?] = [
"commandLineArguments": commandLineArguments,
"preActions": preActions.map { $0.toJSONValue() },
"postActions": postActions.map { $0.toJSONValue() },
"environmentVariables": environmentVariables.map { $0.toJSONValue() },
"config": config,
"language": language,
"region": region,
"askForAppToLaunch": askForAppToLaunch,
"launchAutomaticallySubstyle": launchAutomaticallySubstyle,
"executable": executable,
"macroExpansion": macroExpansion
]
if enableGPUFrameCaptureMode != XCScheme.LaunchAction.defaultGPUFrameCaptureMode {
dict["enableGPUFrameCaptureMode"] = enableGPUFrameCaptureMode.toJSONValue()
}
if enableGPUValidationMode != Scheme.Run.enableGPUValidationModeDefault {
dict["enableGPUValidationMode"] = enableGPUValidationMode
}
if disableMainThreadChecker != Scheme.Run.disableMainThreadCheckerDefault {
dict["disableMainThreadChecker"] = disableMainThreadChecker
}
if stopOnEveryMainThreadCheckerIssue != Scheme.Run.stopOnEveryMainThreadCheckerIssueDefault {
dict["stopOnEveryMainThreadCheckerIssue"] = stopOnEveryMainThreadCheckerIssue
}
if disableThreadPerformanceChecker != Scheme.Run.disableThreadPerformanceCheckerDefault {
dict["disableThreadPerformanceChecker"] = disableThreadPerformanceChecker
}
if debugEnabled != Scheme.Run.debugEnabledDefault {
dict["debugEnabled"] = debugEnabled
}
if let simulateLocation = simulateLocation {
dict["simulateLocation"] = simulateLocation.toJSONValue()
}
if let storeKitConfiguration = storeKitConfiguration {
dict["storeKitConfiguration"] = storeKitConfiguration
}
if let customLLDBInit = customLLDBInit {
dict["customLLDBInit"] = customLLDBInit
}
return dict
}
}
extension Scheme.Test: PathContainer {
static var pathProperties: [PathProperty] {
[
.object("testPlans", TestPlan.pathProperties),
]
}
}
extension Scheme.Test: JSONObjectConvertible {
public init(jsonDictionary: JSONDictionary) throws {
config = jsonDictionary.json(atKeyPath: "config")
gatherCoverageData = jsonDictionary.json(atKeyPath: "gatherCoverageData") ?? Scheme.Test.gatherCoverageDataDefault
if let coverages = jsonDictionary["coverageTargets"] as? [Any] {
coverageTargets = try coverages.compactMap { target in
if let string = target as? String {
return try TestableTargetReference(string)
} else if let dictionary = target as? JSONDictionary,
let target: TestableTargetReference = try? .init(jsonDictionary: dictionary) {
return target
} else {
return nil
}
}
} else {
coverageTargets = []
}
disableMainThreadChecker = jsonDictionary.json(atKeyPath: "disableMainThreadChecker") ?? Scheme.Test.disableMainThreadCheckerDefault
commandLineArguments = jsonDictionary.json(atKeyPath: "commandLineArguments") ?? [:]
if let targets = jsonDictionary["targets"] as? [Any] {
self.targets = try targets.compactMap { target in
if let string = target as? String {
return try TestTarget(targetReference: TestableTargetReference(string))
} else if let dictionary = target as? JSONDictionary {
return try TestTarget(jsonDictionary: dictionary)
} else {
return nil
}
}
} else {
targets = []
}
preActions = jsonDictionary.json(atKeyPath: "preActions") ?? []
postActions = jsonDictionary.json(atKeyPath: "postActions") ?? []
environmentVariables = try XCScheme.EnvironmentVariable.parseAll(jsonDictionary: jsonDictionary)
testPlans = try (jsonDictionary.json(atKeyPath: "testPlans") ?? []).map { try TestPlan(jsonDictionary: $0) }
language = jsonDictionary.json(atKeyPath: "language")
region = jsonDictionary.json(atKeyPath: "region")
debugEnabled = jsonDictionary.json(atKeyPath: "debugEnabled") ?? Scheme.Test.debugEnabledDefault
customLLDBInit = jsonDictionary.json(atKeyPath: "customLLDBInit")
captureScreenshotsAutomatically = jsonDictionary.json(atKeyPath: "captureScreenshotsAutomatically") ?? Scheme.Test.captureScreenshotsAutomaticallyDefault
deleteScreenshotsWhenEachTestSucceeds = jsonDictionary.json(atKeyPath: "deleteScreenshotsWhenEachTestSucceeds") ?? Scheme.Test.deleteScreenshotsWhenEachTestSucceedsDefault
macroExpansion = jsonDictionary.json(atKeyPath: "macroExpansion")
preferredScreenCaptureFormat = jsonDictionary.json(atKeyPath: "preferredScreenCaptureFormat") ?? Scheme.Test.preferredScreenCaptureFormatDefault
}
}
extension Scheme.Test: JSONEncodable {
public func toJSONValue() -> Any {
var dict: [String: Any?] = [
"commandLineArguments": commandLineArguments,
"targets": targets.map { $0.toJSONValue() },
"preActions": preActions.map { $0.toJSONValue() },
"postActions": postActions.map { $0.toJSONValue() },
"environmentVariables": environmentVariables.map { $0.toJSONValue() },
"testPlans": testPlans.map { $0.toJSONValue() },
"config": config,
"language": language,
"region": region,
"coverageTargets": coverageTargets.map { $0.reference },
"macroExpansion": macroExpansion
]
if gatherCoverageData != Scheme.Test.gatherCoverageDataDefault {
dict["gatherCoverageData"] = gatherCoverageData
}
if disableMainThreadChecker != Scheme.Test.disableMainThreadCheckerDefault {
dict["disableMainThreadChecker"] = disableMainThreadChecker
}
if debugEnabled != Scheme.Run.debugEnabledDefault {
dict["debugEnabled"] = debugEnabled
}
if let customLLDBInit = customLLDBInit {
dict["customLLDBInit"] = customLLDBInit
}
if captureScreenshotsAutomatically != Scheme.Test.captureScreenshotsAutomaticallyDefault {
dict["captureScreenshotsAutomatically"] = captureScreenshotsAutomatically
}
if deleteScreenshotsWhenEachTestSucceeds != Scheme.Test.deleteScreenshotsWhenEachTestSucceedsDefault {
dict["deleteScreenshotsWhenEachTestSucceeds"] = deleteScreenshotsWhenEachTestSucceeds
}
if preferredScreenCaptureFormat != Scheme.Test.preferredScreenCaptureFormatDefault {
dict["preferredScreenCaptureFormat"] = preferredScreenCaptureFormat.toJSONValue()
}
return dict
}
}
extension Scheme.Test.TestTarget: JSONObjectConvertible {
public init(jsonDictionary: JSONDictionary) throws {
if let name: String = jsonDictionary.json(atKeyPath: "name") {
targetReference = try TestableTargetReference(name)
} else if let local: String = jsonDictionary.json(atKeyPath: "local") {
self.targetReference = TestableTargetReference.local(local)
} else if let project: String = jsonDictionary.json(atKeyPath: "project") {
self.targetReference = TestableTargetReference.project(project)
} else if let package: String = jsonDictionary.json(atKeyPath: "package") {
self.targetReference = TestableTargetReference.package(package)
} else {
self.targetReference = try jsonDictionary.json(atKeyPath: "target")
}
randomExecutionOrder = jsonDictionary.json(atKeyPath: "randomExecutionOrder") ?? Scheme.Test.TestTarget.randomExecutionOrderDefault
parallelizable = jsonDictionary.json(atKeyPath: "parallelizable") ?? Scheme.Test.TestTarget.parallelizableDefault
location = jsonDictionary.json(atKeyPath: "location") ?? nil
skipped = jsonDictionary.json(atKeyPath: "skipped") ?? false
skippedTests = jsonDictionary.json(atKeyPath: "skippedTests") ?? []
selectedTests = jsonDictionary.json(atKeyPath: "selectedTests") ?? []
}
}
extension Scheme.Test.TestTarget: JSONEncodable {
public func toJSONValue() -> Any {
if randomExecutionOrder == Scheme.Test.TestTarget.randomExecutionOrderDefault,
parallelizable == Scheme.Test.TestTarget.parallelizableDefault {
return targetReference.reference
}
var dict: JSONDictionary = [
"name": targetReference.reference,
]
if randomExecutionOrder != Scheme.Test.TestTarget.randomExecutionOrderDefault {
dict["randomExecutionOrder"] = randomExecutionOrder
}
if parallelizable != Scheme.Test.TestTarget.parallelizableDefault {
dict["parallelizable"] = parallelizable
}
if let location = location {
dict["location"] = location
}
if skipped {
dict["skipped"] = skipped
}
return dict
}
}
extension Scheme.Profile: JSONObjectConvertible {
public init(jsonDictionary: JSONDictionary) throws {
config = jsonDictionary.json(atKeyPath: "config")
commandLineArguments = jsonDictionary.json(atKeyPath: "commandLineArguments") ?? [:]
preActions = jsonDictionary.json(atKeyPath: "preActions") ?? []
postActions = jsonDictionary.json(atKeyPath: "postActions") ?? []
environmentVariables = try XCScheme.EnvironmentVariable.parseAll(jsonDictionary: jsonDictionary)
if let askLaunch: Bool = jsonDictionary.json(atKeyPath: "askForAppToLaunch") {
askForAppToLaunch = askLaunch
}
}
}
extension Scheme.Profile: JSONEncodable {
public func toJSONValue() -> Any {
[
"commandLineArguments": commandLineArguments,
"preActions": preActions.map { $0.toJSONValue() },
"postActions": postActions.map { $0.toJSONValue() },
"environmentVariables": environmentVariables.map { $0.toJSONValue() },
"config": config,
"askForAppToLaunch": askForAppToLaunch,
] as [String: Any?]
}
}
extension Scheme.Analyze: JSONObjectConvertible {
public init(jsonDictionary: JSONDictionary) throws {
config = jsonDictionary.json(atKeyPath: "config")
}
}
extension Scheme.Analyze: JSONEncodable {
public func toJSONValue() -> Any {
[
"config": config,
]
}
}
extension Scheme.Archive: JSONObjectConvertible {
public init(jsonDictionary: JSONDictionary) throws {
config = jsonDictionary.json(atKeyPath: "config")
customArchiveName = jsonDictionary.json(atKeyPath: "customArchiveName")
revealArchiveInOrganizer = jsonDictionary.json(atKeyPath: "revealArchiveInOrganizer") ?? Scheme.Archive.revealArchiveInOrganizerDefault
preActions = jsonDictionary.json(atKeyPath: "preActions") ?? []
postActions = jsonDictionary.json(atKeyPath: "postActions") ?? []
}
}
extension Scheme.Archive: JSONEncodable {
public func toJSONValue() -> Any {
var dict: [String: Any?] = [
"preActions": preActions.map { $0.toJSONValue() },
"postActions": postActions.map { $0.toJSONValue() },
"config": config,
"customArchiveName": customArchiveName,
]
if revealArchiveInOrganizer != Scheme.Archive.revealArchiveInOrganizerDefault {
dict["revealArchiveInOrganizer"] = revealArchiveInOrganizer
}
return dict
}
}
extension Scheme: NamedJSONDictionaryConvertible {
public init(name: String, jsonDictionary: JSONDictionary) throws {
self.name = name
build = try jsonDictionary.json(atKeyPath: "build")
run = jsonDictionary.json(atKeyPath: "run")
test = jsonDictionary.json(atKeyPath: "test")
analyze = jsonDictionary.json(atKeyPath: "analyze")
profile = jsonDictionary.json(atKeyPath: "profile")
archive = jsonDictionary.json(atKeyPath: "archive")
management = jsonDictionary.json(atKeyPath: "management")
}
}
extension Scheme: JSONEncodable {
public func toJSONValue() -> Any {
[
"build": build.toJSONValue(),
"run": run?.toJSONValue(),
"test": test?.toJSONValue(),
"analyze": analyze?.toJSONValue(),
"profile": profile?.toJSONValue(),
"archive": archive?.toJSONValue(),
"management": management?.toJSONValue(),
] as [String: Any?]
}
}
extension Scheme.Build: JSONObjectConvertible {
public init(jsonDictionary: JSONDictionary) throws {
let targetDictionary: JSONDictionary = try jsonDictionary.json(atKeyPath: "targets")
var targets: [Scheme.BuildTarget] = []
for (targetRepr, possibleBuildTypes) in targetDictionary {
let buildTypes: [BuildType]
if let string = possibleBuildTypes as? String {
switch string {
case "all": buildTypes = BuildType.all
case "none": buildTypes = []
case "testing": buildTypes = [.testing, .analyzing]
case "indexing": buildTypes = [.testing, .analyzing, .archiving]
default: buildTypes = BuildType.all
}
} else if let enabledDictionary = possibleBuildTypes as? [String: Bool] {
buildTypes = enabledDictionary.filter { $0.value }.compactMap { BuildType.from(jsonValue: $0.key) }
} else if let array = possibleBuildTypes as? [String] {
buildTypes = array.compactMap(BuildType.from)
} else {
buildTypes = BuildType.all
}
let target = try TestableTargetReference(targetRepr)
targets.append(Scheme.BuildTarget(target: target, buildTypes: buildTypes))
}
self.targets = targets.sorted { $0.target.name < $1.target.name }
preActions = try jsonDictionary.json(atKeyPath: "preActions")?.map(Scheme.ExecutionAction.init) ?? []
postActions = try jsonDictionary.json(atKeyPath: "postActions")?.map(Scheme.ExecutionAction.init) ?? []
parallelizeBuild = jsonDictionary.json(atKeyPath: "parallelizeBuild") ?? Scheme.Build.parallelizeBuildDefault
buildImplicitDependencies = jsonDictionary.json(atKeyPath: "buildImplicitDependencies") ?? Scheme.Build.buildImplicitDependenciesDefault
runPostActionsOnFailure = jsonDictionary.json(atKeyPath: "runPostActionsOnFailure") ?? Scheme.Build.runPostActionsOnFailureDefault
}
}
extension Scheme.Build: JSONEncodable {
public func toJSONValue() -> Any {
let targetPairs = targets.map { ($0.target.reference, $0.buildTypes.map { $0.toJSONValue() }) }
var dict: JSONDictionary = [
"targets": Dictionary(uniqueKeysWithValues: targetPairs),
"preActions": preActions.map { $0.toJSONValue() },
"postActions": postActions.map { $0.toJSONValue() },
]
if parallelizeBuild != Scheme.Build.parallelizeBuildDefault {
dict["parallelizeBuild"] = parallelizeBuild
}
if buildImplicitDependencies != Scheme.Build.buildImplicitDependenciesDefault {
dict["buildImplicitDependencies"] = buildImplicitDependencies
}
if runPostActionsOnFailure != Scheme.Build.runPostActionsOnFailureDefault {
dict["runPostActionsOnFailure"] = runPostActionsOnFailure
}
return dict
}
}
extension BuildType: JSONUtilities.JSONPrimitiveConvertible {
public typealias JSONType = String
public static func from(jsonValue: String) -> BuildType? {
switch jsonValue {
case "test", "testing": return .testing
case "profile", "profiling": return .profiling
case "run", "running": return .running
case "archive", "archiving": return .archiving
case "analyze", "analyzing": return .analyzing
default: return nil
}
}
public static var all: [BuildType] {
[.running, .testing, .profiling, .analyzing, .archiving]
}
}
extension BuildType: JSONEncodable {
public func toJSONValue() -> Any {
switch self {
case .testing: return "testing"
case .profiling: return "profiling"
case .running: return "running"
case .archiving: return "archiving"
case .analyzing: return "analyzing"
}
}
}
extension XCScheme.EnvironmentVariable: JSONUtilities.JSONObjectConvertible {
public static let enabledDefault = true
private static func parseValue(_ value: Any) -> String {
if let bool = value as? Bool {
return bool ? "YES" : "NO"
} else {
return String(describing: value)
}
}
public init(jsonDictionary: JSONDictionary) throws {
let value: String
if let jsonValue = jsonDictionary["value"] {
value = XCScheme.EnvironmentVariable.parseValue(jsonValue)
} else {
// will throw error
value = try jsonDictionary.json(atKeyPath: "value")
}
let variable: String = try jsonDictionary.json(atKeyPath: "variable")
let enabled: Bool = jsonDictionary.json(atKeyPath: "isEnabled") ?? XCScheme.EnvironmentVariable.enabledDefault
self.init(variable: variable, value: value, enabled: enabled)
}
static func parseAll(jsonDictionary: JSONDictionary) throws -> [XCScheme.EnvironmentVariable] {
if let variablesDictionary: [String: Any] = jsonDictionary.json(atKeyPath: "environmentVariables") {
return variablesDictionary.mapValues(parseValue)
.map { XCScheme.EnvironmentVariable(variable: $0.key, value: $0.value, enabled: true) }
.sorted { $0.variable < $1.variable }
} else if let variablesArray: [JSONDictionary] = jsonDictionary.json(atKeyPath: "environmentVariables") {
return try variablesArray.map(XCScheme.EnvironmentVariable.init)
} else {
return []
}
}
}
extension XCScheme.EnvironmentVariable: JSONEncodable {
public func toJSONValue() -> Any {
var dict: [String: Any] = [
"variable": variable,
"value": value,
]
if enabled != XCScheme.EnvironmentVariable.enabledDefault {
dict["isEnabled"] = enabled
}
return dict
}
}
extension XCScheme.LaunchAction.GPUFrameCaptureMode: JSONEncodable {
public func toJSONValue() -> Any {
switch self {
case .autoEnabled:
return "autoEnabled"
case .metal:
return "metal"
case .openGL:
return "openGL"
case .disabled:
return "disabled"
}
}
static func fromJSONValue(_ string: String) -> XCScheme.LaunchAction.GPUFrameCaptureMode {
switch string {
case "autoEnabled":
return .autoEnabled
case "metal":
return .metal
case "openGL":
return .openGL
case "disabled":
return .disabled
default:
fatalError("Invalid enableGPUFrameCaptureMode value. Valid values are: autoEnabled, metal, openGL, disabled")
}
}
}
extension XCScheme.TestAction.ScreenCaptureFormat: JSONEncodable {
public func toJSONValue() -> Any {
rawValue
}
}