From b4e0f019746338f53c49a7b3730daa087809b057 Mon Sep 17 00:00:00 2001 From: mcfans Date: Wed, 22 Feb 2023 11:25:04 +0800 Subject: [PATCH] Squashed commit of the following: commit bb02e0116410367aa497598d5f741490b57b4540 Author: takeshi-1000 Date: Thu Dec 8 05:15:58 2022 +0900 Fixed logic related to order of elements in localization directory Path array commit bad37c94cb3d1cd48b3027c9d272f7cced9e4dbb Author: takeshi-1000 Date: Thu Dec 8 05:09:44 2022 +0900 Revert "Fixed some logic in PBXVariantGroup." This reverts commit ea402c839f7672caa3ab9423f4ca4110928d459e. commit ea402c839f7672caa3ab9423f4ca4110928d459e Author: takeshi-1000 Date: Wed Dec 7 09:23:02 2022 +0900 Fixed some logic in PBXVariantGroup. Try to make the logic simpler so that an error does not occur under the Linux environment. commit b9359fb8a618ecd3f33dd8492abdc6ff4503680f Author: takeshi-1000 Date: Tue Dec 6 19:00:20 2022 +0900 fix fixtures test commit ca25eca7a740b606de7c201c34ac112ca2cf9e55 Author: takeshi-1000 Date: Tue Dec 6 12:33:23 2022 +0900 fix compilation error in ci enviroment commit a40341fb3dac36545a07c4fc4ab275cf5f486207 Author: takeshi-1000 Date: Mon Dec 5 21:05:49 2022 +0900 add test commit cb28c355b1eb7a75aac174e1b03ecafb247f22f3 Author: takeshi-1000 Date: Mon Dec 5 21:05:41 2022 +0900 update SourceGenerator, PBXProjGenerator, SourceType ## SourceGenerator - adapt SourceGenerator to TargetSourceFilterable - refactor variant group logic - add logic where you can add target membership to another target ## PBXProjGenerator - apply. new PBXProjGenerator ## SourceType - add new sourceType commit 8a33b015481c83d30d8dc5f582ea39afc8c953fd Author: takeshi-1000 Date: Mon Dec 5 21:05:08 2022 +0900 add PBXVariantGroupGenerator, TargetSourceFilterable commit e7f753785e6ee135e5ea77268d149e9cd10bb7ed Author: Mathieu Olivari <1377279+ma-oli@users.noreply.github.com> Date: Thu Nov 3 01:05:46 2022 -0700 Fix includes related issues and improve their performances (#1275) * Fix recursive include path when relativePath is not set If relativePath is not set on a particular include, the first level of include will currently work, but starting at the second level of iteration, the computed include path will fail as relativePath will be appended over and over onto the filePath. We're fixing that recursion problem here and adding the corresponding tests to make sure it doesn't happen again. * Include projectRoot in include paths The projectRoot setting (when specified) is currently ignored when computing the include paths. We're fixing that in that commit. * Use memoization during recursive SpecFiles creation SpecFile objects are created by recursive through includes. On a large project with programatically generated SpecFile, it is not rare to have hundreds of SpecFiles, creating a large web of include dependencies. In such a case, it is not rare either for a particular SpecFile to be included by multiple other SpecFiles. When that happens, XcodeGen currently creates a SpecFile object every time a SpecFile gets included, which can lead to an exponential growth of includes. I have seen hundreds of files being turned into hundred of thousands of SpecFile object creations, which leads to an impractical XcodeGen run of tens of minutes. This change adds memoization during SpecFile recursion, in order to reuse the previously created SpecFiles, if available, instead of re-creating them. * Update CHANGELOG.md Add the following changes to the changelog: * b97bdc4 - Use memoization during recursive SpecFiles creation * a6b96ad - Include projectRoot in include paths * 557b074 - Fix recursive include path when relativePath is not set commit 3e9fd048efdaa746debe71f0a0d8a29e08fe42f9 Author: Roland Date: Wed Nov 2 07:42:22 2022 +0100 allow multiple spec files to be provided to XcodeGen (#1270) * allow spec to be a comma separated list of specs instead of one * update readme and --spec command documentation * update Changelog * print project name commit 87d7c7e136caf6392738096dae0568355a0619e3 Author: Yonas Kolb Date: Sat Oct 1 20:50:18 2022 +1000 Update CHANGELOG.md commit 435c19443a279c03e7c655f4738b98fe35592571 Author: SofteqDG Date: Sat Oct 1 11:23:09 2022 +0300 Extend possible paths for SettingsPresets (#1135) * Search for presets in Bundle.main.resourcesPath dir (if exists) commit ed5ec74668180de55bd7f52e4a2e9e9ac333014a Author: Craig Siemens Date: Wed Sep 28 22:08:37 2022 -0600 Added scheme generation for aggregate targets (#1250) * Updated SchemeGenerator to generate schemes for all projectTargets. * Added changelog entry commit 6f331720c90438070b67195f3b2327c96b8a1a2b Author: Bobby Sudekum <1058624+bsudekum@users.noreply.github.com> Date: Fri Sep 9 01:43:39 2022 -0700 Add enableGPUFrameCaptureMode to Scheme (#1251) commit ebf70f1a718e90eeeefeebd02e1e0af1e9463f5a Author: Yonas Kolb Date: Fri Aug 19 00:53:34 2022 +1000 Update to 2.32.0 commit 594c67fbe9df46d8e898be3e51ac02aae8fca853 Author: freddi(Yuki Aki) Date: Fri Aug 12 15:21:43 2022 +0900 Add `enable` option for `include` to enable optional including for addtional spec (#1242) * add new option enable for include of spec * fix to see the environment variable when parsing include * add test for include with environment variable * fix how to parse boolean value * add spec about enable for include * add Change Log * fix the number of PR in changelog * fix include test to make more clear * fix test to focus enable option more * fix english error * fix to expand variable only one time * add new test case by setting environment object as NO commit e9295f1ff3284facb103e8a4dbb025f5246d5327 Author: Steven Sheldon Date: Thu Aug 11 05:45:06 2022 -0700 Fix profile action to not run frameworks (#1245) * Fix profile action to not run frameworks * Add PR number to changelog * Update CHANGELOG.md Co-authored-by: Yonas Kolb commit ac525a445e0a1420fbe56248e18f1f0d9826b1af Author: Shinolr Date: Tue Aug 9 22:32:33 2022 +0800 remove redundant bracket (#1243) commit 34f50d645e6a3b0d9930c2b105c00521bfe2c8cf Author: Isaac Halvorson Date: Mon Aug 1 17:27:14 2022 -0500 Correct name of package in example yaml (#1240) Hey there, I just noticed that one of the example yaml snippets had the wrong package name specified. commit ff552f38802d8b33b820bb09ccc71b5e79899379 Author: antonsergeev88 Date: Sun Jul 31 11:33:20 2022 +0300 Handle mlmodelc as a single unit (#1237) * Handle mlmodelc as a single unit * Add mlmodelc support in changelog commit de2a537ab4b6a88ee160b05b3c165ba42196586c Author: Yonas Kolb Date: Sun Jul 24 16:10:15 2022 +1000 Update to 2.31.0 commit 24572daeb5daac32b68a68e4cc4ec301151ea73b Author: Aleksei Sapitskii <45671572+aleksproger@users.noreply.github.com> Date: Sun Jul 24 09:08:33 2022 +0300 Added duplicate dependencies validation (#1234) **Reason** - More strict validation of added dependencies **Contents** - Added changelog entry - Added check for duplicates in validation stage - Added test commit da8aad004fab67da0ea3a126dc9791a65665bc36 Author: matsuji Date: Thu Jul 21 20:25:34 2022 +0900 Add a new CopyFilesBuildPhase, "Embed ExtensionKit Extensions" (#1230) * Embed ExtensionKit Extensions * Fix explicitFileType for extensionKit * Update ChangeLog * Fix if statement structure * Add a new example extension to Tests/Fixtures/TestProject/ * Update Tests/Fixtures/TestProject/Project.xcodeproj * Comment out example for extension kit extension in Tests/Fixtures/TestProject/ * Update Tests/Fixtures/TestProject/Project.xcodeproj commit c1d5c65ae48e70f7424cc2084904a688c0236d5d Author: Yonas Kolb Date: Sat Jul 16 16:57:26 2022 +1000 Update to 2.30.0 commit c082bc0c7cf0181907921c27df0f12da796c0fc1 Author: Aleksei Sapitskii <45671572+aleksproger@users.noreply.github.com> Date: Sat Jul 16 09:46:42 2022 +0300 Fix XcodeGen building after XcodeProj update to 8.8.0 (#1228) * Fix XcodeGen building after XcodeProj update to 8.8.0 **Reason** - XcodeProj has been updated and has API breaking changes **Content** - Added new enum case handling in `Linkage` - Renamed the enum case name for `XCWorkspaceDataFileRef.init` * add new product type to docs * update changelog Co-authored-by: Yonas Kolb commit 19817f319272cbb3cb5d20992a0289a733191b19 Author: Luca Bartoletti Date: Sat Jul 16 07:46:31 2022 +0100 Fix `watchapp2-container` product name (#1219) The correct name is `application.watchapp2-container` --- CHANGELOG.md | 199 +++++++++++++++- Docs/ProjectSpec.md | 11 +- Makefile | 2 +- Package.resolved | 4 +- Package.swift | 2 +- README.md | 4 +- Sources/ProjectSpec/AggregateTarget.swift | 2 + Sources/ProjectSpec/Dependency.swift | 2 +- Sources/ProjectSpec/FileType.swift | 1 + Sources/ProjectSpec/Linkage.swift | 3 +- Sources/ProjectSpec/Project.swift | 9 +- Sources/ProjectSpec/ProjectTarget.swift | 2 + Sources/ProjectSpec/Scheme.swift | 42 ++++ Sources/ProjectSpec/SourceType.swift | 1 + Sources/ProjectSpec/SpecFile.swift | 63 +++-- Sources/ProjectSpec/SpecLoader.swift | 5 +- Sources/ProjectSpec/SpecValidation.swift | 80 ++++--- Sources/ProjectSpec/SpecValidationError.swift | 3 + Sources/ProjectSpec/XCProjExtensions.swift | 2 +- Sources/XcodeGen/main.swift | 2 +- .../Commands/GenerateCommand.swift | 2 +- .../XcodeGenCLI/Commands/ProjectCommand.swift | 44 ++-- Sources/XcodeGenKit/PBXProjGenerator.swift | 31 ++- .../PBXVariantGroupGenerator.swift | 155 +++++++++++++ Sources/XcodeGenKit/ProjectGenerator.swift | 2 +- Sources/XcodeGenKit/SchemeGenerator.swift | 22 +- Sources/XcodeGenKit/SettingsBuilder.swift | 4 + Sources/XcodeGenKit/SourceGenerator.swift | 218 +++++------------- .../XcodeGenKit/TargetSourceFilterable.swift | 79 +++++++ Sources/XcodeGenKit/XCProjExtensions.swift | 6 +- .../xcshareddata/xcschemes/App.xcscheme | 22 +- ...{Main.storyboard => Storyboard.storyboard} | 0 .../App_Clip/en.lproj/Localizable.stringsdict | 30 +++ .../ExtensionKit Extension/EntryPoint.swift | 5 + .../ExtensionKit Extension/Info.plist | 11 + .../ExtensionKit Extension/Intent.swift | 9 + .../Project.xcodeproj/project.pbxproj | 48 +++- .../xcshareddata/xcschemes/App_Clip.xcscheme | 22 +- .../xcschemes/App_Scheme.xcscheme | 29 +-- .../xcschemes/App_iOS Production.xcscheme | 26 +-- .../xcschemes/App_iOS Staging.xcscheme | 26 +-- .../xcschemes/App_iOS Test.xcscheme | 26 +-- .../xcshareddata/xcschemes/App_macOS.xcscheme | 8 +- .../xcschemes/App_watchOS.xcscheme | 12 +- .../xcschemes/DriverKitDriver.xcscheme | 8 +- .../EndpointSecuritySystemExtension.xcscheme | 8 +- .../xcshareddata/xcschemes/Framework.xcscheme | 13 +- .../xcschemes/NetworkSystemExtension.xcscheme | 8 +- .../xcshareddata/xcschemes/Tool.xcscheme | 8 +- .../xcschemes/iMessageApp.xcscheme | 8 +- .../xcschemes/iMessageExtension.xcscheme | 12 +- Tests/Fixtures/TestProject/project.yml | 15 +- Tests/Fixtures/include_test.yml | 11 +- Tests/Fixtures/included_addtional.yml | 12 + .../legacy_included_paths_test.yml | 5 +- .../legacy_paths_test/recursive_include.yml | 4 + Tests/PerformanceTests/PerformanceTests.swift | 7 +- Tests/ProjectSpecTests/ProjectSpecTests.swift | 35 +++ Tests/ProjectSpecTests/SpecLoadingTests.swift | 38 ++- .../ProjectGeneratorTests.swift | 44 ++++ .../SchemeGeneratorTests.swift | 6 +- .../SourceGeneratorTests.swift | 90 +++++--- 62 files changed, 1162 insertions(+), 446 deletions(-) create mode 100644 Sources/XcodeGenKit/PBXVariantGroupGenerator.swift create mode 100644 Sources/XcodeGenKit/TargetSourceFilterable.swift rename Tests/Fixtures/TestProject/App_Clip/Base.lproj/{Main.storyboard => Storyboard.storyboard} (100%) create mode 100644 Tests/Fixtures/TestProject/App_Clip/en.lproj/Localizable.stringsdict create mode 100644 Tests/Fixtures/TestProject/ExtensionKit Extension/EntryPoint.swift create mode 100644 Tests/Fixtures/TestProject/ExtensionKit Extension/Info.plist create mode 100644 Tests/Fixtures/TestProject/ExtensionKit Extension/Intent.swift create mode 100644 Tests/Fixtures/included_addtional.yml create mode 100644 Tests/Fixtures/legacy_paths_test/recursive_include.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index b8200acb..b4af2736 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,52 @@ ## Next Version +### Added + +- Added support for `enableGPUFrameCaptureMode` #1251 @bsudekum +- Config setting presets can now also be loaded from the main bundle when bundling XcodeGenKit #1135 @SofteqDG +- Added ability to generate multiple projects in one XcodeGen launch #1270 @skofgar +- Use memoization during recursive SpecFiles creation. This provides a drastic performance boost with lots of recursive includes #1275 @ma-oli + +### Fixed + +- Fix scheme not being generated for aggregate targets #1250 @CraigSiemens +- Fix recursive include path when relativePath is not set #1275 @ma-oli +- Include projectRoot in include paths #1275 @ma-oli + +## 2.32.0 + +### Added + +- Add support for `mlmodelc` files #1236 @antonsergeev88 +- Add `enable` option for `include` #1242 @freddi-kit + +### Fixed + +- Fix checking environment variable in `include` #1242 @freddi-kit +- Fix profile action for frameworks in Xcode 14 #1245 @SSheldon + +## 2.31.0 + +### Added + +- Added a new CopyFilesBuildPhase, "Embed ExtensionKit Extensions" #1230 @mtj0928 +- Added duplicate dependencies validation #1234 @aleksproger + +## 2.30.0 + +### Added + +- Added support for new target type `extensionkit-extension` in Xcode 14 #1228 @aleksproger + ### Changed - Speed up generating build settings for large projects #1221 @jpsim +### Fixed + +- Fix XcodeGen building as library after breaking XcodeProj update 8.8.0 #1228 @aleksproger + ## 2.29.0 Some support for Xcode Test Plans has been added. For now test plans are not generated by XcodeGen and must be created in Xcode and checked in, and then referenced by path. If the test targets are added, removed or renamed, the test plans may need to be updated in Xcode @@ -26,7 +68,7 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen #### Added -- Support for specifying custom group locations for SPM packages. #1173 @John-Connolly +- Support for specifying custom group locations for SPM packages. #1173 @John-Connolly ### Fixed @@ -58,11 +100,12 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen ### Changed -- Speed up source inclusion checking for big projects #1122 @PaulTaykalo +- Speed up source inclusion checking for big projects #1122 @PaulTaykalo ## 2.25.0 ### Added + - Allow specifying a `copy` setting for each dependency. #1038 @JakubBednar ### Fixed @@ -86,50 +129,61 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen - Add ability to specify UI testing screenshot behavior in test schemes #942 @daltonclaybrook ### Changed + - **Breaking**: Rename the `platform` field on `Dependency` to `platformFilter` #1087 @daltonclaybrook ## 2.23.1 ### Changed + - Reverted "Change FRAMEWORK_SEARCH_PATH for xcframeworks (#1015)", introduced in 2.20.0. XCFrameworks need to be referenced directly in the project for Xcode's build system to extract the appropriate frameworks #1081 @elliottwilliams ## 2.23.0 #### Added + - Added ability to set custom platform for dependency #934 @raptorxcz #### Fixed + - Added `()` to config variant trimming charater set to fix scheme config variant lookups for some configs like `Debug (Development)` that broke in 2.22.0 #1078 @DavidWoohyunLee - Fixed Linux builds on Swift 5.4 #1083 @yonaskolb ## 2.22.0 #### Added + - Support `runPostActionsOnFailure` for running build post scripts on failing build #1075 @freddi-kit #### Changed + - Xcode no longer alerts to project changes after regeneration, due to internal workspace not regenerating if identical #1072 @yonaskolb #### Fixed + - Fixed no such module `DOT` error when package is used as a dependency #1067 @yanamura - Fixed scheme config variant lookups for some configs like `ProdDebug` and `Prod-Debug` that broke in 2.21.0 #1070 @yonaskolb ## 2.21.0 #### Added + - Support weak link for Swift Package Dependency #1064 @freddi-kit #### Changed + - Carthage frameworks are no longer embedded for "order-only" target dependencies. This avoid redundant embeds in situations where a target's sources _import_ a Carthage framework but do not have a binary dependency on it (like a test target which runs in a host app). #1041 @elliottwilliams #### Fixed + - The `Core` target is renamed to avoid collisions with other packages. #1057 @elliottwilliams - Lookup scheme config variants by whole words, fixing incorrect assignment in names that contain subtrings of each other (eg PreProd and Prod) #976 @stefanomondino ## 2.20.0 #### Added + - Allow specifying a `github` name like `JohnSundell/Ink` instead of a full `url` for Swift Packages #1029 @yonaskolb - Added explicity `LastUpgradeCheck` and `LastUpgradeVersion` override support so it's possible to override these properties without using the `project.xcodeVersion`. [1013](https://github.com/yonaskolb/XcodeGen/pull/1013) @Andre113 - Added `macroExpansion` for `run` in `schemes` #1036 @freddi-kit @@ -137,17 +191,20 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen - Added support for selectedTests in schemes `Test` configuration. #913 @ooodin #### Fixed + - Fixed regression on `.storekit` configuration files' default build phase. #1026 @jcolicchio - Fixed framework search paths when using `.xcframework`s. #1015 @FranzBusch - Fixed bug where schemes without a build target would crash instead of displaying an error #1040 @dalemyers - Fixed files with names ending in **Info.plist** (such as **GoogleServices-Info.plist**) from being omitted from the Copy Resources build phase. Now, only the resolved info plist file for each specific target is omitted. #1027 @liamnichols #### Internal + - Build universal binaries for release. XcodeGen now runs natively on Apple Silicon. #1024 @thii ## 2.19.0 #### Added + - Added support for building and running on Linux platforms. Tested for compatibility with Swift 5.3+ and Ubuntu 18.04. #988 @elliottwilliams - Added `useBaseInternationalization` to Project Spec Options to opt out of Base Internationalization. #961 @liamnichols - Added `storeKitConfiguration` to allow specifying StoreKit Configuration in Scheme and TargetScheme, supporting either xcodeproj or xcworkspace via `schemePathPrefix` option. #964 @jcolicchio @@ -157,22 +214,26 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen - Added discovered dependency file for a build script #1012 @polac24 @fggeraissate #### Changed + - **Breaking**: Info.plists with custom prefixes are no longer added to the Copy Bundle Resources build phase #945 @anivaros - **Breaking**: `workingDirectory` of included legacy targets is now made relative to including project #981 @jcolicchio - **Breaking**: Make `simulateLocation` respect `schemePathPrefix` option. #973 @jcolicchio #### Fixed + - Fixed error message output for `minimumXcodeGenVersion`. #967 @joshwalker - Remove force-unwrapping causing crash for `LegacyTarget`s #982 @jcolicchio - Fixed a race condition in an internal JSON decoder, which would occasionally fail with an error like `Parsing project spec failed: Error Domain=Unspecified error Code=0`. #995 @elliottwilliams - Fixed issue where frameworks with `MACH_O_TYPE: staticlib` were being incorrectly embedded. #1003 @mrabiciu #### Internal + - Updated to Yams 4.0.0 #984 @swiftty ## 2.18.0 #### Added + - Add `Scheme.Test.TestTarget.skipped` to allow skipping of an entire test target. #916 @codeman9 - Added ability to set custom LLDBInit scripts for launch and test schemes #929 @polac24 - Adds App Clip support. #909 @brentleyjones @dflems @@ -181,12 +242,15 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen - Enable Base Internationalization by default as per Xcode 12 behavior. #954 @liamnichols #### Changed + - Change default project version to Xcode 12 #960 @yonaskolb #### Internal + - Updates CI to run on Xcode 12. #936 @dflems @yonaskolb #### Fixed + - Select the first runnable build target, if present. #957 @codeman9 - Allow SDK dependencies to be embedded. #922 @k-thorat - Allow creating intermediary groups outside of the project directory. #892 @segiddins @@ -196,21 +260,25 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen ## 2.17.0 #### Added + - Added `options.fileTypes` which lets you set cross project defaults for certain file extensions #914 @yonaskolb - Added `onlyCopyFilesOnInstall` option to targets for the Embed Files build phase. #912 @jsorge #### Fixed + - Treat all directories with known UTI as file wrapper. #896 @KhaosT - Generated schemes for application extensions now contain `wasCreatedForAppExtension = YES`. #898 @muizidn - Allow package dependencies to use `link: false` #920 @k-thorat - Fixed issue computing relative paths. #915 @andrewreach #### Internal + - Updated to XcodeProj 7.13.0 #908 @brentleyjones ## 2.16.0 #### Added + - Improve speed of metadata parsing and dependency resolution. #803 @michaeleisel - Improve support for iOS sticker packs and add support for `launchAutomaticallySubstyle` to run schemes. #824 @scelis - Add --project-root option to generate command. #828 @ileitch @@ -221,6 +289,7 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen - Added ability to set executable to Ask to Launch. #871 @pinda #### Fixed + - Fixed issue when linking and embeding static frameworks: they should be linked and NOT embed. #820 @acecilia - Fixed issue when generating projects for paths with a dot in the folder for swift sources. #826 @asifmohd - Prefix static library target filenames with 'lib' to match Xcode. #831 @ileitch @@ -242,6 +311,7 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen ## 2.15.1 #### Fixed + - Fixed issue which caused watch app schemes to be generated incorrectly, preventing these apps from launching. #798 @daltonclaybrook - Added build presets for the target type `framework.static`. #819 @acecilia - Fixed XcodeProj resolution and updated to 7.10.0 #822 @soffes @@ -249,10 +319,12 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen ## 2.15.0 #### Added + - Add support for local Swift Packages in `packages` using `path`. #808 @freddi-kit - Add `buildImplicitDependencies` as an option on `TargetScheme`. #810 @evandcoleman #### Fixed + - Fixed resolving path to local Swift Packages #796 @freddi-kit - Added ability to stop on every main thread checker issue on Run schemes and TargetSchemes #799 @ionutivan - Avoid copying ObjC interface header when SWIFT_INSTALL_OBJC_HEADER=false. #805 @kateinoigakukun @@ -260,9 +332,11 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen ## 2.14.0 #### Added + - Add ability to embed and code sign Swift package dependencies with dynamic products. #788 @alexruperez #### Fixed + - Revert "Add Base to known regions even if one doesn't exist" #791 @bryansum - Set `defaultConfigurationName` for every target which is defined in a project. #787 @ken0nek - Set `TEST_TARGET_NAME` only when a project has UITest bundle. #792 @ken0nek @@ -271,30 +345,36 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen ## 2.13.1 #### Fixed + - Validate scheme test action and test coverage target references before generating. #775 @liamnichols - Fixed parsing prerelease identifiers in Swift package versions #779 @yonaskolb - Fixed using legacy targets as dependencies #778 @yonaskolb #### Internal + - Updated to XcodeProj 7.8.0 #777 @yonaskolb -- Use https://github.com/mxcl/Version #779 @yonaskolb +- Use #779 @yonaskolb ## 2.13.0 #### Added + - Support External Target References via subprojects. #701 @evandcoleman #### Fixed + - Fixed compilation as library by locking down XcodeProj version #767 @yonaskolb - Stabilized sorting of groups with duplicate names/paths. #671 @ChristopherRogers - Moved `Copy Bundle Resources` to after `Link with Libraries` build phase #768 @yonaskolb #### Internal + - Updated to XcodeProj 7.7.0 #767 @yonaskolb ## 2.12.0 #### Added + - Added pre and post command options. Useful for running `pod install` in combination with `--use-cache` #759 @yonaskolb - Support for language and region settings on a target basis #728 @FranzBusch - Added option to generate only Info.plist files with `--only-plists` #739 @namolnad @@ -302,6 +382,7 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen - Support for On Demand Resources tags #753 @sipao #### Fixed + - Fixed resolving a relative path for `projectReference.path` #740 @kateinoigakukun - Don't add framework dependency's directory to `FRAMEWORK_SEARCH_PATHS` if it is implicit #744 @ikesyo @yutailang0119 - Fixed resolving relative path passed to `XcodeProj` #751 @PycKamil @@ -309,11 +390,13 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen - Added an extra check for package versions. #755 @basvankuijck #### Internal + - Update to SwiftCLI 6.0 and use the new property wrappers #749 @yonaskolb ## 2.11.0 #### Added + - Add Carthage static framework dependencies support. #688 @giginet - Added `xcodegen dump` command #710 @yonaskolb - Added `--no-env` option to disable environment variables expansion #704 @rcari @@ -321,6 +404,7 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen - Added new dependency type, `bundle`. This allows targets to copy bundles from other projects #616 @bsmith11 #### Fixed + - Improved variable expansion runtime #704 @rcari - Fixed missing headers for static framework targets #705 @wag-miles - Using more file types from XcodeProj for PBXFileReferences resulting in less project diffs #715 @yonaskolb @@ -329,6 +413,7 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen - Fixed unnecessary dependencies related to SwiftPM #726 @tid-kijyun #### Changed + - Deprecated `$old_form` variables in favor of `${new_form}` variables #704 @rcari - Updated XcodeProj to 7.4.0 #709 @yonaskolb - Updated to Swift 5.1 #714 @yonaskolb @@ -336,6 +421,7 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen ## 2.10.1 #### Fixed + - Add Base to knownRegions even if one doesn't exist #694 @bryansum - Fixed missing `onlyGenerateCoverageForSpecifiedTargets` issue #700 @kateinoigakukun - Fixed regression on dependencies `link` flag #703 @rcari @@ -343,10 +429,12 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen ## 2.10.0 #### Added + - Support Target Reference to another project. #655 @kateinoigakukun - Added `coverageTargets` for test target. This enables to gather code coverage for specific targets. #656 @kateinoigakukun #### Fixed + - Add base localisation by default even if no base localised files were found. Fixes warning in Xcode 11 #685 @yonaskolb - Don't generate CFBundleExecutable in default generated Info.plist for `bundle` target types #689 @FranzBusch - Fixed resolving relative paths with custom project destination #681 @giginet @@ -354,26 +442,31 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen - Fixed macOS unit test target TEST_HOST #696 @mjarvis #### Internal + - Restructure targets #698 @yonaskolb ## 2.9.0 #### Added + - Added Scheme Templates #672 @bclymer #### Fixed + - Fixed macOS unit test setting preset #665 @yonaskolb - Add `rcproject` files to sources build phase instead of resources #669 @Qusic - Prefer default configuration names for generated schemes #673 @giginet - Fixed some resource files being placed to "Recovered References" group #679 @nivanchikov #### Internal + - Updated to SwiftCLI 5.3.2 #667 @giginet - Fixed tests in case-sensitive file system #670 @Qusic ## 2.8.0 #### Added + - Added support for Swift Package dependencies #624 @yonaskolb - Added `includes` to `sources` for a Target. This follows the same glob-style as `excludes` but functions as a way to only include files that match a specified pattern. Useful if you only want a certain file type, for example specifying `**/*.swift`. #637 @bclymer - Support `dylib` SDK. #650 @kateinoigakukun @@ -381,74 +474,89 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen - Added `debugEnabled` option for `run` and `test` scheme #657 @kateinoigakukun #### Fixed + - Expand template variable in Array of Any #651 @kateinoigakukun - Significantly improve performance when running with a large number files. #658 @kateinoigakukun - Removed some more diffs between the generated .pbxproj and when Xcode resaves it #663 @yonaskolb #### Internal + - Removed needless `Array` initialization. #661 @RomanPodymov - Updated to XcodeProj 7.1.0 #624 @yonaskolb ## 2.7.0 #### Added + - Added Bash 4 style recursive globbing (`**/*`) in target sources `excludes` #636 @bclymer - Added ability to disable main thread checker in Schemes #601 @wag-miles #### Fixed + - Fixed included specs that were referenced multiple times from duplicating content #599 @haritowa - Fixed `.orig` files being added to the project #627 @keith #### Changed + - Allow linking of dependencies into static libraries when `link` is set to true #635 @kateinoigakukun ## 2.6.0 #### Added + - Added ability to skip tests #582 @kadarandras - Added ability to set `attributes` on build files #583 @min - Allow using environment variables in the form of `${SOME_VARIABLE}`. This might be a **breaking** change when a target template attribute is also defined as an environment variable #594 @tomquist - Added support for `watchapp2-container` and `framework.static` product types #604 @yonaskolb #### Fixed + - Fixed `.pch` files being bundled as resources #597 @thii - Fixed an issue that prevents watchOS Intents Extension from running correctly. #571 @KhaosT #### Changed + - Updated the default `compatibilityVersion` project setting from `Xcode 9.3` to `Xcode 10.0` #581 @acecilia - Updated to XcodeProj 7.0.0. Note that the length of generated UUIDs has changed #604 @yonaskolb #### Internal + - Added ability to encode ProjectSpec #545 @ryohey ## 2.5.0 #### Added + - Added support for `app-extension.intents-service` target type #536 @yonaskolb - Added support for custom `root` in `sdk` dependency #562 @raptorxcz #### Changed + - Updated to xcodeproj 6.7.0 including its performance improvements #536 @yonaskolb - Updated default generated settings for Xcode 10.2 #555 @yonaskolb - Changed order of file generation so that plists are now generated before the project, so they will be included in the projects files #544 @tomquist - Updated Yams to 2.0.0 @yonaskolb #### Fixed + - Fixed groups from sources outside a project spec's directory from being flattened. #550 @sroebert - Fixed `optional` file sources not being added to the project #557 @yonaskolb - Fixed Carthage dependencies being incorrectly embedded in WatchKit app bundles instead of a WatchKit app extension #558 @KhaosT ## 2.4.0 -#### Fixed: +#### Fixed + - Fixed installation when building in Swift 5 #549 @yonaskolb #### Changed + - Updated to Swift 5 and dropped Swift 4.2 #549 @yonaskolb ## 2.3.0 #### Added + - Added ability to automatically find all the frameworks for Carthage dependencies via the global `options.findCarthageFrameworks` or dependency specfic `dependency.findFrameworks`. See the [Carthage](Docs/Usage.md#carthage) usage docs for more info #506 @rpassis @yonaskolb - Added support for nested target templates #534 @tomquist - Added ability to define `templateAttributes` within a target to be able to parameterize templates. #533 @tomquist @@ -457,9 +565,11 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen - Added ability to define a per-platform `deploymentTarget` for Multi-Platform targets. #510 @ainopara #### Changed + - **DEPRECATION**: Placeholders `$target_name` and `$platform` have been deprecated in favour of `${target_name}` and `${platform}`. Support for the old placeholders will be removed in a future version #533 @tomquist #### Fixed + - Sources outside a project spec's directory will be correctly referenced as relative paths in the project file. #524 - Fixed error when `optional` directory source is missing #527 @yonaskolb - Fixed excludes within included spec #535 @yonaskolb @@ -470,6 +580,7 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen ## 2.2.0 #### Added + - Added ability to generate empty directories via `options.generateEmptyDirectories` #480 @Beniamiiin - Added support for the `instrumentsPackage` product type #482 @ksulliva - Added support for `inputFileLists` and `outputFileLists` within project build scripts #500 @lukewakeford @@ -477,12 +588,14 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen - Added `createIntermediateGroups` to individual Target Sources which overrides the top level option #505 @yonaskolb #### Changed + - **BREAKING**: All the paths within `include` files are now relative to that file and not the root spec. This can be disabled with a `relativePaths: false` on the include. See the [documentation](https://github.com/yonaskolb/XcodeGen/blob/master/Docs/ProjectSpec.md#include) for more details #489 @ellneal - Updated the Xcode compatibility version from 3.2 to 9.3 #497 @yonaskolb - Exact matches to config names in build settings won't partial apply to other configs #503 @yonaskolb - UUIDs in the project are standard and don't contain any type prefixes anymore #### Fixed + - Fixed `--project` argument not taking effect #487 @monowerker - Fixed Sticker Packs from generating an empty Source file phase which caused in error in the new build system #492 @rpassis - Fixed generated schemes for tool targets not setting the executable #496 @yonaskolb @@ -491,14 +604,17 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen ## 2.1.0 #### Added + - Added an experiment new caching feature. Pass `--use-cache` to opt in. This will read and write from a cache file to prevent unnecessarily generating the project. Give it a try as it may become the default in a future release #412 @yonaskolb #### Changed + - Changed spelling of build phases to **preBuildPhase** and **postBuildPhase**. The older names are deprecated but still work [402](https://github.com/yonaskolb/XcodeGen/pull/402) @brentleyjones - Moved generation to a specific subcommand `xcodegen generate`. Simple `xcodegen` will continue to work for now #437 @yonaskolb - If `INFOPLIST_FILE` has been set on a target, then an `info` path won't ovewrite it #443 @feischl97 #### Fixed + - Fixed XPC Service package type in generated `Info.plist` #435 @alvarhansen - Fixed phase ordering for modulemap and static libary header Copy File phases. [402](https://github.com/yonaskolb/XcodeGen/pull/402) @brentleyjones - Fixed intermittent errors when running multiple `xcodegen`s concurrently #450 @bryansum @@ -511,6 +627,7 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen ## 2.0.0 #### Added + - Added `weak` linking setting for dependencies #411 @alvarhansen - Added `info` to targets for generating an `Info.plist` #415 @yonaskolb - Added `entitlements` to targets for generating an `.entitlement` file #415 @yonaskolb @@ -520,6 +637,7 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen - Automatically set project `SDKROOT` if there is only a single platform within the project #433 @yonaskolb #### Changed + - Performance improvements for large projects #388 @yonaskolb @kastiglione - Upgraded to xcodeproj 6 #388 @yonaskolb - Upgraded to Swift 4.2 #388 @yonaskolb @@ -528,6 +646,7 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen - Added ability to not link Carthage frameworks #432 @yonaskolb #### Fixed + - Fixed code signing issues #414 @yonaskolb - Fixed `TargetSource.headerVisibility` not being set in initializer #419 @jerrymarino - Fixed crash when using Xcode Legacy targets as dependencies #427 @dflems @@ -537,24 +656,28 @@ Some support for Xcode Test Plans has been added. For now test plans are not gen If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project will not be deterministic. This will be fixed in an upcoming release with an update to xcodeproj 6.0 #### Fixed + - Fixed release builds in Swift 4.2 #404 @pepibumur - Fixed default settings for macOS unit-tests #387 @frankdilo - Fixed Copy Headers phase ordering for Xcode 10 #401 @brentleyjones - Fixed generated schemes on aggregate targets #394 @vgorloff #### Changed + - Added `en` as default value for knownRegions #390 @Saik0s - Update `PathKit`, `Spectre`, `Yams` and `xcodeproj` dependencies ## 1.11.1 #### Fixed + - Fixed `FRAMEWORK_SEARCH_PATHS` for `framework` dependency paths with spaces #382 @brentleyjones - Fixed aggregate targets not being found with `transitivelyLinkDependencies` #383 @brentleyjones ## 1.11.0 #### Added + - Added `showEnvVars` to build scripts to disable printing the environment #351 @keith - Added `requiresObjCLinking` to `target` #354 @brentleyjones - Added `targetTemplates` #355 @yonaskolb @@ -565,6 +688,7 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil - Added `customArchiveName` and `revealArchiveInOrganizer` to `archive` #367 @sxua #### Fixed + - Sort files using localizedStandardCompare #341 @rohitpal440 - Use the latest `xcdatamodel` when sorted by version #341 @rohitpal440 - Fixed compiler flags being set on non source files in mixed build phase target sources #347 @brentleyjones @@ -575,6 +699,7 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil - Fixed `.metal` files being added to resources #380 @vgorloff #### Changed + - Improved linking for `static.library` targets #352 @brentleyjones - Changed default group sorting to be after files #356 @yonaskolb - Moved `Frameworks` and `Products` top level groups to bottom #356 @yonaskolb @@ -586,41 +711,49 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil - Copy files phases have descriptive names #360 @brentley #### Internal + - Moved brew formula to homebrew core - Added `CONTRIBUTING.md` ## 1.10.3 #### Fixed + - Fixed Mint installations finding `SettingPresets` #338 @yonaskolb ## 1.10.2 #### Changed + - Set `transitivelyLinkDependencies` to false by default ## 1.10.1 #### Fixed + - Fixed `transitivelyLinkDependencies` typo #332 @brentleyjones - Fixed framework target dependencies not being code signed by default #332 @yonaskolb #### Changed + - Code sign all dependencies by default except target executables #332 @yonaskolb ## 1.10.0 #### Added + - Added build rule support #306 @yonaskolb - Added support for frameworks in sources #308 @keith - Added ability to automatically embed transient dependencies. Controlled with `transitivelyLinkDependencies` #327 @brentleyjones #### Changed + - Upgraded to Swift 4.1 - Improved Carthage dependency lookup performance with many targets #298 @keith - By default don't CodeSignOnCopy `target` dependencies. This can still be controlled with `Dependency.codeSign` #324 @yonaskolb #### Fixed + - Fixed PBXBuildFile and PBXFileReference being incorrectly generated for Legacy targets #296 @sascha - Fixed required sources build phase not being generated if there are no sources #307 @yonaskolb - Fixed install script in binary release #303 @alvarhansen @@ -635,15 +768,18 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil ## 1.9.0 #### Added + - Scheme pre and post actions can now be added to `target.scheme` #280 @yonaskolb - Individual files can now be added to `fileGroups` #293 @yonaskolb #### Changed + - Updated to `xcproj` 4.3.0 for Xcode 9.3 updates - Update default Xcode version to 9.3 including new settings #284 @LinusU - **Breaking for ProjectSpec library users** Changed `ProjectSpec` to `Project` and `ProjectSpec.Options` to `SpecOptions` #281 @jerrymarino #### Fixed + - Fixed manual build phase of `none` not being applied to folders #288 @yonaskolb - Quoted values now correctly get parsed as strings #282 @yonaskolb - Fixed adding a root source folder when `createIntermediateGroups` is on #291 @yonaskolb @@ -653,16 +789,19 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil ## 1.8.0 #### Added + - Added Project `defaultConfig` #269 @keith - Added Target `attributes` #276 @yonaskolb - Automatically set `DevelopmentTeam` and `ProvisioningStyle` within `TargetAttributes` if relevant build settings are defined #277 @yonaskolb #### Fixed + - Fixed default `LD_RUNPATH_SEARCH_PATHS` for app extensions #272 @LinusU #### Internal + - Make `LegacyTarget` init public #264 @jerrymarino -- Upgrade to *xcproj* to 4.2.0, *Yams* to 0.6.0 and *PathKit* to 0.9.1 @yonaskolb +- Upgrade to _xcproj_ to 4.2.0, _Yams_ to 0.6.0 and _PathKit_ to 0.9.1 @yonaskolb ## 1.7.0 @@ -679,6 +818,7 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil - Releases now include a pre-compiled binary and setting presets, including an install script #### Fixed + - Fixed Mint installation from reading setting presets #248 @yonaskolb - Fixed setting `buildPhase` on a `folder` source. This allows for a folder of header files #254 @toshi0383 - Carthage dependencies are not automatically embedded into test targets #256 @yonaskolb @@ -689,23 +829,27 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil ## 1.6.0 #### Added + - Added scheme pre-actions and post-actions #231 @kastiglione - Added `options.disabledValidations` including `missingConfigs` to disable project validation errors #220 @keith - Generate UI Test Target Attributes #221 @anreitersimon #### Fixed + - Filter out duplicate source files #217 @allu22 - Fixed how `lastKnownFileType` and `explicitFileType` were generated across platforms #115 @toshi0383 - Removed a few cases of project diffs when opening the project in Xcode @yonaskolb - Fixed Swift not being embedded by default in watch apps @yonaskolb #### Changed + - Change arrays to strings in setting presets #218 @allu22 - Updated to xcproj 4.0 #227 ## 1.5.0 #### Added + - added support for `gatherCoverageData` flag in target schemes #170 @alexruperez - added support for `commandLineOptions` in target schemes #172 @rahul-malik - added Project spec as a SwiftPM library for reuse in other projects #164 @soffes @@ -723,6 +867,7 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil - added `deploymentTarget` setting to project and target #205 @yonaskolb #### Changed + - huge performance improvements when writing the project file due to changes in xcproj - updated dependencies - minor logging changes @@ -733,6 +878,7 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil - when specifying a `--spec` argument, the default for the `--project` path is now the directory containing the spec #211 @yonaskolb #### Fixed + - fixed shell scripts escaping quotes twice #186 @allu22 - fixed `createIntermediateGroups` when using a relative spec path #184 @kastiglione - fixed command line arguments for test and profile from being overridden #199 @vhbit @@ -743,6 +889,7 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil ## 1.4.0 #### Added + - added `--version` flag #112 @mironal - added support for adding individual file sources #106 @bkase - added source compiler flag support #121 @bkase @@ -753,6 +900,7 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil - added `ProjectSpec.options.developmentLanguage` #155 @yonaskolb #### Changed + - updated to xcproj 1.2.0 #113 @yonaskolb - build settings from presets will be removed if they are provided in `xcconfig` files #77 @toshi0383 - all files and groups are sorted by type and then alphabetically #144 @yonaskolb @@ -761,6 +909,7 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil - make UUIDs more deterministic #154 @yonaskolb #### Fixed + - only add headers to frameworks and libraries #118 @ryohey - fixed localized files with the same name #126 @ryohey - fix intermediate sources #144 @yonaskolb @@ -771,6 +920,7 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil - all localizations found are added to a projects known regions #157 @ryohey #### Internal + - refactoring - more tests - added release scripts @@ -778,11 +928,13 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil ## 1.3.0 #### Added + - generate output files for Carthage copy-frameworks script #84 @mironal - added options.settingPreset to choose which setting presets get applied #100 @yonaskolb - added `link` option for target dependencies #109 @keith #### Changed + - updated to xcproj 0.4.1 #85 @enmiller - don't copy base settings if config type has been left out #100 @yonaskolb - generate localised files under a single variant group #70 @ryohey @@ -791,6 +943,7 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil - other small internal changes @yonaskolb #### Fixed + - embed Carthage frameworks for macOS #82 @toshi0383 - fixed copying of watchOS app resources #96 @keith - automatically ignore more file types for a target's sources (entitlements, gpx, apns) #94 @keith @@ -803,16 +956,19 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil ## 1.2.4 #### Fixed + - setting presets only apply `ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES: YES` to applications - don't add carthage dependency to `copy-frameworks` script if `embed: false` - sort group children on APFS #### Changed + - update to xcproj 0.3.0 ## 1.2.3 #### Fixed + - Fixed wrong carthage directory name reference for macOS #74 @toshi0383 - Removed unnecessary `carthage copy-frameworks` for macOS app target #76 @toshi0383 - Added some missing default settings for framework targets. `SKIP_INSTALL: YES` fixes archiving @@ -821,16 +977,18 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil ## 1.2.2 #### Added + - automatically set `TEST_TARGET_NAME` on UI test targets if one of the dependencies is an application target #### Fixed + - set `DYLIB_INSTALL_NAME_BASE` to `@rpath` in framework target presets - fixed tvOS launch screen setting. `ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME` is now `LaunchImage` not `tvOS LaunchImage` - ## 1.2.0 #### Added + - `include` now supports a single string as well as a list - add support setting xcconfig files on a project with `configFiles` #64 - add `fileGroups` to project spec for adding groups of files that aren't target source files #64 @@ -840,6 +998,7 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil - add `mint` installation support #### Fixed + - fixed homebrew installation - fixed target xcconfig files not working via `configFiles` #64 - look for `INFOPLIST_FILE` setting in project and xcconfig files before adding it automatically. It was just looking in target settings before #64 @@ -848,107 +1007,129 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil ## 1.1.0 #### Changed + - set project version to Xcode 9 - `LastUpgradeVersion` attribute to `0900` - set default Swift version to 4.0 - `SWIFT_VERSION` build setting to `4.0` ### 1.0.1 ### Fixed + - fixed incorrect default build script shell path - fixed install scripts ## 1.0.0 #### Added + - Swift 4 support #52 - Support for C and C++ files #48 by @antoniocasero - Xcode 9 default settings #### Fixed + - fixed empty string in YAML not being parsed properly #50 by @antoniocasero #### Changed + - updated to xcodeproj 0.1.2 #56 - **BREAKING**: changed target definitions from list to map #54 - ## 0.6.1 #### Added + - Ability to set PBXProject attributes #45 #### Changed + - Don't bother linking target frameworks for target dependencies. - Move code signing default settings from all iOS targets to iOS application targets, via Product + Platform setting preset files #46 ## 0.6.0 #### Added + - Allow a project spec to include other project specs #44 #### Changed + - Changed default spec path to `project.yml` - Changed default project directory to the current directory instead of the spec file's directory ## 0.5.1 #### Fixed + - Fix embedded framework dependencies - Add `CODE_SIGN_IDENTITY[sdk=iphoneos*]` back to iOS targets - Fix build scripts with "" generating invalid projects #43 ## 0.5.0 + #### Added + - Added multi platform targets #35 - Automatically generate platform specific `FRAMEWORK_SEARCH_PATHS` for Carthage dependencies #38 - Automatically find Info.plist and set `INFOPLIST_FILE` build setting if it doesn't exist on a target #40 - Add options for controlling embedding of dependencies #37 #### Fixed + - Fixed localized files not being added to a target's resources #### Changed + - Renamed Setting Presets to Setting Groups - Carthage group is now created under top level Frameworks group ## 0.4.0 ##### Added + - Homebrew support #16 by @pepibumur - Added `runOnlyWhenInstalling` to build scripts #32 - Added `carthageBuildPath` option #34 #### Fixed + - Fixed installations of XcodeGen not applying build setting presets for configs, products, and platforms, due to missing resources #### Changed -- Upgraded to https://github.com/swift-xcode/xcodeproj 0.1.1 #33 + +- Upgraded to 0.1.1 #33 ## 0.3.0 - Extensions and Scheme Tests #### Added + - Support for app extension dependencies, using the same `target: MyExtension` syntax #19 - Added test targets to generated target schemes via `Target.scheme.testTargets` #21 #### Changed + - Updated xcodeproj to 0.0.9 #### Fixed + - Fixed watch and messages apps not copying carthage dependencies #### Breaking changes + - Changed `Target.generatedSchemes` to `Target.scheme.configVariants` ## 0.2.0 - Build scripts #### Added + - Added Target build scripts with `Target.prebuildScripts` and `Target.postbuildScripts` #17 - Support for absolute paths in target sources, run script files, and config files - Add validation for incorrect `Target.configFiles` #### Fixed + - Fixed some project objects sometimes having duplicate ids ## 0.1.0 -First official release +First official release diff --git a/Docs/ProjectSpec.md b/Docs/ProjectSpec.md index 0bb1e6b0..d56650c0 100644 --- a/Docs/ProjectSpec.md +++ b/Docs/ProjectSpec.md @@ -64,12 +64,13 @@ An include can be provided via a string (the path) or an object of the form: - [x] **path**: **String** - The path to the included file. - [ ] **relativePaths**: **Bool** - Dictates whether the included spec specifies paths relative to itself (the default) or the root spec file. - +- [ ] **enable**: **Bool** - Dictates whether the specified spec should be included or not. You can also specify it by environment variable. ```yaml include: - includedFile.yml - path: path/to/includedFile.yml relativePaths: false + enable: ${INCLUDE_ADDITIONAL_YAML} ``` By default specs are merged additively. That is for every value: @@ -274,6 +275,7 @@ This will provide default build settings for a certain product type. It can be a - `application.messages` - `application.watchapp` - `application.watchapp2` +- `application.watchapp2-container` - `app-extension` - `app-extension.intents-service` - `app-extension.messages` @@ -282,6 +284,7 @@ This will provide default build settings for a certain product type. It can be a - `bundle.ocunit-test` - `bundle.ui-testing` - `bundle.unit-test` +- `extensionkit-extension` - `framework` - `instruments-package` - `library.dynamic` @@ -289,7 +292,6 @@ This will provide default build settings for a certain product type. It can be a - `framework.static` - `tool` - `tv-app-extension` -- `watchapp2-container` - `watchkit-extension` - `watchkit2-extension` - `xcode-extension` @@ -731,7 +733,7 @@ This is used to override settings or run build scripts in specific targets ## Target Template -This is a template that can be referenced from a normal target using the `templates` property. The properties of this template are the same as a [Target](#target)]. +This is a template that can be referenced from a normal target using the `templates` property. The properties of this template are the same as a [Target](#target). Any instances of `${target_name}` within each template will be replaced by the final target name which references the template. Any attributes defined within a targets `templateAttributes` will be used to replace any attribute references in the template using the syntax `${attribute_name}`. @@ -806,6 +808,7 @@ The different actions share some properties: - [ ] **preActions**: **[[Execution Action](#execution-action)]** - Scripts that are run *before* the action - [ ] **postActions**: **[[Execution Action](#execution-action)]** - Scripts that are run *after* the action - [ ] **environmentVariables**: **[[Environment Variable](#environment-variable)]** or **[String:String]** - `run`, `test` and `profile` actions can define the environment variables. When passing a dictionary, every key-value entry maps to a corresponding variable that is enabled. +- [ ] **enableGPUFrameCaptureMode**: **GPUFrameCaptureMode** - Property value set for `GPU Frame Capture`. Possible values are `autoEnabled`, `metal`, `openGL`, `disabled`. Default is `autoEnabled`. - [ ] **disableMainThreadChecker**: **Bool** - `run` and `test` actions can define a boolean that indicates that this scheme should disable the Main Thread Checker. This defaults to false - [ ] **stopOnEveryMainThreadCheckerIssue**: **Bool** - a boolean that indicates if this scheme should stop at every Main Thread Checker issue. This defaults to false - [ ] **language**: **String** - `run` and `test` actions can define a language that is used for Application Language @@ -1026,7 +1029,7 @@ packages: Yams: url: https://github.com/jpsim/Yams from: 2.0.0 - Yams: + Ink: github: JohnSundell/Ink from: 0.5.0 RxClient: diff --git a/Makefile b/Makefile index d5f6668c..82db425c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ TOOL_NAME = XcodeGen export EXECUTABLE_NAME = xcodegen -VERSION = 2.29.0 +VERSION = 2.32.0 PREFIX = /usr/local INSTALL_PATH = $(PREFIX)/bin/$(EXECUTABLE_NAME) diff --git a/Package.resolved b/Package.resolved index 613d2c8f..509ec1c4 100644 --- a/Package.resolved +++ b/Package.resolved @@ -78,8 +78,8 @@ "repositoryURL": "https://github.com/tuist/XcodeProj.git", "state": { "branch": null, - "revision": "c75c3acc25460195cfd203a04dde165395bf00e0", - "version": "8.7.1" + "revision": "b6de1bfe021b861c94e7c83821b595083f74b997", + "version": "8.8.0" } }, { diff --git a/Package.swift b/Package.swift index bbdef959..9d709baf 100644 --- a/Package.swift +++ b/Package.swift @@ -16,7 +16,7 @@ let package = Package( .package(url: "https://github.com/yonaskolb/JSONUtilities.git", from: "4.2.0"), .package(url: "https://github.com/kylef/Spectre.git", from: "0.9.2"), .package(url: "https://github.com/onevcat/Rainbow.git", from: "3.0.0"), - .package(url: "https://github.com/tuist/XcodeProj.git", from: "8.7.0"), + .package(url: "https://github.com/tuist/XcodeProj.git", from: "8.8.0"), .package(url: "https://github.com/jakeheis/SwiftCLI.git", from: "6.0.3"), .package(url: "https://github.com/mxcl/Version", from: "2.0.0"), .package(url: "https://github.com/SwiftDocOrg/GraphViz.git", .exact("0.2.0")), diff --git a/README.md b/README.md index b8088cbe..2bc909bd 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ swift run xcodegen Add the following to your Package.swift file's dependencies: ```swift -.package(url: "https://github.com/yonaskolb/XcodeGen.git", from: "2.29.0"), +.package(url: "https://github.com/yonaskolb/XcodeGen.git", from: "2.32.0"), ``` And then import wherever needed: `import XcodeGenKit` @@ -130,7 +130,7 @@ This will look for a project spec in the current directory called `project.yml` Options: -- **--spec**: An optional path to a `.yml` or `.json` project spec. Defaults to `project.yml` +- **--spec**: An optional path to a `.yml` or `.json` project spec. Defaults to `project.yml`. (It is also possible to link to multiple spec files by comma separating them. Note that all other flags will be the same.) - **--project**: An optional path to a directory where the project will be generated. By default this is the directory the spec lives in. - **--quiet**: Suppress informational and success messages. - **--use-cache**: Used to prevent unnecessarily generating the project. If this is set, then a cache file will be written to when a project is generated. If `xcodegen` is later run but the spec and all the files it contains are the same, the project won't be generated. diff --git a/Sources/ProjectSpec/AggregateTarget.swift b/Sources/ProjectSpec/AggregateTarget.swift index b2964e5b..3769e64c 100644 --- a/Sources/ProjectSpec/AggregateTarget.swift +++ b/Sources/ProjectSpec/AggregateTarget.swift @@ -1,8 +1,10 @@ import Foundation import JSONUtilities +import XcodeProj public struct AggregateTarget: ProjectTarget { public var name: String + public var type: PBXProductType = .none public var targets: [String] public var settings: Settings public var buildScripts: [BuildScript] diff --git a/Sources/ProjectSpec/Dependency.swift b/Sources/ProjectSpec/Dependency.swift index 2037bd44..1c01a8d8 100644 --- a/Sources/ProjectSpec/Dependency.swift +++ b/Sources/ProjectSpec/Dependency.swift @@ -56,7 +56,7 @@ public struct Dependency: Equatable { public static let `default` = dynamic } - public enum DependencyType: Equatable { + public enum DependencyType: Hashable { case target case framework case carthage(findFrameworks: Bool?, linkType: CarthageLinkType) diff --git a/Sources/ProjectSpec/FileType.swift b/Sources/ProjectSpec/FileType.swift index 70ae7632..c794b64e 100644 --- a/Sources/ProjectSpec/FileType.swift +++ b/Sources/ProjectSpec/FileType.swift @@ -87,6 +87,7 @@ extension FileType { "intentdefinition": FileType(buildPhase: .sources), "metal": FileType(buildPhase: .sources), "mlmodel": FileType(buildPhase: .sources), + "mlmodelc": FileType(buildPhase: .resources), "rcproject": FileType(buildPhase: .sources), "iig": FileType(buildPhase: .sources), "docc": FileType(buildPhase: .sources), diff --git a/Sources/ProjectSpec/Linkage.swift b/Sources/ProjectSpec/Linkage.swift index 0e134fa0..250f8207 100644 --- a/Sources/ProjectSpec/Linkage.swift +++ b/Sources/ProjectSpec/Linkage.swift @@ -35,7 +35,8 @@ extension Target { .xcodeExtension, .xpcService, .systemExtension, - .driverExtension: + .driverExtension, + .extensionKitExtension: return .none case .framework, .xcFramework: // Check the MACH_O_TYPE for "Static Framework" diff --git a/Sources/ProjectSpec/Project.swift b/Sources/ProjectSpec/Project.swift index bc82e9aa..4b325eab 100644 --- a/Sources/ProjectSpec/Project.swift +++ b/Sources/ProjectSpec/Project.swift @@ -155,7 +155,14 @@ extension Project: Equatable { extension Project { public init(path: Path) throws { - let spec = try SpecFile(path: path) + var cachedSpecFiles: [Path: SpecFile] = [:] + let spec = try SpecFile(filePath: path, basePath: path.parent(), cachedSpecFiles: &cachedSpecFiles) + try self.init(spec: spec) + } + + public init(path: Path, basePath: Path) throws { + var cachedSpecFiles: [Path: SpecFile] = [:] + let spec = try SpecFile(filePath: path, basePath: basePath, cachedSpecFiles: &cachedSpecFiles) try self.init(spec: spec) } diff --git a/Sources/ProjectSpec/ProjectTarget.swift b/Sources/ProjectSpec/ProjectTarget.swift index 0411b0eb..99fd1d77 100644 --- a/Sources/ProjectSpec/ProjectTarget.swift +++ b/Sources/ProjectSpec/ProjectTarget.swift @@ -1,8 +1,10 @@ import Foundation +import XcodeProj public protocol ProjectTarget: BuildSettingsContainer { var name: String { get } + var type: PBXProductType { get } var buildScripts: [BuildScript] { get } var scheme: TargetScheme? { get } var attributes: [String: Any] { get } diff --git a/Sources/ProjectSpec/Scheme.swift b/Sources/ProjectSpec/Scheme.swift index 3f896c39..d2ac1d79 100644 --- a/Sources/ProjectSpec/Scheme.swift +++ b/Sources/ProjectSpec/Scheme.swift @@ -130,6 +130,7 @@ public struct Scheme: Equatable { public var preActions: [ExecutionAction] public var postActions: [ExecutionAction] public var environmentVariables: [XCScheme.EnvironmentVariable] + public var enableGPUFrameCaptureMode: XCScheme.LaunchAction.GPUFrameCaptureMode public var disableMainThreadChecker: Bool public var stopOnEveryMainThreadCheckerIssue: Bool public var language: String? @@ -150,6 +151,7 @@ public struct Scheme: Equatable { preActions: [ExecutionAction] = [], postActions: [ExecutionAction] = [], environmentVariables: [XCScheme.EnvironmentVariable] = [], + enableGPUFrameCaptureMode: XCScheme.LaunchAction.GPUFrameCaptureMode = XCScheme.LaunchAction.defaultGPUFrameCaptureMode, disableMainThreadChecker: Bool = disableMainThreadCheckerDefault, stopOnEveryMainThreadCheckerIssue: Bool = stopOnEveryMainThreadCheckerIssueDefault, language: String? = nil, @@ -168,6 +170,7 @@ public struct Scheme: Equatable { self.postActions = postActions self.environmentVariables = environmentVariables self.disableMainThreadChecker = disableMainThreadChecker + self.enableGPUFrameCaptureMode = enableGPUFrameCaptureMode self.stopOnEveryMainThreadCheckerIssue = stopOnEveryMainThreadCheckerIssue self.language = language self.region = region @@ -458,6 +461,11 @@ extension Scheme.Run: JSONObjectConvertible { preActions = jsonDictionary.json(atKeyPath: "preActions") ?? [] postActions = jsonDictionary.json(atKeyPath: "postActions") ?? [] environmentVariables = try XCScheme.EnvironmentVariable.parseAll(jsonDictionary: jsonDictionary) + if let gpuFrameCaptureMode: String = jsonDictionary.json(atKeyPath: "enableGPUFrameCaptureMode") { + enableGPUFrameCaptureMode = XCScheme.LaunchAction.GPUFrameCaptureMode.fromJSONValue(gpuFrameCaptureMode) + } else { + enableGPUFrameCaptureMode = XCScheme.LaunchAction.defaultGPUFrameCaptureMode + } disableMainThreadChecker = jsonDictionary.json(atKeyPath: "disableMainThreadChecker") ?? Scheme.Run.disableMainThreadCheckerDefault stopOnEveryMainThreadCheckerIssue = jsonDictionary.json(atKeyPath: "stopOnEveryMainThreadCheckerIssue") ?? Scheme.Run.stopOnEveryMainThreadCheckerIssueDefault language = jsonDictionary.json(atKeyPath: "language") @@ -499,6 +507,10 @@ extension Scheme.Run: JSONEncodable { "macroExpansion": macroExpansion ] + if enableGPUFrameCaptureMode != XCScheme.LaunchAction.defaultGPUFrameCaptureMode { + dict["enableGPUFrameCaptureMode"] = enableGPUFrameCaptureMode.toJSONValue() + } + if disableMainThreadChecker != Scheme.Run.disableMainThreadCheckerDefault { dict["disableMainThreadChecker"] = disableMainThreadChecker } @@ -916,3 +928,33 @@ extension XCScheme.EnvironmentVariable: JSONEncodable { return dict } } + +extension XCScheme.LaunchAction.GPUFrameCaptureMode: JSONEncodable { + public func toJSONValue() -> Any { + switch self { + case .autoEnabled: + return "autoEnabled" + case .metal: + return "metal" + case .openGL: + return "openGL" + case .disabled: + return "disabled" + } + } + + static func fromJSONValue(_ string: String) -> XCScheme.LaunchAction.GPUFrameCaptureMode { + switch string { + case "autoEnabled": + return .autoEnabled + case "metal": + return .metal + case "openGL": + return .openGL + case "disabled": + return .disabled + default: + fatalError("Invalid enableGPUFrameCaptureMode value. Valid values are: autoEnabled, metal, openGL, disabled") + } + } +} diff --git a/Sources/ProjectSpec/SourceType.swift b/Sources/ProjectSpec/SourceType.swift index 77ce4ffe..819cf1b1 100644 --- a/Sources/ProjectSpec/SourceType.swift +++ b/Sources/ProjectSpec/SourceType.swift @@ -11,4 +11,5 @@ public enum SourceType: String { case group case file case folder + case variantGroup } diff --git a/Sources/ProjectSpec/SpecFile.swift b/Sources/ProjectSpec/SpecFile.swift index adf97471..7667a821 100644 --- a/Sources/ProjectSpec/SpecFile.swift +++ b/Sources/ProjectSpec/SpecFile.swift @@ -1,6 +1,7 @@ import Foundation import JSONUtilities import PathKit +import Yams public struct SpecFile { public let basePath: Path @@ -13,17 +14,20 @@ public struct SpecFile { fileprivate struct Include { let path: Path let relativePaths: Bool + let enable: Bool static let defaultRelativePaths = true + static let defaultEnable = true init?(any: Any) { if let string = any as? String { path = Path(string) relativePaths = Include.defaultRelativePaths - } else if let dictionary = any as? JSONDictionary, - let path = dictionary["path"] as? String { + enable = Include.defaultEnable + } else if let dictionary = any as? JSONDictionary, let path = dictionary["path"] as? String { self.path = Path(path) - relativePaths = dictionary["relativePaths"] as? Bool ?? Include.defaultRelativePaths + relativePaths = Self.resolveBoolean(dictionary, key: "relativePaths") ?? Include.defaultRelativePaths + enable = Self.resolveBoolean(dictionary, key: "enable") ?? Include.defaultEnable } else { return nil } @@ -38,10 +42,14 @@ public struct SpecFile { return [] } } + + private static func resolveBoolean(_ dictionary: [String: Any], key: String) -> Bool? { + dictionary[key] as? Bool ?? (dictionary[key] as? NSString)?.boolValue + } } - public init(path: Path) throws { - try self.init(filePath: path, basePath: path.parent()) + public init(path: Path, cachedSpecFiles: inout [Path: SpecFile], variables: [String: String] = [:]) throws { + try self.init(filePath: path, basePath: path.parent(), cachedSpecFiles: &cachedSpecFiles, variables: variables) } public init(filePath: Path, jsonDictionary: JSONDictionary, basePath: Path = "", relativePath: Path = "", subSpecs: [SpecFile] = []) { @@ -52,23 +60,29 @@ public struct SpecFile { self.filePath = filePath } - private init(include: Include, basePath: Path, relativePath: Path) throws { - let basePath = include.relativePaths ? (basePath + relativePath) : (basePath + relativePath + include.path.parent()) + private init(include: Include, basePath: Path, relativePath: Path, cachedSpecFiles: inout [Path: SpecFile], variables: [String: String]) throws { + let basePath = include.relativePaths ? (basePath + relativePath) : basePath let relativePath = include.relativePaths ? include.path.parent() : Path() + let includePath = include.relativePaths ? basePath + relativePath + include.path.lastComponent : basePath + include.path - try self.init(filePath: include.path, basePath: basePath, relativePath: relativePath) + try self.init(filePath: includePath, basePath: basePath, cachedSpecFiles: &cachedSpecFiles, variables: variables, relativePath: relativePath) } - private init(filePath: Path, basePath: Path, relativePath: Path = "") throws { - let path = basePath + relativePath + filePath.lastComponent - let jsonDictionary = try SpecFile.loadDictionary(path: path) - + public init(filePath: Path, basePath: Path, cachedSpecFiles: inout [Path: SpecFile], variables: [String: String] = [:], relativePath: Path = "") throws { + let jsonDictionary = try SpecFile.loadDictionary(path: filePath).expand(variables: variables) let includes = Include.parse(json: jsonDictionary["include"]) - let subSpecs: [SpecFile] = try includes.map { include in - try SpecFile(include: include, basePath: basePath, relativePath: relativePath) - } + let subSpecs: [SpecFile] = try includes + .filter(\.enable) + .map { include in + if let specFile = cachedSpecFiles[filePath] { + return specFile + } else { + return try SpecFile(include: include, basePath: basePath, relativePath: relativePath, cachedSpecFiles: &cachedSpecFiles, variables: variables) + } + } self.init(filePath: filePath, jsonDictionary: jsonDictionary, basePath: basePath, relativePath: relativePath, subSpecs: subSpecs) + cachedSpecFiles[filePath] = self } static func loadDictionary(path: Path) throws -> JSONDictionary { @@ -85,12 +99,13 @@ public struct SpecFile { } } - public func resolvedDictionary(variables: [String: String] = [:]) -> JSONDictionary { - resolvedDictionaryWithUniqueTargets().expand(variables: variables) + public func resolvedDictionary() -> JSONDictionary { + resolvedDictionaryWithUniqueTargets() } private func resolvedDictionaryWithUniqueTargets() -> JSONDictionary { - let resolvedSpec = resolvingPaths() + var cachedSpecFiles: [Path: SpecFile] = [:] + let resolvedSpec = resolvingPaths(cachedSpecFiles: &cachedSpecFiles) var value = Set() return resolvedSpec.mergedDictionary(set: &value) @@ -108,19 +123,25 @@ public struct SpecFile { .reduce([:]) { $1.merged(onto: $0) }) } - func resolvingPaths(relativeTo basePath: Path = Path()) -> SpecFile { + func resolvingPaths(cachedSpecFiles: inout [Path: SpecFile], relativeTo basePath: Path = Path()) -> SpecFile { + if let cachedSpecFile = cachedSpecFiles[filePath] { + return cachedSpecFile + } + let relativePath = (basePath + self.relativePath).normalize() guard relativePath != Path() else { return self } let jsonDictionary = Project.pathProperties.resolvingPaths(in: self.jsonDictionary, relativeTo: relativePath) - return SpecFile( + let specFile = SpecFile( filePath: filePath, jsonDictionary: jsonDictionary, relativePath: self.relativePath, - subSpecs: subSpecs.map { $0.resolvingPaths(relativeTo: relativePath) } + subSpecs: subSpecs.map { $0.resolvingPaths(cachedSpecFiles: &cachedSpecFiles, relativeTo: relativePath) } ) + cachedSpecFiles[filePath] = specFile + return specFile } } diff --git a/Sources/ProjectSpec/SpecLoader.swift b/Sources/ProjectSpec/SpecLoader.swift index 142d3bf1..555e1371 100644 --- a/Sources/ProjectSpec/SpecLoader.swift +++ b/Sources/ProjectSpec/SpecLoader.swift @@ -16,8 +16,9 @@ public class SpecLoader { } public func loadProject(path: Path, projectRoot: Path? = nil, variables: [String: String] = [:]) throws -> Project { - let spec = try SpecFile(path: path) - let resolvedDictionary = spec.resolvedDictionary(variables: variables) + var cachedSpecFiles: [Path: SpecFile] = [:] + let spec = try SpecFile(filePath: path, basePath: projectRoot ?? path.parent(), cachedSpecFiles: &cachedSpecFiles, variables: variables) + let resolvedDictionary = spec.resolvedDictionary() let project = try Project(basePath: projectRoot ?? spec.basePath, jsonDictionary: resolvedDictionary) self.project = project diff --git a/Sources/ProjectSpec/SpecValidation.swift b/Sources/ProjectSpec/SpecValidation.swift index c0141b10..376c0153 100644 --- a/Sources/ProjectSpec/SpecValidation.swift +++ b/Sources/ProjectSpec/SpecValidation.swift @@ -154,38 +154,16 @@ extension Project { } for target in targets { + var uniqueDependencies = Set() + for dependency in target.dependencies { - switch dependency.type { - case .target: - let dependencyTargetReference = try TargetReference(dependency.reference) - - switch dependencyTargetReference.location { - case .local: - if getProjectTarget(dependency.reference) == nil { - errors.append(.invalidTargetDependency(target: target.name, dependency: dependency.reference)) - } - case .project(let dependencyProjectName): - if getProjectReference(dependencyProjectName) == nil { - errors.append(.invalidTargetDependency(target: target.name, dependency: dependency.reference)) - } - } - case .sdk: - let path = Path(dependency.reference) - if !dependency.reference.contains("/") { - switch path.extension { - case "framework"?, - "tbd"?, - "dylib"?: - break - default: - errors.append(.invalidSDKDependency(target: target.name, dependency: dependency.reference)) - } - } - case .package: - if packages[dependency.reference] == nil { - errors.append(.invalidSwiftPackage(name: dependency.reference, target: target.name)) - } - default: break + let dependencyValidationErrors = try validate(dependency, in: target) + errors.append(contentsOf: dependencyValidationErrors) + + if uniqueDependencies.contains(dependency) { + errors.append(.duplicateDependencies(target: target.name, dependencyReference: dependency.reference)) + } else { + uniqueDependencies.insert(dependency) } } @@ -252,6 +230,46 @@ extension Project { } } + // Returns error if the given dependency from target is invalid. + private func validate(_ dependency: Dependency, in target: Target) throws -> [SpecValidationError.ValidationError] { + var errors: [SpecValidationError.ValidationError] = [] + + switch dependency.type { + case .target: + let dependencyTargetReference = try TargetReference(dependency.reference) + + switch dependencyTargetReference.location { + case .local: + if getProjectTarget(dependency.reference) == nil { + errors.append(.invalidTargetDependency(target: target.name, dependency: dependency.reference)) + } + case .project(let dependencyProjectName): + if getProjectReference(dependencyProjectName) == nil { + errors.append(.invalidTargetDependency(target: target.name, dependency: dependency.reference)) + } + } + case .sdk: + let path = Path(dependency.reference) + if !dependency.reference.contains("/") { + switch path.extension { + case "framework"?, + "tbd"?, + "dylib"?: + break + default: + errors.append(.invalidSDKDependency(target: target.name, dependency: dependency.reference)) + } + } + case .package: + if packages[dependency.reference] == nil { + errors.append(.invalidSwiftPackage(name: dependency.reference, target: target.name)) + } + default: break + } + + return errors + } + /// Returns a descriptive error if the given target reference was invalid otherwise `nil`. private func validationError(for targetReference: TargetReference, in scheme: Scheme, action: String) -> SpecValidationError.ValidationError? { switch targetReference.location { diff --git a/Sources/ProjectSpec/SpecValidationError.swift b/Sources/ProjectSpec/SpecValidationError.swift index 2cbf0447..eadfca3b 100644 --- a/Sources/ProjectSpec/SpecValidationError.swift +++ b/Sources/ProjectSpec/SpecValidationError.swift @@ -35,6 +35,7 @@ public struct SpecValidationError: Error, CustomStringConvertible { case invalidProjectReferencePath(ProjectReference) case invalidTestPlan(TestPlan) case multipleDefaultTestPlans + case duplicateDependencies(target: String, dependencyReference: String) public var description: String { switch self { @@ -88,6 +89,8 @@ public struct SpecValidationError: Error, CustomStringConvertible { return "Test plan path \"\(testPlan.path)\" doesn't exist" case .multipleDefaultTestPlans: return "Your test plans contain more than one default test plan" + case let .duplicateDependencies(target, dependencyReference): + return "Target \(target.quoted) has the dependency \(dependencyReference.quoted) multiple times" } } } diff --git a/Sources/ProjectSpec/XCProjExtensions.swift b/Sources/ProjectSpec/XCProjExtensions.swift index 9bee91be..91b4c91f 100644 --- a/Sources/ProjectSpec/XCProjExtensions.swift +++ b/Sources/ProjectSpec/XCProjExtensions.swift @@ -90,7 +90,7 @@ extension Platform { } } -extension Target { +extension ProjectTarget { public var shouldExecuteOnLaunch: Bool { // This is different from `type.isExecutable`, because we don't want to "run" a test type.isApp || type.isExtension || type.isSystemExtension || type == .commandLineTool diff --git a/Sources/XcodeGen/main.swift b/Sources/XcodeGen/main.swift index e80d7965..31f102ba 100644 --- a/Sources/XcodeGen/main.swift +++ b/Sources/XcodeGen/main.swift @@ -3,6 +3,6 @@ import ProjectSpec import XcodeGenCLI import Version -let version = Version("2.29.0") +let version = Version("2.32.0") let cli = XcodeGenCLI(version: version) cli.execute() diff --git a/Sources/XcodeGenCLI/Commands/GenerateCommand.swift b/Sources/XcodeGenCLI/Commands/GenerateCommand.swift index aceae2fc..54cdac67 100644 --- a/Sources/XcodeGenCLI/Commands/GenerateCommand.swift +++ b/Sources/XcodeGenCLI/Commands/GenerateCommand.swift @@ -64,7 +64,7 @@ class GenerateCommand: ProjectCommand { do { let existingCacheFile: String = try cacheFilePath.read() if cacheFile.string == existingCacheFile { - info("Project has not changed since cache was written") + info("Project \(project.name) has not changed since cache was written") return } } catch { diff --git a/Sources/XcodeGenCLI/Commands/ProjectCommand.swift b/Sources/XcodeGenCLI/Commands/ProjectCommand.swift index e20b82ea..894dbc5b 100644 --- a/Sources/XcodeGenCLI/Commands/ProjectCommand.swift +++ b/Sources/XcodeGenCLI/Commands/ProjectCommand.swift @@ -12,8 +12,8 @@ class ProjectCommand: Command { let name: String let shortDescription: String - @Key("-s", "--spec", description: "The path to the project spec file. Defaults to project.yml") - var spec: Path? + @Key("-s", "--spec", description: "The path to the project spec file. Defaults to project.yml. (It is also possible to link to multiple spec files by comma separating them. Note that all other flags will be the same.)") + var spec: String? @Key("-r", "--project-root", description: "The path to the project root directory. Defaults to the directory containing the project spec.") var projectRoot: Path? @@ -29,24 +29,32 @@ class ProjectCommand: Command { func execute() throws { - let projectSpecPath = (spec ?? "project.yml").absolute() - - if !projectSpecPath.exists { - throw GenerationError.missingProjectSpec(projectSpecPath) + var projectSpecs: [Path] = [] + if let spec = spec { + projectSpecs = spec.components(separatedBy: ",").map { Path($0).absolute() } + } else { + projectSpecs = [ Path("project.yml").absolute() ] } - - let specLoader = SpecLoader(version: version) - let project: Project - - let variables: [String: String] = disableEnvExpansion ? [:] : ProcessInfo.processInfo.environment - - do { - project = try specLoader.loadProject(path: projectSpecPath, projectRoot: projectRoot, variables: variables) - } catch { - throw GenerationError.projectSpecParsingError(error) + + for projectSpecPath in projectSpecs { + if !projectSpecPath.exists { + throw GenerationError.missingProjectSpec(projectSpecPath) + } + + + let specLoader = SpecLoader(version: version) + let project: Project + + let variables: [String: String] = disableEnvExpansion ? [:] : ProcessInfo.processInfo.environment + + do { + project = try specLoader.loadProject(path: projectSpecPath, projectRoot: projectRoot, variables: variables) + } catch { + throw GenerationError.projectSpecParsingError(error) + } + + try execute(specLoader: specLoader, projectSpecPath: projectSpecPath, project: project) } - - try execute(specLoader: specLoader, projectSpecPath: projectSpecPath, project: project) } func execute(specLoader: SpecLoader, projectSpecPath: Path, project: Project) throws {} diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index 20ffcfb0..6ad5697d 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -128,8 +128,8 @@ public class PBXProjGenerator { var explicitFileType: String? var lastKnownFileType: String? - let fileType = Xcode.fileType(path: Path(target.filename)) - if target.platform == .macOS || target.platform == .watchOS || target.type == .framework { + let fileType = Xcode.fileType(path: Path(target.filename), productType: target.type) + if target.platform == .macOS || target.platform == .watchOS || target.type == .framework || target.type == .extensionKitExtension { explicitFileType = fileType } else { lastKnownFileType = fileType @@ -222,7 +222,8 @@ public class PBXProjGenerator { pbxProject.projects = subprojects } - try project.targets.forEach(generateTarget) + let pbxVariantGroupInfoList = try PBXVariantGroupGenerator(pbxProj: pbxProj, project: project).generate() + try project.targets.forEach { try generateTarget($0, pbxVariantGroupInfoList: pbxVariantGroupInfoList) } try project.aggregateTargets.forEach(generateAggregateTarget) if !carthageFrameworksByPlatform.isEmpty { @@ -648,13 +649,13 @@ public class PBXProjGenerator { return pbxproj } - func generateTarget(_ target: Target) throws { + func generateTarget(_ target: Target, pbxVariantGroupInfoList: [PBXVariantGroupInfo]) throws { let carthageDependencies = carthageResolver.dependencies(for: target) let infoPlistFiles: [Config: String] = getInfoPlists(for: target) let sourceFileBuildPhaseOverrideSequence: [(Path, BuildPhaseSpec)] = Set(infoPlistFiles.values).map({ (project.basePath + $0, .none) }) let sourceFileBuildPhaseOverrides = Dictionary(uniqueKeysWithValues: sourceFileBuildPhaseOverrideSequence) - let sourceFiles = try sourceGenerator.getAllSourceFiles(targetType: target.type, sources: target.sources, buildPhases: sourceFileBuildPhaseOverrides) + let sourceFiles = try sourceGenerator.getAllSourceFiles(targetName: target.name, targetType: target.type, sources: target.sources, buildPhases: sourceFileBuildPhaseOverrides, pbxVariantGroupInfoList: pbxVariantGroupInfoList) .sorted { $0.path.lastComponent < $1.path.lastComponent } var anyDependencyRequiresObjCLinking = false @@ -670,6 +671,7 @@ public class PBXProjGenerator { var copyWatchReferences: [PBXBuildFile] = [] var packageDependencies: [XCSwiftPackageProductDependency] = [] var extensions: [PBXBuildFile] = [] + var extensionKitExtensions: [PBXBuildFile] = [] var systemExtensions: [PBXBuildFile] = [] var appClips: [PBXBuildFile] = [] var carthageFrameworksToEmbed: [String] = [] @@ -736,8 +738,13 @@ public class PBXProjGenerator { // custom copy takes precedence customCopyDependenciesReferences.append(embedFile) } else if dependencyTarget.type.isExtension { - // embed app extension - extensions.append(embedFile) + if dependencyTarget.type == .extensionKitExtension { + // embed extension kit extension + extensionKitExtensions.append(embedFile) + } else { + // embed app extension + extensions.append(embedFile) + } } else if dependencyTarget.type.isSystemExtension { // embed system extension systemExtensions.append(embedFile) @@ -1156,13 +1163,21 @@ public class PBXProjGenerator { if !extensions.isEmpty { - let copyFilesPhase = addObject( + let copyFilesPhase = addObject( getPBXCopyFilesBuildPhase(dstSubfolderSpec: .plugins, name: "Embed App Extensions", files: extensions) ) buildPhases.append(copyFilesPhase) } + if !extensionKitExtensions.isEmpty { + + let copyFilesPhase = addObject( + getPBXCopyFilesBuildPhase(dstSubfolderSpec: .productsDirectory, dstPath: "$(EXTENSIONS_FOLDER_PATH)", name: "Embed ExtensionKit Extensions", files: extensionKitExtensions) + ) + buildPhases.append(copyFilesPhase) + } + if !systemExtensions.isEmpty { let copyFilesPhase = addObject( diff --git a/Sources/XcodeGenKit/PBXVariantGroupGenerator.swift b/Sources/XcodeGenKit/PBXVariantGroupGenerator.swift new file mode 100644 index 00000000..347aead6 --- /dev/null +++ b/Sources/XcodeGenKit/PBXVariantGroupGenerator.swift @@ -0,0 +1,155 @@ +import XcodeProj +import ProjectSpec +import PathKit +import XcodeGenCore + +class PBXVariantGroupInfo { + let targetName: String + let variantGroup: PBXVariantGroup + var path: Path + + init(targetName: String, variantGroup: PBXVariantGroup, path: Path) { + self.targetName = targetName + self.variantGroup = variantGroup + self.path = path + } +} + +class PBXVariantGroupGenerator: TargetSourceFilterable { + let pbxProj: PBXProj + let project: Project + + init(pbxProj: PBXProj, project: Project) { + self.pbxProj = pbxProj + self.project = project + } + + var alwaysStoredBaseExtensions: [String] { + [".xib", ".storyboard", ".intentdefinition"] + } + + func generate() throws -> [PBXVariantGroupInfo] { + var variantGroupInfoList: [PBXVariantGroupInfo] = [] + + try project.targets.forEach { target in + try target.sources.forEach { targetSource in + let excludePaths = getSourceMatches(targetSource: targetSource, + patterns: targetSource.excludes) + let includePaths = getSourceMatches(targetSource: targetSource, + patterns: targetSource.includes) + + let path = project.basePath + targetSource.path + + try generateVarientGroup(targetName: target.name, + targetSource: targetSource, + path: path, + excludePaths: excludePaths, + includePaths: SortedArray(includePaths)) + } + } + + func generateVarientGroup(targetName: String, + targetSource: TargetSource, + path: Path, + excludePaths: Set, + includePaths: SortedArray) throws { + guard path.exists && path.isDirectory && !Xcode.isDirectoryFileWrapper(path: path) else { + return + } + + let children = try getSourceChildren(targetSource: targetSource, + dirPath: path, + excludePaths: excludePaths, + includePaths: includePaths) + + try children.forEach { + let excludePaths = getSourceMatches(targetSource: targetSource, + patterns: targetSource.excludes) + let includePaths = getSourceMatches(targetSource: targetSource, + patterns: targetSource.includes) + + try generateVarientGroup(targetName: targetName, + targetSource: targetSource, + path: $0, + excludePaths: excludePaths, + includePaths: SortedArray(includePaths)) + } + + let localizeDirs: [Path] = children + .filter ({ $0.extension == "lproj" }) + .reduce(into: [Path]()) { partialResult, path in + if path.lastComponentWithoutExtension == "Base" { + partialResult.append(path) + } else { + partialResult.insert(path, at: 0) + } + } + + guard localizeDirs.count > 0 else { + return + } + + try localizeDirs.forEach { localizedDir in + try localizedDir.children() + .filter { self.isIncludedPath($0, excludePaths: excludePaths, includePaths: includePaths) } + .sorted() + .forEach { localizedDirChildPath in + let fileReferencePath = try localizedDirChildPath.relativePath(from: path) + let fileRef = PBXFileReference( + sourceTree: .group, + name: localizedDir.lastComponentWithoutExtension, + lastKnownFileType: Xcode.fileType(path: localizedDirChildPath), + path: fileReferencePath.string + ) + pbxProj.add(object: fileRef) + + let variantGroupInfo = getVariantGroupInfo(targetName: targetName, localizedChildPath: localizedDirChildPath) + + if localizedDir.lastComponentWithoutExtension == "Base" || project.options.developmentLanguage == localizedDir.lastComponentWithoutExtension { + + variantGroupInfo.path = localizedDirChildPath + variantGroupInfo.variantGroup.name = localizedDirChildPath.lastComponent + } + + variantGroupInfo.variantGroup.children.append(fileRef) + } + } + } + + func getVariantGroupInfo(targetName: String, localizedChildPath: Path) -> PBXVariantGroupInfo { + let pbxVariantGroupInfo = variantGroupInfoList + .filter { $0.targetName == targetName } + .first { + let existsAlwaysStoredBaseFile = alwaysStoredBaseExtensions + .reduce(into: [Bool]()) { $0.append(localizedChildPath.lastComponent.contains($1)) } + .filter { $0 } + .count > 0 + + if existsAlwaysStoredBaseFile { + return $0.path.lastComponentWithoutExtension == localizedChildPath.lastComponentWithoutExtension + } else { + return $0.path.lastComponent == localizedChildPath.lastComponent + } + } + + if let pbxVariantGroupInfo = pbxVariantGroupInfo { + return pbxVariantGroupInfo + } else { + let variantGroup = PBXVariantGroup( + sourceTree: .group, + name: localizedChildPath.lastComponent + ) + pbxProj.add(object: variantGroup) + + let pbxVariantGroupInfo = PBXVariantGroupInfo(targetName: targetName, + variantGroup: variantGroup, + path: localizedChildPath) + variantGroupInfoList.append(pbxVariantGroupInfo) + + return pbxVariantGroupInfo + } + } + + return variantGroupInfoList + } +} diff --git a/Sources/XcodeGenKit/ProjectGenerator.swift b/Sources/XcodeGenKit/ProjectGenerator.swift index 2116d714..1e03fa07 100644 --- a/Sources/XcodeGenKit/ProjectGenerator.swift +++ b/Sources/XcodeGenKit/ProjectGenerator.swift @@ -51,7 +51,7 @@ public class ProjectGenerator { func generateWorkspace() throws -> XCWorkspace { - let selfReference = XCWorkspaceDataFileRef(location: .`self`("")) + let selfReference = XCWorkspaceDataFileRef(location: .current("")) let dataElement = XCWorkspaceDataElement.file(selfReference) let workspaceData = XCWorkspaceData(children: [dataElement]) return XCWorkspace(data: workspaceData) diff --git a/Sources/XcodeGenKit/SchemeGenerator.swift b/Sources/XcodeGenKit/SchemeGenerator.swift index cd6a516b..9a4b5065 100644 --- a/Sources/XcodeGenKit/SchemeGenerator.swift +++ b/Sources/XcodeGenKit/SchemeGenerator.swift @@ -48,7 +48,7 @@ public class SchemeGenerator { xcschemes.append(xcscheme) } - for target in project.targets { + for target in project.projectTargets { if let targetScheme = target.scheme { if targetScheme.configVariants.isEmpty { let schemeName = target.name @@ -95,7 +95,7 @@ public class SchemeGenerator { return xcschemes } - public func generateScheme(_ scheme: Scheme, for target: Target? = nil) throws -> XCScheme { + public func generateScheme(_ scheme: Scheme, for target: ProjectTarget? = nil) throws -> XCScheme { func getBuildableReference(_ target: TargetReference) throws -> XCScheme.BuildableReference { let pbxProj: PBXProj @@ -179,7 +179,7 @@ public class SchemeGenerator { return XCScheme.ExecutionAction(scriptText: action.script, title: action.name, environmentBuildable: environmentBuildable) } - let schemeTarget: Target? + let schemeTarget: ProjectTarget? if let targetName = scheme.run?.executable { schemeTarget = project.getTarget(targetName) @@ -308,6 +308,7 @@ public class SchemeGenerator { askForAppToLaunch: scheme.run?.askForAppToLaunch, allowLocationSimulation: allowLocationSimulation, locationScenarioReference: locationScenarioReference, + enableGPUFrameCaptureMode: scheme.run?.enableGPUFrameCaptureMode ?? XCScheme.LaunchAction.defaultGPUFrameCaptureMode, disableMainThreadChecker: scheme.run?.disableMainThreadChecker ?? Scheme.Run.disableMainThreadCheckerDefault, stopOnEveryMainThreadCheckerIssue: scheme.run?.stopOnEveryMainThreadCheckerIssue ?? Scheme.Run.stopOnEveryMainThreadCheckerIssueDefault, commandlineArguments: launchCommandLineArgs, @@ -320,10 +321,11 @@ public class SchemeGenerator { ) let profileAction = XCScheme.ProfileAction( - buildableProductRunnable: runnables.profile, + buildableProductRunnable: shouldExecuteOnLaunch ? runnables.profile : nil, buildConfiguration: scheme.profile?.config ?? defaultReleaseConfig.name, preActions: scheme.profile?.preActions.map(getExecutionAction) ?? [], postActions: scheme.profile?.postActions.map(getExecutionAction) ?? [], + macroExpansion: shouldExecuteOnLaunch ? nil : buildableReference, shouldUseLaunchSchemeArgsEnv: scheme.profile?.shouldUseLaunchSchemeArgsEnv ?? true, askForAppToLaunch: scheme.profile?.askForAppToLaunch, commandlineArguments: profileCommandLineArgs, @@ -357,7 +359,7 @@ public class SchemeGenerator { ) } - private func launchAutomaticallySubstyle(for target: Target?) -> String? { + private func launchAutomaticallySubstyle(for target: ProjectTarget?) -> String? { if target?.type.isExtension == true { return "2" } else { @@ -365,7 +367,7 @@ public class SchemeGenerator { } } - private func makeProductRunnables(for target: Target?, buildableReference: XCScheme.BuildableReference) -> (launch: XCScheme.Runnable, profile: XCScheme.BuildableProductRunnable) { + private func makeProductRunnables(for target: ProjectTarget?, buildableReference: XCScheme.BuildableReference) -> (launch: XCScheme.Runnable, profile: XCScheme.BuildableProductRunnable) { let buildable = XCScheme.BuildableProductRunnable(buildableReference: buildableReference) if target?.type.isWatchApp == true { let remote = XCScheme.RemoteRunnable( @@ -379,7 +381,7 @@ public class SchemeGenerator { } } - private func selectedDebuggerIdentifier(for target: Target?, run: Scheme.Run?) -> String { + private func selectedDebuggerIdentifier(for target: ProjectTarget?, run: Scheme.Run?) -> String { if target?.type.canUseDebugLauncher != false && run?.debugEnabled ?? Scheme.Run.debugEnabledDefault { return XCScheme.defaultDebugger } else { @@ -387,7 +389,7 @@ public class SchemeGenerator { } } - private func selectedLauncherIdentifier(for target: Target?, run: Scheme.Run?) -> String { + private func selectedLauncherIdentifier(for target: ProjectTarget?, run: Scheme.Run?) -> String { if target?.type.canUseDebugLauncher != false && run?.debugEnabled ?? Scheme.Run.debugEnabledDefault { return XCScheme.defaultLauncher } else { @@ -418,7 +420,7 @@ enum SchemeGenerationError: Error, CustomStringConvertible { } extension Scheme { - public init(name: String, target: Target, targetScheme: TargetScheme, project: Project, debugConfig: String, releaseConfig: String) { + public init(name: String, target: ProjectTarget, targetScheme: TargetScheme, project: Project, debugConfig: String, releaseConfig: String) { self.init( name: name, build: .init( @@ -464,7 +466,7 @@ extension Scheme { ) } - private static func buildTargets(for target: Target, project: Project) -> [BuildTarget] { + private static func buildTargets(for target: ProjectTarget, project: Project) -> [BuildTarget] { let buildTarget = Scheme.BuildTarget(target: TestableTargetReference.local(target.name)) switch target.type { case .watchApp, .watch2App: diff --git a/Sources/XcodeGenKit/SettingsBuilder.swift b/Sources/XcodeGenKit/SettingsBuilder.swift index 36a252db..e4ae29f4 100644 --- a/Sources/XcodeGenKit/SettingsBuilder.swift +++ b/Sources/XcodeGenKit/SettingsBuilder.swift @@ -193,6 +193,10 @@ extension SettingsPresetFile { Path(#file).parent().parent().parent() + relativePath, ] + if let resourcePath = Bundle.main.resourcePath { + possibleSettingsPaths.append(Path(resourcePath) + relativePath) + } + if let symlink = try? (bundlePath + "xcodegen").symlinkDestination() { possibleSettingsPaths = [ symlink.parent() + relativePath, diff --git a/Sources/XcodeGenKit/SourceGenerator.swift b/Sources/XcodeGenKit/SourceGenerator.swift index e788ef09..9adbbc60 100644 --- a/Sources/XcodeGenKit/SourceGenerator.swift +++ b/Sources/XcodeGenKit/SourceGenerator.swift @@ -11,25 +11,18 @@ struct SourceFile { let buildPhase: BuildPhaseSpec? } -class SourceGenerator { +class SourceGenerator: TargetSourceFilterable { var rootGroups: Set = [] private let projectDirectory: Path? private var fileReferencesByPath: [String: PBXFileElement] = [:] private var groupsByPath: [Path: PBXGroup] = [:] - private var variantGroupsByPath: [Path: PBXVariantGroup] = [:] + private var pbxVariantGroupInfoList: [PBXVariantGroupInfo] = [] private var localPackageGroup: PBXGroup? - private let project: Project + let project: Project let pbxProj: PBXProj - private var defaultExcludedFiles = [ - ".DS_Store", - ] - private let defaultExcludedExtensions = [ - "orig", - ] - private(set) var knownRegions: Set = [] init(project: Project, pbxProj: PBXProj, projectDirectory: Path?) { @@ -90,16 +83,19 @@ class SourceGenerator { /// Collects an array complete of all `SourceFile` objects that make up the target based on the provided `TargetSource` definitions. /// /// - Parameters: - /// - targetType: The type of target that the source files should belong to. - /// - sources: The array of sources defined as part of the targets spec. - /// - buildPhases: A dictionary containing any build phases that should be applied to source files at specific paths in the event that the associated `TargetSource` didn't already define a `buildPhase`. Values from this dictionary are used in cases where the project generator knows more about a file than the spec/filesystem does (i.e if the file should be treated as the targets Info.plist and so on). - func getAllSourceFiles(targetType: PBXProductType, sources: [TargetSource], buildPhases: [Path : BuildPhaseSpec]) throws -> [SourceFile] { - try sources.flatMap { try getSourceFiles(targetType: targetType, targetSource: $0, buildPhases: buildPhases) } + /// - targetName: The name of target that the source files should belong to. + /// - targetType: The type of target that the source files should belong to. + /// - sources: The array of sources defined as part of the targets spec. + /// - buildPhases: A dictionary containing any build phases that should be applied to source files at specific paths in the event that the associated `TargetSource` didn't already define a `buildPhase`. Values from this dictionary are used in cases where the project generator knows more about a file than the spec/filesystem does (i.e if the file should be treated as the targets Info.plist and so on). + /// - pbxVariantGroupInfoList: An array of all PBXVariantGroup information expected to be added to the target + func getAllSourceFiles(targetName: String, targetType: PBXProductType, sources: [TargetSource], buildPhases: [Path : BuildPhaseSpec], pbxVariantGroupInfoList: [PBXVariantGroupInfo]) throws -> [SourceFile] { + self.pbxVariantGroupInfoList = pbxVariantGroupInfoList + return try sources.flatMap { try getSourceFiles(targetName: targetName, targetType: targetType, targetSource: $0, buildPhases: buildPhases) } } // get groups without build files. Use for Project.fileGroups func getFileGroups(path: String) throws { - _ = try getSourceFiles(targetType: .none, targetSource: TargetSource(path: path), buildPhases: [:]) + _ = try getSourceFiles(targetName: "", targetType: .none, targetSource: TargetSource(path: path), buildPhases: [:]) } func getFileType(path: Path) -> FileType? { @@ -338,84 +334,9 @@ class SourceGenerator { return groupReference } - /// Creates a variant group or returns an existing one at the path - private func getVariantGroup(path: Path, inPath: Path) -> PBXVariantGroup { - let variantGroup: PBXVariantGroup - if let cachedGroup = variantGroupsByPath[path] { - variantGroup = cachedGroup - } else { - let group = PBXVariantGroup( - sourceTree: .group, - name: path.lastComponent - ) - variantGroup = addObject(group) - variantGroupsByPath[path] = variantGroup - } - return variantGroup - } - - /// Collects all the excluded paths within the targetSource - private func getSourceMatches(targetSource: TargetSource, patterns: [String]) -> Set { - let rootSourcePath = project.basePath + targetSource.path - - return Set( - patterns.parallelMap { pattern in - guard !pattern.isEmpty else { return [] } - return Glob(pattern: "\(rootSourcePath)/\(pattern)") - .map { Path($0) } - .map { - guard $0.isDirectory else { - return [$0] - } - - return (try? $0.recursiveChildren()) ?? [] - } - .reduce([], +) - } - .reduce([], +) - ) - } - - /// Checks whether the path is not in any default or TargetSource excludes - func isIncludedPath(_ path: Path, excludePaths: Set, includePaths: SortedArray) -> Bool { - return !defaultExcludedFiles.contains(where: { path.lastComponent == $0 }) - && !(path.extension.map(defaultExcludedExtensions.contains) ?? false) - && !excludePaths.contains(path) - // If includes is empty, it's included. If it's not empty, the path either needs to match exactly, or it needs to be a direct parent of an included path. - && (includePaths.value.isEmpty || _isIncludedPathSorted(path, sortedPaths: includePaths)) - } - - private func _isIncludedPathSorted(_ path: Path, sortedPaths: SortedArray) -> Bool { - guard let idx = sortedPaths.firstIndex(where: { $0 >= path }) else { return false } - let foundPath = sortedPaths.value[idx] - return foundPath.description.hasPrefix(path.description) - } - - - /// Gets all the children paths that aren't excluded - private func getSourceChildren(targetSource: TargetSource, dirPath: Path, excludePaths: Set, includePaths: SortedArray) throws -> [Path] { - try dirPath.children() - .filter { - if $0.isDirectory { - let children = try $0.children() - - if children.isEmpty { - return project.options.generateEmptyDirectories - } - - return !children - .filter { self.isIncludedPath($0, excludePaths: excludePaths, includePaths: includePaths) } - .isEmpty - } else if $0.isFile { - return self.isIncludedPath($0, excludePaths: excludePaths, includePaths: includePaths) - } else { - return false - } - } - } - /// creates all the source files and groups they belong to for a given targetSource private func getGroupSources( + targetName: String, targetType: PBXProductType, targetSource: TargetSource, path: Path, @@ -449,9 +370,6 @@ class SourceGenerator { } } - let localisedDirectories = children - .filter { $0.extension == "lproj" } - var groupChildren: [PBXFileElement] = filePaths.map { getFileReference(path: $0, inPath: path) } var allSourceFiles: [SourceFile] = filePaths.map { generateSourceFile(targetType: targetType, targetSource: targetSource, path: $0, buildPhases: buildPhases) @@ -461,6 +379,7 @@ class SourceGenerator { for path in directories { let subGroups = try getGroupSources( + targetName: targetName, targetType: targetType, targetSource: targetSource, path: path, @@ -484,79 +403,36 @@ class SourceGenerator { groups += subGroups.groups } } - - // find the base localised directory - let baseLocalisedDirectory: Path? = { - func findLocalisedDirectory(by languageId: String) -> Path? { - localisedDirectories.first { $0.lastComponent == "\(languageId).lproj" } - } - return findLocalisedDirectory(by: "Base") ?? - findLocalisedDirectory(by: NSLocale.canonicalLanguageIdentifier(from: project.options.developmentLanguage ?? "en")) - }() - - knownRegions.formUnion(localisedDirectories.map { $0.lastComponentWithoutExtension }) - - // create variant groups of the base localisation first - var baseLocalisationVariantGroups: [PBXVariantGroup] = [] - - if let baseLocalisedDirectory = baseLocalisedDirectory { - let filePaths = try baseLocalisedDirectory.children() + + let localisedDirectories = children + .filter { $0.extension == "lproj" } + + for localizedDir in localisedDirectories { + + let localizedDirChildren = try localizedDir.children() .filter { self.isIncludedPath($0, excludePaths: excludePaths, includePaths: includePaths) } .sorted() - for filePath in filePaths { - let variantGroup = getVariantGroup(path: filePath, inPath: path) - groupChildren.append(variantGroup) - baseLocalisationVariantGroups.append(variantGroup) - + + for localizedDirChildPath in localizedDirChildren { + + guard let variantGroupInfo = pbxVariantGroupInfoList + .filter({ $0.targetName == targetName }) + .first(where: { $0.path == localizedDirChildPath }) else { + break + } + groupChildren.append(variantGroupInfo.variantGroup) + let sourceFile = generateSourceFile(targetType: targetType, targetSource: targetSource, - path: filePath, - fileReference: variantGroup, + path: localizedDirChildPath, + fileReference: variantGroupInfo.variantGroup, buildPhases: buildPhases) allSourceFiles.append(sourceFile) } } - - // add references to localised resources into base localisation variant groups - for localisedDirectory in localisedDirectories { - let localisationName = localisedDirectory.lastComponentWithoutExtension - let filePaths = try localisedDirectory.children() - .filter { self.isIncludedPath($0, excludePaths: excludePaths, includePaths: includePaths) } - .sorted { $0.lastComponent < $1.lastComponent } - for filePath in filePaths { - // find base localisation variant group - // ex: Foo.strings will be added to Foo.strings or Foo.storyboard variant group - let variantGroup = baseLocalisationVariantGroups - .first { - Path($0.name!).lastComponent == filePath.lastComponent - - } ?? baseLocalisationVariantGroups.first { - Path($0.name!).lastComponentWithoutExtension == filePath.lastComponentWithoutExtension - } - - let fileReference = getFileReference( - path: filePath, - inPath: path, - name: variantGroup != nil ? localisationName : filePath.lastComponent - ) - - if let variantGroup = variantGroup { - if !variantGroup.children.contains(fileReference) { - variantGroup.children.append(fileReference) - } - } else { - // add SourceFile to group if there is no Base.lproj directory - let sourceFile = generateSourceFile(targetType: targetType, - targetSource: targetSource, - path: filePath, - fileReference: fileReference, - buildPhases: buildPhases) - allSourceFiles.append(sourceFile) - groupChildren.append(fileReference) - } - } - } - + + knownRegions.formUnion(localisedDirectories.map { $0.lastComponentWithoutExtension }) + let group = getGroup( path: path, mergingChildren: groupChildren, @@ -573,7 +449,7 @@ class SourceGenerator { } /// creates source files - private func getSourceFiles(targetType: PBXProductType, targetSource: TargetSource, buildPhases: [Path: BuildPhaseSpec]) throws -> [SourceFile] { + private func getSourceFiles(targetName: String, targetType: PBXProductType, targetSource: TargetSource, buildPhases: [Path: BuildPhaseSpec]) throws -> [SourceFile] { // generate excluded paths let path = project.basePath + targetSource.path @@ -642,6 +518,7 @@ class SourceGenerator { } let (groupSourceFiles, groups) = try getGroupSources( + targetName: targetName, targetType: targetType, targetSource: targetSource, path: path, @@ -659,6 +536,19 @@ class SourceGenerator { sourceFiles += groupSourceFiles sourceReference = group + + case .variantGroup: + let variantGroup: PBXVariantGroup? = pbxVariantGroupInfoList + .first { $0.path == path }?.variantGroup + + let sourceFile = generateSourceFile(targetType: targetType, + targetSource: targetSource, + path: path, + fileReference: variantGroup, + buildPhases: buildPhases) + + sourceFiles.append(sourceFile) + sourceReference = variantGroup! } if hasCustomParent { @@ -675,7 +565,11 @@ class SourceGenerator { /// /// While `TargetSource` declares `type`, its optional and in the event that the value is not defined then we must resolve a sensible default based on the path of the source. private func resolvedTargetSourceType(for targetSource: TargetSource, at path: Path) -> SourceType { - return targetSource.type ?? (path.isFile || path.extension != nil ? .file : .group) + if targetSource.path.contains(".lproj") { + return .variantGroup + } else { + return targetSource.type ?? (path.isFile || path.extension != nil ? .file : .group) + } } private func createParentGroups(_ parentGroups: [String], for fileElement: PBXFileElement) { diff --git a/Sources/XcodeGenKit/TargetSourceFilterable.swift b/Sources/XcodeGenKit/TargetSourceFilterable.swift new file mode 100644 index 00000000..74fb608e --- /dev/null +++ b/Sources/XcodeGenKit/TargetSourceFilterable.swift @@ -0,0 +1,79 @@ +import XcodeProj +import ProjectSpec +import PathKit +import XcodeGenCore + +protocol TargetSourceFilterable { + var project: Project { get } + var defaultExcludedFiles: [String] { get } + var defaultExcludedExtensions: [String] { get } +} + +extension TargetSourceFilterable { + + var defaultExcludedFiles: [String] { + [".DS_Store"] + } + + var defaultExcludedExtensions: [String] { + ["orig"] + } + + /// Gets all the children paths that aren't excluded + func getSourceChildren(targetSource: TargetSource, dirPath: Path, excludePaths: Set, includePaths: SortedArray) throws -> [Path] { + try dirPath.children() + .filter { + if $0.isDirectory { + let children = try $0.children() + + if children.isEmpty { + return project.options.generateEmptyDirectories + } + + return !children + .filter { self.isIncludedPath($0, excludePaths: excludePaths, includePaths: includePaths) } + .isEmpty + } else if $0.isFile { + return self.isIncludedPath($0, excludePaths: excludePaths, includePaths: includePaths) + } else { + return false + } + } + } + + /// Checks whether the path is not in any default or TargetSource excludes + func isIncludedPath(_ path: Path, excludePaths: Set, includePaths: SortedArray) -> Bool { + return !defaultExcludedFiles.contains(where: { path.lastComponent == $0 }) + && !(path.extension.map(defaultExcludedExtensions.contains) ?? false) + && !excludePaths.contains(path) + // If includes is empty, it's included. If it's not empty, the path either needs to match exactly, or it needs to be a direct parent of an included path. + && (includePaths.value.isEmpty || _isIncludedPathSorted(path, sortedPaths: includePaths)) + } + + private func _isIncludedPathSorted(_ path: Path, sortedPaths: SortedArray) -> Bool { + guard let idx = sortedPaths.firstIndex(where: { $0 >= path }) else { return false } + let foundPath = sortedPaths.value[idx] + return foundPath.description.hasPrefix(path.description) + } + + func getSourceMatches(targetSource: TargetSource, patterns: [String]) -> Set { + let rootSourcePath = project.basePath + targetSource.path + + return Set( + patterns.parallelMap { pattern in + guard !pattern.isEmpty else { return [] } + return Glob(pattern: "\(rootSourcePath)/\(pattern)") + .map { Path($0) } + .map { + guard $0.isDirectory else { + return [$0] + } + + return (try? $0.recursiveChildren()) ?? [] + } + .reduce([], +) + } + .reduce([], +) + ) + } +} diff --git a/Sources/XcodeGenKit/XCProjExtensions.swift b/Sources/XcodeGenKit/XCProjExtensions.swift index dc03fe9d..4247ce91 100644 --- a/Sources/XcodeGenKit/XCProjExtensions.swift +++ b/Sources/XcodeGenKit/XCProjExtensions.swift @@ -53,10 +53,12 @@ extension Dictionary { extension Xcode { - public static func fileType(path: Path) -> String? { + public static func fileType(path: Path, productType: PBXProductType? = nil) -> String? { guard let fileExtension = path.extension else { return nil } - switch fileExtension { + switch (fileExtension, productType) { // cases that aren't handled (yet) in XcodeProj. + case ("appex", .extensionKitExtension): + return "wrapper.extensionkit-extension" default: // fallback to XcodeProj defaults return Xcode.filetype(extension: fileExtension) diff --git a/Tests/Fixtures/SPM/SPM.xcodeproj/xcshareddata/xcschemes/App.xcscheme b/Tests/Fixtures/SPM/SPM.xcodeproj/xcshareddata/xcschemes/App.xcscheme index a1a2a212..8e271576 100644 --- a/Tests/Fixtures/SPM/SPM.xcodeproj/xcshareddata/xcschemes/App.xcscheme +++ b/Tests/Fixtures/SPM/SPM.xcodeproj/xcshareddata/xcschemes/App.xcscheme @@ -27,8 +27,17 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - onlyGenerateCoverageForSpecifiedTargets = "NO" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES" + onlyGenerateCoverageForSpecifiedTargets = "NO"> + + + + @@ -51,15 +60,6 @@ - - - - diff --git a/Tests/Fixtures/TestProject/App_Clip/Base.lproj/Main.storyboard b/Tests/Fixtures/TestProject/App_Clip/Base.lproj/Storyboard.storyboard similarity index 100% rename from Tests/Fixtures/TestProject/App_Clip/Base.lproj/Main.storyboard rename to Tests/Fixtures/TestProject/App_Clip/Base.lproj/Storyboard.storyboard diff --git a/Tests/Fixtures/TestProject/App_Clip/en.lproj/Localizable.stringsdict b/Tests/Fixtures/TestProject/App_Clip/en.lproj/Localizable.stringsdict new file mode 100644 index 00000000..006d3e9b --- /dev/null +++ b/Tests/Fixtures/TestProject/App_Clip/en.lproj/Localizable.stringsdict @@ -0,0 +1,30 @@ + + + + + StringKey + + NSStringLocalizedFormatKey + %#@VARIABLE@ + VARIABLE + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + + zero + + one + + two + + few + + many + + other + + + + + diff --git a/Tests/Fixtures/TestProject/ExtensionKit Extension/EntryPoint.swift b/Tests/Fixtures/TestProject/ExtensionKit Extension/EntryPoint.swift new file mode 100644 index 00000000..0e665c55 --- /dev/null +++ b/Tests/Fixtures/TestProject/ExtensionKit Extension/EntryPoint.swift @@ -0,0 +1,5 @@ +import AppIntents + +@main +struct EntryPoint: AppIntentsExtension { +} diff --git a/Tests/Fixtures/TestProject/ExtensionKit Extension/Info.plist b/Tests/Fixtures/TestProject/ExtensionKit Extension/Info.plist new file mode 100644 index 00000000..8d15acbe --- /dev/null +++ b/Tests/Fixtures/TestProject/ExtensionKit Extension/Info.plist @@ -0,0 +1,11 @@ + + + + + EXAppExtensionAttributes + + EXExtensionPointIdentifier + com.apple.appintents-extension + + + diff --git a/Tests/Fixtures/TestProject/ExtensionKit Extension/Intent.swift b/Tests/Fixtures/TestProject/ExtensionKit Extension/Intent.swift new file mode 100644 index 00000000..0449c505 --- /dev/null +++ b/Tests/Fixtures/TestProject/ExtensionKit Extension/Intent.swift @@ -0,0 +1,9 @@ +import AppIntents + +struct Intent: AppIntent { + static var title: LocalizedStringResource = "Intent" + + func perform() async throws -> some IntentResult { + return .result() + } +} diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj b/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj index cc3fa31d..5c010b57 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj @@ -35,7 +35,6 @@ 0AB541AE3163B063E7012877 /* StaticLibrary_ObjC.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5A2B916A11DCC2565241359F /* StaticLibrary_ObjC.h */; }; 0BDA156BEBFCB9E65910F838 /* MyFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A58A16491CDDF968B0D56DE /* MyFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0D0E2466833FC2636B92C43D /* Swinject in Frameworks */ = {isa = PBXBuildFile; platformFilter = ios; productRef = D7917D10F77DA9D69937D493 /* Swinject */; }; - 0F99AECCB4691803C791CDCE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2FC2A8A829CE71B1CF415FF7 /* Main.storyboard */; }; 15129B8D9ED000BDA1FEEC27 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23A2F16890ECF2EE3FED72AE /* AppDelegate.swift */; }; 1551370B0ACAC632E15C853B /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF47010E7368583405AA50CB /* SwiftyJSON.framework */; }; 1BC891D89980D82738D963F3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 74FBDFA5CB063F6001AD8ACD /* Main.storyboard */; }; @@ -43,6 +42,7 @@ 1E2A4D61E96521FF7123D7B0 /* XPC Service.xpc in CopyFiles */ = {isa = PBXBuildFile; fileRef = 22237B8EBD9E6BE8EBC8735F /* XPC Service.xpc */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 1E457F55331FD2C3E8E00BE2 /* Result.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0C5AC2545AE4D4F7F44E2E9B /* Result.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 1F9168A43FD8E2FCC2699E14 /* Documentation.docc in Sources */ = {isa = PBXBuildFile; fileRef = B5C943D39DD7812CAB94B614 /* Documentation.docc */; settings = {COMPILER_FLAGS = "-Werror"; }; }; + 20B51B15FDAA4B296642DB9D /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = E8222828982682ACB6942EC9 /* Localizable.stringsdict */; }; 210B49C23B9717C668B40C8C /* FrameworkFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5F527F2590C14956518174 /* FrameworkFile.swift */; }; 2116F89CF5A04EA0EFA30A89 /* TestProjectUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D88C6BF7355702B74396791 /* TestProjectUITests.swift */; }; 212BCB51DAF3212993DDD49E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D51CC8BCCBD68A90E90A3207 /* Assets.xcassets */; }; @@ -62,6 +62,7 @@ 3133B36F3898A27A2B1C56FC /* FrameworkFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5F527F2590C14956518174 /* FrameworkFile.swift */; }; 32956CD11BD6B02E64F5D8D1 /* swift-tagged.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E4841131C451A658AC8596C /* swift-tagged.framework */; }; 3318F40C855184C18197ED30 /* StaticLibrary_ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D0C79A8C750EC0DE748C463 /* StaticLibrary_ObjC.m */; }; + 3352A6F4623250F4186D49AF /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BDF80447206456A66BD42FB7 /* Storyboard.storyboard */; }; 339578307B9266AB3D7722D9 /* File2.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC56891DA7446EAC8C2F27EB /* File2.swift */; }; 3535891EC86283BB5064E7E1 /* Headers in Headers */ = {isa = PBXBuildFile; fileRef = 2E1E747C7BC434ADB80CC269 /* Headers */; settings = {ATTRIBUTES = (Public, ); }; }; 3788E1382B38DF4ACE3D2BB1 /* MyFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A58A16491CDDF968B0D56DE /* MyFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -135,6 +136,7 @@ A90C4C147AD175DB9F7B5114 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03CD22B8CD2E91BB97CC534E /* main.swift */; }; A949422315536EACDF8DD78A /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B785B1161553A7DD6DA4255 /* NetworkExtension.framework */; }; A9548E5DCFE92236494164DF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CE1F06D99242F4223D081F0D /* LaunchScreen.storyboard */; }; + AC15BD11AE6121DDE7C34A51 /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BDF80447206456A66BD42FB7 /* Storyboard.storyboard */; }; AFF19412E9B35635D3AF48CB /* XPC_Service.m in Sources */ = {isa = PBXBuildFile; fileRef = 148B7C933698BCC4F1DBA979 /* XPC_Service.m */; }; B142965C5AE9C6200BF65802 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C5AC2545AE4D4F7F44E2E9B /* Result.framework */; platformFilter = maccatalyst; }; B18C121B0A4D43ED8149D8E2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 79325B44B19B83EC6CEDBCC5 /* LaunchScreen.storyboard */; }; @@ -157,6 +159,7 @@ CCA17097382757012B58C17C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1BC32A813B80A53962A1F365 /* Assets.xcassets */; }; D5458D67C3596943114C3205 /* Standalone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F5BD97AF0F94A15A5B7DDB7 /* Standalone.swift */; }; D61BEABD5B26B2DE67D0C2EC /* FrameworkFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5F527F2590C14956518174 /* FrameworkFile.swift */; }; + D6312C8EBF458001D43FBDC2 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = E8222828982682ACB6942EC9 /* Localizable.stringsdict */; }; D8ED40ED61AD912385CFF5F0 /* StaticLibrary_ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D0C79A8C750EC0DE748C463 /* StaticLibrary_ObjC.m */; }; DD5FBFC3C1B2DB3D0D1CF210 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B785B1161553A7DD6DA4255 /* NetworkExtension.framework */; }; E0B27599D701E6BB0223D0A8 /* FilterDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16AA52945B70B1BF9E246350 /* FilterDataProvider.swift */; }; @@ -690,7 +693,6 @@ 2A5F527F2590C14956518174 /* FrameworkFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrameworkFile.swift; sourceTree = ""; }; 2E1E747C7BC434ADB80CC269 /* Headers */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Headers; sourceTree = SOURCE_ROOT; }; 2F430AABE04B7499B458D9DB /* SwiftFileInDotPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftFileInDotPath.swift; sourceTree = ""; }; - 3096A0760969873D46F80A92 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 325F18855099386B08DD309B /* Resource.abcd */ = {isa = PBXFileReference; path = Resource.abcd; sourceTree = ""; }; 33F6DCDC37D2E66543D4965D /* App_macOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App_macOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; 34F13B632328979093CE6056 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; @@ -798,6 +800,7 @@ E43116070AFEF5D8C3A5A957 /* TestFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TestFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; E55F45EACB0F382722D61C8D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; E5E0A80CCE8F8DB662DCD2D0 /* EndpointSecuritySystemExtension.systemextension */ = {isa = PBXFileReference; explicitFileType = "wrapper.system-extension"; includeInIndex = 0; path = EndpointSecuritySystemExtension.systemextension; sourceTree = BUILT_PRODUCTS_DIR; }; + E9182F7632482B8412DC5AE0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = ""; }; E9672EF8FE1DDC8DE0705129 /* PushNotificationPayload.apns */ = {isa = PBXFileReference; lastKnownFileType = text; path = PushNotificationPayload.apns; sourceTree = ""; }; EDCC70978B8AD49373DA0DE0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; EE1343F2238429D4DA9D830B /* File1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = File1.swift; path = Group/File1.swift; sourceTree = ""; }; @@ -806,6 +809,7 @@ F192E783CCA898FBAA5C34EA /* AnotherProject */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = AnotherProject; path = AnotherProject/AnotherProject.xcodeproj; sourceTree = ""; }; F2950763C4C568CC85021D18 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; F2FA55A558627ED576A4AFD6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + FA152C2101E254C78F43CFAE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Storyboard.storyboard; sourceTree = ""; }; FA86D418796C1A6864414460 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; }; FD05F36F95D6F098A76F220B /* XPC_Service.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPC_Service.h; sourceTree = ""; }; FD4A16C7B8FEB7F97F3CBE3F /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; @@ -1342,7 +1346,8 @@ 1FA5E208EC184E3030D2A21D /* Clip.entitlements */, 6F165CDD5BCC13AFF50B65E2 /* Info.plist */, 79325B44B19B83EC6CEDBCC5 /* LaunchScreen.storyboard */, - 2FC2A8A829CE71B1CF415FF7 /* Main.storyboard */, + E8222828982682ACB6942EC9 /* Localizable.stringsdict */, + BDF80447206456A66BD42FB7 /* Storyboard.storyboard */, DFE6A6FAAFF701FE729293DE /* ViewController.swift */, ); path = App_Clip; @@ -1941,6 +1946,7 @@ buildConfigurationList = 129D9E77D45A66B1C78578F2 /* Build configuration list for PBXNativeTarget "App_Clip_UITests" */; buildPhases = ( 2E1429F0FB524A2BCFC61DF1 /* Sources */, + 78249BAE6D3EE80459CF1FA9 /* Resources */, 05D615CB74F875917AA8C9B0 /* Embed Frameworks */, ); buildRules = ( @@ -2306,6 +2312,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 78249BAE6D3EE80459CF1FA9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D6312C8EBF458001D43FBDC2 /* Localizable.stringsdict in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 8508BA1B733839E314AF2853 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -2322,6 +2336,7 @@ 61601545B6BE00CA74A4E38F /* SceneKitCatalog.scnassets in Resources */, 28A96EBC76D53817AABDA91C /* Settings.bundle in Resources */, E8A135F768448632F8D77C8F /* StandaloneAssets.xcassets in Resources */, + AC15BD11AE6121DDE7C34A51 /* Storyboard.storyboard in Resources */, 818D448D4DDD6649B5B26098 /* example.mp4 in Resources */, 2C7C03B45571A13D472D6B23 /* iMessageApp.app in Resources */, ); @@ -2341,7 +2356,8 @@ files = ( 61516CAC12B2843FBC4572E6 /* Assets.xcassets in Resources */, B18C121B0A4D43ED8149D8E2 /* LaunchScreen.storyboard in Resources */, - 0F99AECCB4691803C791CDCE /* Main.storyboard in Resources */, + 20B51B15FDAA4B296642DB9D /* Localizable.stringsdict in Resources */, + 3352A6F4623250F4186D49AF /* Storyboard.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3007,14 +3023,6 @@ name = LocalizedStoryboard.storyboard; sourceTree = ""; }; - 2FC2A8A829CE71B1CF415FF7 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 3096A0760969873D46F80A92 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; 65C8D6D1DDC1512D396C07B7 /* Localizable.stringsdict */ = { isa = PBXVariantGroup; children = ( @@ -3065,6 +3073,14 @@ name = Localizable.strings; sourceTree = ""; }; + BDF80447206456A66BD42FB7 /* Storyboard.storyboard */ = { + isa = PBXVariantGroup; + children = ( + FA152C2101E254C78F43CFAE /* Base */, + ); + name = Storyboard.storyboard; + sourceTree = ""; + }; C872631362DDBAFCE71E5C66 /* Interface.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -3081,6 +3097,14 @@ name = LaunchScreen.storyboard; sourceTree = ""; }; + E8222828982682ACB6942EC9 /* Localizable.stringsdict */ = { + isa = PBXVariantGroup; + children = ( + E9182F7632482B8412DC5AE0 /* en */, + ); + name = Localizable.stringsdict; + sourceTree = ""; + }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_Clip.xcscheme b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_Clip.xcscheme index 5634a004..a8251587 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_Clip.xcscheme +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_Clip.xcscheme @@ -27,8 +27,17 @@ buildConfiguration = "Production Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - onlyGenerateCoverageForSpecifiedTargets = "NO" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES" + onlyGenerateCoverageForSpecifiedTargets = "NO"> + + + + @@ -51,15 +60,6 @@ - - - - diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_Scheme.xcscheme b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_Scheme.xcscheme index c157cfbe..529d76e3 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_Scheme.xcscheme +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_Scheme.xcscheme @@ -27,16 +27,25 @@ buildConfiguration = "Production Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - codeCoverageEnabled = "YES" - onlyGenerateCoverageForSpecifiedTargets = "NO" + customLLDBInitFile = "${SRCROOT}/.lldbinit" shouldUseLaunchSchemeArgsEnv = "YES" - customLLDBInitFile = "${SRCROOT}/.lldbinit"> + codeCoverageEnabled = "YES" + onlyGenerateCoverageForSpecifiedTargets = "NO"> + + + + @@ -65,15 +74,6 @@ - - - - @@ -81,13 +81,14 @@ buildConfiguration = "Production Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "${SRCROOT}/.lldbinit" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" - allowLocationSimulation = "YES" - customLLDBInitFile = "${SRCROOT}/.lldbinit"> + enableGPUFrameCaptureMode = "3" + allowLocationSimulation = "YES"> + disableMainThreadChecker = "YES" + codeCoverageEnabled = "YES" + onlyGenerateCoverageForSpecifiedTargets = "YES"> + + + + @@ -53,15 +62,6 @@ - - - - diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_iOS Staging.xcscheme b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_iOS Staging.xcscheme index ca647df9..d68715c4 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_iOS Staging.xcscheme +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_iOS Staging.xcscheme @@ -27,10 +27,19 @@ buildConfiguration = "Staging Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - codeCoverageEnabled = "YES" - onlyGenerateCoverageForSpecifiedTargets = "YES" shouldUseLaunchSchemeArgsEnv = "NO" - disableMainThreadChecker = "YES"> + disableMainThreadChecker = "YES" + codeCoverageEnabled = "YES" + onlyGenerateCoverageForSpecifiedTargets = "YES"> + + + + @@ -53,15 +62,6 @@ - - - - diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_iOS Test.xcscheme b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_iOS Test.xcscheme index cef83f89..38d23c89 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_iOS Test.xcscheme +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_iOS Test.xcscheme @@ -27,10 +27,19 @@ buildConfiguration = "Test Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - codeCoverageEnabled = "YES" - onlyGenerateCoverageForSpecifiedTargets = "YES" shouldUseLaunchSchemeArgsEnv = "NO" - disableMainThreadChecker = "YES"> + disableMainThreadChecker = "YES" + codeCoverageEnabled = "YES" + onlyGenerateCoverageForSpecifiedTargets = "YES"> + + + + @@ -53,15 +62,6 @@ - - - - diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_macOS.xcscheme b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_macOS.xcscheme index 094f19bb..b4c58b61 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_macOS.xcscheme +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_macOS.xcscheme @@ -27,10 +27,8 @@ buildConfiguration = "Production Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - onlyGenerateCoverageForSpecifiedTargets = "NO" - shouldUseLaunchSchemeArgsEnv = "YES"> - - + shouldUseLaunchSchemeArgsEnv = "YES" + onlyGenerateCoverageForSpecifiedTargets = "NO"> + + diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_watchOS.xcscheme b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_watchOS.xcscheme index 3282fb2a..63ec7f6a 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_watchOS.xcscheme +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_watchOS.xcscheme @@ -41,10 +41,8 @@ buildConfiguration = "Production Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - onlyGenerateCoverageForSpecifiedTargets = "NO" - shouldUseLaunchSchemeArgsEnv = "YES"> - - + shouldUseLaunchSchemeArgsEnv = "YES" + onlyGenerateCoverageForSpecifiedTargets = "NO"> + + @@ -68,8 +68,8 @@ debugServiceExtension = "internal" allowLocationSimulation = "YES"> + runnableDebuggingMode = "2" + BundleIdentifier = "com.apple.Carousel"> - - + shouldUseLaunchSchemeArgsEnv = "YES" + onlyGenerateCoverageForSpecifiedTargets = "NO"> + + diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/EndpointSecuritySystemExtension.xcscheme b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/EndpointSecuritySystemExtension.xcscheme index 9657adfa..be2f3dab 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/EndpointSecuritySystemExtension.xcscheme +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/EndpointSecuritySystemExtension.xcscheme @@ -27,10 +27,8 @@ buildConfiguration = "Production Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - onlyGenerateCoverageForSpecifiedTargets = "NO" - shouldUseLaunchSchemeArgsEnv = "YES"> - - + shouldUseLaunchSchemeArgsEnv = "YES" + onlyGenerateCoverageForSpecifiedTargets = "NO"> + + diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/Framework.xcscheme b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/Framework.xcscheme index af66ac90..3f0af839 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/Framework.xcscheme +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/Framework.xcscheme @@ -46,12 +46,10 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" language = "ja" + shouldUseLaunchSchemeArgsEnv = "YES" region = "en" codeCoverageEnabled = "YES" - onlyGenerateCoverageForSpecifiedTargets = "NO" - shouldUseLaunchSchemeArgsEnv = "YES"> - - + onlyGenerateCoverageForSpecifiedTargets = "NO"> + + @@ -100,8 +100,7 @@ savedToolIdentifier = "" useCustomWorkingDirectory = "NO" debugDocumentVersioning = "YES"> - + - + diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/NetworkSystemExtension.xcscheme b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/NetworkSystemExtension.xcscheme index 960e2242..81af9fc0 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/NetworkSystemExtension.xcscheme +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/NetworkSystemExtension.xcscheme @@ -27,10 +27,8 @@ buildConfiguration = "Production Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - onlyGenerateCoverageForSpecifiedTargets = "NO" - shouldUseLaunchSchemeArgsEnv = "YES"> - - + shouldUseLaunchSchemeArgsEnv = "YES" + onlyGenerateCoverageForSpecifiedTargets = "NO"> + + diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/Tool.xcscheme b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/Tool.xcscheme index bdde4cd5..4eea0b5b 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/Tool.xcscheme +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/Tool.xcscheme @@ -27,10 +27,8 @@ buildConfiguration = "Production Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - onlyGenerateCoverageForSpecifiedTargets = "NO" - shouldUseLaunchSchemeArgsEnv = "YES"> - - + shouldUseLaunchSchemeArgsEnv = "YES" + onlyGenerateCoverageForSpecifiedTargets = "NO"> + + diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/iMessageApp.xcscheme b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/iMessageApp.xcscheme index 064fffc4..30a5fccf 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/iMessageApp.xcscheme +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/iMessageApp.xcscheme @@ -27,10 +27,8 @@ buildConfiguration = "Production Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - onlyGenerateCoverageForSpecifiedTargets = "NO" - shouldUseLaunchSchemeArgsEnv = "YES"> - - + shouldUseLaunchSchemeArgsEnv = "YES" + onlyGenerateCoverageForSpecifiedTargets = "NO"> + + diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/iMessageExtension.xcscheme b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/iMessageExtension.xcscheme index ed530e2c..5a9e872b 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/iMessageExtension.xcscheme +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/iMessageExtension.xcscheme @@ -1,8 +1,8 @@ + wasCreatedForAppExtension = "YES" + version = "1.7"> - - + shouldUseLaunchSchemeArgsEnv = "YES" + onlyGenerateCoverageForSpecifiedTargets = "NO"> + + diff --git a/Tests/Fixtures/TestProject/project.yml b/Tests/Fixtures/TestProject/project.yml index 5692e7e2..06d70b85 100644 --- a/Tests/Fixtures/TestProject/project.yml +++ b/Tests/Fixtures/TestProject/project.yml @@ -121,6 +121,7 @@ targets: resourceTags: - tag1 - tag2 + - path: App_Clip/Base.lproj/Storyboard.storyboard settings: INFOPLIST_FILE: App_iOS/Info.plist PRODUCT_BUNDLE_IDENTIFIER: com.project.app @@ -146,6 +147,9 @@ targets: - package: Swinject product: Swinject platformFilter: iOS +# https://github.com/yonaskolb/XcodeGen/issues/1232 +# After GitHub Actions start supporting Xcode 14, an example for extensionKit should be added. +# - target: ExtensionKitExtension onlyCopyFilesOnInstall: true scheme: testTargets: @@ -387,9 +391,17 @@ targets: App_Clip_UITests: type: bundle.ui-testing platform: iOS - sources: App_Clip_UITests + sources: + - path: App_Clip_UITests + - path: App_Clip/en.lproj/Localizable.stringsdict dependencies: - target: App_Clip +# https://github.com/yonaskolb/XcodeGen/issues/1232 +# After GitHub Actions start supporting Xcode 14, an example for extensionKit should be added. +# ExtensionKitExtension: +# type: extensionkit-extension +# platform: iOS +# sources: ExtensionKit Extension schemes: Framework: @@ -419,6 +431,7 @@ schemes: allow: true defaultLocation: Honolulu, HI, USA customLLDBInit: ${SRCROOT}/.lldbinit + enableGPUFrameCaptureMode: "disabled" storeKitConfiguration: "App_iOS/Configuration.storekit" macroExpansion: App_iOS test: diff --git a/Tests/Fixtures/include_test.yml b/Tests/Fixtures/include_test.yml index 6affefa6..1c24a731 100644 --- a/Tests/Fixtures/include_test.yml +++ b/Tests/Fixtures/include_test.yml @@ -1,4 +1,11 @@ -include: [included.yml] +include: + - included.yml + - path: included_addtional.yml + enable: ${INCLUDE_ADDTIONAL_YAML} +packages: + Yams: + url: https://github.com/jpsim/Yams + majorVersion: 2.0.0 name: NewName settingGroups: test: @@ -19,3 +26,5 @@ targets: name: IncludedTargetNew platform: tvOS sources:REPLACE: NewSource + dependencies: + - package: Yams diff --git a/Tests/Fixtures/included_addtional.yml b/Tests/Fixtures/included_addtional.yml new file mode 100644 index 00000000..3623d2be --- /dev/null +++ b/Tests/Fixtures/included_addtional.yml @@ -0,0 +1,12 @@ +name: Included_Addtional +settingGroups: + test: + MY_SETTING5: ADDTIONAL +packages: + SwiftPM: + url: https://github.com/apple/swift-package-manager + branch: swift-5.0-branch +targets: + IncludedTarget: + dependencies: + - package: SwiftPM diff --git a/Tests/Fixtures/legacy_paths_test/legacy_included_paths_test.yml b/Tests/Fixtures/legacy_paths_test/legacy_included_paths_test.yml index de8cce3c..7156ff0f 100644 --- a/Tests/Fixtures/legacy_paths_test/legacy_included_paths_test.yml +++ b/Tests/Fixtures/legacy_paths_test/legacy_included_paths_test.yml @@ -1,5 +1,8 @@ configFiles: IncludedConfig: config +include: + - path: legacy_paths_test/recursive_include.yml + relativePaths: false options: carthageBuildPath: carthage_build carthageExecutablePath: carthage_executable @@ -9,8 +12,6 @@ targets: platform: tvOS configFiles: Config: config - sources: - - source dependencies: - framework: Framework info: diff --git a/Tests/Fixtures/legacy_paths_test/recursive_include.yml b/Tests/Fixtures/legacy_paths_test/recursive_include.yml new file mode 100644 index 00000000..0da21bd9 --- /dev/null +++ b/Tests/Fixtures/legacy_paths_test/recursive_include.yml @@ -0,0 +1,4 @@ +targets: + IncludedTarget: + sources: + - source diff --git a/Tests/PerformanceTests/PerformanceTests.swift b/Tests/PerformanceTests/PerformanceTests.swift index 294b1b9c..a241e348 100644 --- a/Tests/PerformanceTests/PerformanceTests.swift +++ b/Tests/PerformanceTests/PerformanceTests.swift @@ -13,10 +13,13 @@ class GeneratedPerformanceTests: XCTestCase { let project = try Project.testProject(basePath: basePath) let specPath = basePath + "project.yaml" try dumpYamlDictionary(project.toJSONDictionary(), path: specPath) + var cachedSpecFiles: [Path: SpecFile] = [:] measure { - let spec = try! SpecFile(path: specPath) - _ = spec.resolvedDictionary(variables: ProcessInfo.processInfo.environment) + let spec = try! SpecFile(path: specPath, + cachedSpecFiles: &cachedSpecFiles, + variables: ProcessInfo.processInfo.environment) + _ = spec.resolvedDictionary() } } diff --git a/Tests/ProjectSpecTests/ProjectSpecTests.swift b/Tests/ProjectSpecTests/ProjectSpecTests.swift index 65f9398e..56df66f3 100644 --- a/Tests/ProjectSpecTests/ProjectSpecTests.swift +++ b/Tests/ProjectSpecTests/ProjectSpecTests.swift @@ -142,6 +142,40 @@ class ProjectSpecTests: XCTestCase { try expectValidationError(project, .invalidBuildSettingConfig("invalidSettingGroupConfig")) } + $0.it("fails with duplicate dependencies") { + var project = baseProject + project.targets = [ + Target( + name: "target1", + type: .application, + platform: .iOS, + settings: invalidSettings, + dependencies: [ + Dependency(type: .target, reference: "dependency1"), + Dependency(type: .target, reference: "dependency1"), + Dependency(type: .framework, reference: "dependency2"), + Dependency(type: .framework, reference: "dependency2"), + ] + ), + Target( + name: "target2", + type: .framework, + platform: .iOS, + settings: invalidSettings, + dependencies: [ + Dependency(type: .framework, reference: "dependency3"), + Dependency(type: .target, reference: "dependency3"), + Dependency(type: .target, reference: "dependency4"), + Dependency(type: .target, reference: "dependency4"), + ] + ) + ] + + try expectValidationError(project, .duplicateDependencies(target: "target1", dependencyReference: "dependency1")) + try expectValidationError(project, .duplicateDependencies(target: "target1", dependencyReference: "dependency2")) + try expectValidationError(project, .duplicateDependencies(target: "target2", dependencyReference: "dependency4")) + } + $0.it("allows non-existent configurations") { var project = baseProject project.options = SpecOptions(disabledValidations: [.missingConfigs]) @@ -606,6 +640,7 @@ class ProjectSpecTests: XCTestCase { environmentVariables: [XCScheme.EnvironmentVariable(variable: "foo", value: "bar", enabled: false)], + enableGPUFrameCaptureMode: .openGL, launchAutomaticallySubstyle: "2", storeKitConfiguration: "Configuration.storekit"), test: Scheme.Test(config: "Config", diff --git a/Tests/ProjectSpecTests/SpecLoadingTests.swift b/Tests/ProjectSpecTests/SpecLoadingTests.swift index 7bab9329..5f7354ef 100644 --- a/Tests/ProjectSpecTests/SpecLoadingTests.swift +++ b/Tests/ProjectSpecTests/SpecLoadingTests.swift @@ -29,7 +29,7 @@ class SpecLoadingTests: XCTestCase { describe { $0.it("merges includes") { let path = fixturePath + "include_test.yml" - let project = try loadSpec(path: path) + let project = try loadSpec(path: path, variables: [:]) try expect(project.name) == "NewName" try expect(project.settingGroups) == [ @@ -38,7 +38,39 @@ class SpecLoadingTests: XCTestCase { "toReplace": Settings(dictionary: ["MY_SETTING2": "VALUE2"]), ] try expect(project.targets) == [ - Target(name: "IncludedTargetNew", type: .application, platform: .tvOS, sources: ["NewSource"]), + Target(name: "IncludedTargetNew", type: .application, platform: .tvOS, sources: ["NewSource"], dependencies: [Dependency(type: .package(product: nil), reference: "Yams")]), + Target(name: "NewTarget", type: .application, platform: .iOS, sources: ["template", "target"]), + ] + } + + $0.it("merges includes with addtional one") { + let path = fixturePath + "include_test.yml" + let project = try loadSpec(path: path, variables: ["INCLUDE_ADDTIONAL_YAML": "YES"]) + + try expect(project.name) == "NewName" + try expect(project.settingGroups) == [ + "test": Settings(dictionary: ["MY_SETTING1": "NEW VALUE", "MY_SETTING2": "VALUE2", "MY_SETTING3": "VALUE3", "MY_SETTING4": "${SETTING4}", "MY_SETTING5": "ADDTIONAL"]), + "new": Settings(dictionary: ["MY_SETTING": "VALUE"]), + "toReplace": Settings(dictionary: ["MY_SETTING2": "VALUE2"]), + ] + try expect(project.targets) == [ + Target(name: "IncludedTargetNew", type: .application, platform: .tvOS, sources: ["NewSource"], dependencies: [Dependency(type: .package(product: nil), reference: "SwiftPM"), Dependency(type: .package(product: nil), reference: "Yams")]), + Target(name: "NewTarget", type: .application, platform: .iOS, sources: ["template", "target"]), + ] + } + + $0.it("merges includes without addtional one by environemnt variable") { + let path = fixturePath + "include_test.yml" + let project = try loadSpec(path: path, variables: ["INCLUDE_ADDTIONAL_YAML": "NO"]) + + try expect(project.name) == "NewName" + try expect(project.settingGroups) == [ + "test": Settings(dictionary: ["MY_SETTING1": "NEW VALUE", "MY_SETTING2": "VALUE2", "MY_SETTING3": "VALUE3", "MY_SETTING4": "${SETTING4}"]), + "new": Settings(dictionary: ["MY_SETTING": "VALUE"]), + "toReplace": Settings(dictionary: ["MY_SETTING2": "VALUE2"]), + ] + try expect(project.targets) == [ + Target(name: "IncludedTargetNew", type: .application, platform: .tvOS, sources: ["NewSource"], dependencies: [Dependency(type: .package(product: nil), reference: "Yams")]), Target(name: "NewTarget", type: .application, platform: .iOS, sources: ["template", "target"]), ] } @@ -791,6 +823,7 @@ class SpecLoadingTests: XCTestCase { "run": [ "config": "debug", "launchAutomaticallySubstyle": 2, + "enableGPUFrameCaptureMode": "disabled", "storeKitConfiguration": "Configuration.storekit", ], "test": [ @@ -841,6 +874,7 @@ class SpecLoadingTests: XCTestCase { let expectedRun = Scheme.Run( config: "debug", + enableGPUFrameCaptureMode: .disabled, launchAutomaticallySubstyle: "2", storeKitConfiguration: "Configuration.storekit" ) diff --git a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift index 168bf401..4ed5ae08 100644 --- a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift @@ -2094,6 +2094,50 @@ class ProjectGeneratorTests: XCTestCase { try expectCopyPhase(in: pbxProject, withFilePaths: ["extA.appex"], toSubFolder: .executables, dstPath: "test") } } + + $0.context("extensionKit") { + + let extA = Target( + name: "extA", + type: .extensionKitExtension, + platform: .macOS + ) + let extB = Target( + name: "extB", + type: .extensionKitExtension, + platform: .macOS + ) + + $0.it("embeds them into plugins without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: extA.name, embed: true), + Dependency(type: .target, reference: extB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [extA, extB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["extA.appex"], toSubFolder: .productsDirectory, dstPath: "$(EXTENSIONS_FOLDER_PATH)") + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: extA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .productsDirectory, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: extB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .productsDirectory, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [extA, extB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["extA.appex"], toSubFolder: .productsDirectory, dstPath: "test") + } + } $0.context("commandLineTool") { diff --git a/Tests/XcodeGenKitTests/SchemeGeneratorTests.swift b/Tests/XcodeGenKitTests/SchemeGeneratorTests.swift index e2c7ded6..ef110faf 100644 --- a/Tests/XcodeGenKitTests/SchemeGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/SchemeGeneratorTests.swift @@ -52,7 +52,7 @@ class SchemeGeneratorTests: XCTestCase { let scheme = try Scheme( name: "MyScheme", build: Scheme.Build(targets: [buildTarget], preActions: [preAction]), - run: Scheme.Run(config: "Debug", askForAppToLaunch: true, launchAutomaticallySubstyle: "2", simulateLocation: simulateLocation, storeKitConfiguration: storeKitConfiguration, customLLDBInit: "/sample/.lldbinit"), + run: Scheme.Run(config: "Debug", enableGPUFrameCaptureMode: .metal, askForAppToLaunch: true, launchAutomaticallySubstyle: "2", simulateLocation: simulateLocation, storeKitConfiguration: storeKitConfiguration, customLLDBInit: "/sample/.lldbinit"), test: Scheme.Test(config: "Debug", targets: [ Scheme.Test.TestTarget(targetReference: TestableTargetReference(framework.name), location: "test.gpx"), Scheme.Test.TestTarget(targetReference: TestableTargetReference(framework.name), location: "New York, NY, USA") @@ -110,6 +110,7 @@ class SchemeGeneratorTests: XCTestCase { try expect(xcscheme.launchAction?.locationScenarioReference?.referenceType) == Scheme.SimulateLocation.ReferenceType.predefined.rawValue try expect(xcscheme.launchAction?.locationScenarioReference?.identifier) == "New York, NY, USA" try expect(xcscheme.launchAction?.customLLDBInitFile) == "/sample/.lldbinit" + try expect(xcscheme.launchAction?.enableGPUFrameCaptureMode) == .metal try expect(xcscheme.testAction?.customLLDBInitFile) == "/test/.lldbinit" try expect(xcscheme.testAction?.systemAttachmentLifetime).to.beNil() @@ -266,7 +267,7 @@ class SchemeGeneratorTests: XCTestCase { let scheme = Scheme( name: "TestScheme", build: Scheme.Build(targets: [buildTarget]), - run: Scheme.Run(config: "Debug", debugEnabled: false, simulateLocation: .init(allow: true, defaultLocation: "File.gpx"), storeKitConfiguration: "Configuration.storekit") + run: Scheme.Run(config: "Debug", enableGPUFrameCaptureMode: .metal, debugEnabled: false, simulateLocation: .init(allow: true, defaultLocation: "File.gpx"), storeKitConfiguration: "Configuration.storekit") ) let project = Project( name: "test", @@ -282,6 +283,7 @@ class SchemeGeneratorTests: XCTestCase { try expect(xcscheme.launchAction?.storeKitConfigurationFileReference?.identifier) == "../../Configuration.storekit" try expect(xcscheme.launchAction?.locationScenarioReference?.referenceType) == Scheme.SimulateLocation.ReferenceType.gpx.rawValue try expect(xcscheme.launchAction?.locationScenarioReference?.identifier) == "../../File.gpx" + try expect(xcscheme.launchAction?.enableGPUFrameCaptureMode) == .metal } $0.it("generate scheme without debugger - test") { diff --git a/Tests/XcodeGenKitTests/SourceGeneratorTests.swift b/Tests/XcodeGenKitTests/SourceGeneratorTests.swift index e1121df7..460308b2 100644 --- a/Tests/XcodeGenKitTests/SourceGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/SourceGeneratorTests.swift @@ -143,41 +143,77 @@ class SourceGeneratorTests: XCTestCase { let directories = """ Sources: Base.lproj: + - LocalizedXib.xib - LocalizedStoryboard.storyboard + - IntentDefinition.intentdefinition + - BaseLocalizable.strings en.lproj: + - LocalizedXib.strings - LocalizedStoryboard.strings + - IntentDefinition.strings + - BaseLocalizable.strings + - Localizable.strings + ja.lproj: + - LocalizedXib.strings + - LocalizedStoryboard.strings + - IntentDefinition.strings + - BaseLocalizable.strings + - Localizable.strings """ try createDirectories(directories) let target = Target(name: "Test", type: .application, platform: .iOS, sources: ["Sources"]) - let project = Project(basePath: directoryPath, name: "Test", targets: [target]) + let project = Project(basePath: directoryPath, name: "Test", targets: [target], options: SpecOptions(developmentLanguage: "en")) let pbxProj = try project.generatePbxProj() - - func getFileReferences(_ path: String) -> [PBXFileReference] { - pbxProj.fileReferences.filter { $0.path == path } - } - - func getVariableGroups(_ name: String?) -> [PBXVariantGroup] { - pbxProj.variantGroups.filter { $0.name == name } - } - - let resourceName = "LocalizedStoryboard.storyboard" - let baseResource = "Base.lproj/LocalizedStoryboard.storyboard" - let localizedResource = "en.lproj/LocalizedStoryboard.strings" - - let variableGroup = try unwrap(getVariableGroups(resourceName).first) - - do { - let refs = getFileReferences(baseResource) - try expect(refs.count) == 1 - try expect(variableGroup.children.filter { $0 == refs.first }.count) == 1 - } - - do { - let refs = getFileReferences(localizedResource) - try expect(refs.count) == 1 - try expect(variableGroup.children.filter { $0 == refs.first }.count) == 1 + + let resourceList: [(name: String, basePath: String, localizedResources: [String])] = [ + // resouce is stored in base localized directory + ( + name: "LocalizedXib.xib", + basePath: "Base.lproj/LocalizedXib.xib", + localizedResources: ["en.lproj/LocalizedXib.strings", "ja.lproj/LocalizedXib.strings"] + ), + ( + name: "LocalizedStoryboard.storyboard", + basePath: "Base.lproj/LocalizedStoryboard.storyboard", + localizedResources: ["en.lproj/LocalizedStoryboard.strings", "ja.lproj/LocalizedStoryboard.strings"] + ), + ( + name: "IntentDefinition.intentdefinition", + basePath: "Base.lproj/IntentDefinition.intentdefinition", + localizedResources: ["en.lproj/IntentDefinition.strings", "ja.lproj/IntentDefinition.strings"] + ), + ( + name: "BaseLocalizable.strings", + basePath: "Base.lproj/BaseLocalizable.strings", + localizedResources: ["en.lproj/BaseLocalizable.strings", "ja.lproj/BaseLocalizable.strings"] + ), + // resouce is not stored in base localized directory + ( + name: "Localizable.strings", + basePath: "en.lproj/Localizable.strings", + localizedResources: ["ja.lproj/Localizable.strings"] + ) + ] + + try resourceList.forEach { resource in + + let variableGroup = try unwrap(pbxProj.variantGroups.filter { $0.name == resource.name }.first) + + do { + let refs = pbxProj.fileReferences.filter { $0.path == resource.basePath } + try expect(refs.count) == 1 + try expect(variableGroup.children.filter { $0 == refs.first }.count) == 1 + } + + try resource.localizedResources.forEach { localizedResource in + do { + let refs = pbxProj.fileReferences.filter { $0.path == localizedResource } + try expect(refs.count) == 1 + try expect(variableGroup.children.filter { $0 == refs.first }.count) == 1 + } + } } } @@ -589,6 +625,7 @@ class SourceGeneratorTests: XCTestCase { - file.xcassets - file.metal - file.mlmodel + - file.mlmodelc - Info.plist - Intent.intentdefinition - Configuration.storekit @@ -647,6 +684,7 @@ class SourceGeneratorTests: XCTestCase { try pbxProj.expectFile(paths: ["C", "Info.plist"], buildPhase: BuildPhaseSpec.none) try pbxProj.expectFile(paths: ["C", "file.metal"], buildPhase: .sources) try pbxProj.expectFile(paths: ["C", "file.mlmodel"], buildPhase: .sources) + try pbxProj.expectFile(paths: ["C", "file.mlmodelc"], buildPhase: .resources) try pbxProj.expectFile(paths: ["C", "Intent.intentdefinition"], buildPhase: .sources) try pbxProj.expectFile(paths: ["C", "Configuration.storekit"], buildPhase: .resources) try pbxProj.expectFile(paths: ["C", "Settings.bundle"], buildPhase: .resources)