mirror of
https://github.com/yonaskolb/XcodeGen.git
synced 2026-03-18 20:02:25 +00:00
Added ability to use custom location for local Swift packages (#1175)
* Added xcodePath functionality * Added xcodePath functionality * Renamed Xcode path to group * Updated change log and added fixture tests
This commit is contained in:
@@ -2,6 +2,9 @@
|
||||
|
||||
## Next Version
|
||||
|
||||
#### Added
|
||||
- Support for specifying custom group locations for SPM packages. [#1173](https://github.com/yonaskolb/XcodeGen/issues/1173) @John-Connolly
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix Monterey macOS shell version, shell login flag for environments [#1167](https://github.com/yonaskolb/XcodeGen/issues/1167) @bimawa
|
||||
|
||||
@@ -993,6 +993,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.
|
||||
|
||||
```yml
|
||||
packages:
|
||||
@@ -1004,6 +1005,9 @@ packages:
|
||||
from: 0.5.0
|
||||
RxClient:
|
||||
path: ../RxClient
|
||||
AppFeature:
|
||||
path: ../Packages
|
||||
group: Domains/AppFeature
|
||||
```
|
||||
|
||||
## Project Reference
|
||||
|
||||
@@ -193,7 +193,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)
|
||||
$0[packageName] = .local(path: $1, group: nil)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -54,7 +54,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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ public enum SwiftPackage: Equatable {
|
||||
static let githubPrefix = "https://github.com/"
|
||||
|
||||
case remote(url: String, versionRequirement: VersionRequirement)
|
||||
case local(path: String)
|
||||
case local(path: String, group: String?)
|
||||
|
||||
public var isLocal: Bool {
|
||||
if case .local = self {
|
||||
@@ -23,8 +23,10 @@ public enum SwiftPackage: Equatable {
|
||||
extension SwiftPackage: JSONObjectConvertible {
|
||||
|
||||
public init(jsonDictionary: JSONDictionary) throws {
|
||||
if let path: String = jsonDictionary.json(atKeyPath: "path") {
|
||||
self = .local(path: path)
|
||||
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)
|
||||
} else {
|
||||
let versionRequirement: VersionRequirement = try VersionRequirement(jsonDictionary: jsonDictionary)
|
||||
try Self.validateVersion(versionRequirement: versionRequirement)
|
||||
@@ -90,8 +92,9 @@ extension SwiftPackage: JSONEncodable {
|
||||
dictionary["revision"] = revision
|
||||
}
|
||||
return dictionary
|
||||
case .local(let path):
|
||||
case let .local(path, group):
|
||||
dictionary["path"] = path
|
||||
dictionary["group"] = group
|
||||
}
|
||||
|
||||
return dictionary
|
||||
|
||||
@@ -28,9 +28,9 @@ class ProjectCommand: Command {
|
||||
}
|
||||
|
||||
func execute() throws {
|
||||
|
||||
|
||||
let projectSpecPath = (spec ?? "project.yml").absolute()
|
||||
|
||||
|
||||
if !projectSpecPath.exists {
|
||||
throw GenerationError.missingProjectSpec(projectSpecPath)
|
||||
}
|
||||
|
||||
@@ -168,8 +168,8 @@ public class PBXProjGenerator {
|
||||
let packageReference = XCRemoteSwiftPackageReference(repositoryURL: url, versionRequirement: versionRequirement)
|
||||
packageReferences[name] = packageReference
|
||||
addObject(packageReference)
|
||||
case let .local(path):
|
||||
try sourceGenerator.createLocalPackage(path: Path(path))
|
||||
case let .local(path, group):
|
||||
try sourceGenerator.createLocalPackage(path: Path(path), group: group.map { Path($0) })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ public class SchemeGenerator {
|
||||
switch target.location {
|
||||
case .package(let packageName):
|
||||
guard let package = self.project.getPackage(packageName),
|
||||
case .local(let path) = package else {
|
||||
case let .local(path, _) = package else {
|
||||
throw SchemeGenerationError.missingPackage(packageName)
|
||||
}
|
||||
return XCScheme.BuildableReference(
|
||||
|
||||
@@ -53,16 +53,22 @@ class SourceGenerator {
|
||||
return object
|
||||
}
|
||||
|
||||
func createLocalPackage(path: Path) throws {
|
||||
|
||||
if localPackageGroup == nil {
|
||||
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
|
||||
|
||||
@@ -74,7 +80,11 @@ class SourceGenerator {
|
||||
path: fileReferencePath
|
||||
)
|
||||
)
|
||||
localPackageGroup!.children.append(fileReference)
|
||||
if let pbxGroup = pbxGroup {
|
||||
pbxGroup.children.append(fileReference)
|
||||
} else {
|
||||
localPackageGroup!.children.append(fileReference)
|
||||
}
|
||||
}
|
||||
|
||||
/// Collects an array complete of all `SourceFile` objects that make up the target based on the provided `TargetSource` definitions.
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
23C6626698DE560017A89F2F /* XcodeGen in Frameworks */ = {isa = PBXBuildFile; productRef = 6F7DEA2D82649EDF903FBDBD /* XcodeGen */; };
|
||||
2DA7998902987953B119E4CE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26F7EFEE613987D1E1258A60 /* AppDelegate.swift */; };
|
||||
3986ED6965842721C46C0452 /* SwiftRoaringDynamic in Frameworks */ = {isa = PBXBuildFile; productRef = DC73B269C8B0C0BF6912842C /* SwiftRoaringDynamic */; };
|
||||
4CC663B42B270404EF5FD037 /* libStaticLibrary.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CAB5625F6FEA668410ED5482 /* libStaticLibrary.a */; };
|
||||
@@ -58,8 +59,8 @@
|
||||
61C17B77601A9D1B7895AB42 /* StaticLibrary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticLibrary.swift; sourceTree = "<group>"; };
|
||||
7970A2253B14A9B27C307FAC /* SPMTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPMTests.swift; sourceTree = "<group>"; };
|
||||
A9601593D0AD02931266A4E5 /* App.xctestplan */ = {isa = PBXFileReference; path = App.xctestplan; sourceTree = "<group>"; };
|
||||
C1DE9A872F470EAA65B9B0B0 /* XcodeGen */ = {isa = PBXFileReference; lastKnownFileType = folder; name = XcodeGen; path = ../../..; sourceTree = SOURCE_ROOT; };
|
||||
CAB5625F6FEA668410ED5482 /* libStaticLibrary.a */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = archive.ar; path = libStaticLibrary.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
ED284AB7C13DCC0A95DAA680 /* XcodeGen */ = {isa = PBXFileReference; lastKnownFileType = folder; name = XcodeGen; path = ../../..; sourceTree = SOURCE_ROOT; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -70,6 +71,7 @@
|
||||
CE46CBA5671B951B546C8673 /* Codability in Frameworks */,
|
||||
3986ED6965842721C46C0452 /* SwiftRoaringDynamic in Frameworks */,
|
||||
4CC663B42B270404EF5FD037 /* libStaticLibrary.a in Frameworks */,
|
||||
23C6626698DE560017A89F2F /* XcodeGen in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -83,6 +85,7 @@
|
||||
26F7EFEE613987D1E1258A60 /* AppDelegate.swift */,
|
||||
4E22B8BCC18A29EFE1DE3BE4 /* Assets.xcassets */,
|
||||
464ACF8D8F2D9F219BCFD3E7 /* Info.plist */,
|
||||
ED284AB7C13DCC0A95DAA680 /* XcodeGen */,
|
||||
);
|
||||
path = SPM;
|
||||
sourceTree = "<group>";
|
||||
@@ -98,7 +101,6 @@
|
||||
218F6C96DF9E182F526258CF = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AD0F3623091EEA8D1EA3DFF8 /* Packages */,
|
||||
17DD374CC81D710476AFF41C /* SPM */,
|
||||
CF3BD77AEAA56553289456BA /* SPMTests */,
|
||||
1FA59BFD192FB5A68D5F587C /* StaticLibrary */,
|
||||
@@ -116,14 +118,6 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
AD0F3623091EEA8D1EA3DFF8 /* Packages */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C1DE9A872F470EAA65B9B0B0 /* XcodeGen */,
|
||||
);
|
||||
name = Packages;
|
||||
sourceTree = SOURCE_ROOT;
|
||||
};
|
||||
CF3BD77AEAA56553289456BA /* SPMTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -193,6 +187,7 @@
|
||||
packageProductDependencies = (
|
||||
16E6FE01D5BD99F78D4A17E2 /* Codability */,
|
||||
DC73B269C8B0C0BF6912842C /* SwiftRoaringDynamic */,
|
||||
6F7DEA2D82649EDF903FBDBD /* XcodeGen */,
|
||||
);
|
||||
productName = App;
|
||||
productReference = 097F2DB5622B591E21BC3C73 /* App.app */;
|
||||
@@ -596,6 +591,10 @@
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = XcodeGen;
|
||||
};
|
||||
6F7DEA2D82649EDF903FBDBD /* XcodeGen */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = XcodeGen;
|
||||
};
|
||||
AF233B61592982A7F6431FC6 /* Codability */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 5BA91390AE78D2EE15C60091 /* XCRemoteSwiftPackageReference "Codability" */;
|
||||
|
||||
@@ -8,6 +8,7 @@ packages:
|
||||
majorVersion: 1.0.4
|
||||
XcodeGen:
|
||||
path: ../../.. #XcodeGen itself
|
||||
group: SPM
|
||||
targets:
|
||||
App:
|
||||
type: application
|
||||
@@ -24,6 +25,7 @@ targets:
|
||||
product: SwiftRoaringDynamic
|
||||
embed: true
|
||||
- target: StaticLibrary
|
||||
- package: XcodeGen
|
||||
Tests:
|
||||
type: bundle.unit-test
|
||||
platform: iOS
|
||||
|
||||
@@ -126,7 +126,7 @@ class ProjectSpecTests: XCTestCase {
|
||||
project.settings = invalidSettings
|
||||
project.configFiles = ["invalidConfig": "invalidConfigFile"]
|
||||
project.fileGroups = ["invalidFileGroup"]
|
||||
project.packages = ["invalidLocalPackage": .local(path: "invalidLocalPackage")]
|
||||
project.packages = ["invalidLocalPackage": .local(path: "invalidLocalPackage", group: nil)]
|
||||
project.settingGroups = ["settingGroup1": Settings(
|
||||
configSettings: ["invalidSettingGroupConfig": [:]],
|
||||
groups: ["invalidSettingGroupSettingGroup"]
|
||||
|
||||
@@ -1227,9 +1227,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"),
|
||||
"package9": .local(path: "package/package", group: nil),
|
||||
"package10": .remote(url: "https://github.com/yonaskolb/XcodeGen", versionRequirement: .exact("1.2.2")),
|
||||
"XcodeGen": .local(path: "../XcodeGen"),
|
||||
"XcodeGen": .local(path: "../XcodeGen", group: nil),
|
||||
"package11": .local(path: "../XcodeGen", group: "Packages/Feature"),
|
||||
], options: .init(localPackagesGroup: "MyPackages"))
|
||||
|
||||
let dictionary: [String: Any] = [
|
||||
@@ -1248,6 +1249,7 @@ class SpecLoadingTests: XCTestCase {
|
||||
"package8": ["url": "package.git", "majorVersion": "4.0.0-beta.5"],
|
||||
"package9": ["path": "package/package"],
|
||||
"package10": ["github": "yonaskolb/XcodeGen", "exactVersion": "1.2.2"],
|
||||
"package11": ["path": "../XcodeGen", "group": "Packages/Feature"],
|
||||
],
|
||||
"localPackages": ["../XcodeGen"],
|
||||
]
|
||||
@@ -1257,8 +1259,8 @@ class SpecLoadingTests: XCTestCase {
|
||||
|
||||
$0.it("parses old local package format") {
|
||||
let project = Project(name: "spm", packages: [
|
||||
"XcodeGen": .local(path: "../XcodeGen"),
|
||||
"Yams": .local(path: "Yams"),
|
||||
"XcodeGen": .local(path: "../XcodeGen", group: nil),
|
||||
"Yams": .local(path: "Yams", group: nil),
|
||||
], options: .init(localPackagesGroup: "MyPackages"))
|
||||
|
||||
let dictionary: [String: Any] = [
|
||||
|
||||
@@ -1271,7 +1271,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"),
|
||||
"Yams": .local(path: "../Yams", group: nil),
|
||||
], options: .init(localPackagesGroup: "MyPackages"))
|
||||
|
||||
let pbxProject = try project.generatePbxProj(specValidate: false)
|
||||
@@ -1304,7 +1304,38 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
]
|
||||
)
|
||||
|
||||
let project = Project(name: "test", targets: [app], packages: ["XcodeGen": .local(path: "../XcodeGen")])
|
||||
let project = Project(name: "test", targets: [app], packages: ["XcodeGen": .local(path: "../XcodeGen", group: nil)])
|
||||
|
||||
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 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",
|
||||
type: .application,
|
||||
platform: .iOS,
|
||||
dependencies: [
|
||||
Dependency(type: .package(product: nil), reference: "XcodeGen"),
|
||||
]
|
||||
)
|
||||
|
||||
let project = Project(name: "test", targets: [app], packages: ["XcodeGen": .local(path: "../XcodeGen", group: "Packages/Feature")])
|
||||
|
||||
let pbxProject = try project.generatePbxProj(specValidate: false)
|
||||
let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name }))
|
||||
|
||||
@@ -404,7 +404,7 @@ class SchemeGeneratorTests: XCTestCase {
|
||||
name: "test",
|
||||
targets: [framework],
|
||||
schemes: [scheme],
|
||||
packages: ["XcodeGen": .local(path: "../")],
|
||||
packages: ["XcodeGen": .local(path: "../", group: nil)],
|
||||
projectReferences: [
|
||||
ProjectReference(name: "TestProject", path: externalProject.string),
|
||||
]
|
||||
@@ -493,7 +493,7 @@ class SchemeGeneratorTests: XCTestCase {
|
||||
let project = Project(
|
||||
name: "ios_test",
|
||||
targets: [app],
|
||||
packages: ["XcodeGen": .local(path: "../")]
|
||||
packages: ["XcodeGen": .local(path: "../", group: nil)]
|
||||
)
|
||||
let xcodeProject = try project.generateXcodeProject()
|
||||
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
|
||||
|
||||
Reference in New Issue
Block a user