Fix synced folder issues: configFiles duplicate, group insertion, and directory-level membershipExceptions#1607
Conversation
f5b01a8 to
7f1fefa
Compare
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 yonaskolb#1602, but for configFiles rather than target sources.
7f1fefa to
391bd18
Compare
…eptions - Prevent rootGroups insertion for paths inside synced folders, avoiding duplicate PBXGroup alongside PBXFileSystemSynchronizedRootGroup - Recurse into non-included directories in findExceptions to list individual file paths instead of directory names, since Xcode does not recursively exclude directory contents from membershipExceptions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…in exceptions Xcode does not recursively exclude directory contents from membershipExceptions, so the correct behavior is to list individual files rather than directory names. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@4brunu or @yonaskolb could you take a look on my PR when you have some time? |
| /// Whether the given path falls inside a target source configured as a synced folder. | ||
| /// Checks the project spec directly because configFiles are resolved before target sources | ||
| /// populate `syncedGroupsByPath`. | ||
| private func isInsideSyncedFolder(path: Path) -> Bool { |
There was a problem hiding this comment.
I'm concerned about the performance implications of such a loop
There was a problem hiding this comment.
Fair point. In practice it's pretty small I think because it is only called from two cold paths (getContainedFileReference for configFiles and the getGroup root insertion guard), not per-file.
But I can easily cache it with a lazy, it could look like this:
private lazy var syncedFolderPrefixes: Set<String> = {
var prefixes = Set<String>()
for target in project.targets {
for source in target.sources {
let type = source.type ?? (project.options.defaultSourceDirectoryType ?? .group)
if type == .syncedFolder {
prefixes.insert(source.path + "/")
}
}
}
return prefixes
}()
private func isInsideSyncedFolder(path: Path) -> Bool {
let relativePath = (try? path.relativePath(from: basePath)) ?? path
return syncedFolderPrefixes.contains { relativePath.string.hasPrefix($0) }
}
´´´
Want me to go with that?| let parentPath = path.parent() | ||
|
|
||
| guard !isInsideSyncedFolder(path: path) else { | ||
| return getFileReference(path: path, inPath: project.basePath, sourceTree: .sourceRoot) |
There was a problem hiding this comment.
we have a new basePath getter that may be a better value, as xcodegen can be run in a different directory than the project base path.
There was a problem hiding this comment.
You're right, I did't see it.
I just changed with basePath, it's way more cleaner
When XcodeGen is run with --project-directory, the computed basePath property accounts for the different output location. Using project.basePath would resolve paths incorrectly in that scenario. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Description
3 related fixes for
defaultSourceDirectoryType: syncedFoldersupport.1. configFiles creating duplicate groups
When using
configFilesthat reference paths inside a synced folder source, a duplicatePBXGroupis created alongside thePBXFileSystemSynchronizedRootGroup.Root cause:
getContainedFileReference()always creates aPBXGrouphierarchy viagetGroup(), regardless of whether the file lives inside a synced folder. Same class of issue as #1602, but forconfigFiles.Fix: Return a file reference with
sourceTree: .sourceRootwhen the path is inside a synced folder, skipping group creation entirely.2. Root group duplication for paths inside synced folders
When multiple targets reference a synced folder path (e.g., extension targets with
type: syncedFolder),getGroup()inserts the group intorootGroups, causing a duplicate entry in the project navigator.Fix: Skip
rootGroupsinsertion when the path is inside an existing synced folder.3. Directory-level membershipExceptions not working
When using
includeson a synced folder source,findExceptionsadds directory names tomembershipExceptionsinstead of individual file paths. Xcode does not recursively exclude directory contents from membership exceptions, leading to:Supporting Files/directory in exceptions doesn't excludeSupporting Files/Info.plist)Fix: Recurse into non-included directories in
findExceptionsto list individual file paths instead of directory names.Tests
does not create duplicate group for configFiles inside synced folderincludescover the membershipExceptions behaviorEnvironment