15
15
is only enough functionality to allow serialization of Xcode projects.
16
16
*/
17
17
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
+
18
45
extension Xcode . Project : PropertyListSerializable {
19
46
20
47
/// Generates and returns the contents of a `project.pbxproj` plist. Does
@@ -31,9 +58,13 @@ extension Xcode.Project: PropertyListSerializable {
31
58
// the serialized object dictionaries.
32
59
let serializer = PropertyListSerializer ( )
33
60
try serializer. serialize ( object: self )
61
+ var minVersion = MinVersion . xcode8
62
+ if hasBuildableFolders {
63
+ minVersion = . xcode16
64
+ }
34
65
return . dictionary( [
35
66
" archiveVersion " : . string( " 1 " ) ,
36
- " objectVersion " : . string( " 46 " ) , // Xcode 8.0
67
+ " objectVersion " : . string( String ( minVersion . objectVersion ) ) ,
37
68
" rootObject " : . identifier( serializer. id ( of: self ) ) ,
38
69
" objects " : . dictionary( serializer. idsToDicts) ,
39
70
] )
@@ -76,61 +107,38 @@ extension Xcode.Project: PropertyListSerializable {
76
107
}
77
108
}
78
109
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)
129
118
}
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 " )
133
140
}
141
+ dict [ " isa " ] = . string( xcodeClassName)
134
142
return dict
135
143
}
136
144
}
@@ -178,6 +186,11 @@ extension Xcode.Target: PropertyListSerializable {
178
186
// so we need a helper class here.
179
187
try . identifier( serializer. serialize ( object: TargetDependency ( target: dep. target) ) )
180
188
} ) )
189
+ if !buildableFolders. isEmpty {
190
+ dict [ " fileSystemSynchronizedGroups " ] = . array(
191
+ buildableFolders. map { . identifier( serializer. id ( of: $0) ) }
192
+ )
193
+ }
181
194
dict [ " productName " ] = . string( productName)
182
195
if let productType = productType {
183
196
dict [ " productType " ] = . string( productType. rawValue)
0 commit comments