diff --git a/.gitignore b/.gitignore index dc51c07..6b194fb 100644 --- a/.gitignore +++ b/.gitignore @@ -37,30 +37,3 @@ playground.xcworkspace # Packages/ .build/ .swiftpm - -# CocoaPods -# -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control -# -# Pods/ - -# Carthage -# -# Add this line if you want to avoid checking in source code from Carthage dependencies. -# Carthage/Checkouts - -Carthage/Build - -# fastlane -# -# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the -# screenshots whenever they are needed. -# For more information about the recommended setup visit: -# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md - -fastlane/report.xml -fastlane/Preview.html -fastlane/screenshots -fastlane/test_output diff --git a/.travis.yml b/.travis.yml index ed323c3..09cc6d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,4 @@ language: swift osx_image: xcode10.2 -xcode_project: XcodeProject.xcodeproj -xcode_scheme: XcodeProject script: - - xcodebuild test -scheme XcodeProject | tee xcodebuild.log | xcpretty && exit ${PIPESTATUS[0]} + - swift test | tee xcodebuild.log | xcpretty && exit ${PIPESTATUS[0]} diff --git a/Makefile b/Makefile deleted file mode 100644 index a5c3597..0000000 --- a/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -SWIFTC_FLAGS = -Xswiftc "-target" -Xswiftc "x86_64-apple-macosx10.12" - -build: - swift build $(SWIFTC_FLAGS) - -test: - swift test $(SWIFTC_FLAGS) - -xcode: - swift package generate-xcodeproj --xcconfig-overrides=overrides.xcconfig - -linux: - swift test --generate-linuxmain $(SWIFTC_FLAGS) - -clean: - swift build --clean diff --git a/Sources/XcodeProject/Archiving/Encoder/AnyCodingKey.swift b/Sources/XcodeProject/Archiving/Encoder/AnyCodingKey.swift new file mode 100644 index 0000000..d73a6ce --- /dev/null +++ b/Sources/XcodeProject/Archiving/Encoder/AnyCodingKey.swift @@ -0,0 +1,31 @@ +// +// AnyCodingKey.swift +// XcodeProject +// +// Created by Geoffrey Foster on 2019-06-19. +// + +import Foundation + +struct AnyCodingKey: CodingKey, Equatable, Hashable { + var stringValue: String + var intValue: Int? + + init?(stringValue: String) { + self.stringValue = stringValue + self.intValue = nil + } + + init?(intValue: Int) { + self.stringValue = "\(intValue)" + self.intValue = intValue + } + + init(_ base: Key) where Key: CodingKey { + if let intValue = base.intValue { + self.init(intValue: intValue)! + } else { + self.init(stringValue: base.stringValue)! + } + } +} diff --git a/Sources/XcodeProject/Archiving/Encoder/PBXEncoder.swift b/Sources/XcodeProject/Archiving/Encoder/PBXEncoder.swift new file mode 100644 index 0000000..86b98ab --- /dev/null +++ b/Sources/XcodeProject/Archiving/Encoder/PBXEncoder.swift @@ -0,0 +1,31 @@ +// +// PBXEncoder.swift +// XcodeProject +// +// Created by Geoffrey Foster on 2019-06-18. +// + +import Foundation + +class PBXObjectEncoder { + static let objectVersionKey = CodingUserInfoKey(rawValue: "objectVersion")! + var objectVersion: ObjectVersion = .xcode93 + + func encode(_ object: PBXObject) throws -> [String: AnyObject] { + let encoder = _PBXObjectEncoder() + encoder.userInfo = [PBXObjectEncoder.objectVersionKey: objectVersion] + try object.encode(to: encoder) + return encoder.storage.popContainer() as? [String: AnyObject] ?? [:] + } +} + +extension Encoder { + var objectVersion: ObjectVersion { + return userInfo[PBXObjectEncoder.objectVersionKey] as? ObjectVersion ?? ObjectVersion.allCases.last! + } + + // TODO: better name, but this will allow for encode(to:) function to be able to "smartly" decide to encode id's or objects + var supportsCyclic: Bool { + return self is _PBXObjectEncoder + } +} diff --git a/Sources/XcodeProject/Archiving/Encoder/_PBXObjectEncoder+KeyedContainer.swift b/Sources/XcodeProject/Archiving/Encoder/_PBXObjectEncoder+KeyedContainer.swift new file mode 100644 index 0000000..a795580 --- /dev/null +++ b/Sources/XcodeProject/Archiving/Encoder/_PBXObjectEncoder+KeyedContainer.swift @@ -0,0 +1,59 @@ +// +// _PBXObjectEncoder+KeyedContainer.swift +// XcodeProject +// +// Created by Geoffrey Foster on 2019-06-19. +// + +import Foundation + +extension _PBXObjectEncoder { + final class KeyedContainer where Key: CodingKey { + private let encoder: _PBXObjectEncoder + var codingPath: [CodingKey] + + private var container: NSMutableDictionary + + init(referencing encoder: _PBXObjectEncoder, codingPath: [CodingKey], wrapping container: NSMutableDictionary) { + self.encoder = encoder + self.codingPath = codingPath + self.container = container + } + } +} + +extension _PBXObjectEncoder.KeyedContainer: KeyedEncodingContainerProtocol { + private func nestedCodingPath(forKey key: CodingKey) -> [CodingKey] { + return self.codingPath + [key] + } + + func encodeNil(forKey key: Key) throws { + container[key.stringValue] = NSNull() + } + + func encode(_ value: String, forKey key: Key) throws { + container[key.stringValue] = NSString(string: value.quotedString) + } + + func encode(_ value: T, forKey key: Key) throws where T: Encodable { + encoder.codingPath.append(key) + defer { encoder.codingPath.removeLast() } + container[key.stringValue] = try encoder.box(value) + } + + func nestedContainer(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer where NestedKey: CodingKey { + fatalError() + } + + func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { + fatalError() + } + + func superEncoder() -> Encoder { + fatalError() + } + + func superEncoder(forKey key: Key) -> Encoder { + fatalError() + } +} diff --git a/Sources/XcodeProject/Archiving/Encoder/_PBXObjectEncoder+SingleValueContainer.swift b/Sources/XcodeProject/Archiving/Encoder/_PBXObjectEncoder+SingleValueContainer.swift new file mode 100644 index 0000000..a3a53ce --- /dev/null +++ b/Sources/XcodeProject/Archiving/Encoder/_PBXObjectEncoder+SingleValueContainer.swift @@ -0,0 +1,103 @@ +// +// _PBXObjectEncoder+SingleValueContainer.swift +// XcodeProject +// +// Created by Geoffrey Foster on 2019-06-19. +// + +import Foundation + +extension _PBXObjectEncoder { + final class SingleValueContainer { + private let encoder: _PBXObjectEncoder + var codingPath: [CodingKey] + + init(referencing encoder: _PBXObjectEncoder, codingPath: [CodingKey]) { + self.encoder = encoder + self.codingPath = codingPath + } + } +} + +extension _PBXObjectEncoder.SingleValueContainer: SingleValueEncodingContainer { + private func assertCanEncodeNewValue() { + precondition(encoder.canEncodeNewValue, "Attempt to encode value through single value container when previously value already encoded.") + } + + func encodeNil() throws { + encoder.storage.pushValue(NSNull()) + } + + func encode(_ value: Bool) throws { + assertCanEncodeNewValue() + encoder.storage.pushValue(NSNumber(value: value)) + } + + func encode(_ value: String) throws { + assertCanEncodeNewValue() + encoder.storage.pushValue(NSString(string: value.quotedString)) + } + + func encode(_ value: Double) throws { + throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: codingPath, debugDescription: "Unsupported type: \(type(of: value))")) + } + + func encode(_ value: Float) throws { + throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: codingPath, debugDescription: "Unsupported type: \(type(of: value))")) + } + + func encode(_ value: Int) throws { + assertCanEncodeNewValue() + encoder.storage.pushValue(NSNumber(value: value)) + } + + func encode(_ value: Int8) throws { + assertCanEncodeNewValue() + encoder.storage.pushValue(NSNumber(value: value)) + } + + func encode(_ value: Int16) throws { + assertCanEncodeNewValue() + encoder.storage.pushValue(NSNumber(value: value)) + } + + func encode(_ value: Int32) throws { + assertCanEncodeNewValue() + encoder.storage.pushValue(NSNumber(value: value)) + } + + func encode(_ value: Int64) throws { + assertCanEncodeNewValue() + encoder.storage.pushValue(NSNumber(value: value)) + } + + func encode(_ value: UInt) throws { + assertCanEncodeNewValue() + encoder.storage.pushValue(NSNumber(value: value)) + } + + func encode(_ value: UInt8) throws { + assertCanEncodeNewValue() + encoder.storage.pushValue(NSNumber(value: value)) + } + + func encode(_ value: UInt16) throws { + assertCanEncodeNewValue() + encoder.storage.pushValue(NSNumber(value: value)) + } + + func encode(_ value: UInt32) throws { + assertCanEncodeNewValue() + encoder.storage.pushValue(NSNumber(value: value)) + } + + func encode(_ value: UInt64) throws { + assertCanEncodeNewValue() + encoder.storage.pushValue(NSNumber(value: value)) + } + + func encode(_ value: T) throws where T: Encodable { + assertCanEncodeNewValue() + encoder.storage.pushValue(try encoder.box(value)) + } +} diff --git a/Sources/XcodeProject/Archiving/Encoder/_PBXObjectEncoder+UnkeyedContainer.swift b/Sources/XcodeProject/Archiving/Encoder/_PBXObjectEncoder+UnkeyedContainer.swift new file mode 100644 index 0000000..473ba8c --- /dev/null +++ b/Sources/XcodeProject/Archiving/Encoder/_PBXObjectEncoder+UnkeyedContainer.swift @@ -0,0 +1,59 @@ +// +// _PBXObjectEncoder+UnkeyedContainer.swift +// XcodeProject +// +// Created by Geoffrey Foster on 2019-06-19. +// + +import Foundation + +extension _PBXObjectEncoder { + final class UnkeyedContainer { + private let encoder: _PBXObjectEncoder + var codingPath: [CodingKey] + + private var container: NSMutableArray + + init(referencing encoder: _PBXObjectEncoder, codingPath: [CodingKey], wrapping container: NSMutableArray) { + self.encoder = encoder + self.codingPath = codingPath + self.container = container + } + } +} + +extension _PBXObjectEncoder.UnkeyedContainer: UnkeyedEncodingContainer { + private var nestedCodingPath: [CodingKey] { + return codingPath + [AnyCodingKey(intValue: count)!] + } + + var count: Int { + return container.count + } + + func encodeNil() throws { + container.add(NSNull()) + } + + func encode(_ value: String) throws { + container.add(NSString(string: value.quotedString)) + } + + func encode(_ value: T) throws where T: Encodable { + encoder.codingPath.append(AnyCodingKey(intValue: count)!) + defer { encoder.codingPath.removeLast() } + container.add(try encoder.box(value)) + } + + func nestedContainer(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer where NestedKey: CodingKey { + fatalError() + } + + func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { + fatalError() + } + + func superEncoder() -> Encoder { + fatalError() + } +} diff --git a/Sources/XcodeProject/Archiving/Encoder/_PBXObjectEncoder.swift b/Sources/XcodeProject/Archiving/Encoder/_PBXObjectEncoder.swift new file mode 100644 index 0000000..28f32d5 --- /dev/null +++ b/Sources/XcodeProject/Archiving/Encoder/_PBXObjectEncoder.swift @@ -0,0 +1,59 @@ +// +// _PBXObjectEncoder.swift +// XcodeProject +// +// Created by Geoffrey Foster on 2019-06-19. +// + +import Foundation + +final class _PBXObjectEncoder: Encoder { + var codingPath: [CodingKey] = [] + var userInfo: [CodingUserInfoKey: Any] = [:] + + var storage = _PBXObjectEncodingStorage() + + func container(keyedBy type: Key.Type) -> KeyedEncodingContainer where Key: CodingKey { + let topContainer: NSMutableDictionary + if canEncodeNewValue { + topContainer = storage.pushKeyedContainer() + } else { + guard let container = storage.top as? NSMutableDictionary else { + preconditionFailure("Attempt to push new keyed encoding container when already previously encoded at this path.") + } + topContainer = container + } + + return KeyedEncodingContainer(KeyedContainer(referencing: self, codingPath: codingPath, wrapping: topContainer)) + } + + func unkeyedContainer() -> UnkeyedEncodingContainer { + let topContainer: NSMutableArray + if canEncodeNewValue { + topContainer = storage.pushUnkeyedContainer() + } else { + guard let container = storage.top as? NSMutableArray else { + preconditionFailure("Attempt to push new unkeyed encoding container when already previously encoded at this path.") + } + topContainer = container + } + return UnkeyedContainer(referencing: self, codingPath: codingPath, wrapping: topContainer) + } + + func singleValueContainer() -> SingleValueEncodingContainer { + return SingleValueContainer(referencing: self, codingPath: codingPath) + } + + var canEncodeNewValue: Bool { + return storage.count == codingPath.count + } + + func box(_ value: T) throws -> NSObject where T: Encodable { + if let value = value as? PBXObject { + return NSString(string: value.plistID.description) + } else { + try value.encode(to: self) + return storage.popContainer() + } + } +} diff --git a/Sources/XcodeProject/Archiving/Encoder/_PBXObjectEncodingStorage.swift b/Sources/XcodeProject/Archiving/Encoder/_PBXObjectEncodingStorage.swift new file mode 100644 index 0000000..e1957ab --- /dev/null +++ b/Sources/XcodeProject/Archiving/Encoder/_PBXObjectEncodingStorage.swift @@ -0,0 +1,44 @@ +// +// _PBXObjectEncodingStorage.swift +// XcodeProject +// +// Created by Geoffrey Foster on 2019-06-19. +// + +import Foundation + +struct _PBXObjectEncodingStorage { + private var containers: [NSObject] = [] + init() {} + + var count: Int { + return containers.count + } + + var top: NSObject? { + return containers.last + } + + mutating func pushKeyedContainer() -> NSMutableDictionary { + let reference = NSMutableDictionary() + containers.append(reference) + return reference + } + + mutating func pushUnkeyedContainer() -> NSMutableArray { + let reference = NSMutableArray() + containers.append(reference) + return reference + } + + @discardableResult + mutating func pushValue(_ value: NSObject) -> NSObject { + containers.append(value) + return value + } + + mutating func popContainer() -> NSObject { + precondition(!containers.isEmpty, "Empty container stack.") + return containers.popLast()! + } +} diff --git a/Sources/XcodeProject/Archiving/PBXPListArchiver.swift b/Sources/XcodeProject/Archiving/PBXPListArchiver.swift index b17a7d3..43ef114 100644 --- a/Sources/XcodeProject/Archiving/PBXPListArchiver.swift +++ b/Sources/XcodeProject/Archiving/PBXPListArchiver.swift @@ -55,9 +55,9 @@ public class OutputStreamWriter: StreamWritable { struct Format { struct Indentation: CustomStringConvertible { - var enabled = true var character: String = "\t" var level: Int = 0 + var enabled = true mutating func increase() { if enabled { level += 1 @@ -78,6 +78,17 @@ struct Format { var startOfLine: String = "\n" var endOfLine: String = "\n" var indentation: Indentation = Indentation() + + static var singleLine: Format { + return Format(startOfLine: "", endOfLine: " ", indentation: Format.Indentation(character: "", level: 0, enabled: false)) + } + + func indented(_ block: (Format) throws -> Void) rethrows { + var format = self + format.indentation.increase() + try block(format) + format.indentation.decrease() + } } struct ObjectMap { @@ -111,20 +122,19 @@ public final class PBXPListArchiver { } public func write(stream: StreamWritable) throws { - var format = Format() - + let format = Format() try stream.write("// !$*UTF8*$!\(format.endOfLine)") try stream.write("{\(format.endOfLine)") - format.indentation.increase() - try archiveDictionary.sorted { (obj1, obj2) in - return obj1.key < obj2.key - }.forEach { (key, value) in - guard let value = value else { return } - try stream.write("\(format.indentation)\(key) = ") - try stream.write(value.plistRepresentation(format: format)) - try stream.write(";\(format.endOfLine)") + try format.indented { format in + try archiveDictionary.sorted { (obj1, obj2) in + return obj1.key < obj2.key + }.forEach { (key, value) in + guard let value = value else { return } + try stream.write("\(format.indentation)\(key) = ") + try stream.write(value.plistRepresentation(format: format, objectVersion: projectFile.objectVersion)) + try stream.write(";\(format.endOfLine)") + } } - format.indentation.decrease() try stream.write("}\(format.endOfLine)") } diff --git a/Sources/XcodeProject/Archiving/PListArchivable.swift b/Sources/XcodeProject/Archiving/PListArchivable.swift index 37a90a4..cf63ab8 100644 --- a/Sources/XcodeProject/Archiving/PListArchivable.swift +++ b/Sources/XcodeProject/Archiving/PListArchivable.swift @@ -10,7 +10,7 @@ import Foundation protocol PListArchivable { var archiveInPlistOnSingleLine: Bool { get } - func plistRepresentation(format: Format) -> String + func plistRepresentation(format: Format, objectVersion: ObjectVersion) -> String } extension PListArchivable { @@ -20,13 +20,13 @@ extension PListArchivable { } extension ObjectMap: PListArchivable { - func plistRepresentation(format: Format) -> String { + func plistRepresentation(format: Format, objectVersion: ObjectVersion) -> String { func plist(objects: [PBXObject], format: Format) -> String { var str = "" objects.sorted { (obj1, obj2) -> Bool in obj1.globalID < obj2.globalID }.forEach { - str += $0.plistRepresentation(format: format) + str += $0.plistRepresentation(format: format, objectVersion: objectVersion) } return str } @@ -35,10 +35,9 @@ extension ObjectMap: PListArchivable { return obj1.key < obj2.key }.forEach { (key, value) in str += "\n/* Begin \(key) section */\n" - var format = format - format.indentation.increase() - str += plist(objects: value, format: format) - format.indentation.decrease() + format.indented { + str += plist(objects: value, format: $0) + } str += "/* End \(key) section */\n" } str += "\(format.indentation)}" @@ -47,144 +46,96 @@ extension ObjectMap: PListArchivable { } extension NSString: PListArchivable { - func plistRepresentation(format: Format) -> String { - return (self as String).plistRepresentation(format: format) + func plistRepresentation(format: Format, objectVersion: ObjectVersion) -> String { + return (self as String).plistRepresentation(format: format, objectVersion: objectVersion) + } +} + +extension NSNumber: PListArchivable { + func plistRepresentation(format: Format, objectVersion: ObjectVersion) -> String { + return "\(self.description)" } } extension NSDictionary: PListArchivable { - func plistRepresentation(format: Format) -> String { - return (self as! [String: Any]).plistRepresentation(format: format) + func plistRepresentation(format: Format, objectVersion: ObjectVersion) -> String { + return (self as! [String: Any]).plistRepresentation(format: format, objectVersion: objectVersion) } } extension NSArray: PListArchivable { - func plistRepresentation(format: Format) -> String { - return (self as! [Any]).plistRepresentation(format: format) + func plistRepresentation(format: Format, objectVersion: ObjectVersion) -> String { + return (self as! [Any]).plistRepresentation(format: format, objectVersion: objectVersion) } } extension String: PListArchivable { - static let replacements: [(String, String)] = [ - ("\\", "\\\\"), - ("\"", "\\\""), - ("\n", "\\n"), - ("\t", "\\t"), - ] - var quotedString: String { - var string = self - - let characterSet = CharacterSet(charactersIn: "+-<>@$()=,:~").union(CharacterSet.whitespacesAndNewlines) - - var requiresQuotes = string.isEmpty - if !requiresQuotes { - for character in string.unicodeScalars where characterSet.contains(character) { - requiresQuotes = true - break - } - } - - String.replacements.forEach { - string = string.replacingOccurrences(of: $0.0, with: $0.1) - } - - if requiresQuotes { - string = "\"\(string)\"" - } - - return string - } - - fileprivate var unquotedString: String { - var string = self - if let firstRange = string.range(of: ("\""), options: []), firstRange.lowerBound == startIndex, - let lastRange = string.range(of: ("\""), options: [.backwards]), lastRange.upperBound == endIndex { - string.removeSubrange(lastRange) - string.removeSubrange(firstRange) - } - - String.replacements.reversed().forEach { - string = string.replacingOccurrences(of: $0.1, with: $0.0) - } - - return string - } - - func plistRepresentation(format: Format) -> String { - return self.quotedString + func plistRepresentation(format: Format, objectVersion: ObjectVersion) -> String { + return self } } extension UInt: PListArchivable { - func plistRepresentation(format: Format) -> String { + func plistRepresentation(format: Format, objectVersion: ObjectVersion) -> String { return "\(self)" } } extension Int: PListArchivable { - func plistRepresentation(format: Format) -> String { + func plistRepresentation(format: Format, objectVersion: ObjectVersion) -> String { return "\(self)" } } extension Int8: PListArchivable { - func plistRepresentation(format: Format) -> String { + func plistRepresentation(format: Format, objectVersion: ObjectVersion) -> String { return "\(self)" } } extension Int32: PListArchivable { - func plistRepresentation(format: Format) -> String { + func plistRepresentation(format: Format, objectVersion: ObjectVersion) -> String { return "\(self)" } } extension Bool: PListArchivable { - func plistRepresentation(format: Format) -> String { + func plistRepresentation(format: Format, objectVersion: ObjectVersion) -> String { return self ? "1" : "0" } } extension PBXObject: PListArchivable { - func plistRepresentation(format: Format) -> String { - let singleLine = archiveInPlistOnSingleLine - var subformat = format - if singleLine { - subformat.startOfLine = "" - subformat.endOfLine = " " - subformat.indentation.character = "" - subformat.indentation.level = 0 - subformat.indentation.enabled = false + func plistRepresentation(format: Format, objectVersion: ObjectVersion) -> String { + let objectEncoder = PBXObjectEncoder() + objectEncoder.objectVersion = objectVersion + guard let encoded = try? objectEncoder.encode(self).sorted(by: { (obj1, obj2) -> Bool in + return (obj1.key == "isa") || (obj1.key < obj2.key && obj2.key != "isa") + }) else { + return "" } - var str = "\(format.indentation)\(self.plistID) = {\(subformat.startOfLine)" - - subformat.indentation.increase() - plistRepresentation.sorted { (obj1, obj2) -> Bool in - return (obj1.key == "isa") || (obj1.key < obj2.key && obj2.key != "isa") - }.forEach { (key, value) in - if value == nil { return } - guard let value = value as? PListArchivable else { - return + var str = "\(format.indentation)\(self.plistID) = {" + (archiveInPlistOnSingleLine ? Format.singleLine : format).indented { (format) in + str += "\(format.startOfLine)" + encoded.forEach { (key, value) in + guard let value = value as? PListArchivable else { return } + str += "\(format.indentation)\(key) = \(value.plistRepresentation(format: format, objectVersion: objectVersion));\(format.endOfLine)" } - - str += "\(subformat.indentation)\(key) = \(value.plistRepresentation(format: subformat));\(subformat.endOfLine)" } - - subformat.indentation.decrease() - str += "\(subformat.indentation)};\n" + if !archiveInPlistOnSingleLine { + str += "\(format.indentation)" + } + str += "};\(format.endOfLine)" return str } } extension Dictionary: PListArchivable { - func plistRepresentation(format: Format) -> String { - var format = format + func plistRepresentation(format: Format, objectVersion: ObjectVersion) -> String { var str = "{\(format.startOfLine)" - var plist: [String: String] = [:] - for (key, value) in self { guard let archivableKey = key as? PListArchivable else { fatalError("Key `\(key)` of type \(type(of: key)) is not PListArchivable") @@ -192,21 +143,19 @@ extension Dictionary: PListArchivable { guard let archivableValue = value as? PListArchivable else { fatalError("Value `\(value)` of type \(type(of: key)) is not PListArchivable") } - format.indentation.increase() - let keyString = archivableKey.plistRepresentation(format: format) - let valueString = archivableValue.plistRepresentation(format: format) - - plist[keyString] = valueString - - format.indentation.decrease() + format.indented { (format) in + let keyString = archivableKey.plistRepresentation(format: format, objectVersion: objectVersion) + let valueString = archivableValue.plistRepresentation(format: format, objectVersion: objectVersion) + plist[keyString] = valueString + } } plist.sorted { return $0.key.unquotedString < $1.key.unquotedString }.forEach { (keyString, valueString) in - format.indentation.increase() - str += "\(format.indentation)\(keyString) = \(valueString);\(format.endOfLine)" - format.indentation.decrease() + format.indented { (format) in + str += "\(format.indentation)\(keyString) = \(valueString);\(format.endOfLine)" + } } str += "\(format.indentation)}" @@ -215,28 +164,21 @@ extension Dictionary: PListArchivable { } extension Array: PListArchivable { - func plistRepresentation(format: Format) -> String { - var format = format + func plistRepresentation(format: Format, objectVersion: ObjectVersion) -> String { var str = "(\(format.startOfLine)" - format.indentation.increase() - for item in self { - guard let item = item as? PListArchivable else { fatalError() } - str += "\(format.indentation)\(item.plistRepresentation(format: format)),\(format.endOfLine)" + format.indented { (format) in + for item in self { + guard let item = item as? PListArchivable else { fatalError() } + str += "\(format.indentation)\(item.plistRepresentation(format: format, objectVersion: objectVersion)),\(format.endOfLine)" + } } - format.indentation.decrease() str += "\(format.indentation))" return str } } extension PlistID: PListArchivable { - func plistRepresentation(format: Format) -> String { - return rawValue - } -} - -extension PlistISA: PListArchivable { - func plistRepresentation(format: Format) -> String { - return rawValue + func plistRepresentation(format: Format, objectVersion: ObjectVersion) -> String { + return description } } diff --git a/Sources/XcodeProject/Archiving/PropertyList.swift b/Sources/XcodeProject/Archiving/PropertyList.swift index 32408c5..419260f 100644 --- a/Sources/XcodeProject/Archiving/PropertyList.swift +++ b/Sources/XcodeProject/Archiving/PropertyList.swift @@ -29,6 +29,10 @@ struct PropertyList { return getTypedObject() } + func objectArray() -> [PropertyList]? { + return (object as? [Any])?.map { PropertyList($0) } + } + var array: [String]? { return getTypedObject() } diff --git a/Sources/XcodeProject/Extensions/Sequence+Extension.swift b/Sources/XcodeProject/Extensions/Sequence+Extension.swift new file mode 100644 index 0000000..dad25a7 --- /dev/null +++ b/Sources/XcodeProject/Extensions/Sequence+Extension.swift @@ -0,0 +1,22 @@ +// +// File.swift +// +// +// Created by Geoffrey Foster on 2019-06-23. +// + +import Foundation + +extension Sequence { + func sorted(by keyPath: KeyPath) -> [Self.Element] { + return self.sorted { (lhs, rhs) -> Bool in + lhs[keyPath: keyPath] < rhs[keyPath: keyPath] + } + } + + func sorted(by keyPath: KeyPath, using comparator: (Value) -> (Value) -> ComparisonResult) -> [Self.Element] { + return self.sorted { (lhs, rhs) -> Bool in + comparator(lhs[keyPath: keyPath])(rhs[keyPath: keyPath]) == .orderedAscending + } + } +} diff --git a/Sources/XcodeProject/Extensions/String+Extensions.swift b/Sources/XcodeProject/Extensions/String+Extensions.swift new file mode 100644 index 0000000..15e69ca --- /dev/null +++ b/Sources/XcodeProject/Extensions/String+Extensions.swift @@ -0,0 +1,56 @@ +// +// String+Extensions.swift +// XcodeProject +// +// Created by Geoffrey Foster on 2019-06-23. +// + +import Foundation + +extension String { + static let replacements: [(String, String)] = [ + ("\\", "\\\\"), + ("\"", "\\\""), + ("\n", "\\n"), + ("\t", "\\t"), + ] + + var quotedString: String { + var string = self + + let characterSet = CharacterSet(charactersIn: "+-<>@$()=,:~").union(CharacterSet.whitespacesAndNewlines) + + var requiresQuotes = string.isEmpty + if !requiresQuotes { + for character in string.unicodeScalars where characterSet.contains(character) { + requiresQuotes = true + break + } + } + + String.replacements.forEach { + string = string.replacingOccurrences(of: $0.0, with: $0.1) + } + + if requiresQuotes { + string = "\"\(string)\"" + } + + return string + } + + var unquotedString: String { + var string = self + if let firstRange = string.range(of: ("\""), options: []), firstRange.lowerBound == startIndex, + let lastRange = string.range(of: ("\""), options: [.backwards]), lastRange.upperBound == endIndex { + string.removeSubrange(lastRange) + string.removeSubrange(firstRange) + } + + String.replacements.reversed().forEach { + string = string.replacingOccurrences(of: $0.1, with: $0.0) + } + + return string + } +} diff --git a/Sources/XcodeProject/Objects+Extensions/PBXGroup+FolderSync.swift b/Sources/XcodeProject/Objects+Extensions/PBXGroup+FolderSync.swift index 9492016..3f99813 100644 --- a/Sources/XcodeProject/Objects+Extensions/PBXGroup+FolderSync.swift +++ b/Sources/XcodeProject/Objects+Extensions/PBXGroup+FolderSync.swift @@ -48,21 +48,19 @@ public extension PBXGroup { } private func removeDuplicateFiles(recursive: Bool) { - var seen: Set = [] - var duplicates: [Int] = [] - for i in 0.. 1 } + for (_, references) in duplicates { + references.filter { $0.isLeaf && $0.buildFiles.isEmpty }.forEach { remove(child: $0) } + } + if recursive { + children.compactMap { $0 as? PBXGroup }.forEach { + $0.removeDuplicateFiles(recursive: recursive) + } } } @@ -130,6 +128,7 @@ public extension PBXGroup { guard let childURL = $0.url else { return nil } return (childURL.path, $0) } + let childPathMap = Dictionary(uniqueKeysWithValues: childPathItems) do { let contents = try FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil, options: [.skipsHiddenFiles]) diff --git a/Sources/XcodeProject/Objects/Build Phases/PBXBuildPhase.swift b/Sources/XcodeProject/Objects/Build Phases/PBXBuildPhase.swift index 1c48a07..f89c840 100644 --- a/Sources/XcodeProject/Objects/Build Phases/PBXBuildPhase.swift +++ b/Sources/XcodeProject/Objects/Build Phases/PBXBuildPhase.swift @@ -7,6 +7,13 @@ // public class PBXBuildPhase: PBXObject { + private enum CodingKeys: String, CodingKey { + case name + case files + case runOnlyForDeploymentPostprocessing + case buildActionMask + } + class var defaultName: String { return "" } @@ -96,12 +103,12 @@ public class PBXBuildPhase: PBXObject { } } - override var plistRepresentation: [String: Any?] { - var plist = super.plistRepresentation - plist["name"] = _name - plist["files"] = files.map { $0.plistID } - plist["runOnlyForDeploymentPostprocessing"] = runOnlyForDeploymentPostprocessing - plist["buildActionMask"] = buildActionMask - return plist + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(_name, forKey: .name) + try container.encode(files, forKey: .files) + try container.encodeIfPresent(runOnlyForDeploymentPostprocessing, forKey: .runOnlyForDeploymentPostprocessing) + try container.encode(buildActionMask, forKey: .buildActionMask) } } diff --git a/Sources/XcodeProject/Objects/Build Phases/PBXCopyFilesBuildPhase.swift b/Sources/XcodeProject/Objects/Build Phases/PBXCopyFilesBuildPhase.swift index a9be336..a4addf3 100644 --- a/Sources/XcodeProject/Objects/Build Phases/PBXCopyFilesBuildPhase.swift +++ b/Sources/XcodeProject/Objects/Build Phases/PBXCopyFilesBuildPhase.swift @@ -7,11 +7,16 @@ // public final class PBXCopyFilesBuildPhase: PBXBuildPhase { + private enum CodingKeys: String, CodingKey { + case dstPath + case dstSubfolderSpec + } + class override var defaultName: String { return "Copy Files" } - enum Destination: Int8 { + enum Destination: Int8, Encodable { case absolutePath = 0 case wrapper = 1 case executables = 6 @@ -40,10 +45,10 @@ public final class PBXCopyFilesBuildPhase: PBXBuildPhase { self.dstSubfolderSpec = dstSubfolderSpec } - override var plistRepresentation: [String : Any?] { - var plist = super.plistRepresentation - plist["dstPath"] = dstPath - plist["dstSubfolderSpec"] = dstSubfolderSpec.rawValue - return plist + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(dstPath, forKey: .dstPath) + try container.encode(dstSubfolderSpec, forKey: .dstSubfolderSpec) } } diff --git a/Sources/XcodeProject/Objects/Build Phases/PBXShellScriptBuildPhase.swift b/Sources/XcodeProject/Objects/Build Phases/PBXShellScriptBuildPhase.swift index 8b74921..2f74255 100644 --- a/Sources/XcodeProject/Objects/Build Phases/PBXShellScriptBuildPhase.swift +++ b/Sources/XcodeProject/Objects/Build Phases/PBXShellScriptBuildPhase.swift @@ -7,8 +7,20 @@ // public final class PBXShellScriptBuildPhase: PBXBuildPhase { + private enum CodingKeys: String, CodingKey { + case inputPaths + case outputPaths + case inputFileListPaths + case outputFileListPaths + case shellPath + case shellScript + case showEnvVarsInLog + } + var inputPaths: [String] = [] var outputPaths: [String] = [] + var inputFileListPaths: [String] = [] + var outputFileListPaths: [String] = [] var shellPath: String? var shellScript: String? var showEnvVarsInLog: Bool? @@ -17,18 +29,27 @@ public final class PBXShellScriptBuildPhase: PBXBuildPhase { super.update(with: plist, objectCache: objectCache) self.inputPaths = plist["inputPaths"]?.array ?? [] self.outputPaths = plist["outputPaths"]?.array ?? [] + self.inputFileListPaths = plist["inputFileListPaths"]?.array ?? [] + self.outputFileListPaths = plist["outputFileListPaths"]?.array ?? [] self.shellPath = plist["shellPath"]?.string self.shellScript = plist["shellScript"]?.string self.showEnvVarsInLog = plist["showEnvVarsInLog"]?.bool } - override var plistRepresentation: [String : Any?] { - var plist = super.plistRepresentation - plist["inputPaths"] = inputPaths - plist["outputPaths"] = outputPaths - plist["shellPath"] = shellPath - plist["shellScript"] = shellScript - plist["showEnvVarsInLog"] = showEnvVarsInLog - return plist + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(inputPaths, forKey: .inputPaths) + try container.encode(outputPaths, forKey: .outputPaths) + + if encoder.objectVersion >= .xcode93 { + try container.encode(inputFileListPaths, forKey: .inputFileListPaths) + try container.encode(outputFileListPaths, forKey: .outputFileListPaths) + } + + try container.encodeIfPresent(shellPath, forKey: .shellPath) + try container.encodeIfPresent(shellScript, forKey: .shellScript) + try container.encodeIfPresent(showEnvVarsInLog, forKey: .showEnvVarsInLog) } } diff --git a/Sources/XcodeProject/Objects/PBXBuildFile.swift b/Sources/XcodeProject/Objects/PBXBuildFile.swift index b0e2620..8e86ef1 100644 --- a/Sources/XcodeProject/Objects/PBXBuildFile.swift +++ b/Sources/XcodeProject/Objects/PBXBuildFile.swift @@ -7,7 +7,48 @@ // public final class PBXBuildFile: PBXObject { - + private enum CodingKeys: String, CodingKey { + case fileRef + case settings + } + public enum Attribute: String, Comparable, Encodable { + public static func < (lhs: PBXBuildFile.Attribute, rhs: PBXBuildFile.Attribute) -> Bool { + return lhs.rawValue < rhs.rawValue + } + + case `public` = "Public" + case `private` = "Private" + case `weak` = "Weak" + case client = "Client" + case server = "Server" + case noCodegen = "no_codegen" + case codeSignOnCopy = "CodeSignOnCopy" + case removeHeadersOnCopy = "RemoveHeadersOnCopy" + } + struct Settings: Encodable { + private enum CodingKeys: String, CodingKey { + case attributes = "ATTRIBUTES" + case compilerFlags = "COMPILER_FLAGS" + case assetTags = "ASSET_TAGS" + } + + var attributes: Set? + var compilerFlags: String? + + init?(_ plist: [String: Any]?) { + guard let plist = plist else { return nil } + if let attributes = plist[CodingKeys.attributes.rawValue] as? [String] { + self.attributes = Set(attributes.compactMap({ Attribute(rawValue: $0) })) + } + self.compilerFlags = plist[CodingKeys.compilerFlags.rawValue] as? String + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(attributes?.sorted(by: <), forKey: .attributes) + try container.encodeIfPresent(compilerFlags, forKey: .compilerFlags) + } + } var buildPhase: PBXBuildPhase? { return parent as? PBXBuildPhase } @@ -18,17 +59,24 @@ public final class PBXBuildFile: PBXObject { fileRef?.register(buildFile: self) } } - var settings: [String: Any]? + var settings: Settings? public convenience init(globalID: PBXGlobalID, fileReference: PBXReference) { self.init(globalID: globalID) fileRef = fileReference } + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(fileRef, forKey: .fileRef) + try container.encodeIfPresent(settings, forKey: .settings) + } + override func update(with plist: PropertyList, objectCache: ObjectCache) { super.update(with: plist, objectCache: objectCache) self.fileRef = objectCache.object(for: PBXGlobalID(rawValue: plist["fileRef"]?.string)) - self.settings = plist["settings"]?.dictionary + self.settings = Settings(plist["settings"]?.dictionary) } override var archiveComment: String { @@ -43,13 +91,6 @@ public final class PBXBuildFile: PBXObject { visitor.visit(object: fileRef) } - override var plistRepresentation: [String : Any?] { - var plist = super.plistRepresentation - plist["fileRef"] = fileRef?.plistID - plist["settings"] = settings - return plist - } - override var archiveInPlistOnSingleLine: Bool { return true } diff --git a/Sources/XcodeProject/Objects/PBXBuildRule.swift b/Sources/XcodeProject/Objects/PBXBuildRule.swift index 10381da..c306db4 100644 --- a/Sources/XcodeProject/Objects/PBXBuildRule.swift +++ b/Sources/XcodeProject/Objects/PBXBuildRule.swift @@ -7,6 +7,13 @@ // public final class PBXBuildRule: PBXObject { + private enum CodingKeys: String, CodingKey { + case compilerSpec + case fileType + case isEditable + case outputFiles + case script + } var compilerSpec: String? var fileType: String? var isEditable: Bool = true @@ -22,13 +29,13 @@ public final class PBXBuildRule: PBXObject { self.script = plist["script"]?.string } - override var plistRepresentation: [String : Any?] { - var plist = super.plistRepresentation - plist["compilerSpec"] = compilerSpec - plist["fileType"] = fileType - plist["isEditable"] = isEditable - plist["outputFiles"] = outputFiles - plist["script"] = script - return plist + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(compilerSpec, forKey: .compilerSpec) + try container.encodeIfPresent(fileType, forKey: .fileType) + try container.encode(isEditable, forKey: .isEditable) + try container.encode(outputFiles, forKey: .outputFiles) + try container.encodeIfPresent(script, forKey: .script) } } diff --git a/Sources/XcodeProject/Objects/PBXContainerItemProxy.swift b/Sources/XcodeProject/Objects/PBXContainerItemProxy.swift index 4689956..671a69f 100644 --- a/Sources/XcodeProject/Objects/PBXContainerItemProxy.swift +++ b/Sources/XcodeProject/Objects/PBXContainerItemProxy.swift @@ -7,7 +7,14 @@ // final class PBXContainerItemProxy: PBXObject { - enum ProxyType: Int8 { + private enum CodingKeys: String, CodingKey { + case containerPortal + case proxyType + case remoteGlobalIDString + case remoteInfo + } + + enum ProxyType: Int8, Encodable { case nativeTarget = 1 case reference = 2 @@ -44,12 +51,12 @@ final class PBXContainerItemProxy: PBXObject { visitor.visit(object: containerPortal) } - override var plistRepresentation: [String: Any?] { - var plist = super.plistRepresentation - plist["containerPortal"] = containerPortal?.plistID - plist["proxyType"] = proxyType?.rawValue - plist["remoteGlobalIDString"] = remoteGlobalIDString - plist["remoteInfo"] = remoteInfo - return plist + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(containerPortal, forKey: .containerPortal) + try container.encodeIfPresent(proxyType, forKey: .proxyType) + try container.encodeIfPresent(remoteGlobalIDString, forKey: .remoteGlobalIDString) + try container.encodeIfPresent(remoteInfo, forKey: .remoteInfo) } } diff --git a/Sources/XcodeProject/Objects/PBXGlobalID.swift b/Sources/XcodeProject/Objects/PBXGlobalID.swift index 95b06ca..5fec291 100644 --- a/Sources/XcodeProject/Objects/PBXGlobalID.swift +++ b/Sources/XcodeProject/Objects/PBXGlobalID.swift @@ -7,10 +7,7 @@ import Foundation -public struct PBXGlobalID: RawRepresentable, CustomStringConvertible, CustomDebugStringConvertible { - public var description: String { return rawValue } - public var debugDescription: String { return rawValue } - +public struct PBXGlobalID: Encodable, RawRepresentable, CustomStringConvertible, CustomDebugStringConvertible { public let rawValue: String public init(rawValue: String) { @@ -26,6 +23,14 @@ public struct PBXGlobalID: RawRepresentable, CustomStringConvertible, CustomDebu self.rawValue = PBXGlobalID.generator.next() } + public var description: String { + return rawValue + } + + public var debugDescription: String { + return rawValue + } + static func ids(from strings: [String]?) -> [PBXGlobalID]? { return strings?.compactMap { return PBXGlobalID(rawValue: $0) } } diff --git a/Sources/XcodeProject/Objects/PBXObject.swift b/Sources/XcodeProject/Objects/PBXObject.swift index 58780a0..a4f2462 100644 --- a/Sources/XcodeProject/Objects/PBXObject.swift +++ b/Sources/XcodeProject/Objects/PBXObject.swift @@ -6,7 +6,11 @@ // Copyright © 2017 Geoffrey Foster. All rights reserved. // -public class PBXObject { +public class PBXObject: Encodable { + private enum CodingKeys: String, CodingKey { + case isa + } + public let globalID: PBXGlobalID public internal(set) weak var parent: PBXObject? { willSet { @@ -21,6 +25,11 @@ public class PBXObject { self.globalID = globalID } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(isa, forKey: .isa) + } + func willMove(from: PBXObject?) { guard let from = from else { return } from.parentProject?.objects[globalID] = nil @@ -38,7 +47,7 @@ public class PBXObject { // MARK: - Archiving var archiveComment: String { - return String(describing: type(of:self)) + return String(describing: type(of: self)) } func visit(_ visitor: ObjectVisitor) { @@ -50,15 +59,7 @@ public class PBXObject { } var plistID: PlistID { - var plistID = "\(globalID.rawValue.quotedString)" - if archiveComment.isEmpty == false { - plistID += " /* \(archiveComment) */" - } - return PlistID(rawValue: plistID) - } - - var plistRepresentation: [String: Any?] { - return ["isa": PlistISA(rawValue: isa)] + return PlistID(globalID, comment: archiveComment) } var archiveInPlistOnSingleLine: Bool { @@ -80,19 +81,30 @@ public protocol PBXContainer { var name: String? { get } } -struct PlistID: CustomStringConvertible { - public let rawValue: String +struct PlistID: Encodable, CustomStringConvertible { + public let objectID: PBXGlobalID + public let comment: String? - public var description: String { - return rawValue + init(_ objectID: PBXGlobalID, comment: String?) { + self.objectID = objectID + if let comment = comment, comment.isEmpty { + self.comment = nil + } else { + self.comment = comment + } } -} - -struct PlistISA: CustomStringConvertible { - public let rawValue: String public var description: String { - return rawValue + var string = "\(objectID)" + if let comment = comment { + string += " /* \(comment) */" + } + return string + } + + func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(description) } } diff --git a/Sources/XcodeProject/Objects/PBXProject.swift b/Sources/XcodeProject/Objects/PBXProject.swift index 2a1fd19..3ba290d 100644 --- a/Sources/XcodeProject/Objects/PBXProject.swift +++ b/Sources/XcodeProject/Objects/PBXProject.swift @@ -9,13 +9,79 @@ import Foundation public final class PBXProject: PBXObject, PBXContainer { - var attributes: [String: Any] = [:] - var buildConfigurationList: XCConfigurationList { - didSet { - buildConfigurationList.parent = self + private enum CodingKeys: String, CodingKey { + case attributes + case buildConfigurationList + case compatibilityVersion + case developmentRegion + case hasScannedForEncodings + case knownRegions + case mainGroup + case productRefGroup + case projectDirPath + case projectReferences + case projectRoot + case targets + } + + public class Attributes: Encodable { + public enum Value: Encodable { + case string(String) + case array([Value]) + case dictionary([String: Value]) + + public func encode(to encoder: Encoder) throws { + switch self { + case .string(let string): + var container = encoder.singleValueContainer() + try container.encode(string) + case .array(let array): + var container = encoder.unkeyedContainer() + for value in array { + try container.encode(value) + } + case .dictionary(let dictionary): + var container = encoder.container(keyedBy: AnyCodingKey.self) + for (key, value) in dictionary { + try container.encode(value, forKey: AnyCodingKey(stringValue: key)!) + } + } + } + } + private var attributes: [String: Value] = [:] + + init(_ existingAttributes: [String: Any]) { + func decodeAttribute(value: Any) -> Value? { + if let value = value as? String { + return .string(value) + } else if let array = value as? [Any] { + return .array(array.compactMap { decodeAttribute(value: $0) }) + } else if let dictionary = value as? [String: Any] { + var mappedDictionary: [String: Value] = [:] + for (key, value) in dictionary { + if let mappedValue = decodeAttribute(value: value) { + mappedDictionary[key] = mappedValue + } + } + return .dictionary(mappedDictionary) + } else { + return nil + } + } + for existingAttribute in existingAttributes { + if let existingValue = decodeAttribute(value: existingAttribute.value) { + attributes[existingAttribute.key] = existingValue + } + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(attributes) } } - enum CompatibilityVersion: String { + + enum CompatibilityVersion: String, Encodable { case xcode3_0 = "Xcode 3.0" case xcode3_2 = "Xcode 3.2" case xcode6_3 = "Xcode 6.3" @@ -23,6 +89,14 @@ public final class PBXProject: PBXObject, PBXContainer { case xcode9_3 = "Xcode 9.3" case xcode_10 = "Xcode 10.0" } + + var attributes = Attributes([:]) + var buildConfigurationList: XCConfigurationList { + didSet { + buildConfigurationList.parent = self + } + } + var compatibilityVersion: CompatibilityVersion = .xcode8_0 var developmentRegion: String = "English" var hasScannedForEncodings: Bool = false @@ -34,7 +108,7 @@ public final class PBXProject: PBXObject, PBXContainer { } var productRefGroup: PBXGroup var projectDirPath: String? - var projectReferences: [(productGroup: PBXObject, projectRef: PBXFileReference)]? + var projectReferences: Set? var projectRoot: String? public internal(set) var targets: [PBXTarget] = [] { didSet { @@ -88,7 +162,7 @@ public final class PBXProject: PBXObject, PBXContainer { fatalError() } - self.attributes = attributes + self.attributes = Attributes(attributes) self.buildConfigurationList = buildConfigurationList self.compatibilityVersion = compatibilityVersion self.developmentRegion = developmentRegion @@ -98,19 +172,10 @@ public final class PBXProject: PBXObject, PBXContainer { self.productRefGroup = productRefGroup self.projectDirPath = projectDirPath - if let projectReferences = plist["projectReferences"]?.object as? [[String: String]] { - self.projectReferences = projectReferences.compactMap { projectReference in - guard - let projectRefId = PBXGlobalID(rawValue: projectReference["ProjectRef"]), - let projectRef = objectCache.object(for: projectRefId) as? PBXFileReference, - - let productGroupId = PBXGlobalID(rawValue: projectReference["ProductGroup"]), - let productGroup = objectCache.object(for: productGroupId) - else { - return nil - } - return (productGroup: productGroup, projectRef: projectRef) - } + if let projectReferences = plist["projectReferences"]?.objectArray() { + self.projectReferences = Set(projectReferences.map { + XCProjectReferenceInfo(with: $0, objectCache: objectCache) + }) } self.projectRoot = projectRoot @@ -154,25 +219,25 @@ public final class PBXProject: PBXObject, PBXContainer { } projectReferences?.forEach { visitor.visit(object: $0.productGroup) - visitor.visit(object: $0.projectRef) + visitor.visit(object: $0.projectReference) } } - override var plistRepresentation: [String: Any?] { - var plist = super.plistRepresentation - plist["attributes"] = attributes - plist["buildConfigurationList"] = buildConfigurationList.plistID - plist["compatibilityVersion"] = compatibilityVersion.rawValue - plist["developmentRegion"] = developmentRegion - plist["hasScannedForEncodings"] = hasScannedForEncodings - plist["knownRegions"] = knownRegions - plist["mainGroup"] = mainGroup.plistID - plist["productRefGroup"] = productRefGroup.plistID - plist["projectDirPath"] = projectDirPath - plist["projectReferences"] = projectReferences?.map { return ["ProjectRef": $0.projectRef.plistID, "ProductGroup": $0.productGroup.plistID] } - plist["projectRoot"] = projectRoot - plist["targets"] = targets.map { $0.plistID } - return plist + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(attributes, forKey: .attributes) + try container.encode(buildConfigurationList, forKey: .buildConfigurationList) + try container.encode(compatibilityVersion, forKey: .compatibilityVersion) + try container.encode(developmentRegion, forKey: .developmentRegion) + try container.encode(hasScannedForEncodings, forKey: .hasScannedForEncodings) + try container.encode(knownRegions, forKey: .knownRegions) + try container.encode(mainGroup, forKey: .mainGroup) + try container.encode(productRefGroup, forKey: .productRefGroup) + try container.encodeIfPresent(projectDirPath, forKey: .projectDirPath) + try container.encodeIfPresent(projectReferences?.sorted(by: \XCProjectReferenceInfo.projectReference.displayName, using: String.caseInsensitiveCompare), forKey: .projectReferences) + try container.encodeIfPresent(projectRoot, forKey: .projectRoot) + try container.encode(targets, forKey: .targets) } public var name: String? { diff --git a/Sources/XcodeProject/Objects/PBXTargetDependency.swift b/Sources/XcodeProject/Objects/PBXTargetDependency.swift index 7e20694..9a9e5dc 100644 --- a/Sources/XcodeProject/Objects/PBXTargetDependency.swift +++ b/Sources/XcodeProject/Objects/PBXTargetDependency.swift @@ -7,6 +7,12 @@ // public class PBXTargetDependency: PBXObject { + private enum CodingKeys: String, CodingKey { + case name + case target + case targetProxy + } + var name: String? var target: PBXTarget? { didSet { @@ -44,11 +50,11 @@ public class PBXTargetDependency: PBXObject { visitor.visit(object: targetProxy) } - override var plistRepresentation: [String : Any?] { - var plist = super.plistRepresentation - plist["name"] = name - plist["target"] = target?.plistID - plist["targetProxy"] = targetProxy?.plistID - return plist + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(name, forKey: .name) + try container.encodeIfPresent(target, forKey: .target) + try container.encodeIfPresent(targetProxy, forKey: .targetProxy) } } diff --git a/Sources/XcodeProject/Objects/References/PBXFileReference.swift b/Sources/XcodeProject/Objects/References/PBXFileReference.swift index 45d5441..03b8258 100644 --- a/Sources/XcodeProject/Objects/References/PBXFileReference.swift +++ b/Sources/XcodeProject/Objects/References/PBXFileReference.swift @@ -9,6 +9,15 @@ import Foundation public final class PBXFileReference: PBXReference { + private enum CodingKeys: String, CodingKey { + case fileEncoding + case includeInIndex + case xcLanguageSpecificationIdentifier + case wrapsLines + case lastKnownFileType + case explicitFileType + } + public enum FileType { case lastKnown(String) case explicit(String) @@ -36,10 +45,11 @@ public final class PBXFileReference: PBXReference { } } - var fileEncoding: String.Encoding? = nil - var includeInIndex: Bool? + public private(set) var fileEncoding: String.Encoding? = nil + public private(set) var includeInIndex: Bool? public private(set) var fileType: FileType = .unknown - public internal(set) var xcLanguageSpecificationIdentifier: String? // TODO: this should be a PBXFileType (xcode.lang.swift) + public private(set) var xcLanguageSpecificationIdentifier: String? // TODO: this should be a PBXFileType (xcode.lang.swift) + public private(set) var wrapsLines: Bool? public required init(globalID: PBXGlobalID) { super.init(globalID: globalID) @@ -70,22 +80,24 @@ public final class PBXFileReference: PBXReference { self.includeInIndex = plist["includeInIndex"]?.bool self.fileType = FileType.from(plist) self.xcLanguageSpecificationIdentifier = plist["xcLanguageSpecificationIdentifier"]?.string + self.wrapsLines = plist["wrapsLines"]?.bool } - override var plistRepresentation: [String: Any?] { - var plist = super.plistRepresentation - plist["fileEncoding"] = fileEncoding?.rawValue - plist["includeInIndex"] = includeInIndex - plist["xcLanguageSpecificationIdentifier"] = xcLanguageSpecificationIdentifier + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(fileEncoding?.rawValue, forKey: .fileEncoding) + try container.encodeIfPresent(includeInIndex, forKey: .includeInIndex) + try container.encodeIfPresent(xcLanguageSpecificationIdentifier, forKey: .xcLanguageSpecificationIdentifier) + try container.encodeIfPresent(wrapsLines, forKey: .wrapsLines) switch fileType { case .lastKnown(let type): - plist["lastKnownFileType"] = type + try container.encodeIfPresent(type, forKey: .lastKnownFileType) case .explicit(let type): - plist["explicitFileType"] = type + try container.encodeIfPresent(type, forKey: .explicitFileType) case .unknown: break } - return plist } override var archiveInPlistOnSingleLine: Bool { diff --git a/Sources/XcodeProject/Objects/References/PBXGroup.swift b/Sources/XcodeProject/Objects/References/PBXGroup.swift index d43874a..4f8e6fc 100644 --- a/Sources/XcodeProject/Objects/References/PBXGroup.swift +++ b/Sources/XcodeProject/Objects/References/PBXGroup.swift @@ -7,6 +7,10 @@ // public class PBXGroup: PBXReference { + private enum CodingKeys: String, CodingKey { + case children + } + public var children: [PBXReference] = [] { didSet { children.forEach { @@ -15,6 +19,15 @@ public class PBXGroup: PBXReference { } } + public override var isGroup: Bool { return true } + public override var isLeaf: Bool { return false } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(children, forKey: .children) + } + override func willMove(from: PBXObject?) { super.willMove(from: from) children.forEach { @@ -41,12 +54,6 @@ public class PBXGroup: PBXReference { } } - override var plistRepresentation: [String : Any?] { - var plist = super.plistRepresentation - plist["children"] = children.map { $0.plistID } - return plist - } - public func add(child: PBXReference) { children.append(child) self.child(child, didMoveTo: self) diff --git a/Sources/XcodeProject/Objects/References/PBXReference.swift b/Sources/XcodeProject/Objects/References/PBXReference.swift index 4b6e9b9..1e734b2 100644 --- a/Sources/XcodeProject/Objects/References/PBXReference.swift +++ b/Sources/XcodeProject/Objects/References/PBXReference.swift @@ -9,7 +9,17 @@ import Foundation public class PBXReference: PBXObject { - public enum SourceTree: String { + private enum CodingKeys: String, CodingKey { + case name + case path + case sourceTree + case usesTabs + case lineEnding + case tabWidth + case indentWidth + } + + public enum SourceTree: String, Encodable { case absolute = "" case group = "" case project = "SOURCE_ROOT" @@ -18,24 +28,12 @@ public class PBXReference: PBXObject { case sdkRoot = "SDKROOT" } - enum LineEnding: Int8 { + public enum LineEnding: Int8, Encodable { case lf = 0 case cr = 1 case crlf = 2 } - public internal(set) var path: String? - public internal(set) var name: String? - public internal(set) var sourceTree: SourceTree? - var usesTabs: Bool? - var tabWidth: Int? - var lineEnding: LineEnding? - var indentWidth: Int? - - var buildFiles: [PBXBuildFile] { - return _buildFiles.compactMap { $0.item } - } - private struct WeakBuildFile: Hashable { weak var item: PBXBuildFile? @@ -48,16 +46,20 @@ public class PBXReference: PBXObject { } } - private var _buildFiles: Array = [] - - func register(buildFile: PBXBuildFile) { - _buildFiles.removeAll { $0.item == nil } - _buildFiles.append(WeakBuildFile(item: buildFile)) + public internal(set) var path: String? + public internal(set) var name: String? + public internal(set) var sourceTree: SourceTree? + public internal(set) var usesTabs: Bool? + public internal(set) var tabWidth: Int? + public internal(set) var lineEnding: LineEnding? + public internal(set) var indentWidth: Int? + public var buildFiles: [PBXBuildFile] { + return _buildFiles.compactMap { $0.item } } + public var isGroup: Bool { return false } + public var isLeaf: Bool { return true } - func unregister(buildFile: PBXBuildFile) { - _buildFiles.removeAll { $0.item == nil || $0.item == buildFile } - } + private var _buildFiles: Array = [] public var displayName: String { if let name = name { @@ -85,6 +87,18 @@ public class PBXReference: PBXObject { } } + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(name, forKey: .name) + try container.encodeIfPresent(path, forKey: .path) + try container.encodeIfPresent(sourceTree, forKey: .sourceTree) + try container.encodeIfPresent(usesTabs, forKey: .usesTabs) + try container.encodeIfPresent(lineEnding, forKey: .lineEnding) + try container.encodeIfPresent(tabWidth, forKey: .tabWidth) + try container.encodeIfPresent(indentWidth, forKey: .indentWidth) + } + // MARK: - PList Unarchiving override func update(with plist: PropertyList, objectCache: ObjectCache) { super.update(with: plist, objectCache: objectCache) @@ -108,15 +122,12 @@ public class PBXReference: PBXObject { return "" } - override var plistRepresentation: [String: Any?] { - var plist = super.plistRepresentation - plist["name"] = name - plist["path"] = path - plist["sourceTree"] = sourceTree?.rawValue - plist["usesTabs"] = usesTabs - plist["lineEnding"] = lineEnding?.rawValue - plist["tabWidth"] = tabWidth - plist["indentWidth"] = indentWidth - return plist + func register(buildFile: PBXBuildFile) { + _buildFiles.removeAll { $0.item == nil } + _buildFiles.append(WeakBuildFile(item: buildFile)) + } + + func unregister(buildFile: PBXBuildFile) { + _buildFiles.removeAll { $0.item == nil || $0.item == buildFile } } } diff --git a/Sources/XcodeProject/Objects/References/PBXReferenceProxy.swift b/Sources/XcodeProject/Objects/References/PBXReferenceProxy.swift index 65bc785..23f5d7e 100644 --- a/Sources/XcodeProject/Objects/References/PBXReferenceProxy.swift +++ b/Sources/XcodeProject/Objects/References/PBXReferenceProxy.swift @@ -7,6 +7,11 @@ // public final class PBXReferenceProxy: PBXReference { + private enum CodingKeys: String, CodingKey { + case fileType + case remoteRef + } + var fileType: String? //PBXFileType var remoteRef: PBXContainerItemProxy? { didSet { @@ -36,10 +41,10 @@ public final class PBXReferenceProxy: PBXReference { visitor.visit(object: remoteRef) } - override var plistRepresentation: [String: Any?] { - var plist = super.plistRepresentation - plist["fileType"] = fileType - plist["remoteRef"] = remoteRef?.plistID - return plist + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(fileType, forKey: .fileType) + try container.encodeIfPresent(remoteRef, forKey: .remoteRef) } } diff --git a/Sources/XcodeProject/Objects/References/XCVersionGroup.swift b/Sources/XcodeProject/Objects/References/XCVersionGroup.swift index bf4e40f..f6171b8 100644 --- a/Sources/XcodeProject/Objects/References/XCVersionGroup.swift +++ b/Sources/XcodeProject/Objects/References/XCVersionGroup.swift @@ -7,6 +7,11 @@ // public final class XCVersionGroup: PBXGroup { + private enum CodingKeys: String, CodingKey { + case currentVersion + case versionGroupType + } + var currentVersion: PBXFileReference? { didSet { currentVersion?.parent = self @@ -38,10 +43,10 @@ public final class XCVersionGroup: PBXGroup { self.versionGroupType = versionGroupType } - override var plistRepresentation: [String: Any?] { - var plist = super.plistRepresentation - plist["currentVersion"] = currentVersion?.plistID - plist["versionGroupType"] = versionGroupType - return plist + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(currentVersion?.plistID, forKey: .currentVersion) + try container.encodeIfPresent(versionGroupType, forKey: .versionGroupType) } } diff --git a/Sources/XcodeProject/Objects/Targets/PBXLegacyTarget.swift b/Sources/XcodeProject/Objects/Targets/PBXLegacyTarget.swift index 97e2d76..955bd65 100644 --- a/Sources/XcodeProject/Objects/Targets/PBXLegacyTarget.swift +++ b/Sources/XcodeProject/Objects/Targets/PBXLegacyTarget.swift @@ -7,6 +7,13 @@ // public final class PBXLegacyTarget: PBXTarget { + private enum CodingKeys: String, CodingKey { + case buildArgumentsString + case buildToolPath + case buildWorkingDirectory + case passBuildSettingsInEnvironment + } + var buildArguments: String? var buildToolPath: String? var buildWorkingDirectory: String? @@ -23,12 +30,12 @@ public final class PBXLegacyTarget: PBXTarget { } } - override var plistRepresentation: [String : Any?] { - var plist = super.plistRepresentation - plist["buildArgumentsString"] = buildArguments - plist["buildToolPath"] = buildToolPath - plist["buildWorkingDirectory"] = buildWorkingDirectory - plist["passBuildSettingsInEnvironment"] = passBuildSettingsInEnvironment - return plist + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(buildArguments, forKey: .buildArgumentsString) + try container.encode(buildToolPath, forKey: .buildToolPath) + try container.encode(buildWorkingDirectory, forKey: .buildWorkingDirectory) + try container.encode(passBuildSettingsInEnvironment, forKey: .passBuildSettingsInEnvironment) } } diff --git a/Sources/XcodeProject/Objects/Targets/PBXNativeTarget.swift b/Sources/XcodeProject/Objects/Targets/PBXNativeTarget.swift index f2bbbdc..06a6a51 100644 --- a/Sources/XcodeProject/Objects/Targets/PBXNativeTarget.swift +++ b/Sources/XcodeProject/Objects/Targets/PBXNativeTarget.swift @@ -7,7 +7,11 @@ // public final class PBXNativeTarget: PBXTarget { - public enum ProductType: String { + private enum CodingKeys: String, CodingKey { + case productType + } + + public enum ProductType: String, Encodable { case application = "com.apple.product-type.application" case framework = "com.apple.product-type.framework" case dynamicLibrary = "com.apple.product-type.library.dynamic" @@ -42,10 +46,10 @@ public final class PBXNativeTarget: PBXTarget { self.productType = productType } - override var plistRepresentation: [String : Any?] { - var plist = super.plistRepresentation - plist["productType"] = productType.rawValue - return plist + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(productType, forKey: .productType) } public override func addBuildPhase() -> T? { diff --git a/Sources/XcodeProject/Objects/Targets/PBXTarget.swift b/Sources/XcodeProject/Objects/Targets/PBXTarget.swift index a36c0ef..6da370f 100644 --- a/Sources/XcodeProject/Objects/Targets/PBXTarget.swift +++ b/Sources/XcodeProject/Objects/Targets/PBXTarget.swift @@ -7,6 +7,16 @@ // public class PBXTarget: PBXObject, PBXContainer { + private enum CodingKeys: String, CodingKey { + case buildConfigurationList + case buildPhases + case buildRules + case dependencies + case name + case productName + case productReference + } + class var allowedBuildPhases: [PBXBuildPhase.Type] { return [] } @@ -106,16 +116,16 @@ public class PBXTarget: PBXObject, PBXContainer { visitor.visit(object: productReference) } - override var plistRepresentation: [String : Any?] { - var plist = super.plistRepresentation - plist["buildConfigurationList"] = buildConfigurationList?.plistID - plist["buildPhases"] = buildPhases.map { $0.plistID } - plist["buildRules"] = buildRules?.map { $0.plistID } - plist["dependencies"] = dependencies.map { $0.plistID } - plist["name"] = name - plist["productName"] = productName - plist["productReference"] = productReference?.plistID - return plist + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(buildConfigurationList, forKey: .buildConfigurationList) + try container.encodeIfPresent(buildPhases, forKey: .buildPhases) + try container.encodeIfPresent(buildRules, forKey: .buildRules) + try container.encode(dependencies, forKey: .dependencies) + try container.encodeIfPresent(name, forKey: .name) + try container.encodeIfPresent(productName, forKey: .productName) + try container.encodeIfPresent(productReference, forKey: .productReference) } } diff --git a/Sources/XcodeProject/Objects/XCBuildConfiguration.swift b/Sources/XcodeProject/Objects/XCBuildConfiguration.swift index 924efa2..3ca94a2 100644 --- a/Sources/XcodeProject/Objects/XCBuildConfiguration.swift +++ b/Sources/XcodeProject/Objects/XCBuildConfiguration.swift @@ -9,6 +9,11 @@ import Foundation final class XCBuildConfiguration: PBXObject { + private enum CodingKeys: String, CodingKey { + case name + case buildSettings + case baseConfigurationReference + } var name: String? var buildSettings = BuildSettings([:]) var baseConfigurationReference: PBXFileReference? @@ -44,16 +49,16 @@ final class XCBuildConfiguration: PBXObject { visitor.visit(object: baseConfigurationReference) } - override var plistRepresentation: [String : Any?] { - var plist = super.plistRepresentation - plist["name"] = name - plist["buildSettings"] = buildSettings - plist["baseConfigurationReference"] = baseConfigurationReference?.plistID - return plist + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(name, forKey: .name) + try container.encode(buildSettings, forKey: .buildSettings) + try container.encodeIfPresent(baseConfigurationReference, forKey: .baseConfigurationReference) } } -struct BuildSettings: PListArchivable { +struct BuildSettings: Encodable { // CODE_SIGN_IDENTITY = "iPhone Developer"; // "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -109,30 +114,31 @@ struct BuildSettings: PListArchivable { } } - // where * in the sdk = 10.2, 10.12, 3.1, etc - struct Value: PListArchivable { - let value: Any + enum Value: Encodable { + case string(String) + case array([String]) + init?(_ value: Any) { - if value is String || value is [String] { - self.value = value + if let value = value as? String { + self = .string(value) + } else if let value = value as? [String] { + self = .array(value) } else { return nil } } - var string: String? { - return value as? String - } - - var array: [String]? { - return value as? [String] - } - - func plistRepresentation(format: Format) -> String { - guard let value = value as? PListArchivable else { - fatalError() + func encode(to encoder: Encoder) throws { + switch self { + case .string(let value): + var container = encoder.singleValueContainer() + try container.encode(value) + case .array(let values): + var container = encoder.unkeyedContainer() + try values.forEach { + try container.encode($0) + } } - return value.plistRepresentation(format: format) } } @@ -154,7 +160,11 @@ struct BuildSettings: PListArchivable { return settings[sdkString] } - func plistRepresentation(format: Format) -> String { - return settings.plistRepresentation(format: format) + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: AnyCodingKey.self) + for setting in settings { + let key = AnyCodingKey(stringValue: setting.key)! + try container.encode(setting.value, forKey: key) + } } } diff --git a/Sources/XcodeProject/Objects/XCConfigurationList.swift b/Sources/XcodeProject/Objects/XCConfigurationList.swift index cc2bc4d..8da89cf 100644 --- a/Sources/XcodeProject/Objects/XCConfigurationList.swift +++ b/Sources/XcodeProject/Objects/XCConfigurationList.swift @@ -7,6 +7,12 @@ // final class XCConfigurationList: PBXObject { + private enum CodingKeys: String, CodingKey { + case buildConfigurations + case defaultConfigurationIsVisible + case defaultConfigurationName + } + var buildConfigurations: [XCBuildConfiguration] = [] { didSet { buildConfigurations.forEach { $0.parent = self } @@ -65,11 +71,11 @@ final class XCConfigurationList: PBXObject { return comment } - override var plistRepresentation: [String : Any?] { - var plist = super.plistRepresentation - plist["buildConfigurations"] = buildConfigurations.map { $0.plistID } - plist["defaultConfigurationIsVisible"] = defaultConfigurationIsVisible - plist["defaultConfigurationName"] = defaultConfigurationName - return plist + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(buildConfigurations, forKey: .buildConfigurations) + try container.encode(defaultConfigurationIsVisible, forKey: .defaultConfigurationIsVisible) + try container.encodeIfPresent(defaultConfigurationName, forKey: .defaultConfigurationName) } } diff --git a/Sources/XcodeProject/Objects/XCProjectReferenceInfo.swift b/Sources/XcodeProject/Objects/XCProjectReferenceInfo.swift new file mode 100644 index 0000000..9652f1b --- /dev/null +++ b/Sources/XcodeProject/Objects/XCProjectReferenceInfo.swift @@ -0,0 +1,47 @@ +// +// XCProjectReferenceInfo.swift +// XcodeProject +// +// Created by Geoffrey Foster on 2019-06-23. +// + +import Foundation + +final class XCProjectReferenceInfo: Hashable, Encodable { + static func == (lhs: XCProjectReferenceInfo, rhs: XCProjectReferenceInfo) -> Bool { + return lhs.productGroup == rhs.productGroup && lhs.projectReference == rhs.projectReference + } + + private enum CodingKeys: String, CodingKey { + case productGroup = "ProductGroup" + case projectReference = "ProjectRef" + } + + var productGroup: PBXGroup + var projectReference: PBXFileReference + + init(with plist: PropertyList, objectCache: ObjectCache) { + guard let productGroupID = PBXGlobalID(rawValue: plist[CodingKeys.productGroup.rawValue]?.string), + let productGroup = objectCache.object(for: productGroupID) as? PBXGroup else { + fatalError() + } + guard let projectReferenceId = PBXGlobalID(rawValue: plist[CodingKeys.projectReference.rawValue]?.string), + let projectReference = objectCache.object(for: projectReferenceId) as? PBXFileReference else { + fatalError() + } + + self.productGroup = productGroup + self.projectReference = projectReference + } + + func hash(into hasher: inout Hasher) { + hasher.combine(productGroup) + hasher.combine(projectReference) + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(productGroup, forKey: .productGroup) + try container.encode(projectReference, forKey: .projectReference) + } +} diff --git a/Sources/XcodeProject/ProjectFile.swift b/Sources/XcodeProject/ProjectFile.swift index eb75129..cc60f2d 100644 --- a/Sources/XcodeProject/ProjectFile.swift +++ b/Sources/XcodeProject/ProjectFile.swift @@ -8,6 +8,19 @@ import Foundation +public enum ObjectVersion: UInt, Comparable, CaseIterable { + public static func < (lhs: ObjectVersion, rhs: ObjectVersion) -> Bool { + return lhs.rawValue < rhs.rawValue + } + + case xcode31 = 45 + case xcode32 = 46 + case xcode63 = 47 + case xcode8 = 48 + case xcode93 = 50 + case xcode10 = 51 +} + public final class ProjectFile { enum Error: Swift.Error { case invalid @@ -22,15 +35,6 @@ public final class ProjectFile { static let rootObject = "rootObject" } - public enum ObjectVersion: UInt { - case xcode31 = 45 - case xcode32 = 46 - case xcode63 = 47 - case xcode8 = 48 - case xcode93 = 50 - case xcode10 = 51 - } - var archiveVersion: UInt = 1 var objectVersion: ObjectVersion = .xcode8 var classes: [AnyHashable: Any] = [:] diff --git a/Tests/XcodeProjectTests/XCTestManifests.swift b/Tests/XcodeProjectTests/XCTestManifests.swift index 364f0b7..9533529 100644 --- a/Tests/XcodeProjectTests/XCTestManifests.swift +++ b/Tests/XcodeProjectTests/XCTestManifests.swift @@ -1,25 +1,29 @@ +#if !canImport(ObjectiveC) import XCTest extension PBXGlobalIDTests { - static let __allTests = [ + // DO NOT MODIFY: This is autogenerated, use: + // `swift test --generate-linuxmain` + // to regenerate. + static let __allTests__PBXGlobalIDTests = [ ("testIDGeneration", testIDGeneration), ] } extension XcodeProjectTests { - static let __allTests = [ + // DO NOT MODIFY: This is autogenerated, use: + // `swift test --generate-linuxmain` + // to regenerate. + static let __allTests__XcodeProjectTests = [ ("testAggregateTarget", testAggregateTarget), ("testPrivateProjectFolder", testPrivateProjectFolder), - ("testSelfArchive", testSelfArchive), - ("testSelfSave", testSelfSave), ] } -#if !os(macOS) public func __allTests() -> [XCTestCaseEntry] { return [ - testCase(PBXGlobalIDTests.__allTests), - testCase(XcodeProjectTests.__allTests), + testCase(PBXGlobalIDTests.__allTests__PBXGlobalIDTests), + testCase(XcodeProjectTests.__allTests__XcodeProjectTests), ] } #endif diff --git a/Tests/XcodeProjectTests/XcodeProjectTests.swift b/Tests/XcodeProjectTests/XcodeProjectTests.swift index 2744a63..fa12f96 100644 --- a/Tests/XcodeProjectTests/XcodeProjectTests.swift +++ b/Tests/XcodeProjectTests/XcodeProjectTests.swift @@ -39,24 +39,12 @@ class XcodeProjectTests: XCTestCase { if streamWriter.string != string { let failureURL = URL(fileURLWithPath: "\(NSTemporaryDirectory())\(UUID().uuidString).pbxproj") try streamWriter.string.write(to: failureURL, atomically: true, encoding: .utf8) + add(XCTAttachment(contentsOfFile: failureURL)) XCTFail("Failed to generate matching output for \(url.lastPathComponent). Run ksdiff \(url.path) \(failureURL.path)") } } - func testSelfArchive() throws { - // Disabled this test for now because Swift Package Manager generates project in a way that isn't great. The main group always has an empty comment associated with it, but Xcode doesn't do this >:( - //try assertReadWriteProject(url: selfPath) - } - - func testSelfSave() throws { - let copiedProjectURL = URL(fileURLWithPath: "\(NSTemporaryDirectory())\(UUID().uuidString).xcodeproj", isDirectory: true) - try FileManager.default.copyItem(at: selfPath, to: copiedProjectURL) - let projectFile = try ProjectFile(url: copiedProjectURL) - projectFile.project.mainGroup.sort(recursive: true, by: .type) - try projectFile.save() - } - func testAggregateTarget() throws { try assertReadWriteProject(url: try urlForProject(named: "AggregateLibrary")) } diff --git a/XcodeProject.xcodeproj/project.pbxproj b/XcodeProject.xcodeproj/project.pbxproj deleted file mode 100644 index 3dbefb4..0000000 --- a/XcodeProject.xcodeproj/project.pbxproj +++ /dev/null @@ -1,665 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 6C2643E21E11C16A0057CFA4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C2643E11E11C16A0057CFA4 /* Foundation.framework */; }; - 6C2644091E11C80A0057CFA4 /* PBXPListArchiver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643E51E11C80A0057CFA4 /* PBXPListArchiver.swift */; }; - 6C26440A1E11C80A0057CFA4 /* PBXPListUnarchiver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643E61E11C80A0057CFA4 /* PBXPListUnarchiver.swift */; }; - 6C26440B1E11C80A0057CFA4 /* PListArchivable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643E71E11C80A0057CFA4 /* PListArchivable.swift */; }; - 6C26440C1E11C80A0057CFA4 /* PropertyList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643E81E11C80A0057CFA4 /* PropertyList.swift */; }; - 6C26440D1E11C80A0057CFA4 /* PBXGlobalID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643EA1E11C80A0057CFA4 /* PBXGlobalID.swift */; }; - 6C26440E1E11C80A0057CFA4 /* PBXAggregateTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643EC1E11C80A0057CFA4 /* PBXAggregateTarget.swift */; }; - 6C26440F1E11C80A0057CFA4 /* PBXBuildFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643ED1E11C80A0057CFA4 /* PBXBuildFile.swift */; }; - 6C2644101E11C80A0057CFA4 /* PBXBuildPhase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643EE1E11C80A0057CFA4 /* PBXBuildPhase.swift */; }; - 6C2644111E11C80A0057CFA4 /* PBXBuildRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643EF1E11C80A0057CFA4 /* PBXBuildRule.swift */; }; - 6C2644121E11C80A0057CFA4 /* PBXContainerItemProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643F01E11C80A0057CFA4 /* PBXContainerItemProxy.swift */; }; - 6C2644131E11C80A0057CFA4 /* PBXCopyFilesBuildPhase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643F11E11C80A0057CFA4 /* PBXCopyFilesBuildPhase.swift */; }; - 6C2644141E11C80A0057CFA4 /* PBXFileReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643F21E11C80A0057CFA4 /* PBXFileReference.swift */; }; - 6C2644151E11C80A0057CFA4 /* PBXFrameworksBuildPhase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643F31E11C80A0057CFA4 /* PBXFrameworksBuildPhase.swift */; }; - 6C2644161E11C80A0057CFA4 /* PBXGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643F41E11C80A0057CFA4 /* PBXGroup.swift */; }; - 6C2644171E11C80A0057CFA4 /* PBXHeadersBuildPhase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643F51E11C80A0057CFA4 /* PBXHeadersBuildPhase.swift */; }; - 6C2644181E11C80A0057CFA4 /* PBXLegacyTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643F61E11C80A0057CFA4 /* PBXLegacyTarget.swift */; }; - 6C2644191E11C80A0057CFA4 /* PBXNativeTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643F71E11C80A0057CFA4 /* PBXNativeTarget.swift */; }; - 6C26441A1E11C80A0057CFA4 /* PBXObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643F81E11C80A0057CFA4 /* PBXObject.swift */; }; - 6C26441B1E11C80A0057CFA4 /* PBXProject+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643F91E11C80A0057CFA4 /* PBXProject+Helpers.swift */; }; - 6C26441C1E11C80A0057CFA4 /* PBXProject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643FA1E11C80A0057CFA4 /* PBXProject.swift */; }; - 6C26441D1E11C80A0057CFA4 /* PBXReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643FB1E11C80A0057CFA4 /* PBXReference.swift */; }; - 6C26441E1E11C80A0057CFA4 /* PBXReferenceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643FC1E11C80A0057CFA4 /* PBXReferenceProxy.swift */; }; - 6C26441F1E11C80A0057CFA4 /* PBXResourcesBuildPhase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643FD1E11C80A0057CFA4 /* PBXResourcesBuildPhase.swift */; }; - 6C2644201E11C80A0057CFA4 /* PBXShellScriptBuildPhase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643FE1E11C80A0057CFA4 /* PBXShellScriptBuildPhase.swift */; }; - 6C2644211E11C80A0057CFA4 /* PBXSourcesBuildPhase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2643FF1E11C80A0057CFA4 /* PBXSourcesBuildPhase.swift */; }; - 6C2644221E11C80A0057CFA4 /* PBXTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2644001E11C80A0057CFA4 /* PBXTarget.swift */; }; - 6C2644231E11C80A0057CFA4 /* PBXTargetDependency.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2644011E11C80A0057CFA4 /* PBXTargetDependency.swift */; }; - 6C2644241E11C80A0057CFA4 /* PBXVariantGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2644021E11C80A0057CFA4 /* PBXVariantGroup.swift */; }; - 6C2644251E11C80A0057CFA4 /* XCBuildConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2644031E11C80A0057CFA4 /* XCBuildConfiguration.swift */; }; - 6C2644261E11C80A0057CFA4 /* XCConfigurationList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2644041E11C80A0057CFA4 /* XCConfigurationList.swift */; }; - 6C2644271E11C80A0057CFA4 /* XCVersionGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2644051E11C80A0057CFA4 /* XCVersionGroup.swift */; }; - 6C2644281E11C80A0057CFA4 /* ProjectFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2644061E11C80A0057CFA4 /* ProjectFile.swift */; }; - 6C82B6841FFC03180040FD50 /* Workspace.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C82B6831FFC03180040FD50 /* Workspace.swift */; }; - 6CD2228D1DDD5C180058C7CD /* XcodeProject.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CD222831DDD5C180058C7CD /* XcodeProject.framework */; }; - 6CD222921DDD5C180058C7CD /* XcodeProjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CD222911DDD5C180058C7CD /* XcodeProjectTests.swift */; }; - 6CE0F78A1E0C69FC001DF692 /* PBXGlobalIDTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CE0F7891E0C69FC001DF692 /* PBXGlobalIDTests.swift */; }; - 6CE346AD1FE9B2E400EFF588 /* PBXGroup+Sorting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CE346AC1FE9B2E400EFF588 /* PBXGroup+Sorting.swift */; }; - 6CE346AF1FE9B45E00EFF588 /* PBXGroup+FolderSync.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CE346AE1FE9B45E00EFF588 /* PBXGroup+FolderSync.swift */; }; - 6CE346B11FE9B4F600EFF588 /* PBXReference+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CE346B01FE9B4F600EFF588 /* PBXReference+Extensions.swift */; }; - 6CE346CC1FECA29100EFF588 /* PBXTarget+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CE346CB1FECA29100EFF588 /* PBXTarget+Extensions.swift */; }; - 6CE346CE1FECAF7C00EFF588 /* PBXFileType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CE346CD1FECAF7C00EFF588 /* PBXFileType.swift */; }; - 6CE3A46E21B782E500C4C039 /* PBXGlobalID+Generator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CE3A46D21B782E500C4C039 /* PBXGlobalID+Generator.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 6CD2228E1DDD5C180058C7CD /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 6CD2227A1DDD5C170058C7CD /* Project object */; - proxyType = 1; - remoteGlobalIDString = 6CD222821DDD5C170058C7CD; - remoteInfo = XcodeProject; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 6C2643DF1E11C0E50057CFA4 /* GameplayKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameplayKit.framework; path = System/Library/Frameworks/GameplayKit.framework; sourceTree = SDKROOT; }; - 6C2643E11E11C16A0057CFA4 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 6C2643E51E11C80A0057CFA4 /* PBXPListArchiver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXPListArchiver.swift; sourceTree = ""; }; - 6C2643E61E11C80A0057CFA4 /* PBXPListUnarchiver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXPListUnarchiver.swift; sourceTree = ""; }; - 6C2643E71E11C80A0057CFA4 /* PListArchivable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PListArchivable.swift; sourceTree = ""; }; - 6C2643E81E11C80A0057CFA4 /* PropertyList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PropertyList.swift; sourceTree = ""; }; - 6C2643EA1E11C80A0057CFA4 /* PBXGlobalID.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXGlobalID.swift; sourceTree = ""; }; - 6C2643EC1E11C80A0057CFA4 /* PBXAggregateTarget.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXAggregateTarget.swift; sourceTree = ""; }; - 6C2643ED1E11C80A0057CFA4 /* PBXBuildFile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXBuildFile.swift; sourceTree = ""; }; - 6C2643EE1E11C80A0057CFA4 /* PBXBuildPhase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXBuildPhase.swift; sourceTree = ""; }; - 6C2643EF1E11C80A0057CFA4 /* PBXBuildRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXBuildRule.swift; sourceTree = ""; }; - 6C2643F01E11C80A0057CFA4 /* PBXContainerItemProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXContainerItemProxy.swift; sourceTree = ""; }; - 6C2643F11E11C80A0057CFA4 /* PBXCopyFilesBuildPhase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXCopyFilesBuildPhase.swift; sourceTree = ""; }; - 6C2643F21E11C80A0057CFA4 /* PBXFileReference.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; path = PBXFileReference.swift; sourceTree = ""; }; - 6C2643F31E11C80A0057CFA4 /* PBXFrameworksBuildPhase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXFrameworksBuildPhase.swift; sourceTree = ""; }; - 6C2643F41E11C80A0057CFA4 /* PBXGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXGroup.swift; sourceTree = ""; }; - 6C2643F51E11C80A0057CFA4 /* PBXHeadersBuildPhase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXHeadersBuildPhase.swift; sourceTree = ""; }; - 6C2643F61E11C80A0057CFA4 /* PBXLegacyTarget.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXLegacyTarget.swift; sourceTree = ""; }; - 6C2643F71E11C80A0057CFA4 /* PBXNativeTarget.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXNativeTarget.swift; sourceTree = ""; }; - 6C2643F81E11C80A0057CFA4 /* PBXObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXObject.swift; sourceTree = ""; }; - 6C2643F91E11C80A0057CFA4 /* PBXProject+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PBXProject+Helpers.swift"; sourceTree = ""; }; - 6C2643FA1E11C80A0057CFA4 /* PBXProject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXProject.swift; sourceTree = ""; }; - 6C2643FB1E11C80A0057CFA4 /* PBXReference.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXReference.swift; sourceTree = ""; }; - 6C2643FC1E11C80A0057CFA4 /* PBXReferenceProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXReferenceProxy.swift; sourceTree = ""; }; - 6C2643FD1E11C80A0057CFA4 /* PBXResourcesBuildPhase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXResourcesBuildPhase.swift; sourceTree = ""; }; - 6C2643FE1E11C80A0057CFA4 /* PBXShellScriptBuildPhase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXShellScriptBuildPhase.swift; sourceTree = ""; }; - 6C2643FF1E11C80A0057CFA4 /* PBXSourcesBuildPhase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXSourcesBuildPhase.swift; sourceTree = ""; }; - 6C2644001E11C80A0057CFA4 /* PBXTarget.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXTarget.swift; sourceTree = ""; }; - 6C2644011E11C80A0057CFA4 /* PBXTargetDependency.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXTargetDependency.swift; sourceTree = ""; }; - 6C2644021E11C80A0057CFA4 /* PBXVariantGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXVariantGroup.swift; sourceTree = ""; }; - 6C2644031E11C80A0057CFA4 /* XCBuildConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XCBuildConfiguration.swift; sourceTree = ""; }; - 6C2644041E11C80A0057CFA4 /* XCConfigurationList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XCConfigurationList.swift; sourceTree = ""; }; - 6C2644051E11C80A0057CFA4 /* XCVersionGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XCVersionGroup.swift; sourceTree = ""; }; - 6C2644061E11C80A0057CFA4 /* ProjectFile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProjectFile.swift; sourceTree = ""; }; - 6C7AFC381FFEF59800AB707B /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 6C82B6831FFC03180040FD50 /* Workspace.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Workspace.swift; sourceTree = ""; }; - 6CD222831DDD5C180058C7CD /* XcodeProject.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = XcodeProject.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 6CD2228C1DDD5C180058C7CD /* XcodeProjectTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = XcodeProjectTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 6CD222911DDD5C180058C7CD /* XcodeProjectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcodeProjectTests.swift; sourceTree = ""; }; - 6CE0F7891E0C69FC001DF692 /* PBXGlobalIDTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBXGlobalIDTests.swift; sourceTree = ""; }; - 6CE346AC1FE9B2E400EFF588 /* PBXGroup+Sorting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PBXGroup+Sorting.swift"; sourceTree = ""; }; - 6CE346AE1FE9B45E00EFF588 /* PBXGroup+FolderSync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PBXGroup+FolderSync.swift"; sourceTree = ""; }; - 6CE346B01FE9B4F600EFF588 /* PBXReference+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PBXReference+Extensions.swift"; sourceTree = ""; }; - 6CE346CB1FECA29100EFF588 /* PBXTarget+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PBXTarget+Extensions.swift"; sourceTree = ""; }; - 6CE346CD1FECAF7C00EFF588 /* PBXFileType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PBXFileType.swift; sourceTree = ""; }; - 6CE3A46D21B782E500C4C039 /* PBXGlobalID+Generator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PBXGlobalID+Generator.swift"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 6CD2227F1DDD5C170058C7CD /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 6C2643E21E11C16A0057CFA4 /* Foundation.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 6CD222891DDD5C180058C7CD /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 6CD2228D1DDD5C180058C7CD /* XcodeProject.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 6C2643DE1E11C0E50057CFA4 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 6C2643E11E11C16A0057CFA4 /* Foundation.framework */, - 6C2643DF1E11C0E50057CFA4 /* GameplayKit.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 6C2643E31E11C80A0057CFA4 /* XcodeProject */ = { - isa = PBXGroup; - children = ( - 6C2644061E11C80A0057CFA4 /* ProjectFile.swift */, - 6C82B6831FFC03180040FD50 /* Workspace.swift */, - 6C2643E41E11C80A0057CFA4 /* Archiving */, - 6C2643EB1E11C80A0057CFA4 /* Objects */, - 6CE346AB1FE9B24000EFF588 /* Objects+Extensions */, - 6C7AFC371FFEF59800AB707B /* Supporting Files */, - ); - name = XcodeProject; - path = Sources/XcodeProject; - sourceTree = ""; - }; - 6C2643E41E11C80A0057CFA4 /* Archiving */ = { - isa = PBXGroup; - children = ( - 6C2643E51E11C80A0057CFA4 /* PBXPListArchiver.swift */, - 6C2643E61E11C80A0057CFA4 /* PBXPListUnarchiver.swift */, - 6C2643E71E11C80A0057CFA4 /* PListArchivable.swift */, - 6C2643E81E11C80A0057CFA4 /* PropertyList.swift */, - ); - path = Archiving; - sourceTree = ""; - }; - 6C2643EB1E11C80A0057CFA4 /* Objects */ = { - isa = PBXGroup; - children = ( - 6CE3A46D21B782E500C4C039 /* PBXGlobalID+Generator.swift */, - 6C2643ED1E11C80A0057CFA4 /* PBXBuildFile.swift */, - 6C2643EF1E11C80A0057CFA4 /* PBXBuildRule.swift */, - 6C2643F01E11C80A0057CFA4 /* PBXContainerItemProxy.swift */, - 6CE346CD1FECAF7C00EFF588 /* PBXFileType.swift */, - 6C2643F81E11C80A0057CFA4 /* PBXObject.swift */, - 6C2643EA1E11C80A0057CFA4 /* PBXGlobalID.swift */, - 6C2643FA1E11C80A0057CFA4 /* PBXProject.swift */, - 6C2644011E11C80A0057CFA4 /* PBXTargetDependency.swift */, - 6C2644031E11C80A0057CFA4 /* XCBuildConfiguration.swift */, - 6C2644041E11C80A0057CFA4 /* XCConfigurationList.swift */, - 6C26442A1E1432670057CFA4 /* Build Phases */, - 6C26442C1E1432A80057CFA4 /* References */, - 6C26442B1E1432780057CFA4 /* Targets */, - ); - path = Objects; - sourceTree = ""; - }; - 6C26442A1E1432670057CFA4 /* Build Phases */ = { - isa = PBXGroup; - children = ( - 6C2643EE1E11C80A0057CFA4 /* PBXBuildPhase.swift */, - 6C2643F11E11C80A0057CFA4 /* PBXCopyFilesBuildPhase.swift */, - 6C2643F31E11C80A0057CFA4 /* PBXFrameworksBuildPhase.swift */, - 6C2643F51E11C80A0057CFA4 /* PBXHeadersBuildPhase.swift */, - 6C2643FD1E11C80A0057CFA4 /* PBXResourcesBuildPhase.swift */, - 6C2643FE1E11C80A0057CFA4 /* PBXShellScriptBuildPhase.swift */, - 6C2643FF1E11C80A0057CFA4 /* PBXSourcesBuildPhase.swift */, - ); - path = "Build Phases"; - sourceTree = ""; - }; - 6C26442B1E1432780057CFA4 /* Targets */ = { - isa = PBXGroup; - children = ( - 6C2643EC1E11C80A0057CFA4 /* PBXAggregateTarget.swift */, - 6C2643F61E11C80A0057CFA4 /* PBXLegacyTarget.swift */, - 6C2643F71E11C80A0057CFA4 /* PBXNativeTarget.swift */, - 6C2644001E11C80A0057CFA4 /* PBXTarget.swift */, - ); - path = Targets; - sourceTree = ""; - }; - 6C26442C1E1432A80057CFA4 /* References */ = { - isa = PBXGroup; - children = ( - 6C2643F21E11C80A0057CFA4 /* PBXFileReference.swift */, - 6C2643F41E11C80A0057CFA4 /* PBXGroup.swift */, - 6C2643FB1E11C80A0057CFA4 /* PBXReference.swift */, - 6C2643FC1E11C80A0057CFA4 /* PBXReferenceProxy.swift */, - 6C2644021E11C80A0057CFA4 /* PBXVariantGroup.swift */, - 6C2644051E11C80A0057CFA4 /* XCVersionGroup.swift */, - ); - path = References; - sourceTree = ""; - }; - 6C7AFC371FFEF59800AB707B /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 6C7AFC381FFEF59800AB707B /* Info.plist */, - ); - path = "Supporting Files"; - sourceTree = ""; - }; - 6CD222791DDD5C170058C7CD = { - isa = PBXGroup; - children = ( - 6C2643E31E11C80A0057CFA4 /* XcodeProject */, - 6CD222901DDD5C180058C7CD /* XcodeProjectTests */, - 6CD222841DDD5C180058C7CD /* Products */, - 6C2643DE1E11C0E50057CFA4 /* Frameworks */, - ); - sourceTree = ""; - usesTabs = 1; - }; - 6CD222841DDD5C180058C7CD /* Products */ = { - isa = PBXGroup; - children = ( - 6CD222831DDD5C180058C7CD /* XcodeProject.framework */, - 6CD2228C1DDD5C180058C7CD /* XcodeProjectTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 6CD222901DDD5C180058C7CD /* XcodeProjectTests */ = { - isa = PBXGroup; - children = ( - 6CE0F7891E0C69FC001DF692 /* PBXGlobalIDTests.swift */, - 6CD222911DDD5C180058C7CD /* XcodeProjectTests.swift */, - ); - name = XcodeProjectTests; - path = Tests/XcodeProjectTests; - sourceTree = ""; - }; - 6CE346AB1FE9B24000EFF588 /* Objects+Extensions */ = { - isa = PBXGroup; - children = ( - 6CE346AE1FE9B45E00EFF588 /* PBXGroup+FolderSync.swift */, - 6CE346AC1FE9B2E400EFF588 /* PBXGroup+Sorting.swift */, - 6C2643F91E11C80A0057CFA4 /* PBXProject+Helpers.swift */, - 6CE346B01FE9B4F600EFF588 /* PBXReference+Extensions.swift */, - 6CE346CB1FECA29100EFF588 /* PBXTarget+Extensions.swift */, - ); - path = "Objects+Extensions"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 6CD222801DDD5C170058C7CD /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 6CD222821DDD5C170058C7CD /* XcodeProject */ = { - isa = PBXNativeTarget; - buildConfigurationList = 6CD222971DDD5C180058C7CD /* Build configuration list for PBXNativeTarget "XcodeProject" */; - buildPhases = ( - 6CD2227E1DDD5C170058C7CD /* Sources */, - 6CD2227F1DDD5C170058C7CD /* Frameworks */, - 6CD222801DDD5C170058C7CD /* Headers */, - 6CD222811DDD5C170058C7CD /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = XcodeProject; - productName = XcodeProject; - productReference = 6CD222831DDD5C180058C7CD /* XcodeProject.framework */; - productType = "com.apple.product-type.framework"; - }; - 6CD2228B1DDD5C180058C7CD /* XcodeProjectTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 6CD2229A1DDD5C180058C7CD /* Build configuration list for PBXNativeTarget "XcodeProjectTests" */; - buildPhases = ( - 6CD222881DDD5C180058C7CD /* Sources */, - 6CD222891DDD5C180058C7CD /* Frameworks */, - 6CD2228A1DDD5C180058C7CD /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 6CD2228F1DDD5C180058C7CD /* PBXTargetDependency */, - ); - name = XcodeProjectTests; - productName = XcodeProjectTests; - productReference = 6CD2228C1DDD5C180058C7CD /* XcodeProjectTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 6CD2227A1DDD5C170058C7CD /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0810; - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "Geoffrey Foster"; - TargetAttributes = { - 6CD222821DDD5C170058C7CD = { - CreatedOnToolsVersion = 8.1; - LastSwiftMigration = 1010; - ProvisioningStyle = Automatic; - }; - 6CD2228B1DDD5C180058C7CD = { - CreatedOnToolsVersion = 8.1; - LastSwiftMigration = 1010; - ProvisioningStyle = Automatic; - }; - }; - }; - buildConfigurationList = 6CD2227D1DDD5C170058C7CD /* Build configuration list for PBXProject "XcodeProject" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 6CD222791DDD5C170058C7CD; - productRefGroup = 6CD222841DDD5C180058C7CD /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 6CD222821DDD5C170058C7CD /* XcodeProject */, - 6CD2228B1DDD5C180058C7CD /* XcodeProjectTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 6CD222811DDD5C170058C7CD /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 6CD2228A1DDD5C180058C7CD /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 6CD2227E1DDD5C170058C7CD /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 6C2644211E11C80A0057CFA4 /* PBXSourcesBuildPhase.swift in Sources */, - 6C2644231E11C80A0057CFA4 /* PBXTargetDependency.swift in Sources */, - 6C2644111E11C80A0057CFA4 /* PBXBuildRule.swift in Sources */, - 6C2644281E11C80A0057CFA4 /* ProjectFile.swift in Sources */, - 6C26440B1E11C80A0057CFA4 /* PListArchivable.swift in Sources */, - 6C2644141E11C80A0057CFA4 /* PBXFileReference.swift in Sources */, - 6C2644261E11C80A0057CFA4 /* XCConfigurationList.swift in Sources */, - 6C2644101E11C80A0057CFA4 /* PBXBuildPhase.swift in Sources */, - 6C2644191E11C80A0057CFA4 /* PBXNativeTarget.swift in Sources */, - 6C82B6841FFC03180040FD50 /* Workspace.swift in Sources */, - 6CE346CC1FECA29100EFF588 /* PBXTarget+Extensions.swift in Sources */, - 6C26440A1E11C80A0057CFA4 /* PBXPListUnarchiver.swift in Sources */, - 6C26440D1E11C80A0057CFA4 /* PBXGlobalID.swift in Sources */, - 6CE346AD1FE9B2E400EFF588 /* PBXGroup+Sorting.swift in Sources */, - 6C2644181E11C80A0057CFA4 /* PBXLegacyTarget.swift in Sources */, - 6C2644251E11C80A0057CFA4 /* XCBuildConfiguration.swift in Sources */, - 6C2644171E11C80A0057CFA4 /* PBXHeadersBuildPhase.swift in Sources */, - 6C2644201E11C80A0057CFA4 /* PBXShellScriptBuildPhase.swift in Sources */, - 6C26441A1E11C80A0057CFA4 /* PBXObject.swift in Sources */, - 6C26440E1E11C80A0057CFA4 /* PBXAggregateTarget.swift in Sources */, - 6C26441D1E11C80A0057CFA4 /* PBXReference.swift in Sources */, - 6C26440C1E11C80A0057CFA4 /* PropertyList.swift in Sources */, - 6C26441C1E11C80A0057CFA4 /* PBXProject.swift in Sources */, - 6C26441F1E11C80A0057CFA4 /* PBXResourcesBuildPhase.swift in Sources */, - 6C2644091E11C80A0057CFA4 /* PBXPListArchiver.swift in Sources */, - 6C2644121E11C80A0057CFA4 /* PBXContainerItemProxy.swift in Sources */, - 6C2644221E11C80A0057CFA4 /* PBXTarget.swift in Sources */, - 6C26440F1E11C80A0057CFA4 /* PBXBuildFile.swift in Sources */, - 6C2644131E11C80A0057CFA4 /* PBXCopyFilesBuildPhase.swift in Sources */, - 6C2644271E11C80A0057CFA4 /* XCVersionGroup.swift in Sources */, - 6CE346CE1FECAF7C00EFF588 /* PBXFileType.swift in Sources */, - 6CE3A46E21B782E500C4C039 /* PBXGlobalID+Generator.swift in Sources */, - 6C2644161E11C80A0057CFA4 /* PBXGroup.swift in Sources */, - 6C2644241E11C80A0057CFA4 /* PBXVariantGroup.swift in Sources */, - 6C26441E1E11C80A0057CFA4 /* PBXReferenceProxy.swift in Sources */, - 6C26441B1E11C80A0057CFA4 /* PBXProject+Helpers.swift in Sources */, - 6C2644151E11C80A0057CFA4 /* PBXFrameworksBuildPhase.swift in Sources */, - 6CE346AF1FE9B45E00EFF588 /* PBXGroup+FolderSync.swift in Sources */, - 6CE346B11FE9B4F600EFF588 /* PBXReference+Extensions.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 6CD222881DDD5C180058C7CD /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 6CD222921DDD5C180058C7CD /* XcodeProjectTests.swift in Sources */, - 6CE0F78A1E0C69FC001DF692 /* PBXGlobalIDTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 6CD2228F1DDD5C180058C7CD /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 6CD222821DDD5C170058C7CD /* XcodeProject */; - targetProxy = 6CD2228E1DDD5C180058C7CD /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 6CD222951DDD5C180058C7CD /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.12; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 6CD222961DDD5C180058C7CD /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.12; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 6CD222981DDD5C180058C7CD /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - COMBINE_HIDPI_IMAGES = YES; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_VERSION = A; - INFOPLIST_FILE = "$(SRCROOT)/Sources/XcodeProject/Supporting Files/Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "net.g-Off.XcodeProject"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 6CD222991DDD5C180058C7CD /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - COMBINE_HIDPI_IMAGES = YES; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_VERSION = A; - INFOPLIST_FILE = "$(SRCROOT)/Sources/XcodeProject/Supporting Files/Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "net.g-Off.XcodeProject"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - }; - name = Release; - }; - 6CD2229B1DDD5C180058C7CD /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - COMBINE_HIDPI_IMAGES = YES; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "net.g-Off.XcodeProjectTests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 6CD2229C1DDD5C180058C7CD /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - COMBINE_HIDPI_IMAGES = YES; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "net.g-Off.XcodeProjectTests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 6CD2227D1DDD5C170058C7CD /* Build configuration list for PBXProject "XcodeProject" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 6CD222951DDD5C180058C7CD /* Debug */, - 6CD222961DDD5C180058C7CD /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 6CD222971DDD5C180058C7CD /* Build configuration list for PBXNativeTarget "XcodeProject" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 6CD222981DDD5C180058C7CD /* Debug */, - 6CD222991DDD5C180058C7CD /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 6CD2229A1DDD5C180058C7CD /* Build configuration list for PBXNativeTarget "XcodeProjectTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 6CD2229B1DDD5C180058C7CD /* Debug */, - 6CD2229C1DDD5C180058C7CD /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 6CD2227A1DDD5C170058C7CD /* Project object */; -} diff --git a/XcodeProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/XcodeProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 7761417..0000000 --- a/XcodeProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/XcodeProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/XcodeProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/XcodeProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/XcodeProject.xcodeproj/project.xcworkspace/xcshareddata/XcodeProject.xcscmblueprint b/XcodeProject.xcodeproj/project.xcworkspace/xcshareddata/XcodeProject.xcscmblueprint deleted file mode 100644 index 660acee..0000000 --- a/XcodeProject.xcodeproj/project.xcworkspace/xcshareddata/XcodeProject.xcscmblueprint +++ /dev/null @@ -1,30 +0,0 @@ -{ - "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "3774C87E4AF785C2D2A372F14EB679E91270AD9A", - "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { - - }, - "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { - "6A1D64846D9388ADB4B33665D09FCB6ACB6B6158" : 9223372036854775807, - "3774C87E4AF785C2D2A372F14EB679E91270AD9A" : 9223372036854775807 - }, - "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "53F96319-EDFD-4DF7-B0AA-873844C4F618", - "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { - "6A1D64846D9388ADB4B33665D09FCB6ACB6B6158" : "", - "3774C87E4AF785C2D2A372F14EB679E91270AD9A" : "XcodeProject\/" - }, - "DVTSourceControlWorkspaceBlueprintNameKey" : "XcodeProject", - "DVTSourceControlWorkspaceBlueprintVersion" : 204, - "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "XcodeProject.xcodeproj", - "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ - { - "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:g-Off\/XcodeProject.git", - "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", - "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "3774C87E4AF785C2D2A372F14EB679E91270AD9A" - }, - { - "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:g-Off\/Xcoder.git", - "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", - "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "6A1D64846D9388ADB4B33665D09FCB6ACB6B6158" - } - ] -} \ No newline at end of file diff --git a/XcodeProject.xcodeproj/xcshareddata/xcschemes/XcodeProject.xcscheme b/XcodeProject.xcodeproj/xcshareddata/xcschemes/XcodeProject.xcscheme deleted file mode 100644 index 5d05462..0000000 --- a/XcodeProject.xcodeproj/xcshareddata/xcschemes/XcodeProject.xcscheme +++ /dev/null @@ -1,107 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/overrides.xcconfig b/overrides.xcconfig deleted file mode 100644 index a94a510..0000000 --- a/overrides.xcconfig +++ /dev/null @@ -1 +0,0 @@ -MACOSX_DEPLOYMENT_TARGET = 10.11