Skip to content

Commit f5b01a8

Browse files
committed
Fix configFiles creating duplicate group inside synced folder
When configFiles reference paths inside a synced folder source, getContainedFileReference() created a separate PBXGroup hierarchy that duplicated the PBXFileSystemSynchronizedRootGroup already managing those files. Skip group creation in getContainedFileReference when the file path falls inside an existing synced folder root. Fixes the same class of issue as #1602, but for configFiles rather than target sources.
1 parent acd366f commit f5b01a8

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

Sources/XcodeGenKit/SourceGenerator.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,14 @@ class SourceGenerator {
201201

202202
let parentPath = path.parent()
203203
let fileReference = getFileReference(path: path, inPath: parentPath)
204+
205+
// Synced folders already own their file hierarchy, so creating a PBXGroup would duplicate it.
206+
// We check the project spec directly because configFiles are resolved before target sources
207+
// populate syncedGroupsByPath.
208+
guard !isInsideSyncedFolder(path: path) else {
209+
return fileReference
210+
}
211+
204212
let parentGroup = getGroup(
205213
path: parentPath,
206214
mergingChildren: [fileReference],
@@ -277,6 +285,17 @@ class SourceGenerator {
277285
}
278286
}
279287

288+
/// Whether the given path falls inside a target source configured as a synced folder.
289+
private func isInsideSyncedFolder(path: Path) -> Bool {
290+
let relativePath = (try? path.relativePath(from: project.basePath)) ?? path
291+
return project.targets.contains { target in
292+
target.sources.contains { source in
293+
let resolvedType = source.type ?? (project.options.defaultSourceDirectoryType ?? .group)
294+
return resolvedType == .syncedFolder && relativePath.string.hasPrefix(source.path + "/")
295+
}
296+
}
297+
}
298+
280299
/// returns a default build phase for a given path. This is based off the filename
281300
private func getDefaultBuildPhase(for path: Path, targetType: PBXProductType) -> BuildPhaseSpec? {
282301
if let buildPhase = getFileType(path: path)?.buildPhase {

Tests/XcodeGenKitTests/SourceGeneratorTests.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,34 @@ class SourceGeneratorTests: XCTestCase {
491491
try expect(appGroup === testsGroup) == true
492492
}
493493

494+
$0.it("does not create duplicate group for configFiles inside synced folder") {
495+
let directories = """
496+
Sources:
497+
- a.swift
498+
- Config:
499+
- config.xcconfig
500+
"""
501+
try createDirectories(directories)
502+
503+
let source = TargetSource(path: "Sources", type: .syncedFolder)
504+
let target = Target(name: "Target1", type: .application, platform: .iOS, sources: [source])
505+
let project = Project(
506+
basePath: directoryPath,
507+
name: "Test",
508+
targets: [target],
509+
configFiles: ["Debug": "Sources/Config/config.xcconfig"]
510+
)
511+
512+
let pbxProj = try project.generatePbxProj()
513+
let mainGroup = try pbxProj.getMainGroup()
514+
515+
let sourcesChildren = mainGroup.children.filter { $0.path == "Sources" || $0.name == "Sources" }
516+
try expect(sourcesChildren.count) == 1
517+
518+
let syncedFolders = mainGroup.children.compactMap { $0 as? PBXFileSystemSynchronizedRootGroup }
519+
try expect(syncedFolders.count) == 1
520+
}
521+
494522
$0.it("supports frameworks in sources") {
495523
let directories = """
496524
Sources:

0 commit comments

Comments
 (0)