diff --git a/Sources/ProjectSpec/AggregateTarget.swift b/Sources/ProjectSpec/AggregateTarget.swift index 45fcba14..27c445bc 100644 --- a/Sources/ProjectSpec/AggregateTarget.swift +++ b/Sources/ProjectSpec/AggregateTarget.swift @@ -1,5 +1,6 @@ import Foundation import JSONUtilities +import struct PathKit.Path public struct AggregateTarget: ProjectTarget { public var name: String @@ -61,3 +62,17 @@ extension AggregateTarget: NamedJSONDictionaryConvertible { attributes = jsonDictionary.json(atKeyPath: "attributes") ?? [:] } } + +extension AggregateTarget: PathContaining { + + static func expandPaths(for source: [String: JSONDictionary], relativeTo path: Path) -> [String: JSONDictionary] { + var result = source + + for (targetName, var target) in result { + target = expandStringPaths(from: target, forKey: "configFiles", relativeTo: path) + target = expandChildPaths(from: target, forKey: "buildScripts", relativeTo: path, type: BuildScript.self) + result[targetName] = target + } + return result + } +} diff --git a/Sources/ProjectSpec/BuildScript.swift b/Sources/ProjectSpec/BuildScript.swift index 30b63404..6d3315bd 100644 --- a/Sources/ProjectSpec/BuildScript.swift +++ b/Sources/ProjectSpec/BuildScript.swift @@ -1,5 +1,6 @@ import Foundation import JSONUtilities +import struct PathKit.Path public struct BuildScript: Equatable { @@ -53,3 +54,10 @@ extension BuildScript: JSONObjectConvertible { showEnvVars = jsonDictionary.json(atKeyPath: "showEnvVars") ?? true } } + +extension BuildScript: PathContaining { + + static func expandPaths(for source: JSONDictionary, relativeTo path: Path) -> JSONDictionary { + return expandStringPaths(from: source, forKey: "path", relativeTo: path) + } +} diff --git a/Sources/ProjectSpec/Dependency.swift b/Sources/ProjectSpec/Dependency.swift index 722aae65..76641d8f 100644 --- a/Sources/ProjectSpec/Dependency.swift +++ b/Sources/ProjectSpec/Dependency.swift @@ -1,5 +1,6 @@ import Foundation import JSONUtilities +import struct PathKit.Path public struct Dependency: Equatable { @@ -72,3 +73,10 @@ extension Dependency: JSONObjectConvertible { } } } + +extension Dependency: PathContaining { + + static func expandPaths(for source: JSONDictionary, relativeTo path: Path) -> JSONDictionary { + return expandStringPaths(from: source, forKey: "framework", relativeTo: path) + } +} diff --git a/Sources/ProjectSpec/Plist.swift b/Sources/ProjectSpec/Plist.swift index 5b2a502a..d66721a2 100644 --- a/Sources/ProjectSpec/Plist.swift +++ b/Sources/ProjectSpec/Plist.swift @@ -1,5 +1,6 @@ import Foundation import JSONUtilities +import struct PathKit.Path public struct Plist: Equatable { @@ -24,3 +25,9 @@ extension Plist: JSONObjectConvertible { properties = jsonDictionary.json(atKeyPath: "properties") ?? [:] } } + +extension Plist: PathContaining { + static func expandPaths(for source: JSONDictionary, relativeTo path: Path) -> JSONDictionary { + return expandStringPaths(from: source, forKey: "path", relativeTo: path) + } +} diff --git a/Sources/ProjectSpec/Project.swift b/Sources/ProjectSpec/Project.swift index c5f78e52..2f948f26 100644 --- a/Sources/ProjectSpec/Project.swift +++ b/Sources/ProjectSpec/Project.swift @@ -168,6 +168,30 @@ extension Project { } } +extension Project: PathContaining { + + static func expandPaths(for spec: Spec, relativeTo basePath: Path = "") -> Spec { + let relativePath = (basePath + spec.relativePath).normalize() + guard relativePath != Path() else { + return spec + } + + var jsonDictionary = spec.jsonDictionary + + jsonDictionary = expandStringPaths(from: jsonDictionary, forKey: "configFiles", relativeTo: relativePath) + jsonDictionary = expandChildPaths(from: jsonDictionary, forKey: "options", relativeTo: relativePath, type: SpecOptions.self) + jsonDictionary = expandChildPaths(from: jsonDictionary, forKey: "targets", relativeTo: relativePath, type: Target.self) + jsonDictionary = expandChildPaths(from: jsonDictionary, forKey: "aggregateTargets", relativeTo: relativePath, type: AggregateTarget.self) + return Spec( + relativePath: spec.relativePath, + jsonDictionary: jsonDictionary, + subSpecs: spec.subSpecs.map { template in + return Project.expandPaths(for: template, relativeTo: relativePath) + } + ) + } +} + extension Project { public var allFiles: [Path] { diff --git a/Sources/ProjectSpec/SpecOptions.swift b/Sources/ProjectSpec/SpecOptions.swift index f218c88b..295fdbb3 100644 --- a/Sources/ProjectSpec/SpecOptions.swift +++ b/Sources/ProjectSpec/SpecOptions.swift @@ -1,5 +1,6 @@ import Foundation import JSONUtilities +import struct PathKit.Path public struct SpecOptions: Equatable { @@ -120,3 +121,15 @@ extension SpecOptions: JSONObjectConvertible { generateEmptyDirectories = jsonDictionary.json(atKeyPath: "generateEmptyDirectories") ?? false } } + +extension SpecOptions: PathContaining { + + static func expandPaths(for source: JSONDictionary, relativeTo path: Path) -> JSONDictionary { + var result = source + + result = expandStringPaths(from: result, forKey: "carthageBuildPath", relativeTo: path) + result = expandStringPaths(from: result, forKey: "carthageExecutablePath", relativeTo: path) + result = expandStringPaths(from: result, forKey: "defaultConfig", relativeTo: path) + return result + } +} diff --git a/Sources/ProjectSpec/Target.swift b/Sources/ProjectSpec/Target.swift index b7727e66..3cd7aed4 100644 --- a/Sources/ProjectSpec/Target.swift +++ b/Sources/ProjectSpec/Target.swift @@ -1,5 +1,6 @@ import Foundation import JSONUtilities +import struct PathKit.Path import xcodeproj public struct LegacyTarget: Equatable { @@ -110,6 +111,30 @@ extension Target: CustomStringConvertible { } } +extension Target: PathContaining { + + static func expandPaths(for source: [String: JSONDictionary], relativeTo path: Path) -> [String: JSONDictionary] { + var result = source + for (targetName, var target) in result { + + // sources can either be an array of strings or an array of objects, so attempt to expand both + target = expandStringPaths(from: target, forKey: "sources", relativeTo: path) + target = expandChildPaths(from: target, forKey: "sources", relativeTo: path, type: TargetSource.self) + + target = expandStringPaths(from: target, forKey: "configFiles", relativeTo: path) + target = expandChildPaths(from: target, forKey: "dependencies", relativeTo: path, type: Dependency.self) + target = expandChildPaths(from: target, forKey: "info", relativeTo: path, type: Plist.self) + target = expandChildPaths(from: target, forKey: "entitlements", relativeTo: path, type: Plist.self) + target = expandChildPaths(from: target, forPotentialKeys: ["preBuildScripts", "prebuildScripts"], relativeTo: path, type: BuildScript.self) + target = expandChildPaths(from: target, forKey: "postCompileScripts", relativeTo: path, type: BuildScript.self) + target = expandChildPaths(from: target, forKey: "postBuildScripts", relativeTo: path, type: BuildScript.self) + + result[targetName] = target + } + return result + } +} + extension Target { static func resolveTargetTemplates(jsonDictionary: JSONDictionary) throws -> JSONDictionary { diff --git a/Sources/ProjectSpec/TargetSource.swift b/Sources/ProjectSpec/TargetSource.swift index fe51e445..4ad78dde 100644 --- a/Sources/ProjectSpec/TargetSource.swift +++ b/Sources/ProjectSpec/TargetSource.swift @@ -1,6 +1,6 @@ import Foundation import JSONUtilities -import PathKit +import struct PathKit.Path import xcodeproj public struct TargetSource: Equatable { @@ -207,3 +207,14 @@ extension TargetSource.BuildPhase.CopyFilesSettings: JSONObjectConvertible { phaseOrder = .postCompile } } + +extension TargetSource: PathContaining { + + static func expandPaths(for source: JSONDictionary, relativeTo path: Path) -> JSONDictionary { + var result = source + + result = expandStringPaths(from: result, forKey: "path", relativeTo: path) + result = expandStringPaths(from: result, forKey: "excludes", relativeTo: path) + return result + } +}