From efed786cec1fac143d72801d5e516d464a073029 Mon Sep 17 00:00:00 2001 From: Jierong Li Date: Thu, 3 Dec 2020 06:52:24 +0900 Subject: [PATCH] Add baseOnDependencyAnalysis to Project Spec Build Script (#992) * Add baseOnDependencyAnalysis to BuildScript * Add tests for baseOnDependencyAnalysis * Update CHANGELOG.md --- CHANGELOG.md | 1 + Docs/ProjectSpec.md | 1 + Sources/ProjectSpec/BuildScript.swift | 11 ++++++++++- Sources/XcodeGenKit/PBXProjGenerator.swift | 3 ++- .../TestProject/Project.xcodeproj/project.pbxproj | 1 + Tests/Fixtures/TestProject/project.yml | 1 + Tests/ProjectSpecTests/ProjectSpecTests.swift | 12 ++++++++---- Tests/ProjectSpecTests/SpecLoadingTests.swift | 12 ++++++++---- 8 files changed, 32 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9a46585..c0c22cf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Support for building and running on Linux platforms. Tested for compatibility with Swift 5.3+ and Ubuntu 18.04. [#988](https://github.com/yonaskolb/XcodeGen/pull/988) @elliottwilliams - Add `useBaseInternationalization` to Project Spec Options to opt out of Base Internationalization. [#961](https://github.com/yonaskolb/XcodeGen/pull/961) @liamnichols - More detailed error message with method arguments. [#990](https://github.com/yonaskolb/XcodeGen/pull/990) @bannzai +- Added `baseOnDependencyAnalysis` to Project Spec Build Script to be able to choose not to skip the script. [#992](https://github.com/yonaskolb/XcodeGen/pull/992) @myihsan #### Fixed - Fixed error message output for `minimumXcodeGenVersion`. [#967](https://github.com/yonaskolb/XcodeGen/pull/967) @joshwalker diff --git a/Docs/ProjectSpec.md b/Docs/ProjectSpec.md index a6ce3d4a..c992af48 100644 --- a/Docs/ProjectSpec.md +++ b/Docs/ProjectSpec.md @@ -563,6 +563,7 @@ Each script can contain: - [ ] **shell**: **String** - shell used for the script. Defaults to `/bin/sh` - [ ] **showEnvVars**: **Bool** - whether the environment variables accessible to the script show be printed to the build log. Defaults to yes - [ ] **runOnlyWhenInstalling**: **Bool** - whether the script is only run when installing (`runOnlyForDeploymentPostprocessing`). Defaults to no +- [ ] **baseOnDependencyAnalysis**: **Bool** - whether to skip the script if inputs, context, or outputs haven't changed. Defaults to yes Either a **path** or **script** must be defined, the rest are optional. diff --git a/Sources/ProjectSpec/BuildScript.swift b/Sources/ProjectSpec/BuildScript.swift index 9c280e1d..0fccf54b 100644 --- a/Sources/ProjectSpec/BuildScript.swift +++ b/Sources/ProjectSpec/BuildScript.swift @@ -4,6 +4,7 @@ import JSONUtilities public struct BuildScript: Equatable { public static let runOnlyWhenInstallingDefault = false public static let showEnvVarsDefault = true + public static let baseOnDependencyAnalysisDefault = true public var script: ScriptType public var name: String? @@ -14,6 +15,7 @@ public struct BuildScript: Equatable { public var outputFileLists: [String] public var runOnlyWhenInstalling: Bool public let showEnvVars: Bool + public let baseOnDependencyAnalysis: Bool public enum ScriptType: Equatable { case path(String) @@ -29,7 +31,8 @@ public struct BuildScript: Equatable { outputFileLists: [String] = [], shell: String? = nil, runOnlyWhenInstalling: Bool = runOnlyWhenInstallingDefault, - showEnvVars: Bool = showEnvVarsDefault + showEnvVars: Bool = showEnvVarsDefault, + baseOnDependencyAnalysis: Bool = baseOnDependencyAnalysisDefault ) { self.script = script self.name = name @@ -40,6 +43,7 @@ public struct BuildScript: Equatable { self.shell = shell self.runOnlyWhenInstalling = runOnlyWhenInstalling self.showEnvVars = showEnvVars + self.baseOnDependencyAnalysis = baseOnDependencyAnalysis } } @@ -61,6 +65,7 @@ extension BuildScript: JSONObjectConvertible { shell = jsonDictionary.json(atKeyPath: "shell") runOnlyWhenInstalling = jsonDictionary.json(atKeyPath: "runOnlyWhenInstalling") ?? BuildScript.runOnlyWhenInstallingDefault showEnvVars = jsonDictionary.json(atKeyPath: "showEnvVars") ?? BuildScript.showEnvVarsDefault + baseOnDependencyAnalysis = jsonDictionary.json(atKeyPath: "baseOnDependencyAnalysis") ?? BuildScript.baseOnDependencyAnalysisDefault } } @@ -80,6 +85,10 @@ extension BuildScript: JSONEncodable { dict["showEnvVars"] = showEnvVars } + if baseOnDependencyAnalysis != BuildScript.baseOnDependencyAnalysisDefault { + dict["baseOnDependencyAnalysis"] = baseOnDependencyAnalysis + } + switch script { case .path(let string): dict["path"] = string diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index 55e13ce7..4cff3b27 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -478,7 +478,8 @@ public class PBXProjGenerator { shellPath: buildScript.shell ?? "/bin/sh", shellScript: shellScript, runOnlyForDeploymentPostprocessing: buildScript.runOnlyWhenInstalling, - showEnvVarsInLog: buildScript.showEnvVars + showEnvVarsInLog: buildScript.showEnvVars, + alwaysOutOfDate: !buildScript.baseOnDependencyAnalysis ) return addObject(shellScriptPhase) } diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj b/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj index 185a1781..6d4ccc57 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj @@ -2115,6 +2115,7 @@ }; 71A4CC6ECC8522178F566E7B /* Strip Unused Architectures from Frameworks */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); diff --git a/Tests/Fixtures/TestProject/project.yml b/Tests/Fixtures/TestProject/project.yml index dd129f35..ff0f75f7 100644 --- a/Tests/Fixtures/TestProject/project.yml +++ b/Tests/Fixtures/TestProject/project.yml @@ -144,6 +144,7 @@ targets: - path: scripts/strip-frameworks.sh name: Strip Unused Architectures from Frameworks runOnlyWhenInstalling: true + baseOnDependencyAnalysis: false - name: MyScript script: | echo "You ran a script!" diff --git a/Tests/ProjectSpecTests/ProjectSpecTests.swift b/Tests/ProjectSpecTests/ProjectSpecTests.swift index 1f465154..a1a32df7 100644 --- a/Tests/ProjectSpecTests/ProjectSpecTests.swift +++ b/Tests/ProjectSpecTests/ProjectSpecTests.swift @@ -388,7 +388,8 @@ class ProjectSpecTests: XCTestCase { outputFileLists: ["bar.xcfilelist"], shell: "/bin/bash", runOnlyWhenInstalling: true, - showEnvVars: true)], + showEnvVars: true, + baseOnDependencyAnalysis: false)], postCompileScripts: [BuildScript(script: .path("cmd.sh"), name: "Bar script", inputFiles: ["foo"], @@ -397,7 +398,8 @@ class ProjectSpecTests: XCTestCase { outputFileLists: ["bar.xcfilelist"], shell: "/bin/bash", runOnlyWhenInstalling: true, - showEnvVars: true)], + showEnvVars: true, + baseOnDependencyAnalysis: false)], postBuildScripts: [BuildScript(script: .path("cmd.sh"), name: "an another script", inputFiles: ["foo"], @@ -406,7 +408,8 @@ class ProjectSpecTests: XCTestCase { outputFileLists: ["bar.xcfilelist"], shell: "/bin/bash", runOnlyWhenInstalling: true, - showEnvVars: true)], + showEnvVars: true, + baseOnDependencyAnalysis: false)], buildRules: [BuildRule(fileType: .pattern("*.xcassets"), action: .script("pre_process_swift.py"), name: "My Build Rule", @@ -455,7 +458,8 @@ class ProjectSpecTests: XCTestCase { outputFileLists: ["bar.xcfilelist"], shell: "/bin/bash", runOnlyWhenInstalling: true, - showEnvVars: false)], + showEnvVars: false, + baseOnDependencyAnalysis: false)], scheme: TargetScheme(testTargets: [Scheme.Test.TestTarget(targetReference: "test target", randomExecutionOrder: false, parallelizable: false)], diff --git a/Tests/ProjectSpecTests/SpecLoadingTests.swift b/Tests/ProjectSpecTests/SpecLoadingTests.swift index 3a7b5ec5..ba3b450c 100644 --- a/Tests/ProjectSpecTests/SpecLoadingTests.swift +++ b/Tests/ProjectSpecTests/SpecLoadingTests.swift @@ -1052,8 +1052,10 @@ class SpecLoadingTests: XCTestCase { ["path": "script.sh"], ["script": "shell script\ndo thing", "name": "myscript", "inputFiles": ["file", "file2"], "outputFiles": ["file", "file2"], "shell": "bin/customshell", "runOnlyWhenInstalling": true], ["script": "shell script\ndo thing", "name": "myscript", "inputFiles": ["file", "file2"], "outputFiles": ["file", "file2"], "shell": "bin/customshell", "showEnvVars": false], + ["script": "shell script\ndo thing", "name": "myscript", "inputFiles": ["file", "file2"], "outputFiles": ["file", "file2"], "shell": "bin/customshell", "baseOnDependencyAnalysis": false], ["script": "shell script\nwith file lists", "name": "myscript", "inputFileLists": ["inputList.xcfilelist"], "outputFileLists": ["outputList.xcfilelist"], "shell": "bin/customshell", "runOnlyWhenInstalling": true], ["script": "shell script\nwith file lists", "name": "myscript", "inputFileLists": ["inputList.xcfilelist"], "outputFileLists": ["outputList.xcfilelist"], "shell": "bin/customshell", "showEnvVars": false], + ["script": "shell script\nwith file lists", "name": "myscript", "inputFileLists": ["inputList.xcfilelist"], "outputFileLists": ["outputList.xcfilelist"], "shell": "bin/customshell", "baseOnDependencyAnalysis": false], ] target["preBuildScripts"] = scripts target["postCompileScripts"] = scripts @@ -1061,10 +1063,12 @@ class SpecLoadingTests: XCTestCase { let expectedScripts = [ BuildScript(script: .path("script.sh")), - BuildScript(script: .script("shell script\ndo thing"), name: "myscript", inputFiles: ["file", "file2"], outputFiles: ["file", "file2"], shell: "bin/customshell", runOnlyWhenInstalling: true, showEnvVars: true), - BuildScript(script: .script("shell script\ndo thing"), name: "myscript", inputFiles: ["file", "file2"], outputFiles: ["file", "file2"], shell: "bin/customshell", runOnlyWhenInstalling: false, showEnvVars: false), - BuildScript(script: .script("shell script\nwith file lists"), name: "myscript", inputFileLists: ["inputList.xcfilelist"], outputFileLists: ["outputList.xcfilelist"], shell: "bin/customshell", runOnlyWhenInstalling: true, showEnvVars: true), - BuildScript(script: .script("shell script\nwith file lists"), name: "myscript", inputFileLists: ["inputList.xcfilelist"], outputFileLists: ["outputList.xcfilelist"], shell: "bin/customshell", runOnlyWhenInstalling: false, showEnvVars: false), + BuildScript(script: .script("shell script\ndo thing"), name: "myscript", inputFiles: ["file", "file2"], outputFiles: ["file", "file2"], shell: "bin/customshell", runOnlyWhenInstalling: true, showEnvVars: true, baseOnDependencyAnalysis: true), + BuildScript(script: .script("shell script\ndo thing"), name: "myscript", inputFiles: ["file", "file2"], outputFiles: ["file", "file2"], shell: "bin/customshell", runOnlyWhenInstalling: false, showEnvVars: false, baseOnDependencyAnalysis: true), + BuildScript(script: .script("shell script\ndo thing"), name: "myscript", inputFiles: ["file", "file2"], outputFiles: ["file", "file2"], shell: "bin/customshell", runOnlyWhenInstalling: false, showEnvVars: true, baseOnDependencyAnalysis: false), + BuildScript(script: .script("shell script\nwith file lists"), name: "myscript", inputFileLists: ["inputList.xcfilelist"], outputFileLists: ["outputList.xcfilelist"], shell: "bin/customshell", runOnlyWhenInstalling: true, showEnvVars: true, baseOnDependencyAnalysis: true), + BuildScript(script: .script("shell script\nwith file lists"), name: "myscript", inputFileLists: ["inputList.xcfilelist"], outputFileLists: ["outputList.xcfilelist"], shell: "bin/customshell", runOnlyWhenInstalling: false, showEnvVars: false, baseOnDependencyAnalysis: true), + BuildScript(script: .script("shell script\nwith file lists"), name: "myscript", inputFileLists: ["inputList.xcfilelist"], outputFileLists: ["outputList.xcfilelist"], shell: "bin/customshell", runOnlyWhenInstalling: false, showEnvVars: true, baseOnDependencyAnalysis: false), ] let parsedTarget = try Target(name: "test", jsonDictionary: target)