Enable adding local Swift packages to the project root

This commit is contained in:
Hilton Campbell 2023-11-06 11:04:00 -08:00
parent 87a275fb08
commit eab3e3bc67
3 changed files with 93 additions and 16 deletions

View File

@ -147,7 +147,7 @@ Note that target names can also be changed by adding a `name` property to a targ
- [ ] **transitivelyLinkDependencies**: **Bool** - If this is `true` then targets will link to the dependencies of their target dependencies. If a target should embed its dependencies, such as application and test bundles, it will embed these transitive dependencies as well. Some complex setups might want to set this to `false` and explicitly specify dependencies at every level. Targets can override this with [Target](#target).transitivelyLinkDependencies. Defaults to `false`.
- [ ] **generateEmptyDirectories**: **Bool** - If this is `true` then empty directories will be added to project too else will be missed. Defaults to `false`.
- [ ] **findCarthageFrameworks**: **Bool** - When this is set to `true`, all the individual frameworks for Carthage framework dependencies will automatically be found. This property can be overridden individually for each carthage dependency - for more details see See **findFrameworks** in the [Dependency](#dependency) section. Defaults to `false`.
- [ ] **localPackagesGroup**: **String** - The group name that local packages are put into. This defaults to `Packages`
- [ ] **localPackagesGroup**: **String** - The group name that local packages are put into. This defaults to `Packages`. Use `""` to specify the project root.
- [ ] **fileTypes**: **[String: [FileType](#filetype)]** - A list of default file options for specific file extensions across the project. Values in [Sources](#sources) will overwrite these settings.
- [ ] **preGenCommand**: **String** - A bash command to run before 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 generating resources files before the project is regenerated.
- [ ] **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.
@ -1240,7 +1240,7 @@ Swift packages are defined at a project level, and then linked to individual tar
### Local Package
- [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.
- [ ] **group** : **String**- Optional path that specifies the location where the package will live in your xcode project. Use `""` to specify the project root.
```yml
packages:

View File

@ -54,21 +54,8 @@ class SourceGenerator {
}
func createLocalPackage(path: Path, group: Path?) throws {
var pbxGroup: PBXGroup?
if let location = group {
let fullLocationPath = project.basePath + location
pbxGroup = getGroup(path: fullLocationPath, mergingChildren: [], createIntermediateGroups: true, hasCustomParent: false, isBaseGroup: true)
}
if localPackageGroup == nil && group == nil {
let groupName = project.options.localPackagesGroup ?? "Packages"
localPackageGroup = addObject(PBXGroup(sourceTree: .sourceRoot, name: groupName))
rootGroups.insert(localPackageGroup!)
}
let absolutePath = project.basePath + path.normalize()
// Get the local package's relative path from the project root
let fileReferencePath = try? absolutePath.relativePath(from: projectDirectory ?? project.basePath).string
@ -80,6 +67,28 @@ class SourceGenerator {
path: fileReferencePath
)
)
var pbxGroup: PBXGroup?
if let location = group {
if location == "" {
pbxGroup = pbxProj.rootObject?.mainGroup
rootGroups.insert(fileReference)
} else {
let fullLocationPath = project.basePath + location
pbxGroup = getGroup(path: fullLocationPath, mergingChildren: [], createIntermediateGroups: true, hasCustomParent: false, isBaseGroup: true)
}
} else if localPackageGroup == nil {
let groupName = project.options.localPackagesGroup ?? "Packages"
if groupName == "" {
pbxGroup = pbxProj.rootObject?.mainGroup
rootGroups.insert(fileReference)
} else {
localPackageGroup = addObject(PBXGroup(sourceTree: .sourceRoot, name: groupName))
rootGroups.insert(localPackageGroup!)
}
}
if let pbxGroup = pbxGroup {
pbxGroup.children.append(fileReference)
} else {

View File

@ -1604,6 +1604,74 @@ class ProjectGeneratorTests: XCTestCase {
try expect(file.product?.productName) == "XcodeGen"
}
$0.it("generates local swift packages at the top level") {
let app = Target(
name: "MyApp",
type: .application,
platform: .iOS,
dependencies: [
Dependency(type: .package(products: []), reference: "XcodeGen"),
]
)
let project = Project(name: "test", targets: [app], packages: ["XcodeGen": .local(path: "../XcodeGen", group: "")])
let pbxProject = try project.generatePbxProj(specValidate: false)
let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name }))
let localPackageFile = try unwrap(pbxProject.fileReferences.first(where: { $0.path == "../XcodeGen" }))
try expect(localPackageFile.lastKnownFileType) == "folder"
let mainGroup = try pbxProject.getMainGroup()
try expect(mainGroup.children.contains(localPackageFile)) == true
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 package group at the top level") {
let app = Target(
name: "MyApp",
type: .application,
platform: .iOS,
dependencies: [
Dependency(type: .package(products: []), reference: "XcodeGen"),
]
)
let project = Project(name: "test", targets: [app], packages: ["XcodeGen": .local(path: "../XcodeGen", group: nil)], options: .init(localPackagesGroup: ""))
let pbxProject = try project.generatePbxProj(specValidate: false)
let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name }))
let localPackageFile = try unwrap(pbxProject.fileReferences.first(where: { $0.path == "../XcodeGen" }))
try expect(localPackageFile.lastKnownFileType) == "folder"
let mainGroup = try pbxProject.getMainGroup()
try expect(mainGroup.children.contains(localPackageFile)) == true
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 info.plist") {
let plist = Plist(path: "Info.plist", attributes: ["UISupportedInterfaceOrientations": ["UIInterfaceOrientationPortrait", "UIInterfaceOrientationLandscapeLeft"]])
let tempPath = Path.temporary + "info"