mirror of
https://github.com/yonaskolb/XcodeGen.git
synced 2024-11-10 14:51:04 +03:00
Merge pull request #103 from yonaskolb/spec_base_path
Move basePath into ProjectSpec
This commit is contained in:
commit
6e795fbc3c
@ -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
|
||||
|
@ -38,7 +38,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")
|
||||
|
||||
|
@ -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<T: PBXObject>(_ 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
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user