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)