diff --git a/Docs/ProjectSpec.md b/Docs/ProjectSpec.md index d6e722ca..6faceb28 100644 --- a/Docs/ProjectSpec.md +++ b/Docs/ProjectSpec.md @@ -120,6 +120,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 invididual frameworks for Carthage dependencies will automatically be found. This property can be overriden 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` ```yaml options: diff --git a/Docs/Usage.md b/Docs/Usage.md index 31d4c646..546c12aa 100644 --- a/Docs/Usage.md +++ b/Docs/Usage.md @@ -185,6 +185,8 @@ localPackages: - ../../Yams - ~/Developer/MyPackage ``` +These local packages get put into a `Packages` group in the root of the project by default. This can be changed with `options.localPackagesGroup` + > For now local packages that don't mirror remote packages aren't able to be linked to ### SDK diff --git a/Sources/ProjectSpec/SpecOptions.swift b/Sources/ProjectSpec/SpecOptions.swift index fc55641e..1b2081b9 100644 --- a/Sources/ProjectSpec/SpecOptions.swift +++ b/Sources/ProjectSpec/SpecOptions.swift @@ -27,6 +27,7 @@ public struct SpecOptions: Equatable { public var groupSortPosition: GroupSortPosition public var generateEmptyDirectories: Bool public var findCarthageFrameworks: Bool + public var localPackagesGroup: String? public enum ValidationType: String { case missingConfigs @@ -82,7 +83,8 @@ public struct SpecOptions: Equatable { transitivelyLinkDependencies: Bool = transitivelyLinkDependenciesDefault, groupSortPosition: GroupSortPosition = groupSortPositionDefault, generateEmptyDirectories: Bool = generateEmptyDirectoriesDefault, - findCarthageFrameworks: Bool = findCarthageFrameworksDefault + findCarthageFrameworks: Bool = findCarthageFrameworksDefault, + localPackagesGroup: String? = nil ) { self.minimumXcodeGenVersion = minimumXcodeGenVersion self.carthageBuildPath = carthageBuildPath @@ -102,6 +104,7 @@ public struct SpecOptions: Equatable { self.groupSortPosition = groupSortPosition self.generateEmptyDirectories = generateEmptyDirectories self.findCarthageFrameworks = findCarthageFrameworks + self.localPackagesGroup = localPackagesGroup } } @@ -129,6 +132,7 @@ extension SpecOptions: JSONObjectConvertible { groupSortPosition = jsonDictionary.json(atKeyPath: "groupSortPosition") ?? SpecOptions.groupSortPositionDefault generateEmptyDirectories = jsonDictionary.json(atKeyPath: "generateEmptyDirectories") ?? SpecOptions.generateEmptyDirectoriesDefault findCarthageFrameworks = jsonDictionary.json(atKeyPath: "findCarthageFrameworks") ?? SpecOptions.findCarthageFrameworksDefault + localPackagesGroup = jsonDictionary.json(atKeyPath: "localPackagesGroup") } } @@ -149,6 +153,7 @@ extension SpecOptions: JSONEncodable { "indentWidth": indentWidth.flatMap { Int($0) }, "tabWidth": tabWidth.flatMap { Int($0) }, "defaultConfig": defaultConfig, + "localPackagesGroup": localPackagesGroup, ] if settingPresets != SpecOptions.settingPresetsDefault { diff --git a/Sources/XcodeGenKit/SourceGenerator.swift b/Sources/XcodeGenKit/SourceGenerator.swift index 5f9492d7..e00230e5 100644 --- a/Sources/XcodeGenKit/SourceGenerator.swift +++ b/Sources/XcodeGenKit/SourceGenerator.swift @@ -16,6 +16,7 @@ class SourceGenerator { private var fileReferencesByPath: [String: PBXFileElement] = [:] private var groupsByPath: [Path: PBXGroup] = [:] private var variantGroupsByPath: [Path: PBXVariantGroup] = [:] + private var localPackageGroup: PBXGroup? private let project: Project let pbxProj: PBXProj @@ -42,15 +43,22 @@ class SourceGenerator { } func createLocalPackage(path: Path) throws { + + + if localPackageGroup == nil { + let groupName = project.options.localPackagesGroup ?? "Packages" + localPackageGroup = addObject(PBXGroup(sourceTree: .sourceRoot, name: groupName)) + rootGroups.insert(localPackageGroup!) + } let fileReference = addObject( PBXFileReference( - sourceTree: .group, + sourceTree: .sourceRoot, name: path.lastComponent, lastKnownFileType: "folder", path: try path.relativePath(from: project.basePath).string ) ) - rootGroups.insert(fileReference) + localPackageGroup!.children.append(fileReference) } func getAllSourceFiles(targetType: PBXProductType, sources: [TargetSource]) throws -> [SourceFile] { diff --git a/Tests/Fixtures/SPM/SPM.xcodeproj/project.pbxproj b/Tests/Fixtures/SPM/SPM.xcodeproj/project.pbxproj index c5c0992c..dd33053a 100644 --- a/Tests/Fixtures/SPM/SPM.xcodeproj/project.pbxproj +++ b/Tests/Fixtures/SPM/SPM.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 2DA7998902987953B119E4CE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26F7EFEE613987D1E1258A60 /* AppDelegate.swift */; }; + 578E78BC3627CF48FB2CE129 /* App.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = A9601593D0AD02931266A4E5 /* App.xctestplan */; }; 78E2E1F9F271C0C4CDA04BD9 /* StaticLibrary.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F7AFEF8ECCC678519EA643C /* StaticLibrary.a */; }; 9C4AD0711D706FD3ED0E436D /* StaticLibrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C17B77601A9D1B7895AB42 /* StaticLibrary.swift */; }; CE46CBA5671B951B546C8673 /* Codability in Frameworks */ = {isa = PBXBuildFile; productRef = 16E6FE01D5BD99F78D4A17E2 /* Codability */; }; @@ -31,7 +32,8 @@ 464ACF8D8F2D9F219BCFD3E7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4E22B8BCC18A29EFE1DE3BE4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 61C17B77601A9D1B7895AB42 /* StaticLibrary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticLibrary.swift; sourceTree = ""; }; - EA6A9C2D515205854C4FC36F /* XcodeGen */ = {isa = PBXFileReference; lastKnownFileType = folder; name = XcodeGen; path = ../../..; sourceTree = ""; }; + A9601593D0AD02931266A4E5 /* App.xctestplan */ = {isa = PBXFileReference; path = App.xctestplan; sourceTree = ""; }; + C1DE9A872F470EAA65B9B0B0 /* XcodeGen */ = {isa = PBXFileReference; lastKnownFileType = folder; name = XcodeGen; path = ../../..; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -50,6 +52,7 @@ 17DD374CC81D710476AFF41C /* SPM */ = { isa = PBXGroup; children = ( + A9601593D0AD02931266A4E5 /* App.xctestplan */, 26F7EFEE613987D1E1258A60 /* AppDelegate.swift */, 4E22B8BCC18A29EFE1DE3BE4 /* Assets.xcassets */, 464ACF8D8F2D9F219BCFD3E7 /* Info.plist */, @@ -68,7 +71,7 @@ 218F6C96DF9E182F526258CF = { isa = PBXGroup; children = ( - EA6A9C2D515205854C4FC36F /* XcodeGen */, + AD0F3623091EEA8D1EA3DFF8 /* Packages */, 17DD374CC81D710476AFF41C /* SPM */, 1FA59BFD192FB5A68D5F587C /* StaticLibrary */, 5D68FDDE55EE935627A1B376 /* Products */, @@ -84,6 +87,14 @@ name = Products; sourceTree = ""; }; + AD0F3623091EEA8D1EA3DFF8 /* Packages */ = { + isa = PBXGroup; + children = ( + C1DE9A872F470EAA65B9B0B0 /* XcodeGen */, + ); + name = Packages; + sourceTree = SOURCE_ROOT; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -162,6 +173,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 578E78BC3627CF48FB2CE129 /* App.xctestplan in Resources */, E368431019ABC696E4FFC0CF /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Tests/Fixtures/SPM/SPM/App.xctestplan b/Tests/Fixtures/SPM/SPM/App.xctestplan new file mode 100644 index 00000000..0a76fad8 --- /dev/null +++ b/Tests/Fixtures/SPM/SPM/App.xctestplan @@ -0,0 +1,23 @@ +{ + "configurations" : [ + { + "id" : "521B6958-2D62-4961-B353-91EF8F252F4B", + "name" : "Configuration 1", + "options" : { + + } + } + ], + "defaultOptions" : { + "codeCoverage" : false, + "targetForVariableExpansion" : { + "containerPath" : "container:SPM.xcodeproj", + "identifier" : "C99E3C420D63D5219CE57E33", + "name" : "App" + } + }, + "testTargets" : [ + + ], + "version" : 1 +} diff --git a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift index 4c22621a..266e1b42 100644 --- a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift @@ -921,7 +921,7 @@ class ProjectGeneratorTests: XCTestCase { let project = Project(name: "test", targets: [app], packages: [ "XcodeGen": SwiftPackage(url: "http://github.com/yonaskolb/XcodeGen", versionRequirement: .branch("master")), "Codability": SwiftPackage(url: "http://github.com/yonaskolb/Codability", versionRequirement: .exact("1.0.0")), - ], localPackages: ["../XcodeGen"]) + ], localPackages: ["../XcodeGen"], options: .init(localPackagesGroup: "MyPackages")) let pbxProject = try project.generatePbxProj(specValidate: false) guard let nativeTarget = pbxProject.nativeTargets.first(where: { $0.name == app.name }) else { @@ -942,10 +942,15 @@ class ProjectGeneratorTests: XCTestCase { try expect(codabilityDependency.package?.name) == "Codability" try expect(codabilityDependency.package?.versionRequirement) == .exact("1.0.0") + guard let localPackagesGroup = try pbxProject.getMainGroup().children.first(where: { $0.name == "MyPackages" }) as? PBXGroup else { + throw failure("Group not found") + } + guard let localPackageFile = pbxProject.fileReferences.first(where: { $0.path == "../XcodeGen" }) else { throw failure("FileReference not found") } + try expect(localPackagesGroup.children.contains(localPackageFile)) == true try expect(localPackageFile.lastKnownFileType) == "folder" } diff --git a/Tests/XcodeGenKitTests/SpecLoadingTests.swift b/Tests/XcodeGenKitTests/SpecLoadingTests.swift index 556d9dd7..4fa2f6e4 100644 --- a/Tests/XcodeGenKitTests/SpecLoadingTests.swift +++ b/Tests/XcodeGenKitTests/SpecLoadingTests.swift @@ -970,10 +970,14 @@ class SpecLoadingTests: XCTestCase { "package5": SwiftPackage(url: "package.git", versionRequirement: .revision("x")), "package6": SwiftPackage(url: "package.git", versionRequirement: .range(from: "1.2.0", to: "1.2.5")), ], - localPackages: ["../../Package"]) + localPackages: ["../../Package"], + options: .init(localPackagesGroup: "MyPackages")) let dictionary: [String: Any] = [ "name": "spm", + "options": [ + "localPackagesGroup": "MyPackages" + ], "packages": [ "package1": ["url": "package.git", "exactVersion": "1.2.2"], "package2": ["url": "package.git", "majorVersion": "1.2.2"],