1515 is only enough functionality to allow serialization of Xcode projects.
1616 */
1717
18+ extension Xcode . Project {
19+ fileprivate enum MinVersion {
20+ case xcode8, xcode16
21+
22+ var objectVersion : Int {
23+ switch self {
24+ case . xcode8: 46
25+ case . xcode16: 77
26+ }
27+ }
28+ }
29+
30+ fileprivate var hasBuildableFolders : Bool {
31+ var worklist : [ Xcode . Reference ] = [ ]
32+ worklist. append ( mainGroup)
33+ while let ref = worklist. popLast ( ) {
34+ if let fileRef = ref as? Xcode . FileReference , fileRef. isBuildableFolder {
35+ return true
36+ }
37+ if let group = ref as? Xcode . Group {
38+ worklist += group. subitems
39+ }
40+ }
41+ return false
42+ }
43+ }
44+
1845extension Xcode . Project : PropertyListSerializable {
1946
2047 /// Generates and returns the contents of a `project.pbxproj` plist. Does
@@ -31,9 +58,13 @@ extension Xcode.Project: PropertyListSerializable {
3158 // the serialized object dictionaries.
3259 let serializer = PropertyListSerializer ( )
3360 try serializer. serialize ( object: self )
61+ var minVersion = MinVersion . xcode8
62+ if hasBuildableFolders {
63+ minVersion = . xcode16
64+ }
3465 return . dictionary( [
3566 " archiveVersion " : . string( " 1 " ) ,
36- " objectVersion " : . string( " 46 " ) , // Xcode 8.0
67+ " objectVersion " : . string( String ( minVersion . objectVersion ) ) ,
3768 " rootObject " : . identifier( serializer. id ( of: self ) ) ,
3869 " objects " : . dictionary( serializer. idsToDicts) ,
3970 ] )
@@ -76,61 +107,38 @@ extension Xcode.Project: PropertyListSerializable {
76107 }
77108}
78109
79- /// Private helper function that constructs and returns a partial property list
80- /// dictionary for references. The caller can add to the returned dictionary.
81- /// FIXME: It would be nicer to be able to use inheritance to serialize the
82- /// attributes inherited from Reference, but but in Swift 3.0 we get an error
83- /// that "declarations in extensions cannot override yet".
84- fileprivate func makeReferenceDict(
85- reference: Xcode . Reference ,
86- serializer: PropertyListSerializer ,
87- xcodeClassName: String
88- ) -> [ String : PropertyList ] {
89- var dict = [ String: PropertyList] ( )
90- dict [ " isa " ] = . string( xcodeClassName)
91- dict [ " path " ] = . string( reference. path)
92- if let name = reference. name {
93- dict [ " name " ] = . string( name)
94- }
95- dict [ " sourceTree " ] = . string( reference. pathBase. rawValue)
96- return dict
97- }
98-
99- extension Xcode . Group : PropertyListSerializable {
100-
101- /// Called by the Serializer to serialize the Group.
102- fileprivate func serialize( to serializer: PropertyListSerializer ) throws -> [ String : PropertyList ] {
103- // Create a `PBXGroup` plist dictionary.
104- // FIXME: It would be nicer to be able to use inheritance for the code
105- // inherited from Reference, but but in Swift 3.0 we get an error that
106- // "declarations in extensions cannot override yet".
107- var dict = makeReferenceDict ( reference: self , serializer: serializer, xcodeClassName: " PBXGroup " )
108- dict [ " children " ] = try . array( subitems. map ( { reference in
109- // For the same reason, we have to cast as `PropertyListSerializable`
110- // here; as soon as we try to make Reference conform to the protocol,
111- // we get the problem of not being able to override `serialize(to:)`.
112- try . identifier( serializer. serialize ( object: reference as! PropertyListSerializable ) )
113- } ) )
114- return dict
115- }
116- }
117-
118- extension Xcode . FileReference : PropertyListSerializable {
119-
120- /// Called by the Serializer to serialize the FileReference.
121- fileprivate func serialize( to serializer: PropertyListSerializer ) -> [ String : PropertyList ] {
122- // Create a `PBXFileReference` plist dictionary.
123- // FIXME: It would be nicer to be able to use inheritance for the code
124- // inherited from Reference, but but in Swift 3.0 we get an error that
125- // "declarations in extensions cannot override yet".
126- var dict = makeReferenceDict ( reference: self , serializer: serializer, xcodeClassName: " PBXFileReference " )
127- if let fileType = fileType {
128- dict [ " explicitFileType " ] = . string( fileType)
110+ extension Xcode . Reference : PropertyListSerializable {
111+ fileprivate dynamic func serialize(
112+ to serializer: PropertyListSerializer
113+ ) throws -> [ String : PropertyList ] {
114+ var dict = [ String: PropertyList] ( )
115+ dict [ " path " ] = . string( path)
116+ if let name = name {
117+ dict [ " name " ] = . string( name)
129118 }
130- // FileReferences don't need to store a name if it's the same as the path.
131- if name == path {
132- dict [ " name " ] = nil
119+ dict [ " sourceTree " ] = . string( pathBase. rawValue)
120+
121+ let xcodeClassName : String
122+ switch self {
123+ case let group as Xcode . Group :
124+ xcodeClassName = " PBXGroup "
125+ dict [ " children " ] = try . array( group. subitems. map ( { reference in
126+ try . identifier( serializer. serialize ( object: reference) )
127+ } ) )
128+ case let fileRef as Xcode . FileReference :
129+ xcodeClassName = fileRef. isBuildableFolder
130+ ? " PBXFileSystemSynchronizedRootGroup " : " PBXFileReference "
131+ if let fileType = fileRef. fileType {
132+ dict [ " explicitFileType " ] = . string( fileType)
133+ }
134+ // FileReferences don't need to store a name if it's the same as the path.
135+ if name == path {
136+ dict [ " name " ] = nil
137+ }
138+ default :
139+ fatalError ( " Unhandled subclass " )
133140 }
141+ dict [ " isa " ] = . string( xcodeClassName)
134142 return dict
135143 }
136144}
@@ -178,6 +186,11 @@ extension Xcode.Target: PropertyListSerializable {
178186 // so we need a helper class here.
179187 try . identifier( serializer. serialize ( object: TargetDependency ( target: dep. target) ) )
180188 } ) )
189+ if !buildableFolders. isEmpty {
190+ dict [ " fileSystemSynchronizedGroups " ] = . array(
191+ buildableFolders. map { . identifier( serializer. id ( of: $0) ) }
192+ )
193+ }
181194 dict [ " productName " ] = . string( productName)
182195 if let productType = productType {
183196 dict [ " productType " ] = . string( productType. rawValue)
0 commit comments