Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update for XcodeProj with strongly typed settings #145

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@
"package": "XcodeProj",
"repositoryURL": "https://github.com/tuist/xcodeproj.git",
"state": {
"branch": null,
"revision": "6f90427e172da66336739801c84b9cef3e17367b",
"version": "8.26.6"
"branch": "waltflanagan/StrongTypes",
"revision": "bf96639f81663c8c032a0296e75c911041c95220",
"version": null
}
}
]
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ let package = Package(
dependencies: [
.package(url: "https://github.com/apple/swift-tools-support-core.git", from: "0.3.0"),
.package(url: "https://github.com/kylef/PathKit", from: "1.0.0"),
.package(url: "https://github.com/tuist/xcodeproj.git", from: "8.26.6"),
.package(url: "https://github.com/tuist/xcodeproj.git", branch: "waltflanagan/StrongTypes"),
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.0"),
],
targets: [
Expand Down
2 changes: 1 addition & 1 deletion Sources/XCDiffCore/Comparator/CopyFilesComparator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ final class CopyFilesComparator: Comparator {
) ?? buildFile.file?.path else {
return nil
}
let attributes = buildFile.settings?["ATTRIBUTES"] as? [String] ?? []
let attributes = buildFile.settings?["ATTRIBUTES"]?.arrayValue ?? []

return BuildFileDescriptor(
name: path,
Expand Down
24 changes: 18 additions & 6 deletions Sources/XCDiffCore/Comparator/ResolvedSettingsComparator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
secondBuildSettings)
}

private func buildSettings(path: String, target: String, configuration: String) throws -> [String: String] {
private func buildSettings(path: String, target: String, configuration: String) throws -> [String: BuildSetting] {
let command = extractBuildSettingsCommand(path: path, target: target, config: configuration)
let output = try system.execute(arguments: command)
do {
Expand Down Expand Up @@ -100,24 +100,36 @@
return arguments
}

private func parseRawJsonBuildSettings(output: String) throws -> [String: String] {
private func parseRawJsonBuildSettings(output: String) throws -> [String: BuildSetting] {
let data = output.data(using: .utf8)!
let result = try jsonDecoder.decode([RawShowBuildSettingsItem].self, from: data)
var buildSettings = result[0].buildSettings
let replacementKeys: [String] = ["PROJECT_TEMP_DIR", "PROJECT_TEMP_ROOT", "BUILD_DIR", "PROJECT_FILE_PATH"]
let replacementValues = replacementKeys.compactMap { (key: String) -> (key: String, value: String)? in
let replacementValues = replacementKeys.compactMap { (key: String) -> (key: String, value: BuildSetting)? in
buildSettings[key].map { (key: key, value: $0) }
}
replacementValues.forEach { replacement in
buildSettings.forEach { setting in
buildSettings[setting.key] =
setting.value.replacingOccurrences(of: replacement.value, with: "$(\(replacement.key))")
switch setting.value {
case let .string(stringValue):
buildSettings[setting.key] =
.string(
stringValue.replacingOccurrences(of: "\(replacement.value)", with: "$(\(replacement.key))")
)
case let .array(arrayValue):
buildSettings[setting.key] =
.array(
arrayValue.map {
$0.replacingOccurrences(of: "\(replacement.value)", with: "$(\(replacement.key))")
}
)

Check warning on line 125 in Sources/XCDiffCore/Comparator/ResolvedSettingsComparator.swift

View check run for this annotation

Codecov / codecov/patch

Sources/XCDiffCore/Comparator/ResolvedSettingsComparator.swift#L120-L125

Added lines #L120 - L125 were not covered by tests
}
}
}
return buildSettings
}
}

private struct RawShowBuildSettingsItem: Decodable {
let buildSettings: [String: String]
let buildSettings: [String: BuildSetting]
}
31 changes: 31 additions & 0 deletions Sources/XCDiffCore/Library/PBX+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,34 @@
}
}
}

extension BuildSetting {
var stringValue: String {
switch self {
case let .string(value):
value
case let .array(value):
value.joined(separator: ", ")
}
}
}

extension BuildFileSetting {
var stringValue: String {
switch self {
case let .string(value):
value
case let .array(value):
value.joined(separator: ", ")
}
}

var arrayValue: [String] {
switch self {
case let .string(value):
[value]

Check warning on line 89 in Sources/XCDiffCore/Library/PBX+Extensions.swift

View check run for this annotation

Codecov / codecov/patch

Sources/XCDiffCore/Library/PBX+Extensions.swift#L89

Added line #L89 was not covered by tests
case let .array(value):
value
}
}
}
38 changes: 17 additions & 21 deletions Sources/XCDiffCore/Library/SettingsHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,16 @@ class SettingsHelper {
let onlyInSecond = secondKeys.subtractingAndSorted(firstKeys).map { keyAndValue($0, buildSettings: second) }

// we attempt to ignore differences that are a result of different project names
let firstProjectName = first["PROJECT_NAME"] as? String
let secondProjectName = second["PROJECT_NAME"] as? String
let firstProjectName = first["PROJECT_NAME"]?.stringValue
let secondProjectName = second["PROJECT_NAME"]?.stringValue
let settingValueComparator = SettingValueComparator(firstProjectName: firstProjectName,
secondProjectName: secondProjectName)

let valueDifferences: [CompareResult.DifferentValues] = try commonKeys.compactMap { settingName in
let valueDifferences: [CompareResult.DifferentValues] = commonKeys.compactMap { settingName in
let firstSetting = first[settingName]
let secondSettings = second[settingName]
let firstString = try stringFromBuildSetting(firstSetting)
let secondString = try stringFromBuildSetting(secondSettings)
let firstString = stringFromBuildSetting(firstSetting)
let secondString = stringFromBuildSetting(secondSettings)
guard settingValueComparator.compare(firstString, secondString) == .orderedSame else {
return .init(context: settingName,
first: firstString,
Expand All @@ -57,25 +57,21 @@ class SettingsHelper {
// MARK: - Private

private func keyAndValue(_ key: String, buildSettings: BuildSettings) -> String {
return "\(key) = \(buildSettings[key] ?? "nil")"
return "\(key) = \(buildSettings[key]?.settingDiffValue ?? "nil")"
}

private func stringFromBuildSetting(_ buildSetting: Any?) throws -> String {
// try to unwrap
guard let buildSetting else {
return "nil"
}

// try to cast to string
if let buildSettingString = buildSetting as? String {
return buildSettingString
}
private func stringFromBuildSetting(_ buildSetting: BuildSetting?) -> String {
buildSetting?.stringValue ?? "nil"
}
}

// try to case to array
if let buildSettingArray = buildSetting as? NSArray {
return buildSettingArray.compactMap { $0 as? String }.joined(separator: " ")
extension BuildSetting {
var settingDiffValue: String {
switch self {
case let .string(value):
value
case let .array(value):
"\(value)"
}

throw ComparatorError.generic("Cannot convert build setting to string")
}
}
23 changes: 2 additions & 21 deletions Sources/XCDiffCore/Library/TargetsHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -318,30 +318,11 @@ final class TargetsHelper {

private extension PBXBuildFile {
func compilerFlags() -> String? {
guard let flags = settings?["COMPILER_FLAGS"] else {
return nil
}
if let flagsString = flags as? String {
return flagsString
}
if let flagsArray = flags as? [String] {
return flagsArray.joined(separator: ", ")
}

return nil
settings?["COMPILER_FLAGS"]?.stringValue
}

func attributes() -> String? {
guard let anyAttributes = settings?["ATTRIBUTES"] else {
return nil
}
if let attributes = anyAttributes as? [String] {
return attributes.joined(separator: ", ")
}
if let attributes = anyAttributes as? String {
return attributes
}
return String(describing: anyAttributes)
settings?["ATTRIBUTES"]?.stringValue
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ import XcodeProj

final class PBXBuildConfigurationBuilder {
private let name: String
private var buildSettings: [String: Any] = [:]
private var buildSettings: [String: BuildSetting] = [:]
private var baseConfiguration: PBXFileReference?

init(name: String) {
self.name = name
}

@discardableResult
func setValue(_ value: Any, forKey key: String) -> PBXBuildConfigurationBuilder {
func setValue(_ value: BuildSetting, forKey key: String) -> PBXBuildConfigurationBuilder {
buildSettings[key] = value
return self
}
Expand Down
6 changes: 3 additions & 3 deletions Tests/XCDiffCoreTests/Helpers/PBXBuildFileBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ final class PBXBuildFileBuilder {
private var name: String?
private var platformFilter: String?
private var platformFilters: [String]?
private var settings: [String: Any]?
private var settings: [String: BuildFileSetting]?
private var packageProduct: SwiftPackageProductDependencyData?

@discardableResult
Expand Down Expand Up @@ -51,13 +51,13 @@ final class PBXBuildFileBuilder {

@discardableResult
func setSettings(_ settings: [String: [String]]) -> PBXBuildFileBuilder {
self.settings = settings
self.settings = settings.mapValues { .array($0) }
return self
}

@discardableResult
func setSettings(_ settings: [String: String]) -> PBXBuildFileBuilder {
self.settings = settings
self.settings = settings.mapValues { .string($0) }
return self
}

Expand Down
Loading