@@ -156,18 +156,18 @@ public struct TargetSourcesBuilder {
156
156
/// Run the builder to produce the sources of the target.
157
157
public func run( ) throws -> ( sources: Sources , resources: [ Resource ] , headers: [ AbsolutePath ] , ignored: [ AbsolutePath ] , others: [ AbsolutePath ] ) {
158
158
let contents = self . computeContents ( )
159
- var pathToRule : [ AbsolutePath : Rule ] = [ : ]
159
+ var pathToRule : [ AbsolutePath : FileRuleDescription . Rule ] = [ : ]
160
160
161
161
for path in contents {
162
162
pathToRule [ path] = self . computeRule ( for: path)
163
163
}
164
164
165
- let headers = pathToRule. lazy. filter { $0. value. rule == . header } . map { $0. key } . sorted ( )
166
- let compilePaths = pathToRule. lazy. filter { $0. value. rule == . compile } . map { $0. key }
165
+ let headers = pathToRule. lazy. filter { $0. value == . header } . map { $0. key } . sorted ( )
166
+ let compilePaths = pathToRule. lazy. filter { $0. value == . compile } . map { $0. key }
167
167
let sources = Sources ( paths: Array ( compilePaths) , root: targetPath)
168
168
let resources : [ Resource ] = pathToRule. compactMap { resource ( for: $0. key, with: $0. value) }
169
- let ignored = pathToRule. filter { $0. value. rule == . ignored } . map { $0. key }
170
- let others = pathToRule. filter { $0. value. rule == . none } . map { $0. key }
169
+ let ignored = pathToRule. filter { $0. value == . ignored } . map { $0. key }
170
+ let others = pathToRule. filter { $0. value == . none } . map { $0. key }
171
171
172
172
diagnoseConflictingResources ( in: resources)
173
173
diagnoseCopyConflictsWithLocalizationDirectories ( in: resources)
@@ -184,43 +184,38 @@ public struct TargetSourcesBuilder {
184
184
return ( sources, resources, headers, ignored, others)
185
185
}
186
186
187
- private struct Rule {
188
- let rule : FileRuleDescription . Rule
189
- let localization : TargetDescription . Resource . Localization ?
190
- }
191
-
192
187
/// Compute the rule for the given path.
193
- private func computeRule( for path: AbsolutePath ) -> Rule {
194
- var matchedRule : Rule = Rule ( rule : . none, localization : nil )
188
+ private func computeRule( for path: AbsolutePath ) -> FileRuleDescription . Rule {
189
+ var matchedRule : FileRuleDescription . Rule = . none
195
190
196
191
// First match any resources explicitly declared in the manifest file.
197
192
for declaredResource in target. resources {
198
193
let resourcePath = self . targetPath. appending ( RelativePath ( declaredResource. path) )
199
194
if path. isDescendantOfOrEqual ( to: resourcePath) {
200
- if matchedRule. rule != . none {
195
+ if matchedRule != . none {
201
196
self . observabilityScope. emit ( error: " duplicate resource rule ' \( declaredResource. rule) ' found for file at ' \( path) ' " )
202
197
}
203
- matchedRule = Rule ( rule : declaredResource. rule. fileRule , localization : declaredResource . localization )
198
+ matchedRule = . init ( declaredResource. rule)
204
199
}
205
200
}
206
201
207
202
// Match any sources explicitly declared in the manifest file.
208
203
if let declaredSources = self . declaredSources {
209
204
for sourcePath in declaredSources {
210
205
if path. isDescendantOfOrEqual ( to: sourcePath) {
211
- if matchedRule. rule != . none {
206
+ if matchedRule != . none {
212
207
self . observabilityScope. emit ( error: " duplicate rule found for file at ' \( path) ' " )
213
208
}
214
209
215
210
// Check for header files as they're allowed to be mixed with sources.
216
211
if let ext = path. extension,
217
212
FileRuleDescription . header. fileTypes. contains ( ext) {
218
- matchedRule = Rule ( rule : . header, localization : nil )
213
+ matchedRule = . header
219
214
} else if toolsVersion >= . v5_3 {
220
- matchedRule = Rule ( rule : . compile, localization : nil )
215
+ matchedRule = . compile
221
216
} else if let ext = path. extension,
222
217
SupportedLanguageExtension . validExtensions ( toolsVersion: toolsVersion) . contains ( ext) {
223
- matchedRule = Rule ( rule : . compile, localization : nil )
218
+ matchedRule = . compile
224
219
}
225
220
// The source file might have been declared twice so
226
221
// exit on first match.
@@ -232,7 +227,7 @@ public struct TargetSourcesBuilder {
232
227
233
228
// We haven't found a rule using that's explicitly declared in the manifest
234
229
// so try doing an automatic match.
235
- if matchedRule. rule == . none {
230
+ if matchedRule == . none {
236
231
let effectiveRules : [ FileRuleDescription ] = {
237
232
// Don't automatically match compile rules if target's sources are
238
233
// explicitly declared in the package manifest.
@@ -243,18 +238,18 @@ public struct TargetSourcesBuilder {
243
238
} ( )
244
239
245
240
if let needle = effectiveRules. first ( where: { $0. match ( path: path, toolsVersion: toolsVersion) } ) {
246
- matchedRule = Rule ( rule : needle. rule, localization : nil )
241
+ matchedRule = needle. rule
247
242
} else if path. parentDirectory. extension == Resource . localizationDirectoryExtension {
248
- matchedRule = Rule ( rule : . processResource, localization: nil )
243
+ matchedRule = . processResource( localization: . none )
249
244
}
250
245
}
251
246
252
247
return matchedRule
253
248
}
254
249
255
250
/// Returns the `Resource` file associated with a file and a particular rule, if there is one.
256
- private func resource( for path: AbsolutePath , with rule: Rule ) -> Resource ? {
257
- switch rule. rule {
251
+ private func resource( for path: AbsolutePath , with rule: FileRuleDescription . Rule ) -> Resource ? {
252
+ switch rule {
258
253
case . compile, . header, . none, . modulemap, . ignored:
259
254
return nil
260
255
case . processResource:
@@ -267,10 +262,13 @@ public struct TargetSourcesBuilder {
267
262
} ( )
268
263
269
264
let explicitLocalization : String ? = {
270
- switch rule. localization {
271
- case . default? : return defaultLocalization ?? " en "
272
- case . base? : return " Base "
273
- case nil : return nil
265
+ switch rule {
266
+ case . processResource( localization: . default) :
267
+ return defaultLocalization ?? " en "
268
+ case . processResource( localization: . base) :
269
+ return " Base "
270
+ default :
271
+ return . none
274
272
}
275
273
} ( )
276
274
@@ -281,9 +279,9 @@ public struct TargetSourcesBuilder {
281
279
return nil
282
280
}
283
281
284
- return Resource ( rule: . process, path : path , localization: implicitLocalization ?? explicitLocalization)
282
+ return Resource ( rule: . process( localization: implicitLocalization ?? explicitLocalization) , path : path )
285
283
case . copy:
286
- return Resource ( rule: . copy, path: path, localization : nil )
284
+ return Resource ( rule: . copy, path: path)
287
285
}
288
286
}
289
287
@@ -481,14 +479,14 @@ public struct FileRuleDescription {
481
479
/// A rule semantically describes a file/directory in a target.
482
480
///
483
481
/// It is up to the build system to translate a rule into a build command.
484
- public enum Rule {
482
+ public enum Rule : Equatable {
485
483
/// The compile rule for `sources` in a package.
486
484
case compile
487
485
488
486
/// Process resource file rule for any type of platform-specific processing.
489
487
///
490
488
/// This defaults to copy if there's no specialized behavior.
491
- case processResource
489
+ case processResource( localization : TargetDescription . Resource . Localization ? )
492
490
493
491
/// The copy rule.
494
492
case copy
@@ -583,7 +581,7 @@ public struct FileRuleDescription {
583
581
/// File types related to the interface builder and storyboards.
584
582
public static let xib : FileRuleDescription = {
585
583
. init(
586
- rule: . processResource,
584
+ rule: . processResource( localization : . none ) ,
587
585
toolsVersion: . v5_3,
588
586
fileTypes: [ " nib " , " xib " , " storyboard " ]
589
587
)
@@ -592,7 +590,7 @@ public struct FileRuleDescription {
592
590
/// File types related to the asset catalog.
593
591
public static let assetCatalog : FileRuleDescription = {
594
592
. init(
595
- rule: . processResource,
593
+ rule: . processResource( localization : . none ) ,
596
594
toolsVersion: . v5_3,
597
595
fileTypes: [ " xcassets " ]
598
596
)
@@ -601,7 +599,7 @@ public struct FileRuleDescription {
601
599
/// File types related to the CoreData.
602
600
public static let coredata : FileRuleDescription = {
603
601
. init(
604
- rule: . processResource,
602
+ rule: . processResource( localization : . none ) ,
605
603
toolsVersion: . v5_3,
606
604
fileTypes: [ " xcdatamodeld " , " xcdatamodel " , " xcmappingmodel " ]
607
605
)
@@ -610,7 +608,7 @@ public struct FileRuleDescription {
610
608
/// File types related to Metal.
611
609
public static let metal : FileRuleDescription = {
612
610
. init(
613
- rule: . processResource,
611
+ rule: . processResource( localization : . none ) ,
614
612
toolsVersion: . v5_3,
615
613
fileTypes: [ " metal " ]
616
614
)
@@ -656,13 +654,24 @@ public struct FileRuleDescription {
656
654
}
657
655
}
658
656
659
- extension TargetDescription . Resource . Rule {
660
- fileprivate var fileRule : FileRuleDescription . Rule {
661
- switch self {
662
- case . process:
663
- return . processResource
657
+ extension FileRuleDescription . Rule {
658
+ init ( _ seed : TargetDescription . Resource . Rule ) {
659
+ switch seed {
660
+ case . process( let localization ) :
661
+ self = . processResource( localization : localization )
664
662
case . copy:
665
- return . copy
663
+ self = . copy
664
+ }
665
+ }
666
+ }
667
+
668
+ extension Resource {
669
+ var localization : String ? {
670
+ switch self . rule {
671
+ case . process( let localization) :
672
+ return localization
673
+ default :
674
+ return . none
666
675
}
667
676
}
668
677
}
@@ -695,8 +704,8 @@ extension ObservabilityMetadata {
695
704
}
696
705
}
697
706
698
- fileprivate extension PackageReference . Kind {
699
- var emitAuthorWarnings : Bool {
707
+ extension PackageReference . Kind {
708
+ fileprivate var emitAuthorWarnings : Bool {
700
709
switch self {
701
710
case . remoteSourceControl, . registry:
702
711
return false
0 commit comments