mirror of
https://github.com/yonaskolb/XcodeGen.git
synced 2026-03-18 20:02:25 +00:00
167d11998a
* Add explicitFolders support to syncedFolder Adds an `explicitFolders` property to `TargetSource` that is expanded from Glob patterns and passed through to `PBXFileSystemSynchronizedRootGroup`. * Fix syncedFolder sources ignoring createIntermediateGroups When createIntermediateGroups was enabled and a syncedFolder source had a multi-component path (e.g. SyncedParent/SyncedChild), two things went wrong: 1. The synced folder was unconditionally added to rootGroups, causing it to appear both at the project root and inside the correct intermediate parent group. 2. The synced folder kept its full project-relative path instead of being made relative to its parent group, so Xcode concatenated them into a wrong path (e.g. SyncedParent/SyncedParent/SyncedChild). * Enhance PBXFileElement to recognize synced folders as groups that can be sorted * Fix membership exceptions for nested synced folder with intermediate groups * Update Changelog
169 lines
5.9 KiB
Swift
169 lines
5.9 KiB
Swift
import Foundation
|
|
import JSONUtilities
|
|
import PathKit
|
|
|
|
public struct TargetSource: Equatable {
|
|
public static let optionalDefault = false
|
|
|
|
public var path: String {
|
|
didSet {
|
|
path = (path as NSString).standardizingPath
|
|
}
|
|
}
|
|
|
|
public var name: String?
|
|
public var group: String?
|
|
public var compilerFlags: [String]
|
|
public var excludes: [String]
|
|
public var includes: [String]
|
|
public var explicitFolders: [String]
|
|
public var type: SourceType?
|
|
public var optional: Bool
|
|
public var buildPhase: BuildPhaseSpec?
|
|
public var headerVisibility: HeaderVisibility?
|
|
public var createIntermediateGroups: Bool?
|
|
public var attributes: [String]
|
|
public var resourceTags: [String]
|
|
public var inferDestinationFiltersByPath: Bool?
|
|
public var destinationFilters: [SupportedDestination]?
|
|
|
|
public enum HeaderVisibility: String {
|
|
case `public`
|
|
case `private`
|
|
case project
|
|
|
|
public var settingName: String {
|
|
switch self {
|
|
case .public: return "Public"
|
|
case .private: return "Private"
|
|
case .project: return "Project"
|
|
}
|
|
}
|
|
}
|
|
|
|
public init(
|
|
path: String,
|
|
name: String? = nil,
|
|
group: String? = nil,
|
|
compilerFlags: [String] = [],
|
|
excludes: [String] = [],
|
|
includes: [String] = [],
|
|
explicitFolders: [String] = [],
|
|
type: SourceType? = nil,
|
|
optional: Bool = optionalDefault,
|
|
buildPhase: BuildPhaseSpec? = nil,
|
|
headerVisibility: HeaderVisibility? = nil,
|
|
createIntermediateGroups: Bool? = nil,
|
|
attributes: [String] = [],
|
|
resourceTags: [String] = [],
|
|
inferDestinationFiltersByPath: Bool? = nil,
|
|
destinationFilters: [SupportedDestination]? = nil
|
|
) {
|
|
self.path = (path as NSString).standardizingPath
|
|
self.name = name
|
|
self.group = group
|
|
self.compilerFlags = compilerFlags
|
|
self.excludes = excludes
|
|
self.includes = includes
|
|
self.explicitFolders = explicitFolders
|
|
self.type = type
|
|
self.optional = optional
|
|
self.buildPhase = buildPhase
|
|
self.headerVisibility = headerVisibility
|
|
self.createIntermediateGroups = createIntermediateGroups
|
|
self.attributes = attributes
|
|
self.resourceTags = resourceTags
|
|
self.inferDestinationFiltersByPath = inferDestinationFiltersByPath
|
|
self.destinationFilters = destinationFilters
|
|
}
|
|
}
|
|
|
|
extension TargetSource: ExpressibleByStringLiteral {
|
|
|
|
public init(stringLiteral value: String) {
|
|
self = TargetSource(path: value)
|
|
}
|
|
|
|
public init(extendedGraphemeClusterLiteral value: String) {
|
|
self = TargetSource(path: value)
|
|
}
|
|
|
|
public init(unicodeScalarLiteral value: String) {
|
|
self = TargetSource(path: value)
|
|
}
|
|
}
|
|
|
|
extension TargetSource: JSONObjectConvertible {
|
|
|
|
public init(jsonDictionary: JSONDictionary) throws {
|
|
path = try jsonDictionary.json(atKeyPath: "path")
|
|
path = (path as NSString).standardizingPath // Done in two steps as the compiler can't figure out the types otherwise
|
|
name = jsonDictionary.json(atKeyPath: "name")
|
|
group = jsonDictionary.json(atKeyPath: "group")
|
|
|
|
let maybeCompilerFlagsString: String? = jsonDictionary.json(atKeyPath: "compilerFlags")
|
|
let maybeCompilerFlagsArray: [String]? = jsonDictionary.json(atKeyPath: "compilerFlags")
|
|
compilerFlags = maybeCompilerFlagsArray ??
|
|
maybeCompilerFlagsString.map { $0.split(separator: " ").map { String($0) } } ?? []
|
|
|
|
headerVisibility = jsonDictionary.json(atKeyPath: "headerVisibility")
|
|
excludes = jsonDictionary.json(atKeyPath: "excludes") ?? []
|
|
includes = jsonDictionary.json(atKeyPath: "includes") ?? []
|
|
explicitFolders = jsonDictionary.json(atKeyPath: "explicitFolders") ?? []
|
|
type = jsonDictionary.json(atKeyPath: "type")
|
|
optional = jsonDictionary.json(atKeyPath: "optional") ?? TargetSource.optionalDefault
|
|
|
|
if let string: String = jsonDictionary.json(atKeyPath: "buildPhase") {
|
|
buildPhase = try BuildPhaseSpec(string: string)
|
|
} else if let dict: JSONDictionary = jsonDictionary.json(atKeyPath: "buildPhase") {
|
|
buildPhase = try BuildPhaseSpec(jsonDictionary: dict)
|
|
}
|
|
|
|
createIntermediateGroups = jsonDictionary.json(atKeyPath: "createIntermediateGroups")
|
|
attributes = jsonDictionary.json(atKeyPath: "attributes") ?? []
|
|
resourceTags = jsonDictionary.json(atKeyPath: "resourceTags") ?? []
|
|
|
|
inferDestinationFiltersByPath = jsonDictionary.json(atKeyPath: "inferDestinationFiltersByPath")
|
|
|
|
if let destinationFilters: [SupportedDestination] = jsonDictionary.json(atKeyPath: "destinationFilters") {
|
|
self.destinationFilters = destinationFilters
|
|
}
|
|
}
|
|
}
|
|
|
|
extension TargetSource: JSONEncodable {
|
|
public func toJSONValue() -> Any {
|
|
var dict: [String: Any?] = [
|
|
"compilerFlags": compilerFlags,
|
|
"excludes": excludes,
|
|
"includes": includes,
|
|
"explicitFolders": explicitFolders,
|
|
"name": name,
|
|
"group": group,
|
|
"headerVisibility": headerVisibility?.rawValue,
|
|
"type": type?.rawValue,
|
|
"buildPhase": buildPhase?.toJSONValue(),
|
|
"createIntermediateGroups": createIntermediateGroups,
|
|
"resourceTags": resourceTags,
|
|
"path": path,
|
|
"inferDestinationFiltersByPath": inferDestinationFiltersByPath,
|
|
"destinationFilters": destinationFilters?.map { $0.rawValue },
|
|
]
|
|
|
|
if optional != TargetSource.optionalDefault {
|
|
dict["optional"] = optional
|
|
}
|
|
|
|
return dict
|
|
}
|
|
}
|
|
|
|
extension TargetSource: PathContainer {
|
|
|
|
static var pathProperties: [PathProperty] {
|
|
[
|
|
.string("path"),
|
|
]
|
|
}
|
|
}
|