Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1b57ba5

Browse files
authored
Improve INFOPLIST_FILE handling to only omit used Info.plist's from Copy Bundle Resources Build Phase (yonaskolb#1027)
* Update TestProject Fixture to include GoogleService-Info.plist resource bsaed on 2.18.0 generator * Update TestProject fixture to include an Info.plist file named 'App-Info.plist' to simulate scenario in yonaskolb#945 * Resolve INFOPLIST_FILE values upfront ahead of resolving all source files for a target * fixup! Resolve INFOPLIST_FILE values upfront ahead of resolving all source files for a target * fixup! Resolve INFOPLIST_FILE values upfront ahead of resolving all source files for a target * Refactor SourceGenerator to remove some redundant arguments on internal methods when generating source files in a target * Update SourceGenerator to accept '[Path: BuildPhaseSpec]' of preferred build phases in order to prioritise over 'default' value. Remove explicit Info.plist check from SourceGenerator. Update PBXProjGenerator to inject hash of build phases for resolved INFOPLIST_FILE values. Update SourceGeneratorTests to comply with change where only the FIRST Info.plist is excluded from copy bundle resources build phase, additionally resolve absolute path * Ensure project.basePath is always absolute when resolving Info.plist path relative to project * Add test coverage in SourceGeneratorTests.swift * Update CHANGELOG.md * Reword CHANGELOG.md
1 parent ff64a4a commit 1b57ba5

File tree

10 files changed

+214
-59
lines changed

10 files changed

