When using type: syncedFolder in a target source, the excludes and includes options are completely ignored. This appears to be an implementation gap rather than a bug.
Expected Behavior
According to the ProjectSpec documentation, both excludes and includes should work with all source types:
- excludes: [String] - A list of global patterns representing the files to exclude. These rules are relative to
path and not the directory where project.yml resides.
- includes: [String] - A list of global patterns in the same format as
excludes representing the files to include.
Example configuration:
sources:
- path: MyApp
type: syncedFolder
createIntermediateGroups: true
excludes:
- "Resources/Firebase/**"
- "Resources/container/**"
Expected: Files matching the exclude patterns should not be included in the project.
Actual Behavior
All files under the syncedFolder are included regardless of the excludes patterns.
Root Cause
After investigating the source code, I found that excludes and includes are not implemented for syncedFolder:
In SourceGenerator.swift lines 690-701:
case .syncedFolder:
let relativePath = (try? path.relativePath(from: project.basePath)) ?? path
let syncedRootGroup = PBXFileSystemSynchronizedRootGroup(
sourceTree: .group,
path: relativePath.string,
name: targetSource.name,
explicitFileTypes: [:],
exceptions: [], // ← Always empty!
explicitFolders: [] // ← Always empty!
)
Compare this with case .group (around line 676), which properly handles excludePaths and includePaths:
case .group:
let (groupSourceFiles, groups) = try getGroupSources(
targetType: targetType,
targetSource: targetSource,
path: path,
isBaseGroup: true,
hasCustomParent: hasCustomParent,
excludePaths: excludePaths, // ← Properly passed
includePaths: includePaths.flatMap(SortedArray.init(_:)), // ← Properly passed
buildPhases: buildPhases
)
The excludePaths and includePaths are computed at lines 608-610 but never used in the syncedFolder case:
let excludePaths = getSourceMatches(targetSource: targetSource, patterns: targetSource.excludes)
let includePaths = targetSource.includes.isEmpty ? nil : getSourceMatches(targetSource: targetSource, patterns: targetSource.includes)
Proposed Solution
The exceptions parameter in PBXFileSystemSynchronizedRootGroup should be populated based on the excludes patterns. The implementation would need to:
- Convert the glob patterns from
excludes into the format expected by PBXFileSystemSynchronizedRootGroup.exceptions
- Handle
includes if applicable (though this might require understanding how Xcode 16's synchronized folders handle inclusions)
I'd be happy to contribute a PR if you can provide guidance on how exceptions should be formatted for PBXFileSystemSynchronizedRootGroup.
When using
type: syncedFolderin a target source, theexcludesandincludesoptions are completely ignored. This appears to be an implementation gap rather than a bug.Expected Behavior
According to the ProjectSpec documentation, both
excludesandincludesshould work with all source types:Example configuration:
Expected: Files matching the exclude patterns should not be included in the project.
Actual Behavior
All files under the
syncedFolderare included regardless of theexcludespatterns.Root Cause
After investigating the source code, I found that
excludesandincludesare not implemented forsyncedFolder:In
SourceGenerator.swiftlines 690-701:Compare this with
case .group(around line 676), which properly handlesexcludePathsandincludePaths:The
excludePathsandincludePathsare computed at lines 608-610 but never used in thesyncedFoldercase:Proposed Solution
The
exceptionsparameter inPBXFileSystemSynchronizedRootGroupshould be populated based on theexcludespatterns. The implementation would need to:excludesinto the format expected byPBXFileSystemSynchronizedRootGroup.exceptionsincludesif applicable (though this might require understanding how Xcode 16's synchronized folders handle inclusions)I'd be happy to contribute a PR if you can provide guidance on how
exceptionsshould be formatted forPBXFileSystemSynchronizedRootGroup.