From 0328fa03e79a8072ac1bbc9734b65dc864cb2e06 Mon Sep 17 00:00:00 2001 From: Sebastian Celis Date: Mon, 6 Apr 2020 13:37:37 -0500 Subject: [PATCH] Add improved support for simple iOS sticker packs (#824) * Allow messages applications to skip the compile sources phase By default, simple iOS sticker packs created in Xcode do not include a compile sources phase. This change will allow messages applications with an empty list of sources to skip that phase entirely. * Add support for launchAutomaticallySubstyle in run schemes This is especially important for simple iOS sticker packs that require this run scheme setting to be set to 2 in order to run the scheme properly. --- CHANGELOG.md | 1 + Docs/Examples.md | 1 + Docs/ProjectSpec.md | 1 + Sources/ProjectSpec/Scheme.swift | 12 +++++++++ Sources/ProjectSpec/XCProjExtensions.swift | 11 ++++++++ Sources/XcodeGenKit/PBXProjGenerator.swift | 4 +-- Sources/XcodeGenKit/SchemeGenerator.swift | 3 ++- .../Project.xcodeproj/project.pbxproj | 8 ------ Tests/ProjectSpecTests/ProjectSpecTests.swift | 3 ++- Tests/ProjectSpecTests/SpecLoadingTests.swift | 26 +++++++++++++++++++ .../SchemeGeneratorTests.swift | 3 ++- 11 files changed, 59 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 151e75cb..c54b96d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Next Version #### Added - Improve speed of metadata parsing and dependency resolution. [#803](https://github.com/yonaskolb/XcodeGen/pull/803) @michaeleisel +- Improve support for iOS sticker packs and add support for `launchAutomaticallySubstyle` to run schemes. [#824](https://github.com/yonaskolb/XcodeGen/pull/824) @scelis ## 2.15.1 diff --git a/Docs/Examples.md b/Docs/Examples.md index 1da7c2bf..d10f8663 100644 --- a/Docs/Examples.md +++ b/Docs/Examples.md @@ -7,3 +7,4 @@ These are a bunch of real world examples of XcodeGen project specs. Feel free to - [johndpope/swift-models](https://github.com/johndpope/swift-models/tree/stable/Inference) - [atelier-socle/AppRepositoryTemplate](https://github.com/atelier-socle/AppRepositoryTemplate/blob/master/project.yml) - [atelier-socle/FrameworkRepositoryTemplate](https://github.com/atelier-socle/FrameworkRepositoryTemplate/blob/master/project.yml) +- [scelis/XcodeGen-TestStickers](https://github.com/scelis/XcodeGen-TestStickers/blob/master/project.yml) diff --git a/Docs/ProjectSpec.md b/Docs/ProjectSpec.md index 6800f4f2..8ac4af01 100644 --- a/Docs/ProjectSpec.md +++ b/Docs/ProjectSpec.md @@ -738,6 +738,7 @@ The different actions share some properties: - [ ] **region**: **String** - `run` and `test` actions can define a language that is used for Application Region - [ ] **debugEnabled**: **Bool** - `run` and `test` actions can define a whether debugger should be used. This defaults to true. - [ ] **simulateLocation**: **[Simulate Location](#simulate-location)** - `run` action can define a simulated location +- [ ] **launchAutomaticallySubstyle**: **String** - `run` action can define the launch automatically substyle ('2' for extensions). ### Execution Action diff --git a/Sources/ProjectSpec/Scheme.swift b/Sources/ProjectSpec/Scheme.swift index e7b0059f..4584975f 100644 --- a/Sources/ProjectSpec/Scheme.swift +++ b/Sources/ProjectSpec/Scheme.swift @@ -107,6 +107,7 @@ public struct Scheme: Equatable { public var stopOnEveryMainThreadCheckerIssue: Bool public var language: String? public var region: String? + public var launchAutomaticallySubstyle: String? public var debugEnabled: Bool public var simulateLocation: SimulateLocation? @@ -120,6 +121,7 @@ public struct Scheme: Equatable { stopOnEveryMainThreadCheckerIssue: Bool = stopOnEveryMainThreadCheckerIssueDefault, language: String? = nil, region: String? = nil, + launchAutomaticallySubstyle: String? = nil, debugEnabled: Bool = debugEnabledDefault, simulateLocation: SimulateLocation? = nil ) { @@ -132,6 +134,7 @@ public struct Scheme: Equatable { self.stopOnEveryMainThreadCheckerIssue = stopOnEveryMainThreadCheckerIssue self.language = language self.region = region + self.launchAutomaticallySubstyle = launchAutomaticallySubstyle self.debugEnabled = debugEnabled self.simulateLocation = simulateLocation } @@ -349,6 +352,14 @@ extension Scheme.Run: JSONObjectConvertible { region = jsonDictionary.json(atKeyPath: "region") debugEnabled = jsonDictionary.json(atKeyPath: "debugEnabled") ?? Scheme.Run.debugEnabledDefault simulateLocation = jsonDictionary.json(atKeyPath: "simulateLocation") + + // launchAutomaticallySubstyle is defined as a String in XcodeProj but its value is often + // an integer. Parse both to be nice. + if let int: Int = jsonDictionary.json(atKeyPath: "launchAutomaticallySubstyle") { + launchAutomaticallySubstyle = String(int) + } else if let string: String = jsonDictionary.json(atKeyPath: "launchAutomaticallySubstyle") { + launchAutomaticallySubstyle = string + } } } @@ -362,6 +373,7 @@ extension Scheme.Run: JSONEncodable { "config": config, "language": language, "region": region, + "launchAutomaticallySubstyle": launchAutomaticallySubstyle, ] if disableMainThreadChecker != Scheme.Run.disableMainThreadCheckerDefault { diff --git a/Sources/ProjectSpec/XCProjExtensions.swift b/Sources/ProjectSpec/XCProjExtensions.swift index 7d90a723..11c35f26 100644 --- a/Sources/ProjectSpec/XCProjExtensions.swift +++ b/Sources/ProjectSpec/XCProjExtensions.swift @@ -41,6 +41,17 @@ extension PBXProductType { public var name: String { rawValue.replacingOccurrences(of: "com.apple.product-type.", with: "") } + + public var canSkipCompileSourcesBuildPhase: Bool { + switch self { + case .stickerPack, .messagesApplication: + // Sticker packs and simple messages applications without sources should not include a + // compile sources build phase. Doing so can cause Xcode to produce an error on build. + return true + default: + return false + } + } } extension Platform { diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index c47db40d..07fe5bc7 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -927,9 +927,7 @@ public class PBXProjGenerator { } let sourcesBuildPhaseFiles = getBuildFilesForPhase(.sources) - // Sticker packs should not include a compile sources build phase as they - // are purely based on a set of image files, and nothing else. - let shouldSkipSourcesBuildPhase = sourcesBuildPhaseFiles.isEmpty && target.type == .stickerPack + let shouldSkipSourcesBuildPhase = sourcesBuildPhaseFiles.isEmpty && target.type.canSkipCompileSourcesBuildPhase if !shouldSkipSourcesBuildPhase { let sourcesBuildPhase = addObject(PBXSourcesBuildPhase(files: sourcesBuildPhaseFiles)) buildPhases.append(sourcesBuildPhase) diff --git a/Sources/XcodeGenKit/SchemeGenerator.swift b/Sources/XcodeGenKit/SchemeGenerator.swift index 4df57ff3..5b787d57 100644 --- a/Sources/XcodeGenKit/SchemeGenerator.swift +++ b/Sources/XcodeGenKit/SchemeGenerator.swift @@ -241,7 +241,8 @@ public class SchemeGenerator { commandlineArguments: launchCommandLineArgs, environmentVariables: launchVariables, language: scheme.run?.language, - region: scheme.run?.region + region: scheme.run?.region, + launchAutomaticallySubstyle: scheme.run?.launchAutomaticallySubstyle ) let profileAction = XCScheme.ProfileAction( diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj b/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj index 1b20f798..d4d07410 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj @@ -1441,7 +1441,6 @@ isa = PBXNativeTarget; buildConfigurationList = 1FC6945BE13C2202A2BCA3BC /* Build configuration list for PBXNativeTarget "iMessageApp" */; buildPhases = ( - D067D70CFD13DFBED478C228 /* Sources */, 61001E265009194959C2CF36 /* Resources */, 2F0735A423E554B267BBA0A5 /* Embed App Extensions */, ); @@ -2143,13 +2142,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - D067D70CFD13DFBED478C228 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; D1F422E9C4DD531AA88418C9 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; diff --git a/Tests/ProjectSpecTests/ProjectSpecTests.swift b/Tests/ProjectSpecTests/ProjectSpecTests.swift index e0e165d2..f5d1080b 100644 --- a/Tests/ProjectSpecTests/ProjectSpecTests.swift +++ b/Tests/ProjectSpecTests/ProjectSpecTests.swift @@ -475,7 +475,8 @@ class ProjectSpecTests: XCTestCase { settingsTarget: "foo")], environmentVariables: [XCScheme.EnvironmentVariable(variable: "foo", value: "bar", - enabled: false)]), + enabled: false)], + launchAutomaticallySubstyle: "2"), test: Scheme.Test(config: "Config", gatherCoverageData: true, disableMainThreadChecker: true, diff --git a/Tests/ProjectSpecTests/SpecLoadingTests.swift b/Tests/ProjectSpecTests/SpecLoadingTests.swift index 1e048e34..3d55551f 100644 --- a/Tests/ProjectSpecTests/SpecLoadingTests.swift +++ b/Tests/ProjectSpecTests/SpecLoadingTests.swift @@ -771,6 +771,10 @@ class SpecLoadingTests: XCTestCase { ], ], ], + "run": [ + "config": "debug", + "launchAutomaticallySubstyle": 2, + ], "test": [ "config": "debug", "targets": [ @@ -806,6 +810,12 @@ class SpecLoadingTests: XCTestCase { try expect(scheme.build.parallelizeBuild) == false try expect(scheme.build.buildImplicitDependencies) == false + let expectedRun = Scheme.Run( + config: "debug", + launchAutomaticallySubstyle: "2" + ) + try expect(scheme.run) == expectedRun + let expectedTest = Scheme.Test( config: "debug", gatherCoverageData: true, @@ -835,6 +845,7 @@ class SpecLoadingTests: XCTestCase { ["variable": "ENVIRONMENT", "value": "VARIABLE"], ["variable": "OTHER_ENV_VAR", "value": "VAL", "isEnabled": false], ], + "launchAutomaticallySubstyle": "2" ], "test": [ "environmentVariables": [ @@ -864,11 +875,26 @@ class SpecLoadingTests: XCTestCase { ] try expect(scheme.run?.environmentVariables) == expectedRunVariables + try expect(scheme.run?.launchAutomaticallySubstyle) == "2" try expect(scheme.test?.environmentVariables) == expectedTestVariables try expect(scheme.profile?.config) == "Release" try expect(scheme.profile?.environmentVariables.isEmpty) == true } + $0.it("parses alternate schemes variables") { + let schemeDictionary: [String: Any] = [ + "build": [ + "targets": ["Target1": "all"], + ], + "run": [ + "launchAutomaticallySubstyle": 2, // Both integer and string supported + ], + ] + + let scheme = try Scheme(name: "Scheme", jsonDictionary: schemeDictionary) + try expect(scheme.run?.launchAutomaticallySubstyle) == "2" + } + $0.it("parses scheme templates") { let targetDictionary: [String: Any] = [ "deploymentTarget": "1.2.0", diff --git a/Tests/XcodeGenKitTests/SchemeGeneratorTests.swift b/Tests/XcodeGenKitTests/SchemeGeneratorTests.swift index 81ddb5e9..62cea300 100644 --- a/Tests/XcodeGenKitTests/SchemeGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/SchemeGeneratorTests.swift @@ -51,7 +51,7 @@ class SchemeGeneratorTests: XCTestCase { let scheme = Scheme( name: "MyScheme", build: Scheme.Build(targets: [buildTarget], preActions: [preAction]), - run: Scheme.Run(config: "Debug", simulateLocation: simulateLocation) + run: Scheme.Run(config: "Debug", launchAutomaticallySubstyle: "2", simulateLocation: simulateLocation) ) let project = Project( name: "test", @@ -94,6 +94,7 @@ class SchemeGeneratorTests: XCTestCase { try expect(xcscheme.launchAction?.selectedDebuggerIdentifier) == XCScheme.defaultDebugger try expect(xcscheme.testAction?.selectedDebuggerIdentifier) == XCScheme.defaultDebugger + try expect(xcscheme.launchAction?.launchAutomaticallySubstyle) == "2" try expect(xcscheme.launchAction?.allowLocationSimulation) == true try expect(xcscheme.launchAction?.locationScenarioReference?.referenceType) == Scheme.SimulateLocation.ReferenceType.predefined.rawValue try expect(xcscheme.launchAction?.locationScenarioReference?.identifier) == "New York, NY, USA"