+214
-59
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#### Fixed
1111
- Fixed regression on **.storekit** configuration files' default build phase. [#1026](https://github.com/yonaskolb/XcodeGen/pull/1026) @jcolicchio
1212
- Fixed bug where schemes without a build target would crash instead of displaying an error [#1040](https://github.com/yonaskolb/XcodeGen/pull/1040) @dalemyers
13+
- Fixed files with names ending in **Info.plist** (such as **GoogleServices-Info.plist**) from being omitted from the Copy Resources build phase. Now, only the resolved info plist file for each specific target is omitted. [#1027](https://github.com/yonaskolb/XcodeGen/pull/1027) @liamnichols
1314

1415
#### Internal
1516
- Build universal binaries for release. XcodeGen now runs natively on Apple Silicon. [#1024](https://github.com/yonaskolb/XcodeGen/pull/1024) @thii

Sources/ProjectSpec/Config.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Foundation
22
import JSONUtilities
33

4-
public struct Config: Equatable {
4+
public struct Config: Hashable {
55
public var name: String
66
public var type: ConfigType?
77

Sources/XcodeGenKit/PBXProjGenerator.swift

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -643,11 +643,12 @@ public class PBXProjGenerator {
643643
func generateTarget(_ target: Target) throws {
644644
let carthageDependencies = carthageResolver.dependencies(for: target)
645645

646-
let sourceFiles = try sourceGenerator.getAllSourceFiles(targetType: target.type, sources: target.sources)
646+
let infoPlistFiles: [Config: String] = getInfoPlists(for: target)
647+
let sourceFileBuildPhaseOverrideSequence: [(Path, BuildPhaseSpec)] = Set(infoPlistFiles.values).map({ (project.basePath + $0, .none) })
648+
let sourceFileBuildPhaseOverrides = Dictionary(uniqueKeysWithValues: sourceFileBuildPhaseOverrideSequence)
649+
let sourceFiles = try sourceGenerator.getAllSourceFiles(targetType: target.type, sources: target.sources, buildPhases: sourceFileBuildPhaseOverrides)
647650
.sorted { $0.path.lastComponent < $1.path.lastComponent }
648651

649-
var plistPath: Path?
650-
var searchForPlist = true
651652
var anyDependencyRequiresObjCLinking = false
652653

653654
var dependencies: [PBXTargetDependency] = []
@@ -1167,17 +1168,9 @@ public class PBXProjGenerator {
11671168
buildSettings["CODE_SIGN_ENTITLEMENTS"] = entitlements.path
11681169
}
11691170

1170-
// Set INFOPLIST_FILE if not defined in settings
1171-
if !project.targetHasBuildSetting("INFOPLIST_FILE", target: target, config: config) {
1172-
if let info = target.info {
1173-
buildSettings["INFOPLIST_FILE"] = info.path
1174-
} else if searchForPlist {
1175-
plistPath = getInfoPlist(target.sources)
1176-
searchForPlist = false
1177-
}
1178-
if let plistPath = plistPath {
1179-
buildSettings["INFOPLIST_FILE"] = (try? plistPath.relativePath(from: projectDirectory ?? project.basePath)) ?? plistPath
1180-
}
1171+
// Set INFOPLIST_FILE based on the resolved value
1172+
if let infoPlistFile = infoPlistFiles[config] {
1173+
buildSettings["INFOPLIST_FILE"] = infoPlistFile
11811174
}
11821175

11831176
// automatically calculate bundle id
@@ -1301,6 +1294,43 @@ public class PBXProjGenerator {
13011294
}
13021295
}
13031296

1297+
func getInfoPlists(for target: Target) -> [Config: String] {
1298+
var searchForDefaultInfoPlist: Bool = true
1299+
var defaultInfoPlist: String?
1300+
1301+
let values: [(Config, String)] = project.configs.compactMap { config in
1302+
// First, if the plist path was defined by `INFOPLIST_FILE`, use that
1303+
let buildSettings = project.getTargetBuildSettings(target: target, config: config)
1304+
if let value = buildSettings["INFOPLIST_FILE"] as? String {
1305+
return (config, value)
1306+
}
1307+
1308+
// Otherwise check if the path was defined as part of the `info` spec
1309+
if let value = target.info?.path {
1310+
return (config, value)
1311+
}
1312+
1313+
// If we haven't yet looked for the default info plist, try doing so
1314+
if searchForDefaultInfoPlist {
1315+
searchForDefaultInfoPlist = false
1316+
1317+
if let plistPath = getInfoPlist(target.sources) {
1318+
let basePath = projectDirectory ?? project.basePath.absolute()
1319+
let relative = (try? plistPath.relativePath(from: basePath)) ?? plistPath
1320+
defaultInfoPlist = relative.string
1321+
}
1322+
}
1323+
1324+
// Return the default plist if there was one
1325+
if let value = defaultInfoPlist {
1326+
return (config, value)
1327+
}
1328+
return nil
1329+
}
1330+
1331+
return Dictionary(uniqueKeysWithValues: values)
1332+
}
1333+
13041334
func getInfoPlist(_ sources: [TargetSource]) -> Path? {
13051335
sources
13061336
.lazy

Sources/XcodeGenKit/SourceGenerator.swift

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,19 @@ class SourceGenerator {
7777
localPackageGroup!.children.append(fileReference)
7878
}
7979

80-
func getAllSourceFiles(targetType: PBXProductType, sources: [TargetSource]) throws -> [SourceFile] {
81-
try sources.flatMap { try getSourceFiles(targetType: targetType, targetSource: $0, path: project.basePath + $0.path) }
80+
/// Collects an array complete of all `SourceFile` objects that make up the target based on the provided `TargetSource` definitions.
81+
///
82+
/// - Parameters:
83+
/// - targetType: The type of target that the source files should belong to.
84+
/// - sources: The array of sources defined as part of the targets spec.
85+
/// - buildPhases: A dictionary containing any build phases that should be applied to source files at specific paths in the event that the associated `TargetSource` didn't already define a `buildPhase`. Values from this dictionary are used in cases where the project generator knows more about a file than the spec/filesystem does (i.e if the file should be treated as the targets Info.plist and so on).
86+
func getAllSourceFiles(targetType: PBXProductType, sources: [TargetSource], buildPhases: [Path : BuildPhaseSpec]) throws -> [SourceFile] {
87+
try sources.flatMap { try getSourceFiles(targetType: targetType, targetSource: $0, buildPhases: buildPhases) }
8288
}
8389

8490
// get groups without build files. Use for Project.fileGroups
8591
func getFileGroups(path: String) throws {
86-
let fullPath = project.basePath + path
87-
_ = try getSourceFiles(targetType: .none, targetSource: TargetSource(path: path), path: fullPath)
92+
_ = try getSourceFiles(targetType: .none, targetSource: TargetSource(path: path), buildPhases: [:])
8893
}
8994

9095
func getFileType(path: Path) -> FileType? {
@@ -95,7 +100,7 @@ class SourceGenerator {
95100
}
96101
}
97102

98-
func generateSourceFile(targetType: PBXProductType, targetSource: TargetSource, path: Path, buildPhase: BuildPhaseSpec? = nil, fileReference: PBXFileElement? = nil) -> SourceFile {
103+
func generateSourceFile(targetType: PBXProductType, targetSource: TargetSource, path: Path, fileReference: PBXFileElement? = nil, buildPhases: [Path: BuildPhaseSpec]) -> SourceFile {
99104
let fileReference = fileReference ?? fileReferencesByPath[path.string.lowercased()]!
100105
var settings: [String: Any] = [:]
101106
let fileType = getFileType(path: path)
@@ -106,9 +111,11 @@ class SourceGenerator {
106111

107112
let headerVisibility = targetSource.headerVisibility ?? .public
108113

109-
if let buildPhase = buildPhase {
114+
if let buildPhase = targetSource.buildPhase {
110115
chosenBuildPhase = buildPhase
111-
} else if let buildPhase = targetSource.buildPhase {
116+
} else if resolvedTargetSourceType(for: targetSource, at: path) == .folder {
117+
chosenBuildPhase = .resources
118+
} else if let buildPhase = buildPhases[path] {
112119
chosenBuildPhase = buildPhase
113120
} else {
114121
chosenBuildPhase = getDefaultBuildPhase(for: path, targetType: targetType)
@@ -250,9 +257,6 @@ class SourceGenerator {
250257

251258
/// returns a default build phase for a given path. This is based off the filename
252259
private func getDefaultBuildPhase(for path: Path, targetType: PBXProductType) -> BuildPhaseSpec? {
253-
if path.lastComponent.hasSuffix("Info.plist") {
254-
return nil
255-
}
256260
if let buildPhase = getFileType(path: path)?.buildPhase {
257261
return buildPhase
258262
}
@@ -404,7 +408,8 @@ class SourceGenerator {
404408
isBaseGroup: Bool,
405409
hasCustomParent: Bool,
406410
excludePaths: Set<Path>,
407-
includePaths: Set<Path>
411+
includePaths: Set<Path>,
412+
buildPhases: [Path: BuildPhaseSpec]
408413
) throws -> (sourceFiles: [SourceFile], groups: [PBXGroup]) {
409414

410415
let children = try getSourceChildren(targetSource: targetSource, dirPath: path, excludePaths: excludePaths, includePaths: includePaths)
@@ -435,7 +440,7 @@ class SourceGenerator {
435440

436441
var groupChildren: [PBXFileElement] = filePaths.map { getFileReference(path: $0, inPath: path) }
437442
var allSourceFiles: [SourceFile] = filePaths.map {
438-
generateSourceFile(targetType: targetType, targetSource: targetSource, path: $0)
443+
generateSourceFile(targetType: targetType, targetSource: targetSource, path: $0, buildPhases: buildPhases)
439444
}
440445
var groups: [PBXGroup] = []
441446

@@ -448,7 +453,8 @@ class SourceGenerator {
448453
isBaseGroup: false,
449454
hasCustomParent: false,
450455
excludePaths: excludePaths,
451-
includePaths: includePaths
456+
includePaths: includePaths,
457+
buildPhases: buildPhases
452458
)
453459

454460
guard !subGroups.sourceFiles.isEmpty || project.options.generateEmptyDirectories else {
@@ -491,7 +497,8 @@ class SourceGenerator {
491497
let sourceFile = generateSourceFile(targetType: targetType,
492498
targetSource: targetSource,
493499
path: filePath,
494-
fileReference: variantGroup)
500+
fileReference: variantGroup,
501+
buildPhases: buildPhases)
495502
allSourceFiles.append(sourceFile)
496503
}
497504
}
@@ -528,7 +535,8 @@ class SourceGenerator {
528535
let sourceFile = generateSourceFile(targetType: targetType,
529536
targetSource: targetSource,
530537
path: filePath,
531-
fileReference: fileReference)
538+
fileReference: fileReference,
539+
buildPhases: buildPhases)
532540
allSourceFiles.append(sourceFile)
533541
groupChildren.append(fileReference)
534542
}
@@ -551,14 +559,15 @@ class SourceGenerator {
551559
}
552560

553561
/// creates source files
554-
private func getSourceFiles(targetType: PBXProductType, targetSource: TargetSource, path: Path) throws -> [SourceFile] {
562+
private func getSourceFiles(targetType: PBXProductType, targetSource: TargetSource, buildPhases: [Path: BuildPhaseSpec]) throws -> [SourceFile] {
555563

556564
// generate excluded paths
565+
let path = project.basePath + targetSource.path
557566
let excludePaths = getSourceMatches(targetSource: targetSource, patterns: targetSource.excludes)
558567
// generate included paths. Excluded paths will override this.
559568
let includePaths = getSourceMatches(targetSource: targetSource, patterns: targetSource.includes)
560569

561-
let type = targetSource.type ?? (path.isFile || path.extension != nil ? .file : .group)
570+
let type = resolvedTargetSourceType(for: targetSource, at: path)
562571

563572
let customParentGroups = (targetSource.group ?? "").split(separator: "/").map { String($0) }
564573
let hasCustomParent = !customParentGroups.isEmpty
@@ -570,11 +579,10 @@ class SourceGenerator {
570579
var sourcePath = path
571580
switch type {
572581
case .folder:
573-
let folderPath = project.basePath + Path(targetSource.path)
574582
let fileReference = getFileReference(
575-
path: folderPath,
583+
path: path,
576584
inPath: project.basePath,
577-
name: targetSource.name ?? folderPath.lastComponent,
585+
name: targetSource.name ?? path.lastComponent,
578586
sourceTree: .sourceRoot,
579587
lastKnownFileType: "folder"
580588
)
@@ -583,22 +591,15 @@ class SourceGenerator {
583591
rootGroups.insert(fileReference)
584592
}
585593

586-
let buildPhase: BuildPhaseSpec?
587-
if let targetBuildPhase = targetSource.buildPhase {
588-
buildPhase = targetBuildPhase
589-
} else {
590-
buildPhase = .resources
591-
}
592-
593-
let sourceFile = generateSourceFile(targetType: targetType, targetSource: targetSource, path: folderPath, buildPhase: buildPhase)
594+
let sourceFile = generateSourceFile(targetType: targetType, targetSource: targetSource, path: path, buildPhases: buildPhases)
594595

595596
sourceFiles.append(sourceFile)
596597
sourceReference = fileReference
597598
case .file:
598599
let parentPath = path.parent()
599600
let fileReference = getFileReference(path: path, inPath: parentPath, name: targetSource.name)
600601

601-
let sourceFile = generateSourceFile(targetType: targetType, targetSource: targetSource, path: path)
602+
let sourceFile = generateSourceFile(targetType: targetType, targetSource: targetSource, path: path, buildPhases: buildPhases)
602603

603604
if hasCustomParent {
604605
sourcePath = path
@@ -633,7 +634,8 @@ class SourceGenerator {
633634
isBaseGroup: true,
634635
hasCustomParent: hasCustomParent,
635636
excludePaths: excludePaths,
636-
includePaths: includePaths
637+
includePaths: includePaths,
638+
buildPhases: buildPhases
637639
)
638640

639641
let group = groups.first!
@@ -655,6 +657,13 @@ class SourceGenerator {
655657
return sourceFiles
656658
}
657659

660+
/// Returns the resolved `SourceType` for a given `TargetSource`.
661+
///
662+
/// While `TargetSource` declares `type`, its optional and in the event that the value is not defined then we must resolve a sensible default based on the path of the source.
663+
private func resolvedTargetSourceType(for targetSource: TargetSource, at path: Path) -> SourceType {
664+
return targetSource.type ?? (path.isFile || path.extension != nil ? .file : .group)
665+
}
666+
658667
private func createParentGroups(_ parentGroups: [String], for fileElement: PBXFileElement) {
659668
guard let parentName = parentGroups.last else {
660669
return
File renamed without changes.

0 commit comments

Comments
 (0)