Skip to content

Commit

Permalink
Add excludeFromProject option for local packages (#1512)
Browse files Browse the repository at this point in the history
  • Loading branch information
maximkrouk authored Feb 17, 2025
1 parent b1e03f0 commit 434dfec
Show file tree
Hide file tree
Showing 12 changed files with 79 additions and 31 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ XcodeGen.xcodeproj
xcodegen.zip
xcodegen.artifactbundle.zip
.vscode/launch.json
DerivedData
2 changes: 2 additions & 0 deletions Docs/ProjectSpec.md
Original file line number Diff line number Diff line change
Expand Up @@ -1246,6 +1246,7 @@ Swift packages are defined at a project level, and then linked to individual tar

- [x] **path**: **String** - the path to the package in local. The path must be directory with a `Package.swift`.
- [ ] **group** : **String**- Optional path that specifies the location where the package will live in your xcode project. Use `""` to specify the project root.
- [ ] **excludeFromProject** : **String**- Optional flag to exclude the package from the generated project (useful if the package is already added via xcworkspace and the project is not intended for standalone use), defaults to `false`

```yml
packages:
Expand All @@ -1260,6 +1261,7 @@ packages:
AppFeature:
path: ../Packages
group: Domains/AppFeature
excludeFromProject: false
```

## Project Reference
Expand Down
2 changes: 1 addition & 1 deletion Sources/ProjectSpec/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ extension Project {
packages.merge(localPackages.reduce(into: [String: SwiftPackage]()) {
// Project name will be obtained by resolved abstractpath's lastComponent for dealing with some path case, like "../"
let packageName = (basePath + Path($1).normalize()).lastComponent
$0[packageName] = .local(path: $1, group: nil)
$0[packageName] = .local(path: $1, group: nil, excludeFromProject: false)
}
)
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/ProjectSpec/SpecValidation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ extension Project {
}

for (name, package) in packages {
if case let .local(path, _) = package, !(basePath + Path(path).normalize()).exists {
if case let .local(path, _, _) = package, !(basePath + Path(path).normalize()).exists {
errors.append(.invalidLocalPackage(name))
}
}
Expand Down
13 changes: 7 additions & 6 deletions Sources/ProjectSpec/SwiftPackage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public enum SwiftPackage: Equatable {
static let githubPrefix = "https://github.com/"

case remote(url: String, versionRequirement: VersionRequirement)
case local(path: String, group: String?)
case local(path: String, group: String?, excludeFromProject: Bool)

public var isLocal: Bool {
if case .local = self {
Expand All @@ -23,10 +23,10 @@ public enum SwiftPackage: Equatable {
extension SwiftPackage: JSONObjectConvertible {

public init(jsonDictionary: JSONDictionary) throws {
if let path: String = jsonDictionary.json(atKeyPath: "path"), let customLocation: String = jsonDictionary.json(atKeyPath: "group") {
self = .local(path: path, group: customLocation)
} else if let path: String = jsonDictionary.json(atKeyPath: "path") {
self = .local(path: path, group: nil)
if let path: String = jsonDictionary.json(atKeyPath: "path") {
let customLocation: String? = jsonDictionary.json(atKeyPath: "group")
let excludeFromProject: Bool = jsonDictionary.json(atKeyPath: "excludeFromProject") ?? false
self = .local(path: path, group: customLocation, excludeFromProject: excludeFromProject)
} else {
let versionRequirement: VersionRequirement = try VersionRequirement(jsonDictionary: jsonDictionary)
try Self.validateVersion(versionRequirement: versionRequirement)
Expand Down Expand Up @@ -92,9 +92,10 @@ extension SwiftPackage: JSONEncodable {
dictionary["revision"] = revision
}
return dictionary
case let .local(path, group):
case let .local(path, group, excludeFromProject):
dictionary["path"] = path
dictionary["group"] = group
dictionary["excludeFromProject"] = excludeFromProject
}

return dictionary
Expand Down
10 changes: 6 additions & 4 deletions Sources/XcodeGenKit/PBXProjGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,14 @@ public class PBXProjGenerator {
let packageReference = XCRemoteSwiftPackageReference(repositoryURL: url, versionRequirement: versionRequirement)
packageReferences[name] = packageReference
addObject(packageReference)
case let .local(path, group):
case let .local(path, group, excludeFromProject):
let packageReference = XCLocalSwiftPackageReference(relativePath: path)
localPackageReferences[name] = packageReference
addObject(packageReference)

try sourceGenerator.createLocalPackage(path: Path(path), group: group.map { Path($0) })

if !excludeFromProject {
addObject(packageReference)
try sourceGenerator.createLocalPackage(path: Path(path), group: group.map { Path($0) })
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/XcodeGenKit/SchemeGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public class SchemeGenerator {
switch target.location {
case .package(let packageName):
guard let package = self.project.getPackage(packageName),
case let .local(path, _) = package else {
case let .local(path, _, _) = package else {
throw SchemeGenerationError.missingPackage(packageName)
}
return XCScheme.BuildableReference(
Expand Down
2 changes: 1 addition & 1 deletion Tests/ProjectSpecTests/ProjectSpecTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class ProjectSpecTests: XCTestCase {
project.settings = invalidSettings
project.configFiles = ["invalidConfig": "invalidConfigFile"]
project.fileGroups = ["invalidFileGroup"]
project.packages = ["invalidLocalPackage": .local(path: "invalidLocalPackage", group: nil)]
project.packages = ["invalidLocalPackage": .local(path: "invalidLocalPackage", group: nil, excludeFromProject: false)]
project.settingGroups = ["settingGroup1": Settings(
configSettings: ["invalidSettingGroupConfig": [:]],
groups: ["invalidSettingGroupSettingGroup"]
Expand Down
10 changes: 5 additions & 5 deletions Tests/ProjectSpecTests/SpecLoadingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1489,10 +1489,10 @@ class SpecLoadingTests: XCTestCase {
"package6": .remote(url: "package.git", versionRequirement: .range(from: "1.2.0", to: "1.2.5")),
"package7": .remote(url: "package.git", versionRequirement: .exact("1.2.2")),
"package8": .remote(url: "package.git", versionRequirement: .upToNextMajorVersion("4.0.0-beta.5")),
"package9": .local(path: "package/package", group: nil),
"package9": .local(path: "package/package", group: nil, excludeFromProject: false),
"package10": .remote(url: "https://github.com/yonaskolb/XcodeGen", versionRequirement: .exact("1.2.2")),
"XcodeGen": .local(path: "../XcodeGen", group: nil),
"package11": .local(path: "../XcodeGen", group: "Packages/Feature"),
"XcodeGen": .local(path: "../XcodeGen", group: nil, excludeFromProject: false),
"package11": .local(path: "../XcodeGen", group: "Packages/Feature", excludeFromProject: false),
], options: .init(localPackagesGroup: "MyPackages"))

let dictionary: [String: Any] = [
Expand Down Expand Up @@ -1521,8 +1521,8 @@ class SpecLoadingTests: XCTestCase {

$0.it("parses old local package format") {
let project = Project(name: "spm", packages: [
"XcodeGen": .local(path: "../XcodeGen", group: nil),
"Yams": .local(path: "Yams", group: nil),
"XcodeGen": .local(path: "../XcodeGen", group: nil, excludeFromProject: false),
"Yams": .local(path: "Yams", group: nil, excludeFromProject: false),
], options: .init(localPackagesGroup: "MyPackages"))

let dictionary: [String: Any] = [
Expand Down
6 changes: 3 additions & 3 deletions Tests/XcodeGenKitTests/PBXProjGeneratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -325,9 +325,9 @@ class PBXProjGeneratorTests: XCTestCase {
name: "Test",
targets: [target],
packages: [
"Common": .local(path: "Packages/Common", group: nil),
"FeatureA": .local(path: "Packages/FeatureA", group: nil),
"FeatureB": .local(path: "Packages/FeatureB", group: nil),
"Common": .local(path: "Packages/Common", group: nil, excludeFromProject: false),
"FeatureA": .local(path: "Packages/FeatureA", group: nil, excludeFromProject: false),
"FeatureB": .local(path: "Packages/FeatureB", group: nil, excludeFromProject: false),
],
options: options
)
Expand Down
56 changes: 49 additions & 7 deletions Tests/XcodeGenKitTests/ProjectGeneratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1548,7 +1548,7 @@ class ProjectGeneratorTests: XCTestCase {
let project = Project(name: "test", targets: [app], packages: [
"XcodeGen": .remote(url: "http://github.com/yonaskolb/XcodeGen", versionRequirement: .branch("master")),
"Codability": .remote(url: "http://github.com/yonaskolb/Codability", versionRequirement: .exact("1.0.0")),
"Yams": .local(path: "../Yams", group: nil),
"Yams": .local(path: "../Yams", group: nil, excludeFromProject: false),
], options: .init(localPackagesGroup: "MyPackages"))

let pbxProject = try project.generatePbxProj(specValidate: false)
Expand Down Expand Up @@ -1581,7 +1581,7 @@ class ProjectGeneratorTests: XCTestCase {
]
)

let project = Project(name: "test", targets: [app], packages: ["XcodeGen": .local(path: "../XcodeGen", group: nil)])
let project = Project(name: "test", targets: [app], packages: ["XcodeGen": .local(path: "../XcodeGen", group: nil, excludeFromProject: false)])

let pbxProject = try project.generatePbxProj(specValidate: false)
let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name }))
Expand All @@ -1604,7 +1604,49 @@ class ProjectGeneratorTests: XCTestCase {

try expect(file.product?.productName) == "XcodeGen"
}


$0.it("excludes local swift packages from generated project if needed") {
let app = Target(
name: "MyApp",
type: .application,
platform: .iOS,
dependencies: [
Dependency(type: .package(products: ["XcodeGen"]), reference: "XcodeGen"),
]
)

let project = Project(
name: "test",
targets: [app],
packages: [
"XcodeGen": .local(
path: "../XcodeGen",
group: nil,
excludeFromProject: true
)
]
)

let pbxProject = try project.generatePbxProj(specValidate: false)
let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name }))
let localPackageFile = pbxProject.fileReferences.first(where: { $0.path == "../XcodeGen" })

try expect(localPackageFile).to.beNil()
try expect(pbxProject.rootObject?.localPackages.count) == 0

let frameworkPhases = nativeTarget.buildPhases.compactMap { $0 as? PBXFrameworksBuildPhase }

guard let frameworkPhase = frameworkPhases.first else {
return XCTFail("frameworkPhases should have more than one")
}

guard let file = frameworkPhase.files?.first else {
return XCTFail("frameworkPhase should have file")
}

try expect(file.product?.productName) == "XcodeGen"
}

$0.it("generates local swift packages with custom xcode path") {
let app = Target(
name: "MyApp",
Expand All @@ -1616,7 +1658,7 @@ class ProjectGeneratorTests: XCTestCase {
)

let customLocalPackageGroup = "Packages/Feature"
let project = Project(name: "test", targets: [app], packages: ["XcodeGen": .local(path: "../XcodeGen", group: customLocalPackageGroup)])
let project = Project(name: "test", targets: [app], packages: ["XcodeGen": .local(path: "../XcodeGen", group: customLocalPackageGroup, excludeFromProject: false)])

let pbxProject = try project.generatePbxProj(specValidate: false)
let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name }))
Expand Down Expand Up @@ -1657,7 +1699,7 @@ class ProjectGeneratorTests: XCTestCase {
]
)

let project = Project(name: "test", targets: [app], packages: ["XcodeGen": .local(path: "../XcodeGen", group: "")])
let project = Project(name: "test", targets: [app], packages: ["XcodeGen": .local(path: "../XcodeGen", group: "", excludeFromProject: false)])

let pbxProject = try project.generatePbxProj(specValidate: false)
let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name }))
Expand Down Expand Up @@ -1691,7 +1733,7 @@ class ProjectGeneratorTests: XCTestCase {
]
)

let project = Project(name: "test", targets: [app], packages: ["XcodeGen": .local(path: "../XcodeGen", group: nil)], options: .init(localPackagesGroup: ""))
let project = Project(name: "test", targets: [app], packages: ["XcodeGen": .local(path: "../XcodeGen", group: nil, excludeFromProject: false)], options: .init(localPackagesGroup: ""))

let pbxProject = try project.generatePbxProj(specValidate: false)
let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name }))
Expand Down Expand Up @@ -1867,7 +1909,7 @@ class ProjectGeneratorTests: XCTestCase {
)

let project = Project(name: "test", targets: [app], packages: [
"FooFeature": .local(path: "../FooFeature", group: nil)
"FooFeature": .local(path: "../FooFeature", group: nil, excludeFromProject: false)
], options: .init(localPackagesGroup: "MyPackages"))

let pbxProject = try project.generatePbxProj(specValidate: false)
Expand Down
4 changes: 2 additions & 2 deletions Tests/XcodeGenKitTests/SchemeGeneratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ class SchemeGeneratorTests: XCTestCase {
name: "test",
targets: [framework],
schemes: [scheme],
packages: ["XcodeGen": .local(path: "../", group: nil)],
packages: ["XcodeGen": .local(path: "../", group: nil, excludeFromProject: false)],
projectReferences: [
ProjectReference(name: "TestProject", path: externalProject.string),
]
Expand Down Expand Up @@ -570,7 +570,7 @@ class SchemeGeneratorTests: XCTestCase {
let project = Project(
name: "ios_test",
targets: [app],
packages: ["XcodeGen": .local(path: "../", group: nil)]
packages: ["XcodeGen": .local(path: "../", group: nil, excludeFromProject: false)]
)
let xcodeProject = try project.generateXcodeProject()
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
Expand Down

0 comments on commit 434dfec

Please sign in to comment.