From 20f7797df77c07d188d7f94eabe500e9a0925aaf Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Sun, 22 Oct 2017 19:24:14 +0100 Subject: [PATCH 01/21] add applySettingPresets option --- Sources/ProjectSpec/ProjectSpec.swift | 23 +++++++++++++++++++ Sources/XcodeGenKit/SettingsBuilder.swift | 12 ++++++---- .../ProjectGeneratorTests.swift | 10 ++++++++ docs/ProjectSpec.md | 8 +++++-- 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/Sources/ProjectSpec/ProjectSpec.swift b/Sources/ProjectSpec/ProjectSpec.swift index a5d17731..e086b503 100644 --- a/Sources/ProjectSpec/ProjectSpec.swift +++ b/Sources/ProjectSpec/ProjectSpec.swift @@ -29,6 +29,28 @@ public struct ProjectSpec { public struct Options { public var carthageBuildPath: String? public var bundleIdPrefix: String? + public var applySettingPresets: SettingPresets = .all + + public enum SettingPresets: String { + case all + case none + case project + case targets + + public var applyTarget: Bool { + switch self { + case .all, .targets: return true + default: return false + } + } + + public var applyProject: Bool { + switch self { + case .all, .project: return true + default: return false + } + } + } public init() { } @@ -133,5 +155,6 @@ extension ProjectSpec.Options: JSONObjectConvertible { public init(jsonDictionary: JSONDictionary) throws { carthageBuildPath = jsonDictionary.json(atKeyPath: "carthageBuildPath") bundleIdPrefix = jsonDictionary.json(atKeyPath: "bundleIdPrefix") + applySettingPresets = jsonDictionary.json(atKeyPath: "applySettingPresets") ?? .all } } diff --git a/Sources/XcodeGenKit/SettingsBuilder.swift b/Sources/XcodeGenKit/SettingsBuilder.swift index 6c81e28c..e8257ce1 100644 --- a/Sources/XcodeGenKit/SettingsBuilder.swift +++ b/Sources/XcodeGenKit/SettingsBuilder.swift @@ -18,7 +18,7 @@ extension ProjectSpec { public func getProjectBuildSettings(config: Config) -> BuildSettings { var buildSettings: BuildSettings = [:] - if let type = config.type { + if let type = config.type, options.applySettingPresets.applyProject { buildSettings += SettingsPresetFile.base.getBuildSettings() buildSettings += SettingsPresetFile.config(type).getBuildSettings() } @@ -30,10 +30,12 @@ extension ProjectSpec { public func getTargetBuildSettings(target: Target, config: Config) -> BuildSettings { var buildSettings = BuildSettings() - - buildSettings += SettingsPresetFile.platform(target.platform).getBuildSettings() - buildSettings += SettingsPresetFile.product(target.type).getBuildSettings() - buildSettings += SettingsPresetFile.productPlatform(target.type, target.platform).getBuildSettings() + + if options.applySettingPresets.applyTarget { + buildSettings += SettingsPresetFile.platform(target.platform).getBuildSettings() + buildSettings += SettingsPresetFile.product(target.type).getBuildSettings() + buildSettings += SettingsPresetFile.productPlatform(target.type, target.platform).getBuildSettings() + } buildSettings += getBuildSettings(settings: target.settings, config: config) return buildSettings diff --git a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift index 6fb551a8..b1020607 100644 --- a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift @@ -41,6 +41,16 @@ func projectGeneratorTests() { } try expect(buildConfig.buildSettings["PRODUCT_BUNDLE_IDENTIFIER"] as? String) == "com.test.MyFramework" } + + $0.it("clears setting presets") { + var options = ProjectSpec.Options() + options.applySettingPresets = .none + let spec = ProjectSpec(name: "test", targets: [framework], options: options) + let project = try getProject(spec) + let allSettings = project.pbxproj.buildConfigurations.reduce([:]) { $0.merged($1.buildSettings)}.keys.sorted() + try expect(allSettings) == ["SETTING_2"] + } + } $0.describe("Config") { diff --git a/docs/ProjectSpec.md b/docs/ProjectSpec.md index 2b1c8d97..98ad69dc 100644 --- a/docs/ProjectSpec.md +++ b/docs/ProjectSpec.md @@ -64,9 +64,13 @@ Note that target names can also be changed by adding a `name` property to a targ ### Options - ⚪️ **carthageBuildPath**: `String` - The path to the carthage build directory. Defaults to `Carthage/Build`. This is used when specifying target carthage dependencies - ⚪️ **bundleIdPrefix**: `String` - If this is specified then any target that doesn't have an `PRODUCT_BUNDLE_IDENTIFIER` (via all levels of build settings) will get an autogenerated one by combining `bundleIdPrefix` and the target name: `bundleIdPrefix.name`. The target name will be stripped of all characters that aren't alphanumerics, hyphens, or periods. Underscores will be replace with hyphens. - +- ⚪️ **applySettingPresets**: `String` - This controls the settings that are automatically applied to the project and its targets. These are the same build settings that Xcode would add when creating a new project. Project settings are applied by config type. Target settings are applied by the product type and platform. By default this is set to `all` + - `all`: project and target settings + - `project`: only project settings + - `targets`: only target settings + - `none`: no settings are automatically applied ### Configs -Each config maps to a build type of either `debug` or `release` which will then apply default build settings. Any value other than `debug` or `release` (for example "none"), will mean no default build settings will be applied. +Each config maps to a build type of either `debug` or `release` which will then apply default build settings to the project. Any value other than `debug` or `release` (for example `none`), will mean no default build settings will be applied to the project. ```yaml configs: From 0204f27c8283e50774cde6d6b3b80494e08b4a5d Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Sun, 22 Oct 2017 20:37:03 +0100 Subject: [PATCH 02/21] rename Options.applySettingPresets to Options.settingPresets --- Sources/ProjectSpec/ProjectSpec.swift | 4 ++-- Sources/XcodeGenKit/SettingsBuilder.swift | 4 ++-- Tests/XcodeGenKitTests/ProjectGeneratorTests.swift | 2 +- docs/ProjectSpec.md | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Sources/ProjectSpec/ProjectSpec.swift b/Sources/ProjectSpec/ProjectSpec.swift index e086b503..494e212f 100644 --- a/Sources/ProjectSpec/ProjectSpec.swift +++ b/Sources/ProjectSpec/ProjectSpec.swift @@ -29,7 +29,7 @@ public struct ProjectSpec { public struct Options { public var carthageBuildPath: String? public var bundleIdPrefix: String? - public var applySettingPresets: SettingPresets = .all + public var settingPresets: SettingPresets = .all public enum SettingPresets: String { case all @@ -155,6 +155,6 @@ extension ProjectSpec.Options: JSONObjectConvertible { public init(jsonDictionary: JSONDictionary) throws { carthageBuildPath = jsonDictionary.json(atKeyPath: "carthageBuildPath") bundleIdPrefix = jsonDictionary.json(atKeyPath: "bundleIdPrefix") - applySettingPresets = jsonDictionary.json(atKeyPath: "applySettingPresets") ?? .all + settingPresets = jsonDictionary.json(atKeyPath: "settingPresets") ?? .all } } diff --git a/Sources/XcodeGenKit/SettingsBuilder.swift b/Sources/XcodeGenKit/SettingsBuilder.swift index e8257ce1..a6491f0b 100644 --- a/Sources/XcodeGenKit/SettingsBuilder.swift +++ b/Sources/XcodeGenKit/SettingsBuilder.swift @@ -18,7 +18,7 @@ extension ProjectSpec { public func getProjectBuildSettings(config: Config) -> BuildSettings { var buildSettings: BuildSettings = [:] - if let type = config.type, options.applySettingPresets.applyProject { + if let type = config.type, options.settingPresets.applyProject { buildSettings += SettingsPresetFile.base.getBuildSettings() buildSettings += SettingsPresetFile.config(type).getBuildSettings() } @@ -31,7 +31,7 @@ extension ProjectSpec { public func getTargetBuildSettings(target: Target, config: Config) -> BuildSettings { var buildSettings = BuildSettings() - if options.applySettingPresets.applyTarget { + if options.settingPresets.applyTarget { buildSettings += SettingsPresetFile.platform(target.platform).getBuildSettings() buildSettings += SettingsPresetFile.product(target.type).getBuildSettings() buildSettings += SettingsPresetFile.productPlatform(target.type, target.platform).getBuildSettings() diff --git a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift index b1020607..26268719 100644 --- a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift @@ -44,7 +44,7 @@ func projectGeneratorTests() { $0.it("clears setting presets") { var options = ProjectSpec.Options() - options.applySettingPresets = .none + options.settingPresets = .none let spec = ProjectSpec(name: "test", targets: [framework], options: options) let project = try getProject(spec) let allSettings = project.pbxproj.buildConfigurations.reduce([:]) { $0.merged($1.buildSettings)}.keys.sorted() diff --git a/docs/ProjectSpec.md b/docs/ProjectSpec.md index 98ad69dc..e8bed454 100644 --- a/docs/ProjectSpec.md +++ b/docs/ProjectSpec.md @@ -64,7 +64,7 @@ Note that target names can also be changed by adding a `name` property to a targ ### Options - ⚪️ **carthageBuildPath**: `String` - The path to the carthage build directory. Defaults to `Carthage/Build`. This is used when specifying target carthage dependencies - ⚪️ **bundleIdPrefix**: `String` - If this is specified then any target that doesn't have an `PRODUCT_BUNDLE_IDENTIFIER` (via all levels of build settings) will get an autogenerated one by combining `bundleIdPrefix` and the target name: `bundleIdPrefix.name`. The target name will be stripped of all characters that aren't alphanumerics, hyphens, or periods. Underscores will be replace with hyphens. -- ⚪️ **applySettingPresets**: `String` - This controls the settings that are automatically applied to the project and its targets. These are the same build settings that Xcode would add when creating a new project. Project settings are applied by config type. Target settings are applied by the product type and platform. By default this is set to `all` +- ⚪️ **settingPresets**: `String` - This controls the settings that are automatically applied to the project and its targets. These are the same build settings that Xcode would add when creating a new project. Project settings are applied by config type. Target settings are applied by the product type and platform. By default this is set to `all` - `all`: project and target settings - `project`: only project settings - `targets`: only target settings From 24175c3411a1400473eee8dab6804efeecce578c Mon Sep 17 00:00:00 2001 From: ryohey Date: Mon, 23 Oct 2017 11:45:35 +0900 Subject: [PATCH 03/21] fix duplicate file reference --- Sources/XcodeGenKit/PBXProjGenerator.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index c7c7495f..18e1f6ab 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -549,8 +549,6 @@ public class PBXProjGenerator { for localisedDirectory in localisedDirectories { let localisationName = localisedDirectory.lastComponentWithoutExtension for path in try localisedDirectory.children().sorted { $0.lastComponent < $1.lastComponent } { - - let filePath = "\(localisedDirectory.lastComponent)/\(path.lastComponent)" // find base localisation variant group @@ -571,7 +569,9 @@ public class PBXProjGenerator { } if let variantGroup = variantGroup { - variantGroup.children.append(fileReference) + if !variantGroup.children.contains(fileReference) { + variantGroup.children.append(fileReference) + } } else { // add SourceFile to group if there is no Base.lproj directory let buildFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, fileReference), From 8d1e77b9c357bd43a9a7b77b5f5963a58b44893a Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Tue, 24 Oct 2017 11:24:34 +0200 Subject: [PATCH 04/21] update equatable --- Sources/ProjectSpec/ProjectSpec.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/ProjectSpec/ProjectSpec.swift b/Sources/ProjectSpec/ProjectSpec.swift index 494e212f..544782e4 100644 --- a/Sources/ProjectSpec/ProjectSpec.swift +++ b/Sources/ProjectSpec/ProjectSpec.swift @@ -119,7 +119,8 @@ extension ProjectSpec.Options: Equatable { public static func ==(lhs: ProjectSpec.Options, rhs: ProjectSpec.Options) -> Bool { return lhs.carthageBuildPath == rhs.carthageBuildPath && - lhs.bundleIdPrefix == rhs.bundleIdPrefix + lhs.bundleIdPrefix == rhs.bundleIdPrefix && + lhs.settingPresets == rhs.settingPresets } } From 779397ec8d2761dbe1a95069bb11f8c0fbd07233 Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Tue, 24 Oct 2017 21:30:06 +0200 Subject: [PATCH 05/21] move basePath into ProjectSpec --- Sources/ProjectSpec/ProjectSpec.swift | 9 ++++--- Sources/XcodeGen/main.swift | 2 +- Sources/XcodeGenKit/PBXProjGenerator.swift | 26 +++++++++---------- Sources/XcodeGenKit/ProjectGenerator.swift | 8 +++--- Sources/XcodeGenKit/SpecLoader.swift | 2 +- Sources/XcodeGenKit/SpecValidation.swift | 12 ++++----- Tests/XcodeGenKitTests/FixtureTests.swift | 4 +-- .../ProjectGeneratorTests.swift | 20 +++++++------- Tests/XcodeGenKitTests/SpecLoadingTests.swift | 8 +++--- 9 files changed, 45 insertions(+), 46 deletions(-) diff --git a/Sources/ProjectSpec/ProjectSpec.swift b/Sources/ProjectSpec/ProjectSpec.swift index 544782e4..7789f9fe 100644 --- a/Sources/ProjectSpec/ProjectSpec.swift +++ b/Sources/ProjectSpec/ProjectSpec.swift @@ -14,6 +14,7 @@ import Yams public struct ProjectSpec { + public var basePath: Path public var name: String public var targets: [Target] public var settings: Settings @@ -56,7 +57,8 @@ public struct ProjectSpec { } } - public init(name: String, configs: [Config] = [], targets: [Target] = [], settings: Settings = .empty, settingGroups: [String: Settings] = [:], schemes: [Scheme] = [], options: Options = Options(), fileGroups: [String] = [], configFiles: [String: String] = [:], attributes: [String: Any] = [:]) { + public init(basePath: Path, name: String, configs: [Config] = [], targets: [Target] = [], settings: Settings = .empty, settingGroups: [String: Settings] = [:], schemes: [Scheme] = [], options: Options = Options(), fileGroups: [String] = [], configFiles: [String: String] = [:], attributes: [String: Any] = [:]) { + self.basePath = basePath self.name = name self.targets = targets self.configs = configs @@ -124,9 +126,10 @@ extension ProjectSpec.Options: Equatable { } } -extension ProjectSpec: JSONObjectConvertible { +extension ProjectSpec { - public init(jsonDictionary: JSONDictionary) throws { + public init(basePath: Path, jsonDictionary: JSONDictionary) throws { + self.basePath = basePath let jsonDictionary = try ProjectSpec.filterJSON(jsonDictionary: jsonDictionary) name = try jsonDictionary.json(atKeyPath: "name") settings = jsonDictionary.json(atKeyPath: "settings") ?? .empty diff --git a/Sources/XcodeGen/main.swift b/Sources/XcodeGen/main.swift index 4934dcfc..46875360 100644 --- a/Sources/XcodeGen/main.swift +++ b/Sources/XcodeGen/main.swift @@ -33,7 +33,7 @@ func generate(spec: String, project: String) { } do { - let projectGenerator = ProjectGenerator(spec: spec, path: specPath.parent()) + let projectGenerator = ProjectGenerator(spec: spec) let project = try projectGenerator.generateProject() print("⚙️ Generated project") diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index 18e1f6ab..98b24305 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -17,7 +17,6 @@ import ProjectSpec public class PBXProjGenerator { let spec: ProjectSpec - let basePath: Path let currentXcodeVersion: String var fileReferencesByPath: [Path: String] = [:] @@ -38,10 +37,9 @@ public class PBXProjGenerator { return spec.options.carthageBuildPath ?? "Carthage/Build" } - public init(spec: ProjectSpec, path: Path, currentXcodeVersion: String) { + public init(spec: ProjectSpec, currentXcodeVersion: String) { self.currentXcodeVersion = currentXcodeVersion self.spec = spec - basePath = path } public func generateUUID(_ element: T.Type, _ id: String) -> String { @@ -67,14 +65,14 @@ public class PBXProjGenerator { project = PBXProj(archiveVersion: 1, objectVersion: 46, rootObject: generateUUID(PBXProject.self, spec.name)) for group in spec.fileGroups { - _ = try getGroups(path: basePath + group) + _ = try getGroups(path: spec.basePath + group) } let buildConfigs: [XCBuildConfiguration] = spec.configs.map { config in let buildSettings = spec.getProjectBuildSettings(config: config) var baseConfigurationReference: String? if let configPath = spec.configFiles[config.name] { - baseConfigurationReference = getFileReference(path: basePath + configPath, inPath: basePath) + baseConfigurationReference = getFileReference(path: spec.basePath + configPath, inPath: spec.basePath) } return XCBuildConfiguration(reference: generateUUID(XCBuildConfiguration.self, config.name), name: config.name, baseConfigurationReference: baseConfigurationReference, buildSettings: buildSettings) } @@ -159,7 +157,7 @@ public class PBXProjGenerator { let carthageDependencies = getAllCarthageDependencies(target: target) - let sourcePaths = target.sources.map { basePath + $0 } + let sourcePaths = target.sources.map { spec.basePath + $0 } var sourceFiles: [SourceFile] = [] for source in sourcePaths { @@ -177,13 +175,13 @@ public class PBXProjGenerator { // automatically set INFOPLIST_FILE path if let plistPath = infoPlists.first, - !spec.targetHasBuildSetting("INFOPLIST_FILE", basePath: basePath, target: target, config: config) { - buildSettings["INFOPLIST_FILE"] = plistPath.byRemovingBase(path: basePath) + !spec.targetHasBuildSetting("INFOPLIST_FILE", basePath: spec.basePath, target: target, config: config) { + buildSettings["INFOPLIST_FILE"] = plistPath.byRemovingBase(path: spec.basePath) } // automatically calculate bundle id if let bundleIdPrefix = spec.options.bundleIdPrefix, - !spec.targetHasBuildSetting("PRODUCT_BUNDLE_IDENTIFIER", basePath: basePath, target: target, config: config) { + !spec.targetHasBuildSetting("PRODUCT_BUNDLE_IDENTIFIER", basePath: spec.basePath, target: target, config: config) { let characterSet = CharacterSet.alphanumerics.union(CharacterSet(charactersIn: "-.")).inverted let escapedTargetName = target.name.replacingOccurrences(of: "_", with: "-").components(separatedBy: characterSet).joined(separator: "") buildSettings["PRODUCT_BUNDLE_IDENTIFIER"] = bundleIdPrefix + "." + escapedTargetName @@ -191,7 +189,7 @@ public class PBXProjGenerator { // automatically set test target name if target.type == .uiTestBundle, - !spec.targetHasBuildSetting("TEST_TARGET_NAME", basePath: basePath, target: target, config: config) { + !spec.targetHasBuildSetting("TEST_TARGET_NAME", basePath: spec.basePath, target: target, config: config) { for dependency in target.dependencies { if dependency.type == .target, let dependencyTarget = spec.getTarget(dependency.reference), @@ -219,7 +217,7 @@ public class PBXProjGenerator { var baseConfigurationReference: String? if let configPath = target.configFiles[config.name] { - baseConfigurationReference = getFileReference(path: basePath + configPath, inPath: basePath) + baseConfigurationReference = getFileReference(path: spec.basePath + configPath, inPath: spec.basePath) } return XCBuildConfiguration(reference: generateUUID(XCBuildConfiguration.self, config.name + target.name), name: config.name, baseConfigurationReference: baseConfigurationReference, buildSettings: buildSettings) } @@ -277,7 +275,7 @@ public class PBXProjGenerator { case .framework: - let fileReference = getFileReference(path: Path(dependency.reference), inPath: basePath) + let fileReference = getFileReference(path: Path(dependency.reference), inPath: spec.basePath) let buildFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, fileReference + target.name), fileRef: fileReference) addObject(buildFile) @@ -330,7 +328,7 @@ public class PBXProjGenerator { var shellScript: String switch buildScript.script { case let .path(path): - shellScript = try (basePath + path).read() + shellScript = try (spec.basePath + path).read() case let .script(script): shellScript = script } @@ -583,7 +581,7 @@ public class PBXProjGenerator { } } - let groupPath: String = depth == 0 ? path.byRemovingBase(path: basePath).string : path.lastComponent + let groupPath: String = depth == 0 ? path.byRemovingBase(path: spec.basePath).string : path.lastComponent let group: PBXGroup if let cachedGroup = groupsByPath[path] { group = cachedGroup diff --git a/Sources/XcodeGenKit/ProjectGenerator.swift b/Sources/XcodeGenKit/ProjectGenerator.swift index cd804ec5..1670e7a8 100644 --- a/Sources/XcodeGenKit/ProjectGenerator.swift +++ b/Sources/XcodeGenKit/ProjectGenerator.swift @@ -16,12 +16,10 @@ import ProjectSpec public class ProjectGenerator { var spec: ProjectSpec - var path: Path let currentXcodeVersion = "0900" - public init(spec: ProjectSpec, path: Path) { + public init(spec: ProjectSpec) { self.spec = spec - self.path = path } var defaultDebugConfig: Config { @@ -33,8 +31,8 @@ public class ProjectGenerator { } public func generateProject() throws -> XcodeProj { - try spec.validate(path: path) - let pbxProjGenerator = PBXProjGenerator(spec: spec, path: path, currentXcodeVersion: currentXcodeVersion) + try spec.validate() + let pbxProjGenerator = PBXProjGenerator(spec: spec, currentXcodeVersion: currentXcodeVersion) let pbxProject = try pbxProjGenerator.generate() let workspace = try generateWorkspace() let sharedData = try generateSharedData(pbxProject: pbxProject) diff --git a/Sources/XcodeGenKit/SpecLoader.swift b/Sources/XcodeGenKit/SpecLoader.swift index cee23066..51f10c29 100644 --- a/Sources/XcodeGenKit/SpecLoader.swift +++ b/Sources/XcodeGenKit/SpecLoader.swift @@ -16,7 +16,7 @@ public struct SpecLoader { public static func loadSpec(path: Path) throws -> ProjectSpec { let dictionary = try loadDictionary(path: path) - return try ProjectSpec(jsonDictionary: dictionary) + return try ProjectSpec(basePath: path.parent(), jsonDictionary: dictionary) } private static func loadDictionary(path: Path) throws -> JSONDictionary { diff --git a/Sources/XcodeGenKit/SpecValidation.swift b/Sources/XcodeGenKit/SpecValidation.swift index e27375b3..454e5837 100644 --- a/Sources/XcodeGenKit/SpecValidation.swift +++ b/Sources/XcodeGenKit/SpecValidation.swift @@ -11,7 +11,7 @@ import PathKit extension ProjectSpec { - public mutating func validate(path: Path) throws { + public mutating func validate() throws { if configs.isEmpty { configs = [Config(name: "Debug", type: .debug), Config(name: "Release", type: .release)] @@ -32,13 +32,13 @@ extension ProjectSpec { } for fileGroup in fileGroups { - if !(path + fileGroup).exists { + if !(basePath + fileGroup).exists { errors.append(.invalidFileGroup(fileGroup)) } } for (config, configFile) in configFiles { - if !(path + configFile).exists { + if !(basePath + configFile).exists { errors.append(.invalidConfigFile(configFile: configFile, config: config)) } } @@ -55,7 +55,7 @@ extension ProjectSpec { } for (config, configFile) in target.configFiles { - if !(path + configFile).exists { + if !(basePath + configFile).exists { errors.append(.invalidTargetConfigFile(configFile: configFile, config: config, target: target.name)) } } @@ -67,7 +67,7 @@ extension ProjectSpec { } for source in target.sources { - let sourcePath = path + source + let sourcePath = basePath + source if !sourcePath.exists { errors.append(.missingTargetSource(target: target.name, source: sourcePath.string)) } @@ -94,7 +94,7 @@ extension ProjectSpec { let scripts = target.prebuildScripts + target.postbuildScripts for script in scripts { if case let .path(pathString) = script.script { - let scriptPath = path + pathString + let scriptPath = basePath + pathString if !scriptPath.exists { errors.append(.invalidBuildScriptPath(target: target.name, path: pathString)) } diff --git a/Tests/XcodeGenKitTests/FixtureTests.swift b/Tests/XcodeGenKitTests/FixtureTests.swift index 8fad8542..fe808cbc 100644 --- a/Tests/XcodeGenKitTests/FixtureTests.swift +++ b/Tests/XcodeGenKitTests/FixtureTests.swift @@ -7,8 +7,8 @@ import ProjectSpec let fixturePath = Path(#file).parent().parent().parent() + "Fixtures" func generate(specPath: Path, projectPath: Path) throws -> XcodeProj { - let spec = try ProjectSpec(path: specPath) - let generator = ProjectGenerator(spec: spec, path: specPath.parent()) + let spec = try SpecLoader.loadSpec(path: specPath) + let generator = ProjectGenerator(spec: spec) let project = try generator.generateProject() let oldProject = try XcodeProj(path: projectPath) try project.write(path: projectPath, override: true) diff --git a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift index 26268719..4238033b 100644 --- a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift @@ -7,7 +7,7 @@ import ProjectSpec func projectGeneratorTests() { func getProject(_ spec: ProjectSpec) throws -> XcodeProj { - let generator = ProjectGenerator(spec: spec, path: Path("")) + let generator = ProjectGenerator(spec: spec) return try generator.generateProject() } @@ -31,7 +31,7 @@ func projectGeneratorTests() { $0.it("generates bundle id") { var options = ProjectSpec.Options() options.bundleIdPrefix = "com.test" - let spec = ProjectSpec(name: "test", targets: [framework], options: options) + let spec = ProjectSpec(basePath: "", name: "test", targets: [framework], options: options) let project = try getProject(spec) guard let target = project.pbxproj.nativeTargets.first, let buildConfigs = project.pbxproj.configurationLists.getReference(target.buildConfigurationList), @@ -45,7 +45,7 @@ func projectGeneratorTests() { $0.it("clears setting presets") { var options = ProjectSpec.Options() options.settingPresets = .none - let spec = ProjectSpec(name: "test", targets: [framework], options: options) + let spec = ProjectSpec(basePath: "", name: "test", targets: [framework], options: options) let project = try getProject(spec) let allSettings = project.pbxproj.buildConfigurations.reduce([:]) { $0.merged($1.buildSettings)}.keys.sorted() try expect(allSettings) == ["SETTING_2"] @@ -56,7 +56,7 @@ func projectGeneratorTests() { $0.describe("Config") { $0.it("generates config defaults") { - let spec = ProjectSpec(name: "test") + let spec = ProjectSpec(basePath: "", name: "test") let project = try getProject(spec) let configs = project.pbxproj.buildConfigurations try expect(configs.count) == 2 @@ -65,7 +65,7 @@ func projectGeneratorTests() { } $0.it("generates configs") { - let spec = ProjectSpec(name: "test", configs: [Config(name: "config1"), Config(name: "config2")]) + let spec = ProjectSpec(basePath: "", name: "test", configs: [Config(name: "config1"), Config(name: "config2")]) let project = try getProject(spec) let configs = project.pbxproj.buildConfigurations try expect(configs.count) == 2 @@ -74,7 +74,7 @@ func projectGeneratorTests() { } $0.it("clears config settings when missing type") { - let spec = ProjectSpec(name: "test", configs: [Config(name: "config")]) + let spec = ProjectSpec(basePath: "", name: "test", configs: [Config(name: "config")]) let project = try getProject(spec) guard let config = project.pbxproj.buildConfigurations.first else { throw failure("configuration not found") @@ -83,7 +83,7 @@ func projectGeneratorTests() { } $0.it("merges settings") { - let spec = try ProjectSpec(path: fixturePath + "settings_test.yml") + let spec = try SpecLoader.loadSpec(path: fixturePath + "settings_test.yml") guard let config = spec.getConfig("config1") else { throw failure("Couldn't find config1") } let debugProjectSettings = spec.getProjectBuildSettings(config: config) @@ -113,7 +113,7 @@ func projectGeneratorTests() { $0.describe("Targets") { - let spec = ProjectSpec(name: "test", targets: targets) + let spec = ProjectSpec(basePath: "", name: "test", targets: targets) $0.it("generates targets") { let pbxProject = try getPbxProj(spec) @@ -164,7 +164,7 @@ func projectGeneratorTests() { let buildTarget = Scheme.BuildTarget(target: application.name) $0.it("generates scheme") { let scheme = Scheme(name: "MyScheme", build: Scheme.Build(targets: [buildTarget])) - let spec = ProjectSpec(name: "test", targets: [application, framework], schemes: [scheme]) + let spec = ProjectSpec(basePath: "", name: "test", targets: [application, framework], schemes: [scheme]) let project = try getProject(spec) guard let target = project.pbxproj.nativeTargets.first(where: { $0.name == application.name }) else { throw failure("Target not found") } guard let xcscheme = project.sharedData?.schemes.first else { throw failure("Scheme not found") } @@ -203,7 +203,7 @@ func projectGeneratorTests() { Config(name: "Production Release", type: .release), ] - let spec = ProjectSpec(name: "test", configs: configs, targets: [target, framework]) + let spec = ProjectSpec(basePath: "", name: "test", configs: configs, targets: [target, framework]) let project = try getProject(spec) try expect(project.sharedData?.schemes.count) == 2 diff --git a/Tests/XcodeGenKitTests/SpecLoadingTests.swift b/Tests/XcodeGenKitTests/SpecLoadingTests.swift index d7319601..60279410 100644 --- a/Tests/XcodeGenKitTests/SpecLoadingTests.swift +++ b/Tests/XcodeGenKitTests/SpecLoadingTests.swift @@ -12,7 +12,7 @@ func specLoadingTests() { for (key, value) in spec { specDictionary[key] = value } - return try ProjectSpec(jsonDictionary: specDictionary) + return try ProjectSpec(basePath: "", jsonDictionary: specDictionary) } func expectProjectSpecError(_ spec: [String: Any], _ expectedError: ProjectSpecError) throws { @@ -82,7 +82,7 @@ func specLoadingTests() { try expect(target.dependencies[2]) == Dependency(type: .framework, reference: "path") } - $0.it("parsed cross platform targets") { + $0.it("parses cross platform targets") { let targetDictionary: [String: Any] = [ "platform": ["iOS", "tvOS"], "type": "framework", @@ -128,7 +128,7 @@ func specLoadingTests() { } $0.it("parses settings") { - let spec = try ProjectSpec(path: fixturePath + "settings_test.yml") + let spec = try SpecLoader.loadSpec(path: fixturePath + "settings_test.yml") let buildSettings: BuildSettings = ["SETTING": "value"] let configSettings: [String: Settings] = ["config1": Settings(buildSettings: ["SETTING1": "value"])] let groups = ["preset1"] @@ -176,7 +176,7 @@ func specLoadingTests() { var options = ProjectSpec.Options() options.carthageBuildPath = "../Carthage/Build" options.bundleIdPrefix = "com.test" - let expected = ProjectSpec(name: "test", options: options) + let expected = ProjectSpec(basePath: "", name: "test", options: options) let parsedSpec = try getProjectSpec(["options": ["carthageBuildPath": "../Carthage/Build", "bundleIdPrefix": "com.test"]]) try expect(parsedSpec) == expected } From 2d1d81246d75767c47920be75413f644c7c59aad Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Tue, 24 Oct 2017 22:21:21 +0200 Subject: [PATCH 06/21] log explicit missing spec error --- Sources/XcodeGen/main.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Sources/XcodeGen/main.swift b/Sources/XcodeGen/main.swift index 4934dcfc..0242dbbb 100644 --- a/Sources/XcodeGen/main.swift +++ b/Sources/XcodeGen/main.swift @@ -20,6 +20,11 @@ func generate(spec: String, project: String) { let specPath = Path(spec).normalize() let projectPath = Path(project).normalize() + if !specPath.exists { + print("No project spec found at \(specPath.absolute())".red) + exit(1) + } + let spec: ProjectSpec do { spec = try SpecLoader.loadSpec(path: specPath) @@ -42,6 +47,7 @@ func generate(spec: String, project: String) { print("💾 Saved project to \(projectFile.string)".green) } catch let error as SpecValidationError { print(error.description.red) + exit(1) } catch { print("Generation failed: \(error.localizedDescription)".red) exit(1) From 6d4449192caa89076db3a29d73f60555463571a3 Mon Sep 17 00:00:00 2001 From: Brandon Kase Date: Tue, 24 Oct 2017 14:13:26 -0700 Subject: [PATCH 07/21] Remove unused sourceExcludes --- Sources/ProjectSpec/Target.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Sources/ProjectSpec/Target.swift b/Sources/ProjectSpec/Target.swift index 006e140b..93504214 100644 --- a/Sources/ProjectSpec/Target.swift +++ b/Sources/ProjectSpec/Target.swift @@ -16,7 +16,6 @@ public struct Target { public var platform: Platform public var settings: Settings public var sources: [String] - public var sourceExludes: [String] public var dependencies: [Dependency] public var prebuildScripts: [BuildScript] public var postbuildScripts: [BuildScript] @@ -31,14 +30,13 @@ public struct Target { return name } - public init(name: String, type: PBXProductType, platform: Platform, settings: Settings = .empty, configFiles: [String: String] = [:], sources: [String] = [], sourceExludes: [String] = [], dependencies: [Dependency] = [], prebuildScripts: [BuildScript] = [], postbuildScripts: [BuildScript] = [], scheme: TargetScheme? = nil) { + public init(name: String, type: PBXProductType, platform: Platform, settings: Settings = .empty, configFiles: [String: String] = [:], sources: [String] = [], dependencies: [Dependency] = [], prebuildScripts: [BuildScript] = [], postbuildScripts: [BuildScript] = [], scheme: TargetScheme? = nil) { self.name = name self.type = type self.platform = platform self.settings = settings self.configFiles = configFiles self.sources = sources - self.sourceExludes = sourceExludes self.dependencies = dependencies self.prebuildScripts = prebuildScripts self.postbuildScripts = postbuildScripts @@ -129,7 +127,6 @@ extension Target: Equatable { lhs.settings == rhs.settings && lhs.configFiles == rhs.configFiles && lhs.sources == rhs.sources && - lhs.sourceExludes == rhs.sourceExludes && lhs.dependencies == rhs.dependencies && lhs.prebuildScripts == rhs.prebuildScripts && lhs.postbuildScripts == rhs.postbuildScripts && @@ -186,7 +183,6 @@ extension Target: NamedJSONDictionaryConvertible { } else { sources = jsonDictionary.json(atKeyPath: "sources") ?? [] } - sourceExludes = jsonDictionary.json(atKeyPath: "sourceExludes") ?? [] if jsonDictionary["dependencies"] == nil { dependencies = [] } else { From 8e95044d553f689f30a57c43aab05c9cac9eb771 Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Wed, 25 Oct 2017 21:05:53 +0200 Subject: [PATCH 08/21] fix carthage file references from being duplicated --- Sources/XcodeGenKit/PBXProjGenerator.swift | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index 98b24305..bfe12c90 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -27,7 +27,7 @@ public class PBXProjGenerator { var targetBuildFiles: [String: PBXBuildFile] = [:] var targetFileReferences: [String: String] = [:] var topLevelGroups: [PBXGroup] = [] - var carthageFrameworksByPlatform: [String: [String]] = [:] + var carthageFrameworksByPlatform: [String: Set] = [:] var frameworkFiles: [String] = [] var uuids: Set = [] @@ -103,11 +103,11 @@ public class PBXProjGenerator { if !carthageFrameworksByPlatform.isEmpty { var platforms: [PBXGroup] = [] for (platform, fileReferences) in carthageFrameworksByPlatform { - let platformGroup = PBXGroup(reference: generateUUID(PBXGroup.self, platform), children: fileReferences, sourceTree: .group, name: platform, path: platform) + let platformGroup = PBXGroup(reference: generateUUID(PBXGroup.self, platform), children: fileReferences.sorted(), sourceTree: .group, name: platform, path: platform) addObject(platformGroup) platforms.append(platformGroup) } - let carthageGroup = PBXGroup(reference: generateUUID(PBXGroup.self, "Carthage"), children: platforms.references, sourceTree: .group, name: "Carthage", path: carthageBuildPath) + let carthageGroup = PBXGroup(reference: generateUUID(PBXGroup.self, "Carthage"), children: platforms.references.sorted(), sourceTree: .group, name: "Carthage", path: carthageBuildPath) addObject(carthageGroup) frameworkFiles.append(carthageGroup.reference) } @@ -291,9 +291,6 @@ public class PBXProjGenerator { copyFrameworksReferences.append(embedFile.reference) } case .carthage: - if carthageFrameworksByPlatform[target.platform.carthageDirectoryName] == nil { - carthageFrameworksByPlatform[target.platform.carthageDirectoryName] = [] - } var platformPath = Path(getCarthageBuildPath(platform: target.platform)) var frameworkPath = platformPath + dependency.reference if frameworkPath.extension == nil { @@ -303,7 +300,7 @@ public class PBXProjGenerator { let buildFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, fileReference + target.name), fileRef: fileReference) addObject(buildFile) - carthageFrameworksByPlatform[target.platform.carthageDirectoryName]?.append(fileReference) + carthageFrameworksByPlatform[target.platform.carthageDirectoryName, default: []].insert(fileReference) targetFrameworkBuildFiles.append(buildFile.reference) if target.platform == .macOS && target.type.isApp { From 08de6077d9051492aeeba5d52dd6b30797bb1be0 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Wed, 25 Oct 2017 15:55:49 -0700 Subject: [PATCH 09/21] Add option for not linking dependencies This adds a new attribute to Dependency that allows consumers to choose to not link a dependency. This is useful for if you have this dependency tree with static libraries: App -> A -> Shared App -> B -> Shared Where A and B both share a static library dependency, that is finally linked into App. If Shared is added to the link phase of A and B, you end up with duplicate symbols during the link phase. With this change consumers could set link: False on A and B's dependency on Shared, this way Shared will get build before A and B, but not linked. --- Sources/ProjectSpec/Target.swift | 7 ++++++- Sources/XcodeGenKit/PBXProjGenerator.swift | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Sources/ProjectSpec/Target.swift b/Sources/ProjectSpec/Target.swift index 93504214..0037741e 100644 --- a/Sources/ProjectSpec/Target.swift +++ b/Sources/ProjectSpec/Target.swift @@ -201,6 +201,7 @@ public struct Dependency: Equatable { public var embed: Bool? public var codeSign: Bool = true public var removeHeaders: Bool = true + public var link: Bool = true public init(type: DependencyType, reference: String, embed: Bool? = nil) { self.type = type @@ -219,7 +220,8 @@ public struct Dependency: Equatable { lhs.type == rhs.type && lhs.codeSign == rhs.codeSign && lhs.removeHeaders == rhs.removeHeaders && - lhs.embed == rhs.embed + lhs.embed == rhs.embed && + lhs.link == rhs.link } public var buildSettings: [String: Any] { @@ -252,6 +254,9 @@ extension Dependency: JSONObjectConvertible { embed = jsonDictionary.json(atKeyPath: "embed") + if let bool: Bool = jsonDictionary.json(atKeyPath: "link") { + link = bool + } if let bool: Bool = jsonDictionary.json(atKeyPath: "codeSign") { codeSign = bool } diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index bfe12c90..6c50eb1a 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -248,7 +248,7 @@ public class PBXProjGenerator { addObject(targetDependency) dependencies.append(targetDependency.reference) - if dependencyTarget.type.isLibrary || dependencyTarget.type.isFramework { + if (dependencyTarget.type.isLibrary || dependencyTarget.type.isFramework) && dependency.link { let dependencyBuildFile = targetBuildFiles[dependencyTargetName]! let buildFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, dependencyBuildFile.reference + target.name), fileRef: dependencyBuildFile.fileRef) addObject(buildFile) From 5c65ef13b7472a7cdd706cd0b2a377845cad94af Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Thu, 26 Oct 2017 19:40:46 +0200 Subject: [PATCH 10/21] add setting config reference linting --- Sources/XcodeGenKit/SpecValidation.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Sources/XcodeGenKit/SpecValidation.swift b/Sources/XcodeGenKit/SpecValidation.swift index 454e5837..4bd40956 100644 --- a/Sources/XcodeGenKit/SpecValidation.swift +++ b/Sources/XcodeGenKit/SpecValidation.swift @@ -28,6 +28,11 @@ extension ProjectSpec { errors.append(.invalidSettingsGroup(group)) } } + for config in settings.configSettings.keys { + if getConfig(config) == nil { + errors.append(.invalidConfigReference(config)) + } + } return errors } @@ -150,6 +155,7 @@ public struct SpecValidationError: Error, CustomStringConvertible { case invalidTargetSchemeConfigVariant(target: String, configVariant: String, configType: ConfigType) case invalidTargetSchemeTest(target: String, testTarget: String) case invalidFileGroup(String) + case invalidConfigReference(String) public var description: String { switch self { @@ -165,6 +171,7 @@ public struct SpecValidationError: Error, CustomStringConvertible { case let .invalidTargetSchemeConfigVariant(target, configVariant, configType): return "Target \(target.quoted) has invalid scheme config varians which requires a config that has a \(configType.rawValue.quoted) type and contains the name \(configVariant.quoted)" case let .invalidTargetSchemeTest(target, test): return "Target \(target.quoted) scheme has invalid test \(test.quoted)" case let .invalidFileGroup(group): return "Invalid file group \(group.quoted)" + case let .invalidConfigReference(config): return "Invalid config reference \(config.quoted)" } } } From 11abfb0ae2b90701537799e20fcefcd404944291 Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Thu, 26 Oct 2017 21:50:45 +0200 Subject: [PATCH 11/21] apply partial matching to Settings.configs --- Sources/XcodeGenKit/SettingsBuilder.swift | 6 ++++-- Sources/XcodeGenKit/SpecValidation.swift | 2 +- Tests/XcodeGenKitTests/ProjectGeneratorTests.swift | 13 ++++++++++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Sources/XcodeGenKit/SettingsBuilder.swift b/Sources/XcodeGenKit/SettingsBuilder.swift index a6491f0b..f4a7a9a5 100644 --- a/Sources/XcodeGenKit/SettingsBuilder.swift +++ b/Sources/XcodeGenKit/SettingsBuilder.swift @@ -52,8 +52,10 @@ extension ProjectSpec { buildSettings += settings.buildSettings - if let configSettings = settings.configSettings[config.name] { - buildSettings += getBuildSettings(settings: configSettings, config: config) + for (configVariant, settings) in settings.configSettings { + if config.name.contains(configVariant) { + buildSettings += getBuildSettings(settings: settings, config: config) + } } return buildSettings diff --git a/Sources/XcodeGenKit/SpecValidation.swift b/Sources/XcodeGenKit/SpecValidation.swift index 4bd40956..109f6178 100644 --- a/Sources/XcodeGenKit/SpecValidation.swift +++ b/Sources/XcodeGenKit/SpecValidation.swift @@ -29,7 +29,7 @@ extension ProjectSpec { } } for config in settings.configSettings.keys { - if getConfig(config) == nil { + if !configs.contains(where: { $0.name.contains(config)}) { errors.append(.invalidConfigReference(config)) } } diff --git a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift index 4238033b..21aa17f4 100644 --- a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift @@ -37,7 +37,7 @@ func projectGeneratorTests() { let buildConfigs = project.pbxproj.configurationLists.getReference(target.buildConfigurationList), let buildConfigReference = buildConfigs.buildConfigurations.first, let buildConfig = project.pbxproj.buildConfigurations.getReference(buildConfigReference) else { - throw failure("Build Config not found") + throw failure("Build Config not found") } try expect(buildConfig.buildSettings["PRODUCT_BUNDLE_IDENTIFIER"] as? String) == "com.test.MyFramework" } @@ -109,6 +109,17 @@ func projectGeneratorTests() { try expect(targetDebugSettings.equals(expectedTargetDebugSettings)).beTrue() } + + $0.it("applies partial config settings") { + let spec = ProjectSpec(basePath: "", name: "test", configs: [ + Config(name: "Staging Debug", type: .debug), + Config(name: "Staging Release", type: .release)], + settings: Settings(configSettings: ["Staging": ["SETTING1": "VALUE1"], "Debug": ["SETTING2": "VALUE2"]])) + + var buildSettings = spec.getProjectBuildSettings(config: spec.configs.first!) + try expect(buildSettings["SETTING1"] as? String) == "VALUE1" + try expect(buildSettings["SETTING2"] as? String) == "VALUE2" + } } $0.describe("Targets") { From 08079c914e2cf043f929172d9f8ac2f52a0b3278 Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Thu, 26 Oct 2017 21:53:16 +0200 Subject: [PATCH 12/21] make Settings.configs case insensitive --- Sources/XcodeGenKit/SettingsBuilder.swift | 2 +- Sources/XcodeGenKit/SpecValidation.swift | 2 +- Tests/XcodeGenKitTests/ProjectGeneratorTests.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/XcodeGenKit/SettingsBuilder.swift b/Sources/XcodeGenKit/SettingsBuilder.swift index f4a7a9a5..26b2b78e 100644 --- a/Sources/XcodeGenKit/SettingsBuilder.swift +++ b/Sources/XcodeGenKit/SettingsBuilder.swift @@ -53,7 +53,7 @@ extension ProjectSpec { buildSettings += settings.buildSettings for (configVariant, settings) in settings.configSettings { - if config.name.contains(configVariant) { + if config.name.lowercased().contains(configVariant.lowercased()) { buildSettings += getBuildSettings(settings: settings, config: config) } } diff --git a/Sources/XcodeGenKit/SpecValidation.swift b/Sources/XcodeGenKit/SpecValidation.swift index 109f6178..4a86d979 100644 --- a/Sources/XcodeGenKit/SpecValidation.swift +++ b/Sources/XcodeGenKit/SpecValidation.swift @@ -29,7 +29,7 @@ extension ProjectSpec { } } for config in settings.configSettings.keys { - if !configs.contains(where: { $0.name.contains(config)}) { + if !configs.contains(where: { $0.name.lowercased().contains(config.lowercased())}) { errors.append(.invalidConfigReference(config)) } } diff --git a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift index 21aa17f4..cd7244ee 100644 --- a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift @@ -114,7 +114,7 @@ func projectGeneratorTests() { let spec = ProjectSpec(basePath: "", name: "test", configs: [ Config(name: "Staging Debug", type: .debug), Config(name: "Staging Release", type: .release)], - settings: Settings(configSettings: ["Staging": ["SETTING1": "VALUE1"], "Debug": ["SETTING2": "VALUE2"]])) + settings: Settings(configSettings: ["staging": ["SETTING1": "VALUE1"], "debug": ["SETTING2": "VALUE2"]])) var buildSettings = spec.getProjectBuildSettings(config: spec.configs.first!) try expect(buildSettings["SETTING1"] as? String) == "VALUE1" From 57204c5054f8785fe9f27068a3dd63e19031b9a1 Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Thu, 26 Oct 2017 22:09:26 +0200 Subject: [PATCH 13/21] add partial config matching documentation --- docs/ProjectSpec.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ProjectSpec.md b/docs/ProjectSpec.md index e8bed454..3a141a22 100644 --- a/docs/ProjectSpec.md +++ b/docs/ProjectSpec.md @@ -103,7 +103,7 @@ settingGroups: Settings can either be a simple map of build settings `[String: String]`, or can be more advanced with the following properties: - ⚪️ **groups**: `[String]` - List of setting groups to include and merge -- ⚪️ **configs**: [String: [Settings](#settings)] - Mapping of config name to a settings spec. These settings will only be applied for that config +- ⚪️ **configs**: [String: [Settings](#settings)] - Mapping of config name to a settings spec. These settings will only be applied for that config. Each key will be matched to any configs that contain the key and is case insensitive. So if you had `Staging Debug` and `Staging Release`, you could apply settings to both of them using `staging`. - ⚪️ **base**: `[String: String]` - Used to specify default settings that apply to any config ```yaml From d31f9be4bfb99cbfe9605eb935ca5e747c79e4b4 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Thu, 26 Oct 2017 10:34:32 -0700 Subject: [PATCH 14/21] Update documentation for link dependency --- docs/ProjectSpec.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/ProjectSpec.md b/docs/ProjectSpec.md index e8bed454..2b0b892c 100644 --- a/docs/ProjectSpec.md +++ b/docs/ProjectSpec.md @@ -219,6 +219,7 @@ A dependency can be one of a 3 types: These only applied to `target` and `framework` dependencies. - ⚪️ **embed**: `Bool` - Whether to embed the dependency. Defaults to true for application target and false for non application targets. +- ⚪️ **link**: `Bool` - Whether to link the dependency. Defaults to true but only static library and dynamic frameworks are linked. This only applies for target dependencies. - ⚪️ **codeSign**: `Bool` - Whether the `codeSignOnCopy` setting is applied when embedding framework. Defaults to true - ⚪️ **removeHeaders**: `Bool` - Whether the `removeHeadersOnCopy` setting is applied when embedding the framework. Defaults to true From ebb945ede21b58b6a91d340e7595ec081c79b0bc Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Thu, 26 Oct 2017 23:52:18 +0200 Subject: [PATCH 15/21] add spec validation that a spec has debug and release configs when generating a target scheme --- Sources/XcodeGenKit/SpecValidation.swift | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Sources/XcodeGenKit/SpecValidation.swift b/Sources/XcodeGenKit/SpecValidation.swift index 4a86d979..d2841cdc 100644 --- a/Sources/XcodeGenKit/SpecValidation.swift +++ b/Sources/XcodeGenKit/SpecValidation.swift @@ -89,6 +89,15 @@ extension ProjectSpec { } } + if scheme.configVariants.isEmpty { + if !configs.contains(where: { $0.type == .debug }) { + errors.append(.missingConfigTypeForGeneratedTargetScheme(target: target.name, configType: .debug)) + } + if !configs.contains(where: { $0.type == .release }) { + errors.append(.missingConfigTypeForGeneratedTargetScheme(target: target.name, configType: .release)) + } + } + for testTarget in scheme.testTargets { if getTarget(testTarget) == nil { errors.append(.invalidTargetSchemeTest(target: target.name, testTarget: testTarget)) @@ -156,6 +165,7 @@ public struct SpecValidationError: Error, CustomStringConvertible { case invalidTargetSchemeTest(target: String, testTarget: String) case invalidFileGroup(String) case invalidConfigReference(String) + case missingConfigTypeForGeneratedTargetScheme(target: String, configType: ConfigType) public var description: String { switch self { @@ -168,10 +178,11 @@ public struct SpecValidationError: Error, CustomStringConvertible { case let .missingTargetSource(target, source): return "Target \(target.quoted) has a missing source directory \(source.quoted)" case let .invalidSettingsGroup(group): return "Invalid settings group \(group.quoted)" case let .invalidBuildScriptPath(target, path): return "Target \(target.quoted) has a script path that doesn't exist \(path.quoted)" - case let .invalidTargetSchemeConfigVariant(target, configVariant, configType): return "Target \(target.quoted) has invalid scheme config varians which requires a config that has a \(configType.rawValue.quoted) type and contains the name \(configVariant.quoted)" + case let .invalidTargetSchemeConfigVariant(target, configVariant, configType): return "Target \(target.quoted) has an invalid scheme config variant which requires a config that has a \(configType.rawValue.quoted) type and contains the name \(configVariant.quoted)" case let .invalidTargetSchemeTest(target, test): return "Target \(target.quoted) scheme has invalid test \(test.quoted)" case let .invalidFileGroup(group): return "Invalid file group \(group.quoted)" case let .invalidConfigReference(config): return "Invalid config reference \(config.quoted)" + case let .missingConfigTypeForGeneratedTargetScheme(target, configType): return "Target \(target.quoted) is missing a config of type \(configType.rawValue) to generate its scheme" } } } From c2136b22d6fefde1a1cec8ca126e8ed8fd6b073a Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Fri, 27 Oct 2017 00:31:14 +0200 Subject: [PATCH 16/21] update changelog --- CHANGELOG.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa719390..b2377bf8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,20 @@ ## Master +## 1.3.0 + ### Added - generate output files for Carthage copy-frameworks script [#84](https://github.com/yonaskolb/XcodeGen/pull/84) @mironal +- added options.settingPreset to choose which setting presets get applied [#100](https://github.com/yonaskolb/XcodeGen/pull/101) @yonaskolb +- added `link` option for target dependencies [#109](https://github.com/yonaskolb/XcodeGen/pull/109) @keith ### Changed - updated to xcproj 0.4.1 [#85](https://github.com/yonaskolb/XcodeGen/pull/85) @enmiller - don't copy base settings if config type has been left out [#100](https://github.com/yonaskolb/XcodeGen/pull/100) @yonaskolb - generate localised files under a single variant group [#70](https://github.com/yonaskolb/XcodeGen/pull/70) @ryohey +- don't apply common project settings to configs with no type [#100](https://github.com/yonaskolb/XcodeGen/pull/100) @yonaskolb +- config references in settings can now be partially matched and are case insensitive [#111](https://github.com/yonaskolb/XcodeGen/pull/111) @yonaskolb +- other small internal changes @yonaskolb ### Fixed - embed Carthage frameworks for macOS [#82](https://github.com/yonaskolb/XcodeGen/pull/82) @toshi0383 @@ -17,10 +24,9 @@ - change make build to a PHONY task [#98](https://github.com/yonaskolb/XcodeGen/pull/98) @keith - allow copying of resource files from dependant targets [#95](https://github.com/yonaskolb/XcodeGen/pull/95) @keith - fixed library linking [#93](https://github.com/yonaskolb/XcodeGen/pull/93) @keith +- fixed duplicate carthage file references [#107](https://github.com/yonaskolb/XcodeGen/pull/107) @yonaskolb - - - +[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.2.4...1.3.0) ## 1.2.4 From 4539ead7f99e4595856e4cb30fad5d2b515aa1d0 Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Fri, 27 Oct 2017 00:35:29 +0200 Subject: [PATCH 17/21] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2377bf8..392bf649 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - allow copying of resource files from dependant targets [#95](https://github.com/yonaskolb/XcodeGen/pull/95) @keith - fixed library linking [#93](https://github.com/yonaskolb/XcodeGen/pull/93) @keith - fixed duplicate carthage file references [#107](https://github.com/yonaskolb/XcodeGen/pull/107) @yonaskolb +- an error is now shown if you try and generate a target scheme and don't have debug and release builds @yonaskolb [Commits](https://github.com/yonaskolb/XcodeGen/compare/1.2.4...1.3.0) From d17099123d54ec832812a9a32bf48b5bfb987de1 Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Fri, 27 Oct 2017 00:39:32 +0200 Subject: [PATCH 18/21] update version --- Formula/xcodegen.rb | 4 ++-- Makefile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Formula/xcodegen.rb b/Formula/xcodegen.rb index 8cb16be6..b657f5e8 100644 --- a/Formula/xcodegen.rb +++ b/Formula/xcodegen.rb @@ -1,8 +1,8 @@ class Xcodegen < Formula desc "Tool that generates your Xcode project from a project spec" homepage "https://github.com/yonaskolb/XcodeGen" - url "https://github.com/yonaskolb/XcodeGen/archive/1.2.4.tar.gz" - sha256 "4490df6f2e1442a0817f1a7e8e2eb34c1f173f2c92405870e62de1de87a6772d" + url "https://github.com/yonaskolb/XcodeGen/archive/1.3.0.tar.gz" + sha256 "6a78b0eb6768122d0c71a8ceaba877f431cd1650bb5caa06b53c33a8cd512b20" head "https://github.com/yonaskolb/XcodeGen.git" depends_on :xcode diff --git a/Makefile b/Makefile index 3fc7958a..ebec0517 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ TOOL_NAME = XcodeGen -VERSION = 1.2.0 +VERSION = 1.3.0 PREFIX = /usr/local INSTALL_PATH = $(PREFIX)/bin/$(TOOL_NAME) From 770b502638e29ea306448953abe1864cf9026ec6 Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Fri, 27 Oct 2017 00:50:21 +0200 Subject: [PATCH 19/21] change target description --- Sources/ProjectSpec/Target.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/ProjectSpec/Target.swift b/Sources/ProjectSpec/Target.swift index 0037741e..d0277b98 100644 --- a/Sources/ProjectSpec/Target.swift +++ b/Sources/ProjectSpec/Target.swift @@ -47,7 +47,7 @@ public struct Target { extension Target: CustomStringConvertible { public var description: String { - return "\(platform.emoji) \(type): \(name)" + return "\(platform.emoji) \(name) - \(type)" } } From ac2a1ac2d6a46d833ce553882208131d575a5a1d Mon Sep 17 00:00:00 2001 From: mironal Date: Fri, 27 Oct 2017 11:45:18 +0900 Subject: [PATCH 20/21] add support --vesion option --- Sources/XcodeGen/main.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/XcodeGen/main.swift b/Sources/XcodeGen/main.swift index 30db7e1d..4a37ea08 100644 --- a/Sources/XcodeGen/main.swift +++ b/Sources/XcodeGen/main.swift @@ -15,6 +15,8 @@ import ProjectSpec import JSONUtilities import Rainbow +let version = "1.3.0" + func generate(spec: String, project: String) { let specPath = Path(spec).normalize() @@ -58,4 +60,4 @@ command( Option("spec", "project.yml", flag: "s", description: "The path to the spec file"), Option("project", "", flag: "p", description: "The path to the folder where the project should be generated"), generate) - .run() + .run(version) From a4471e839efba217b40771fb4f84dea7abe1b04c Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Tue, 24 Oct 2017 20:30:44 +0200 Subject: [PATCH 21/21] update to xcproj 1.2 --- .../GeneratedProject.xcodeproj/project.pbxproj | 15 --------------- Package.resolved | 4 ++-- Package.swift | 2 +- Sources/XcodeGenKit/PBXProjGenerator.swift | 8 ++++---- .../XcodeGenKitTests/ProjectGeneratorTests.swift | 3 ++- 5 files changed, 9 insertions(+), 23 deletions(-) diff --git a/Fixtures/TestProject/GeneratedProject.xcodeproj/project.pbxproj b/Fixtures/TestProject/GeneratedProject.xcodeproj/project.pbxproj index ce7e60b9..e3d1e4c9 100644 --- a/Fixtures/TestProject/GeneratedProject.xcodeproj/project.pbxproj +++ b/Fixtures/TestProject/GeneratedProject.xcodeproj/project.pbxproj @@ -1,6 +1,5 @@ // !$*UTF8*$! { - archiveVersion = 1; classes = { }; objectVersion = 46; @@ -44,13 +43,11 @@ /* Begin PBXCopyFilesBuildPhase section */ CFBP50493301 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( BF3862341101 /* MyFramework.framework in CopyFiles */, ); - runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ @@ -191,7 +188,6 @@ buildActionMask = 2147483647; files = ( ); - runOnlyForDeploymentPostprocessing = 0; }; HBP299349701 /* Frameworks */ = { isa = PBXHeadersBuildPhase; @@ -199,14 +195,12 @@ files = ( BF3515549501 /* MyFramework.h in Headers */, ); - runOnlyForDeploymentPostprocessing = 0; }; HBP652326301 /* Frameworks */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( ); - runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ @@ -297,14 +291,12 @@ buildActionMask = 2147483647; files = ( ); - runOnlyForDeploymentPostprocessing = 0; }; RBP299349701 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); - runOnlyForDeploymentPostprocessing = 0; }; RBP652326301 /* Resources */ = { isa = PBXResourcesBuildPhase; @@ -315,7 +307,6 @@ BF2513089601 /* LocalizedStoryboard.storyboard in Resources */, BF2250910101 /* Main.storyboard in Resources */, ); - runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ @@ -387,7 +378,6 @@ files = ( BF9001417701 /* TestProjectTests.swift in Sources */, ); - runOnlyForDeploymentPostprocessing = 0; }; SBP299349701 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -395,7 +385,6 @@ files = ( BF9155249601 /* FrameworkFile.swift in Sources */, ); - runOnlyForDeploymentPostprocessing = 0; }; SBP652326301 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -404,7 +393,6 @@ BF1073850101 /* AppDelegate.swift in Sources */, BF1744565901 /* ViewController.swift in Sources */, ); - runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ @@ -704,7 +692,6 @@ XCBC89077001 /* Debug */, XCBC60448901 /* Release */, ); - defaultConfigurationIsVisible = 0; defaultConfigurationName = ""; }; XCCL29934901 /* Build configuration list for PBXNativeTarget "MyFramework" */ = { @@ -713,7 +700,6 @@ XCBC19846901 /* Debug */, XCBC89204001 /* Release */, ); - defaultConfigurationIsVisible = 0; defaultConfigurationName = ""; }; XCCL65232601 /* Build configuration list for PBXNativeTarget "TestProject" */ = { @@ -722,7 +708,6 @@ XCBC37128501 /* Debug */, XCBC86437501 /* Release */, ); - defaultConfigurationIsVisible = 0; defaultConfigurationName = ""; }; XCCL81399401 /* Build configuration list for PBXProject "GeneratedProject" */ = { diff --git a/Package.resolved b/Package.resolved index 58535b03..0fd79d68 100644 --- a/Package.resolved +++ b/Package.resolved @@ -69,8 +69,8 @@ "repositoryURL": "https://github.com/xcodeswift/xcproj.git", "state": { "branch": null, - "revision": "cd1c329c6e092fdf5afbddf10dd59da564293aa6", - "version": "0.4.1" + "revision": "fc8cbfce8a6bc1a98773181afe8da97c2516b722", + "version": "1.2.0" } } ] diff --git a/Package.swift b/Package.swift index d1e588f1..2a7a0ff3 100644 --- a/Package.swift +++ b/Package.swift @@ -15,7 +15,7 @@ let package = Package( .package(url: "https://github.com/yonaskolb/JSONUtilities.git", from: "3.3.0"), .package(url: "https://github.com/kylef/Spectre.git", from: "0.7.0"), .package(url: "https://github.com/onevcat/Rainbow.git", from: "2.1.0"), - .package(url: "https://github.com/xcodeswift/xcproj.git", from: "0.1.2"), + .package(url: "https://github.com/xcodeswift/xcproj.git", from: "1.0.0"), ], targets: [ .target(name: "XcodeGen", dependencies: [ diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index 18e1f6ab..6a23b6d3 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -64,7 +64,7 @@ public class PBXProjGenerator { public func generate() throws -> PBXProj { uuids = [] - project = PBXProj(archiveVersion: 1, objectVersion: 46, rootObject: generateUUID(PBXProject.self, spec.name)) + project = PBXProj(objectVersion: 46, rootObject: generateUUID(PBXProject.self, spec.name)) for group in spec.fileGroups { _ = try getGroups(path: basePath + group) @@ -252,7 +252,7 @@ public class PBXProjGenerator { if dependencyTarget.type.isLibrary || dependencyTarget.type.isFramework { let dependencyBuildFile = targetBuildFiles[dependencyTargetName]! - let buildFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, dependencyBuildFile.reference + target.name), fileRef: dependencyBuildFile.fileRef) + let buildFile = PBXBuildFile(reference: generateUUID(PBXBuildFile.self, dependencyBuildFile.reference + target.name), fileRef: dependencyBuildFile.fileRef!) addObject(buildFile) targetFrameworkBuildFiles.append(buildFile.reference) } @@ -430,11 +430,11 @@ public class PBXProjGenerator { let nativeTarget = PBXNativeTarget( reference: targetNativeReferences[target.name]!, + name: target.name, buildConfigurationList: buildConfigList.reference, buildPhases: buildPhases, buildRules: [], dependencies: dependencies, - name: target.name, productReference: fileReference, productType: target.type) addObject(nativeTarget) @@ -553,7 +553,7 @@ public class PBXProjGenerator { // find base localisation variant group let name = path.lastComponentWithoutExtension - let variantGroup = baseLocalisationVariantGroups.first { Path($0.name).lastComponentWithoutExtension == name } + let variantGroup = baseLocalisationVariantGroups.first { Path($0.name!).lastComponentWithoutExtension == name } let fileReference: String if let cachedFileReference = fileReferencesByPath[path] { diff --git a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift index 26268719..2e5ca360 100644 --- a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift @@ -34,7 +34,8 @@ func projectGeneratorTests() { let spec = ProjectSpec(name: "test", targets: [framework], options: options) let project = try getProject(spec) guard let target = project.pbxproj.nativeTargets.first, - let buildConfigs = project.pbxproj.configurationLists.getReference(target.buildConfigurationList), + let buildConfigList = target.buildConfigurationList, + let buildConfigs = project.pbxproj.configurationLists.getReference(buildConfigList), let buildConfigReference = buildConfigs.buildConfigurations.first, let buildConfig = project.pbxproj.buildConfigurations.getReference(buildConfigReference) else { throw failure("Build Config not found")