mirror of
https://github.com/yonaskolb/XcodeGen.git
synced 2026-03-18 20:02:25 +00:00
refactored
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// ProjectExtensions.swift
|
||||
// XcodeGen
|
||||
//
|
||||
// Created by Yonas Kolb on 19/7/17.
|
||||
//
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import xcodeproj
|
||||
|
||||
extension Array where Element: ProjectElement {
|
||||
|
||||
var referenceList: [String] {
|
||||
return map { $0.reference }
|
||||
}
|
||||
|
||||
var referenceSet: Set<String> {
|
||||
return Set(referenceList)
|
||||
}
|
||||
}
|
||||
@@ -11,15 +11,24 @@ import PathKit
|
||||
import xcodeproj
|
||||
import xcodeprojprotocols
|
||||
|
||||
public struct Generator {
|
||||
public class ProjectGenerator {
|
||||
|
||||
public static func generate(spec: Spec, path: Path) throws {
|
||||
let spec: Spec
|
||||
let path: Path
|
||||
|
||||
public init(spec: Spec, path: Path) {
|
||||
self.spec = spec
|
||||
self.path = path
|
||||
}
|
||||
|
||||
public func generate() throws -> XcodeProj {
|
||||
|
||||
let workspaceReferences: [XCWorkspace.Data.FileRef] = [XCWorkspace.Data.FileRef.project(path: path)]
|
||||
let workspaceData = XCWorkspace.Data(path: path + "project.xcworkspace/contents.xcworkspacedata", references: workspaceReferences)
|
||||
let workspace = XCWorkspace(path: path + "project.xcworkspace", data: workspaceData)
|
||||
|
||||
var objects: [PBXObject] = []
|
||||
var groupsByPath: [String: String] = [:]
|
||||
var ids = 0
|
||||
|
||||
func id() -> String {
|
||||
@@ -28,47 +37,77 @@ public struct Generator {
|
||||
// return "OBJECT_\(ids)"
|
||||
}
|
||||
|
||||
let mainGroup = PBXGroup(reference: id(), children: [], sourceTree: .group)
|
||||
|
||||
let buildConfigs = spec.configs.map { config in
|
||||
|
||||
XCBuildConfiguration(reference: id(), name: config.name, baseConfigurationReference: nil, buildSettings: BuildSettings(dictionary: config.settings))
|
||||
}
|
||||
let buildConfigList = XCConfigurationList(reference: id(), buildConfigurations: Set(buildConfigs.map { $0.reference }), defaultConfigurationName: buildConfigs.first?.name ?? "", defaultConfigurationIsVisible: 0)
|
||||
let buildConfigList = XCConfigurationList(reference: id(), buildConfigurations: buildConfigs.referenceSet, defaultConfigurationName: buildConfigs.first?.name ?? "", defaultConfigurationIsVisible: 0)
|
||||
|
||||
|
||||
objects += buildConfigs.map { .xcBuildConfiguration($0) }
|
||||
objects.append(.xcConfigurationList(buildConfigList))
|
||||
|
||||
|
||||
var groups: [PBXGroup] = []
|
||||
var fileReferences: [PBXFileReference] = []
|
||||
var topLevelGroups: [PBXGroup] = []
|
||||
|
||||
func getGroup(path: Path) throws -> PBXGroup {
|
||||
|
||||
let directories = try path.children().filter { $0.isDirectory }
|
||||
let files = try path.children().filter { $0.isFile }
|
||||
var children: [String] = []
|
||||
|
||||
for path in files {
|
||||
let fileReference = PBXFileReference(reference: id(), sourceTree: .group, path: path.lastComponent)
|
||||
fileReferences.append(fileReference)
|
||||
children.append(fileReference.reference)
|
||||
}
|
||||
|
||||
for path in directories {
|
||||
let group = try getGroup(path: path)
|
||||
children.append(group.reference)
|
||||
}
|
||||
|
||||
let group = PBXGroup(reference: id(), children: Set(children), sourceTree: .group, name: path.lastComponent, path: path.lastComponent)
|
||||
groups.append(group)
|
||||
return group
|
||||
}
|
||||
|
||||
var targets: [String] = []
|
||||
for target in spec.targets {
|
||||
let sourcePaths: [Path] = try target.sources.reduce([]) { paths, source in
|
||||
// $0 + spec.path.parent().glob($1)
|
||||
let sourcePaths = spec.path.parent() + source
|
||||
let sourceFiles = try sourcePaths.recursiveChildren().filter { $0.isFile }
|
||||
return paths + sourceFiles
|
||||
}
|
||||
let fileReferences = sourcePaths.map { PBXFileReference(reference: id(), sourceTree: .group, path: $0.lastComponent) }
|
||||
let buildFiles = fileReferences.map { PBXBuildFile(reference: id(), fileRef: $0.reference) }
|
||||
let buildPhase = PBXSourcesBuildPhase(reference: id(), files: Set(buildFiles.map { $0.reference }))
|
||||
let buildPhases = [buildPhase]
|
||||
let source = spec.path.parent() + target.sources.first!
|
||||
|
||||
let productReference = PBXFileReference(reference: id(), sourceTree: .buildProductsDir, path: target.name, includeInIndex: 0)
|
||||
|
||||
let buildConfigList = XCConfigurationList(reference: id(), buildConfigurations: [], defaultConfigurationName: "")
|
||||
let nativeTarget = PBXNativeTarget(reference: id(), buildConfigurationList: buildConfigList.reference, buildPhases: buildPhases.map{ $0.reference }, buildRules: [], dependencies: [], name: target.name, productReference: productReference.reference, productType: target.type)
|
||||
|
||||
objects += buildFiles.map { .pbxBuildFile($0) }
|
||||
groups = []
|
||||
fileReferences = []
|
||||
let sourceGroup = try getGroup(path: source)
|
||||
topLevelGroups.append(sourceGroup)
|
||||
objects += groups.map { .pbxGroup($0) }
|
||||
objects += fileReferences.map { .pbxFileReference($0) }
|
||||
|
||||
let buildFiles = fileReferences.map { PBXBuildFile(reference: id(), fileRef: $0.reference) }
|
||||
objects += buildFiles.map { .pbxBuildFile($0) }
|
||||
let buildPhase = PBXSourcesBuildPhase(reference: id(), files: buildFiles.referenceSet)
|
||||
let buildPhases = [buildPhase]
|
||||
objects += buildPhases.map { .pbxSourcesBuildPhase($0) }
|
||||
|
||||
|
||||
let buildConfigList = XCConfigurationList(reference: id(), buildConfigurations: [], defaultConfigurationName: "")
|
||||
objects.append(.xcConfigurationList(buildConfigList))
|
||||
objects.append(.pbxNativeTarget(nativeTarget))
|
||||
|
||||
|
||||
let productReference = PBXFileReference(reference: id(), sourceTree: .buildProductsDir, path: target.name, includeInIndex: 0)
|
||||
objects.append(.pbxFileReference(productReference))
|
||||
|
||||
let nativeTarget = PBXNativeTarget(reference: id(), buildConfigurationList: buildConfigList.reference, buildPhases: buildPhases.referenceList, buildRules: [], dependencies: [], name: target.name, productReference: productReference.reference, productType: target.type)
|
||||
objects.append(.pbxNativeTarget(nativeTarget))
|
||||
|
||||
targets.append(nativeTarget.reference)
|
||||
}
|
||||
|
||||
let mainGroup = PBXGroup(reference: id(), children: topLevelGroups.referenceSet, sourceTree: .group)
|
||||
objects.append(.pbxGroup(mainGroup))
|
||||
|
||||
let pbxProjectRoot = PBXProject(reference: id(), buildConfigurationList: buildConfigList.reference, compatibilityVersion: "Xcode 3.2", mainGroup: mainGroup.reference, targets: targets)
|
||||
objects.append(.pbxProject(pbxProjectRoot))
|
||||
|
||||
@@ -87,7 +126,7 @@ public struct Generator {
|
||||
let sharedData = XCSharedData(path: path + "xcshareddata", schemes: schemes)
|
||||
let project = XcodeProj(path: path, workspace: workspace, pbxproj: pbxProject, sharedData: sharedData)
|
||||
|
||||
try project.write(override: true)
|
||||
return project
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
//
|
||||
// Spec.swift
|
||||
// XcodeGen
|
||||
//
|
||||
// Created by Yonas Kolb on 19/5/17.
|
||||
//
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import xcodeproj
|
||||
import JSONUtilities
|
||||
import PathKit
|
||||
import Yams
|
||||
|
||||
extension Spec {
|
||||
|
||||
public init(path: Path) throws {
|
||||
var url = URL(string: path.string)!
|
||||
if url.scheme == nil {
|
||||
url = URL(fileURLWithPath: path.string)
|
||||
}
|
||||
|
||||
let data = try Data(contentsOf: url)
|
||||
let string = String(data: data, encoding: .utf8)!
|
||||
|
||||
try self.init(path: path, string: string)
|
||||
}
|
||||
|
||||
public init(path: Path, string: String) throws {
|
||||
let yaml = try Yams.load(yaml: string)
|
||||
let json = yaml as! JSONDictionary
|
||||
|
||||
try self.init(path: path, jsonDictionary: json)
|
||||
}
|
||||
|
||||
public init(path: Path, jsonDictionary: JSONDictionary) throws {
|
||||
self.path = path
|
||||
settingGroups = try jsonDictionary.json(atKeyPath: "settingGroups")
|
||||
configs = try jsonDictionary.json(atKeyPath: "configs")
|
||||
targets = try jsonDictionary.json(atKeyPath: "targets")
|
||||
schemes = try jsonDictionary.json(atKeyPath: "schemes")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct Spec {
|
||||
|
||||
public var settingGroups: [BuildSettingGroup]
|
||||
public var configs: [Config]
|
||||
public var targets: [TargetSpec]
|
||||
public var schemes: [SchemeSpec]
|
||||
public var path: Path
|
||||
}
|
||||
|
||||
public struct TargetSpec {
|
||||
public var name: String
|
||||
public var type: PBXProductType
|
||||
public var localizedSource: String?
|
||||
public var sources: [String]
|
||||
public var sourceExludes: [String]
|
||||
public var dependancies: [Dependancy]
|
||||
public var prebuildScripts: [String]
|
||||
public var postbuildScripts: [String]
|
||||
}
|
||||
|
||||
extension TargetSpec: NamedJSONObjectConvertible {
|
||||
|
||||
public init(name: String, jsonDictionary: JSONDictionary) throws {
|
||||
self.name = name
|
||||
let typeString: String = try jsonDictionary.json(atKeyPath: "type")
|
||||
if let type = PBXProductType(rawValue: typeString) {
|
||||
self.type = type
|
||||
} else {
|
||||
switch typeString {
|
||||
case "application": type = .application
|
||||
case "framework": type = .framework
|
||||
default: throw SpecError.unknownTargetType(typeString)
|
||||
}
|
||||
}
|
||||
sources = jsonDictionary.json(atKeyPath: "sources") ?? []
|
||||
sourceExludes = jsonDictionary.json(atKeyPath: "sourceExludes") ?? []
|
||||
dependancies = jsonDictionary.json(atKeyPath: "dependancies") ?? []
|
||||
prebuildScripts = jsonDictionary.json(atKeyPath: "prebuildScripts") ?? []
|
||||
postbuildScripts = jsonDictionary.json(atKeyPath: "postbuildScripts") ?? []
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct Dependancy {
|
||||
|
||||
public var path: String
|
||||
public var type: DependancyType
|
||||
|
||||
public enum DependancyType: String {
|
||||
case target
|
||||
case system
|
||||
}
|
||||
}
|
||||
|
||||
extension Dependancy: JSONObjectConvertible {
|
||||
|
||||
public init(jsonDictionary: JSONDictionary) throws {
|
||||
path = try jsonDictionary.json(atKeyPath: "path")
|
||||
type = try jsonDictionary.json(atKeyPath: "type")
|
||||
}
|
||||
}
|
||||
|
||||
public struct Config {
|
||||
public var name: String
|
||||
public var buildSettingGroups: [BuildSettingGroup]
|
||||
public var settings: [String: String]
|
||||
}
|
||||
|
||||
extension Config: NamedJSONObjectConvertible {
|
||||
|
||||
public init(name: String, jsonDictionary: JSONDictionary) throws {
|
||||
self.name = name
|
||||
buildSettingGroups = try jsonDictionary.json(atKeyPath: "settingGroups")
|
||||
settings = jsonDictionary.json(atKeyPath: "settings") ?? [:]
|
||||
}
|
||||
}
|
||||
|
||||
public struct BuildSettingGroup {
|
||||
public var name: String
|
||||
public var buildSettings: [String: String]
|
||||
}
|
||||
|
||||
extension BuildSettingGroup: NamedJSONObjectConvertible {
|
||||
|
||||
public init(name: String, jsonDictionary: JSONDictionary) throws {
|
||||
self.name = name
|
||||
buildSettings = [:]
|
||||
for (key, value) in jsonDictionary {
|
||||
buildSettings[key] = String(describing: value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// BuildSettings.swift
|
||||
// XcodeGen
|
||||
//
|
||||
// Created by Yonas Kolb on 20/7/17.
|
||||
//
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import xcodeproj
|
||||
import JSONUtilities
|
||||
|
||||
public struct BuildSettingGroup {
|
||||
public var name: String
|
||||
public var buildSettings: [String: String]
|
||||
}
|
||||
|
||||
extension BuildSettingGroup: NamedJSONObjectConvertible {
|
||||
|
||||
public init(name: String, jsonDictionary: JSONDictionary) throws {
|
||||
self.name = name
|
||||
buildSettings = [:]
|
||||
for (key, value) in jsonDictionary {
|
||||
buildSettings[key] = String(describing: value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// Config.swift
|
||||
// XcodeGen
|
||||
//
|
||||
// Created by Yonas Kolb on 20/7/17.
|
||||
//
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import xcodeproj
|
||||
import JSONUtilities
|
||||
|
||||
public struct Config {
|
||||
public var name: String
|
||||
public var buildSettingGroups: [BuildSettingGroup]
|
||||
public var settings: [String: String]
|
||||
}
|
||||
|
||||
extension Config: NamedJSONObjectConvertible {
|
||||
|
||||
public init(name: String, jsonDictionary: JSONDictionary) throws {
|
||||
self.name = name
|
||||
buildSettingGroups = try jsonDictionary.json(atKeyPath: "settingGroups")
|
||||
settings = jsonDictionary.json(atKeyPath: "settings") ?? [:]
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import Foundation
|
||||
import xcodeproj
|
||||
import JSONUtilities
|
||||
|
||||
public struct SchemeSpec {
|
||||
public struct Scheme {
|
||||
|
||||
public var name: String
|
||||
public var build: Build
|
||||
@@ -25,7 +25,7 @@ public struct SchemeSpec {
|
||||
}
|
||||
}
|
||||
|
||||
extension SchemeSpec: NamedJSONObjectConvertible {
|
||||
extension Scheme: NamedJSONObjectConvertible {
|
||||
|
||||
public init(name: String, jsonDictionary: JSONDictionary) throws {
|
||||
self.name = name
|
||||
@@ -33,14 +33,14 @@ extension SchemeSpec: NamedJSONObjectConvertible {
|
||||
}
|
||||
}
|
||||
|
||||
extension SchemeSpec.Build: JSONObjectConvertible {
|
||||
extension Scheme.Build: JSONObjectConvertible {
|
||||
|
||||
public init(jsonDictionary: JSONDictionary) throws {
|
||||
entries = try jsonDictionary.json(atKeyPath: "targets")
|
||||
}
|
||||
}
|
||||
|
||||
extension SchemeSpec.BuildEntry: NamedJSONObjectConvertible {
|
||||
extension Scheme.BuildEntry: NamedJSONObjectConvertible {
|
||||
|
||||
public init(name: String, jsonDictionary: JSONDictionary) throws {
|
||||
target = name
|
||||
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// Spec.swift
|
||||
// XcodeGen
|
||||
//
|
||||
// Created by Yonas Kolb on 19/5/17.
|
||||
//
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import xcodeproj
|
||||
import JSONUtilities
|
||||
import PathKit
|
||||
import Yams
|
||||
|
||||
extension Spec {
|
||||
|
||||
public init(path: Path) throws {
|
||||
var url = URL(string: path.string)!
|
||||
if url.scheme == nil {
|
||||
url = URL(fileURLWithPath: path.string)
|
||||
}
|
||||
|
||||
let data = try Data(contentsOf: url)
|
||||
let string = String(data: data, encoding: .utf8)!
|
||||
|
||||
try self.init(path: path, string: string)
|
||||
}
|
||||
|
||||
public init(path: Path, string: String) throws {
|
||||
let yaml = try Yams.load(yaml: string)
|
||||
let json = yaml as! JSONDictionary
|
||||
|
||||
try self.init(path: path, jsonDictionary: json)
|
||||
}
|
||||
|
||||
public init(path: Path, jsonDictionary: JSONDictionary) throws {
|
||||
self.path = path
|
||||
settingGroups = try jsonDictionary.json(atKeyPath: "settingGroups")
|
||||
configs = try jsonDictionary.json(atKeyPath: "configs")
|
||||
targets = try jsonDictionary.json(atKeyPath: "targets")
|
||||
schemes = try jsonDictionary.json(atKeyPath: "schemes")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct Spec {
|
||||
|
||||
public var settingGroups: [BuildSettingGroup]
|
||||
public var configs: [Config]
|
||||
public var targets: [Target]
|
||||
public var schemes: [Scheme]
|
||||
public var path: Path
|
||||
}
|
||||
|
||||
|
||||
public struct Dependancy {
|
||||
|
||||
public var path: String
|
||||
public var type: DependancyType
|
||||
|
||||
public enum DependancyType: String {
|
||||
case target
|
||||
case system
|
||||
}
|
||||
}
|
||||
|
||||
extension Dependancy: JSONObjectConvertible {
|
||||
|
||||
public init(jsonDictionary: JSONDictionary) throws {
|
||||
path = try jsonDictionary.json(atKeyPath: "path")
|
||||
type = try jsonDictionary.json(atKeyPath: "type")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Target.swift
|
||||
// XcodeGen
|
||||
//
|
||||
// Created by Yonas Kolb on 20/7/17.
|
||||
//
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import xcodeproj
|
||||
import JSONUtilities
|
||||
|
||||
public struct Target {
|
||||
public var name: String
|
||||
public var type: PBXProductType
|
||||
public var localizedSource: String?
|
||||
public var sources: [String]
|
||||
public var sourceExludes: [String]
|
||||
public var dependancies: [Dependancy]
|
||||
public var prebuildScripts: [String]
|
||||
public var postbuildScripts: [String]
|
||||
}
|
||||
|
||||
extension Target: NamedJSONObjectConvertible {
|
||||
|
||||
public init(name: String, jsonDictionary: JSONDictionary) throws {
|
||||
self.name = name
|
||||
let typeString: String = try jsonDictionary.json(atKeyPath: "type")
|
||||
if let type = PBXProductType(rawValue: typeString) {
|
||||
self.type = type
|
||||
} else {
|
||||
switch typeString {
|
||||
case "application": type = .application
|
||||
case "framework": type = .framework
|
||||
default: throw SpecError.unknownTargetType(typeString)
|
||||
}
|
||||
}
|
||||
sources = jsonDictionary.json(atKeyPath: "sources") ?? []
|
||||
sourceExludes = jsonDictionary.json(atKeyPath: "sourceExludes") ?? []
|
||||
dependancies = jsonDictionary.json(atKeyPath: "dependancies") ?? []
|
||||
prebuildScripts = jsonDictionary.json(atKeyPath: "prebuildScripts") ?? []
|
||||
postbuildScripts = jsonDictionary.json(atKeyPath: "postbuildScripts") ?? []
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user