-
-
Notifications
You must be signed in to change notification settings - Fork 505
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
Allow setting deployment target devices #541
Changes from all commits
14fe176
ef67e4c
fb0252b
d1ef2ea
7486e0d
cc9f231
a37720d
37ee400
4e851d3
0e2086d
c9de8b3
8f5ecc2
5fc3300
440fea8
9aabecc
bcab6cb
93909c0
f400cc1
2221d1e
8f2c178
7d3c7a0
83c1faf
30e915a
d9e82b7
f408af8
86d1980
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import Foundation | ||
|
||
// MARK: - DeploymentDevice | ||
|
||
public struct DeploymentDevice: OptionSet, Codable { | ||
public static let iphone = DeploymentDevice(rawValue: 1 << 0) | ||
public static let ipad = DeploymentDevice(rawValue: 1 << 1) | ||
public static let mac = DeploymentDevice(rawValue: 1 << 2) | ||
|
||
public let rawValue: UInt | ||
|
||
public init(rawValue: UInt) { | ||
self.rawValue = rawValue | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import Foundation | ||
|
||
// MARK: - DeploymentTarget | ||
|
||
public enum DeploymentTarget: Codable { | ||
case iOS(targetVersion: String, devices: DeploymentDevice) | ||
case macOS(targetVersion: String) | ||
// TODO: π Add `watchOS` and `tvOS` support | ||
|
||
private enum Kind: String, Codable { | ||
case iOS | ||
case macOS | ||
} | ||
|
||
enum CodingKeys: String, CodingKey { | ||
case kind | ||
case version | ||
case deploymentDevices | ||
} | ||
|
||
public init(from decoder: Decoder) throws { | ||
let container = try decoder.container(keyedBy: CodingKeys.self) | ||
let kind = try container.decode(Kind.self, forKey: .kind) | ||
switch kind { | ||
case .iOS: | ||
let version = try container.decode(String.self, forKey: .version) | ||
let deploymentDevices = try container.decode(DeploymentDevice.self, forKey: .deploymentDevices) | ||
self = .iOS(targetVersion: version, devices: deploymentDevices) | ||
case .macOS: | ||
let version = try container.decode(String.self, forKey: .version) | ||
self = .macOS(targetVersion: version) | ||
} | ||
} | ||
|
||
public func encode(to encoder: Encoder) throws { | ||
var container = encoder.container(keyedBy: CodingKeys.self) | ||
switch self { | ||
case let .iOS(version, deploymentDevices): | ||
try container.encode(Kind.iOS.self, forKey: .kind) | ||
try container.encode(version, forKey: .version) | ||
try container.encode(deploymentDevices, forKey: .deploymentDevices) | ||
case let .macOS(version): | ||
try container.encode(Kind.macOS.self, forKey: .kind) | ||
try container.encode(version, forKey: .version) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import Foundation | ||
|
||
// MARK: - Regex | ||
|
||
extension String { | ||
public func matches(pattern: String) -> Bool { | ||
guard let range = self.range(of: pattern, options: .regularExpression) else { | ||
return false | ||
} | ||
return range == self.range(of: self) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -128,6 +128,11 @@ final class ConfigGenerator: ConfigGenerating { | |
let settingsHelper = SettingsHelper() | ||
var settings = try defaultSettingsProvider.targetSettings(target: target, | ||
buildConfiguration: buildConfiguration) | ||
updateTargetDerived(buildSettings: &settings, | ||
target: target, | ||
graph: graph, | ||
sourceRootPath: sourceRootPath) | ||
|
||
settingsHelper.extend(buildSettings: &settings, with: target.settings?.base ?? [:]) | ||
settingsHelper.extend(buildSettings: &settings, with: configuration?.settings ?? [:]) | ||
|
||
|
@@ -139,11 +144,6 @@ final class ConfigGenerator: ConfigGenerating { | |
variantBuildConfiguration.baseConfiguration = fileReference | ||
} | ||
|
||
updateTargetDerived(buildSettings: &settings, | ||
target: target, | ||
graph: graph, | ||
sourceRootPath: sourceRootPath) | ||
|
||
variantBuildConfiguration.buildSettings = settings.toAny() | ||
pbxproj.add(object: variantBuildConfiguration) | ||
configurationList.buildConfigurations.append(variantBuildConfiguration) | ||
|
@@ -191,5 +191,24 @@ final class ConfigGenerator: ConfigGenerating { | |
} | ||
} | ||
} | ||
|
||
if let deploymentTarget = target.deploymentTarget { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any help how we could test it? Shall we add checking the settings build to an existing method in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, here's an example of one of the test cases that could be written in func test_generateTargetWithDeploymentTarget() throws {
// Given
let target = Target.test(deploymentTarget: .iOS("12.0", [.iphone, .ipad]))
// When
try subject.generateTargetConfig(target,
pbxTarget: pbxTarget,
pbxproj: pbxproj,
projectSettings: .default,
fileElements: ProjectFileElements(),
graph: Graph.test(),
sourceRootPath: AbsolutePath("/project"))
// Then
let configurationList = pbxTarget.buildConfigurationList
let debugConfig = configurationList?.configuration(name: "Debug")
let releaseConfig = configurationList?.configuration(name: "Release")
let expectedSettings = [
"TARGETED_DEVICE_FAMILY": "1,2",
"IPHONEOS_DEPLOYMENT_TARGET": "12.0"
]
assert(config: debugConfig, contains: expectedSettings)
assert(config: releaseConfig, contains: expectedSettings)
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added deployment target tests to |
||
switch deploymentTarget { | ||
case let .iOS(version, devices): | ||
var deviceFamilyValues: [Int] = [] | ||
if devices.contains(.iphone) { deviceFamilyValues.append(1) } | ||
if devices.contains(.ipad) { deviceFamilyValues.append(2) } | ||
|
||
settings["TARGETED_DEVICE_FAMILY"] = .string(deviceFamilyValues.map { "\($0)" }.joined(separator: ",")) | ||
settings["IPHONEOS_DEPLOYMENT_TARGET"] = .string(version) | ||
|
||
if devices.contains(.ipad), devices.contains(.mac) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah didn't realise this ... is the iPad checkbox a pre-requisite to the Mac checkbox ? i.e. is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
settings["SUPPORTS_MACCATALYST"] = "YES" | ||
settings["DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER"] = "YES" | ||
} | ||
case let .macOS(version): | ||
settings["MACOSX_DEPLOYMENT_TARGET"] = .string(version) | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import Foundation | ||
|
||
// MARK: - DeploymentDevice | ||
|
||
public struct DeploymentDevice: OptionSet { | ||
public static let iphone = DeploymentDevice(rawValue: 1 << 0) | ||
public static let ipad = DeploymentDevice(rawValue: 1 << 1) | ||
public static let mac = DeploymentDevice(rawValue: 1 << 2) | ||
|
||
public let rawValue: UInt | ||
|
||
public init(rawValue: UInt) { | ||
self.rawValue = rawValue | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import Foundation | ||
|
||
// MARK: - DeploymentTarget | ||
|
||
public enum DeploymentTarget { | ||
case iOS(String, DeploymentDevice) | ||
case macOS(String) | ||
// TODO: π Add `watchOS` and `tvOS` support | ||
pepicrft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
public var platform: String { | ||
switch self { | ||
case .iOS: return "iOS" | ||
case .macOS: return "macOS" | ||
} | ||
} | ||
|
||
public var version: String { | ||
switch self { | ||
case let .iOS(version, _): return version | ||
case let .macOS(version): return version | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import Foundation | ||
import TuistCoreTesting | ||
import XCTest | ||
|
||
@testable import ProjectDescription | ||
|
||
final class DeploymentTargetTests: XCTestCase { | ||
func test_toJSON_whenIOS() { | ||
let subject = DeploymentTarget.iOS(targetVersion: "13.1", devices: [.iphone, .ipad]) | ||
let expected = "{\"kind\":\"iOS\",\"version\":\"13.1\",\"deploymentDevices\":3}" | ||
XCTAssertCodableEqualToJson(subject, expected) | ||
} | ||
|
||
func test_toJSON_whenMacOS() { | ||
let subject = DeploymentTarget.macOS(targetVersion: "10.15") | ||
let expected = "{\"kind\":\"macOS\",\"version\":\"10.15\"}" | ||
XCTAssertCodableEqualToJson(subject, expected) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import SPMUtility | ||
import XCTest | ||
@testable import TuistCore | ||
|
||
final class StringRegexTests: XCTestCase { | ||
func test_string_regex() { | ||
let osVersionPattern = "\\b[0-9]+\\.[0-9]+(?:\\.[0-9]+)?\\b" | ||
XCTAssertTrue("10.0.1".matches(pattern: osVersionPattern)) | ||
XCTAssertFalse("tuist".matches(pattern: osVersionPattern)) | ||
|
||
let twoDigitsOnlyPattern = "^[0-9]{2}$" | ||
XCTAssertTrue("10".matches(pattern: twoDigitsOnlyPattern)) | ||
XCTAssertFalse("10.0.1".matches(pattern: twoDigitsOnlyPattern)) | ||
|
||
let singleWordPattern = "project*" | ||
XCTAssertTrue("project".matches(pattern: singleWordPattern)) | ||
XCTAssertFalse("This is a project".matches(pattern: singleWordPattern)) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Soon :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, what platforms should we support in this PR? π€
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I leave this TODO or is it possible to support
watchOS
andtvOS
right now?