diff --git a/CHANGELOG.md b/CHANGELOG.md index 6740687f..d408ce4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,9 +3,9 @@ ## Next Version #### Added - - Added ability to encode ProjectSpec to JSON [#545](https://github.com/yonaskolb/XcodeGen/pull/545) @ryohey - Added ability to skip tests [#582](https://github.com/yonaskolb/XcodeGen/pull/582) @kadarandras +- Added ability to set `attributes` on build files [#583](https://github.com/yonaskolb/XcodeGen/pull/583) @min #### Fixed - Fixed `.pch` files being bundled as resources [#597](https://github.com/yonaskolb/XcodeGen/pull/597) @thii diff --git a/Docs/ProjectSpec.md b/Docs/ProjectSpec.md index de79d1c4..1fc9e6e1 100644 --- a/Docs/ProjectSpec.md +++ b/Docs/ProjectSpec.md @@ -326,6 +326,7 @@ A source can be provided via a string (the path) or an object of the form: - `public` - `private` - `project` +- [ ] **attributes**: **[String]** - Additional settings attributes that will be applied to any build files. ```yaml targets: diff --git a/Sources/ProjectSpec/TargetSource.swift b/Sources/ProjectSpec/TargetSource.swift index e21dbe78..8e88bb1d 100644 --- a/Sources/ProjectSpec/TargetSource.swift +++ b/Sources/ProjectSpec/TargetSource.swift @@ -15,6 +15,7 @@ public struct TargetSource: Equatable { public var buildPhase: BuildPhase? public var headerVisibility: HeaderVisibility? public var createIntermediateGroups: Bool? + public var attributes: [String] public enum HeaderVisibility: String { case `public` @@ -127,7 +128,8 @@ public struct TargetSource: Equatable { optional: Bool = optionalDefault, buildPhase: BuildPhase? = nil, headerVisibility: HeaderVisibility? = nil, - createIntermediateGroups: Bool? = nil + createIntermediateGroups: Bool? = nil, + attributes: [String] = [] ) { self.path = path self.name = name @@ -138,6 +140,7 @@ public struct TargetSource: Equatable { self.buildPhase = buildPhase self.headerVisibility = headerVisibility self.createIntermediateGroups = createIntermediateGroups + self.attributes = attributes } } @@ -179,6 +182,7 @@ extension TargetSource: JSONObjectConvertible { } createIntermediateGroups = jsonDictionary.json(atKeyPath: "createIntermediateGroups") + attributes = jsonDictionary.json(atKeyPath: "attributes") ?? [] } } diff --git a/Sources/XcodeGenKit/SourceGenerator.swift b/Sources/XcodeGenKit/SourceGenerator.swift index 4ed48631..2b8407a8 100644 --- a/Sources/XcodeGenKit/SourceGenerator.swift +++ b/Sources/XcodeGenKit/SourceGenerator.swift @@ -51,6 +51,7 @@ class SourceGenerator { func generateSourceFile(targetType: PBXProductType, targetSource: TargetSource, path: Path, buildPhase: TargetSource.BuildPhase? = nil) -> SourceFile { let fileReference = fileReferencesByPath[path.string.lowercased()]! var settings: [String: Any] = [:] + var attributes: [String] = targetSource.attributes var chosenBuildPhase: TargetSource.BuildPhase? let headerVisibility = targetSource.headerVisibility ?? .public @@ -80,13 +81,17 @@ class SourceGenerator { if chosenBuildPhase == .headers { if headerVisibility != .project { // Xcode doesn't write the default of project - settings["ATTRIBUTES"] = [headerVisibility.settingName] + attributes.append(headerVisibility.settingName) } } if chosenBuildPhase == .sources && targetSource.compilerFlags.count > 0 { settings["COMPILER_FLAGS"] = targetSource.compilerFlags.joined(separator: " ") } + if !attributes.isEmpty { + settings["ATTRIBUTES"] = attributes + } + let buildFile = PBXBuildFile(file: fileReference, settings: settings.isEmpty ? nil : settings) return SourceFile( path: path, diff --git a/Tests/XcodeGenKitTests/SourceGeneratorTests.swift b/Tests/XcodeGenKitTests/SourceGeneratorTests.swift index 0e718f75..6aa9e668 100644 --- a/Tests/XcodeGenKitTests/SourceGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/SourceGeneratorTests.swift @@ -644,6 +644,38 @@ class SourceGeneratorTests: XCTestCase { try pbxProj.expectFile(paths: ["../OtherDirectory", "Outside", "a.swift"], names: ["OtherDirectory", "Outside", "a.swift"], buildPhase: .sources) try pbxProj.expectFile(paths: ["../OtherDirectory", "Outside", "Outside2", "b.swift"], names: ["OtherDirectory", "Outside", "Outside2", "b.swift"], buildPhase: .sources) } + + $0.it("correctly adds target source attributes") { + let directories = """ + A: + - Intent.intentdefinition + """ + try createDirectories(directories) + + let definition: String = "Intent.intentdefinition" + + let target = Target(name: "Test", type: .framework, platform: .iOS, sources: [ + TargetSource(path: "A/\(definition)", buildPhase: .sources, attributes: ["no_codegen"]) + ]) + let project = Project(basePath: directoryPath, name: "Test", targets: [target]) + + let pbxProj = try project.generatePbxProj() + + let fileReference = pbxProj.getFileReference( + paths: ["A", definition], + names: ["A", definition] + ) + guard let buildFile = pbxProj.buildFiles + .first(where: { $0.file == fileReference }) else { + throw failure("Cant find build file") + } + + try pbxProj.expectFile(paths: ["A", definition], buildPhase: .sources) + + if (buildFile.settings! as NSDictionary) != (["ATTRIBUTES": ["no_codegen"]] as NSDictionary) { + throw failure("File does not contain no_codegen attribute") + } + } } } }