From 4be7b7c313a41d831d64e89ffaa3092068093474 Mon Sep 17 00:00:00 2001 From: Kazuki Chigita Date: Sun, 19 Apr 2026 12:56:05 +0900 Subject: [PATCH 1/4] fix: add missing Equality.generated entry for XCLocalSwiftPackageReference --- .../XcodeProj/Objects/Sourcery/Equality.generated.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Sources/XcodeProj/Objects/Sourcery/Equality.generated.swift b/Sources/XcodeProj/Objects/Sourcery/Equality.generated.swift index 49fe28bb7..2b8794738 100644 --- a/Sources/XcodeProj/Objects/Sourcery/Equality.generated.swift +++ b/Sources/XcodeProj/Objects/Sourcery/Equality.generated.swift @@ -276,6 +276,14 @@ extension XCConfigurationList { } } +extension XCLocalSwiftPackageReference { + /// :nodoc: + func isEqual(to rhs: XCLocalSwiftPackageReference) -> Bool { + if relativePath != rhs.relativePath { return false } + return super.isEqual(to: rhs) + } +} + extension XCRemoteSwiftPackageReference { /// :nodoc: func isEqual(to rhs: XCRemoteSwiftPackageReference) -> Bool { From 62e4acb44f4ebfb25f3f5968f91eb85353689279 Mon Sep 17 00:00:00 2001 From: Kazuki Chigita Date: Sun, 19 Apr 2026 13:06:17 +0900 Subject: [PATCH 2/4] feat: add traits to XCRemoteSwiftPackageReference --- .../Objects/Sourcery/Equality.generated.swift | 1 + .../XCRemoteSwiftPackageReference.swift | 13 +- .../XCRemoteSwiftPackageReferenceTests.swift | 120 ++++++++++++++++++ 3 files changed, 133 insertions(+), 1 deletion(-) diff --git a/Sources/XcodeProj/Objects/Sourcery/Equality.generated.swift b/Sources/XcodeProj/Objects/Sourcery/Equality.generated.swift index 2b8794738..63d9f8d41 100644 --- a/Sources/XcodeProj/Objects/Sourcery/Equality.generated.swift +++ b/Sources/XcodeProj/Objects/Sourcery/Equality.generated.swift @@ -289,6 +289,7 @@ extension XCRemoteSwiftPackageReference { func isEqual(to rhs: XCRemoteSwiftPackageReference) -> Bool { if repositoryURL != rhs.repositoryURL { return false } if versionRequirement != rhs.versionRequirement { return false } + if traits != rhs.traits { return false } return super.isEqual(to: rhs) } } diff --git a/Sources/XcodeProj/Objects/SwiftPackage/XCRemoteSwiftPackageReference.swift b/Sources/XcodeProj/Objects/SwiftPackage/XCRemoteSwiftPackageReference.swift index c28dc39b3..633878003 100644 --- a/Sources/XcodeProj/Objects/SwiftPackage/XCRemoteSwiftPackageReference.swift +++ b/Sources/XcodeProj/Objects/SwiftPackage/XCRemoteSwiftPackageReference.swift @@ -97,21 +97,28 @@ public class XCRemoteSwiftPackageReference: PBXContainerItem, PlistSerializable /// Version rules. public var versionRequirement: VersionRequirement? + /// Enabled package traits. Requires Xcode 26.4+. + public var traits: [String]? + /// Initializes the remote swift package reference with its attributes. /// /// - Parameters: /// - repositoryURL: Package repository url. /// - versionRequirement: Package version rules. + /// - traits: Enabled package traits. public init(repositoryURL: String, - versionRequirement: VersionRequirement? = nil) { + versionRequirement: VersionRequirement? = nil, + traits: [String]? = nil) { self.repositoryURL = repositoryURL self.versionRequirement = versionRequirement + self.traits = traits super.init() } enum CodingKeys: String, CodingKey { case requirement case repositoryURL + case traits } public required init(from decoder: Decoder) throws { @@ -119,6 +126,7 @@ public class XCRemoteSwiftPackageReference: PBXContainerItem, PlistSerializable repositoryURL = try container.decodeIfPresent(String.self, forKey: .repositoryURL) versionRequirement = try container.decodeIfPresent(VersionRequirement.self, forKey: .requirement) + traits = try container.decodeIfPresent([String].self, forKey: .traits) try super.init(from: decoder) } @@ -137,6 +145,9 @@ public class XCRemoteSwiftPackageReference: PBXContainerItem, PlistSerializable if let versionRequirement { dictionary["requirement"] = PlistValue.dictionary(versionRequirement.plistValues()) } + if let traits { + dictionary["traits"] = .array(traits.map { .string(.init($0)) }) + } return (key: CommentedString(reference, comment: "XCRemoteSwiftPackageReference \"\(name ?? "")\""), value: .dictionary(dictionary)) } diff --git a/Tests/XcodeProjTests/Objects/SwiftPackage/XCRemoteSwiftPackageReferenceTests.swift b/Tests/XcodeProjTests/Objects/SwiftPackage/XCRemoteSwiftPackageReferenceTests.swift index a06008726..12b55cba2 100644 --- a/Tests/XcodeProjTests/Objects/SwiftPackage/XCRemoteSwiftPackageReferenceTests.swift +++ b/Tests/XcodeProjTests/Objects/SwiftPackage/XCRemoteSwiftPackageReferenceTests.swift @@ -148,4 +148,124 @@ final class XCRemoteSwiftPackageReferenceTests: XCTestCase { // Then XCTAssertEqual(subject.name, "xcodeproj") } + + func test_init_decodesTraits() throws { + // Given + let decoder = XcodeprojPropertyListDecoder() + let plist: [String: [String: Any]] = ["ref": [ + "repositoryURL": "url", + "requirement": [ + "kind": "exactVersion", + "version": "1.2.3", + ], + "traits": ["Foo", "Bar"], + ]] + let data = try PropertyListSerialization.data(fromPropertyList: plist, format: .xml, options: 0) + + // When + let decoded = try decoder.decode([String: XCRemoteSwiftPackageReference].self, from: data) + let got = try XCTUnwrap(decoded["ref"]) + + // Then + XCTAssertEqual(got.traits, ["Foo", "Bar"]) + } + + func test_init_decodesEmptyTraits() throws { + // Given + let decoder = XcodeprojPropertyListDecoder() + let plist: [String: [String: Any]] = ["ref": [ + "repositoryURL": "url", + "requirement": [ + "kind": "exactVersion", + "version": "1.2.3", + ], + "traits": [String](), + ]] + let data = try PropertyListSerialization.data(fromPropertyList: plist, format: .xml, options: 0) + + // When + let decoded = try decoder.decode([String: XCRemoteSwiftPackageReference].self, from: data) + let got = try XCTUnwrap(decoded["ref"]) + + // Then + XCTAssertEqual(got.traits, []) + } + + func test_plistValues_writesTraits_whenPresent() throws { + // When + let proj = PBXProj() + let subject = XCRemoteSwiftPackageReference(repositoryURL: "repository", + versionRequirement: .exact("1.2.3"), + traits: ["Foo", "Bar"]) + + // Given + let got = try subject.plistKeyAndValue(proj: proj, reference: "ref") + + // Then + XCTAssertEqual(got.value, .dictionary([ + "isa": "XCRemoteSwiftPackageReference", + "repositoryURL": "repository", + "requirement": .dictionary([ + "kind": "exactVersion", + "version": "1.2.3", + ]), + "traits": .array(["Foo", "Bar"]), + ])) + } + + func test_plistValues_writesEmptyArray_whenEmpty() throws { + // When + let proj = PBXProj() + let subject = XCRemoteSwiftPackageReference(repositoryURL: "repository", + versionRequirement: .exact("1.2.3"), + traits: []) + + // Given + let got = try subject.plistKeyAndValue(proj: proj, reference: "ref") + + // Then + XCTAssertEqual(got.value, .dictionary([ + "isa": "XCRemoteSwiftPackageReference", + "repositoryURL": "repository", + "requirement": .dictionary([ + "kind": "exactVersion", + "version": "1.2.3", + ]), + "traits": .array([]), + ])) + } + + func test_plistValues_omitsTraitsKey_whenNil() throws { + // When + let proj = PBXProj() + let subject = XCRemoteSwiftPackageReference(repositoryURL: "repository", + versionRequirement: .exact("1.2.3"), + traits: nil) + + // Given + let got = try subject.plistKeyAndValue(proj: proj, reference: "ref") + + // Then + XCTAssertEqual(got.value, .dictionary([ + "isa": "XCRemoteSwiftPackageReference", + "repositoryURL": "repository", + "requirement": .dictionary([ + "kind": "exactVersion", + "version": "1.2.3", + ]), + ])) + } + + func test_equal_whenTraitsDiffer_returnsFalse() { + // When + let first = XCRemoteSwiftPackageReference(repositoryURL: "repository", + versionRequirement: .exact("1.2.3"), + traits: ["Foo"]) + let second = XCRemoteSwiftPackageReference(repositoryURL: "repository", + versionRequirement: .exact("1.2.3"), + traits: ["Bar"]) + + // Then + XCTAssertNotEqual(first, second) + } } From 6ce46e063941a2a2777ad2ab4d59c39c852a65ec Mon Sep 17 00:00:00 2001 From: Kazuki Chigita Date: Sun, 19 Apr 2026 13:07:30 +0900 Subject: [PATCH 3/4] feat: add traits to XCLocalSwiftPackageReference --- .../Objects/Sourcery/Equality.generated.swift | 1 + .../XCLocalSwiftPackageReference.swift | 15 ++- .../XCLocalSwiftPackageReferenceTests.swift | 92 +++++++++++++++++++ 3 files changed, 106 insertions(+), 2 deletions(-) diff --git a/Sources/XcodeProj/Objects/Sourcery/Equality.generated.swift b/Sources/XcodeProj/Objects/Sourcery/Equality.generated.swift index 63d9f8d41..f2d335f07 100644 --- a/Sources/XcodeProj/Objects/Sourcery/Equality.generated.swift +++ b/Sources/XcodeProj/Objects/Sourcery/Equality.generated.swift @@ -280,6 +280,7 @@ extension XCLocalSwiftPackageReference { /// :nodoc: func isEqual(to rhs: XCLocalSwiftPackageReference) -> Bool { if relativePath != rhs.relativePath { return false } + if traits != rhs.traits { return false } return super.isEqual(to: rhs) } } diff --git a/Sources/XcodeProj/Objects/SwiftPackage/XCLocalSwiftPackageReference.swift b/Sources/XcodeProj/Objects/SwiftPackage/XCLocalSwiftPackageReference.swift index 71566b5bc..8d92615f0 100644 --- a/Sources/XcodeProj/Objects/SwiftPackage/XCLocalSwiftPackageReference.swift +++ b/Sources/XcodeProj/Objects/SwiftPackage/XCLocalSwiftPackageReference.swift @@ -5,23 +5,31 @@ public class XCLocalSwiftPackageReference: PBXContainerItem, PlistSerializable { /// Repository url. public var relativePath: String + /// Enabled package traits. Requires Xcode 26.4+. + public var traits: [String]? + /// Initializes the local swift package reference with its attributes. /// /// - Parameters: - /// - repositoryPath: Package repository path. - public init(relativePath: String) { + /// - relativePath: Package relative path. + /// - traits: Enabled package traits. + public init(relativePath: String, + traits: [String]? = nil) { self.relativePath = relativePath + self.traits = traits super.init() } enum CodingKeys: String, CodingKey { case relativePath + case traits } public required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) relativePath = try container.decode(String.self, forKey: .relativePath) + traits = try container.decodeIfPresent([String].self, forKey: .traits) try super.init(from: decoder) } @@ -35,6 +43,9 @@ public class XCLocalSwiftPackageReference: PBXContainerItem, PlistSerializable { var dictionary = try super.plistValues(proj: proj, reference: reference) dictionary["isa"] = .string(CommentedString(XCLocalSwiftPackageReference.isa)) dictionary["relativePath"] = .string(.init(relativePath)) + if let traits { + dictionary["traits"] = .array(traits.map { .string(.init($0)) }) + } return (key: CommentedString(reference, comment: "XCLocalSwiftPackageReference \"\(name ?? "")\""), value: .dictionary(dictionary)) } diff --git a/Tests/XcodeProjTests/Objects/SwiftPackage/XCLocalSwiftPackageReferenceTests.swift b/Tests/XcodeProjTests/Objects/SwiftPackage/XCLocalSwiftPackageReferenceTests.swift index 1ad9d94f4..95fa86287 100644 --- a/Tests/XcodeProjTests/Objects/SwiftPackage/XCLocalSwiftPackageReferenceTests.swift +++ b/Tests/XcodeProjTests/Objects/SwiftPackage/XCLocalSwiftPackageReferenceTests.swift @@ -52,6 +52,98 @@ final class XCLocalSwiftPackageReferenceTests: XCTestCase { XCTAssertEqual(subject.name, "tuist/xcodeproj") } + // MARK: - Traits + + func test_init_decodesTraits() throws { + // Given + let decoder = XcodeprojPropertyListDecoder() + let plist: [String: [String: Any]] = ["ref": [ + "relativePath": "path", + "traits": ["Foo", "Bar"], + ]] + let data = try PropertyListSerialization.data(fromPropertyList: plist, format: .xml, options: 0) + + // When + let decoded = try decoder.decode([String: XCLocalSwiftPackageReference].self, from: data) + let got = try XCTUnwrap(decoded["ref"]) + + // Then + XCTAssertEqual(got.traits, ["Foo", "Bar"]) + } + + func test_init_decodesEmptyTraits() throws { + // Given + let decoder = XcodeprojPropertyListDecoder() + let plist: [String: [String: Any]] = ["ref": [ + "relativePath": "path", + "traits": [String](), + ]] + let data = try PropertyListSerialization.data(fromPropertyList: plist, format: .xml, options: 0) + + // When + let decoded = try decoder.decode([String: XCLocalSwiftPackageReference].self, from: data) + let got = try XCTUnwrap(decoded["ref"]) + + // Then + XCTAssertEqual(got.traits, []) + } + + func test_plistValues_writesTraits_whenPresent() throws { + // When + let proj = PBXProj() + let subject = XCLocalSwiftPackageReference(relativePath: "repository", traits: ["Foo", "Bar"]) + + // Given + let got = try subject.plistKeyAndValue(proj: proj, reference: "ref") + + // Then + XCTAssertEqual(got.value, .dictionary([ + "isa": "XCLocalSwiftPackageReference", + "relativePath": "repository", + "traits": .array(["Foo", "Bar"]), + ])) + } + + func test_plistValues_writesEmptyArray_whenEmpty() throws { + // When + let proj = PBXProj() + let subject = XCLocalSwiftPackageReference(relativePath: "repository", traits: []) + + // Given + let got = try subject.plistKeyAndValue(proj: proj, reference: "ref") + + // Then + XCTAssertEqual(got.value, .dictionary([ + "isa": "XCLocalSwiftPackageReference", + "relativePath": "repository", + "traits": .array([]), + ])) + } + + func test_plistValues_omitsTraitsKey_whenNil() throws { + // When + let proj = PBXProj() + let subject = XCLocalSwiftPackageReference(relativePath: "repository", traits: nil) + + // Given + let got = try subject.plistKeyAndValue(proj: proj, reference: "ref") + + // Then + XCTAssertEqual(got.value, .dictionary([ + "isa": "XCLocalSwiftPackageReference", + "relativePath": "repository", + ])) + } + + func test_equal_whenTraitsDiffer_returnsFalse() { + // When + let first = XCLocalSwiftPackageReference(relativePath: "repository", traits: ["Foo"]) + let second = XCLocalSwiftPackageReference(relativePath: "repository", traits: ["Bar"]) + + // Then + XCTAssertNotEqual(first, second) + } + // MARK: - Add/Delete Tests func test_add_addsObjectToPBXProj() { From 73e583b5523d1c6d23ad302dfa6c3fa43ddb350b Mon Sep 17 00:00:00 2001 From: Kazuki Chigita Date: Sun, 19 Apr 2026 13:08:45 +0900 Subject: [PATCH 4/4] feat: add fixture and round-trip test for SwiftPackage traits --- .../project.pbxproj | 601 ++++++++++++++++++ .../Project/XcodeProjIntegrationTests.swift | 9 + 2 files changed, 610 insertions(+) create mode 100644 Fixtures/iOS/ProjectWithSwiftPackageTraits.xcodeproj/project.pbxproj diff --git a/Fixtures/iOS/ProjectWithSwiftPackageTraits.xcodeproj/project.pbxproj b/Fixtures/iOS/ProjectWithSwiftPackageTraits.xcodeproj/project.pbxproj new file mode 100644 index 000000000..a33af6b13 --- /dev/null +++ b/Fixtures/iOS/ProjectWithSwiftPackageTraits.xcodeproj/project.pbxproj @@ -0,0 +1,601 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 60; + objects = { + +/* Begin PBXBuildFile section */ + 04D5C09F1F153824008A2F98 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04D5C09E1F153824008A2F98 /* CoreData.framework */; }; + 04D5C0A31F153924008A2F98 /* Public.h in Headers */ = {isa = PBXBuildFile; fileRef = 04D5C0A01F153915008A2F98 /* Public.h */; }; + 04D5C0A41F153924008A2F98 /* Protected.h in Headers */ = {isa = PBXBuildFile; fileRef = 04D5C0A11F15391B008A2F98 /* Protected.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 04D5C0A51F153924008A2F98 /* Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 04D5C0A21F153921008A2F98 /* Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 23766C161EAA3484007A9026 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23766C151EAA3484007A9026 /* AppDelegate.swift */; }; + 23766C181EAA3484007A9026 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23766C171EAA3484007A9026 /* ViewController.swift */; }; + 23766C1B1EAA3484007A9026 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 23766C191EAA3484007A9026 /* Main.storyboard */; }; + 23766C1D1EAA3484007A9026 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 23766C1C1EAA3484007A9026 /* Assets.xcassets */; }; + 23766C201EAA3484007A9026 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 23766C1E1EAA3484007A9026 /* LaunchScreen.storyboard */; }; + 23766C2B1EAA3484007A9026 /* iOSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23766C2A1EAA3484007A9026 /* iOSTests.swift */; }; + 3CD1EADD205763E400DAEECB /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 3CD1EADB205763E400DAEECB /* Model.xcdatamodeld */; }; + 42AA1A1C22AAF48100428760 /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 42AA1A1B22AAF48100428760 /* RxSwift */; }; + C9FDF5C42AD603E50096A37A /* MyLocalPackage in Frameworks */ = {isa = PBXBuildFile; productRef = C9FDF5C32AD603E50096A37A /* MyLocalPackage */; }; + C9FDF5C72AD604310096A37A /* MyLocalPackage in Frameworks */ = {isa = PBXBuildFile; productRef = C9FDF5C62AD604310096A37A /* MyLocalPackage */; }; +/* End PBXBuildFile section */ + +/* Begin PBXBuildRule section */ + 6B7542351FE9CEDE003DFC29 /* PBXBuildRule */ = { + isa = PBXBuildRule; + compilerSpec = com.apple.compilers.proxy.script; + filePatterns = "*.myrule"; + fileType = pattern.proxy; + inputFiles = ( + ); + isEditable = 1; + outputFiles = ( + "$(DERIVED_FILE_DIR)/CompiledRule", + ); + script = $TOOL_PATH/transform; + }; +/* End PBXBuildRule section */ + +/* Begin PBXContainerItemProxy section */ + 23766C271EAA3484007A9026 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 23766C0A1EAA3484007A9026 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 23766C111EAA3484007A9026; + remoteInfo = iOS; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 239688B71EBCD3B10014B321 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 0; + dstSubfolderSpec = 0; + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 04D5C09E1F153824008A2F98 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; + 04D5C0A01F153915008A2F98 /* Public.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Public.h; sourceTree = ""; }; + 04D5C0A11F15391B008A2F98 /* Protected.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Protected.h; sourceTree = ""; }; + 04D5C0A21F153921008A2F98 /* Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Private.h; sourceTree = ""; }; + 23766C121EAA3484007A9026 /* iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 23766C151EAA3484007A9026 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 23766C171EAA3484007A9026 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 23766C1A1EAA3484007A9026 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 23766C1C1EAA3484007A9026 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 23766C1F1EAA3484007A9026 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 23766C211EAA3484007A9026 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 23766C261EAA3484007A9026 /* iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = iOSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 23766C2A1EAA3484007A9026 /* iOSTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSTests.swift; sourceTree = ""; }; + 23766C2C1EAA3484007A9026 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 23C1E0AF23657FB500B8D1EF /* iOS.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = iOS.xctestplan; sourceTree = ""; }; + 3CD1EADC205763E400DAEECB /* Model.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model.xcdatamodel; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 23766C0F1EAA3484007A9026 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 42AA1A1C22AAF48100428760 /* RxSwift in Frameworks */, + C9FDF5C42AD603E50096A37A /* MyLocalPackage in Frameworks */, + 04D5C09F1F153824008A2F98 /* CoreData.framework in Frameworks */, + C9FDF5C72AD604310096A37A /* MyLocalPackage in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 23766C231EAA3484007A9026 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 04D5C09D1F153824008A2F98 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 04D5C09E1F153824008A2F98 /* CoreData.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 23766C091EAA3484007A9026 = { + isa = PBXGroup; + children = ( + 23C1E0AF23657FB500B8D1EF /* iOS.xctestplan */, + 23766C141EAA3484007A9026 /* iOS */, + 23766C291EAA3484007A9026 /* iOSTests */, + 23766C131EAA3484007A9026 /* Products */, + 04D5C09D1F153824008A2F98 /* Frameworks */, + ); + sourceTree = ""; + }; + 23766C131EAA3484007A9026 /* Products */ = { + isa = PBXGroup; + children = ( + 23766C121EAA3484007A9026 /* iOS.app */, + 23766C261EAA3484007A9026 /* iOSTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 23766C141EAA3484007A9026 /* iOS */ = { + isa = PBXGroup; + children = ( + 3CD1EADB205763E400DAEECB /* Model.xcdatamodeld */, + 3CD1EAD92057638200DAEECB /* GroupWithoutFolder */, + 23766C151EAA3484007A9026 /* AppDelegate.swift */, + 23766C171EAA3484007A9026 /* ViewController.swift */, + 23766C191EAA3484007A9026 /* Main.storyboard */, + 23766C1C1EAA3484007A9026 /* Assets.xcassets */, + 23766C1E1EAA3484007A9026 /* LaunchScreen.storyboard */, + 23766C211EAA3484007A9026 /* Info.plist */, + 04D5C0A01F153915008A2F98 /* Public.h */, + 04D5C0A11F15391B008A2F98 /* Protected.h */, + 04D5C0A21F153921008A2F98 /* Private.h */, + ); + path = iOS; + sourceTree = ""; + }; + 23766C291EAA3484007A9026 /* iOSTests */ = { + isa = PBXGroup; + children = ( + 23766C2A1EAA3484007A9026 /* iOSTests.swift */, + 23766C2C1EAA3484007A9026 /* Info.plist */, + ); + path = iOSTests; + sourceTree = ""; + }; + 3CD1EAD92057638200DAEECB /* GroupWithoutFolder */ = { + isa = PBXGroup; + children = ( + ); + name = GroupWithoutFolder; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 23BB67531EE326A800BE9E79 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 04D5C0A41F153924008A2F98 /* Protected.h in Headers */, + 04D5C0A51F153924008A2F98 /* Private.h in Headers */, + 04D5C0A31F153924008A2F98 /* Public.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 23766C111EAA3484007A9026 /* iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 23766C2F1EAA3484007A9026 /* Build configuration list for PBXNativeTarget "iOS" */; + buildPhases = ( + 23766C0E1EAA3484007A9026 /* Sources */, + 23766C0F1EAA3484007A9026 /* Frameworks */, + 23766C101EAA3484007A9026 /* Resources */, + 239688B71EBCD3B10014B321 /* CopyFiles */, + 23BB67521EE325E600BE9E79 /* Run Script */, + 23BB67531EE326A800BE9E79 /* Headers */, + ); + buildRules = ( + 6B7542351FE9CEDE003DFC29 /* PBXBuildRule */, + ); + dependencies = ( + ); + name = iOS; + packageProductDependencies = ( + 42AA1A1B22AAF48100428760 /* RxSwift */, + C9FDF5C32AD603E50096A37A /* MyLocalPackage */, + C9FDF5C62AD604310096A37A /* MyLocalPackage */, + ); + productName = iOS; + productReference = 23766C121EAA3484007A9026 /* iOS.app */; + productType = "com.apple.product-type.application"; + }; + 23766C251EAA3484007A9026 /* iOSTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 23766C321EAA3484007A9026 /* Build configuration list for PBXNativeTarget "iOSTests" */; + buildPhases = ( + 23766C221EAA3484007A9026 /* Sources */, + 23766C231EAA3484007A9026 /* Frameworks */, + 23766C241EAA3484007A9026 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 23766C281EAA3484007A9026 /* PBXTargetDependency */, + ); + name = iOSTests; + productName = iOSTests; + productReference = 23766C261EAA3484007A9026 /* iOSTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 23766C0A1EAA3484007A9026 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0830; + LastUpgradeCheck = 0830; + ORGANIZATIONNAME = es.ppinera; + TargetAttributes = { + 23766C111EAA3484007A9026 = { + CreatedOnToolsVersion = 8.3.1; + ProvisioningStyle = Automatic; + }; + 23766C251EAA3484007A9026 = { + CreatedOnToolsVersion = 8.3.1; + ProvisioningStyle = Automatic; + TestTargetID = 23766C111EAA3484007A9026; + }; + }; + }; + buildConfigurationList = 23766C0D1EAA3484007A9026 /* Build configuration list for PBXProject "ProjectWithSwiftPackageTraits" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + English, + en, + Base, + ); + mainGroup = 23766C091EAA3484007A9026; + packageReferences = ( + 42AA19FF22AAF0D600428760 /* XCRemoteSwiftPackageReference "RxSwift" */, + C9FDF5C52AD604310096A37A /* XCLocalSwiftPackageReference "MyLocalPackage" */, + ); + productRefGroup = 23766C131EAA3484007A9026 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 23766C111EAA3484007A9026 /* iOS */, + 23766C251EAA3484007A9026 /* iOSTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 23766C101EAA3484007A9026 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 23766C201EAA3484007A9026 /* LaunchScreen.storyboard in Resources */, + 23766C1D1EAA3484007A9026 /* Assets.xcassets in Resources */, + 23766C1B1EAA3484007A9026 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 23766C241EAA3484007A9026 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 23BB67521EE325E600BE9E79 /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/myfile", + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"/test\"\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 23766C0E1EAA3484007A9026 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 23766C181EAA3484007A9026 /* ViewController.swift in Sources */, + 23766C181EAA3484007A9026 /* ViewController.swift in Sources */, + 23766C161EAA3484007A9026 /* AppDelegate.swift in Sources */, + 3CD1EADD205763E400DAEECB /* Model.xcdatamodeld in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 23766C221EAA3484007A9026 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 23766C2B1EAA3484007A9026 /* iOSTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 23766C281EAA3484007A9026 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 23766C111EAA3484007A9026 /* iOS */; + targetProxy = 23766C271EAA3484007A9026 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 23766C191EAA3484007A9026 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 23766C1A1EAA3484007A9026 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 23766C1E1EAA3484007A9026 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 23766C1F1EAA3484007A9026 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 23766C2D1EAA3484007A9026 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + 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; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 23766C2E1EAA3484007A9026 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + 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; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 23766C301EAA3484007A9026 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = iOS/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = es.ppinera.iOS; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 23766C311EAA3484007A9026 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = iOS/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = es.ppinera.iOS; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 23766C331EAA3484007A9026 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = iOSTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = es.ppinera.iOSTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOS.app/iOS"; + }; + name = Debug; + }; + 23766C341EAA3484007A9026 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = iOSTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = es.ppinera.iOSTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOS.app/iOS"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 23766C0D1EAA3484007A9026 /* Build configuration list for PBXProject "ProjectWithSwiftPackageTraits" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 23766C2D1EAA3484007A9026 /* Debug */, + 23766C2E1EAA3484007A9026 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 23766C2F1EAA3484007A9026 /* Build configuration list for PBXNativeTarget "iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 23766C301EAA3484007A9026 /* Debug */, + 23766C311EAA3484007A9026 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 23766C321EAA3484007A9026 /* Build configuration list for PBXNativeTarget "iOSTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 23766C331EAA3484007A9026 /* Debug */, + 23766C341EAA3484007A9026 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + C9FDF5C52AD604310096A37A /* XCLocalSwiftPackageReference "MyLocalPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = MyLocalPackage; + traits = ( + NoUIFramework, + ); + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 42AA19FF22AAF0D600428760 /* XCRemoteSwiftPackageReference "RxSwift" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/ReactiveX/RxSwift"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 5.0.1; + }; + traits = ( + ); + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 42AA1A1B22AAF48100428760 /* RxSwift */ = { + isa = XCSwiftPackageProductDependency; + package = 42AA19FF22AAF0D600428760 /* XCRemoteSwiftPackageReference "RxSwift" */; + productName = RxSwift; + }; + C9FDF5C32AD603E50096A37A /* MyLocalPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = MyLocalPackage; + }; + C9FDF5C62AD604310096A37A /* MyLocalPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = MyLocalPackage; + }; +/* End XCSwiftPackageProductDependency section */ + +/* Begin XCVersionGroup section */ + 3CD1EADB205763E400DAEECB /* Model.xcdatamodeld */ = { + isa = XCVersionGroup; + children = ( + 3CD1EADC205763E400DAEECB /* Model.xcdatamodel */, + ); + currentVersion = 3CD1EADC205763E400DAEECB /* Model.xcdatamodel */; + path = Model.xcdatamodeld; + sourceTree = ""; + versionGroupType = wrapper.xcdatamodel; + }; +/* End XCVersionGroup section */ + }; + rootObject = 23766C0A1EAA3484007A9026 /* Project object */; +} diff --git a/Tests/XcodeProjTests/Project/XcodeProjIntegrationTests.swift b/Tests/XcodeProjTests/Project/XcodeProjIntegrationTests.swift index f3bd72571..ea685fe43 100644 --- a/Tests/XcodeProjTests/Project/XcodeProjIntegrationTests.swift +++ b/Tests/XcodeProjTests/Project/XcodeProjIntegrationTests.swift @@ -36,6 +36,11 @@ initModel: XcodeProj.init(path:)) } + func test_read_write_produces_no_diff_when_swiftPackageTraits() throws { + try testReadWriteProducesNoDiff(from: swiftPackageTraitsFixturePath, + initModel: XcodeProj.init(path:)) + } + func test_initialize_PBXProj_with_data() throws { // Given let pbxprojPath = iosProjectPath + "project.pbxproj" @@ -109,6 +114,10 @@ private var synchronizedRootGroupsFixturePath: Path { fixturesPath() + "SynchronizedRootGroups/SynchronizedRootGroups.xcodeproj" } + + private var swiftPackageTraitsFixturePath: Path { + fixturesPath() + "iOS/ProjectWithSwiftPackageTraits.xcodeproj" + } } #endif