Skip to content

Synced folders #1541

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ jobs:
name: Xcode ${{ matrix.xcode }}
strategy:
matrix:
xcode: ["15.4", "16.0"]
xcode: ["16.0"]
include:
- xcode: "15.4"
macos: macos-15
- xcode: "16.0"
macos: macos-15
env:
Expand Down
5 changes: 5 additions & 0 deletions Docs/ProjectSpec.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ Note that target names can also be changed by adding a `name` property to a targ
- [ ] **postGenCommand**: **String** - A bash command to run after the project has been generated. If the project isn't generated due to no changes when using the cache then this won't run. This is useful for running things like `pod install` only if the project is actually regenerated.
- [ ] **useBaseInternationalization**: **Bool** If this is `false` and your project does not include resources located in a **Base.lproj** directory then `Base` will not be included in the projects 'known regions'. The default value is `true`.
- [ ] **schemePathPrefix**: **String** - A path prefix for relative paths in schemes, such as StoreKitConfiguration. The default is `"../../"`, which is suitable for non-workspace projects. For use in workspaces, use `"../"`.
- [ ] **defaultSourceDirectoryType**: **String** - When a [Target source](#target-source) doesn't specify a type and is a directory, this is the type that will be used. If nothing is specified for either then `group` will be used.
- `group` (default)
- `folder`
- `syncedFolder`

```yaml
options:
Expand Down Expand Up @@ -542,6 +546,7 @@ A source can be provided via a string (the path) or an object of the form:
- `file`: a file reference with a parent group will be created (Default for files or directories with extensions)
- `group`: a group with all it's containing files. (Default for directories without extensions)
- `folder`: a folder reference.
- `syncedFolder`: Xcode 16's synchronized folders, also knows as buildable folders
- [ ] **headerVisibility**: **String** - The visibility of any headers. This defaults to `public`, but can be either:
- `public`
- `private`
Expand Down
8 changes: 4 additions & 4 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/tadija/AEXML.git",
"state" : {
"revision" : "38f7d00b23ecd891e1ee656fa6aeebd6ba04ecc3",
"version" : "4.6.1"
"revision" : "db806756c989760b35108146381535aec231092b",
"version" : "4.7.0"
}
},
{
Expand Down Expand Up @@ -77,8 +77,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/tuist/XcodeProj.git",
"state" : {
"revision" : "dc3b87a4e69f9cd06c6cb16199f5d0472e57ef6b",
"version" : "8.24.3"
"revision" : "b1caa062d4aaab3e3d2bed5fe0ac5f8ce9bf84f4",
"version" : "8.27.7"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ let package = Package(
.package(url: "https://github.com/yonaskolb/JSONUtilities.git", from: "4.2.0"),
.package(url: "https://github.com/kylef/Spectre.git", from: "0.9.2"),
.package(url: "https://github.com/onevcat/Rainbow.git", from: "4.0.0"),
.package(url: "https://github.com/tuist/XcodeProj.git", exact: "8.24.3"),
.package(url: "https://github.com/tuist/XcodeProj.git", exact: "8.27.7"),
.package(url: "https://github.com/jakeheis/SwiftCLI.git", from: "6.0.3"),
.package(url: "https://github.com/mxcl/Version", from: "2.0.0"),
.package(url: "https://github.com/freddi-kit/ArtifactBundleGen", exact: "0.0.6")
Expand Down
1 change: 1 addition & 0 deletions Sources/ProjectSpec/SourceType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ public enum SourceType: String {
case group
case file
case folder
case syncedFolder
}
6 changes: 5 additions & 1 deletion Sources/ProjectSpec/SpecOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public struct SpecOptions: Equatable {
public var postGenCommand: String?
public var useBaseInternationalization: Bool
public var schemePathPrefix: String
public var defaultSourceDirectoryType: SourceType?

public enum ValidationType: String {
case missingConfigs
Expand Down Expand Up @@ -100,7 +101,8 @@ public struct SpecOptions: Equatable {
preGenCommand: String? = nil,
postGenCommand: String? = nil,
useBaseInternationalization: Bool = useBaseInternationalizationDefault,
schemePathPrefix: String = schemePathPrefixDefault
schemePathPrefix: String = schemePathPrefixDefault,
defaultSourceDirectoryType: SourceType? = nil
) {
self.minimumXcodeGenVersion = minimumXcodeGenVersion
self.carthageBuildPath = carthageBuildPath
Expand All @@ -127,6 +129,7 @@ public struct SpecOptions: Equatable {
self.postGenCommand = postGenCommand
self.useBaseInternationalization = useBaseInternationalization
self.schemePathPrefix = schemePathPrefix
self.defaultSourceDirectoryType = defaultSourceDirectoryType
}
}

Expand Down Expand Up @@ -160,6 +163,7 @@ extension SpecOptions: JSONObjectConvertible {
postGenCommand = jsonDictionary.json(atKeyPath: "postGenCommand")
useBaseInternationalization = jsonDictionary.json(atKeyPath: "useBaseInternationalization") ?? SpecOptions.useBaseInternationalizationDefault
schemePathPrefix = jsonDictionary.json(atKeyPath: "schemePathPrefix") ?? SpecOptions.schemePathPrefixDefault
defaultSourceDirectoryType = jsonDictionary.json(atKeyPath: "defaultSourceDirectoryType")
if jsonDictionary["fileTypes"] != nil {
fileTypes = try jsonDictionary.json(atKeyPath: "fileTypes")
} else {
Expand Down
6 changes: 6 additions & 0 deletions Sources/XcodeGenKit/PBXProjGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1454,6 +1454,12 @@ public class PBXProjGenerator {
if !target.isLegacy {
targetObject.productType = target.type
}

// add fileSystemSynchronizedGroups
let synchronizedRootGroups = sourceFiles.compactMap { $0.synchronizedRootGroup }
if !synchronizedRootGroups.isEmpty {
targetObject.fileSystemSynchronizedGroups = synchronizedRootGroups
}
}

private func makePlatformFilter(for filter: Dependency.PlatformFilter) -> String? {
Expand Down
40 changes: 39 additions & 1 deletion Sources/XcodeGenKit/SourceGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ struct SourceFile {
let fileReference: PBXFileElement
let buildFile: PBXBuildFile
let buildPhase: BuildPhaseSpec?
var synchronizedRootGroup: PBXFileSystemSynchronizedRootGroup?
}

class SourceGenerator {
Expand Down Expand Up @@ -687,6 +688,33 @@ class SourceGenerator {

sourceFiles += groupSourceFiles
sourceReference = group
case .syncedFolder:

let relativePath = (try? path.relativePath(from: project.basePath)) ?? path

let syncedRootGroup = PBXFileSystemSynchronizedRootGroup(
sourceTree: .group,
path: relativePath.string,
name: targetSource.name,
explicitFileTypes: [:],
exceptions: [],
explicitFolders: []
)
addObject(syncedRootGroup)
sourceReference = syncedRootGroup

// TODO: adjust if hasCustomParent == true
rootGroups.insert(syncedRootGroup)

var sourceFile = generateSourceFile(
targetType: targetType,
targetSource: targetSource,
path: path,
fileReference: syncedRootGroup,
buildPhases: buildPhases
)
sourceFile.synchronizedRootGroup = syncedRootGroup
sourceFiles.append(sourceFile)
}

if hasCustomParent {
Expand All @@ -703,7 +731,17 @@ class SourceGenerator {
///
/// 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.
private func resolvedTargetSourceType(for targetSource: TargetSource, at path: Path) -> SourceType {
return targetSource.type ?? (path.isFile || path.extension != nil ? .file : .group)
if let chosenType = targetSource.type {
return chosenType
} else {
if path.isFile || path.extension != nil {
return .file
} else if let sourceType = project.options.defaultSourceDirectoryType {
return sourceType
} else {
return .group
}
}
}

private func createParentGroups(_ parentGroups: [String], for fileElement: PBXFileElement) {
Expand Down
2 changes: 1 addition & 1 deletion Sources/XcodeGenKit/Version.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ extension Project {
}

var objectVersion: UInt {
54
70
}

var minimizedProjectReferenceProxies: Int {
Expand Down
2 changes: 2 additions & 0 deletions Sources/XcodeGenKit/XCProjExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ extension PBXProj {
string += "\n 🌎 " + variantGroup.nameOrPath
} else if let versionGroup = child as? XCVersionGroup {
string += "\n 🔢 " + versionGroup.nameOrPath
} else if let syncedFolder = child as? PBXFileSystemSynchronizedRootGroup {
string += "\n 📁 " + syncedFolder.nameOrPath
}
}
return string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objectVersion = 70;
objects = {

/* Begin PBXBuildFile section */
Expand Down Expand Up @@ -322,8 +322,6 @@
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1430;
TargetAttributes = {
};
};
buildConfigurationList = D91E14E36EC0B415578456F2 /* Build configuration list for PBXProject "Project" */;
compatibilityVersion = "Xcode 14.0";
Expand All @@ -335,7 +333,7 @@
);
mainGroup = 293D0FF827366B513839236A;
minimizedProjectReferenceProxies = 1;
preferredProjectObjectVersion = 54;
preferredProjectObjectVersion = 70;
projectDirPath = "";
projectRoot = "";
targets = (
Expand Down
6 changes: 2 additions & 4 deletions Tests/Fixtures/SPM/SPM.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objectVersion = 70;
objects = {

/* Begin PBXAggregateTarget section */
Expand Down Expand Up @@ -239,8 +239,6 @@
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1430;
TargetAttributes = {
};
};
buildConfigurationList = 425866ADA259DB93FC4AF1E3 /* Build configuration list for PBXProject "SPM" */;
compatibilityVersion = "Xcode 14.0";
Expand All @@ -259,7 +257,7 @@
630A8CE9F2BE39704ED9D461 /* XCLocalSwiftPackageReference "FooFeature" */,
C6539B364583AE96C18CE377 /* XCLocalSwiftPackageReference "../../.." */,
);
preferredProjectObjectVersion = 54;
preferredProjectObjectVersion = 70;
projectDirPath = "";
projectRoot = "";
targets = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
skipped = "NO"
parallelizable = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "XcodeGenKitTests"
Expand All @@ -50,7 +51,8 @@
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
skipped = "NO"
parallelizable = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "339863E54E2D955C00B56802"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objectVersion = 70;
objects = {

/* Begin PBXFileReference section */
Expand Down Expand Up @@ -120,8 +120,6 @@
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1430;
TargetAttributes = {
};
};
buildConfigurationList = 3DFC1105373EDB6483D4BC5D /* Build configuration list for PBXProject "AnotherProject" */;
compatibilityVersion = "Xcode 14.0";
Expand All @@ -132,7 +130,7 @@
);
mainGroup = 4E8CFA4275C972686621210C;
minimizedProjectReferenceProxies = 1;
preferredProjectObjectVersion = 54;
preferredProjectObjectVersion = 70;
projectDirPath = "";
projectRoot = "";
targets = (
Expand Down
8 changes: 7 additions & 1 deletion Tests/Fixtures/TestProject/App_iOS/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.

// file from a framework
_ = FrameworkStruct()

// Standalone files added to project by path-to-file.
_ = standaloneHello()

// file in a synced folder
_ = SyncedStruct()

return true
}
}
20 changes: 18 additions & 2 deletions Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objectVersion = 70;
objects = {

/* Begin PBXAggregateTarget section */
Expand Down Expand Up @@ -830,6 +830,18 @@
FED40A89162E446494DDE7C7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFileSystemSynchronizedRootGroup section */
AE2AB2772F70DFFF402AA02B /* SyncedFolder */ = {
isa = PBXFileSystemSynchronizedRootGroup;
explicitFileTypes = {
};
explicitFolders = (
);
path = SyncedFolder;
sourceTree = "<group>";
};
/* End PBXFileSystemSynchronizedRootGroup section */

/* Begin PBXFrameworksBuildPhase section */
117840B4DBC04099F6779D00 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
Expand Down Expand Up @@ -1050,6 +1062,7 @@
2E1E747C7BC434ADB80CC269 /* Headers */,
6B1603BA83AA0C7B94E45168 /* ResourceFolder */,
6BBE762F36D94AB6FFBFE834 /* SomeFile */,
AE2AB2772F70DFFF402AA02B /* SyncedFolder */,
79DC4A1E4D2E0D3A215179BC /* Bundles */,
FC1515684236259C50A7747F /* Frameworks */,
AC523591AC7BE9275003D2DB /* Products */,
Expand Down Expand Up @@ -1686,6 +1699,9 @@
E8C078B0A2A2B0E1D35694D5 /* PBXTargetDependency */,
981D116D40DBA0407D0E0E94 /* PBXTargetDependency */,
);
fileSystemSynchronizedGroups = (
AE2AB2772F70DFFF402AA02B /* SyncedFolder */,
);
name = App_iOS;
packageProductDependencies = (
D7917D10F77DA9D69937D493 /* Swinject */,
Expand Down Expand Up @@ -2443,7 +2459,7 @@
packageReferences = (
4EDA79334592CBBA0E507AD2 /* XCRemoteSwiftPackageReference "Swinject" */,
);
preferredProjectObjectVersion = 54;
preferredProjectObjectVersion = 70;
projectDirPath = "";
projectReferences = (
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
skipped = "NO"
parallelizable = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63BFF75AA22335E3DDD5E26A"
Expand All @@ -50,7 +51,8 @@
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
skipped = "NO"
parallelizable = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "91C3E922A8482E07649971B9"
Expand Down
Loading