wrap long lines

This commit is contained in:
Yonas Kolb 2017-12-26 18:47:18 +08:00
parent e75b1c1e89
commit 75e0644b99
20 changed files with 673 additions and 207 deletions

View File

@ -25,8 +25,8 @@ uninstall:
rm -rf $(SHARE_PATH)
format_code:
swiftformat Tests --stripunusedargs closure-only --header strip
swiftformat Sources --stripunusedargs closure-only --header strip
swiftformat Tests --wraparguments beforefirst --stripunusedargs closure-only --header strip
swiftformat Sources --wraparguments beforefirst --stripunusedargs closure-only --header strip
update_brew:
sed -i '' 's|\(url ".*/archive/\)\(.*\)\(.tar\)|\1$(VERSION)\3|' Formula/xcodegen.rb

View File

@ -23,7 +23,14 @@ public struct BuildScript: Equatable {
}
}
public init(script: ScriptType, name: String? = nil, inputFiles: [String] = [], outputFiles: [String] = [], shell: String? = nil, runOnlyWhenInstalling: Bool = false) {
public init(
script: ScriptType,
name: String? = nil,
inputFiles: [String] = [],
outputFiles: [String] = [],
shell: String? = nil,
runOnlyWhenInstalling: Bool = false
) {
self.script = script
self.name = name
self.inputFiles = inputFiles

View File

@ -12,7 +12,13 @@ public struct Dependency: Equatable {
public var link: Bool = true
public var implicit: Bool = false
public init(type: DependencyType, reference: String, embed: Bool? = nil, link: Bool = true, implicit: Bool = false) {
public init(
type: DependencyType,
reference: String,
embed: Bool? = nil,
link: Bool = true,
implicit: Bool = false
) {
self.type = type
self.reference = reference
self.embed = embed

View File

@ -9,7 +9,12 @@ public struct DeploymentTarget: Equatable {
public var watchOS: Version?
public var macOS: Version?
public init(iOS: Version? = nil, tvOS: Version? = nil, watchOS: Version? = nil, macOS: Version? = nil) {
public init(
iOS: Version? = nil,
tvOS: Version? = nil,
watchOS: Version? = nil,
macOS: Version? = nil
) {
self.iOS = iOS
self.tvOS = tvOS
self.watchOS = watchOS

View File

@ -52,7 +52,18 @@ public struct ProjectSpec {
}
}
public init(carthageBuildPath: String? = nil, createIntermediateGroups: Bool = false, bundleIdPrefix: String? = nil, settingPresets: SettingPresets = .all, developmentLanguage: String? = nil, indentWidth: Int? = nil, tabWidth: Int? = nil, usesTabs: Bool? = nil, xcodeVersion: String? = nil, deploymentTarget: DeploymentTarget = .init()) {
public init(
carthageBuildPath: String? = nil,
createIntermediateGroups: Bool = false,
bundleIdPrefix: String? = nil,
settingPresets: SettingPresets = .all,
developmentLanguage: String? = nil,
indentWidth: Int? = nil,
tabWidth: Int? = nil,
usesTabs: Bool? = nil,
xcodeVersion: String? = nil,
deploymentTarget: DeploymentTarget = .init()
) {
self.carthageBuildPath = carthageBuildPath
self.createIntermediateGroups = createIntermediateGroups
self.bundleIdPrefix = bundleIdPrefix
@ -79,7 +90,19 @@ public struct ProjectSpec {
}
}
public init(basePath: Path, name: String, configs: [Config] = Config.defaultConfigs, 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] = Config.defaultConfigs,
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
@ -112,7 +135,10 @@ extension ProjectSpec: CustomDebugStringConvertible {
}
if !settingGroups.isEmpty {
string += "\nSetting Groups:\n\(indent)" + settingGroups.keys.sorted().map { "⚙️ \($0)" }.joined(separator: "\n\(indent)")
string += "\nSetting Groups:\n\(indent)" + settingGroups.keys
.sorted()
.map { "⚙️ \($0)" }
.joined(separator: "\n\(indent)")
}
if !targets.isEmpty {
@ -146,9 +172,11 @@ extension ProjectSpec {
let jsonDictionary = try ProjectSpec.filterJSON(jsonDictionary: jsonDictionary)
name = try jsonDictionary.json(atKeyPath: "name")
settings = jsonDictionary.json(atKeyPath: "settings") ?? .empty
settingGroups = jsonDictionary.json(atKeyPath: "settingGroups") ?? jsonDictionary.json(atKeyPath: "settingPresets") ?? [:]
settingGroups = jsonDictionary.json(atKeyPath: "settingGroups")
?? jsonDictionary.json(atKeyPath: "settingPresets") ?? [:]
let configs: [String: String] = jsonDictionary.json(atKeyPath: "configs") ?? [:]
self.configs = configs.isEmpty ? Config.defaultConfigs : configs.map { Config(name: $0, type: ConfigType(rawValue: $1)) }.sorted { $0.name < $1.name }
self.configs = configs.isEmpty ? Config.defaultConfigs :
configs.map { Config(name: $0, type: ConfigType(rawValue: $1)) }.sorted { $0.name < $1.name }
targets = try jsonDictionary.json(atKeyPath: "targets").sorted { $0.name < $1.name }
schemes = try jsonDictionary.json(atKeyPath: "schemes")
fileGroups = jsonDictionary.json(atKeyPath: "fileGroups") ?? []

View File

@ -14,7 +14,15 @@ public struct Scheme: Equatable {
public var test: Test?
public var profile: Profile?
public init(name: String, build: Build, run: Run? = nil, test: Test? = nil, profile: Profile? = nil, analyze: Analyze? = nil, archive: Archive? = nil) {
public init(
name: String,
build: Build,
run: Run? = nil,
test: Test? = nil,
profile: Profile? = nil,
analyze: Analyze? = nil,
archive: Archive? = nil
) {
self.name = name
self.build = build
self.run = run
@ -55,7 +63,12 @@ public struct Scheme: Equatable {
public var commandLineArguments: [String: Bool]
public var targets: [String]
public init(config: String, gatherCoverageData: Bool = false, commandLineArguments: [String: Bool] = [:], targets: [String] = []) {
public init(
config: String,
gatherCoverageData: Bool = false,
commandLineArguments: [String: Bool] = [:],
targets: [String] = []
) {
self.config = config
self.gatherCoverageData = gatherCoverageData
self.commandLineArguments = commandLineArguments

View File

@ -9,11 +9,16 @@ public enum SpecParsingError: Error, CustomStringConvertible {
public var description: String {
switch self {
case let .unknownTargetType(type): return "Unknown Target type: \(type)"
case let .unknownTargetPlatform(platform): return "Unknown Target platform: \(platform)"
case let .invalidDependency(dependency): return "Unknown Target dependency: \(dependency)"
case let .unknownSourceBuildPhase(buildPhase): return "Unknown Source Build Phase: \(buildPhase)"
case let .invalidVersion(version): return "Invalid version: \(version)"
case let .unknownTargetType(type):
return "Unknown Target type: \(type)"
case let .unknownTargetPlatform(platform):
return "Unknown Target platform: \(platform)"
case let .invalidDependency(dependency):
return "Unknown Target dependency: \(dependency)"
case let .unknownSourceBuildPhase(buildPhase):
return "Unknown Source Build Phase: \(buildPhase)"
case let .invalidVersion(version):
return "Invalid version: \(version)"
}
}
}

View File

@ -72,10 +72,18 @@ extension ProjectSpec {
for configVariant in scheme.configVariants {
if !configs.contains(where: { $0.name.contains(configVariant) && $0.type == .debug }) {
errors.append(.invalidTargetSchemeConfigVariant(target: target.name, configVariant: configVariant, configType: .debug))
errors.append(.invalidTargetSchemeConfigVariant(
target: target.name,
configVariant: configVariant,
configType: .debug
))
}
if !configs.contains(where: { $0.name.contains(configVariant) && $0.type == .release }) {
errors.append(.invalidTargetSchemeConfigVariant(target: target.name, configVariant: configVariant, configType: .release))
errors.append(.invalidTargetSchemeConfigVariant(
target: target.name,
configVariant: configVariant,
configType: .release
))
}
}

View File

@ -22,20 +22,34 @@ public struct SpecValidationError: Error, CustomStringConvertible {
public var description: String {
switch self {
case let .invalidTargetDependency(target, dependency): return "Target \(target.quoted) has invalid dependency: \(dependency.quoted)"
case let .invalidTargetConfigFile(target, configFile, config): return "Target \(target.quoted) has invalid config file \(configFile.quoted) for config \(config.quoted)"
case let .invalidTargetSource(target, source): return "Target \(target.quoted) has a missing source directory \(source.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 .invalidConfigFile(configFile, config): return "Invalid config file \(configFile.quoted) for config \(config.quoted)"
case let .invalidSchemeTarget(scheme, target): return "Scheme \(scheme.quoted) has invalid build target \(target.quoted)"
case let .invalidSchemeConfig(scheme, config): return "Scheme \(scheme.quoted) has invalid build configuration \(config.quoted)"
case let .invalidBuildSettingConfig(config): return "Build setting has invalid build configuration \(config.quoted)"
case let .invalidSettingsGroup(group): return "Invalid settings group \(group.quoted)"
case let .invalidBuildScriptPath(target, name, path): return "Target \(target.quoted) has a script \(name != nil ? "\(name!.quoted) which has a " : "")path that doesn't exist \(path.quoted)"
case let .invalidFileGroup(group): return "Invalid file group \(group.quoted)"
case let .invalidConfigFileConfig(config): return "Config file has invalid config \(config.quoted)"
case let .missingConfigTypeForGeneratedTargetScheme(target, configType): return "Target \(target.quoted) is missing a config of type \(configType.rawValue) to generate its scheme"
case let .invalidTargetDependency(target, dependency):
return "Target \(target.quoted) has invalid dependency: \(dependency.quoted)"
case let .invalidTargetConfigFile(target, configFile, config):
return "Target \(target.quoted) has invalid config file \(configFile.quoted) for config \(config.quoted)"
case let .invalidTargetSource(target, source):
return "Target \(target.quoted) has a missing source directory \(source.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 .invalidConfigFile(configFile, config):
return "Invalid config file \(configFile.quoted) for config \(config.quoted)"
case let .invalidSchemeTarget(scheme, target):
return "Scheme \(scheme.quoted) has invalid build target \(target.quoted)"
case let .invalidSchemeConfig(scheme, config):
return "Scheme \(scheme.quoted) has invalid build configuration \(config.quoted)"
case let .invalidBuildSettingConfig(config):
return "Build setting has invalid build configuration \(config.quoted)"
case let .invalidSettingsGroup(group):
return "Invalid settings group \(group.quoted)"
case let .invalidBuildScriptPath(target, name, path):
return "Target \(target.quoted) has a script \(name != nil ? "\(name!.quoted) which has a " : "")path that doesn't exist \(path.quoted)"
case let .invalidFileGroup(group):
return "Invalid file group \(group.quoted)"
case let .invalidConfigFileConfig(config):
return "Config file has invalid config \(config.quoted)"
case let .missingConfigTypeForGeneratedTargetScheme(target, configType):
return "Target \(target.quoted) is missing a config of type \(configType.rawValue) to generate its scheme"
}
}
}

View File

@ -44,7 +44,20 @@ public struct Target {
return name
}
public init(name: String, type: PBXProductType, platform: Platform, deploymentTarget: Version? = nil, settings: Settings = .empty, configFiles: [String: String] = [:], sources: [TargetSource] = [], dependencies: [Dependency] = [], prebuildScripts: [BuildScript] = [], postbuildScripts: [BuildScript] = [], scheme: TargetScheme? = nil, legacy: LegacyTarget? = nil) {
public init(
name: String,
type: PBXProductType,
platform: Platform,
deploymentTarget: Version? = nil,
settings: Settings = .empty,
configFiles: [String: String] = [:],
sources: [TargetSource] = [],
dependencies: [Dependency] = [],
prebuildScripts: [BuildScript] = [],
postbuildScripts: [BuildScript] = [],
scheme: TargetScheme? = nil,
legacy: LegacyTarget? = nil
) {
self.name = name
self.type = type
self.platform = platform
@ -158,7 +171,12 @@ public struct TargetScheme {
public var gatherCoverageData: Bool
public var commandLineArguments: [String: Bool]
public init(testTargets: [String] = [], configVariants: [String] = [], gatherCoverageData: Bool = false, commandLineArguments: [String: Bool] = [:]) {
public init(
testTargets: [String] = [],
configVariants: [String] = [],
gatherCoverageData: Bool = false,
commandLineArguments: [String: Bool] = [:]
) {
self.testTargets = testTargets
self.configVariants = configVariants
self.gatherCoverageData = gatherCoverageData

View File

@ -35,7 +35,15 @@ public struct TargetSource {
case folder
}
public init(path: String, name: String? = nil, compilerFlags: [String] = [], excludes: [String] = [], type: SourceType? = nil, optional: Bool = false, buildPhase: BuildPhase? = nil) {
public init(
path: String,
name: String? = nil,
compilerFlags: [String] = [],
excludes: [String] = [],
type: SourceType? = nil,
optional: Bool = false,
buildPhase: BuildPhase? = nil
) {
self.path = path
self.name = name
self.compilerFlags = compilerFlags

View File

@ -55,9 +55,29 @@ func generate(spec: String, project: String, isQuiet: Bool, justVersion: Bool) {
}
command(
Option<String>("spec", default: "project.yml", flag: "s", description: "The path to the spec file"),
Option<String>("project", default: "", flag: "p", description: "The path to the folder where the project should be generated"),
Flag("quiet", default: false, flag: "q", description: "Suppress printing of informational and success messages"),
Flag("version", default: false, flag: "v", description: "Show XcodeGen version"),
Option<String>(
"spec",
default: "project.yml",
flag: "s",
description: "The path to the spec file"
),
Option<String>(
"project",
default: "",
flag: "p",
description: "The path to the folder where the project should be generated"
),
Flag(
"quiet",
default: false,
flag: "q",
description: "Suppress printing of informational and success messages"
),
Flag(
"version",
default: false,
flag: "v",
description: "Show XcodeGen version"
),
generate
).run(version)

View File

@ -54,10 +54,20 @@ public class PBXProjGenerator {
if let configPath = spec.configFiles[config.name] {
baseConfigurationReference = sourceGenerator.getContainedFileReference(path: spec.basePath + configPath)
}
return XCBuildConfiguration(reference: referenceGenerator.generate(XCBuildConfiguration.self, config.name), name: config.name, baseConfigurationReference: baseConfigurationReference, buildSettings: buildSettings)
return XCBuildConfiguration(
reference: referenceGenerator.generate(XCBuildConfiguration.self, config.name),
name: config.name,
baseConfigurationReference: baseConfigurationReference,
buildSettings: buildSettings
)
}
let buildConfigList = XCConfigurationList(reference: referenceGenerator.generate(XCConfigurationList.self, spec.name), buildConfigurations: buildConfigs.references, defaultConfigurationName: buildConfigs.first?.name ?? "", defaultConfigurationIsVisible: 0)
let buildConfigList = XCConfigurationList(
reference: referenceGenerator.generate(XCConfigurationList.self, spec.name),
buildConfigurations: buildConfigs.references,
defaultConfigurationName: buildConfigs.first?.name ?? "",
defaultConfigurationIsVisible: 0
)
buildConfigs.forEach(addObject)
addObject(buildConfigList)
@ -65,37 +75,70 @@ public class PBXProjGenerator {
for target in spec.targets {
targetNativeReferences[target.name] =
referenceGenerator.generate(
target.isLegacy ? PBXLegacyTarget.self : PBXNativeTarget.self, target.name)
target.isLegacy ? PBXLegacyTarget.self : PBXNativeTarget.self,
target.name
)
let fileReference = PBXFileReference(reference: referenceGenerator.generate(PBXFileReference.self, target.name), sourceTree: .buildProductsDir, explicitFileType: target.type.fileExtension, path: target.filename, includeInIndex: 0)
let fileReference = PBXFileReference(
reference: referenceGenerator.generate(PBXFileReference.self, target.name),
sourceTree: .buildProductsDir,
explicitFileType: target.type.fileExtension,
path: target.filename,
includeInIndex: 0
)
addObject(fileReference)
targetFileReferences[target.name] = fileReference.reference
let buildFile = PBXBuildFile(reference: referenceGenerator.generate(PBXBuildFile.self, fileReference.reference), fileRef: fileReference.reference)
let buildFile = PBXBuildFile(
reference: referenceGenerator.generate(PBXBuildFile.self, fileReference.reference),
fileRef: fileReference.reference
)
addObject(buildFile)
targetBuildFiles[target.name] = buildFile
}
let targets = try spec.targets.map(generateTarget)
let productGroup = PBXGroup(reference: referenceGenerator.generate(PBXGroup.self, "Products"), children: Array(targetFileReferences.values), sourceTree: .group, name: "Products")
let productGroup = PBXGroup(
reference: referenceGenerator.generate(PBXGroup.self, "Products"),
children: Array(targetFileReferences.values),
sourceTree: .group,
name: "Products"
)
addObject(productGroup)
topLevelGroups.insert(productGroup.reference)
if !carthageFrameworksByPlatform.isEmpty {
var platforms: [PBXGroup] = []
for (platform, fileReferences) in carthageFrameworksByPlatform {
let platformGroup = PBXGroup(reference: referenceGenerator.generate(PBXGroup.self, "Carthage" + platform), children: fileReferences.sorted(), sourceTree: .group, name: platform, path: platform)
let platformGroup = PBXGroup(
reference: referenceGenerator.generate(PBXGroup.self, "Carthage" + platform),
children: fileReferences.sorted(),
sourceTree: .group,
name: platform,
path: platform
)
addObject(platformGroup)
platforms.append(platformGroup)
}
let carthageGroup = PBXGroup(reference: referenceGenerator.generate(PBXGroup.self, "Carthage"), children: platforms.references.sorted(), sourceTree: .group, name: "Carthage", path: carthageBuildPath)
let carthageGroup = PBXGroup(
reference: referenceGenerator.generate(PBXGroup.self, "Carthage"),
children: platforms.references.sorted(),
sourceTree: .group,
name: "Carthage",
path: carthageBuildPath
)
addObject(carthageGroup)
frameworkFiles.append(carthageGroup.reference)
}
if !frameworkFiles.isEmpty {
let group = PBXGroup(reference: referenceGenerator.generate(PBXGroup.self, "Frameworks"), children: frameworkFiles, sourceTree: .group, name: "Frameworks")
let group = PBXGroup(
reference: referenceGenerator.generate(PBXGroup.self, "Frameworks"),
children: frameworkFiles,
sourceTree: .group,
name: "Frameworks"
)
addObject(group)
topLevelGroups.insert(group.reference)
}
@ -104,21 +147,30 @@ public class PBXProjGenerator {
topLevelGroups.insert(rootGroup)
}
let mainGroup = PBXGroup(reference: referenceGenerator.generate(PBXGroup.self, "Project"), children: Array(topLevelGroups), sourceTree: .group, usesTabs: spec.options.usesTabs.map { $0 ? 1 : 0 }, indentWidth: spec.options.indentWidth, tabWidth: spec.options.tabWidth)
let mainGroup = PBXGroup(
reference: referenceGenerator.generate(PBXGroup.self, "Project"),
children: Array(topLevelGroups),
sourceTree: .group,
usesTabs: spec.options.usesTabs.map { $0 ? 1 : 0 },
indentWidth: spec.options.indentWidth,
tabWidth: spec.options.tabWidth
)
addObject(mainGroup)
sortGroups(group: mainGroup)
let projectAttributes: [String: Any] = ["LastUpgradeCheck": spec.xcodeVersion].merged(spec.attributes)
let root = PBXProject(name: spec.name,
reference: proj.rootObject,
buildConfigurationList: buildConfigList.reference,
compatibilityVersion: "Xcode 3.2",
mainGroup: mainGroup.reference,
developmentRegion: spec.options.developmentLanguage ?? "en",
knownRegions: sourceGenerator.knownRegions.sorted(),
targets: targets.references,
attributes: projectAttributes)
let root = PBXProject(
name: spec.name,
reference: proj.rootObject,
buildConfigurationList: buildConfigList.reference,
compatibilityVersion: "Xcode 3.2",
mainGroup: mainGroup.reference,
developmentRegion: spec.options.developmentLanguage ?? "en",
knownRegions: sourceGenerator.knownRegions.sorted(),
targets: targets.references,
attributes: projectAttributes
)
proj.objects.projects.append(root)
return proj
@ -170,7 +222,10 @@ public class PBXProjGenerator {
if let bundleIdPrefix = spec.options.bundleIdPrefix,
!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: "")
let escapedTargetName = target.name
.replacingOccurrences(of: "_", with: "-")
.components(separatedBy: characterSet)
.joined(separator: "")
buildSettings["PRODUCT_BUNDLE_IDENTIFIER"] = bundleIdPrefix + "." + escapedTargetName
}
@ -206,10 +261,19 @@ public class PBXProjGenerator {
if let configPath = target.configFiles[config.name] {
baseConfigurationReference = sourceGenerator.getContainedFileReference(path: spec.basePath + configPath)
}
return XCBuildConfiguration(reference: referenceGenerator.generate(XCBuildConfiguration.self, config.name + target.name), name: config.name, baseConfigurationReference: baseConfigurationReference, buildSettings: buildSettings)
return XCBuildConfiguration(
reference: referenceGenerator.generate(XCBuildConfiguration.self, config.name + target.name),
name: config.name,
baseConfigurationReference: baseConfigurationReference,
buildSettings: buildSettings
)
}
configs.forEach(addObject)
let buildConfigList = XCConfigurationList(reference: referenceGenerator.generate(XCConfigurationList.self, target.name), buildConfigurations: configs.references, defaultConfigurationName: "")
let buildConfigList = XCConfigurationList(
reference: referenceGenerator.generate(XCConfigurationList.self, target.name),
buildConfigurations: configs.references,
defaultConfigurationName: ""
)
addObject(buildConfigList)
var dependencies: [String] = []
@ -228,8 +292,18 @@ public class PBXProjGenerator {
guard let dependencyTarget = spec.getTarget(dependencyTargetName) else { continue }
let dependencyFileReference = targetFileReferences[dependencyTargetName]!
let targetProxy = PBXContainerItemProxy(reference: referenceGenerator.generate(PBXContainerItemProxy.self, target.name), containerPortal: proj.rootObject, remoteGlobalIDString: targetNativeReferences[dependencyTargetName]!, proxyType: .nativeTarget, remoteInfo: dependencyTargetName)
let targetDependency = PBXTargetDependency(reference: referenceGenerator.generate(PBXTargetDependency.self, dependencyTargetName + target.name), target: targetNativeReferences[dependencyTargetName]!, targetProxy: targetProxy.reference)
let targetProxy = PBXContainerItemProxy(
reference: referenceGenerator.generate(PBXContainerItemProxy.self, target.name),
containerPortal: proj.rootObject,
remoteGlobalIDString: targetNativeReferences[dependencyTargetName]!,
proxyType: .nativeTarget,
remoteInfo: dependencyTargetName
)
let targetDependency = PBXTargetDependency(
reference: referenceGenerator.generate(PBXTargetDependency.self, dependencyTargetName + target.name),
target: targetNativeReferences[dependencyTargetName]!,
targetProxy: targetProxy.reference
)
addObject(targetProxy)
addObject(targetDependency)
@ -237,7 +311,10 @@ public class PBXProjGenerator {
if (dependencyTarget.type.isLibrary || dependencyTarget.type.isFramework) && dependency.link {
let dependencyBuildFile = targetBuildFiles[dependencyTargetName]!
let buildFile = PBXBuildFile(reference: referenceGenerator.generate(PBXBuildFile.self, dependencyBuildFile.reference + target.name), fileRef: dependencyBuildFile.fileRef!)
let buildFile = PBXBuildFile(
reference: referenceGenerator.generate(PBXBuildFile.self, dependencyBuildFile.reference + target.name),
fileRef: dependencyBuildFile.fileRef!
)
addObject(buildFile)
targetFrameworkBuildFiles.append(buildFile.reference)
}
@ -245,7 +322,11 @@ public class PBXProjGenerator {
if embed && !dependencyTarget.type.isLibrary {
let embedSettings = dependency.buildSettings
let embedFile = PBXBuildFile(reference: referenceGenerator.generate(PBXBuildFile.self, dependencyFileReference + target.name), fileRef: dependencyFileReference, settings: embedSettings)
let embedFile = PBXBuildFile(
reference: referenceGenerator.generate(PBXBuildFile.self, dependencyFileReference + target.name),
fileRef: dependencyFileReference,
settings: embedSettings
)
addObject(embedFile)
if dependencyTarget.type.isExtension {
@ -263,12 +344,22 @@ public class PBXProjGenerator {
case .framework:
let fileReference: String
if dependency.implicit {
fileReference = sourceGenerator.getFileReference(path: Path(dependency.reference), inPath: spec.basePath, sourceTree: .buildProductsDir)
fileReference = sourceGenerator.getFileReference(
path: Path(dependency.reference),
inPath: spec.basePath,
sourceTree: .buildProductsDir
)
} else {
fileReference = sourceGenerator.getFileReference(path: Path(dependency.reference), inPath: spec.basePath)
fileReference = sourceGenerator.getFileReference(
path: Path(dependency.reference),
inPath: spec.basePath
)
}
let buildFile = PBXBuildFile(reference: referenceGenerator.generate(PBXBuildFile.self, fileReference + target.name), fileRef: fileReference)
let buildFile = PBXBuildFile(
reference: referenceGenerator.generate(PBXBuildFile.self, fileReference + target.name),
fileRef: fileReference
)
addObject(buildFile)
targetFrameworkBuildFiles.append(buildFile.reference)
@ -277,7 +368,11 @@ public class PBXProjGenerator {
}
if embed {
let embedFile = PBXBuildFile(reference: referenceGenerator.generate(PBXBuildFile.self, fileReference + target.name), fileRef: fileReference, settings: dependency.buildSettings)
let embedFile = PBXBuildFile(
reference: referenceGenerator.generate(PBXBuildFile.self, fileReference + target.name),
fileRef: fileReference,
settings: dependency.buildSettings
)
addObject(embedFile)
copyFrameworksReferences.append(embedFile.reference)
}
@ -289,13 +384,20 @@ public class PBXProjGenerator {
}
let fileReference = sourceGenerator.getFileReference(path: frameworkPath, inPath: platformPath)
let buildFile = PBXBuildFile(reference: referenceGenerator.generate(PBXBuildFile.self, fileReference + target.name), fileRef: fileReference)
let buildFile = PBXBuildFile(
reference: referenceGenerator.generate(PBXBuildFile.self, fileReference + target.name),
fileRef: fileReference
)
addObject(buildFile)
carthageFrameworksByPlatform[target.platform.carthageDirectoryName, default: []].insert(fileReference)
targetFrameworkBuildFiles.append(buildFile.reference)
if target.platform == .macOS && target.type.isApp {
let embedFile = PBXBuildFile(reference: referenceGenerator.generate(PBXBuildFile.self, fileReference + target.name), fileRef: fileReference, settings: dependency.buildSettings)
let embedFile = PBXBuildFile(
reference: referenceGenerator.generate(PBXBuildFile.self, fileReference + target.name),
fileRef: fileReference,
settings: dependency.buildSettings
)
addObject(embedFile)
copyFrameworksReferences.append(embedFile.reference)
}
@ -330,7 +432,8 @@ public class PBXProjGenerator {
inputPaths: buildScript.inputFiles,
outputPaths: buildScript.outputFiles,
shellPath: buildScript.shell ?? "/bin/sh",
shellScript: shellScript)
shellScript: shellScript
)
shellScriptPhase.runOnlyForDeploymentPostprocessing = buildScript.runOnlyWhenInstalling ? 1 : 0
addObject(shellScriptPhase)
buildPhases.append(shellScriptPhase.reference)
@ -365,7 +468,8 @@ public class PBXProjGenerator {
let frameworkBuildPhase = PBXFrameworksBuildPhase(
reference: referenceGenerator.generate(PBXFrameworksBuildPhase.self, target.name),
files: targetFrameworkBuildFiles,
runOnlyForDeploymentPostprocessing: 0)
runOnlyForDeploymentPostprocessing: 0
)
addObject(frameworkBuildPhase)
buildPhases.append(frameworkBuildPhase.reference)
@ -377,7 +481,8 @@ public class PBXProjGenerator {
reference: referenceGenerator.generate(PBXCopyFilesBuildPhase.self, "embed app extensions" + target.name),
dstPath: "",
dstSubfolderSpec: .plugins,
files: extensions)
files: extensions
)
addObject(copyFilesPhase)
buildPhases.append(copyFilesPhase.reference)
@ -389,7 +494,8 @@ public class PBXProjGenerator {
reference: referenceGenerator.generate(PBXCopyFilesBuildPhase.self, "embed frameworks" + target.name),
dstPath: "",
dstSubfolderSpec: .frameworks,
files: copyFrameworksReferences)
files: copyFrameworksReferences
)
addObject(copyFilesPhase)
buildPhases.append(copyFilesPhase.reference)
@ -401,23 +507,36 @@ public class PBXProjGenerator {
reference: referenceGenerator.generate(PBXCopyFilesBuildPhase.self, "embed watch content" + target.name),
dstPath: "$(CONTENTS_FOLDER_PATH)/Watch",
dstSubfolderSpec: .productsDirectory,
files: copyWatchReferences)
files: copyWatchReferences
)
addObject(copyFilesPhase)
buildPhases.append(copyFilesPhase.reference)
}
let carthageFrameworksToEmbed = Array(Set(carthageDependencies
let carthageFrameworksToEmbed = Array(Set(
carthageDependencies
.filter { $0.embed ?? true }
.map { $0.reference }))
.map { $0.reference }
))
.sorted()
if !carthageFrameworksToEmbed.isEmpty {
if target.type.isApp && target.platform != .macOS {
let inputPaths = carthageFrameworksToEmbed.map { "$(SRCROOT)/\(carthageBuildPath)/\(target.platform)/\($0)\($0.contains(".") ? "" : ".framework")" }
let outputPaths = carthageFrameworksToEmbed.map { "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/\($0)\($0.contains(".") ? "" : ".framework")" }
let carthageScript = PBXShellScriptBuildPhase(reference: referenceGenerator.generate(PBXShellScriptBuildPhase.self, "Carthage" + target.name), files: [], name: "Carthage", inputPaths: inputPaths, outputPaths: outputPaths, shellPath: "/bin/sh", shellScript: "/usr/local/bin/carthage copy-frameworks\n")
let inputPaths = carthageFrameworksToEmbed
.map { "$(SRCROOT)/\(carthageBuildPath)/\(target.platform)/\($0)\($0.contains(".") ? "" : ".framework")" }
let outputPaths = carthageFrameworksToEmbed
.map { "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/\($0)\($0.contains(".") ? "" : ".framework")" }
let carthageScript = PBXShellScriptBuildPhase(
reference: referenceGenerator.generate(PBXShellScriptBuildPhase.self, "Carthage" + target.name),
files: [],
name: "Carthage",
inputPaths: inputPaths,
outputPaths: outputPaths,
shellPath: "/bin/sh",
shellScript: "/usr/local/bin/carthage copy-frameworks\n"
)
addObject(carthageScript)
buildPhases.append(carthageScript.reference)
}
@ -450,7 +569,8 @@ public class PBXProjGenerator {
buildRules: [],
dependencies: dependencies,
productReference: fileReference,
productType: target.type)
productType: target.type
)
}
addObject(pbxtarget)
return pbxtarget

View File

@ -41,9 +41,16 @@ public class ProjectGenerator {
func getBuildEntry(_ buildTarget: Scheme.BuildTarget) -> XCScheme.BuildAction.Entry {
let predicate: (PBXTarget) -> Bool = { $0.name == buildTarget.target }
let targetReference = pbxProject.objects.nativeTargets.referenceValues.first { predicate($0 as PBXTarget) } ?? pbxProject.objects.legacyTargets.referenceValues.first { predicate($0 as PBXTarget) }!
let targetReference =
pbxProject.objects.nativeTargets.referenceValues.first { predicate($0 as PBXTarget) } ??
pbxProject.objects.legacyTargets.referenceValues.first { predicate($0 as PBXTarget) }!
let buildableReference = XCScheme.BuildableReference(referencedContainer: "container:\(spec.name).xcodeproj", blueprintIdentifier: targetReference.reference, buildableName: buildTarget.target + (targetReference.productType?.fileExtension.map { ".\($0)" } ?? ""), blueprintName: scheme.name)
let buildableReference = XCScheme.BuildableReference(
referencedContainer: "container:\(spec.name).xcodeproj",
blueprintIdentifier: targetReference.reference,
buildableName: buildTarget.target + (targetReference.productType?.fileExtension.map { ".\($0)" } ?? ""),
blueprintName: scheme.name
)
return XCScheme.BuildAction.Entry(buildableReference: buildableReference, buildFor: buildTarget.buildTypes)
}
@ -60,43 +67,60 @@ public class ProjectGenerator {
let buildableReference = buildActionEntries.first!.buildableReference
let productRunable = XCScheme.BuildableProductRunnable(buildableReference: buildableReference)
let buildAction = XCScheme.BuildAction(buildActionEntries: buildActionEntries, parallelizeBuild: true, buildImplicitDependencies: true)
let buildAction = XCScheme.BuildAction(
buildActionEntries: buildActionEntries,
parallelizeBuild: true,
buildImplicitDependencies: true
)
let testables = testBuildTargetEntries.map { XCScheme.TestableReference(skipped: false, buildableReference: $0.buildableReference) }
let testables = testBuildTargetEntries.map {
XCScheme.TestableReference(skipped: false, buildableReference: $0.buildableReference)
}
let testCommandLineArgs = scheme.test.map { XCScheme.CommandLineArguments($0.commandLineArguments) }
let launchCommandLineArgs = scheme.run.map { XCScheme.CommandLineArguments($0.commandLineArguments) }
let profileCommandLineArgs = scheme.profile.map { XCScheme.CommandLineArguments($0.commandLineArguments) }
let testAction = XCScheme.TestAction(buildConfiguration: scheme.test?.config ?? defaultDebugConfig.name,
macroExpansion: buildableReference,
testables: testables,
shouldUseLaunchSchemeArgsEnv: scheme.test?.commandLineArguments.isEmpty ?? true,
codeCoverageEnabled: scheme.test?.gatherCoverageData ?? false,
commandlineArguments: testCommandLineArgs)
let testAction = XCScheme.TestAction(
buildConfiguration: scheme.test?.config ?? defaultDebugConfig.name,
macroExpansion: buildableReference,
testables: testables,
shouldUseLaunchSchemeArgsEnv: scheme.test?.commandLineArguments.isEmpty ?? true,
codeCoverageEnabled: scheme.test?.gatherCoverageData ?? false,
commandlineArguments: testCommandLineArgs
)
let launchAction = XCScheme.LaunchAction(buildableProductRunnable: productRunable,
buildConfiguration: scheme.run?.config ?? defaultDebugConfig.name,
commandlineArguments: launchCommandLineArgs)
let launchAction = XCScheme.LaunchAction(
buildableProductRunnable: productRunable,
buildConfiguration: scheme.run?.config ?? defaultDebugConfig.name,
commandlineArguments: launchCommandLineArgs
)
let profileAction = XCScheme.ProfileAction(buildableProductRunnable: productRunable,
buildConfiguration: scheme.profile?.config ?? defaultReleaseConfig.name,
shouldUseLaunchSchemeArgsEnv: scheme.profile?.commandLineArguments.isEmpty ?? true,
commandlineArguments: profileCommandLineArgs)
let profileAction = XCScheme.ProfileAction(
buildableProductRunnable: productRunable,
buildConfiguration: scheme.profile?.config ?? defaultReleaseConfig.name,
shouldUseLaunchSchemeArgsEnv: scheme.profile?.commandLineArguments.isEmpty ?? true,
commandlineArguments: profileCommandLineArgs
)
let analyzeAction = XCScheme.AnalyzeAction(buildConfiguration: scheme.analyze?.config ?? defaultDebugConfig.name)
let archiveAction = XCScheme.ArchiveAction(buildConfiguration: scheme.archive?.config ?? defaultReleaseConfig.name, revealArchiveInOrganizer: true)
let archiveAction = XCScheme.ArchiveAction(
buildConfiguration: scheme.archive?.config ?? defaultReleaseConfig.name,
revealArchiveInOrganizer: true
)
return XCScheme(name: scheme.name,
lastUpgradeVersion: spec.xcodeVersion,
version: "1.3",
buildAction: buildAction,
testAction: testAction,
launchAction: launchAction,
profileAction: profileAction,
analyzeAction: analyzeAction,
archiveAction: archiveAction)
return XCScheme(
name: scheme.name,
lastUpgradeVersion: spec.xcodeVersion,
version: "1.3",
buildAction: buildAction,
testAction: testAction,
launchAction: launchAction,
profileAction: profileAction,
analyzeAction: analyzeAction,
archiveAction: archiveAction
)
}
func generateSharedData(pbxProject: PBXProj) throws -> XCSharedData {
@ -116,7 +140,13 @@ public class ProjectGenerator {
let debugConfig = spec.configs.first { $0.type == .debug }!
let releaseConfig = spec.configs.first { $0.type == .release }!
let scheme = Scheme(name: schemeName, target: target, targetScheme: targetScheme, debugConfig: debugConfig.name, releaseConfig: releaseConfig.name)
let scheme = Scheme(
name: schemeName,
target: target,
targetScheme: targetScheme,
debugConfig: debugConfig.name,
releaseConfig: releaseConfig.name
)
let xcscheme = try generateScheme(scheme, pbxProject: pbxProject)
xcschemes.append(xcscheme)
} else {
@ -124,10 +154,18 @@ public class ProjectGenerator {
let schemeName = "\(target.name) \(configVariant)"
let debugConfig = spec.configs.first { $0.type == .debug && $0.name.contains(configVariant) }!
let releaseConfig = spec.configs.first { $0.type == .release && $0.name.contains(configVariant) }!
let debugConfig = spec.configs
.first { $0.type == .debug && $0.name.contains(configVariant) }!
let releaseConfig = spec.configs
.first { $0.type == .release && $0.name.contains(configVariant) }!
let scheme = Scheme(name: schemeName, target: target, targetScheme: targetScheme, debugConfig: debugConfig.name, releaseConfig: releaseConfig.name)
let scheme = Scheme(
name: schemeName,
target: target,
targetScheme: targetScheme,
debugConfig: debugConfig.name,
releaseConfig: releaseConfig.name
)
let xcscheme = try generateScheme(scheme, pbxProject: pbxProject)
xcschemes.append(xcscheme)
}
@ -144,9 +182,20 @@ extension Scheme {
self.init(
name: name,
build: .init(targets: [Scheme.BuildTarget(target: target.name)]),
run: .init(config: debugConfig, commandLineArguments: targetScheme.commandLineArguments),
test: .init(config: debugConfig, gatherCoverageData: targetScheme.gatherCoverageData, commandLineArguments: targetScheme.commandLineArguments, targets: targetScheme.testTargets),
profile: .init(config: releaseConfig, commandLineArguments: targetScheme.commandLineArguments),
run: .init(
config: debugConfig,
commandLineArguments: targetScheme.commandLineArguments
),
test: .init(
config: debugConfig,
gatherCoverageData: targetScheme.gatherCoverageData,
commandLineArguments: targetScheme.commandLineArguments,
targets: targetScheme.testTargets
),
profile: .init(
config: releaseConfig,
commandLineArguments: targetScheme.commandLineArguments
),
analyze: .init(config: debugConfig),
archive: .init(config: releaseConfig)
)

View File

@ -81,7 +81,12 @@ extension ProjectSpec {
}
// combines all levels of a target's settings: target, target config, project, project config
public func getCombinedBuildSettings(basePath: Path, target: Target, config: Config, includeProject: Bool = true) -> BuildSettings {
public func getCombinedBuildSettings(
basePath: Path,
target: Target,
config: Config,
includeProject: Bool = true
) -> BuildSettings {
var buildSettings: BuildSettings = [:]
if includeProject {
if let configFilePath = configFiles[config.name] {
@ -96,8 +101,19 @@ extension ProjectSpec {
return buildSettings
}
public func targetHasBuildSetting(_ setting: String, basePath: Path, target: Target, config: Config, includeProject: Bool = true) -> Bool {
let buildSettings = getCombinedBuildSettings(basePath: basePath, target: target, config: config, includeProject: includeProject)
public func targetHasBuildSetting(
_ setting: String,
basePath: Path,
target: Target,
config: Config,
includeProject: Bool = true
) -> Bool {
let buildSettings = getCombinedBuildSettings(
basePath: basePath,
target: target,
config: config,
includeProject: includeProject
)
return buildSettings[setting] != nil
}

View File

@ -61,9 +61,19 @@ class SourceGenerator {
settings["COMPILER_FLAGS"] = targetSource.compilerFlags.joined(separator: " ")
}
// TODO: add the target name to the reference generator string so shared files don't have same reference (that will be escaped by appending a number)
let buildFile = PBXBuildFile(reference: referenceGenerator.generate(PBXBuildFile.self, fileReference + targetName), fileRef: fileReference, settings: settings.isEmpty ? nil : settings)
return SourceFile(path: path, fileReference: fileReference, buildFile: buildFile, buildPhase: chosenBuildPhase)
// TODO: add the target name to the reference generator string so shared files don't have same reference
// (that will be escaped by appending a number)
let buildFile = PBXBuildFile(
reference: referenceGenerator.generate(PBXBuildFile.self, fileReference + targetName),
fileRef: fileReference,
settings: settings.isEmpty ? nil : settings
)
return SourceFile(
path: path,
fileReference: fileReference,
buildFile: buildFile,
buildPhase: chosenBuildPhase
)
}
func getContainedFileReference(path: Path) -> String {
@ -71,7 +81,12 @@ class SourceGenerator {
let parentPath = path.parent()
let fileReference = getFileReference(path: path, inPath: parentPath)
let parentGroup = getGroup(path: parentPath, mergingChildren: [fileReference], createIntermediateGroups: createIntermediateGroups, isBaseGroup: true)
let parentGroup = getGroup(
path: parentPath,
mergingChildren: [fileReference],
createIntermediateGroups: createIntermediateGroups,
isBaseGroup: true
)
if createIntermediateGroups {
createIntermediaGroups(for: parentGroup.reference, at: parentPath)
@ -83,7 +98,12 @@ class SourceGenerator {
if let fileReference = fileReferencesByPath[path] {
return fileReference
} else {
let fileReference = PBXFileReference(reference: referenceGenerator.generate(PBXFileReference.self, path.byRemovingBase(path: spec.basePath).string), sourceTree: sourceTree, name: name, path: path.byRemovingBase(path: inPath).string)
let fileReference = PBXFileReference(
reference: referenceGenerator.generate(PBXFileReference.self, path.byRemovingBase(path: spec.basePath).string),
sourceTree: sourceTree,
name: name,
path: path.byRemovingBase(path: inPath).string
)
addObject(fileReference)
fileReferencesByPath[path] = fileReference.reference
return fileReference.reference
@ -147,10 +167,12 @@ class SourceGenerator {
if let cachedGroup = variantGroupsByPath[path] {
variantGroup = cachedGroup
} else {
variantGroup = PBXVariantGroup(reference: referenceGenerator.generate(PBXVariantGroup.self, path.byRemovingBase(path: spec.basePath).string),
children: [],
name: path.lastComponent,
sourceTree: .group)
variantGroup = PBXVariantGroup(
reference: referenceGenerator.generate(PBXVariantGroup.self, path.byRemovingBase(path: spec.basePath).string),
children: [],
name: path.lastComponent,
sourceTree: .group
)
addObject(variantGroup)
variantGroupsByPath[path] = variantGroup
}
@ -184,8 +206,10 @@ class SourceGenerator {
+ Pre-defined Excluded files
*/
let sourceExcludeFilePaths: Set<Path> = Set(getSourceExcludes(dirPath: rootSourcePath)
+ defaultExcludedFiles)
let sourceExcludeFilePaths: Set<Path> = Set(
getSourceExcludes(dirPath: rootSourcePath)
+ defaultExcludedFiles
)
return try dirPath.children()
.filter {
@ -204,7 +228,11 @@ class SourceGenerator {
}
}
private func getGroupSources(targetSource: TargetSource, path: Path, isBaseGroup: Bool) throws -> (sourceFiles: [SourceFile], groups: [PBXGroup]) {
private func getGroupSources(
targetSource: TargetSource,
path: Path,
isBaseGroup: Bool
) throws -> (sourceFiles: [SourceFile], groups: [PBXGroup]) {
let children = try getSourceChildren(targetSource: targetSource, dirPath: path)
@ -263,8 +291,18 @@ class SourceGenerator {
groupChildren.append(variantGroup.reference)
baseLocalisationVariantGroups.append(variantGroup)
let buildFile = PBXBuildFile(reference: referenceGenerator.generate(PBXBuildFile.self, variantGroup.reference + targetName), fileRef: variantGroup.reference, settings: nil)
allSourceFiles.append(SourceFile(path: filePath, fileReference: variantGroup.reference, buildFile: buildFile, buildPhase: .resources))
let buildFile = PBXBuildFile(
reference: referenceGenerator.generate(PBXBuildFile.self, variantGroup.reference + targetName),
fileRef: variantGroup.reference,
settings: nil
)
let sourceFile = SourceFile(
path: filePath,
fileReference: variantGroup.reference,
buildFile: buildFile,
buildPhase: .resources
)
allSourceFiles.append(sourceFile)
}
}
@ -274,10 +312,19 @@ class SourceGenerator {
for filePath in try localisedDirectory.children().sorted { $0.lastComponent < $1.lastComponent } {
// find base localisation variant group
// ex: Foo.strings will be added to Foo.strings or Foo.storyboard variant group
let variantGroup = baseLocalisationVariantGroups.first { Path($0.name!).lastComponent == filePath.lastComponent } ??
baseLocalisationVariantGroups.first { Path($0.name!).lastComponentWithoutExtension == filePath.lastComponentWithoutExtension }
let variantGroup = baseLocalisationVariantGroups
.first {
Path($0.name!).lastComponent == filePath.lastComponent
let fileReference = getFileReference(path: filePath, inPath: path, name: variantGroup != nil ? localisationName : filePath.lastComponent)
} ?? baseLocalisationVariantGroups.first {
Path($0.name!).lastComponentWithoutExtension == filePath.lastComponentWithoutExtension
}
let fileReference = getFileReference(
path: filePath,
inPath: path,
name: variantGroup != nil ? localisationName : filePath.lastComponent
)
if let variantGroup = variantGroup {
if !variantGroup.children.contains(fileReference) {
@ -285,16 +332,28 @@ class SourceGenerator {
}
} else {
// add SourceFile to group if there is no Base.lproj directory
let buildFile = PBXBuildFile(reference: referenceGenerator.generate(PBXBuildFile.self, fileReference + targetName),
fileRef: fileReference,
settings: nil)
allSourceFiles.append(SourceFile(path: filePath, fileReference: fileReference, buildFile: buildFile, buildPhase: .resources))
let buildFile = PBXBuildFile(
reference: referenceGenerator.generate(PBXBuildFile.self, fileReference + targetName),
fileRef: fileReference,
settings: nil
)
allSourceFiles.append(SourceFile(
path: filePath,
fileReference: fileReference,
buildFile: buildFile,
buildPhase: .resources
))
groupChildren.append(fileReference)
}
}
}
let group = getGroup(path: path, mergingChildren: groupChildren, createIntermediateGroups: spec.options.createIntermediateGroups, isBaseGroup: isBaseGroup)
let group = getGroup(
path: path,
mergingChildren: groupChildren,
createIntermediateGroups: spec.options.createIntermediateGroups,
isBaseGroup: isBaseGroup
)
if spec.options.createIntermediateGroups {
createIntermediaGroups(for: group.reference, at: path)
}

View File

@ -19,7 +19,8 @@ extension PBXFileElement {
extension PBXProj {
public func printGroups() -> String {
guard let project = objects.projects.first?.value, let mainGroup = objects.groups.getReference(project.mainGroup) else {
guard let project = objects.projects.first?.value,
let mainGroup = objects.groups.getReference(project.mainGroup) else {
return ""
}
return printGroup(group: mainGroup)

View File

@ -20,12 +20,20 @@ func projectGeneratorTests() {
describe("Project Generator") {
let application = Target(name: "MyApp", type: .application, platform: .iOS,
settings: Settings(buildSettings: ["SETTING_1": "VALUE"]),
dependencies: [Dependency(type: .target, reference: "MyFramework")])
let application = Target(
name: "MyApp",
type: .application,
platform: .iOS,
settings: Settings(buildSettings: ["SETTING_1": "VALUE"]),
dependencies: [Dependency(type: .target, reference: "MyFramework")]
)
let framework = Target(name: "MyFramework", type: .framework, platform: .iOS,
settings: Settings(buildSettings: ["SETTING_2": "VALUE"]))
let framework = Target(
name: "MyFramework",
type: .framework,
platform: .iOS,
settings: Settings(buildSettings: ["SETTING_2": "VALUE"])
)
let targets = [application, framework]
@ -94,7 +102,11 @@ func projectGeneratorTests() {
}
$0.it("generates configs") {
let spec = ProjectSpec(basePath: "", 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.objects.buildConfigurations.referenceValues
try expect(configs.count) == 2
@ -103,7 +115,11 @@ func projectGeneratorTests() {
}
$0.it("clears config settings when missing type") {
let spec = ProjectSpec(basePath: "", 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.objects.buildConfigurations.first?.value else {
throw failure("configuration not found")
@ -140,11 +156,15 @@ func projectGeneratorTests() {
}
$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"]]))
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"
@ -207,7 +227,8 @@ func projectGeneratorTests() {
scriptSpec.targets[0].postbuildScripts = [BuildScript(script: .script("script2"))]
let pbxProject = try getPbxProj(scriptSpec)
guard let nativeTarget = pbxProject.objects.nativeTargets.referenceValues.first(where: { !$0.buildPhases.isEmpty }) else {
guard let nativeTarget = pbxProject.objects.nativeTargets.referenceValues
.first(where: { !$0.buildPhases.isEmpty }) else {
throw failure("Target with build phases not found")
}
let buildPhases = nativeTarget.buildPhases
@ -224,9 +245,23 @@ func projectGeneratorTests() {
}
$0.it("generates targets with cylical dependencies") {
let target1 = Target(name: "target1", type: .framework, platform: .iOS, dependencies: [Dependency(type: .target, reference: "target2")])
let target2 = Target(name: "target2", type: .framework, platform: .iOS, dependencies: [Dependency(type: .target, reference: "target1")])
let spec = ProjectSpec(basePath: "", name: "test", targets: [target1, target2])
let target1 = Target(
name: "target1",
type: .framework,
platform: .iOS,
dependencies: [Dependency(type: .target, reference: "target2")]
)
let target2 = Target(
name: "target2",
type: .framework,
platform: .iOS,
dependencies: [Dependency(type: .target, reference: "target1")]
)
let spec = ProjectSpec(
basePath: "",
name: "test",
targets: [target1, target2]
)
_ = try getPbxProj(spec)
}
@ -236,13 +271,28 @@ 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(basePath: "", name: "test", targets: [application, framework], schemes: [scheme])
let scheme = Scheme(
name: "MyScheme",
build: Scheme.Build(targets: [buildTarget])
)
let spec = ProjectSpec(
basePath: "",
name: "test",
targets: [application, framework],
schemes: [scheme]
)
let project = try getProject(spec)
guard let target = project.pbxproj.objects.nativeTargets.referenceValues.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") }
guard let target = project.pbxproj.objects.nativeTargets.referenceValues
.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")
}
try expect(scheme.name) == "MyScheme"
guard let buildActionEntry = xcscheme.buildAction?.buildActionEntries.first else { throw failure("Build Action entry not found") }
guard let buildActionEntry = xcscheme.buildAction?.buildActionEntries.first else {
throw failure("Build Action entry not found")
}
try expect(buildActionEntry.buildFor) == BuildType.all
let buildableReferences: [XCScheme.BuildableReference] = [
@ -281,9 +331,17 @@ func projectGeneratorTests() {
try expect(project.sharedData?.schemes.count) == 2
guard let nativeTarget = project.pbxproj.objects.nativeTargets.referenceValues.first(where: { $0.name == application.name }) else { throw failure("Target not found") }
guard let xcscheme = project.sharedData?.schemes.first(where: { $0.name == "\(target.name) Test" }) else { throw failure("Scheme not found") }
guard let buildActionEntry = xcscheme.buildAction?.buildActionEntries.first else { throw failure("Build Action entry not found") }
guard let nativeTarget = project.pbxproj.objects.nativeTargets.referenceValues
.first(where: { $0.name == application.name }) else {
throw failure("Target not found")
}
guard let xcscheme = project.sharedData?.schemes
.first(where: { $0.name == "\(target.name) Test" }) else {
throw failure("Scheme not found")
}
guard let buildActionEntry = xcscheme.buildAction?.buildActionEntries.first else {
throw failure("Build Action entry not found")
}
try expect(buildActionEntry.buildableReference.blueprintIdentifier) == nativeTarget.reference
try expect(xcscheme.launchAction?.buildConfiguration) == "Test Debug"
@ -397,7 +455,12 @@ func projectGeneratorTests() {
try createDirectories(directories)
let target = Target(name: "Test", type: .application, platform: .iOS, sources: ["Sources"])
let spec = ProjectSpec(basePath: directoryPath, name: "Test", targets: [target], fileGroups: ["Sources"])
let spec = ProjectSpec(
basePath: directoryPath,
name: "Test",
targets: [target],
fileGroups: ["Sources"]
)
let project = try getPbxProj(spec)
try project.expectFile(paths: ["Sources", "a.swift"], buildPhase: .sources)
@ -720,8 +783,10 @@ extension PBXProj {
}
if let buildPhase = buildPhase {
let buildFile = objects.buildFiles.referenceValues.first(where: { $0.fileRef == fileReference.reference })
let actualBuildPhase = buildFile.flatMap { buildFile in objects.buildPhases.referenceValues.first { $0.files.contains(buildFile.reference) } }?.buildPhase
let buildFile = objects.buildFiles.referenceValues
.first(where: { $0.fileRef == fileReference.reference })
let actualBuildPhase = buildFile
.flatMap { buildFile in objects.buildPhases.referenceValues.first { $0.files.contains(buildFile.reference) } }?.buildPhase
var error: String?
if let buildPhase = buildPhase.buildPhase {

View File

@ -7,18 +7,31 @@ func projectSpecTests() {
describe("ProjectSpec") {
let framework = Target(name: "MyFramework", type: .framework, platform: .iOS,
settings: Settings(buildSettings: ["SETTING_2": "VALUE"]))
let staticLibrary = Target(name: "MyStaticLibrary", type: .staticLibrary, platform: .iOS,
settings: Settings(buildSettings: ["SETTING_2": "VALUE"]))
let dynamicLibrary = Target(name: "MyDynamicLibrary", type: .dynamicLibrary, platform: .iOS,
settings: Settings(buildSettings: ["SETTING_2": "VALUE"]))
let framework = Target(
name: "MyFramework",
type: .framework,
platform: .iOS,
settings: Settings(buildSettings: ["SETTING_2": "VALUE"])
)
let staticLibrary = Target(
name: "MyStaticLibrary",
type: .staticLibrary,
platform: .iOS,
settings: Settings(buildSettings: ["SETTING_2": "VALUE"])
)
let dynamicLibrary = Target(
name: "MyDynamicLibrary",
type: .dynamicLibrary,
platform: .iOS,
settings: Settings(buildSettings: ["SETTING_2": "VALUE"])
)
func expectValidationError(_ spec: ProjectSpec, _ expectedError: SpecValidationError.ValidationError) throws {
do {
try spec.validate()
} catch let error as SpecValidationError {
if !error.errors.contains(where: { $0.description == expectedError.description }) {
if !error.errors
.contains(where: { $0.description == expectedError.description }) {
throw failure("Supposed to fail with:\n\(expectedError)\nbut got:\n\(error.errors.map { $0.description }.joined(separator: "\n"))")
}
return
@ -65,14 +78,19 @@ func projectSpecTests() {
$0.describe("Validation") {
let baseSpec = ProjectSpec(basePath: "", name: "", configs: [Config(name: "invalid")])
let invalidSettings = Settings(configSettings: ["invalidConfig": [:]],
groups: ["invalidSettingGroup"])
let invalidSettings = Settings(
configSettings: ["invalidConfig": [:]],
groups: ["invalidSettingGroup"]
)
$0.it("fails with invalid project") {
var spec = baseSpec
spec.settings = invalidSettings
spec.configFiles = ["invalidConfig": "invalidConfigFile"]
spec.fileGroups = ["invalidFileGroup"]
spec.settingGroups = ["settingGroup1": Settings(configSettings: ["invalidSettingGroupConfig": [:]], groups: ["invalidSettingGroupSettingGroup"])]
spec.settingGroups = ["settingGroup1": Settings(
configSettings: ["invalidSettingGroupConfig": [:]],
groups: ["invalidSettingGroupSettingGroup"]
)]
try expectValidationError(spec, .invalidConfigFileConfig("invalidConfig"))
try expectValidationError(spec, .invalidBuildSettingConfig("invalidConfig"))
@ -85,16 +103,17 @@ func projectSpecTests() {
$0.it("fails with invalid target") {
var spec = baseSpec
spec.targets = [Target(name: "target1",
type: .application,
platform: .iOS,
settings: invalidSettings,
configFiles: ["invalidConfig": "invalidConfigFile"],
sources: ["invalidSource"],
dependencies: [Dependency(type: .target, reference: "invalidDependency")],
prebuildScripts: [BuildScript(script: .path("invalidPrebuildScript"), name: "prebuildScript1")],
postbuildScripts: [BuildScript(script: .path("invalidPostbuildScript"))],
scheme: TargetScheme(testTargets: ["invalidTarget"])
spec.targets = [Target(
name: "target1",
type: .application,
platform: .iOS,
settings: invalidSettings,
configFiles: ["invalidConfig": "invalidConfigFile"],
sources: ["invalidSource"],
dependencies: [Dependency(type: .target, reference: "invalidDependency")],
prebuildScripts: [BuildScript(script: .path("invalidPrebuildScript"), name: "prebuildScript1")],
postbuildScripts: [BuildScript(script: .path("invalidPostbuildScript"))],
scheme: TargetScheme(testTargets: ["invalidTarget"])
)]
try expectValidationError(spec, .invalidTargetDependency(target: "target1", dependency: "invalidDependency"))
@ -115,10 +134,11 @@ func projectSpecTests() {
$0.it("fails with invalid scheme") {
var spec = baseSpec
spec.schemes = [Scheme(name: "scheme1",
build: .init(targets: [.init(target: "invalidTarget")]),
run: .init(config: "debugInvalid"),
archive: .init(config: "releaseInvalid")
spec.schemes = [Scheme(
name: "scheme1",
build: .init(targets: [.init(target: "invalidTarget")]),
run: .init(config: "debugInvalid"),
archive: .init(config: "releaseInvalid")
)]
try expectValidationError(spec, .invalidSchemeTarget(scheme: "scheme1", target: "invalidTarget"))
@ -128,10 +148,11 @@ func projectSpecTests() {
$0.it("allows missing optional file") {
var spec = baseSpec
spec.targets = [Target(name: "target1",
type: .application,
platform: .iOS,
sources: [.init(path: "generated.swift", optional: true)]
spec.targets = [Target(
name: "target1",
type: .application,
platform: .iOS,
sources: [.init(path: "generated.swift", optional: true)]
)]
try spec.validate()
}

View File

@ -224,15 +224,18 @@ func specLoadingTests() {
}
$0.it("parses options") {
let options = ProjectSpec.Options(carthageBuildPath: "../Carthage/Build",
createIntermediateGroups: true,
bundleIdPrefix: "com.test",
developmentLanguage: "ja",
deploymentTarget: DeploymentTarget(
iOS: "11.1",
tvOS: "10.0",
watchOS: "3.0",
macOS: "10.12.1"))
let options = ProjectSpec.Options(
carthageBuildPath: "../Carthage/Build",
createIntermediateGroups: true,
bundleIdPrefix: "com.test",
developmentLanguage: "ja",
deploymentTarget: DeploymentTarget(
iOS: "11.1",
tvOS: "10.0",
watchOS: "3.0",
macOS: "10.12.1"
)
)
let expected = ProjectSpec(basePath: "", name: "test", options: options)
let dictionary: [String: Any] = ["options": [
"carthageBuildPath": "../Carthage/Build",