Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ let package = Package(
targets: ["XcodeProject"]),
],
dependencies: [
.package(url: "https://github.com/g-Off/ObjectCoder.git", .exact("0.1.0"))
],
targets: [
.target(
name: "XcodeProject",
dependencies: []),
dependencies: ["ObjectCoder"]),
.testTarget(
name: "XcodeProjectTests",
dependencies: ["XcodeProject"]),
Expand Down
4 changes: 4 additions & 0 deletions Sources/XcodeProject/Archiving/Encoder/AnyCodingKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ struct AnyCodingKey: CodingKey, Equatable, Hashable {
self.intValue = intValue
}

init(index: Int) {
self.init(intValue: index)!
}

init<Key>(_ base: Key) where Key: CodingKey {
if let intValue = base.intValue {
self.init(intValue: intValue)!
Expand Down
28 changes: 25 additions & 3 deletions Sources/XcodeProject/Archiving/Encoder/PBXEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,38 @@
//

import Foundation
import ObjectCoder

class PBXObjectEncoder {
static let objectVersionKey = CodingUserInfoKey(rawValue: "objectVersion")!
var objectVersion: ObjectVersion = .xcode93

private static func quotedKey(_ codingKeys: [CodingKey]) -> CodingKey {
let codingKey = codingKeys.last!
if codingKey.intValue != nil { return codingKey }
return AnyCodingKey(stringValue: codingKey.stringValue.quotedString)!
}

func encode(_ object: PBXObject) throws -> [String: AnyObject] {
let encoder = _PBXObjectEncoder()
encoder.userInfo = [PBXObjectEncoder.objectVersionKey: objectVersion]
let options = ObjectEncoder<NSObject>.Options(
keyEncodingStrategy: .custom(PBXObjectEncoder.quotedKey),
userInfo: [PBXObjectEncoder.objectVersionKey: objectVersion]
)
let boxer = ObjectEncoder<NSObject>.Boxer()
boxer.addWrapper { (object: PBXObject) -> NSObject in
return NSString(string: object.plistID.description)
}
boxer.encodedString = { (value, _) in
return NSString(string: value.quotedString)
}
let encoder = ObjectEncoder(options: options, boxer: boxer)
try object.encode(to: encoder)
return encoder.storage.popContainer() as? [String: AnyObject] ?? [:]
return encoder.encoded as? [String: AnyObject] ?? [:]

// let encoder = _PBXObjectEncoder()
// encoder.userInfo = [PBXObjectEncoder.objectVersionKey: objectVersion]
// try object.encode(to: encoder)
// return encoder.storage.popContainer() as? [String: AnyObject] ?? [:]
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@ extension _PBXObjectEncoder.KeyedContainer: KeyedEncodingContainerProtocol {
}

func encodeNil(forKey key: Key) throws {
container[key.stringValue] = NSNull()
container[key.stringValue.quotedString] = NSNull()
}

func encode(_ value: String, forKey key: Key) throws {
container[key.stringValue] = NSString(string: value.quotedString)
container[key.stringValue.quotedString] = NSString(string: value.quotedString)
}

func encode<T>(_ value: T, forKey key: Key) throws where T: Encodable {
encoder.codingPath.append(key)
defer { encoder.codingPath.removeLast() }
container[key.stringValue] = try encoder.box(value)
container[key.stringValue.quotedString] = try encoder.box(value)
}

func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer<NestedKey> where NestedKey: CodingKey {
Expand Down
5 changes: 5 additions & 0 deletions Sources/XcodeProject/Archiving/PropertyList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ struct PropertyList {
return PropertyList(value)
}

subscript(key: CodingKey) -> PropertyList? {
guard let dictionary = self.dictionary else { return nil }
return PropertyList(dictionary[key.stringValue])
}

private func getTypedObject<T>() -> T? {
return object as? T
}
Expand Down
10 changes: 5 additions & 5 deletions Sources/XcodeProject/Objects/Build Phases/PBXBuildPhase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// Copyright © 2017 Geoffrey Foster. All rights reserved.
//

public class PBXBuildPhase: PBXObject {
public class PBXBuildPhase: PBXProjectItem {
private enum CodingKeys: String, CodingKey {
case name
case files
Expand Down Expand Up @@ -61,18 +61,18 @@ public class PBXBuildPhase: PBXObject {
override func update(with plist: PropertyList, objectCache: ObjectCache) {
super.update(with: plist, objectCache: objectCache)

guard let files = plist["files"]?.array else {
guard let files = plist[CodingKeys.files]?.array else {
fatalError()
}
self._name = plist["name"]?.string
self._name = plist[CodingKeys.name]?.string
self.files = files.compactMap {
let file: PBXBuildFile? = objectCache.object(for: PBXGlobalID(rawValue: $0))
return file
}

self.runOnlyForDeploymentPostprocessing = plist["runOnlyForDeploymentPostprocessing"]?.bool
self.runOnlyForDeploymentPostprocessing = plist[CodingKeys.runOnlyForDeploymentPostprocessing]?.bool

if let v = plist["buildActionMask"]?.string, let buildActionMask = Int32(v) {
if let v = plist[CodingKeys.buildActionMask]?.string, let buildActionMask = Int32(v) {
self.buildActionMask = buildActionMask
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ public final class PBXCopyFilesBuildPhase: PBXBuildPhase {

override func update(with plist: PropertyList, objectCache: ObjectCache) {
super.update(with: plist, objectCache: objectCache)
guard let dstPath = plist["dstPath"]?.string else { fatalError() }
guard let dstPath = plist[CodingKeys.dstPath]?.string else { fatalError() }
self.dstPath = dstPath
guard let dstSubfolderSpec = Destination(string: plist["dstSubfolderSpec"]?.string) else { fatalError() }
guard let dstSubfolderSpec = Destination(string: plist[CodingKeys.dstSubfolderSpec]?.string) else { fatalError() }
self.dstSubfolderSpec = dstSubfolderSpec
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ public final class PBXShellScriptBuildPhase: PBXBuildPhase {

override func update(with plist: PropertyList, objectCache: ObjectCache) {
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
self.inputPaths = plist[CodingKeys.inputPaths]?.array ?? []
self.outputPaths = plist[CodingKeys.outputPaths]?.array ?? []
self.inputFileListPaths = plist[CodingKeys.inputFileListPaths]?.array ?? []
self.outputFileListPaths = plist[CodingKeys.outputFileListPaths]?.array ?? []
self.shellPath = plist[CodingKeys.shellPath]?.string
self.shellScript = plist[CodingKeys.shellScript]?.string
self.showEnvVarsInLog = plist[CodingKeys.showEnvVarsInLog]?.bool
}

public override func encode(to encoder: Encoder) throws {
Expand Down
15 changes: 11 additions & 4 deletions Sources/XcodeProject/Objects/PBXBuildFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
// Copyright © 2017 Geoffrey Foster. All rights reserved.
//

public final class PBXBuildFile: PBXObject {
public final class PBXBuildFile: PBXProjectItem {
private enum CodingKeys: String, CodingKey {
case fileRef
case settings
case productRef
}
public enum Attribute: String, Comparable, Encodable {
public static func < (lhs: PBXBuildFile.Attribute, rhs: PBXBuildFile.Attribute) -> Bool {
Expand All @@ -18,6 +19,7 @@ public final class PBXBuildFile: PBXObject {

case `public` = "Public"
case `private` = "Private"
case required = "Required"
case `weak` = "Weak"
case client = "Client"
case server = "Server"
Expand Down Expand Up @@ -61,6 +63,8 @@ public final class PBXBuildFile: PBXObject {
}
var settings: Settings?

private(set) var productReference: PBXProductDependency?

public convenience init(globalID: PBXGlobalID, fileReference: PBXReference) {
self.init(globalID: globalID)
fileRef = fileReference
Expand All @@ -71,24 +75,27 @@ public final class PBXBuildFile: PBXObject {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(fileRef, forKey: .fileRef)
try container.encodeIfPresent(settings, forKey: .settings)
try container.encodeIfPresent(productReference, forKey: .productRef)
}

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.fileRef = objectCache.object(for: PBXGlobalID(rawValue: plist[CodingKeys.fileRef]?.string))
self.productReference = objectCache.object(for: PBXGlobalID(rawValue: plist[CodingKeys.productRef]?.string))
self.settings = Settings(plist["settings"]?.dictionary)
}

override var archiveComment: String {
guard let fileRef = fileRef, let parent = parent else {
guard let parent = parent, let refComment = fileRef?.archiveComment ?? productReference?.archiveComment else {
return super.archiveComment
}
return "\(fileRef.archiveComment) in \(parent.archiveComment)"
return "\(refComment) in \(parent.archiveComment)"
}

override func visit(_ visitor: ObjectVisitor) {
super.visit(visitor)
visitor.visit(object: fileRef)
visitor.visit(object: productReference)
}

override var archiveInPlistOnSingleLine: Bool {
Expand Down
12 changes: 6 additions & 6 deletions Sources/XcodeProject/Objects/PBXBuildRule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// Copyright © 2017 Geoffrey Foster. All rights reserved.
//

public final class PBXBuildRule: PBXObject {
public final class PBXBuildRule: PBXProjectItem {
private enum CodingKeys: String, CodingKey {
case compilerSpec
case fileType
Expand All @@ -22,11 +22,11 @@ public final class PBXBuildRule: PBXObject {

override func update(with plist: PropertyList, objectCache: ObjectCache) {
super.update(with: plist, objectCache: objectCache)
self.compilerSpec = plist["compilerSpec"]?.string
self.fileType = plist["fileType"]?.string
self.isEditable = plist["isEditable"]?.bool ?? true
self.outputFiles = plist["outputFiles"]?.array ?? []
self.script = plist["script"]?.string
self.compilerSpec = plist[CodingKeys.compilerSpec]?.string
self.fileType = plist[CodingKeys.fileType]?.string
self.isEditable = plist[CodingKeys.isEditable]?.bool ?? true
self.outputFiles = plist[CodingKeys.outputFiles]?.array ?? []
self.script = plist[CodingKeys.script]?.string
}

public override func encode(to encoder: Encoder) throws {
Expand Down
16 changes: 16 additions & 0 deletions Sources/XcodeProject/Objects/PBXContainerItem.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// PBXContainerItem.swift
//
//
// Created by Geoffrey Foster on 2019-07-03.
//

import Foundation

public class PBXContainerItem: PBXObject {

}

public class PBXProjectItem: PBXContainerItem {

}
10 changes: 5 additions & 5 deletions Sources/XcodeProject/Objects/PBXContainerItemProxy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// Copyright © 2017 Geoffrey Foster. All rights reserved.
//

final class PBXContainerItemProxy: PBXObject {
final class PBXContainerItemProxy: PBXContainerItem {
private enum CodingKeys: String, CodingKey {
case containerPortal
case proxyType
Expand All @@ -33,10 +33,10 @@ final class PBXContainerItemProxy: PBXObject {
super.update(with: plist, objectCache: objectCache)

guard
let containerPortal = objectCache.object(for: PBXGlobalID(rawValue: plist["containerPortal"]?.string)),
let proxyType = ProxyType(string: plist["proxyType"]?.string),
let remoteGlobalIDString = plist["remoteGlobalIDString"]?.string,
let remoteInfo = plist["remoteInfo"]?.string
let containerPortal = objectCache.object(for: PBXGlobalID(rawValue: plist[CodingKeys.containerPortal]?.string)),
let proxyType = ProxyType(string: plist[CodingKeys.proxyType]?.string),
let remoteGlobalIDString = plist[CodingKeys.remoteGlobalIDString]?.string,
let remoteInfo = plist[CodingKeys.remoteInfo]?.string
else {
fatalError()
}
Expand Down
7 changes: 7 additions & 0 deletions Sources/XcodeProject/Objects/PBXObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ public class PBXObject: Encodable {
self.globalID = globalID
}

func awake(from decoder: Decoder) throws {

}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(isa, forKey: .isa)
Expand Down Expand Up @@ -129,4 +133,7 @@ let types: [PBXObject.Type] = [
XCBuildConfiguration.self,
XCConfigurationList.self,
XCVersionGroup.self,
XCLocalSwiftPackageReference.self,
XCRemoteSwiftPackageReference.self,
XCSwiftPackageProductDependency.self,
]
12 changes: 12 additions & 0 deletions Sources/XcodeProject/Objects/PBXProductDependency.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// PBXProductDependency.swift
//
//
// Created by Geoffrey Foster on 2019-07-03.
//

import Foundation

public class PBXProductDependency: PBXProjectItem {

}
Loading