diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 990a3b176..84679494b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,31 +4,33 @@ on: pull_request: {} jobs: run: - runs-on: macOS-latest + runs-on: macos-15 name: Xcode ${{ matrix.xcode }} strategy: matrix: - xcode: ["11"] + xcode: ["16.4", "26.2"] + env: + DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer steps: - - uses: actions/checkout@master - - name: Set Xcode - run: | - echo "Available Xcode versions:" - ls /Applications | grep Xcode - echo "Choosing Xcode_${{ matrix.xcode }}.app" - sudo xcode-select -s /Applications/Xcode_${{ matrix.xcode }}.app - xcodebuild -version - swift --version - swift package --version - - name: Resolve - run: swift package resolve - - name: Build - run: swift build - - name: Test - run: set -o pipefail && swift test 2>&1 | xcpretty - - name: Gen fixtures - run: scripts/gen-fixtures.sh - - name: Check fixtures - run: scripts/diff-fixtures.sh - - name: Build fixtures - run: scripts/build-fixtures.sh + - uses: actions/checkout@master + - name: Resolve + run: swift package resolve + - name: Build + run: swift build + - name: Test + run: set -o pipefail && swift test 2>&1 | xcpretty + - name: Gen fixtures + run: scripts/gen-fixtures.sh + - name: Check fixtures + run: scripts/diff-fixtures.sh + - name: Build fixtures + env: + GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: scripts/build-fixtures.sh + run-linux: + runs-on: ubuntu-latest + name: Linux + steps: + - uses: actions/checkout@master + - name: Build and run tests + run: swift test --enable-test-discovery diff --git a/.gitignore b/.gitignore index caf10c284..cb21d3e8f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ xcuserdata *.xcuserstate XcodeGen.xcodeproj xcodegen.zip +xcodegen.artifactbundle.zip +.vscode/launch.json +DerivedData diff --git a/CHANGELOG.md b/CHANGELOG.md index 14a06745d..bc18bf44d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,852 +2,1338 @@ ## Next Version +## 2.44.1 + +### Fixed +- Set the correct object version of 77 for Xcode 16 projects @jakobfelsatdm #1563 +- Support major.minor SPM package versions which would otherwise fail to decode to a string in yaml specs #1546 @RomanPodymov +- Fix regression for `parallelizable` in scheme. It now resolves to "Enabled" and not "Swift Testing Only" #1565 @CraigSiemens + +## 2.44.0 + +### Added +- Basic support for Xcode 16's synchronized folders #1541 @yonaskolb + - `TargetSource.type` can now be `syncedFolder` + - `Options.defaultSourceDirectoryType` can be set to `syncedFolder` for the default type in all sources in the project (defaults to `group`) + - Benefits include faster generation and no cache invalidation or need to regenerate when files are added or removed from these folders + - Note that not all TargetSource options like excludes are supported, just a simple path. Please test and see what is missing in your projects +- Added sanitizer options to run and test actions in Scheme #1550 @hi-kumar + +### Fixed +- Added validation to ensure that all values in `settings.configs` are mappings. Previously, passing non-mapping values did not raise an error, making it difficult to detect misconfigurations. Now, `SpecParsingError.invalidConfigsMappingFormat` is thrown if misused. #1547 @Ryu0118 +- Use `USER` instead of `LOGNAME` for XCUserData #1559 @KostyaSha + +## 2.43.0 + +### Added + +- Added `excludeFromProject` from local packages #1512 @maximkrouk +- Added support for `preferredScreenCaptureFormat` in schemes #1450 @vakhidbetrakhmadov + +### Changes + +- `.appex` files are now copied to plugins directory by default #1531 @iljaiwas +- The `preGenCommand` is now run before validation and caching #1500 #1519 @simonbs @dalemyers +- Improve performance of spec validation #1522 @zewuchen +- The `enableGPUValidationMode` enum is deprecated and is now a boolean #1515 @marcosgriselli @yonaskolb + +### Fixed + +- **Breaking**: `fileGroups` are now relative paths when in included files, like other paths #1534 @shnhrrsn +- **Breaking**: Local package paths are now relative paths when in included files, like other paths #1498 @juri +- Optional groups are no longer skipped when missing and generating projects from a different directory #1529 @SSheldon + +### Internal + +- Fix Swift 6.0 warnings #1513 @marcosgriselli +- Update package swift tools to 5.9 #1489 @0111b +- Add Xcode 16 to CI #1439 @giginet +- Fix test project building on CI #1537 @yonaskolb +- Skip failing tests on Linux #1517 @marcosgriselli +- XcodeProj updated to 8.24.3 #1515 @marcosgriselli @yonaskolb + +## 2.42.0 + +### Added + +- Better support for local Swift packages in Xcode 15 #1465 @kinnarr +- Added `macroExpansion` to test actions in schemes #1468 @erneestoc + +### Changed + +- Better default macroExpansion target in schemes #1471 @erneestoc + +### Removed + +- Removed `xcodegen dump --type graphviz` as graphviz no longer builds in Swift 6 and is no longer maintained. If anyone uses this feature and wishes to keep it, please submit a PR providing a suitable alternative. #1485 @giginet + +## 2.41.0 + +### Added + +- Added `xcodegen cache` command that writes the cache. Useful for `post-commit` git hook integration #1476 @yonaskolb + +### Changed + +- Include folders in file sorting #1466 @jflan-dd + +### Fixed + +- Fixed `supportedDestinations` validation when it contains watchOS for multiplatform apps. #1470 @tatsuky + +## 2.40.1 + +### Fixed + +- Reverted `.xcprivacy` handling. They will now again be treated as resources by default @yonaskolb + +## 2.40.0 + +### Added + +- Added support for local Swift packages at the project root by specifying a "" group #1413 @hiltonc +- Added a custom `shell` to a scheme's pre and post actions #1430 @balazs-vimn + +### Changed + +- `.xcprivacy` files are now not added to any build phases by default #1464 @yonaskolb + +## 2.39.1 + +### Added + +- Proper defaults for `.cp` and `.cxx` files #1447 @eschwieb + +### Fixed + +- Fixed bundle access crash #1448 @freddi-kit +- Pinned XcodeProj version to fix breaking changes when XcodeGen is used as a dependency #1449 @yonaskolb + +## 2.39.0 + +### Added + +- Support Artifact Bundle #1388 @freddi-kit +- Added support for `.xcstrings` String Catalogs #1421 @nicolasbosi95 +- Added default `LD_RUNPATH_SEARCH_PATHS` for visionOS #1444 @Dahlgren +- Added `watchOS` as a supported cross platform destination #1438 @tatsuky + +### Fixed + +- Fixed custom local package groups not being created #1416 @JaapManenschijn +- Fixed spec validation error type #1439 @Lutzifer +- Create parent group for local package groups if it does not exist already #1417 @JaapManenschijn + +### Internal + +- Updated Rainbow version #1424 @nysander + +## 2.38.0 + +### Added + +- [Multi-destination targets](https://github.com/yonaskolb/XcodeGen/blob/master/Docs/ProjectSpec.md#supported-destinations) #1336 @amatig + - Added `supportedDestinations` to target + - Added optional new `platform` value of `auto` when using `supportedDestinations` + - Added `destinationFilters` for sources and dependencies + - Added `inferDestinationFiltersByPath`, a convenience filter for sources +- `.mlpackage` files now default to being a source type #1398 @aaron-foreflight +- Added support for `Build Tool Plug-ins` in `AggregateTarget` #1390 @BarredEwe + +### Fixed + +- Fixed source file `includes` not working when no paths were found #1337 @shnhrrsn +- Supports specifying multiple package products #1395 @simonbs + +## 2.37.0 + +### Added + +- Added support for adding `Build Tool Plug-ins` to targets #1374 @BarredEwe + +## 2.36.1 + +### Fixed + +- Revert addition of `ENABLE_MODULE_VERIFIER` build setting for causing issues in tests and some setups #1387 @yonaskolb + +## 2.36.0 + +### Added + +- Added `scheme.enableGPUValidationMode` #1294 @LouisLWang +- Added visionOS support #1379 @shiba1014 +- Added ability to disable Thread performance checker in Schemes #1380 @piellarda +- Added support for `RuntimeIssue` breakpoints #1384 @yonaskolb + +### Changed + +- The project object version has been updated for Xcode 14.3 #1368 @leonardorock +- Updated recommended settings for Xcode 14.3 #1385 @yonaskolb +- Dropped support for Xcode 12 and 13, due to XcodeProj update #1384 @yonaskolb + +### Fixed + +- Fix external dependencies from being removed by Xcode #1354 @OdNairy +- Stop creating orphaned object references when reusing references to external dependencies #1377 @liamnichols + +## 2.35.0 + +### Added + +- Added support for shared breakpoints #177 @alexruperez @myihsan +- Added support for `putResourcesBeforeSourcesBuildPhase` in a target #1351 @mat1th + +### Fixed + +- Fix case where source paths may not be deduplicated correctly resulting in duplicate groups and/or a crash in running Xcodegen #1341 @dalemyers + +## 2.34.0 + +### Changed + +- Added support for `swiftcrossimport` folders. #1317 @Iron-Ham +- Added support for [Scheme Management](Docs/ProjectSpec.md##scheme-management) #1142 @wendyliga, @teameh + +### Fixed + +- Fix includes when the projectRoot is a relative path #1262 @CraigSiemens +- Renamed build phase `Embed App Extensions` to `Embed Foundation Extensions` to fix Xcode 14 warning #1310 @casperriboe + +## 2.33.0 + +### 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 + +### Internal +- Updated to Yams 5.0.1 #1297 @s2mr +- Delete ignored `try` keyword #1298 @s2mr + +## 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 + +#### Added + +- Schemes and Target Schemes can now reference existing Test Plans under `{scheme}.test.testPlans` and `{target}.scheme.testPlans`, respectively. #716 @yonaskolb @omares + +#### Fixed + +- Fixed an issue where DocC was not added to source file list #1202 @hiragram + +#### Changed + +- Updated XcodeProj to 8.7.1 #1213 @yonaskolb + +## 2.28.0 + +#### Added + +- Support for specifying custom group locations for SPM packages. #1173 @John-Connolly + +### Fixed + +- Fix Monterey macOS shell version, shell login flag for environments #1167 @bimawa +- Fixed crash caused by a simultaneous write during a glob processing #1177 @tr1ckyf0x + +### Changed + +- Run target source pattern matching in parallel #1197 @alvarhansen + +## 2.27.0 + +#### Added + +- Support test target for local Swift Package #1074 @freddi-kit +- Added `coverageTargets` for target test schemes. This enables to gather code coverage for specific targets. #1189 @gabriellanata +- Fixed issue where .gyb files could not be added to source file list #1191 @hakkurishian + +### Fixed + +- Fixed crash caused by a simultaneous write during a glob processing #1177 @tr1ckyf0x +- Skip generating empty compile sources build phases for watch apps #1185 @evandcoleman + +## 2.26.0 + +### Added + +- Added the option to specify a `location` in a test target #1150 @KrisRJack + +### Changed + +- 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 + +- Fix broken codesign option for bundle dependency #1104 @kateinoigakukun +- Ensure fileTypes are mapped to JSON value #1112 @namolnad +- Fix platform filter for package dependecies #1123 @raptorxcz +- Fix Xcode 13 build #1130 @raptorxcz @mthole + +### Changed + +- Update XcodeProj to 8.2.0 #1125 @nnsnodnb + +## 2.24.0 + +### Added + +- Added support for DocC Catalogs #1091 @brevansio +- Added support for "driver-extension" and "system-extension" product types #1092 @vgorloff +- Add support for conditionally linking dependencies for specific platforms #1087 @daltonclaybrook +- 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 explicit `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 +- Added `askForAppToLaunch` for `profile` in `schemes` #1035 @freddi-kit +- 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 -- Add `onlyCopyFilesOnInstall` option to targets for the Embed Files build phase. [#912](https://github.com/yonaskolb/XcodeGen/pull/912) @jsorge + +- 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 +- Added more detailed error message with method arguments. #990 @bannzai +- Added `basedOnDependencyAnalysis` to Project Spec Build Script to be able to choose not to skip the script. #992 @myihsan +- Added `BuildRule.runOncePerArchitecture` to allow running build rules once per architecture. #950 @sascha +- 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 -- Treat all directories with known UTI as file wrapper. [#896](https://github.com/yonaskolb/XcodeGen/pull/896) @KhaosT -- Generated chemes for application extensions now contain `wasCreatedForAppExtension = YES`. [#898](https://github.com/yonaskolb/XcodeGen/issues/898) @muizidn + +- 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 +- Application extension schemes now default to `launchAutomaticallySubstyle = 2` and the correct debugger and launcher identifiers #932 @brentleyjones +- Updated SettingsPresets to use new defaults from Xcode 12. #953 @liamnichols +- Enable Base Internationalization by default as per Xcode 12 behavior. #954 @liamnichols + +#### Changed + +- Change default project version to Xcode 12 #960 @yonaskolb #### Internal -- Updated to XcodeProj 7.13.0 [#908](https://github.com/yonaskolb/XcodeGen/pull/908) @brentleyjones + +- 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 +- Fix appex's Runpath Search Paths under macOS target. #952 @rinsuki +- `onlyCopyFilesOnInstall` is extended for the Embed App Extensions build phase. #948 @RomanPodymov + +## 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](https://github.com/yonaskolb/XcodeGen/pull/803) @michaeleisel -- Improve support for iOS sticker packs and add support for `launchAutomaticallySubstyle` to run schemes. [#824](https://github.com/yonaskolb/XcodeGen/pull/824) @scelis -- Add --project-root option to generate command. [#828](https://github.com/yonaskolb/XcodeGen/pull/828) @ileitch -- Add an ability to set an order of groups with `options.groupOrdering` [#613](https://github.com/yonaskolb/XcodeGen/pull/613) @Beniamiiin -- Add the ability to output a dependency graph in graphviz format [#852](https://github.com/yonaskolb/XcodeGen/pull/852) @jeffctown -- Adds uncluttering the project manifest dumped to YAML from empty values [#858](https://github.com/yonaskolb/XcodeGen/pull/858) @paciej00 -- Added ability to name the executable target when declaring schemes. [#869](https://github.com/yonaskolb/XcodeGen/pull/869) @elland -- Added ability to set executable to Ask to Launch. [#871](https://github.com/yonaskolb/XcodeGen/pull/871) @pinda - -#### Fixed -- Fixed issue when linking and embeding static frameworks: they should be linked and NOT embed. [#820](https://github.com/yonaskolb/XcodeGen/pull/820) @acecilia -- Fixed issue when generating projects for paths with a dot in the folder for swift sources. [#826](https://github.com/yonaskolb/XcodeGen/pull/826) @asifmohd -- Prefix static library target filenames with 'lib' to match Xcode. [#831](https://github.com/yonaskolb/XcodeGen/pull/831), [#842](https://github.com/yonaskolb/XcodeGen/pull/842) @ileitch -- Fixed duplicate addition of carthage static frameworks. [#829](https://github.com/yonaskolb/XcodeGen/pull/829) @funzin -- Fix handling of SWIFT_INSTALL_OBJC_HEADER when its value is YES/NO. [#827](https://github.com/yonaskolb/XcodeGen/pull/827) @ileitch -- Set `preActions` and `postActions` on the `build` action of a TargetScheme instead of the other actions. [#823](https://github.com/yonaskolb/XcodeGen/pull/823) @brentleyjones -- Prevent test targets from being set as a scheme's launch action [#835](https://github.com/yonaskolb/XcodeGen/pull/835) @brentleyjones -- Implicitly include bundles in the Copy Bundle Resources build phase. [#838](https://github.com/yonaskolb/XcodeGen/pull/838) @skirchmeier -- Fixed dumping a project manifest which contains an array of project references [#840](https://github.com/yonaskolb/XcodeGen/pull/840) @paciej00 -- Generate correct PBXTargetDependency for external targets. [#843](https://github.com/yonaskolb/XcodeGen/pull/843) @ileitch -- Fix linking of multiple products from the same Swift Package [#830](https://github.com/yonaskolb/XcodeGen/pull/830) @toshi0383 -- Don't deduplicate files in `include` with different path but same name. [#849](https://github.com/yonaskolb/XcodeGen/pull/849) @akkyie -- Don't link transitive static carthage libraries. [#853](https://github.com/yonaskolb/XcodeGen/pull/853) @akkyie -- Optimize simplifying paths for faster project generation. [#857](https://github.com/yonaskolb/XcodeGen/pull/857) @akkyie -- Fixed issue where wrapper folders may not include correctly in the generated project. [#862](https://github.com/yonaskolb/XcodeGen/pull/862) @KhaosT -- Compile `xcmappingmodel` files instead of copying bundle resources. [#834](https://github.com/yonaskolb/XcodeGen/pull/834) @jcolicchio -- Fixed issue where `Complie Sources` build phase is generated for resource bundles even when they have no files to compile [#878](https://github.com/yonaskolb/XcodeGen/pull/878) @nkukushkin - -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.15.1...2.16.0) + +- 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 +- Add an ability to set an order of groups with `options.groupOrdering` #613 @Beniamiiin +- Add the ability to output a dependency graph in graphviz format #852 @jeffctown +- Adds uncluttering the project manifest dumped to YAML from empty values #858 @paciej00 +- Added ability to name the executable target when declaring schemes. #869 @elland +- Added ability to set executable to Ask to Launch. #871 @pinda + +#### Fixed + +- Fixed issue when linking and embedding 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 +- Fixed duplicate addition of carthage static frameworks. #829 @funzin +- Fix handling of SWIFT_INSTALL_OBJC_HEADER when its value is YES/NO. #827 @ileitch +- Set `preActions` and `postActions` on the `build` action of a TargetScheme instead of the other actions. #823 @brentleyjones +- Prevent test targets from being set as a scheme's launch action #835 @brentleyjones +- Implicitly include bundles in the Copy Bundle Resources build phase. #838 @skirchmeier +- Fixed dumping a project manifest which contains an array of project references #840 @paciej00 +- Generate correct PBXTargetDependency for external targets. #843 @ileitch +- Fix linking of multiple products from the same Swift Package #830 @toshi0383 +- Don't deduplicate files in `include` with different path but same name. #849 @akkyie +- Don't link transitive static carthage libraries. #853 @akkyie +- Optimize simplifying paths for faster project generation. #857 @akkyie +- Fixed issue where wrapper folders may not include correctly in the generated project. #862 @KhaosT +- Compile `xcmappingmodel` files instead of copying bundle resources. #834 @jcolicchio +- Fixed issue where `Complie Sources` build phase is generated for resource bundles even when they have no files to compile #878 @nkukushkin ## 2.15.1 #### Fixed -- Fixed issue which caused watch app schemes to be generated incorrectly, preventing these apps from launching. [#798](https://github.com/yonaskolb/XcodeGen/pull/798) @daltonclaybrook -- Added build presets for the target type `framework.static`. [#819](https://github.com/yonaskolb/XcodeGen/pull/819) @acecilia -- Fixed XcodeProj resolution and updated to 7.10.0 [#822](https://github.com/yonaskolb/XcodeGen/pull/822) @soffes -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.15.0...2.15.1) +- 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 ## 2.15.0 #### Added -- Add support for local Swift Packages in `packages` using `path`. [#808](https://github.com/yonaskolb/XcodeGen/pull/808) @freddi-kit -- Add `buildImplicitDependencies` as an option on `TargetScheme`. [#810](https://github.com/yonaskolb/XcodeGen/pull/810) @evandcoleman + +- 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](https://github.com/yonaskolb/XcodeGen/pull/796) @freddi-kit -- Added ability to stop on every main thread checker issue on Run schemes and TargetSchemes [#799](https://github.com/yonaskolb/XcodeGen/pull/799) @ionutivan -- Avoid copying ObjC interface header when SWIFT_INSTALL_OBJC_HEADER=false. [#805](https://github.com/yonaskolb/XcodeGen/pull/805) @kateinoigakukun -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.14.0...2.15.0) +- 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 ## 2.14.0 #### Added -- Add ability to embed and code sign Swift package dependencies with dynamic products. [#788](https://github.com/yonaskolb/XcodeGen/pull/788) @alexruperez + +- 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](https://github.com/yonaskolb/XcodeGen/pull/792) @bryansum -- Set `defaultConfigurationName` for every target which is defined in a project. [#787](https://github.com/yonaskolb/XcodeGen/pull/787) @ken0nek -- Set `TEST_TARGET_NAME` only when a project has UITest bundle. [#792](https://github.com/yonaskolb/XcodeGen/pull/792) @ken0nek -- Set xcodeproj path in project.xcworkspace/contents.xcworkspacedata [#793](https://github.com/yonaskolb/XcodeGen/pull/793) @ken0nek -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.13.1...2.14.0) +- 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 +- Set xcodeproj path in project.xcworkspace/contents.xcworkspacedata #793 @ken0nek ## 2.13.1 #### Fixed -- Validate scheme test action and test coverage target references before generating. [#775](https://github.com/yonaskolb/XcodeGen/pull/775) @liamnichols -- Fixed parsing prerelease identifiers in Swift package versions [#779](https://github.com/yonaskolb/XcodeGen/pull/779) @yonaskolb -- Fixed using legacy targets as dependencies [#778](https://github.com/yonaskolb/XcodeGen/pull/778) @yonaskolb + +- 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](https://github.com/yonaskolb/XcodeGen/pull/777) @yonaskolb -- Use https://github.com/mxcl/Version [#779](https://github.com/yonaskolb/XcodeGen/pull/779) @yonaskolb -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.13.0...2.13.1) +- Updated to XcodeProj 7.8.0 #777 @yonaskolb +- Use #779 @yonaskolb ## 2.13.0 #### Added -- Support External Target References via subprojects. [#701](https://github.com/yonaskolb/XcodeGen/pull/701) @evandcoleman + +- Support External Target References via subprojects. #701 @evandcoleman #### Fixed -- Fixed compilation as library by locking down XcodeProj version [#767](https://github.com/yonaskolb/XcodeGen/pull/767) @yonaskolb -- Stabilized sorting of groups with duplicate names/paths. [#671](https://github.com/yonaskolb/XcodeGen/pull/671) @ChristopherRogers -- Moved `Copy Bundle Resources` to after `Link with Libraries` build phase [#768](https://github.com/yonaskolb/XcodeGen/pull/768) @yonaskolb + +- 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](https://github.com/yonaskolb/XcodeGen/pull/767) @yonaskolb -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.12.0...2.13.0) +- 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](https://github.com/yonaskolb/XcodeGen/pull/759) @yonaskolb -- Support for language and region settings on a target basis [#728](https://github.com/yonaskolb/XcodeGen/pull/728) @FranzBusch -- Added option to generate only Info.plist files with `--only-plists` [#739](https://github.com/yonaskolb/XcodeGen/pull/739) @namolnad -- Added the option to specify a `simulateLocation` in a scheme [#722](https://github.com/yonaskolb/XcodeGen/issues/722) @basvankuijck -- Support for On Demand Resources tags [#753](https://github.com/yonaskolb/XcodeGen/pull/753) @sipao + +- 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 +- Added the option to specify a `simulateLocation` in a scheme #722 @basvankuijck +- Support for On Demand Resources tags #753 @sipao #### Fixed -- Fixed resolving a relative path for `projectReference.path` [#740](https://github.com/yonaskolb/XcodeGen/pull/740) @kateinoigakukun -- Don't add framework dependency's directory to `FRAMEWORK_SEARCH_PATHS` if it is implicit [#744](https://github.com/yonaskolb/XcodeGen/pull/744) @ikesyo @yutailang0119 -- Fixed resolving relative path passed to `XcodeProj` [#751](https://github.com/yonaskolb/XcodeGen/pull/751) @PycKamil -- Prefer configurations named "Debug" or "Release" for default scheme build configurations [#752](https://github.com/yonaskolb/XcodeGen/pull/752) @john-flanagan -- Added an extra check for package versions. [#755](https://github.com/yonaskolb/XcodeGen/pull/755) @basvankuijck + +- 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 +- Prefer configurations named "Debug" or "Release" for default scheme build configurations #752 @john-flanagan +- Added an extra check for package versions. #755 @basvankuijck #### Internal -- Update to SwiftCLI 6.0 and use the new property wrappers [#749](https://github.com/yonaskolb/XcodeGen/pull/749) @yonaskolb -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.11.0...2.12.0) +- Update to SwiftCLI 6.0 and use the new property wrappers #749 @yonaskolb ## 2.11.0 #### Added -- Add Carthage static framework dependencies support. [#688](https://github.com/yonaskolb/XcodeGen/pull/688) @giginet -- Added `xcodegen dump` command [#710](https://github.com/yonaskolb/XcodeGen/pull/710) @yonaskolb -- Added `--no-env` option to disable environment variables expansion [#704](https://github.com/yonaskolb/XcodeGen/pull/704) @rcari -- Added custom group support for target sources [#621](https://github.com/yonaskolb/XcodeGen/pull/621) @sroebert @rcari -- Added new dependency type, `bundle`. This allows targets to copy bundles from other projects [#616](https://github.com/yonaskolb/XcodeGen/pull/616) @bsmith11 + +- 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 +- Added custom group support for target sources #621 @sroebert @rcari +- Added new dependency type, `bundle`. This allows targets to copy bundles from other projects #616 @bsmith11 #### Fixed -- Improved variable expansion runtime [#704](https://github.com/yonaskolb/XcodeGen/pull/704) @rcari -- Fixed missing headers for static framework targets [#705](https://github.com/yonaskolb/XcodeGen/pull/705) @wag-miles -- Using more file types from XcodeProj for PBXFileReferences resulting in less project diffs [#715](https://github.com/yonaskolb/XcodeGen/pull/715) @yonaskolb -- Fixed localized `*.intentdefinition` not being added to build source phases [#720](https://github.com/yonaskolb/XcodeGen/pull/720) @giginet -- Fixed `selectedLauncherIdentifier` not being set `Xcode.IDEFoundation.Launcher.PosixSpawn` when `debugEnabled: false` is defined in test action [#725](https://github.com/yonaskolb/XcodeGen/pull/725) @ken0nek -- Fixed unnecessary dependencies related to SwiftPM [#726](https://github.com/yonaskolb/XcodeGen/pull/726) @tid-kijyun + +- 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 +- Fixed localized `*.intentdefinition` not being added to build source phases #720 @giginet +- Fixed `selectedLauncherIdentifier` not being set `Xcode.IDEFoundation.Launcher.PosixSpawn` when `debugEnabled: false` is defined in test action #725 @ken0nek +- Fixed unnecessary dependencies related to SwiftPM #726 @tid-kijyun #### Changed -- Deprecated `$old_form` variables in favor of `${new_form}` variables [#704](https://github.com/yonaskolb/XcodeGen/pull/704) @rcari -- Updated XcodeProj to 7.4.0 [#709](https://github.com/yonaskolb/XcodeGen/pull/709) [#715](https://github.com/yonaskolb/XcodeGen/pull/715) @yonaskolb -- Updated to Swift 5.1 [#714](https://github.com/yonaskolb/XcodeGen/pull/714) @yonaskolb -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.10.1...2.11.0) +- 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 ## 2.10.1 #### Fixed -- Add Base to knownRegions even if one doesn't exist [#694](https://github.com/yonaskolb/XcodeGen/pull/694) @bryansum -- Fixed missing `onlyGenerateCoverageForSpecifiedTargets` issue [#700](https://github.com/yonaskolb/XcodeGen/pull/700) @kateinoigakukun -- Fixed regression on dependencies `link` flag [#703](https://github.com/yonaskolb/XcodeGen/pull/703) @rcari -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.10.0...2.10.1) +- 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 ## 2.10.0 #### Added -- Support Target Reference to another project. [#655](https://github.com/yonaskolb/XcodeGen/pull/655) @kateinoigakukun -- Added `coverageTargets` for test target. This enables to gather code coverage for specific targets. [#656](https://github.com/yonaskolb/XcodeGen/pull/656) @kateinoigakukun + +- 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](https://github.com/yonaskolb/XcodeGen/pull/685) @yonaskolb -- Don't generate CFBundleExecutable in default generated Info.plist for `bundle` target types [#689](https://github.com/yonaskolb/XcodeGen/pull/689) @FranzBusch -- Fixed resolving relative paths with custom project destination [#681](https://github.com/yonaskolb/XcodeGen/pull/681) @giginet -- Fixed resolving relative paths for Info.plist [#683](https://github.com/yonaskolb/XcodeGen/pull/683) @giginet -- Fixed macOS unit test target TEST_HOST [#696](https://github.com/yonaskolb/XcodeGen/pull/696) @mjarvis + +- 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 +- Fixed resolving relative paths for Info.plist #683 @giginet +- Fixed macOS unit test target TEST_HOST #696 @mjarvis #### Internal -- Restructure targets [#698](https://github.com/yonaskolb/XcodeGen/pull/698) @yonaskolb -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.9.0...2.10.0) +- Restructure targets #698 @yonaskolb ## 2.9.0 #### Added -- Added Scheme Templates [#672](https://github.com/yonaskolb/XcodeGen/pull/672) @bclymer + +- Added Scheme Templates #672 @bclymer #### Fixed -- Fixed macOS unit test setting preset [#665](https://github.com/yonaskolb/XcodeGen/pull/665) @yonaskolb -- Add `rcproject` files to sources build phase instead of resources [#669](https://github.com/yonaskolb/XcodeGen/pull/669) @Qusic -- Prefer default configuration names for generated schemes [#673](https://github.com/yonaskolb/XcodeGen/pull/673) @giginet -- Fixed some resource files being placed to "Recovered References" group [#679](https://github.com/yonaskolb/XcodeGen/pull/679) @nivanchikov + +- 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](https://github.com/yonaskolb/XcodeGen/pull/667) @giginet -- Fixed tests in case-sensitive file system [#670](https://github.com/yonaskolb/XcodeGen/pull/670) @Qusic -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.8.0...2.9.0) +- 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](https://github.com/yonaskolb/XcodeGen/pull/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](https://github.com/yonaskolb/XcodeGen/pull/637) @bclymer -- Support `dylib` SDK. [#650](https://github.com/yonaskolb/XcodeGen/pull/650) @kateinoigakukun -- Added `language` and `region` options for `run` and `test` scheme [#654](https://github.com/yonaskolb/XcodeGen/pull/654) @kateinoigakukun -- Added `debugEnabled` option for `run` and `test` scheme [#657](https://github.com/yonaskolb/XcodeGen/pull/657) @kateinoigakukun + +- 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 +- Added `language` and `region` options for `run` and `test` scheme #654 @kateinoigakukun +- Added `debugEnabled` option for `run` and `test` scheme #657 @kateinoigakukun #### Fixed -- Expand template variable in Array of Any [#651](https://github.com/yonaskolb/XcodeGen/pull/651) @kateinoigakukun -- Significantly improve performance when running with a large number files. [#658](https://github.com/yonaskolb/XcodeGen/pull/658) @kateinoigakukun -- Removed some more diffs between the generated .pbxproj and when Xcode resaves it [#663](https://github.com/yonaskolb/XcodeGen/pull/663) @yonaskolb + +- 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](https://github.com/yonaskolb/XcodeGen/pull/661) @RomanPodymov -- Updated to XcodeProj 7.1.0 [#624](https://github.com/yonaskolb/XcodeGen/pull/624) @yonaskolb -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.7.0...2.8.0) +- 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](https://github.com/yonaskolb/XcodeGen/pull/636) @bclymer -- Added ability to disable main thread checker in Schemes [#601](https://github.com/yonaskolb/XcodeGen/pull/601) @wag-miles + +- 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](https://github.com/yonaskolb/XcodeGen/pull/599) @haritowa -- Fixed `.orig` files being added to the project [#627](https://github.com/yonaskolb/XcodeGen/pull/627) @keith + +- 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](https://github.com/yonaskolb/XcodeGen/pull/635) @kateinoigakukun -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.6.0...2.7.0) +- 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](https://github.com/yonaskolb/XcodeGen/pull/582) @kadarandras -- Added ability to set `attributes` on build files [#583](https://github.com/yonaskolb/XcodeGen/pull/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](https://github.com/yonaskolb/XcodeGen/pull/594) @tomquist -- Added support for `watchapp2-container` and `framework.static` product types [#604](https://github.com/yonaskolb/XcodeGen/pull/604) @yonaskolb + +- 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](https://github.com/yonaskolb/XcodeGen/pull/597) @thii -- Fixed an issue that prevents watchOS Intents Extension from running correctly. [#571](https://github.com/yonaskolb/XcodeGen/pull/571) @KhaosT + +- 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](https://github.com/yonaskolb/XcodeGen/pull/581) @acecilia -- Updated to XcodeProj 7.0.0. Note that the length of generated UUIDs has changed [#604](https://github.com/yonaskolb/XcodeGen/pull/604) @yonaskolb + +- 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](https://github.com/yonaskolb/XcodeGen/pull/545) @ryohey -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.5.0...2.6.0) +- Added ability to encode ProjectSpec #545 @ryohey ## 2.5.0 #### Added -- Added support for `app-extension.intents-service` target type [#536](https://github.com/yonaskolb/XcodeGen/pull/536) @yonaskolb -- Added support for custom `root` in `sdk` dependency [#562](https://github.com/yonaskolb/XcodeGen/pull/562) @raptorxcz + +- 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](https://github.com/yonaskolb/XcodeGen/pull/536) @yonaskolb -- Updated default generated settings for Xcode 10.2 [#555](https://github.com/yonaskolb/XcodeGen/pull/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](https://github.com/yonaskolb/XcodeGen/issues/544) @tomquist + +- 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](https://github.com/yonaskolb/XcodeGen/pull/550) @sroebert -- Fixed `optional` file sources not being added to the project [#557](https://github.com/yonaskolb/XcodeGen/pull/557) @yonaskolb -- Fixed Carthage dependencies being incorrectly embedded in WatchKit app bundles instead of a WatchKit app extension [#558](https://github.com/yonaskolb/XcodeGen/pull/558) @KhaosT -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.4.0...2.5.0) +- 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 installation when building in Swift 5 [#549](https://github.com/yonaskolb/XcodeGen/pull/549) @yonaskolb +#### Fixed + +- Fixed installation when building in Swift 5 #549 @yonaskolb #### Changed -- Updated to Swift 5 and dropped Swift 4.2 [#549](https://github.com/yonaskolb/XcodeGen/pull/549) @yonaskolb -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.3.0...2.4.0) +- 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](https://github.com/yonaskolb/XcodeGen/pull/506) [#543](https://github.com/yonaskolb/XcodeGen/pull/543) @rpassis @yonaskolb -- Added support for nested target templates [#534](https://github.com/yonaskolb/XcodeGen/pull/534) @tomquist -- Added ability to define `templateAttributes` within a target to be able to parameterize templates. [#533](https://github.com/yonaskolb/XcodeGen/pull/533) @tomquist -- Added ability to set `link` to false in framework dependencies [#532](https://github.com/yonaskolb/XcodeGen/pull/532) @dimatosaurus + +- Added ability to automatically find all the frameworks for Carthage dependencies via the global `options.findCarthageFrameworks` or dependency specific `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 +- Added ability to set `link` to false in framework dependencies #532 @dimatosaurus - Added `missingConfigFiles` to `options.disabledValidations` to optionally skip checking for the existence of config files. -- Added ability to define a per-platform `deploymentTarget` for Multi-Platform targets. [#510](https://github.com/yonaskolb/XcodeGen/pull/510) @ainopara +- 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](https://github.com/yonaskolb/XcodeGen/pull/533) @tomquist + +- **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](https://github.com/yonaskolb/XcodeGen/pull/524) -- Fixed error when `optional` directory source is missing [#527](https://github.com/yonaskolb/XcodeGen/pull/527) @yonaskolb -- Fixed excludes within included spec [#535](https://github.com/yonaskolb/XcodeGen/pull/535) @yonaskolb -- Fixed paths in target templates within included files not being relative [#537](https://github.com/yonaskolb/XcodeGen/pull/537) @yonaskolb -- Fix multi-platform target templates [#541](https://github.com/yonaskolb/XcodeGen/pull/541) @yonaskolb -- Fixed sources in an included target not being relative when the sources are mix of string and dictionaries [#542](https://github.com/yonaskolb/XcodeGen/pull/542) @yonaskolb -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.2.0...2.3.0) +- 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 +- Fixed paths in target templates within included files not being relative #537 @yonaskolb +- Fix multi-platform target templates #541 @yonaskolb +- Fixed sources in an included target not being relative when the sources are mix of string and dictionaries #542 @yonaskolb ## 2.2.0 #### Added -- Added ability to generate empty directories via `options.generateEmptyDirectories` [#480](https://github.com/yonaskolb/XcodeGen/pull/480) @Beniamiiin -- Added support for the `instrumentsPackage` product type [#482](https://github.com/yonaskolb/XcodeGen/pull/482) @ksulliva -- Added support for `inputFileLists` and `outputFileLists` within project build scripts [#500](https://github.com/yonaskolb/XcodeGen/pull/500) @lukewakeford -- Added support for a `$target_name` replacement string within target templates [#504](https://github.com/yonaskolb/XcodeGen/pull/504) @yonaskolb -- Added `createIntermediateGroups` to individual Target Sources which overrides the top level option [#505](https://github.com/yonaskolb/XcodeGen/pull/505) @yonaskolb + +- 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 +- Added support for a `$target_name` replacement string within target templates #504 @yonaskolb +- 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](https://github.com/yonaskolb/XcodeGen/pull/489) @ellneal -- Updated the Xcode compatibility version from 3.2 to 9.3 [#497](https://github.com/yonaskolb/XcodeGen/pull/497) @yonaskolb -- Exact matches to config names in build settings won't partial apply to other configs [#503](https://github.com/yonaskolb/XcodeGen/pull/503) @yonaskolb + +- **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](https://github.com/yonaskolb/XcodeGen/pull/487) @monowerker -- Fixed Sticker Packs from generating an empty Source file phase which caused in error in the new build system [#492](https://github.com/yonaskolb/XcodeGen/pull/492) @rpassis -- Fixed generated schemes for tool targets not setting the executable [#496](https://github.com/yonaskolb/XcodeGen/pull/496) @yonaskolb -- Fixed resolving Carthage dependencies for iOS app with watchOS target. [465](https://github.com/yonaskolb/XcodeGen/pull/465) @raptorxcz -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.1.0...2.2.0) +- 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 +- Fixed resolving Carthage dependencies for iOS app with watchOS target. [465](https://github.com/yonaskolb/XcodeGen/pull/465) @raptorxcz ## 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](https://github.com/yonaskolb/XcodeGen/pull/412) @yonaskolb + +- 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](https://github.com/yonaskolb/XcodeGen/pull/437) @yonaskolb -- If `INFOPLIST_FILE` has been set on a target, then an `info` path won't ovewrite it [#443](https://github.com/yonaskolb/XcodeGen/pull/443) @feischl97 +- 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](https://github.com/yonaskolb/XcodeGen/pull/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](https://github.com/yonaskolb/XcodeGen/pull/450) @bryansum -- Fixed `--project` argument not working [#437](https://github.com/yonaskolb/XcodeGen/pull/437) @yonaskolb -- Fixed unit tests not hooking up to host applications properly by default. They now generate a `TEST_HOST` and a `TestTargetID` [#452](https://github.com/yonaskolb/XcodeGen/pull/452) @yonaskolb -- Fixed static libraries not including external frameworks in their search paths [#454](https://github.com/yonaskolb/XcodeGen/pull/454) @brentleyjones -- Add `.intentdefinition` files to sources build phase instead of resources [#442](https://github.com/yonaskolb/XcodeGen/pull/442) @yonaskolb -- Add `mlmodel` files to sources build phase instead of resources [#457](https://github.com/yonaskolb/XcodeGen/pull/457) @dwb357 -[Commits](https://github.com/yonaskolb/XcodeGen/compare/2.0.0...2.1.0) +- Fixed XPC Service package type in generated `Info.plist` #435 @alvarhansen +- Fixed phase ordering for modulemap and static library header Copy File phases. [402](https://github.com/yonaskolb/XcodeGen/pull/402) @brentleyjones +- Fixed intermittent errors when running multiple `xcodegen`s concurrently #450 @bryansum +- Fixed `--project` argument not working #437 @yonaskolb +- Fixed unit tests not hooking up to host applications properly by default. They now generate a `TEST_HOST` and a `TestTargetID` #452 @yonaskolb +- Fixed static libraries not including external frameworks in their search paths #454 @brentleyjones +- Add `.intentdefinition` files to sources build phase instead of resources #442 @yonaskolb +- Add `mlmodel` files to sources build phase instead of resources #457 @dwb357 ## 2.0.0 #### Added -- Added `weak` linking setting for dependencies [#411](https://github.com/yonaskolb/XcodeGen/pull/411) @alvarhansen -- Added `info` to targets for generating an `Info.plist` [#415](https://github.com/yonaskolb/XcodeGen/pull/415) @yonaskolb -- Added `entitlements` to targets for generating an `.entitlement` file [#415](https://github.com/yonaskolb/XcodeGen/pull/415) @yonaskolb -- Added `sdk` dependency type for linking system frameworks and libs [#430](https://github.com/yonaskolb/XcodeGen/pull/430) @yonaskolb -- Added `parallelizable` and `randomExecutionOrder` to `Scheme` test targets in an expanded form [#434](https://github.com/yonaskolb/XcodeGen/pull/434) @yonaskolb -- Validate incorrect config setting definitions [#431](https://github.com/yonaskolb/XcodeGen/pull/431) @yonaskolb -- Automatically set project `SDKROOT` if there is only a single platform within the project [#433](https://github.com/yonaskolb/XcodeGen/pull/433) @yonaskolb + +- 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 +- Added `sdk` dependency type for linking system frameworks and libs #430 @yonaskolb +- Added `parallelizable` and `randomExecutionOrder` to `Scheme` test targets in an expanded form #434 @yonaskolb +- Validate incorrect config setting definitions #431 @yonaskolb +- Automatically set project `SDKROOT` if there is only a single platform within the project #433 @yonaskolb #### Changed -- Performance improvements for large projects [#388](https://github.com/yonaskolb/XcodeGen/pull/388) [#417](https://github.com/yonaskolb/XcodeGen/pull/417) [#416](https://github.com/yonaskolb/XcodeGen/pull/416) @yonaskolb @kastiglione -- Upgraded to xcodeproj 6 [#388](https://github.com/yonaskolb/XcodeGen/pull/388) @yonaskolb -- Upgraded to Swift 4.2 [#388](https://github.com/yonaskolb/XcodeGen/pull/388) @yonaskolb -- Remove iOS codesigning sdk restriction in setting preset [#414](https://github.com/yonaskolb/XcodeGen/pull/414) @yonaskolb -- Changed default project version to Xcode 10.0 and default Swift version to 4.2 [#423](https://github.com/yonaskolb/XcodeGen/pull/423) @yonaskolb -- Added ability to not link Carthage frameworks [#432](https://github.com/yonaskolb/XcodeGen/pull/432) @yonaskolb + +- Performance improvements for large projects #388 @yonaskolb @kastiglione +- Upgraded to xcodeproj 6 #388 @yonaskolb +- Upgraded to Swift 4.2 #388 @yonaskolb +- Remove iOS codesigning sdk restriction in setting preset #414 @yonaskolb +- Changed default project version to Xcode 10.0 and default Swift version to 4.2 #423 @yonaskolb +- Added ability to not link Carthage frameworks #432 @yonaskolb #### Fixed -- Fixed code signing issues [#414](https://github.com/yonaskolb/XcodeGen/pull/414) @yonaskolb -- Fixed `TargetSource.headerVisibility` not being set in initializer [#419](https://github.com/yonaskolb/XcodeGen/pull/419) @jerrymarino -- Fixed crash when using Xcode Legacy targets as dependencies [#427](https://github.com/yonaskolb/XcodeGen/pull/427) @dflems -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.11.2...2.0.0) +- 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 ## 1.11.2 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](https://github.com/yonaskolb/XcodeGen/pull/404) @pepibumur -- Fixed default settings for macOS unit-tests [#387](https://github.com/yonaskolb/XcodeGen/pull/387) @frankdilo -- Fixed Copy Headers phase ordering for Xcode 10 [#401](https://github.com/yonaskolb/XcodeGen/pull/401) @brentleyjones -- Fixed generated schemes on aggregate targets [#394](https://github.com/yonaskolb/XcodeGen/pull/394) @vgorloff + +- 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](https://github.com/yonaskolb/XcodeGen/pull/390) @Saik0s -- Update `PathKit`, `Spectre`, `Yams` and `xcodeproj` dependencies -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.11.1...1.11.2) +- 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](https://github.com/yonaskolb/XcodeGen/pull/382) @brentleyjones -- Fixed aggregate targets not being found with `transitivelyLinkDependencies` [#383](https://github.com/yonaskolb/XcodeGen/pull/383) @brentleyjones -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.11.0...1.11.1) +- 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](https://github.com/yonaskolb/XcodeGen/pull/351) @keith -- Added `requiresObjCLinking` to `target` [#354](https://github.com/yonaskolb/XcodeGen/pull/354) @brentleyjones -- Added `targetTemplates` [#355](https://github.com/yonaskolb/XcodeGen/pull/355) @yonaskolb -- Added `aggregateTargets` [#353](https://github.com/yonaskolb/XcodeGen/pull/353) [#381](https://github.com/yonaskolb/XcodeGen/pull/381) @yonaskolb -- Added `options.groupSortPosition` [#356](https://github.com/yonaskolb/XcodeGen/pull/356) @yonaskolb -- Added ability to specify `copyFiles` build phase for sources [#345](https://github.com/yonaskolb/XcodeGen/pull/345) @brentleyjones -- Added ability to specify a `minimumXcodeGenVersion` [#349](https://github.com/yonaskolb/XcodeGen/pull/349) @brentleyjones -- Added `customArchiveName` and `revealArchiveInOrganizer` to `archive` [#367](https://github.com/yonaskolb/XcodeGen/pull/367) @sxua - -#### Fixed -- Sort files using localizedStandardCompare [#341](https://github.com/yonaskolb/XcodeGen/pull/341) @rohitpal440 -- Use the latest `xcdatamodel` when sorted by version [#341](https://github.com/yonaskolb/XcodeGen/pull/341) @rohitpal440 -- Fixed compiler flags being set on non source files in mixed build phase target sources [#347](https://github.com/yonaskolb/XcodeGen/pull/347) @brentleyjones -- Fixed `options.xcodeVersion` not being parsed [#348](https://github.com/yonaskolb/XcodeGen/pull/348) @brentleyjones -- Fixed non-application targets using `carthage copy-frameworks` [#361](https://github.com/yonaskolb/XcodeGen/pull/361) @brentleyjones -- Set `xcdatamodel` based on `xccurrentversion` if available [#364](https://github.com/yonaskolb/XcodeGen/pull/364) @rpassis -- XPC Services are now correctly copied [#368](https://github.com/yonaskolb/XcodeGen/pull/368) @brentley -- Fixed `.metal` files being added to resources [#380](https://github.com/yonaskolb/XcodeGen/pull/380) @vgorloff - -#### Changed -- Improved linking for `static.library` targets [#352](https://github.com/yonaskolb/XcodeGen/pull/352) @brentleyjones -- Changed default group sorting to be after files [#356](https://github.com/yonaskolb/XcodeGen/pull/356) @yonaskolb -- Moved `Frameworks` and `Products` top level groups to bottom [#356](https://github.com/yonaskolb/XcodeGen/pull/356) @yonaskolb -- `modulemap` files are automatically copied to the products directory for static library targets [#346](https://github.com/yonaskolb/XcodeGen/pull/346) @brentleyjones -- Public header files are automatically copied to the products directory for static library targets [#365](https://github.com/yonaskolb/XcodeGen/pull/365) @brentleyjones -- Swift Objective-C Interface Header files are automatically copied to the products directory for static library targets [#366](https://github.com/yonaskolb/XcodeGen/pull/366) @brentleyjones -- `FRAMEWORK_SEARCH_PATHS` are adjusted for `framework` dependencies [#373](https://github.com/yonaskolb/XcodeGen/pull/373) @brentley -- `library.static` targets have `SKIP_INSTALL` set to `YES` [#358](https://github.com/yonaskolb/XcodeGen/pull/358) @brentley -- Copy files phases have descriptive names [#360](https://github.com/yonaskolb/XcodeGen/pull/360) @brentley + +- Added `showEnvVars` to build scripts to disable printing the environment #351 @keith +- Added `requiresObjCLinking` to `target` #354 @brentleyjones +- Added `targetTemplates` #355 @yonaskolb +- Added `aggregateTargets` #353 @yonaskolb +- Added `options.groupSortPosition` #356 @yonaskolb +- Added ability to specify `copyFiles` build phase for sources #345 @brentleyjones +- Added ability to specify a `minimumXcodeGenVersion` #349 @brentleyjones +- 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 +- Fixed `options.xcodeVersion` not being parsed #348 @brentleyjones +- Fixed non-application targets using `carthage copy-frameworks` #361 @brentleyjones +- Set `xcdatamodel` based on `xccurrentversion` if available #364 @rpassis +- XPC Services are now correctly copied #368 @brentley +- 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 +- `modulemap` files are automatically copied to the products directory for static library targets #346 @brentleyjones +- Public header files are automatically copied to the products directory for static library targets #365 @brentleyjones +- Swift Objective-C Interface Header files are automatically copied to the products directory for static library targets #366 @brentleyjones +- `FRAMEWORK_SEARCH_PATHS` are adjusted for `framework` dependencies #373 @brentley +- `library.static` targets have `SKIP_INSTALL` set to `YES` #358 @brentley +- Copy files phases have descriptive names #360 @brentley #### Internal + - Moved brew formula to homebrew core - Added `CONTRIBUTING.md` -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.10.3...1.11.0) - ## 1.10.3 #### Fixed -- Fixed Mint installations finding `SettingPresets` [#338](https://github.com/yonaskolb/XcodeGen/pull/338) @yonaskolb -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.10.2...1.10.3) +- Fixed Mint installations finding `SettingPresets` #338 @yonaskolb ## 1.10.2 #### Changed -- Set `transitivelyLinkDependencies` to false by default -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.10.1...1.10.2) +- Set `transitivelyLinkDependencies` to false by default ## 1.10.1 #### Fixed -- Fixed `transitivelyLinkDependencies` typo [#332](https://github.com/yonaskolb/XcodeGen/pull/332) @brentleyjones -- Fixed framework target dependencies not being code signed by default [#332](https://github.com/yonaskolb/XcodeGen/pull/332) @yonaskolb + +- 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](https://github.com/yonaskolb/XcodeGen/pull/332) @yonaskolb -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.10.0...1.10.1) +- Code sign all dependencies by default except target executables #332 @yonaskolb ## 1.10.0 #### Added -- Added build rule support [#306](https://github.com/yonaskolb/XcodeGen/pull/306) @yonaskolb -- Added support for frameworks in sources [#308](https://github.com/yonaskolb/XcodeGen/pull/308) @keith -- Added ability to automatically embed transient dependencies. Controlled with `transitivelyLinkDependencies` [#327](https://github.com/yonaskolb/XcodeGen/pull/327) @brentleyjones + +- 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](https://github.com/yonaskolb/XcodeGen/pull/298) @keith -- By default don't CodeSignOnCopy `target` dependencies. This can still be controlled with `Dependency.codeSign` [#324](https://github.com/yonaskolb/XcodeGen/pull/324) @yonaskolb - -#### Fixed -- Fixed PBXBuildFile and PBXFileReference being incorrectly generated for Legacy targets [#296](https://github.com/yonaskolb/XcodeGen/pull/296) @sascha -- Fixed required sources build phase not being generated if there are no sources [#307](https://github.com/yonaskolb/XcodeGen/pull/307) @yonaskolb -- Fixed install script in binary release [#303](https://github.com/yonaskolb/XcodeGen/pull/303) @alvarhansen -- Removed `ENABLE_TESTABILITY` from framework setting presets [#299](https://github.com/yonaskolb/XcodeGen/pull/299) @allu22 -- Fixed homebrew installation [#297](https://github.com/yonaskolb/XcodeGen/pull/297) @vhbit -- `cc` files are now automatically recognized as source files [#317](https://github.com/yonaskolb/XcodeGen/pull/317) @maicki -- Fixed `commandLineArguments` not parsing when they had dots in them [#323](https://github.com/yonaskolb/XcodeGen/pull/323) @yonaskolb -- Fixed excluding directories that only have sub directories [#326](https://github.com/yonaskolb/XcodeGen/pull/326) @brentleyjones -- Made `PBXContainerItemProxy` ID more deterministic -- Fixed generated framework schemes from being executable [#328](https://github.com/yonaskolb/XcodeGen/pull/328) @brentleyjones +- 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 -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.9.0...1.10.0) +#### 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 +- Removed `ENABLE_TESTABILITY` from framework setting presets #299 @allu22 +- Fixed homebrew installation #297 @vhbit +- `cc` files are now automatically recognized as source files #317 @maicki +- Fixed `commandLineArguments` not parsing when they had dots in them #323 @yonaskolb +- Fixed excluding directories that only have sub directories #326 @brentleyjones +- Made `PBXContainerItemProxy` ID more deterministic +- Fixed generated framework schemes from being executable #328 @brentleyjones ## 1.9.0 #### Added -- Scheme pre and post actions can now be added to `target.scheme` [#280](https://github.com/yonaskolb/XcodeGen/pull/280) @yonaskolb -- Individual files can now be added to `fileGroups` [#293](https://github.com/yonaskolb/XcodeGen/pull/293) @yonaskolb + +- 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](https://github.com/yonaskolb/XcodeGen/pull/284) @LinusU -- **Breaking for ProjectSpec library users** Changed `ProjectSpec` to `Project` and `ProjectSpec.Options` to `SpecOptions` [#281](https://github.com/yonaskolb/XcodeGen/pull/281) @jerrymarino +- 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](https://github.com/yonaskolb/XcodeGen/pull/288) @yonaskolb -- Quoted values now correctly get parsed as strings [#282](https://github.com/yonaskolb/XcodeGen/pull/282) @yonaskolb -- Fixed adding a root source folder when `createIntermediateGroups` is on [#291](https://github.com/yonaskolb/XcodeGen/pull/291) @yonaskolb -- Fixed Homebrew installations issues on some machines [#289](https://github.com/yonaskolb/XcodeGen/pull/289) @vhbit -- Fixed files that are added as root sources from having invalid parent groups outside the project directory [#293](https://github.com/yonaskolb/XcodeGen/pull/293) @yonaskolb -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.8.0...1.9.0) +- 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 +- Fixed Homebrew installations issues on some machines #289 @vhbit +- Fixed files that are added as root sources from having invalid parent groups outside the project directory #293 @yonaskolb ## 1.8.0 #### Added -- Added Project `defaultConfig` [#269](https://github.com/yonaskolb/XcodeGen/pull/269) @keith -- Added Target `attributes` [#276](https://github.com/yonaskolb/XcodeGen/pull/276) @yonaskolb -- Automatically set `DevelopmentTeam` and `ProvisioningStyle` within `TargetAttributes` if relevant build settings are defined [#277](https://github.com/yonaskolb/XcodeGen/pull/277) @yonaskolb + +- 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](https://github.com/yonaskolb/XcodeGen/pull/272) @LinusU + +- Fixed default `LD_RUNPATH_SEARCH_PATHS` for app extensions #272 @LinusU #### Internal -- Make `LegacyTarget` init public [#264](https://github.com/yonaskolb/XcodeGen/pull/264) @jerrymarino -- Upgrade to *xcproj* to 4.2.0, *Yams* to 0.6.0 and *PathKit* to 0.9.1 @yonaskolb -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.7.0...1.8.0) +- 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 ## 1.7.0 #### Added -- Added support for scheme environment variables [#239](https://github.com/yonaskolb/XcodeGen/pull/239) [#254](https://github.com/yonaskolb/XcodeGen/pull/254) [#259](https://github.com/yonaskolb/XcodeGen/pull/259) @turekj @toshi0383 -- Added `carthageExecutablePath` option [#244](https://github.com/yonaskolb/XcodeGen/pull/244) @akkyie -- Added `parallelizeBuild` and `buildImplicitDependencies` to Schemes [#241](https://github.com/yonaskolb/XcodeGen/pull/241) @rahul-malik +- Added support for scheme environment variables #239 @turekj @toshi0383 +- Added `carthageExecutablePath` option #244 @akkyie +- Added `parallelizeBuild` and `buildImplicitDependencies` to Schemes #241 @rahul-malik @yonaskolb -- Added support for Core Data `xcdatamodeld` files [#249](https://github.com/yonaskolb/XcodeGen/pull/249) @yonaskolb -- Projects are now generated atomically by writing to a temporary directory first [#250](https://github.com/yonaskolb/XcodeGen/pull/250) @yonaskolb -- Added script for adding precompiled binary to releases [#246](https://github.com/yonaskolb/XcodeGen/pull/246) @toshi0383 -- Added optional `headerVisibilty` to target source. This still defaults to public [#252](https://github.com/yonaskolb/XcodeGen/pull/252) @yonaskolb +- Added support for Core Data `xcdatamodeld` files #249 @yonaskolb +- Projects are now generated atomically by writing to a temporary directory first #250 @yonaskolb +- Added script for adding precompiled binary to releases #246 @toshi0383 +- Added optional `headerVisibilty` to target source. This still defaults to public #252 @yonaskolb - Releases now include a pre-compiled binary and setting presets, including an install script #### Fixed -- Fixed Mint installation from reading setting presets [#248](https://github.com/yonaskolb/XcodeGen/pull/248) @yonaskolb -- Fixed setting `buildPhase` on a `folder` source. This allows for a folder of header files [#254](https://github.com/yonaskolb/XcodeGen/pull/254) @toshi0383 -- Carthage dependencies are not automatically embedded into test targets [#256](https://github.com/yonaskolb/XcodeGen/pull/256) @yonaskolb -- Carthage dependencies now respect the `embed` property [#256](https://github.com/yonaskolb/XcodeGen/pull/256) @yonaskolb -- iMessage extensions now have proper setting presets in regards to app icon and runtime search paths [#255](https://github.com/yonaskolb/XcodeGen/pull/255) @yonaskolb -- Excluded files are not added within .lproj directories [#238](https://github.com/yonaskolb/XcodeGen/pull/238) @toshi0383 -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.6.0...1.7.0) +- 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 +- Carthage dependencies now respect the `embed` property #256 @yonaskolb +- iMessage extensions now have proper setting presets in regards to app icon and runtime search paths #255 @yonaskolb +- Excluded files are not added within .lproj directories #238 @toshi0383 ## 1.6.0 #### Added -- Added scheme pre-actions and post-actions [#231](https://github.com/yonaskolb/XcodeGen/pull/231) @kastiglione -- Added `options.disabledValidations` including `missingConfigs` to disable project validation errors [#220](https://github.com/yonaskolb/XcodeGen/pull/220) @keith -- Generate UI Test Target Attributes [#221](https://github.com/yonaskolb/XcodeGen/pull/221) @anreitersimon + +- 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](https://github.com/yonaskolb/XcodeGen/pull/217) @allu22 -- Fixed how `lastKnownFileType` and `explicitFileType` were generated across platforms [#115](https://github.com/yonaskolb/XcodeGen/pull/115) @toshi0383 + +- 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](https://github.com/yonaskolb/XcodeGen/pull/218) @allu22 -- Updated to xcproj 4.0 [#227](https://github.com/yonaskolb/XcodeGen/pull/227) -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.5.0...1.6.0) +- 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](https://github.com/yonaskolb/XcodeGen/pull/170) @alexruperez -- added support for `commandLineOptions` in target schemes [#172](https://github.com/yonaskolb/XcodeGen/pull/172) @rahul-malik -- added Project spec as a SwiftPM library for reuse in other projects [#164](https://github.com/yonaskolb/XcodeGen/pull/164) @soffes -- added `implicit` option for framework dependencies [#166](https://github.com/yonaskolb/XcodeGen/pull/166) @sbarow -- added `--quite` option to CLI [#167](https://github.com/yonaskolb/XcodeGen/pull/167) @soffes -- can now print version with `-v` in addition to `--version` [#174](https://github.com/yonaskolb/XcodeGen/pull/174) @kastiglione -- added support for legacy targets [#175](https://github.com/yonaskolb/XcodeGen/pull/175) @bkase -- added support for indentation options [#190](https://github.com/yonaskolb/XcodeGen/pull/190) @bkase -- added source excludes [#135](https://github.com/yonaskolb/XcodeGen/pull/135) [#161](https://github.com/yonaskolb/XcodeGen/pull/161) [#190](https://github.com/yonaskolb/XcodeGen/pull/190) @peymankh @ -- added `options.xcodeVersion` [#197](https://github.com/yonaskolb/XcodeGen/pull/197) @yonaskolb @peymankh -- add test targets to Scheme [#195](https://github.com/yonaskolb/XcodeGen/pull/195) @vhbit -- add option to make a source file optional incase it will be generated later [#200](https://github.com/yonaskolb/XcodeGen/pull/200) @vhbit -- finalize Scheme spec [#201](https://github.com/yonaskolb/XcodeGen/pull/201) @yonaskolb -- added `buildPhase` setting to target source for overriding the guessed build phase of files [#206](https://github.com/yonaskolb/XcodeGen/pull/206) @yonaskolb -- added `deploymentTarget` setting to project and target [#205](https://github.com/yonaskolb/XcodeGen/pull/205) @yonaskolb + +- 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 +- added `implicit` option for framework dependencies #166 @sbarow +- added `--quite` option to CLI #167 @soffes +- can now print version with `-v` in addition to `--version` #174 @kastiglione +- added support for legacy targets #175 @bkase +- added support for indentation options #190 @bkase +- added source excludes #135 @peymankh @ +- added `options.xcodeVersion` #197 @yonaskolb @peymankh +- add test targets to Scheme #195 @vhbit +- add option to make a source file optional incase it will be generated later #200 @vhbit +- finalize Scheme spec #201 @yonaskolb +- added `buildPhase` setting to target source for overriding the guessed build phase of files #206 @yonaskolb +- 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 - updated Project Spec documentation -- scan for `Info.plist` lazely [#194](https://github.com/yonaskolb/XcodeGen/pull/194) @kastiglione -- change setting presets so that icon settings only get applied to application targets [#204](https://github.com/yonaskolb/XcodeGen/pull/204) @yonaskolb -- changed scheme build targets format [#203](https://github.com/yonaskolb/XcodeGen/pull/203) @yonaskolb -- when specifying a `--spec` argument, the default for the `--project` path is now the directory containing the spec [#211](https://github.com/yonaskolb/XcodeGen/pull/211) @yonaskolb +- scan for `Info.plist` lazely #194 @kastiglione +- change setting presets so that icon settings only get applied to application targets #204 @yonaskolb +- changed scheme build targets format #203 @yonaskolb +- 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](https://github.com/yonaskolb/XcodeGen/pull/186) @allu22 -- fixed `createIntermediateGroups` when using a relative spec path [#184](https://github.com/yonaskolb/XcodeGen/pull/184) @kastiglione -- fixed command line arguments for test and profile from being overridden [#199](https://github.com/yonaskolb/XcodeGen/pull/199) @vhbit -- fixed files deep within a hierarchy having the path for a name -- fixed source files from being duplicated if referenced with different casing [#212](https://github.com/yonaskolb/XcodeGen/pull/212) @yonaskolb -- fixed target product name not being written. Fixes integration with R.swift [#213](https://github.com/yonaskolb/XcodeGen/pull/213) @yonaskolb -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.4.0...1.5.0) +- 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 +- fixed files deep within a hierarchy having the path for a name +- fixed source files from being duplicated if referenced with different casing #212 @yonaskolb +- fixed target product name not being written. Fixes integration with R.swift #213 @yonaskolb ## 1.4.0 #### Added -- added `--version` flag [#112](https://github.com/yonaskolb/XcodeGen/pull/112) @mironal -- added support for adding individual file sources [#106](https://github.com/yonaskolb/XcodeGen/pull/106) [#133](https://github.com/yonaskolb/XcodeGen/pull/133) [#142](https://github.com/yonaskolb/XcodeGen/pull/142) [#139](https://github.com/yonaskolb/XcodeGen/pull/139) @bkase -- added source compiler flag support [#121](https://github.com/yonaskolb/XcodeGen/pull/121) @bkase -- added `ProjectSpec.options.createIntermediateGroups` [#108](https://github.com/yonaskolb/XcodeGen/pull/108) @bkase -- added better json loading support [#127](https://github.com/yonaskolb/XcodeGen/pull/127) @rahul-malik -- added source `name` for customizing names of source directories and file [#146](https://github.com/yonaskolb/XcodeGen/pull/146) @yonaskolb -- added folder reference source support via a new `type` property [#151](https://github.com/yonaskolb/XcodeGen/pull/151) @yonaskolb -- added `ProjectSpec.options.developmentLanguage` [#155](https://github.com/yonaskolb/XcodeGen/pull/155) @yonaskolb + +- added `--version` flag #112 @mironal +- added support for adding individual file sources #106 @bkase +- added source compiler flag support #121 @bkase +- added `ProjectSpec.options.createIntermediateGroups` #108 @bkase +- added better json loading support #127 @rahul-malik +- added source `name` for customizing names of source directories and file #146 @yonaskolb +- added folder reference source support via a new `type` property #151 @yonaskolb +- added `ProjectSpec.options.developmentLanguage` #155 @yonaskolb #### Changed -- updated to xcproj 1.2.0 [#113](https://github.com/yonaskolb/XcodeGen/pull/113) @yonaskolb -- build settings from presets will be removed if they are provided in `xcconfig` files [#77](https://github.com/yonaskolb/XcodeGen/pull/77) @toshi0383 -- all files and groups are sorted by type and then alphabetically [#144](https://github.com/yonaskolb/XcodeGen/pull/144) @yonaskolb -- target sources can now have an expanded form [#119](https://github.com/yonaskolb/XcodeGen/pull/119) @yonaskolb -- empty build phases are now not generated [#149](https://github.com/yonaskolb/XcodeGen/pull/149) @yonaskolb -- make UUIDs more deterministic [#154](https://github.com/yonaskolb/XcodeGen/pull/154) @yonaskolb + +- 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 +- target sources can now have an expanded form #119 @yonaskolb +- empty build phases are now not generated #149 @yonaskolb +- make UUIDs more deterministic #154 @yonaskolb #### Fixed -- only add headers to frameworks and libraries [#118](https://github.com/yonaskolb/XcodeGen/pull/118) @ryohey -- fixed localized files with the same name [#126](https://github.com/yonaskolb/XcodeGen/pull/126) @ryohey -- fix intermediate sources [#144](https://github.com/yonaskolb/XcodeGen/pull/144) @yonaskolb -- fix cyclical target dependencies not working [#147](https://github.com/yonaskolb/XcodeGen/pull/147) @yonaskolb -- fix directory bundles not being added properly when referenced directly [#148](https://github.com/yonaskolb/XcodeGen/pull/1478) @yonaskolb -- made `mm`, `c` and `S` file be parsed as source files [#120](https://github.com/yonaskolb/XcodeGen/pull/120) [#125](https://github.com/yonaskolb/XcodeGen/pull/125) [#138](https://github.com/yonaskolb/XcodeGen/pull/138) @bkase @enmiller -- fix the generation of localized variant groups if there is no `Base.lproj` [#157](https://github.com/yonaskolb/XcodeGen/pull/157) @ryohey -- all localizations found are added to a projects known regions [#157](https://github.com/yonaskolb/XcodeGen/pull/157) @ryohey + +- only add headers to frameworks and libraries #118 @ryohey +- fixed localized files with the same name #126 @ryohey +- fix intermediate sources #144 @yonaskolb +- fix cyclical target dependencies not working #147 @yonaskolb +- fix directory bundles not being added properly when referenced directly #148 @yonaskolb +- made `mm`, `c` and `S` file be parsed as source files #120 @bkase @enmiller +- fix the generation of localized variant groups if there is no `Base.lproj` #157 @ryohey +- all localizations found are added to a projects known regions #157 @ryohey #### Internal + - refactoring - more tests - added release scripts -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.3.0...1.4.0) - ## 1.3.0 #### Added -- generate output files for Carthage copy-frameworks script [#84](https://github.com/yonaskolb/XcodeGen/pull/84) @mironal -- added options.settingPreset to choose which setting presets get applied [#100](https://github.com/yonaskolb/XcodeGen/pull/101) @yonaskolb -- added `link` option for target dependencies [#109](https://github.com/yonaskolb/XcodeGen/pull/109) @keith + +- 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](https://github.com/yonaskolb/XcodeGen/pull/85) @enmiller -- don't copy base settings if config type has been left out [#100](https://github.com/yonaskolb/XcodeGen/pull/100) @yonaskolb -- generate localised files under a single variant group [#70](https://github.com/yonaskolb/XcodeGen/pull/70) @ryohey -- don't apply common project settings to configs with no type [#100](https://github.com/yonaskolb/XcodeGen/pull/100) @yonaskolb -- config references in settings can now be partially matched and are case insensitive [#111](https://github.com/yonaskolb/XcodeGen/pull/111) @yonaskolb + +- 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 +- don't apply common project settings to configs with no type #100 @yonaskolb +- config references in settings can now be partially matched and are case insensitive #111 @yonaskolb - other small internal changes @yonaskolb #### Fixed -- embed Carthage frameworks for macOS [#82](https://github.com/yonaskolb/XcodeGen/pull/82) @toshi0383 -- fixed copying of watchOS app resources [#96](https://github.com/yonaskolb/XcodeGen/pull/96) @keith -- automatically ignore more file types for a target's sources (entitlements, gpx, apns) [#94](https://github.com/yonaskolb/XcodeGen/pull/94) @keith -- change make build to a PHONY task [#98](https://github.com/yonaskolb/XcodeGen/pull/98) @keith -- allow copying of resource files from dependant targets [#95](https://github.com/yonaskolb/XcodeGen/pull/95) @keith -- fixed library linking [#93](https://github.com/yonaskolb/XcodeGen/pull/93) @keith -- fixed duplicate carthage file references [#107](https://github.com/yonaskolb/XcodeGen/pull/107) @yonaskolb -- an error is now shown if you try and generate a target scheme and don't have debug and release builds @yonaskolb -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.2.4...1.3.0) +- 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 +- change make build to a PHONY task #98 @keith +- allow copying of resource files from dependant targets #95 @keith +- fixed library linking #93 @keith +- fixed duplicate carthage file references #107 @yonaskolb +- an error is now shown if you try and generate a target scheme and don't have debug and release builds @yonaskolb ## 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 -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.2.3...1.2.4) +- update to xcproj 0.3.0 ## 1.2.3 #### Fixed -- Fixed wrong carthage directory name reference for macOS [#74](https://github.com/yonaskolb/XcodeGen/pull/74) @toshi0383 -- Removed unnecessary `carthage copy-frameworks` for macOS app target [#76](https://github.com/yonaskolb/XcodeGen/pull/76) @toshi0383 + +- 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 - Filter out nulls from setting presets if specifying an empty string -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.2.2...1.2.3) - ## 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` - -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.2.0...1.2.2) - ## 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](https://github.com/yonaskolb/XcodeGen/pull/64) -- add `fileGroups` to project spec for adding groups of files that aren't target source files [#64](https://github.com/yonaskolb/XcodeGen/pull/64) +- 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 - better output (more info, emoji, colors) -- add `options.bundleIdPrefix` for autogenerating `PRODUCT_BUNDLE_IDENTIFIER` [#67](https://github.com/yonaskolb/XcodeGen/pull/67) -- add `:REPLACE` syntax when merging `include` [#68](https://github.com/yonaskolb/XcodeGen/pull/68) +- add `options.bundleIdPrefix` for autogenerating `PRODUCT_BUNDLE_IDENTIFIER` #67 +- add `:REPLACE` syntax when merging `include` #68 - add `mint` installation support #### Fixed + - fixed homebrew installation -- fixed target xcconfig files not working via `configFiles` [#64](https://github.com/yonaskolb/XcodeGen/pull/64) -- look for `INFOPLIST_FILE` setting in project and xcconfig files before adding it automatically. It was just looking in target settings before [#64](https://github.com/yonaskolb/XcodeGen/pull/64) +- 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 - exit with error on failure -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.1.0...1.2.0) - ## 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` -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.0.1...1.1.0) - ### 1.0.1 ### Fixed + - fixed incorrect default build script shell path - fixed install scripts -[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.0.0...1.0.1) - ## 1.0.0 #### Added -- Swift 4 support [#52](https://github.com/yonaskolb/XcodeGen/pull/52) -- Support for C and C++ files [#48](https://github.com/yonaskolb/XcodeGen/pull/48) by @antoniocasero + +- 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](https://github.com/yonaskolb/XcodeGen/pull/50) by @antoniocasero -#### Changed -- updated to xcodeproj 0.1.2 [#56](https://github.com/yonaskolb/XcodeGen/pull/56) -- **BREAKING**: changed target definitions from list to map [#54](https://github.com/yonaskolb/XcodeGen/pull/54) See [Project Spec](docs/ProjectSpec.md) +- fixed empty string in YAML not being parsed properly #50 by @antoniocasero +#### Changed -[Commits](https://github.com/yonaskolb/XcodeGen/compare/0.6.1...1.0.0) +- 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](https://github.com/yonaskolb/XcodeGen/pull/45) + +- 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](https://github.com/yonaskolb/XcodeGen/pull/46) -[Commits](https://github.com/yonaskolb/XcodeGen/compare/0.6.0...0.6.1) +- 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](https://github.com/yonaskolb/XcodeGen/pull/44) + +- 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 -[Commits](https://github.com/yonaskolb/XcodeGen/compare/0.5.1...0.6.0) - ## 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](https://github.com/yonaskolb/XcodeGen/pull/43) - -[Commits](https://github.com/yonaskolb/XcodeGen/compare/0.5.0...0.5.1) +- Fix build scripts with "" generating invalid projects #43 ## 0.5.0 + #### Added -- Added multi platform targets [#35](https://github.com/yonaskolb/XcodeGen/pull/35) -- Automatically generate platform specific `FRAMEWORK_SEARCH_PATHS` for Carthage dependencies [#38](https://github.com/yonaskolb/XcodeGen/pull/38) -- Automatically find Info.plist and set `INFOPLIST_FILE` build setting if it doesn't exist on a target [#40](https://github.com/yonaskolb/XcodeGen/pull/40) -- Add options for controlling embedding of dependencies [#37](https://github.com/yonaskolb/XcodeGen/pull/37) + +- 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 -[Commits](https://github.com/yonaskolb/XcodeGen/compare/0.4.0...0.5.0) - ## 0.4.0 ##### Added -- Homebrew support [#16](https://github.com/yonaskolb/XcodeGen/pull/16) by @pepibumur -- Added `runOnlyWhenInstalling` to build scripts [#32](https://github.com/yonaskolb/XcodeGen/pull/32) -- Added `carthageBuildPath` option [#34](https://github.com/yonaskolb/XcodeGen/pull/34) + +- 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](https://github.com/yonaskolb/XcodeGen/pull/33) -[Commits](https://github.com/yonaskolb/XcodeGen/compare/0.3.0...0.4.0) +- 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](https://github.com/yonaskolb/XcodeGen/pull/19) -- Added test targets to generated target schemes via `Target.scheme.testTargets` [#21](https://github.com/yonaskolb/XcodeGen/pull/21) + +- 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` -[Commits](https://github.com/yonaskolb/XcodeGen/compare/0.2...0.3.0) +- Changed `Target.generatedSchemes` to `Target.scheme.configVariants` ## 0.2.0 - Build scripts #### Added -- Added Target build scripts with `Target.prebuildScripts` and `Target.postbuildScripts` [#17](https://github.com/yonaskolb/XcodeGen/pull/17) + +- 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 -[Commits](https://github.com/yonaskolb/XcodeGen/compare/0.1...0.2) +- Fixed some project objects sometimes having duplicate ids ## 0.1.0 + First official release diff --git a/Docs/Examples.md b/Docs/Examples.md index d10f8663d..fdabac855 100644 --- a/Docs/Examples.md +++ b/Docs/Examples.md @@ -2,9 +2,12 @@ These are a bunch of real world examples of XcodeGen project specs. Feel free to add your own via PR. -- [num42/RxUserDefaults](https://github.com/num42/RxUserDefaults/blob/master/project.yml) - [toshi0383/Bitrise-iOS](https://github.com/toshi0383/Bitrise-iOS/blob/master/project.yml) - [johndpope/swift-models](https://github.com/johndpope/swift-models/tree/stable/Inference) - [atelier-socle/AppRepositoryTemplate](https://github.com/atelier-socle/AppRepositoryTemplate/blob/master/project.yml) - [atelier-socle/FrameworkRepositoryTemplate](https://github.com/atelier-socle/FrameworkRepositoryTemplate/blob/master/project.yml) - [scelis/XcodeGen-TestStickers](https://github.com/scelis/XcodeGen-TestStickers/blob/master/project.yml) +- [minvws/nl-covid19-notification-app-ios](https://github.com/minvws/nl-covid19-notification-app-ios/blob/master/project.yml) +- [pvinis/react-native-xcodegen](https://github.com/pvinis/react-native-xcodegen/blob/master/templates) +- [covid19cz/erouska-ios](https://github.com/covid19cz/erouska-ios/blob/develop/project.yml) +- [markst/hotreloading-vscode-ios](https://github.com/markst/hotreloading-vscode-ios) diff --git a/Docs/FAQ.md b/Docs/FAQ.md index 6f47f1f5a..9d1096816 100644 --- a/Docs/FAQ.md +++ b/Docs/FAQ.md @@ -9,10 +9,14 @@ Absolutely. You will get the most out of XcodeGen by adding your project to your >Note that you can run `xcodegen` as a step in your build process on CI. ## What happens when I switch branches -If files were added or removed in the new checkout you will most likely need to run `xcodegen` again so that your project will reference all your files. Unfortunately this is a manual step at the moment, but in the future this could be automated. - -For now you can always add xcodegen as a git `post-checkout` hook. -It's recommended to use `--use-cache` so that the project is not needlessly generated. +If files were added or removed in the new checkout you will most likely need to run `xcodegen` again so that your project will reference all your files. + +It's recommended to set up some [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) to automate the process: +- run `xcodegen generate --use-cache` on the following hooks. This will make sure the project is up to date when checking out, merging and rebasing + - `post-checkout` + - `post-rewrite` + - `post-merge` +- run `xcodegen cache` on `pre-commit`. This will make sure that when switching branches the cache will be updated in case you made local changes, or are ammending a commit that added a new file. ## Can I use CocoaPods Yes, you will just need to run `pod install` after the project is generated to integrate Cocoapods changes. @@ -24,13 +28,12 @@ Yes, but you need to use a little trick when using CocoaPods. Add this script in ```ruby:Podfile // Your dependencies -pod 'Fabric' -pod 'Crashlytics' - -script_phase :name => 'Run Fabric', - :script => '"${PODS_ROOT}/Fabric/run"', - :input_files => ['$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)'] +pod 'Firebase/Crashlytics' +script_phase name: 'Run Firebase Crashlytics', + shell_path: '/bin/sh', + script: '"${PODS_ROOT}/FirebaseCrashlytics/run"', + input_files: ['$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)'] ``` This script will be added after `[CP] Embed Pods Frameworks.` diff --git a/Docs/ProjectSpec.md b/Docs/ProjectSpec.md index cfbe09878..c1a6259ca 100644 --- a/Docs/ProjectSpec.md +++ b/Docs/ProjectSpec.md @@ -1,52 +1,75 @@ # Project Spec -### Index +The project spec can be written in either YAML or JSON. All the examples below use YAML. + +- [x] required property +- [ ] optional property + +Some of the YAML examples below don't show all the required properties. For example not all target examples will have a platform or type, even though they are required. + +You can also use environment variables in your configuration file, by using `${SOME_VARIABLE}` in a string. -- [General](#general) - [Project](#project) - - [Include](#include) - - [Options](#options) - - [Configs](#configs) - - [Setting Groups](#setting-groups) + - [Include](#include) + - [Options](#options) + - [GroupOrdering](#groupordering) + - [FileType](#filetype) + - [Breakpoints](#breakpoints) + - [Breakpoint Action](#breakpoint-action) + - [Configs](#configs) + - [Setting Groups](#setting-groups) - [Settings](#settings) - [Target](#target) - - [Product Type](#product-type) - - [Platform](#platform) - - [Sources](#sources) - - [Config Files](#config-files) - - [Settings](#settings) - - [Build Script](#build-script) - - [Build Rule](#build-rule) - - [Dependency](#dependency) - - [Target Scheme](#target-scheme) - - [Legacy Target](#legacy-target) + - [Product Type](#product-type) + - [Platform](#platform) + - [Supported Destinations](#supported-destinations) + - [Sources](#sources) + - [Target Source](#target-source) + - [Dependency](#dependency) + - [Config Files](#config-files) + - [Plist](#plist) + - [Build Tool Plug-ins](#build-tool-plug-ins) + - [Build Script](#build-script) + - [Build Rule](#build-rule) + - [Target Scheme](#target-scheme) + - [Legacy Target](#legacy-target) - [Aggregate Target](#aggregate-target) - [Target Template](#target-template) - [Scheme](#scheme) - - [Scheme Template](#scheme-template) + - [Build](#build) + - [Common Build Action options](#common-build-action-options) + - [Execution Action](#execution-action) + - [Run Action](#run-action) + - [Test Action](#test-action) + - [Test Target](#test-target) + - [Other Parameters](#other-parameters) + - [Testable Target Reference](#testable-target-reference) + - [Archive Action](#archive-action) + - [Simulate Location](#simulate-location) + - [Scheme Management](#scheme-management) + - [Environment Variable](#environment-variable) + - [Test Plan](#test-plan) +- [Scheme Template](#scheme-template) - [Swift Package](#swift-package) - -## General - -The project spec can be written in either YAML or JSON. All the examples below use YAML. - -Required properties are marked with checkbox. Some of the YAML examples don't show all the required properties. For example not all target examples will have a platform or type, even though they are required. - -You can also use environment variables in your configuration file, by using `${SOME_VARIABLE}` in a string. + - [Remote Package](#remote-package) + - [Local Package](#local-package) +- [Project Reference](#project-reference) ## Project - [x] **name**: **String** - Name of the generated project - [ ] **include**: **[Include](#include)** - One or more paths to other specs - [ ] **options**: **[Options](#options)** - Various options to override default behaviour -- [ ] **attributes**: **[String: Any]** - The PBXProject attributes. This is for advanced use. This defaults to ``{"LastUpgradeCheck": "XcodeVersion"}`` with `xcodeVersion` being set by [Options](#options)`.xcodeVersion` +- [ ] **attributes**: **[String: Any]** - The PBXProject attributes. This is for advanced use. If no value is set for `LastUpgradeCheck`, it will be defaulted to ``{"LastUpgradeCheck": "XcodeVersion"}`` with `xcodeVersion` being set by [Options](#options)`.xcodeVersion` +- [ ] **breakpoints**: [Breakpoints](#breakpoints) - Add shared breakpoints to the generated project - [ ] **configs**: **[Configs](#configs)** - Project build configurations. Defaults to `Debug` and `Release` configs - [ ] **configFiles**: **[Config Files](#config-files)** - `.xcconfig` files per config - [ ] **settings**: **[Settings](#settings)** - Project specific settings. Default base and config type settings will be applied first before any settings defined here - [ ] **settingGroups**: **[Setting Groups](#setting-groups)** - Setting groups mapped by name - [ ] **targets**: **[String: [Target](#target)]** - The list of targets in the project mapped by name -- [ ] **fileGroups**: **[String]** - A list of paths to add to the root of the project. These aren't files that will be included in your targets, but that you'd like to include in the project hierachy anyway. For example a folder of xcconfig files that aren't already added by any target sources, or a Readme file. +- [ ] **fileGroups**: **[String]** - A list of paths to add to the root of the project. These aren't files that will be included in your targets, but that you'd like to include in the project hierarchy anyway. For example a folder of xcconfig files that aren't already added by any target sources, or a Readme file. - [ ] **schemes**: **[Scheme](#scheme)** - A list of schemes by name. This allows more control over what is found in [Target Scheme](#target-scheme) +- [ ] **schemeTemplates**: **[String: [Scheme Template](#scheme-template)]** - a list of schemes that can be used as templates for actual schemes which reference them via a `template` property. They can be used to extract common scheme settings. Works great in combination with `include`. - [ ] **targetTemplates**: **[String: [Target Template](#target-template)]** - a list of targets that can be used as templates for actual targets which reference them via a `template` property. They can be used to extract common target settings. Works great in combination with `include`. - [ ] **packages**: **[String: [Swift Package](#swift-package)]** - a map of Swift packages by name. - [ ] **projectReferences**: **[String: [Project Reference](#project-reference)]** - a map of project references by name @@ -63,17 +86,18 @@ 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: -- if existing value and new value are both dictionaries merge them and continue down the hierachy +- if existing value and new value are both dictionaries merge them and continue down the hierarchy - if existing value and new value are both an array then add the new value to the end of the array - otherwise replace the existing value with the new value @@ -97,7 +121,7 @@ Note that target names can also be changed by adding a `name` property to a targ - [ ] **minimumXcodeGenVersion**: **String** - The minimum version of XcodeGen required. - [ ] **carthageBuildPath**: **String** - The path to the carthage build directory. Defaults to `Carthage/Build`. This is used when specifying target carthage dependencies - [ ] **carthageExecutablePath**: **String** - The path to the carthage executable. Defaults to `carthage`. You can specify when you use custom built or locally installed Carthage using [Mint](https://github.com/yonaskolb/Mint), for example. -- [ ] **createIntermediateGroups**: **Bool** - If this is specified and set to `true`, then intermediate groups will be created for every path component between the folder containing the source and next existing group it finds or the base path. For example, when enabled if a source path is specified as `Vendor/Foo/Hello.swift`, the group `Vendor` will created as a parent of the `Foo` group. This can be overriden in a specific [Target source](#target-source) +- [ ] **createIntermediateGroups**: **Bool** - If this is specified and set to `true`, then intermediate groups will be created for every path component between the folder containing the source and next existing group it finds or the base path. For example, when enabled if a source path is specified as `Vendor/Foo/Hello.swift`, the group `Vendor` will created as a parent of the `Foo` group. This can be overridden in a specific [Target source](#target-source) - [ ] **bundleIdPrefix**: **String** - If this is specified then any target that doesn't have an `PRODUCT_BUNDLE_IDENTIFIER` (via all levels of build settings) will get an autogenerated one by combining `bundleIdPrefix` and the target name: `bundleIdPrefix.name`. The target name will be stripped of all characters that aren't alphanumerics, hyphens, or periods. Underscores will be replaced with hyphens. - [ ] **settingPresets**: **String** - This controls the settings that are automatically applied to the project and its targets. These are the same build settings that Xcode would add when creating a new project. Project settings are applied by config type. Target settings are applied by the product type and platform. By default this is set to `all` - `all`: project and target settings @@ -113,6 +137,7 @@ Note that target names can also be changed by adding a `name` property to a targ - [ ] **disabledValidations**: **[String]** - A list of validations that can be disabled if they're too strict for your use case. By default this is set to an empty array. Currently these are the available options: - `missingConfigs`: Disable errors for configurations in yaml files that don't exist in the project itself. This can be useful if you include the same yaml file in different projects - `missingConfigFiles`: Disable checking for the existence of configuration files. This can be useful for generating a project in a context where config files are not available. + - `missingTestPlans`: Disable checking if test plan paths exist. This can be useful if your test plans haven't been created yet. - [ ] **defaultConfig**: **String** - The default configuration for command line builds from Xcode. If the configuration provided here doesn't match one in your [configs](#configs) key, XcodeGen will fail. If you don't set this, the first configuration alphabetically will be chosen. - [ ] **groupSortPosition**: **String** - Where groups are sorted in relation to other files. Either: - `none` - sorted alphabetically with all the other files @@ -121,10 +146,17 @@ Note that target names can also be changed by adding a `name` property to a targ - [ ] **groupOrdering**: **[[GroupOrdering]](#groupOrdering)** - An order of groups. - [ ] **transitivelyLinkDependencies**: **Bool** - If this is `true` then targets will link to the dependencies of their target dependencies. If a target should embed its dependencies, such as application and test bundles, it will embed these transitive dependencies as well. Some complex setups might want to set this to `false` and explicitly specify dependencies at every level. Targets can override this with [Target](#target).transitivelyLinkDependencies. Defaults to `false`. - [ ] **generateEmptyDirectories**: **Bool** - If this is `true` then empty directories will be added to project too else will be missed. Defaults to `false`. -- [ ] **findCarthageFrameworks**: **Bool** - When this is set to `true`, all the invididual frameworks for Carthage dependencies will automatically be found. This property can be overriden individually for each carthage dependency - for more details see See **findFrameworks** in the [Dependency](#dependency) section. Defaults to `false`. -- [ ] **localPackagesGroup**: **String** - The group name that local packages are put into. This defaults to `Packages` +- [ ] **findCarthageFrameworks**: **Bool** - When this is set to `true`, all the individual frameworks for Carthage framework dependencies will automatically be found. This property can be overridden individually for each carthage dependency - for more details see See **findFrameworks** in the [Dependency](#dependency) section. Defaults to `false`. +- [ ] **localPackagesGroup**: **String** - The group name that local packages are put into. This defaults to `Packages`. Use `""` to specify the project root. +- [ ] **fileTypes**: **[String: [FileType](#filetype)]** - A list of default file options for specific file extensions across the project. Values in [Sources](#sources) will overwrite these settings. - [ ] **preGenCommand**: **String** - A bash command to run before the project has been generated. If the project isn't generated due to no changes when using the cache then this won't run. This is useful for running things like generating resources files before the project is regenerated. - [ ] **postGenCommand**: **String** - A bash command to run after the project has been generated. If the project isn't generated due to no changes when using the cache then this won't run. This is useful for running things like `pod install` only if the project is actually regenerated. +- [ ] **useBaseInternationalization**: **Bool** If this is `false` and your project does not include resources located in a **Base.lproj** directory then `Base` will not be included in the projects 'known regions'. The default value is `true`. +- [ ] **schemePathPrefix**: **String** - A path prefix for relative paths in schemes, such as StoreKitConfiguration. The default is `"../../"`, which is suitable for non-workspace projects. For use in workspaces, use `"../"`. +- [ ] **defaultSourceDirectoryType**: **String** - When a [Target source](#target-source) doesn't specify a type and is a directory, this is the type that will be used. If nothing is specified for either then `group` will be used. + - `group` (default) + - `folder` + - `syncedFolder` ```yaml options: @@ -151,9 +183,94 @@ options: In this example, we set up the order of two groups. First one is the main group, i.e. the project, note that in this case, we shouldn't set `pattern` option and the second group order is for groups whose names ends with `Screen`. +### FileType +Default settings for file extensions. See [Sources](#sources) for more documentation on properties. If you overwrite an extension that XcodeGen already provides by default, you will need to provide all the settings. + +- [ ] **file**: **Bool** - Whether this extension should be treated like a file. Defaults to true. +- [ ] **buildPhase**: **String** - The default build phase. +- [ ] **attributes**: **[String]** - Additional settings attributes that will be applied to any build files. +- [ ] **resourceTags**: **[String]** - On Demand Resource Tags that will be applied to any resources. This also adds to the project attribute's knownAssetTags. +- [ ] **compilerFlags**: **[String]** - A list of compiler flags to add. + +### Breakpoints + +- [x] **type**: **String** - Breakpoint type + - `File`: file breakpoint + - `Exception`: exception breakpoint + - `SwiftError`: swift error breakpoint + - `OpenGLError`: OpenGL breakpoint + - `Symbolic`: symbolic breakpoint + - `IDEConstraintError`: IDE constraint breakpoint + - `IDETestFailure`: IDE test failure breakpoint + - `RuntimeIssue`: Runtime issue breakpoint +- [ ] **enabled**: **Bool** - Indicates whether it should be active. Default to `true` +- [ ] **ignoreCount**: **Int** - Indicates how many times it should be ignored before stopping, Default to `0` +- [ ] **continueAfterRunningActions**: **Bool** - Indicates if should automatically continue after evaluating actions, Default to `false` +- [ ] **path**: **String** - Breakpoint file path (only required by file breakpoints) +- [ ] **line**: **Int** - Breakpoint line (only required by file breakpoints) +- [ ] **symbol**: **String** - Breakpoint symbol (only used by symbolic breakpoints) +- [ ] **module**: **String** - Breakpoint module (only used by symbolic breakpoints) +- [ ] **scope**: **String** - Breakpoint scope (only used by exception breakpoints) + - `All` + - `Objective-C` (default) + - `C++` +- [ ] **stopOnStyle**: **String** - Indicates if should stop on style (only used by exception breakpoints) + -`throw` (default) + -`catch` +- [ ] **condition**: **String** - Breakpoint condition +- [ ] **actions**: **[[Breakpoint Action](#breakpoint-action)]** - breakpoint actions + +```yaml +breakpoints: + - type: ExceptionBreakpoint + enabled: true + ignoreCount: 0 + continueAfterRunningActions: false +``` + +#### Breakpoint Action + +- [x] **type**: **String** - Breakpoint action type + - `DebuggerCommand`: execute debugger command + - `Log`: log message + - `ShellCommand`: execute shell command + - `GraphicsTrace`: capture GPU frame + - `AppleScript`: execute AppleScript + - `Sound`: play sound +- [ ] **command**: **String** - Debugger command (only used by debugger command breakpoint action) +- [ ] **message**: **String** - Log message (only used log message breakpoint action) +- [ ] **conveyanceType**: **String** - Conveyance type (only used by log message breakpoint action) + - `console`: log message to console (default) + - `speak`: speak message +- [ ] **path**: **String** - Shell command file path (only used by shell command breakpoint action) +- [ ] **arguments**: **String** - Shell command arguments (only used by shell command breakpoint action) +- [ ] **waitUntilDone**: **Bool** - Indicates whether it should wait until done (only used by shell command breakpoint action). Default to `false` +- [ ] **script**: **String** - AppleScript (only used by AppleScript breakpoint action) +- [ ] **sound**: **String** - Sound name (only used by sound breakpoint action) + - `Basso` (default) + - `Blow` + - `Bottle` + - `Frog` + - `Funk` + - `Glass` + - `Hero` + - `Morse` + - `Ping` + - `Pop` + - `Purr` + - `Sosumi` + - `Submarine` + - `Tink` + +```yaml +actions: + - type: Sound + sound: Blow +``` + ### Configs -Each config maps to a build type of either `debug` or `release` which will then apply default build settings to the project. Any value other than `debug` or `release` (for example `none`), will mean no default build settings will be applied to the project. +Each config maps to a build type of either `debug` or `release` which will then apply default `Build Settings` to the project. Any value other than `debug` or `release` (for example `none`), will mean no default `Build Settings` will be applied to the project. ```yaml configs: @@ -165,61 +282,92 @@ If no configs are specified, default `Debug` and `Release` configs will be creat ### Setting Groups -Setting groups are named groups of build settings that can be reused elsewhere. Each preset is a [Settings](#settings) schema, so can include other groups +Setting groups are named groups of `Build Settings` that can be reused elsewhere. Each preset is a [Settings](#settings) schema, so can include other `groups` or define settings by `configs`. ```yaml settingGroups: - preset1: - BUILD_SETTING: value - preset2: + preset_generic: + CUSTOM_SETTING: value_custom + preset_debug: + BUILD_SETTING: value_debug + preset_release: base: - BUILD_SETTING: value + BUILD_SETTING: value_release + preset_all: groups: - - preset - preset3: - configs: - debug: - groups: - - preset + - preset_generic + configs: + debug: + groups: + - preset_debug + release: + groups: + - preset_release + +targets: + Application: + settings: + groups: + - preset_all ``` ## Settings -Settings can either be a simple map of build settings `[String:String]`, or can be more advanced with the following properties: +Settings correspond to `Build Settings` tab in Xcode. To display Setting Names instead of Setting Titles, select `Editor -> Show Setting Names` in Xcode. + +Settings can either be a simple map of `Build Settings` `[String:String]`, or can be more advanced with the following properties: -- [ ] **groups**: **[String]** - List of setting groups to include and merge +- [ ] **groups**: **[String]** - List of [Setting Groups](#setting-groups) to include and merge - [ ] **configs**: **[String:[Settings](#settings)]** - Mapping of config name to a settings spec. These settings will only be applied for that config. Each key will be matched to any configs that contain the key and is case insensitive. So if you had `Staging Debug` and `Staging Release`, you could apply settings to both of them using `staging`. However if a config name is an exact match to a config it won't be applied to any others. eg `Release` will be applied to config `Release` but not `Staging Release` - [ ] **base**: **[String:String]** - Used to specify default settings that apply to any config ```yaml settings: - BUILD_SETTING_1: value 1 - BUILD_SETTING_2: value 2 + GENERATE_INFOPLIST_FILE: NO + CODE_SIGNING_ALLOWED: NO + WRAPPER_EXTENSION: bundle ``` +Don't mix simple maps with `groups`, `base` and `configs`. +If `groups`, `base`, `configs` are used then simple maps is silently ignored. + +In this example, `CURRENT_PROJECT_VERSION` will be set, but `MARKETING_VERSION` will be ignored: ```yaml settings: + MARKETING_VERSION: 100.0.0 base: - BUILD_SETTING_1: value 1 + CURRENT_PROJECT_VERSION: 100.0 +``` + +```yaml +settings: + base: + PRODUCT_NAME: XcodeGenProduct configs: - my_config: - BUILD_SETTING_2: value 2 + debug: + CODE_SIGN_IDENTITY: iPhone Developer + PRODUCT_BUNDLE_IDENTIFIER: com.tomtom.debug_app + release: + CODE_SIGN_IDENTITY: iPhone Distribution + PRODUCT_BUNDLE_IDENTIFIER: com.tomtom.app + PROVISIONING_PROFILE_SPECIFIER: "Xcodegen Release" groups: - my_settings ``` -Settings are merged in the following order: groups, base, configs. +Settings are merged in the following order: `groups`, `base`, `configs` (simple maps are ignored). ## Target - [x] **type**: **[Product Type](#product-type)** - Product type of the target - [x] **platform**: **[Platform](#platform)** - Platform of the target +- [ ] **supportedDestinations**: **[[Supported Destinations](#supported-destinations)]** - List of supported platform destinations for the target. - [ ] **deploymentTarget**: **String** - The deployment target (eg `9.2`). If this is not specified the value from the project set in [Options](#options)`.deploymentTarget.PLATFORM` will be used. - [ ] **sources**: **[Sources](#sources)** - Source directories of the target - [ ] **configFiles**: **[Config Files](#config-files)** - `.xcconfig` files per config - [ ] **settings**: **[Settings](#settings)** - Target specific build settings. Default platform and product type settings will be applied first before any custom settings defined here. Other context dependant settings will be set automatically as well: - `INFOPLIST_FILE`: If it doesn't exist your sources will be searched for `Info.plist` files and the first one found will be used for this setting - - `FRAMEWORK_SEARCH_PATHS`: If carthage dependencies are used, the platform build path will be added to this setting + - `FRAMEWORK_SEARCH_PATHS`: If carthage framework dependencies are used, the platform build path will be added to this setting - `OTHER_LDFLAGS`: See `requiresObjCLinking` below - `TEST_TARGET_NAME`: for ui tests that target an application - `TEST_HOST`: for unit tests that target an application @@ -237,9 +385,10 @@ Settings are merged in the following order: groups, base, configs. - [ ] **templates**: **[String]** - A list of [Target Templates](#target-template) referenced by name that will be merged with the target in order. Any instances of `${target_name}` within these templates will be replaced with the target name. - [ ] **templateAttributes**: **[String: String]** - A list of attributes where each instance of `${attributeName}` within the templates listed in `templates` will be replaced with the value specified. - [ ] **transitivelyLinkDependencies**: **Bool** - If this is not specified the value from the project set in [Options](#options)`.transitivelyLinkDependencies` will be used. -- [ ] **directlyEmbedCarthageDependencies**: **Bool** - If this is `true` Carthage dependencies will be embedded using an `Embed Frameworks` build phase instead of the `copy-frameworks` script. Defaults to `true` for all targets except iOS/tvOS/watchOS Applications. -- [ ] **requiresObjCLinking**: **Bool** - If this is `true` any targets that link to this target will have `-ObjC` added to their `OTHER_LDFLAGS`. This is required if a static library has any catagories or extensions on Objective-C code. See [this guide](https://pewpewthespells.com/blog/objc_linker_flags.html#objc) for more details. Defaults to `true` if `type` is `library.static`. If you are 100% sure you don't have catagories or extensions on Objective-C code (pure Swift with no use of Foundation/UIKit) you can set this to `false`, otherwise it's best to leave it alone. -- [ ]**onlyCopyFilesOnInstall**: **Bool** – If this is `true`, the `Embed Frameworks` build phase will have the "Copy only when installing" chekbox checked. Defaults to `false`. +- [ ] **directlyEmbedCarthageDependencies**: **Bool** - If this is `true` Carthage framework dependencies will be embedded using an `Embed Frameworks` build phase instead of the `copy-frameworks` script. Defaults to `true` for all targets except iOS/tvOS/watchOS Applications. +- [ ] **requiresObjCLinking**: **Bool** - If this is `true` any targets that link to this target will have `-ObjC` added to their `OTHER_LDFLAGS`. This is required if a static library has any categories or extensions on Objective-C code. See [this guide](https://pewpewthespells.com/blog/objc_linker_flags.html#objc) for more details. Defaults to `true` if `type` is `library.static`. If you are 100% sure you don't have categories or extensions on Objective-C code (pure Swift with no use of Foundation/UIKit) you can set this to `false`, otherwise it's best to leave it alone. +- [ ] **onlyCopyFilesOnInstall**: **Bool** – If this is `true`, the `Embed Frameworks` and `Embed App Extensions` (if available) build phases will have the "Copy only when installing" chekbox checked. Defaults to `false`. +- [ ] **buildToolPlugins**: **[[Build Tool Plug-ins](#build-tool-plug-ins)]** - Commands for the build system that run automatically *during* the build. - [ ] **preBuildScripts**: **[[Build Script](#build-script)]** - Build scripts that run *before* any other build phases - [ ] **postCompileScripts**: **[[Build Script](#build-script)]** - Build scripts that run after the Compile Sources phase - [ ] **postBuildScripts**: **[[Build Script](#build-script)]** - Build scripts that run *after* any other build phases @@ -250,23 +399,27 @@ Settings are merged in the following order: groups, base, configs. - `DevelopmentTeam`: if all configurations have the same `DEVELOPMENT_TEAM` setting - `ProvisioningStyle`: if all configurations have the same `CODE_SIGN_STYLE` setting - `TestTargetID`: if all configurations have the same `TEST_TARGET_NAME` setting +- [ ] **putResourcesBeforeSourcesBuildPhase**: **Bool** - If this is `true` the `Copy Resources` step will be placed before the `Compile Sources` build step. ### Product Type This will provide default build settings for a certain product type. It can be any of the following: - `application` +- `application.on-demand-install-capable` - `application.messages` - `application.watchapp` - `application.watchapp2` +- `application.watchapp2-container` - `app-extension` +- `app-extension.intents-service` - `app-extension.messages` - `app-extension.messages-sticker-pack` -- `app-extension.intents-service` - `bundle` -- `bundle.unit-test` -- `bundle.ui-testing` - `bundle.ocunit-test` +- `bundle.ui-testing` +- `bundle.unit-test` +- `extensionkit-extension` - `framework` - `instruments-package` - `library.dynamic` @@ -276,8 +429,9 @@ This will provide default build settings for a certain product type. It can be a - `tv-app-extension` - `watchkit-extension` - `watchkit2-extension` -- `watchapp2-container` - `xcode-extension` +- `driver-extension` +- `system-extension` - `xpc-service` - ``""`` (used for legacy targets) @@ -285,10 +439,14 @@ This will provide default build settings for a certain product type. It can be a This will provide default build settings for a certain platform. It can be any of the following: +- `auto` (available only when we use `supportedDestinations`) - `iOS` - `tvOS` - `macOS` - `watchOS` +- `visionOS` (`visionOS` doesn't support Carthage usage) + +Note that when we use supported destinations with Xcode 14+ we can avoid the definition of platform that fallbacks to the `auto` value. **Multi Platform targets** @@ -320,6 +478,34 @@ targets: The above will generate 2 targets named `MyFramework_iOS` and `MyFramework_tvOS`, with all the relevant platform build settings. They will both have a `PRODUCT_NAME` of `MyFramework` +### Supported Destinations + +This will provide a mix of default build settings for the chosen platform destinations. It can be any of the following: + +- `iOS` +- `tvOS` +- `macOS` +- `macCatalyst` +- `visionOS` +- `watchOS` + +```yaml +targets: + MyFramework: + type: framework + supportedDestinations: [iOS, tvOS] + deploymentTarget: + iOS: 9.0 + tvOS: 10.0 + sources: + - path: MySources + inferDestinationFiltersByPath: true + - path: OtherSources + destinationFilters: [iOS] +``` + +Note that the definition of supported destinations can be applied to almost every type of bundle making everything more easy to manage (app targets, unit tests, UI tests etc). App targets currently do not support the watchOS destination. Create a separate target using `platform` for watchOS apps. See Apple's [Configuring a multiplatform app](https://developer.apple.com/documentation/xcode/configuring-a-multiplatform-app-target) for details. + ### Sources Specifies the source directories for a target. This can either be a single source or a list of sources. Applicable source files, resources, headers, and `.lproj` files will be parsed appropriately. @@ -331,10 +517,12 @@ A source can be provided via a string (the path) or an object of the form: - [x] **path**: **String** - The path to the source file or directory. - [ ] **name**: **String** - Can be used to override the name of the source file or directory. By default the last component of the path is used for the name - [ ] **group**: **String** - Can be used to override the parent group of the source file or directory. By default a group is created at the root with the name of this source file or directory or intermediate groups are created if `createIntermediateGroups` is set to `true`. Multiple groups can be created by separating each one using a `/`. If multiple target sources share the same `group`, they will be put together in the same parent group. -- [ ] **compilerFlags**: **[String]** or **String** - A list of compilerFlags to add to files under this specific path provided as a list or a space delimitted string. Defaults to empty. +- [ ] **compilerFlags**: **[String]** or **String** - A list of compilerFlags to add to files under this specific path provided as a list or a space delimited string. Defaults to empty. - [ ] **excludes**: **[String]** - A list of [global patterns](https://en.wikipedia.org/wiki/Glob_(programming)) representing the files to exclude. These rules are relative to `path` and _not the directory where `project.yml` resides_. XcodeGen uses Bash 4's Glob behaviors where globstar (**) is enabled. - [ ] **includes**: **[String]** - A list of global patterns in the same format as `excludes` representing the files to include. These rules are relative to `path` and _not the directory where `project.yml` resides_. If **excludes** is present and file conflicts with **includes**, **excludes** will override the **includes** behavior. -- [ ] **createIntermediateGroups**: **Bool** - This overrides the value in [Options](#options) +- [ ] **destinationFilters**: **[[Supported Destinations](#supported-destinations)]** - List of supported platform destinations the files should filter to. Defaults to all supported destinations. +- [ ] **inferDestinationFiltersByPath**: **Bool** - This is a convenience filter that helps you to filter the files if their paths match these patterns `**//*` or `*_.swift`. Note, if you use `destinationFilters` this flag will be ignored. +- [ ] **createIntermediateGroups**: **Bool** - This overrides the value in [Options](#options). - [ ] **optional**: **Bool** - Disable missing path check. Defaults to false. - [ ] **buildPhase**: **String** - This manually sets the build phase this file or files in this directory will be added to, otherwise XcodeGen will guess based on the file extension. Note that `Info.plist` files will never be added to any build phases, no matter what this setting is. Possible values are: - `sources` - Compile Sources phase @@ -358,6 +546,7 @@ A source can be provided via a string (the path) or an object of the form: - `file`: a file reference with a parent group will be created (Default for files or directories with extensions) - `group`: a group with all it's containing files. (Default for directories without extensions) - `folder`: a folder reference. + - `syncedFolder`: Xcode 16's synchronized folders, also knows as buildable folders - [ ] **headerVisibility**: **String** - The visibility of any headers. This defaults to `public`, but can be either: - `public` - `private` @@ -370,20 +559,23 @@ targets: MyTarget: sources: MyTargetSource MyOtherTarget: + supportedDestinations: [iOS, tvOS] sources: - MyOtherTargetSource1 - path: MyOtherTargetSource2 + inferDestinationFiltersByPath: true name: MyNewName excludes: - "ios/*.[mh]" - "configs/server[0-2].json" - "*-Private.h" - "**/*.md" # excludes all files with the .md extension - - "ios/**/*Tests.[hm] # excludes all files with an h or m extension within the ios directory. + - "ios/**/*Tests.[hm]" # excludes all files with an h or m extension within the ios directory. compilerFlags: - "-Werror" - "-Wextra" - path: MyOtherTargetSource3 + destinationFilters: [iOS] compilerFlags: "-Werror -Wextra" - path: ModuleMaps buildPhase: @@ -401,8 +593,8 @@ targets: A dependency can be one of a 6 types: - `target: name` - links to another target. If you are using project references you can specify a target within another project by using `ProjectName/TargetName` for the name -- `framework: path` - links to a framework -- `carthage: name` - helper for linking to a Carthage framework +- `framework: path` - links to a framework or XCFramework +- `carthage: name` - helper for linking to a Carthage framework (not XCFramework) - `sdk: name` - links to a dependency with the SDK. This can either be a relative path within the sdk root or a single filename that references a framework (.framework) or lib (.tbd) - `package: name` - links to a Swift Package. The name must match the name of a package defined in the top level `packages` - `bundle: name` - adds the pre-built bundle for the supplied name to the copy resources build phase. This is useful when a dependency exists on a static library target that has an associated bundle target, both existing in a separate project. Only usable in target types which can copy resources. @@ -411,9 +603,25 @@ A dependency can be one of a 6 types: - [ ] **embed**: **Bool** - Whether to embed the dependency. Defaults to true for application target and false for non application targets. - [ ] **link**: **Bool** - Whether to link the dependency. Defaults to `true` depending on the type of the dependency and the type of the target (e.g. static libraries will only link to executables by default). -- [ ] **codeSign**: **Bool** - Whether the `codeSignOnCopy` setting is applied when embedding framework. Defaults to true -- [ ] **removeHeaders**: **Bool** - Whether the `removeHeadersOnCopy` setting is applied when embedding the framework. Defaults to true -- [ ] **weak**: **Bool** - Whether the `Weak` setting is applied when linking the framework. Defaults to false +- [ ] **codeSign**: **Bool** - Whether the `codeSignOnCopy` setting is applied when embedding framework. Defaults to true. +- [ ] **removeHeaders**: **Bool** - Whether the `removeHeadersOnCopy` setting is applied when embedding the framework. Defaults to true. +- [ ] **weak**: **Bool** - Whether the `Weak` setting is applied when linking the framework. Defaults to false. +- [ ] **platformFilter**: **String** - This field is specific to Mac Catalyst. It corresponds to the "Platforms" dropdown in the Frameworks & Libraries section of Target settings in Xcode. Available options are: **iOS**, **macOS** and **all**. Defaults is **all**. +- [ ] **destinationFilters**: **[[Supported Destinations](#supported-destinations)]** - List of supported platform destinations this dependency should filter to. Defaults to all supported destinations. +- [ ] **platforms**: **[[Platform](#platform)]** - List of platforms this dependency should apply to. Defaults to all applicable platforms. +- **copy** - Copy Files Phase for this dependency. This only applies when `embed` is true. Must be specified as an object with the following fields: + - [x] **destination**: **String** - Destination of the Copy Files phase. This can be one of the following values: + - `absolutePath` + - `productsDirectory` + - `wrapper` + - `executables` + - `resources` + - `javaResources` + - `frameworks` + - `sharedFrameworks` + - `sharedSupport` + - `plugins` + - [ ] **subpath**: **String** - The path inside of the destination to copy the files. **Implicit Framework options**: @@ -432,6 +640,9 @@ Carthage frameworks are expected to be in `CARTHAGE_BUILD_PATH/PLATFORM/FRAMEWOR - `PLATFORM` = the target's platform - `FRAMEWORK` = the specified name. + To link an XCFramework produced by Carthage (in `CARTHAGE_BUILD_PATH/FRAMEWORK.xcframework`), use a normal `framework:` + dependency. The helper logic provided by this dependency type is not necessary. + All the individual frameworks of a Carthage dependency can be automatically found via `findFrameworks: true`. This overrides the value of [Options](#options).findCarthageFrameworks. Otherwise each one will have to be listed individually. Xcodegen uses `.version` files generated by Carthage in order for this framework lookup to work, so the Carthage dependencies will need to have already been built at the time XcodeGen is run. @@ -446,13 +657,17 @@ projectReferences: path: path/to/FooLib.xcodeproj targets: MyTarget: + supportedDestinations: [iOS, tvOS] dependencies: - target: MyFramework + destinationFilters: [iOS] - target: FooLib/FooTarget - framework: path/to/framework.framework + destinationFilters: [tvOS] - carthage: Result findFrameworks: false linkType: static + destinationFilters: [iOS] - sdk: Contacts.framework - sdk: libc++.tbd - sdk: libz.dylib @@ -478,7 +693,8 @@ targets: ``` **Package dependency** -- [ ] **product**: **String** - The product to use from the package. This defaults to the package name, so is only required if a Package has multiple libraries or a library with a differing name +- [ ] **product**: **String** - The product to use from the package. This defaults to the package name, so is only required if a Package has multiple libraries or a library with a differing name. Use this over `products` when you want to define different linking options per product. +- [ ] **products**: **String** - A list of products to use from the package. This can be used when depending on multiple products from a package. ```yaml packages: @@ -496,6 +712,21 @@ targets: product: SPMUtility ``` +Depending on multiple products from a package: + +```yaml +packages: + FooFeature: + path: Packages/FooFeature +targets: + App: + dependencies: + - package: FooFeature + products: + - FooDomain + - FooUI +``` + ### Config Files Specifies `.xcconfig` files for each configuration. @@ -530,6 +761,36 @@ targets: com.apple.security.application-groups: group.com.app ``` +### Build Tool Plug-ins + +To add `Build Tool Plug-ins`, you need to add information about plugins to [Target](#target): + +- **buildToolPlugins**: List of plugins to connect to the target + +Each plugin includes information: + +- [x] **plugin**: **String** - plugin name +- [x] **package**: **String** - the name of the package that contains the plugin + +Сonnect the plugin to the desired target: + +```yaml +targets: + App: + buildToolPlugins: + - plugin: MyPlugin + package: MyPackage +``` + +Don't forget to add a package containing the plugin we need: + +```yaml +packages: + MyPackage: + url: https://github.com/MyPackage + from: 1.3.0 +``` + ### Build Script Run script build phases can be added at 3 different points in the build: @@ -548,8 +809,10 @@ Each script can contain: - [ ] **inputFileLists**: **[String]** - list of input .xcfilelist - [ ] **outputFileLists**: **[String]** - list of output .xcfilelist - [ ] **shell**: **String** - shell used for the script. Defaults to `/bin/sh` -- [ ] **showEnvVars**: **Bool** - whether the environment variables accessible to the script show be printed to the build log. Defaults to yes -- [ ] **runOnlyWhenInstalling**: **Bool** - whether the script is only run when installing (`runOnlyForDeploymentPostprocessing`). Defaults to no +- [ ] **showEnvVars**: **Bool** - whether the environment variables accessible to the script show be printed to the build log. Defaults to `true` +- [ ] **runOnlyWhenInstalling**: **Bool** - whether the script is only run when installing (`runOnlyForDeploymentPostprocessing`). Defaults to `false` +- [ ] **basedOnDependencyAnalysis**: **Bool** - whether to skip the script if inputs, context, or outputs haven't changed. Defaults to `true` +- [ ] **discoveredDependencyFile**: **String** - discovered dependency .d file. Defaults to none Either a **path** or **script** must be defined, the rest are optional. @@ -571,6 +834,7 @@ targets: - $(DERIVED_FILE_DIR)/file2 outputFileLists: - $(SRCROOT)/outputFiles.xcfilelist + discoveredDependencyFile: $(DERIVED_FILE_DIR)/target.d postCompileScripts: - script: swiftlint name: Swiftlint @@ -591,6 +855,7 @@ targets: - [ ] **name**: **String** - The name of a build rule. Defaults to `Build Rule` - [ ] **outputFiles**: **[String]** - The list of output files - [ ] **outputFilesCompilerFlags**: **[String]** - The list of compiler flags to apply to the output files +- [ ] **runOncePerArchitecture**: **Bool** - a boolean that indicates if this rule should run once per architecture. This defaults to true ```yaml targets: @@ -605,24 +870,30 @@ targets: compilerSpec: com.apple.xcode.tools.swift.compiler outputFiles: - $(SRCROOT)/Generated.swift + runOncePerArchitecture: false ``` -### Target Scheme +### Target Scheme This is a convenience used to automatically generate schemes for a target based on different configs or included tests. If you want more control check out the top level [Scheme](#scheme). - [x] **configVariants**: **[String]** - This generates a scheme for each entry, using configs that contain the name with debug and release variants. This is useful for having different environment schemes. - [ ] **testTargets**: **[[Test Target](#test-target)]** - a list of test targets that should be included in the scheme. These will be added to the build targets and the test entries. Each entry can either be a simple string, or a [Test Target](#test-target) - [ ] **gatherCoverageData**: **Bool** - a boolean that indicates if this scheme should gather coverage data. This defaults to false +- [ ] **coverageTargets**: **[[Testable Target Reference](#testable-target-reference) - a list of targets to gather code coverage. Each entry can either be a simple string, a string using [Project Reference](#project-reference) or [Testable Target Reference](#testable-target-reference) - [ ] **disableMainThreadChecker**: **Bool** - a boolean that indicates if 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 +- [ ] **disableThreadPerformanceChecker**: **Bool** - a boolean that indicates if this scheme should disable the Thread Performance Checker. This defaults to false - [ ] **buildImplicitDependencies**: **Bool** - Flag to determine if Xcode should build implicit dependencies of this scheme. By default this is `true` if not set. - [ ] **language**: **String** - a String that indicates the language used for running and testing. This defaults to nil - [ ] **region**: **String** - a String that indicates the region used for running and testing. This defaults to nil - [ ] **commandLineArguments**: **[String:Bool]** - a dictionary from the argument name (`String`) to if it is enabled (`Bool`). These arguments will be added to the Test, Profile and Run scheme actions - [ ] **environmentVariables**: **[[Environment Variable](#environment-variable)]** or **[String:String]** - environment variables for Run, Test and Profile scheme actions. When passing a dictionary, every key-value entry maps to a corresponding variable that is enabled. +- [ ] **testPlans**: **[[Test Plan](#test-plan)]** - List of test plan locations that will be referenced in the scheme. - [ ] **preActions**: **[[Execution Action](#execution-action)]** - Scripts that are run *before* the build action - [ ] **postActions**: **[[Execution Action](#execution-action)]** - Scripts that are run *after* the build action +- [ ] **management**: **[Scheme Management](#scheme-management)** - Management options for the scheme +- [ ] **storeKitConfiguration**: **String** - specify storekit configuration to use during run. See [Options](#options). For example, the spec below would create 3 schemes called: @@ -651,6 +922,9 @@ targets: - Staging - Production gatherCoverageData: true + coverageTargets: + - MyTarget1 + - ExternalTarget/OtherTarget1 commandLineArguments: "-MyEnabledArg": true "-MyDisabledArg": false @@ -660,7 +934,7 @@ targets: sources: Tests ``` -### Legacy Target +### Legacy Target By providing a legacy target, you are opting in to the "Legacy Target" mode. This is the "External Build Tool" from the Xcode GUI. This is useful for scripts that you want to run as dependencies of other targets, but you want to make sure that it only runs once even if it is specified as a dependency from multiple other targets. @@ -676,13 +950,14 @@ This is used to override settings or run build scripts in specific targets - [x] **targets**: **[String]** - The list of target names to include as target dependencies - [ ] **configFiles**: **[Config Files](#config-files)** - `.xcconfig` files per config - [ ] **settings**: **[Settings](#settings)** - Target specific build settings. +- [ ] **buildToolPlugins**: **[[Build Tool Plug-ins](#build-tool-plug-ins)]** - Commands for the build system that run automatically *during* the build - [ ] **buildScripts**: **[[Build Script](#build-script)]** - Build scripts to run - [ ] **scheme**: **[Target Scheme](#target-scheme)** - Generated scheme - [ ] **attributes**: **[String: Any]** - This sets values in the project `TargetAttributes`. It is merged with `attributes` from the project and anything automatically added by XcodeGen, with any duplicate values being override by values specified here ## 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}`. @@ -714,6 +989,7 @@ Schemes allows for more control than the convenience [Target Scheme](#target-sch - [ ] ***profile***: The profile action - [ ] ***analyze***: The analyze action - [ ] ***archive***: The archive action +- [ ] ***management***: management metadata ### Build @@ -732,6 +1008,11 @@ Schemes allows for more control than the convenience [Target Scheme](#target-sch - `true`: Discover implicit dependencies of this scheme - `false`: Only build explicit dependencies of this scheme +- [ ] **runPostActionsOnFailure**: **Bool** - Flag to determine if Xcode should run post scripts despite failure build. By default this is `false` if not set. +- `true`: Run post scripts even if build is failed +- `false`: Only run post scripts if build success + + ```yaml targets: MyTarget: all @@ -751,14 +1032,19 @@ 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`. +- [ ] **enableGPUValidationMode**: **Bool** - Property value set for `Metal API Validation`. This defaults to true. - [ ] **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 +- [ ] **disableThreadPerformanceChecker**: **Bool** - `run` action can define a boolean that indicates that this scheme should disable the Thread Performance Checker. This defaults to false - [ ] **language**: **String** - `run` and `test` actions can define a language that is used for Application Language - [ ] **region**: **String** - `run` and `test` actions can define a language that is used for Application Region - [ ] **debugEnabled**: **Bool** - `run` and `test` actions can define a whether debugger should be used. This defaults to true. - [ ] **simulateLocation**: **[Simulate Location](#simulate-location)** - `run` action can define a simulated location -- [ ] **askForAppToLaunch**: **Bool** - `run` action can define the executable set to ask to launch. This defaults to false. +- [ ] **askForAppToLaunch**: **Bool** - `run` and `profile` actions can define the executable set to ask to launch. This defaults to false. - [ ] **launchAutomaticallySubstyle**: **String** - `run` action can define the launch automatically substyle ('2' for extensions). +- [ ] **storeKitConfiguration**: **String** - `run` action can specify a storekit configuration. See [Options](#options). +- [ ] **macroExpansion**: **String** - `run` and `test` actions can define the macro expansion from other target. This defaults to nil. ### Execution Action @@ -771,19 +1057,43 @@ Scheme run scripts added via **preActions** or **postActions**. They run before A multiline script can be written using the various YAML multiline methods, for example with `|`. See [Build Script](#build-script). ### Run Action -- [ ] **executable**: **String** - the name of the target to launch as an executable. Defaults to the first build target in the scheme +- [ ] **executable**: **String** - the name of the target to launch as an executable. Defaults to the first runnable build target in the scheme, or the first build target if a runnable build target is not found +- [ ] **customLLDBInit**: **String** - the absolute path to the custom `.lldbinit` file +- [ ] **customWorkingDirectory**: **String** - a path to use as the working directory when launching the executable. ### Test Action - [ ] **gatherCoverageData**: **Bool** - a boolean that indicates if this scheme should gather coverage data. This defaults to false -- [ ] **coverageTargets**: **[String]** - a list of targets to gather code coverage. Each entry can either be a simple string, or a string using [Project Reference](#project-reference) +- [ ] **coverageTargets**: **[[Testable Target Reference](#testable-target-reference)]** - a list of targets to gather code coverage. Each entry can either be a simple string, a string using [Project Reference](#project-reference) or [Testable Target Reference](#testable-target-reference) - [ ] **targets**: **[[Test Target](#test-target)]** - a list of targets to test. Each entry can either be a simple string, or a [Test Target](#test-target) +- [ ] **customLLDBInit**: **String** - the absolute path to the custom `.lldbinit` file +- [ ] **captureScreenshotsAutomatically**: **Bool** - indicates whether screenshots should be captured automatically while UI Testing. This defaults to true. +- [ ] **deleteScreenshotsWhenEachTestSucceeds**: **Bool** - whether successful UI tests should cause automatically-captured screenshots to be deleted. If `captureScreenshotsAutomatically` is false, this value is ignored. This defaults to true. +- [ ] **testPlans**: **[[Test Plan](#test-plan)]** - List of test plan locations that will be referenced in the scheme. +- [ ] **preferredScreenCaptureFormat**: **String** - automatic screen capture format to use while UI Testing. Possible values are `screenshots`, `screenRecording`. Default is `screenRecording`. #### Test Target -- [x] **name**: **String** - The name of the target +A target can be one of a 2 types: + +- **name**: **String** - The name of the target. +- **target**: **[Testable Target Reference](#testable-target-reference)** - The information of the target. You can specify more detailed information than `name:`. + +As syntax sugar, you can also specify **[Testable Target Reference](#testable-target-reference)** without `target`. + +#### Other Parameters + - [ ] **parallelizable**: **Bool** - Whether to run tests in parallel. Defaults to false - [ ] **randomExecutionOrder**: **Bool** - Whether to run tests in a random order. Defaults to false -- [ ] **skippedTests**: **[String]** - List of tests in the test target to skip. Defaults to empty. +- [ ] **location**: **String** - GPX file or predefined value for simulating location. See [Simulate Location](#simulate-location) for location examples. +- [ ] **skipped**: **Bool** - Whether to skip all of the test target tests. Defaults to false +- [ ] **skippedTests**: **[String]** - List of tests in the test target to skip. Defaults to empty +- [ ] **selectedTests**: **[String]** - List of tests in the test target to whitelist and select. Defaults to empty. This will override `skippedTests` if provided + +#### Testable Target Reference +A Testable Target Reference can be one of 3 types: +- `package: {local-swift-package-name}/{target-name}`: Name of local swift package and its target. +- `local: {target-name}`: Name of local target. +- `project: {project-reference-name}/{target-name}`: Name of local swift package and its target. ### Archive Action @@ -816,6 +1126,12 @@ targets: - location.gpx ``` +Note that the path the gpx file will be prefixed according to the `schemePathPrefix` option in order to support both `.xcodeproj` and `.xcworkspace` setups. See [Options](#options). + +### Scheme Management +- [ ] **shared**: **Bool** - indicates whether the scheme is shared +- [ ] **orderHint**: **Int** - used by Xcode to sort the schemes +- [ ] **isShown**: **Bool** - indicates whether the sheme is shown in the scheme list ### Environment Variable @@ -832,22 +1148,30 @@ schemes: MyTarget2: [run, archive] run: config: prod-debug - commandLineArguments: "--option value" + commandLineArguments: + "-MyEnabledArg": true + "-MyDisabledArg": false environmentVariables: RUN_ENV_VAR: VALUE test: config: prod-debug - commandLineArguments: "--option testValue" + commandLineArguments: + "-MyEnabledArg": true + "-MyDisabledArg": false gatherCoverageData: true coverageTargets: - MyTarget1 - ExternalTarget/OtherTarget1 + - package: LocalPackage/TestTarget targets: - Tester1 - name: Tester2 parallelizable: true randomExecutionOrder: true skippedTests: [Test/testExample()] + - package: APIClient/APIClientTests + parallelizable: true + randomExecutionOrder: true environmentVariables: - variable: TEST_ENV_VAR value: VALUE @@ -862,7 +1186,22 @@ schemes: revealArchiveInOrganizer: false ``` -### Scheme Template +### Test Plan +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. + +- [x] **path**: **String** - path that provides the `xctestplan` location. +- [ ] **defaultPlan**: **Bool** - a bool that defines if given plan is the default one. Defaults to false. If no default is set on any test plan, the first plan is set as the default. + +```yaml +schemes: + TestTarget: + test: + testPlans: + - path: app.xctestplan + defaultPlan: true +``` + +## Scheme Template This is a template that can be referenced from a normal scheme using the `templates` property. The properties of this template are the same as a [Scheme](#scheme). This functions identically in practice to [Target Template](#target-template). Any instances of `${scheme_name}` within each template will be replaced by the final scheme name which references the template. @@ -898,8 +1237,6 @@ The result will be a scheme that builds `MyModule` when you request a build, and ## Swift Package Swift packages are defined at a project level, and then linked to individual targets via a [Dependency](#dependency). -> Note that Swift Packages don't work in projects with configurations other than `Debug` and `Release`. That limitation is tracked here bugs.swift.org/browse/SR-10927 - ### Remote Package - [x] **url**: **URL** - the url to the package @@ -910,23 +1247,28 @@ Swift packages are defined at a project level, and then linked to individual tar - `minVersion: 1.0.0, maxVersion: 1.2.9` - `branch: master` - `revision: xxxxxx` +- [ ] **github** : **String**- this is an optional helper you can use for github repos. Instead of specifying the full url in `url` you can just specify the github org and repo ### Local Package - [x] **path**: **String** - the path to the package in local. The path must be directory with a `Package.swift`. +- [ ] **group** : **String**- Optional path that specifies the location where the package will live in your xcode project. Use `""` to specify the project root. +- [ ] **excludeFromProject** : **String**- Optional flag to exclude the package from the generated project (useful if the package is already added via xcworkspace and the project is not intended for standalone use), defaults to `false` ```yml packages: Yams: url: https://github.com/jpsim/Yams from: 2.0.0 + Ink: + github: JohnSundell/Ink + from: 0.5.0 RxClient: path: ../RxClient -targets: - App: - dependencies: - - package: Yams - - package: RxClient + AppFeature: + path: ../Packages + group: Domains/AppFeature + excludeFromProject: false ``` ## Project Reference diff --git a/Docs/Usage.md b/Docs/Usage.md index 597bf8a4e..390cf5875 100644 --- a/Docs/Usage.md +++ b/Docs/Usage.md @@ -36,7 +36,7 @@ The values from [xcconfig files](#xcconfig-files) will then sit a level above th XcodeGen applies default settings to your project and targets similar to how Xcode creates them when you create a new project or target. Debug and Release settings will be applied to your project. Targets will also get specific settings depending on the platform and product type. ->You can change or disable how these setting presets are applied via the `options.settingPresets` which you can find more about in [Options](#options) +>You can change or disable how these setting presets are applied via the `options.settingPresets` which you can find more about in [Options](ProjectSpec.md#options) ### Settings The `project` and each `target` have a `settings` object that you can define. This can be a simple map of build settings or can provide build settings per `config` via `configs` or `base`. See [Settings](ProjectSpec.md#settings) for more details. @@ -87,7 +87,7 @@ targets: ``` ### xcodebuild environment variables -You can also always overide any build settings on CI when building by passing specific build settings to xcodebuild like so: +You can also always override any build settings on CI when building by passing specific build settings to xcodebuild like so: ```sh DEVELOPMENT_TEAM=XXXXXXXXX xcodebuild ... @@ -127,7 +127,7 @@ targets: - carthage: ReactiveMapKit ``` -XcodeGen can look these up for you automatically! This can be enabled with a global `options.findCarthageFrameworks` or can be overriden for each Carthage dependency. Note that if this is enabled, the Carthage dependencies need to have already been built before XcodeGen is run. This is because XcodeGen loads `.version` files that Carthage writes in the `Carthage/Build` directory which lists the all the frameworks. The name you use must also be the name of the `.version` file Carthage writes to `Carthage/Build`. Be aware that in some cases this name can differ from the name of the repo in the Cartfile and even the framework name. If the `.version` file is not found or fails parsing, XcodeGen will fallback to the regular Framework lookup in the relevant Carthage directory. +XcodeGen can look these up for you automatically! This can be enabled with a global `options.findCarthageFrameworks` or can be overridden for each Carthage dependency. Note that if this is enabled, the Carthage dependencies need to have already been built before XcodeGen is run. This is because XcodeGen loads `.version` files that Carthage writes in the `Carthage/Build` directory which lists the all the frameworks. The name you use must also be the name of the `.version` file Carthage writes to `Carthage/Build`. Be aware that in some cases this name can differ from the name of the repo in the Cartfile and even the framework name. If the `.version` file is not found or fails parsing, XcodeGen will fallback to the regular Framework lookup in the relevant Carthage directory. ```yml options: @@ -204,3 +204,20 @@ targets: dependencies: - framework: Vendor/MyFramework.framework ``` + +# Build Tool Plug-ins +XCodeGen supports working with [Swift Package Plug-ins](https://github.com/apple/swift-package-manager/blob/main/Documentation/Plugins.md#using-a-package-plugin). + +To use plugins, you need to specify in your target which plugin you want to connect, and don't forget to connect the package to target. + +```yaml +packages: + Prefire: + url: https://github.com/BarredEwe/Prefire + from: 1.3.0 +targets: + App: + buildToolPlugins: + - plugin: PrefirePlaybookPlugin + package: Prefire +``` diff --git a/Makefile b/Makefile index bbf78afa5..79a374054 100644 --- a/Makefile +++ b/Makefile @@ -1,25 +1,26 @@ TOOL_NAME = XcodeGen export EXECUTABLE_NAME = xcodegen -VERSION = 2.16.0 +VERSION = 2.44.1 PREFIX = /usr/local INSTALL_PATH = $(PREFIX)/bin/$(EXECUTABLE_NAME) SHARE_PATH = $(PREFIX)/share/$(EXECUTABLE_NAME) CURRENT_PATH = $(PWD) REPO = https://github.com/yonaskolb/$(TOOL_NAME) -RELEASE_TAR = $(REPO)/archive/$(VERSION).tar.gz -SHA = $(shell curl -L -s $(RELEASE_TAR) | shasum -a 256 | sed 's/ .*//') +SWIFT_BUILD_FLAGS = --disable-sandbox -c release --arch arm64 --arch x86_64 +BUILD_PATH = $(shell swift build $(SWIFT_BUILD_FLAGS) --show-bin-path) +EXECUTABLE_PATH = $(BUILD_PATH)/$(EXECUTABLE_NAME) -.PHONY: install build uninstall format_code brew release +.PHONY: install build uninstall format_code release install: build mkdir -p $(PREFIX)/bin - cp -f .build/release/$(EXECUTABLE_NAME) $(INSTALL_PATH) + cp -f $(EXECUTABLE_PATH) $(INSTALL_PATH) mkdir -p $(SHARE_PATH) cp -R $(CURRENT_PATH)/SettingPresets $(SHARE_PATH)/SettingPresets build: - swift build --disable-sandbox -c release + swift build $(SWIFT_BUILD_FLAGS) uninstall: rm -f $(INSTALL_PATH) @@ -36,12 +37,13 @@ release: git commit -m "Update to $(VERSION)" #git tag $(VERSION) -publish: archive brew +publish: archive echo "published $(VERSION)" -brew: - brew update - brew bump-formula-pr --url=$(RELEASE_TAR) XcodeGen - archive: build - ./scripts/archive.sh + ./scripts/archive.sh "$(EXECUTABLE_PATH)" + swift package plugin --allow-writing-to-package-directory generate-artifact-bundle \ + --package-version $(VERSION) \ + --executable-name $(EXECUTABLE_NAME) \ + --build-config release \ + --include-resource-path LICENSE diff --git a/Package.resolved b/Package.resolved index 6dc3e99de..c4dd4b065 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,106 +1,95 @@ { - "object": { - "pins": [ - { - "package": "AEXML", - "repositoryURL": "https://github.com/tadija/AEXML", - "state": { - "branch": null, - "revision": "e4d517844dd03dac557e35d77a8e9ab438de91a6", - "version": "4.4.0" - } - }, - { - "package": "GraphViz", - "repositoryURL": "https://github.com/SwiftDocOrg/GraphViz.git", - "state": { - "branch": null, - "revision": "08e0cddd013fa2272379d27ec3e0093db51f34fb", - "version": "0.1.0" - } - }, - { - "package": "JSONUtilities", - "repositoryURL": "https://github.com/yonaskolb/JSONUtilities.git", - "state": { - "branch": null, - "revision": "128d2ffc22467f69569ef8ff971683e2393191a0", - "version": "4.2.0" - } - }, - { - "package": "PathKit", - "repositoryURL": "https://github.com/kylef/PathKit.git", - "state": { - "branch": null, - "revision": "73f8e9dca9b7a3078cb79128217dc8f2e585a511", - "version": "1.0.0" - } - }, - { - "package": "Rainbow", - "repositoryURL": "https://github.com/onevcat/Rainbow.git", - "state": { - "branch": null, - "revision": "9c52c1952e9b2305d4507cf473392ac2d7c9b155", - "version": "3.1.5" - } - }, - { - "package": "Spectre", - "repositoryURL": "https://github.com/kylef/Spectre.git", - "state": { - "branch": null, - "revision": "f14ff47f45642aa5703900980b014c2e9394b6e5", - "version": "0.9.0" - } - }, - { - "package": "SwiftCLI", - "repositoryURL": "https://github.com/jakeheis/SwiftCLI.git", - "state": { - "branch": null, - "revision": "c72c4564f8c0a24700a59824880536aca45a4cae", - "version": "6.0.1" - } - }, - { - "package": "Version", - "repositoryURL": "https://github.com/mxcl/Version", - "state": { - "branch": null, - "revision": "a94b48f36763c05629fc102837398505032dead9", - "version": "2.0.0" - } - }, - { - "package": "XcodeProj", - "repositoryURL": "https://github.com/tuist/XcodeProj.git", - "state": { - "branch": null, - "revision": "545bfa746b6eb4ea0ad8d3a12c6590445392bb50", - "version": "7.13.0" - } - }, - { - "package": "XcodeProjCExt", - "repositoryURL": "https://github.com/tuist/XcodeProjCExt", - "state": { - "branch": null, - "revision": "21a510c225ff2bc83d5920a21d902af4b1e7e218", - "version": "0.1.0" - } - }, - { - "package": "Yams", - "repositoryURL": "https://github.com/jpsim/Yams.git", - "state": { - "branch": null, - "revision": "c947a306d2e80ecb2c0859047b35c73b8e1ca27f", - "version": "2.0.0" - } + "pins" : [ + { + "identity" : "aexml", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tadija/AEXML.git", + "state" : { + "revision" : "db806756c989760b35108146381535aec231092b", + "version" : "4.7.0" } - ] - }, - "version": 1 + }, + { + "identity" : "artifactbundlegen", + "kind" : "remoteSourceControl", + "location" : "https://github.com/freddi-kit/ArtifactBundleGen", + "state" : { + "revision" : "33f4a65acb296dcde04aeb828b6850fcf9dceb6c", + "version" : "0.0.8" + } + }, + { + "identity" : "jsonutilities", + "kind" : "remoteSourceControl", + "location" : "https://github.com/yonaskolb/JSONUtilities.git", + "state" : { + "revision" : "128d2ffc22467f69569ef8ff971683e2393191a0", + "version" : "4.2.0" + } + }, + { + "identity" : "pathkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kylef/PathKit.git", + "state" : { + "revision" : "3bfd2737b700b9a36565a8c94f4ad2b050a5e574", + "version" : "1.0.1" + } + }, + { + "identity" : "rainbow", + "kind" : "remoteSourceControl", + "location" : "https://github.com/onevcat/Rainbow.git", + "state" : { + "revision" : "e0dada9cd44e3fa7ec3b867e49a8ddbf543e3df3", + "version" : "4.0.1" + } + }, + { + "identity" : "spectre", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kylef/Spectre.git", + "state" : { + "revision" : "26cc5e9ae0947092c7139ef7ba612e34646086c7", + "version" : "0.10.1" + } + }, + { + "identity" : "swiftcli", + "kind" : "remoteSourceControl", + "location" : "https://github.com/jakeheis/SwiftCLI.git", + "state" : { + "revision" : "2e949055d9797c1a6bddcda0e58dada16cc8e970", + "version" : "6.0.3" + } + }, + { + "identity" : "version", + "kind" : "remoteSourceControl", + "location" : "https://github.com/mxcl/Version", + "state" : { + "revision" : "a94b48f36763c05629fc102837398505032dead9", + "version" : "2.0.0" + } + }, + { + "identity" : "xcodeproj", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tuist/XcodeProj.git", + "state" : { + "revision" : "b1caa062d4aaab3e3d2bed5fe0ac5f8ce9bf84f4", + "version" : "8.27.7" + } + }, + { + "identity" : "yams", + "kind" : "remoteSourceControl", + "location" : "https://github.com/jpsim/Yams.git", + "state" : { + "revision" : "01835dc202670b5bb90d07f3eae41867e9ed29f6", + "version" : "5.0.1" + } + } + ], + "version" : 2 } diff --git a/Package.swift b/Package.swift index 69e6d5fd5..eb1cad2c2 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.0 +// swift-tools-version:5.9 import PackageDescription @@ -11,81 +11,82 @@ let package = Package( .library(name: "ProjectSpec", targets: ["ProjectSpec"]), ], dependencies: [ - .package(url: "https://github.com/kylef/PathKit.git", from: "1.0.0"), - .package(url: "https://github.com/jpsim/Yams.git", from: "2.0.0"), + .package(url: "https://github.com/kylef/PathKit.git", from: "1.0.1"), + .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.0"), .package(url: "https://github.com/yonaskolb/JSONUtilities.git", from: "4.2.0"), - .package(url: "https://github.com/kylef/Spectre.git", from: "0.9.0"), - .package(url: "https://github.com/onevcat/Rainbow.git", from: "3.0.0"), - .package(url: "https://github.com/tuist/XcodeProj.git", .exact("7.13.0")), - .package(url: "https://github.com/jakeheis/SwiftCLI.git", from: "6.0.0"), + .package(url: "https://github.com/kylef/Spectre.git", from: "0.9.2"), + .package(url: "https://github.com/onevcat/Rainbow.git", from: "4.0.0"), + .package(url: "https://github.com/tuist/XcodeProj.git", exact: "8.27.7"), + .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", from: "0.1.0"), + .package(url: "https://github.com/freddi-kit/ArtifactBundleGen", exact: "0.0.8") ], targets: [ - .target(name: "XcodeGen", dependencies: [ + .executableTarget(name: "XcodeGen", dependencies: [ "XcodeGenCLI", - "Version", + .product(name: "Version", package: "Version"), ]), .target(name: "XcodeGenCLI", dependencies: [ "XcodeGenKit", "ProjectSpec", - "SwiftCLI", - "Rainbow", - "PathKit", - "Version", + .product(name: "SwiftCLI", package: "SwiftCLI"), + .product(name: "Rainbow", package: "Rainbow"), + .product(name: "PathKit", package: "PathKit"), + .product(name: "Version", package: "Version"), ]), .target(name: "XcodeGenKit", dependencies: [ "ProjectSpec", - "JSONUtilities", - "XcodeProj", - "PathKit", - "Core", - "GraphViz", + .product(name: "JSONUtilities", package: "JSONUtilities"), + .product(name: "XcodeProj", package: "XcodeProj"), + .product(name: "PathKit", package: "PathKit"), + "XcodeGenCore", + ], resources: [ + .copy("SettingPresets") ]), .target(name: "ProjectSpec", dependencies: [ - "JSONUtilities", - "XcodeProj", - "Yams", - "Core", - "Version", + .product(name: "JSONUtilities", package: "JSONUtilities"), + .product(name: "XcodeProj", package: "XcodeProj"), + .product(name: "Yams", package: "yams"), + "XcodeGenCore", + .product(name: "Version", package: "Version"), ]), - .target(name: "Core", dependencies: [ - "PathKit", - "Yams", + .target(name: "XcodeGenCore", dependencies: [ + .product(name: "PathKit", package: "PathKit"), + .product(name: "Yams", package: "yams"), ]), .target(name: "TestSupport", dependencies: [ - "XcodeProj", - "Spectre", - "PathKit", + .product(name: "XcodeProj", package: "XcodeProj"), + .product(name: "Spectre", package: "Spectre"), + .product(name: "PathKit", package: "PathKit"), ]), .testTarget(name: "XcodeGenKitTests", dependencies: [ "XcodeGenKit", - "Spectre", - "PathKit", + .product(name: "Spectre", package: "Spectre"), + .product(name: "PathKit", package: "PathKit"), "TestSupport", ]), .testTarget(name: "FixtureTests", dependencies: [ "XcodeGenKit", - "Spectre", - "PathKit", + .product(name: "Spectre", package: "Spectre"), + .product(name: "PathKit", package: "PathKit"), "TestSupport", ]), - .testTarget(name: "CoreTests", dependencies: [ - "Core", - "Spectre", - "PathKit", + .testTarget(name: "XcodeGenCoreTests", dependencies: [ + "XcodeGenCore", + .product(name: "Spectre", package: "Spectre"), + .product(name: "PathKit", package: "PathKit"), "TestSupport", ]), .testTarget(name: "ProjectSpecTests", dependencies: [ "ProjectSpec", - "Spectre", - "PathKit", + .product(name: "Spectre", package: "Spectre"), + .product(name: "PathKit", package: "PathKit"), "TestSupport", ]), .testTarget(name: "PerformanceTests", dependencies: [ "XcodeGenKit", - "Spectre", - "PathKit", + .product(name: "Spectre", package: "Spectre"), + .product(name: "PathKit", package: "PathKit"), "TestSupport", ]), ] diff --git a/README.md b/README.md index 0acf5a5d5..6a7ed7e77 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,17 @@

- - Swift Package Manager - - + + + + Swift Package Manager Platforms + + + Swift Versions - +

@@ -32,12 +35,13 @@ The project spec is a YAML or JSON file that defines your targets, configuration - ✅ Distribute your spec amongst multiple files for easy **sharing** and overriding - ✅ Easily create **multi-platform** frameworks - ✅ Integrate **Carthage** frameworks without any work -- ✅ Export **Dependency Diagrams** to view in [Graphviz](https://www.graphviz.org) -Given a very simple project spec file like this: +Given an example project spec: ```yaml name: MyProject +include: + - base_spec.yml options: bundleIdPrefix: com.myapp packages: @@ -72,7 +76,7 @@ A project would be created with 2 connected targets, with all the required confi ## Installing -Make sure Xcode 11 is installed first. +Make sure the latest stable (non-beta) version of Xcode is installed first. ### [Mint](https://github.com/yonaskolb/mint) ```sh @@ -108,7 +112,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.16.0"), +.package(url: "https://github.com/yonaskolb/XcodeGen.git", from: "2.44.1"), ``` And then import wherever needed: `import XcodeGenKit` @@ -125,34 +129,13 @@ 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. - **--cache-path**: A custom path to use for your cache file. This defaults to `~/.xcodegen/cache/{PROJECT_SPEC_PATH_HASH}` -There are other commands as well such as `xcodegen dump` which lets out output the resolved spec in many different formats, or write it to a file. Use `xcodegen help` to see more detailed usage information. - -## Dependency Diagrams -
- Click to expand! - -#### How to export dependency diagrams: - -To stdout: - -``` -xcodegen dump --type graphviz -``` - -To a file: - -``` -xcodegen dump --type graphviz --file Graph.viz -``` - -During implementation, `graphviz` formatting was validated using [GraphvizOnline](https://dreampuf.github.io/GraphvizOnline/), [WebGraphviz](http://www.webgraphviz.com), and [Graphviz on MacOS](graphviz.org). -
+There are other commands as well such as `xcodegen dump` which lets one output the resolved spec in many different formats, or write it to a file. Use `xcodegen help` to see more detailed usage information. ## Editing ```shell @@ -160,7 +143,7 @@ git clone https://github.com/yonaskolb/XcodeGen.git cd XcodeGen swift package generate-xcodeproj ``` -This use Swift Project Manager to create an `xcodeproj` file that you can open, edit and run in Xcode, which makes editing any code easier. +This uses Swift Package Manager to create an `xcodeproj` file that you can open, edit and run in Xcode, which makes editing any code easier. If you want to pass any required arguments when running in Xcode, you can edit the scheme to include launch arguments. diff --git a/RELEASE.md b/RELEASE.md index a481e4850..42e9ff786 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -3,10 +3,8 @@ 1. Make sure `CHANGELOG.md` is up to date: - All relevant entries have been added with the PR link and author - The new version number is added at the top after `Master` - - The `Commits` link is at the bottom of the release 1. Update the version at the top of `Makefile` 1. Run `make release` 1. Push commit and tag to github 1. Create release from tag on GitHub using the version number and relevant changelog contents -1. Run `make archive` and upload `xcodegen.zip` to the github release -1. Run `make brew` which will open a PR on homebrew core +1. Run `make archive` and upload `xcodegen.zip` and `xcodegen.artifactbundle.zip` to the github release diff --git a/SettingPresets/Configs/debug.yml b/SettingPresets/Configs/debug.yml index 5b0b75213..6c3e3c20f 100644 --- a/SettingPresets/Configs/debug.yml +++ b/SettingPresets/Configs/debug.yml @@ -6,7 +6,7 @@ ENABLE_TESTABILITY: YES GCC_DYNAMIC_NO_PIC: NO GCC_OPTIMIZATION_LEVEL: '0' GCC_PREPROCESSOR_DEFINITIONS: ["$(inherited)", "DEBUG=1"] -MTL_ENABLE_DEBUG_INFO: YES +MTL_ENABLE_DEBUG_INFO: INCLUDE_SOURCE ONLY_ACTIVE_ARCH: YES # Swift Settings diff --git a/SettingPresets/Configs/release.yml b/SettingPresets/Configs/release.yml index ce6d9f247..7a14baa93 100644 --- a/SettingPresets/Configs/release.yml +++ b/SettingPresets/Configs/release.yml @@ -3,7 +3,8 @@ # /Applications/Xcode.app/Contents/Developer/Library/Xcode/Templates/Project Templates/Base/Base_ProjectSettings.xctemplate/TemplateInfo.plist DEBUG_INFORMATION_FORMAT: dwarf-with-dsym ENABLE_NS_ASSERTIONS: NO -VALIDATE_PRODUCT: YES +MTL_ENABLE_DEBUG_INFO: NO # Swift Settings SWIFT_COMPILATION_MODE: wholemodule +SWIFT_OPTIMIZATION_LEVEL: -O diff --git a/SettingPresets/Platforms/tvOS.yml b/SettingPresets/Platforms/tvOS.yml index 26c99a9dc..40491c07f 100644 --- a/SettingPresets/Platforms/tvOS.yml +++ b/SettingPresets/Platforms/tvOS.yml @@ -1,3 +1,3 @@ -TARGETED_DEVICE_FAMILY: 3 LD_RUNPATH_SEARCH_PATHS: ["$(inherited)", "@executable_path/Frameworks"] SDKROOT: appletvos +TARGETED_DEVICE_FAMILY: 3 diff --git a/SettingPresets/Platforms/visionOS.yml b/SettingPresets/Platforms/visionOS.yml new file mode 100644 index 000000000..d969bf799 --- /dev/null +++ b/SettingPresets/Platforms/visionOS.yml @@ -0,0 +1,3 @@ +LD_RUNPATH_SEARCH_PATHS: ["$(inherited)", "@executable_path/Frameworks"] +SDKROOT: xros +TARGETED_DEVICE_FAMILY: 7 diff --git a/SettingPresets/Product_Platform/app-extension_macOS.yml b/SettingPresets/Product_Platform/app-extension_macOS.yml new file mode 100644 index 000000000..65b36ca7d --- /dev/null +++ b/SettingPresets/Product_Platform/app-extension_macOS.yml @@ -0,0 +1 @@ +LD_RUNPATH_SEARCH_PATHS: ["$(inherited)", "@executable_path/../Frameworks", "@executable_path/../../../../Frameworks"] diff --git a/SettingPresets/Product_Platform/application_visionOS.yml b/SettingPresets/Product_Platform/application_visionOS.yml new file mode 100644 index 000000000..e538b2380 --- /dev/null +++ b/SettingPresets/Product_Platform/application_visionOS.yml @@ -0,0 +1 @@ +ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon diff --git a/SettingPresets/SupportedDestinations/iOS.yml b/SettingPresets/SupportedDestinations/iOS.yml new file mode 100644 index 000000000..91bfa0b47 --- /dev/null +++ b/SettingPresets/SupportedDestinations/iOS.yml @@ -0,0 +1,5 @@ +SUPPORTED_PLATFORMS: iphoneos iphonesimulator +TARGETED_DEVICE_FAMILY: '1,2' +SUPPORTS_MACCATALYST: NO +SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: YES +SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD: YES diff --git a/SettingPresets/SupportedDestinations/macCatalyst.yml b/SettingPresets/SupportedDestinations/macCatalyst.yml new file mode 100644 index 000000000..953af2680 --- /dev/null +++ b/SettingPresets/SupportedDestinations/macCatalyst.yml @@ -0,0 +1,2 @@ +SUPPORTS_MACCATALYST: YES +SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: NO diff --git a/SettingPresets/SupportedDestinations/macOS.yml b/SettingPresets/SupportedDestinations/macOS.yml new file mode 100644 index 000000000..e59a8f69d --- /dev/null +++ b/SettingPresets/SupportedDestinations/macOS.yml @@ -0,0 +1,3 @@ +SUPPORTED_PLATFORMS: macosx +SUPPORTS_MACCATALYST: NO +SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: NO diff --git a/SettingPresets/SupportedDestinations/tvOS.yml b/SettingPresets/SupportedDestinations/tvOS.yml new file mode 100644 index 000000000..a40ce2666 --- /dev/null +++ b/SettingPresets/SupportedDestinations/tvOS.yml @@ -0,0 +1,2 @@ +SUPPORTED_PLATFORMS: appletvos appletvsimulator +TARGETED_DEVICE_FAMILY: '3' diff --git a/SettingPresets/SupportedDestinations/visionOS.yml b/SettingPresets/SupportedDestinations/visionOS.yml new file mode 100644 index 000000000..1353d7191 --- /dev/null +++ b/SettingPresets/SupportedDestinations/visionOS.yml @@ -0,0 +1,3 @@ +SUPPORTED_PLATFORMS: xros xrsimulator +TARGETED_DEVICE_FAMILY: '7' +SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD: NO diff --git a/SettingPresets/SupportedDestinations/watchOS.yml b/SettingPresets/SupportedDestinations/watchOS.yml new file mode 100644 index 000000000..95ba0836d --- /dev/null +++ b/SettingPresets/SupportedDestinations/watchOS.yml @@ -0,0 +1,2 @@ +SUPPORTED_PLATFORMS: watchos watchsimulator +TARGETED_DEVICE_FAMILY: '4' diff --git a/SettingPresets/base.yml b/SettingPresets/base.yml index 0cb9ea15d..d7533a841 100644 --- a/SettingPresets/base.yml +++ b/SettingPresets/base.yml @@ -8,6 +8,7 @@ CLANG_CXX_LANGUAGE_STANDARD: gnu++14 CLANG_CXX_LIBRARY: libc++ CLANG_ENABLE_MODULES: YES CLANG_ENABLE_OBJC_ARC: YES +CLANG_ENABLE_OBJC_WEAK: YES CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING: YES CLANG_WARN_BOOL_CONVERSION: YES CLANG_WARN_COMMA: YES @@ -23,6 +24,7 @@ CLANG_WARN_NON_LITERAL_NULL_CONVERSION: YES CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF: YES CLANG_WARN_OBJC_LITERAL_CONVERSION: YES CLANG_WARN_OBJC_ROOT_CLASS: YES_ERROR +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER: YES CLANG_WARN_RANGE_LOOP_ANALYSIS: YES CLANG_WARN_STRICT_PROTOTYPES: YES CLANG_WARN_SUSPICIOUS_MOVE: YES @@ -39,7 +41,10 @@ GCC_WARN_UNDECLARED_SELECTOR: YES GCC_WARN_UNINITIALIZED_AUTOS: YES_AGGRESSIVE GCC_WARN_UNUSED_FUNCTION: YES GCC_WARN_UNUSED_VARIABLE: YES +MTL_FAST_MATH: YES -# Swift Settings +# Target Settings PRODUCT_NAME: $(TARGET_NAME) + +# Swift Settings SWIFT_VERSION: '5.0' diff --git a/Sources/ProjectSpec/AggregateTarget.swift b/Sources/ProjectSpec/AggregateTarget.swift index b2964e5b8..9bea7098c 100644 --- a/Sources/ProjectSpec/AggregateTarget.swift +++ b/Sources/ProjectSpec/AggregateTarget.swift @@ -1,11 +1,14 @@ 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] + public var buildToolPlugins: [BuildToolPlugin] public var configFiles: [String: String] public var scheme: TargetScheme? public var attributes: [String: Any] @@ -16,6 +19,7 @@ public struct AggregateTarget: ProjectTarget { settings: Settings = .empty, configFiles: [String: String] = [:], buildScripts: [BuildScript] = [], + buildToolPlugins: [BuildToolPlugin] = [], scheme: TargetScheme? = nil, attributes: [String: Any] = [:] ) { @@ -24,6 +28,7 @@ public struct AggregateTarget: ProjectTarget { self.settings = settings self.configFiles = configFiles self.buildScripts = buildScripts + self.buildToolPlugins = buildToolPlugins self.scheme = scheme self.attributes = attributes } @@ -44,6 +49,7 @@ extension AggregateTarget: Equatable { lhs.settings == rhs.settings && lhs.configFiles == rhs.configFiles && lhs.buildScripts == rhs.buildScripts && + lhs.buildToolPlugins == rhs.buildToolPlugins && lhs.scheme == rhs.scheme && NSDictionary(dictionary: lhs.attributes).isEqual(to: rhs.attributes) } @@ -54,9 +60,10 @@ extension AggregateTarget: NamedJSONDictionaryConvertible { public init(name: String, jsonDictionary: JSONDictionary) throws { self.name = jsonDictionary.json(atKeyPath: "name") ?? name targets = jsonDictionary.json(atKeyPath: "targets") ?? [] - settings = jsonDictionary.json(atKeyPath: "settings") ?? .empty + settings = try BuildSettingsParser(jsonDictionary: jsonDictionary).parse() configFiles = jsonDictionary.json(atKeyPath: "configFiles") ?? [:] buildScripts = jsonDictionary.json(atKeyPath: "buildScripts") ?? [] + buildToolPlugins = jsonDictionary.json(atKeyPath: "buildToolPlugins") ?? [] scheme = jsonDictionary.json(atKeyPath: "scheme") attributes = jsonDictionary.json(atKeyPath: "attributes") ?? [:] } @@ -70,6 +77,7 @@ extension AggregateTarget: JSONEncodable { "configFiles": configFiles, "attributes": attributes, "buildScripts": buildScripts.map { $0.toJSONValue() }, + "buildToolPlugins": buildToolPlugins.map { $0.toJSONValue() }, "scheme": scheme?.toJSONValue(), ] as [String: Any?] } diff --git a/Sources/ProjectSpec/Breakpoint.swift b/Sources/ProjectSpec/Breakpoint.swift new file mode 100644 index 000000000..7877a6956 --- /dev/null +++ b/Sources/ProjectSpec/Breakpoint.swift @@ -0,0 +1,264 @@ +import Foundation +import XcodeProj +import JSONUtilities + +public typealias BreakpointActionExtensionID = XCBreakpointList.BreakpointProxy.BreakpointContent.BreakpointActionProxy.ActionExtensionID +public typealias BreakpointExtensionID = XCBreakpointList.BreakpointProxy.BreakpointExtensionID + +public struct Breakpoint: Equatable { + + public enum BreakpointType: Equatable { + + public struct Exception: Equatable { + + public enum Scope: String, Equatable { + case all = "0" + case objectiveC = "1" + case cpp = "2" + } + + public enum StopOnStyle: String, Equatable { + case `throw` = "0" + case `catch` = "1" + } + + public var scope: Scope + public var stopOnStyle: StopOnStyle + + public init(scope: Breakpoint.BreakpointType.Exception.Scope = .objectiveC, + stopOnStyle: Breakpoint.BreakpointType.Exception.StopOnStyle = .throw) { + self.scope = scope + self.stopOnStyle = stopOnStyle + } + } + case file(path: String, line: Int, column: Int?) + case exception(Exception) + case swiftError + case openGLError + case symbolic(symbol: String?, module: String?) + case ideConstraintError + case ideTestFailure + case runtimeIssue + } + + public enum Action: Equatable { + + public struct Log: Equatable { + + public enum ConveyanceType: String, Equatable { + case console = "0" + case speak = "1" + } + + public var message: String? + public var conveyanceType: ConveyanceType + + public init(message: String? = nil, conveyanceType: Breakpoint.Action.Log.ConveyanceType = .console) { + self.message = message + self.conveyanceType = conveyanceType + } + } + + public enum Sound: String, Equatable { + case basso = "Basso" + case blow = "Blow" + case bottle = "Bottle" + case frog = "Frog" + case funk = "Funk" + case glass = "Glass" + case hero = "Hero" + case morse = "Morse" + case ping = "Ping" + case pop = "Pop" + case purr = "Purr" + case sosumi = "Sosumi" + case submarine = "Submarine" + case tink = "Tink" + } + + case debuggerCommand(String?) + case log(Log) + case shellCommand(path: String?, arguments: String?, waitUntilDone: Bool = false) + case graphicsTrace + case appleScript(String?) + case sound(Sound) + } + + public var type: BreakpointType + public var enabled: Bool + public var ignoreCount: Int + public var continueAfterRunningActions: Bool + public var condition: String? + public var actions: [Breakpoint.Action] + + public init(type: BreakpointType, + enabled: Bool = true, + ignoreCount: Int = 0, + continueAfterRunningActions: Bool = false, + filePath: String? = nil, + line: Int? = nil, + condition: String? = nil, + actions: [Breakpoint.Action] = []) { + self.type = type + self.enabled = enabled + self.ignoreCount = ignoreCount + self.continueAfterRunningActions = continueAfterRunningActions + self.condition = condition + self.actions = actions + } +} + +extension Breakpoint.BreakpointType.Exception.Scope { + + public init(string: String) throws { + let string = string.lowercased() + switch string { + case "all": + self = .all + case "objective-c": + self = .objectiveC + case "c++": + self = .cpp + default: + throw SpecParsingError.unknownBreakpointScope(string) + } + } +} + +extension Breakpoint.BreakpointType.Exception.StopOnStyle { + + public init(string: String) throws { + let string = string.lowercased() + switch string { + case "throw": + self = .throw + case "catch": + self = .catch + default: + throw SpecParsingError.unknownBreakpointStopOnStyle(string) + } + } +} + +extension Breakpoint.Action.Log.ConveyanceType { + + init(string: String) throws { + let string = string.lowercased() + switch string { + case "console": + self = .console + case "speak": + self = .speak + default: + throw SpecParsingError.unknownBreakpointActionConveyanceType(string) + } + } +} + +extension Breakpoint.Action.Sound { + + init(name: String) throws { + guard let sound = Self.init(rawValue: name) else { + throw SpecParsingError.unknownBreakpointActionSoundName(name) + } + self = sound + } +} + +extension Breakpoint.Action: JSONObjectConvertible { + + public init(jsonDictionary: JSONDictionary) throws { + let idString: String = try jsonDictionary.json(atKeyPath: "type") + let id = try BreakpointActionExtensionID(string: idString) + switch id { + case .debuggerCommand: + let command: String? = jsonDictionary.json(atKeyPath: "command") + self = .debuggerCommand(command) + case .log: + let message: String? = jsonDictionary.json(atKeyPath: "message") + let conveyanceType: Log.ConveyanceType + if jsonDictionary["conveyanceType"] != nil { + let conveyanceTypeString: String = try jsonDictionary.json(atKeyPath: "conveyanceType") + conveyanceType = try .init(string: conveyanceTypeString) + } else { + conveyanceType = .console + } + self = .log(.init(message: message, conveyanceType: conveyanceType)) + case .shellCommand: + let path: String? = jsonDictionary.json(atKeyPath: "path") + let arguments: String? = jsonDictionary.json(atKeyPath: "arguments") + let waitUntilDone = jsonDictionary.json(atKeyPath: "waitUntilDone") ?? false + self = .shellCommand(path: path, arguments: arguments, waitUntilDone: waitUntilDone) + case .graphicsTrace: + self = .graphicsTrace + case .appleScript: + let script: String? = jsonDictionary.json(atKeyPath: "script") + self = .appleScript(script) + case .sound: + let sound: Sound + if jsonDictionary["sound"] != nil { + let name: String = try jsonDictionary.json(atKeyPath: "sound") + sound = try .init(name: name) + } else { + sound = .basso + } + self = .sound(sound) + case .openGLError: + throw SpecParsingError.unknownBreakpointActionType(idString) + } + } +} + +extension Breakpoint: JSONObjectConvertible { + + public init(jsonDictionary: JSONDictionary) throws { + let idString: String = try jsonDictionary.json(atKeyPath: "type") + let id = try BreakpointExtensionID(string: idString) + switch id { + case .file: + let path: String = try jsonDictionary.json(atKeyPath: "path") + let line: Int = try jsonDictionary.json(atKeyPath: "line") + let column: Int? = jsonDictionary.json(atKeyPath: "column") + type = .file(path: path, line: line, column: column) + case .exception: + let scope: BreakpointType.Exception.Scope + if jsonDictionary["scope"] != nil { + let scopeString: String = try jsonDictionary.json(atKeyPath: "scope") + scope = try .init(string: scopeString) + } else { + scope = .objectiveC + } + let stopOnStyle: BreakpointType.Exception.StopOnStyle + if jsonDictionary["stopOnStyle"] != nil { + let stopOnStyleString: String = try jsonDictionary.json(atKeyPath: "stopOnStyle") + stopOnStyle = try .init(string: stopOnStyleString) + } else { + stopOnStyle = .throw + } + type = .exception(.init(scope: scope, stopOnStyle: stopOnStyle)) + case .swiftError: + type = .swiftError + case .openGLError: + type = .openGLError + case .symbolic: + let symbol: String? = jsonDictionary.json(atKeyPath: "symbol") + let module: String? = jsonDictionary.json(atKeyPath: "module") + type = .symbolic(symbol: symbol, module: module) + case .ideConstraintError: + type = .ideConstraintError + case .ideTestFailure: + type = .ideTestFailure + case .runtimeIssue: + type = .runtimeIssue + } + enabled = jsonDictionary.json(atKeyPath: "enabled") ?? true + ignoreCount = jsonDictionary.json(atKeyPath: "ignoreCount") ?? 0 + continueAfterRunningActions = jsonDictionary.json(atKeyPath: "continueAfterRunningActions") ?? false + condition = jsonDictionary.json(atKeyPath: "condition") + if jsonDictionary["actions"] != nil { + actions = try jsonDictionary.json(atKeyPath: "actions", invalidItemBehaviour: .fail) + } else { + actions = [] + } + } +} diff --git a/Sources/ProjectSpec/BuildPhaseSpec.swift b/Sources/ProjectSpec/BuildPhaseSpec.swift new file mode 100644 index 000000000..6227ced02 --- /dev/null +++ b/Sources/ProjectSpec/BuildPhaseSpec.swift @@ -0,0 +1,154 @@ +// +// File.swift +// +// +// Created by Yonas Kolb on 1/5/20. +// + +import Foundation +import XcodeProj +import JSONUtilities + +public enum BuildPhaseSpec: Equatable { + case sources + case headers + case resources + case copyFiles(CopyFilesSettings) + case none + // Not currently exposed as selectable options, but used internally + case frameworks + case runScript + case carbonResources + + public struct CopyFilesSettings: Equatable, Hashable { + public static let xpcServices = CopyFilesSettings( + destination: .productsDirectory, + subpath: "$(CONTENTS_FOLDER_PATH)/XPCServices", + phaseOrder: .postCompile + ) + + public static let plugins = CopyFilesSettings( + destination: .plugins, + subpath: "$(CONTENTS_FOLDER_PATH)/PlugIns", + phaseOrder: .postCompile + ) + + public enum Destination: String { + case absolutePath + case productsDirectory + case wrapper + case executables + case resources + case javaResources + case frameworks + case sharedFrameworks + case sharedSupport + case plugins + + public var destination: PBXCopyFilesBuildPhase.SubFolder? { + switch self { + case .absolutePath: return .absolutePath + case .productsDirectory: return .productsDirectory + case .wrapper: return .wrapper + case .executables: return .executables + case .resources: return .resources + case .javaResources: return .javaResources + case .frameworks: return .frameworks + case .sharedFrameworks: return .sharedFrameworks + case .sharedSupport: return .sharedSupport + case .plugins: return .plugins + } + } + } + + public enum PhaseOrder: String { + /// Run before the Compile Sources phase + case preCompile + /// Run after the Compile Sources and post-compile Run Script phases + case postCompile + } + + public var destination: Destination + public var subpath: String + public var phaseOrder: PhaseOrder + + public init( + destination: Destination, + subpath: String, + phaseOrder: PhaseOrder + ) { + self.destination = destination + self.subpath = subpath + self.phaseOrder = phaseOrder + } + } + + public var buildPhase: BuildPhase? { + switch self { + case .sources: return .sources + case .headers: return .headers + case .resources: return .resources + case .copyFiles: return .copyFiles + case .frameworks: return .frameworks + case .runScript: return .runScript + case .carbonResources: return .carbonResources + case .none: return nil + } + } +} + +extension BuildPhaseSpec { + + public init(string: String) throws { + switch string { + case "sources": self = .sources + case "headers": self = .headers + case "resources": self = .resources + case "copyFiles": + throw SpecParsingError.invalidSourceBuildPhase("copyFiles must specify a \"destination\" and optional \"subpath\"") + case "none": self = .none + default: + throw SpecParsingError.invalidSourceBuildPhase(string.quoted) + } + } +} + +extension BuildPhaseSpec: JSONObjectConvertible { + + public init(jsonDictionary: JSONDictionary) throws { + self = .copyFiles(try jsonDictionary.json(atKeyPath: "copyFiles")) + } +} + +extension BuildPhaseSpec: JSONEncodable { + public func toJSONValue() -> Any { + switch self { + case .sources: return "sources" + case .headers: return "headers" + case .resources: return "resources" + case .copyFiles(let files): return ["copyFiles": files.toJSONValue()] + case .none: return "none" + case .frameworks: fatalError("invalid build phase") + case .runScript: fatalError("invalid build phase") + case .carbonResources: fatalError("invalid build phase") + } + } +} + +extension BuildPhaseSpec.CopyFilesSettings: JSONObjectConvertible { + + public init(jsonDictionary: JSONDictionary) throws { + destination = try jsonDictionary.json(atKeyPath: "destination") + subpath = jsonDictionary.json(atKeyPath: "subpath") ?? "" + phaseOrder = .postCompile + } +} + +extension BuildPhaseSpec.CopyFilesSettings: JSONEncodable { + public func toJSONValue() -> Any { + [ + "destination": destination.rawValue, + "subpath": subpath, + ] + } +} diff --git a/Sources/ProjectSpec/BuildRule.swift b/Sources/ProjectSpec/BuildRule.swift index 760b57c7a..f5fefc013 100644 --- a/Sources/ProjectSpec/BuildRule.swift +++ b/Sources/ProjectSpec/BuildRule.swift @@ -5,6 +5,7 @@ public struct BuildRule: Equatable { public static let scriptCompilerSpec = "com.apple.compilers.proxy.script" public static let filePatternFileType = "pattern.proxy" + public static let runOncePerArchitectureDefault = true public enum FileType: Equatable { case type(String) @@ -49,13 +50,22 @@ public struct BuildRule: Equatable { public var outputFiles: [String] public var outputFilesCompilerFlags: [String] public var name: String? - - public init(fileType: FileType, action: Action, name: String? = nil, outputFiles: [String] = [], outputFilesCompilerFlags: [String] = []) { + public var runOncePerArchitecture: Bool + + public init( + fileType: FileType, + action: Action, + name: String? = nil, + outputFiles: [String] = [], + outputFilesCompilerFlags: [String] = [], + runOncePerArchitecture: Bool = runOncePerArchitectureDefault + ) { self.fileType = fileType self.action = action self.name = name self.outputFiles = outputFiles self.outputFilesCompilerFlags = outputFilesCompilerFlags + self.runOncePerArchitecture = runOncePerArchitecture } } @@ -78,6 +88,7 @@ extension BuildRule: JSONObjectConvertible { outputFiles = jsonDictionary.json(atKeyPath: "outputFiles") ?? [] outputFilesCompilerFlags = jsonDictionary.json(atKeyPath: "outputFilesCompilerFlags") ?? [] name = jsonDictionary.json(atKeyPath: "name") + runOncePerArchitecture = jsonDictionary.json(atKeyPath: "runOncePerArchitecture") ?? BuildRule.runOncePerArchitectureDefault } } @@ -103,6 +114,10 @@ extension BuildRule: JSONEncodable { dict["script"] = string } + if runOncePerArchitecture != BuildRule.runOncePerArchitectureDefault { + dict["runOncePerArchitecture"] = runOncePerArchitecture + } + return dict } } diff --git a/Sources/ProjectSpec/BuildScript.swift b/Sources/ProjectSpec/BuildScript.swift index 9c280e1d3..f22211bc4 100644 --- a/Sources/ProjectSpec/BuildScript.swift +++ b/Sources/ProjectSpec/BuildScript.swift @@ -4,6 +4,7 @@ import JSONUtilities public struct BuildScript: Equatable { public static let runOnlyWhenInstallingDefault = false public static let showEnvVarsDefault = true + public static let basedOnDependencyAnalysisDefault = true public var script: ScriptType public var name: String? @@ -14,6 +15,8 @@ public struct BuildScript: Equatable { public var outputFileLists: [String] public var runOnlyWhenInstalling: Bool public let showEnvVars: Bool + public let basedOnDependencyAnalysis: Bool + public let discoveredDependencyFile: String? public enum ScriptType: Equatable { case path(String) @@ -29,7 +32,9 @@ public struct BuildScript: Equatable { outputFileLists: [String] = [], shell: String? = nil, runOnlyWhenInstalling: Bool = runOnlyWhenInstallingDefault, - showEnvVars: Bool = showEnvVarsDefault + showEnvVars: Bool = showEnvVarsDefault, + basedOnDependencyAnalysis: Bool = basedOnDependencyAnalysisDefault, + discoveredDependencyFile: String? = nil ) { self.script = script self.name = name @@ -40,6 +45,8 @@ public struct BuildScript: Equatable { self.shell = shell self.runOnlyWhenInstalling = runOnlyWhenInstalling self.showEnvVars = showEnvVars + self.basedOnDependencyAnalysis = basedOnDependencyAnalysis + self.discoveredDependencyFile = discoveredDependencyFile } } @@ -61,6 +68,8 @@ extension BuildScript: JSONObjectConvertible { shell = jsonDictionary.json(atKeyPath: "shell") runOnlyWhenInstalling = jsonDictionary.json(atKeyPath: "runOnlyWhenInstalling") ?? BuildScript.runOnlyWhenInstallingDefault showEnvVars = jsonDictionary.json(atKeyPath: "showEnvVars") ?? BuildScript.showEnvVarsDefault + basedOnDependencyAnalysis = jsonDictionary.json(atKeyPath: "basedOnDependencyAnalysis") ?? BuildScript.basedOnDependencyAnalysisDefault + discoveredDependencyFile = jsonDictionary.json(atKeyPath: "discoveredDependencyFile") } } @@ -80,6 +89,10 @@ extension BuildScript: JSONEncodable { dict["showEnvVars"] = showEnvVars } + if basedOnDependencyAnalysis != BuildScript.basedOnDependencyAnalysisDefault { + dict["basedOnDependencyAnalysis"] = basedOnDependencyAnalysis + } + switch script { case .path(let string): dict["path"] = string @@ -87,6 +100,10 @@ extension BuildScript: JSONEncodable { dict["script"] = string } + if let discoveredDependencyFile = discoveredDependencyFile { + dict["discoveredDependencyFile"] = discoveredDependencyFile + } + return dict } } diff --git a/Sources/ProjectSpec/BuildSettingsExtractor.swift b/Sources/ProjectSpec/BuildSettingsExtractor.swift new file mode 100644 index 000000000..1dfeb93de --- /dev/null +++ b/Sources/ProjectSpec/BuildSettingsExtractor.swift @@ -0,0 +1,37 @@ +import Foundation +import JSONUtilities + +/// A helper for extracting and validating the `Settings` object from a JSON dictionary. +struct BuildSettingsParser { + let jsonDictionary: JSONDictionary + + /// Attempts to extract and parse the `Settings` from the dictionary. + /// + /// - Returns: A valid `Settings` object + func parse() throws -> Settings { + do { + return try jsonDictionary.json(atKeyPath: "settings") + } catch let specParsingError as SpecParsingError { + // Re-throw `SpecParsingError` to prevent the misuse of settings.configs. + throw specParsingError + } catch { + // Ignore all errors except `SpecParsingError` + return .empty + } + } + + /// Attempts to extract and parse setting groups from the dictionary with fallback defaults. + /// + /// - Returns: Parsed setting groups or default groups if parsing fails + func parseSettingGroups() throws -> [String: Settings] { + do { + return try jsonDictionary.json(atKeyPath: "settingGroups", invalidItemBehaviour: .fail) + } catch let specParsingError as SpecParsingError { + // Re-throw `SpecParsingError` to prevent the misuse of settingGroups. + throw specParsingError + } catch { + // Ignore all errors except `SpecParsingError` + return jsonDictionary.json(atKeyPath: "settingPresets") ?? [:] + } + } +} diff --git a/Sources/ProjectSpec/BuildToolPlugin.swift b/Sources/ProjectSpec/BuildToolPlugin.swift new file mode 100644 index 000000000..76de6f0d8 --- /dev/null +++ b/Sources/ProjectSpec/BuildToolPlugin.swift @@ -0,0 +1,58 @@ +import Foundation +import JSONUtilities + +/// Specifies the use of a plug-in product in a target. +public struct BuildToolPlugin: Equatable { + + /// The name of the plug-in target. + public var plugin: String + /// The name of the package that defines the plug-in target. + public var package: String + + public init( + plugin: String, + package: String + ) { + self.plugin = plugin + self.package = package + } +} + +extension BuildToolPlugin: JSONObjectConvertible { + + public init(jsonDictionary: JSONDictionary) throws { + if let plugin: String = jsonDictionary.json(atKeyPath: "plugin") { + self.plugin = plugin + } else { + throw SpecParsingError.invalidDependency(jsonDictionary) + } + + if let package: String = jsonDictionary.json(atKeyPath: "package") { + self.package = package + } else { + throw SpecParsingError.invalidDependency(jsonDictionary) + } + } +} + +extension BuildToolPlugin { + public var uniqueID: String { + return "\(plugin)/\(package)" + } +} + +extension BuildToolPlugin: Hashable { + public func hash(into hasher: inout Hasher) { + hasher.combine(plugin) + hasher.combine(package) + } +} + +extension BuildToolPlugin: JSONEncodable { + public func toJSONValue() -> Any { + [ + "plugin": plugin, + "package": package + ] + } +} diff --git a/Sources/ProjectSpec/CacheFile.swift b/Sources/ProjectSpec/CacheFile.swift index 10e21afdc..95e87014f 100644 --- a/Sources/ProjectSpec/CacheFile.swift +++ b/Sources/ProjectSpec/CacheFile.swift @@ -1,5 +1,5 @@ import Foundation -import Core +import XcodeGenCore import Version public class CacheFile { @@ -10,7 +10,7 @@ public class CacheFile { guard #available(OSX 10.13, *) else { return nil } - let files = Set(project.allFiles) + let files = Set(project.allTrackedFiles) .map { ((try? $0.relativePath(from: project.basePath)) ?? $0).string } .sorted { $0.localizedStandardCompare($1) == .orderedAscending } .joined(separator: "\n") diff --git a/Sources/ProjectSpec/Config.swift b/Sources/ProjectSpec/Config.swift index 2e343e578..49e5d6d2d 100644 --- a/Sources/ProjectSpec/Config.swift +++ b/Sources/ProjectSpec/Config.swift @@ -1,7 +1,7 @@ import Foundation import JSONUtilities -public struct Config: Equatable { +public struct Config: Hashable { public var name: String public var type: ConfigType? @@ -10,10 +10,32 @@ public struct Config: Equatable { self.type = type } - public static var defaultConfigs: [Config] = [Config(name: "Debug", type: .debug), Config(name: "Release", type: .release)] + public static var defaultConfigs: [Config] = [Config(name: ConfigType.debug.name, type: .debug), Config(name: ConfigType.release.name, type: .release)] } -public enum ConfigType: String { +public enum ConfigType: String, Hashable { case debug case release + + public var name: String { + rawValue.prefix(1).uppercased() + rawValue.dropFirst() + } +} + +extension Config { + + public func matchesVariant(_ variant: String, for type: ConfigType) -> Bool { + guard self.type == type else { return false } + let nameWithoutType = self.name.lowercased() + .replacingOccurrences(of: type.name.lowercased(), with: "") + .trimmingCharacters(in: CharacterSet(charactersIn: " -_()")) + return nameWithoutType == variant.lowercased() + } } + +public extension Collection where Element == Config { + func first(including configVariant: String, for type: ConfigType) -> Config? { + first { $0.matchesVariant(configVariant, for: type) } + } +} + diff --git a/Sources/ProjectSpec/Decoding.swift b/Sources/ProjectSpec/Decoding.swift index 2c4fe3f38..e193a7f10 100644 --- a/Sources/ProjectSpec/Decoding.swift +++ b/Sources/ProjectSpec/Decoding.swift @@ -10,36 +10,22 @@ extension Dictionary where Key: JSONKey { } if parallel { let defaultError = NSError(domain: "Unspecified error", code: 0, userInfo: nil) - var itemResults: [Result] = Array(repeating: .failure(defaultError), count: dictionary.count) - var ops: [BlockOperation] = [] - var idx: Int = 0 - for (key, _) in dictionary { - ops.append(BlockOperation { [idx] in + let keys = Array(dictionary.keys) + var itemResults: [Result] = Array(repeating: .failure(defaultError), count: keys.count) + itemResults.withUnsafeMutableBufferPointer { buffer in + let bufferWrapper = BufferWrapper(buffer: buffer) + DispatchQueue.concurrentPerform(iterations: dictionary.count) { idx in do { + let key = keys[idx] let jsonDictionary: JSONDictionary = try dictionary.json(atKeyPath: .key(key)) let item = try T(name: key, jsonDictionary: jsonDictionary) - itemResults[idx] = .success(item) + bufferWrapper.buffer[idx] = .success(item) } catch { - itemResults[idx] = .failure(error) + bufferWrapper.buffer[idx] = .failure(error) } - }) - idx += 1 - } - let queue = OperationQueue() - queue.qualityOfService = .userInteractive - queue.maxConcurrentOperationCount = 8 - queue.addOperations(ops, waitUntilFinished: true) - var items = ContiguousArray() - items.reserveCapacity(itemResults.count) - for result in itemResults { - switch result { - case .failure(let error): - throw error - case .success(let item): - items.append(item) } } - return Array(items) + return try itemResults.map { try $0.get() } } else { var items: [T] = [] for (key, _) in dictionary { @@ -64,6 +50,14 @@ extension Dictionary where Key: JSONKey { } } +private final class BufferWrapper: @unchecked Sendable { + var buffer: UnsafeMutableBufferPointer + + init(buffer: UnsafeMutableBufferPointer) { + self.buffer = buffer + } +} + public protocol NamedJSONDictionaryConvertible { init(name: String, jsonDictionary: JSONDictionary) throws diff --git a/Sources/ProjectSpec/Dependency.swift b/Sources/ProjectSpec/Dependency.swift index 13e8b4849..f7a72c0a9 100644 --- a/Sources/ProjectSpec/Dependency.swift +++ b/Sources/ProjectSpec/Dependency.swift @@ -5,6 +5,7 @@ public struct Dependency: Equatable { public static let removeHeadersDefault = true public static let implicitDefault = false public static let weakLinkDefault = false + public static let platformFilterDefault: PlatformFilter = .all public var type: DependencyType public var reference: String @@ -14,6 +15,10 @@ public struct Dependency: Equatable { public var link: Bool? public var implicit: Bool = implicitDefault public var weakLink: Bool = weakLinkDefault + public var platformFilter: PlatformFilter = platformFilterDefault + public var destinationFilters: [SupportedDestination]? + public var platforms: Set? + public var copyPhase: BuildPhaseSpec.CopyFilesSettings? public init( type: DependencyType, @@ -22,7 +27,11 @@ public struct Dependency: Equatable { codeSign: Bool? = nil, link: Bool? = nil, implicit: Bool = implicitDefault, - weakLink: Bool = weakLinkDefault + weakLink: Bool = weakLinkDefault, + platformFilter: PlatformFilter = platformFilterDefault, + destinationFilters: [SupportedDestination]? = nil, + platforms: Set? = nil, + copyPhase: BuildPhaseSpec.CopyFilesSettings? = nil ) { self.type = type self.reference = reference @@ -31,8 +40,18 @@ public struct Dependency: Equatable { self.link = link self.implicit = implicit self.weakLink = weakLink + self.platformFilter = platformFilter + self.destinationFilters = destinationFilters + self.platforms = platforms + self.copyPhase = copyPhase } - + + public enum PlatformFilter: String, Equatable { + case all + case iOS + case macOS + } + public enum CarthageLinkType: String { case dynamic case `static` @@ -40,12 +59,12 @@ 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) case sdk(root: String?) - case package(product: String?) + case package(products: [String]) case bundle } } @@ -53,9 +72,9 @@ public struct Dependency: Equatable { extension Dependency { public var uniqueID: String { switch type { - case .package(let product): - if let product = product { - return "\(reference)/\(product)" + case .package(let products): + if !products.isEmpty { + return "\(reference)/\(products.joined(separator: ","))" } else { return reference } @@ -67,6 +86,7 @@ extension Dependency { extension Dependency: Hashable { public func hash(into hasher: inout Hasher) { hasher.combine(reference) + hasher.combine(type) } } @@ -89,9 +109,16 @@ extension Dependency: JSONObjectConvertible { type = .sdk(root: sdkRoot) reference = sdk } else if let package: String = jsonDictionary.json(atKeyPath: "package") { - let product: String? = jsonDictionary.json(atKeyPath: "product") - type = .package(product: product) - reference = package + if let products: [String] = jsonDictionary.json(atKeyPath: "products") { + type = .package(products: products) + reference = package + } else if let product: String = jsonDictionary.json(atKeyPath: "product") { + type = .package(products: [product]) + reference = package + } else { + type = .package(products: []) + reference = package + } } else if let bundle: String = jsonDictionary.json(atKeyPath: "bundle") { type = .bundle reference = bundle @@ -112,6 +139,24 @@ extension Dependency: JSONObjectConvertible { if let bool: Bool = jsonDictionary.json(atKeyPath: "weak") { weakLink = bool } + + if let platformFilterString: String = jsonDictionary.json(atKeyPath: "platformFilter"), let platformFilter = PlatformFilter(rawValue: platformFilterString) { + self.platformFilter = platformFilter + } else { + self.platformFilter = .all + } + + if let destinationFilters: [SupportedDestination] = jsonDictionary.json(atKeyPath: "destinationFilters") { + self.destinationFilters = destinationFilters + } + + if let platforms: [ProjectSpec.Platform] = jsonDictionary.json(atKeyPath: "platforms") { + self.platforms = Set(platforms) + } + + if let object: JSONDictionary = jsonDictionary.json(atKeyPath: "copy") { + copyPhase = try BuildPhaseSpec.CopyFilesSettings(jsonDictionary: object) + } } } @@ -121,6 +166,9 @@ extension Dependency: JSONEncodable { "embed": embed, "codeSign": codeSign, "link": link, + "platforms": platforms?.map(\.rawValue).sorted(), + "copy": copyPhase?.toJSONValue(), + "destinationFilters": destinationFilters?.map { $0.rawValue }, ] if removeHeaders != Dependency.removeHeadersDefault { diff --git a/Sources/ProjectSpec/DeploymentTarget.swift b/Sources/ProjectSpec/DeploymentTarget.swift index 958380313..a22f25ce0 100644 --- a/Sources/ProjectSpec/DeploymentTarget.swift +++ b/Sources/ProjectSpec/DeploymentTarget.swift @@ -8,25 +8,30 @@ public struct DeploymentTarget: Equatable { public var tvOS: Version? public var watchOS: Version? public var macOS: Version? + public var visionOS: Version? public init( iOS: Version? = nil, tvOS: Version? = nil, watchOS: Version? = nil, - macOS: Version? = nil + macOS: Version? = nil, + visionOS: Version? = nil ) { self.iOS = iOS self.tvOS = tvOS self.watchOS = watchOS self.macOS = macOS + self.visionOS = visionOS } public func version(for platform: Platform) -> Version? { switch platform { + case .auto: return nil case .iOS: return iOS case .tvOS: return tvOS case .watchOS: return watchOS case .macOS: return macOS + case .visionOS: return visionOS } } } @@ -35,19 +40,23 @@ extension Platform { public var deploymentTargetSetting: String { switch self { + case .auto: return "" case .iOS: return "IPHONEOS_DEPLOYMENT_TARGET" case .tvOS: return "TVOS_DEPLOYMENT_TARGET" case .watchOS: return "WATCHOS_DEPLOYMENT_TARGET" case .macOS: return "MACOSX_DEPLOYMENT_TARGET" + case .visionOS: return "XROS_DEPLOYMENT_TARGET" } } public var sdkRoot: String { switch self { + case .auto: return "auto" case .iOS: return "iphoneos" case .tvOS: return "appletvos" case .watchOS: return "watchos" case .macOS: return "macosx" + case .visionOS: return "xros" } } } @@ -77,6 +86,7 @@ extension DeploymentTarget: JSONObjectConvertible { tvOS = try parseVersion("tvOS") watchOS = try parseVersion("watchOS") macOS = try parseVersion("macOS") + visionOS = try parseVersion("visionOS") } } @@ -87,6 +97,7 @@ extension DeploymentTarget: JSONEncodable { "tvOS": tvOS?.description, "watchOS": watchOS?.description, "macOS": macOS?.description, + "visionOS": visionOS?.description, ] } } diff --git a/Sources/ProjectSpec/FileType.swift b/Sources/ProjectSpec/FileType.swift new file mode 100644 index 000000000..361fba0c4 --- /dev/null +++ b/Sources/ProjectSpec/FileType.swift @@ -0,0 +1,125 @@ +// +// File.swift +// +// +// Created by Yonas Kolb on 1/5/20. +// + +import Foundation +import JSONUtilities +import enum XcodeProj.BuildPhase + +public struct FileType: Equatable { + + public enum Defaults { + public static let file = true + } + + public var file: Bool + public var buildPhase: BuildPhaseSpec? + public var attributes: [String] + public var resourceTags: [String] + public var compilerFlags: [String] + + public init( + file: Bool = Defaults.file, + buildPhase: BuildPhaseSpec? = nil, + attributes: [String] = [], + resourceTags: [String] = [], + compilerFlags: [String] = [] + ) { + self.file = file + self.buildPhase = buildPhase + self.attributes = attributes + self.resourceTags = resourceTags + self.compilerFlags = compilerFlags + } +} + +extension FileType: JSONObjectConvertible { + public init(jsonDictionary: JSONDictionary) throws { + if let string: String = jsonDictionary.json(atKeyPath: "buildPhase") { + buildPhase = try BuildPhaseSpec(string: string) + } else if let dict: JSONDictionary = jsonDictionary.json(atKeyPath: "buildPhase") { + buildPhase = try BuildPhaseSpec(jsonDictionary: dict) + } + file = jsonDictionary.json(atKeyPath: "file") ?? Defaults.file + attributes = jsonDictionary.json(atKeyPath: "attributes") ?? [] + resourceTags = jsonDictionary.json(atKeyPath: "resourceTags") ?? [] + compilerFlags = jsonDictionary.json(atKeyPath: "compilerFlags") ?? [] + } +} + +extension FileType: JSONEncodable { + public func toJSONValue() -> Any { + var dict: [String: Any?] = [ + "buildPhase": buildPhase?.toJSONValue(), + "attributes": attributes, + "resourceTags": resourceTags, + "compilerFlags": compilerFlags, + ] + if file != Defaults.file { + dict["file"] = file + } + return dict + } +} + +extension FileType { + + public static let defaultFileTypes: [String: FileType] = [ + // resources + "bundle": FileType(buildPhase: .resources), + "xcassets": FileType(buildPhase: .resources), + "storekit": FileType(buildPhase: .resources), + "xcstrings": FileType(buildPhase: .resources), + + // sources + "swift": FileType(buildPhase: .sources), + "gyb": FileType(buildPhase: .sources), + "m": FileType(buildPhase: .sources), + "mm": FileType(buildPhase: .sources), + "cpp": FileType(buildPhase: .sources), + "cp": FileType(buildPhase: .sources), + "cxx": FileType(buildPhase: .sources), + "c": FileType(buildPhase: .sources), + "cc": FileType(buildPhase: .sources), + "S": FileType(buildPhase: .sources), + "xcdatamodeld": FileType(buildPhase: .sources), + "xcmappingmodel": FileType(buildPhase: .sources), + "intentdefinition": FileType(buildPhase: .sources), + "metal": FileType(buildPhase: .sources), + "mlmodel": FileType(buildPhase: .sources), + "mlpackage" : FileType(buildPhase: .sources), + "mlmodelc": FileType(buildPhase: .resources), + "rcproject": FileType(buildPhase: .sources), + "iig": FileType(buildPhase: .sources), + "docc": FileType(buildPhase: .sources), + + // headers + "h": FileType(buildPhase: .headers), + "hh": FileType(buildPhase: .headers), + "hpp": FileType(buildPhase: .headers), + "ipp": FileType(buildPhase: .headers), + "tpp": FileType(buildPhase: .headers), + "hxx": FileType(buildPhase: .headers), + "def": FileType(buildPhase: .headers), + + // frameworks + "framework": FileType(buildPhase: .frameworks), + + // copyfiles + "xpc": FileType(buildPhase: .copyFiles(.xpcServices)), + "appex": FileType(buildPhase: .copyFiles(.plugins)), + + // no build phase (not resources) + "xcconfig": FileType(buildPhase: BuildPhaseSpec.none), + "entitlements": FileType(buildPhase: BuildPhaseSpec.none), + "gpx": FileType(buildPhase: BuildPhaseSpec.none), + "lproj": FileType(buildPhase: BuildPhaseSpec.none), + "xcfilelist": FileType(buildPhase: BuildPhaseSpec.none), + "apns": FileType(buildPhase: BuildPhaseSpec.none), + "pch": FileType(buildPhase: BuildPhaseSpec.none), + "xctestplan": FileType(buildPhase: BuildPhaseSpec.none), + ] +} diff --git a/Sources/ProjectSpec/Linkage.swift b/Sources/ProjectSpec/Linkage.swift index 47362562a..250f8207f 100644 --- a/Sources/ProjectSpec/Linkage.swift +++ b/Sources/ProjectSpec/Linkage.swift @@ -7,10 +7,10 @@ public enum Linkage { case none } -extension PBXProductType { +extension Target { public var defaultLinkage: Linkage { - switch self { + switch type { case .none, .appExtension, .application, @@ -20,6 +20,7 @@ extension PBXProductType { .intentsServiceExtension, .messagesApplication, .messagesExtension, + .metalLibrary, .ocUnitTestBundle, .onDemandInstallCapableApplication, .stickerPack, @@ -32,11 +33,18 @@ extension PBXProductType { .watch2AppContainer, .watch2Extension, .xcodeExtension, - .xpcService: + .xpcService, + .systemExtension, + .driverExtension, + .extensionKitExtension: return .none case .framework, .xcFramework: - // TODO: This should check `MACH_O_TYPE` in case this is a "Static Framework" - return .dynamic + // Check the MACH_O_TYPE for "Static Framework" + if settings.buildSettings.machOType == "staticlib" { + return .static + } else { + return .dynamic + } case .dynamicLibrary: return .dynamic case .staticLibrary, .staticFramework: @@ -44,3 +52,10 @@ extension PBXProductType { } } } + +private extension BuildSettings { + + var machOType: String? { + self["MACH_O_TYPE"] as? String + } +} diff --git a/Sources/ProjectSpec/Platform.swift b/Sources/ProjectSpec/Platform.swift index f3652de8b..5f7613b41 100644 --- a/Sources/ProjectSpec/Platform.swift +++ b/Sources/ProjectSpec/Platform.swift @@ -1,8 +1,10 @@ import Foundation public enum Platform: String, Hashable, CaseIterable { + case auto case iOS - case watchOS case tvOS case macOS + case watchOS + case visionOS } diff --git a/Sources/ProjectSpec/Plist.swift b/Sources/ProjectSpec/Plist.swift index d478fd019..124b4bfbf 100644 --- a/Sources/ProjectSpec/Plist.swift +++ b/Sources/ProjectSpec/Plist.swift @@ -30,7 +30,7 @@ extension Plist: JSONEncodable { [ "path": path, "properties": properties, - ] + ] as [String : Any] } } diff --git a/Sources/ProjectSpec/Project.swift b/Sources/ProjectSpec/Project.swift index 2d6842dcf..e872a27bf 100644 --- a/Sources/ProjectSpec/Project.swift +++ b/Sources/ProjectSpec/Project.swift @@ -25,6 +25,7 @@ public struct Project: BuildSettingsContainer { public var settingGroups: [String: Settings] public var configs: [Config] public var schemes: [Scheme] + public var breakpoints: [Breakpoint] public var options: SpecOptions public var attributes: [String: Any] public var fileGroups: [String] @@ -49,6 +50,7 @@ public struct Project: BuildSettingsContainer { settings: Settings = .empty, settingGroups: [String: Settings] = [:], schemes: [Scheme] = [], + breakpoints: [Breakpoint] = [], packages: [String: SwiftPackage] = [:], options: SpecOptions = SpecOptions(), fileGroups: [String] = [], @@ -66,6 +68,7 @@ public struct Project: BuildSettingsContainer { self.settings = settings self.settingGroups = settingGroups self.schemes = schemes + self.breakpoints = breakpoints self.packages = packages self.options = options self.fileGroups = fileGroups @@ -83,6 +86,10 @@ public struct Project: BuildSettingsContainer { targetsMap[targetName] } + public func getPackage(_ packageName: String) -> SwiftPackage? { + packages[packageName] + } + public func getAggregateTarget(_ targetName: String) -> AggregateTarget? { aggregateTargetsMap[targetName] } @@ -140,6 +147,7 @@ extension Project: Equatable { lhs.settingGroups == rhs.settingGroups && lhs.configs == rhs.configs && lhs.schemes == rhs.schemes && + lhs.breakpoints == rhs.breakpoints && lhs.fileGroups == rhs.fileGroups && lhs.configFiles == rhs.configFiles && lhs.options == rhs.options && @@ -163,11 +171,13 @@ extension Project { self.basePath = basePath let jsonDictionary = Project.resolveProject(jsonDictionary: jsonDictionary) + let buildSettingsParser = BuildSettingsParser(jsonDictionary: jsonDictionary) name = try jsonDictionary.json(atKeyPath: "name") - settings = jsonDictionary.json(atKeyPath: "settings") ?? .empty - settingGroups = jsonDictionary.json(atKeyPath: "settingGroups") - ?? jsonDictionary.json(atKeyPath: "settingPresets") ?? [:] + + settings = try buildSettingsParser.parse() + settingGroups = try buildSettingsParser.parseSettingGroups() + let configs: [String: String] = jsonDictionary.json(atKeyPath: "configs") ?? [:] self.configs = configs.isEmpty ? Config.defaultConfigs : configs.map { Config(name: $0, type: ConfigType(rawValue: $1)) }.sorted { $0.name < $1.name } @@ -175,6 +185,11 @@ extension Project { aggregateTargets = try jsonDictionary.json(atKeyPath: "aggregateTargets").sorted { $0.name < $1.name } projectReferences = try jsonDictionary.json(atKeyPath: "projectReferences").sorted { $0.name < $1.name } schemes = try jsonDictionary.json(atKeyPath: "schemes") + if jsonDictionary["breakpoints"] != nil { + breakpoints = try jsonDictionary.json(atKeyPath: "breakpoints", invalidItemBehaviour: .fail) + } else { + breakpoints = [] + } fileGroups = jsonDictionary.json(atKeyPath: "fileGroups") ?? [] configFiles = jsonDictionary.json(atKeyPath: "configFiles") ?? [:] attributes = jsonDictionary.json(atKeyPath: "attributes") ?? [:] @@ -189,7 +204,7 @@ extension Project { packages.merge(localPackages.reduce(into: [String: SwiftPackage]()) { // Project name will be obtained by resolved abstractpath's lastComponent for dealing with some path case, like "../" let packageName = (basePath + Path($1).normalize()).lastComponent - $0[packageName] = .local(path: $1) + $0[packageName] = .local(path: $1, group: nil, excludeFromProject: false) } ) } @@ -226,14 +241,18 @@ extension Project: PathContainer { .object("targets", Target.pathProperties), .object("targetTemplates", Target.pathProperties), .object("aggregateTargets", AggregateTarget.pathProperties), + .object("schemes", Scheme.pathProperties), .object("projectReferences", ProjectReference.pathProperties), + .object("packages", SwiftPackage.pathProperties), + .string("localPackages"), + .string("fileGroups") ] } } extension Project { - public var allFiles: [Path] { + public var allTrackedFiles: [Path] { var files: [Path] = [] files.append(contentsOf: configFilePaths) for fileGroup in fileGroups { @@ -251,8 +270,12 @@ extension Project { files.append(contentsOf: target.configFilePaths) for source in target.sources { let sourcePath = basePath + source.path - let sourceChildren = (try? sourcePath.recursiveChildren()) ?? [] - files.append(contentsOf: sourceChildren) + + let type = source.type ?? options.defaultSourceDirectoryType ?? .group + if type.projectTracksChildren { + let sourceChildren = (try? sourcePath.recursiveChildren()) ?? [] + files.append(contentsOf: sourceChildren) + } files.append(sourcePath) } } @@ -260,6 +283,18 @@ extension Project { } } +extension SourceType { + + var projectTracksChildren: Bool { + switch self { + case .file: false + case .folder: false + case .group: true + case .syncedFolder: false + } + } +} + extension BuildSettingsContainer { fileprivate var configFilePaths: [Path] { diff --git a/Sources/ProjectSpec/ProjectTarget.swift b/Sources/ProjectSpec/ProjectTarget.swift index 0411b0eb2..6539f3e84 100644 --- a/Sources/ProjectSpec/ProjectTarget.swift +++ b/Sources/ProjectSpec/ProjectTarget.swift @@ -1,9 +1,12 @@ import Foundation +import XcodeProj public protocol ProjectTarget: BuildSettingsContainer { var name: String { get } + var type: PBXProductType { get } var buildScripts: [BuildScript] { get } + var buildToolPlugins: [BuildToolPlugin] { get } var scheme: TargetScheme? { get } var attributes: [String: Any] { get } } diff --git a/Sources/ProjectSpec/Scheme.swift b/Sources/ProjectSpec/Scheme.swift index 986268aa8..a19951fe8 100644 --- a/Sources/ProjectSpec/Scheme.swift +++ b/Sources/ProjectSpec/Scheme.swift @@ -1,5 +1,6 @@ import Foundation import JSONUtilities +import PathKit import XcodeProj public typealias BuildType = XCScheme.BuildAction.Entry.BuildFor @@ -13,6 +14,7 @@ public struct Scheme: Equatable { public var analyze: Analyze? public var test: Test? public var profile: Profile? + public var management: Management? public init( name: String, @@ -21,7 +23,8 @@ public struct Scheme: Equatable { test: Test? = nil, profile: Profile? = nil, analyze: Analyze? = nil, - archive: Archive? = nil + archive: Archive? = nil, + management: Management? = nil ) { self.name = name self.build = build @@ -30,6 +33,29 @@ public struct Scheme: Equatable { self.profile = profile self.analyze = analyze self.archive = archive + self.management = management + } + + public struct Management: Equatable { + public static let sharedDefault = true + + public var shared: Bool + public var orderHint: Int? + public var isShown: Bool? + + public init?( + shared: Bool = Scheme.Management.sharedDefault, + orderHint: Int? = nil, + isShown: Bool? = nil + ) { + if shared == Scheme.Management.sharedDefault, orderHint == nil, isShown == nil { + return nil + } + + self.shared = shared + self.orderHint = orderHint + self.isShown = isShown + } } public struct SimulateLocation: Equatable { @@ -62,50 +88,69 @@ public struct Scheme: Equatable { public var script: String public var name: String public var settingsTarget: String? - public init(name: String, script: String, settingsTarget: String? = nil) { + public var shell: String? + public init(name: String, script: String, shell: String? = nil, settingsTarget: String? = nil) { self.script = script self.name = name self.settingsTarget = settingsTarget + self.shell = shell } } public struct Build: Equatable { public static let parallelizeBuildDefault = true public static let buildImplicitDependenciesDefault = true + public static let runPostActionsOnFailureDefault = false public var targets: [BuildTarget] public var parallelizeBuild: Bool public var buildImplicitDependencies: Bool public var preActions: [ExecutionAction] public var postActions: [ExecutionAction] + public var runPostActionsOnFailure: Bool public init( targets: [BuildTarget], parallelizeBuild: Bool = parallelizeBuildDefault, buildImplicitDependencies: Bool = buildImplicitDependenciesDefault, preActions: [ExecutionAction] = [], - postActions: [ExecutionAction] = [] + postActions: [ExecutionAction] = [], + runPostActionsOnFailure: Bool = false ) { self.targets = targets self.parallelizeBuild = parallelizeBuild self.buildImplicitDependencies = buildImplicitDependencies self.preActions = preActions self.postActions = postActions + self.runPostActionsOnFailure = runPostActionsOnFailure } } public struct Run: BuildAction { + public static let enableAddressSanitizerDefault = false + public static let enableASanStackUseAfterReturnDefault = false + public static let enableThreadSanitizerDefault = false + public static let enableUBSanitizerDefault = false public static let disableMainThreadCheckerDefault = false public static let stopOnEveryMainThreadCheckerIssueDefault = false + public static let disableThreadPerformanceCheckerDefault = false public static let debugEnabledDefault = true + public static let enableGPUValidationModeDefault = true public var config: String? public var commandLineArguments: [String: Bool] public var preActions: [ExecutionAction] public var postActions: [ExecutionAction] public var environmentVariables: [XCScheme.EnvironmentVariable] + public var enableGPUFrameCaptureMode: XCScheme.LaunchAction.GPUFrameCaptureMode + public var enableGPUValidationMode: Bool + public var enableAddressSanitizer: Bool + public var enableASanStackUseAfterReturn: Bool + public var enableThreadSanitizer: Bool + public var enableUBSanitizer: Bool public var disableMainThreadChecker: Bool public var stopOnEveryMainThreadCheckerIssue: Bool + public var disableThreadPerformanceChecker: Bool public var language: String? public var region: String? public var askForAppToLaunch: Bool? @@ -113,47 +158,84 @@ public struct Scheme: Equatable { public var debugEnabled: Bool public var simulateLocation: SimulateLocation? public var executable: String? + public var storeKitConfiguration: String? + public var customLLDBInit: String? + public var macroExpansion: String? + public var customWorkingDirectory: String? public init( - config: String, + config: String? = nil, executable: String? = nil, commandLineArguments: [String: Bool] = [:], preActions: [ExecutionAction] = [], postActions: [ExecutionAction] = [], environmentVariables: [XCScheme.EnvironmentVariable] = [], + enableGPUFrameCaptureMode: XCScheme.LaunchAction.GPUFrameCaptureMode = XCScheme.LaunchAction.defaultGPUFrameCaptureMode, + enableGPUValidationMode: Bool = enableGPUValidationModeDefault, + enableAddressSanitizer: Bool = enableAddressSanitizerDefault, + enableASanStackUseAfterReturn: Bool = enableASanStackUseAfterReturnDefault, + enableThreadSanitizer: Bool = enableThreadSanitizerDefault, + enableUBSanitizer: Bool = enableUBSanitizerDefault, disableMainThreadChecker: Bool = disableMainThreadCheckerDefault, stopOnEveryMainThreadCheckerIssue: Bool = stopOnEveryMainThreadCheckerIssueDefault, + disableThreadPerformanceChecker: Bool = disableThreadPerformanceCheckerDefault, language: String? = nil, region: String? = nil, askForAppToLaunch: Bool? = nil, launchAutomaticallySubstyle: String? = nil, debugEnabled: Bool = debugEnabledDefault, - simulateLocation: SimulateLocation? = nil + simulateLocation: SimulateLocation? = nil, + storeKitConfiguration: String? = nil, + customLLDBInit: String? = nil, + macroExpansion: String? = nil, + customWorkingDirectory: String? = nil ) { self.config = config self.commandLineArguments = commandLineArguments self.preActions = preActions self.postActions = postActions self.environmentVariables = environmentVariables + self.enableAddressSanitizer = enableAddressSanitizer + self.enableASanStackUseAfterReturn = enableASanStackUseAfterReturn + self.enableThreadSanitizer = enableThreadSanitizer + self.enableUBSanitizer = enableUBSanitizer self.disableMainThreadChecker = disableMainThreadChecker + self.enableGPUFrameCaptureMode = enableGPUFrameCaptureMode + self.enableGPUValidationMode = enableGPUValidationMode self.stopOnEveryMainThreadCheckerIssue = stopOnEveryMainThreadCheckerIssue + self.disableThreadPerformanceChecker = disableThreadPerformanceChecker self.language = language self.region = region self.askForAppToLaunch = askForAppToLaunch self.launchAutomaticallySubstyle = launchAutomaticallySubstyle self.debugEnabled = debugEnabled self.simulateLocation = simulateLocation + self.storeKitConfiguration = storeKitConfiguration + self.customLLDBInit = customLLDBInit + self.macroExpansion = macroExpansion + self.customWorkingDirectory = customWorkingDirectory } } public struct Test: BuildAction { public static let gatherCoverageDataDefault = false + public static let enableAddressSanitizerDefault = false + public static let enableASanStackUseAfterReturnDefault = false + public static let enableThreadSanitizerDefault = false + public static let enableUBSanitizerDefault = false public static let disableMainThreadCheckerDefault = false public static let debugEnabledDefault = true + public static let captureScreenshotsAutomaticallyDefault = true + public static let deleteScreenshotsWhenEachTestSucceedsDefault = true + public static let preferredScreenCaptureFormatDefault = XCScheme.TestAction.ScreenCaptureFormat.screenRecording public var config: String? public var gatherCoverageData: Bool - public var coverageTargets: [TargetReference] + public var coverageTargets: [TestableTargetReference] + public var enableAddressSanitizer: Bool + public var enableASanStackUseAfterReturn: Bool + public var enableThreadSanitizer: Bool + public var enableUBSanitizer: Bool public var disableMainThreadChecker: Bool public var commandLineArguments: [String: Bool] public var targets: [TestTarget] @@ -163,35 +245,54 @@ public struct Scheme: Equatable { public var language: String? public var region: String? public var debugEnabled: Bool + public var customLLDBInit: String? + public var captureScreenshotsAutomatically: Bool + public var deleteScreenshotsWhenEachTestSucceeds: Bool + public var testPlans: [TestPlan] + public var macroExpansion: String? + public var preferredScreenCaptureFormat: XCScheme.TestAction.ScreenCaptureFormat public struct TestTarget: Equatable, ExpressibleByStringLiteral { + public static let randomExecutionOrderDefault = false public static let parallelizableDefault = false public var name: String { targetReference.name } - public let targetReference: TargetReference + public let targetReference: TestableTargetReference public var randomExecutionOrder: Bool public var parallelizable: Bool + public var location: String? + public var skipped: Bool public var skippedTests: [String] + public var selectedTests: [String] public init( - targetReference: TargetReference, + targetReference: TestableTargetReference, randomExecutionOrder: Bool = randomExecutionOrderDefault, parallelizable: Bool = parallelizableDefault, - skippedTests: [String] = [] + location: String? = nil, + skipped: Bool = false, + skippedTests: [String] = [], + selectedTests: [String] = [] ) { self.targetReference = targetReference self.randomExecutionOrder = randomExecutionOrder self.parallelizable = parallelizable + self.location = location + self.skipped = skipped self.skippedTests = skippedTests + self.selectedTests = selectedTests } public init(stringLiteral value: String) { do { - targetReference = try TargetReference(value) + targetReference = try TestableTargetReference(value) randomExecutionOrder = false parallelizable = false + location = nil + skipped = false skippedTests = [] + selectedTests = [] } catch { fatalError(SpecParsingError.invalidTargetReference(value).description) } @@ -199,9 +300,13 @@ public struct Scheme: Equatable { } public init( - config: String, + config: String? = nil, gatherCoverageData: Bool = gatherCoverageDataDefault, - coverageTargets: [TargetReference] = [], + coverageTargets: [TestableTargetReference] = [], + enableAddressSanitizer: Bool = enableAddressSanitizerDefault, + enableASanStackUseAfterReturn: Bool = enableASanStackUseAfterReturnDefault, + enableThreadSanitizer: Bool = enableThreadSanitizerDefault, + enableUBSanitizer: Bool = enableUBSanitizerDefault, disableMainThreadChecker: Bool = disableMainThreadCheckerDefault, randomExecutionOrder: Bool = false, parallelizable: Bool = false, @@ -210,22 +315,38 @@ public struct Scheme: Equatable { preActions: [ExecutionAction] = [], postActions: [ExecutionAction] = [], environmentVariables: [XCScheme.EnvironmentVariable] = [], + testPlans: [TestPlan] = [], language: String? = nil, region: String? = nil, - debugEnabled: Bool = debugEnabledDefault + debugEnabled: Bool = debugEnabledDefault, + customLLDBInit: String? = nil, + captureScreenshotsAutomatically: Bool = captureScreenshotsAutomaticallyDefault, + deleteScreenshotsWhenEachTestSucceeds: Bool = deleteScreenshotsWhenEachTestSucceedsDefault, + macroExpansion: String? = nil, + preferredScreenCaptureFormat: XCScheme.TestAction.ScreenCaptureFormat = preferredScreenCaptureFormatDefault ) { self.config = config self.gatherCoverageData = gatherCoverageData self.coverageTargets = coverageTargets + self.enableAddressSanitizer = enableAddressSanitizer + self.enableASanStackUseAfterReturn = enableASanStackUseAfterReturn + self.enableThreadSanitizer = enableThreadSanitizer + self.enableUBSanitizer = enableUBSanitizer self.disableMainThreadChecker = disableMainThreadChecker self.commandLineArguments = commandLineArguments self.targets = targets self.preActions = preActions self.postActions = postActions self.environmentVariables = environmentVariables + self.testPlans = testPlans self.language = language self.region = region self.debugEnabled = debugEnabled + self.customLLDBInit = customLLDBInit + self.captureScreenshotsAutomatically = captureScreenshotsAutomatically + self.deleteScreenshotsWhenEachTestSucceeds = deleteScreenshotsWhenEachTestSucceeds + self.macroExpansion = macroExpansion + self.preferredScreenCaptureFormat = preferredScreenCaptureFormat } public var shouldUseLaunchSchemeArgsEnv: Bool { @@ -246,18 +367,22 @@ public struct Scheme: Equatable { public var preActions: [ExecutionAction] public var postActions: [ExecutionAction] public var environmentVariables: [XCScheme.EnvironmentVariable] + public var askForAppToLaunch: Bool? + public init( - config: String, + config: String? = nil, commandLineArguments: [String: Bool] = [:], preActions: [ExecutionAction] = [], postActions: [ExecutionAction] = [], - environmentVariables: [XCScheme.EnvironmentVariable] = [] + environmentVariables: [XCScheme.EnvironmentVariable] = [], + askForAppToLaunch: Bool? = nil ) { self.config = config self.commandLineArguments = commandLineArguments self.preActions = preActions self.postActions = postActions self.environmentVariables = environmentVariables + self.askForAppToLaunch = askForAppToLaunch } public var shouldUseLaunchSchemeArgsEnv: Bool { @@ -274,7 +399,7 @@ public struct Scheme: Equatable { public var preActions: [ExecutionAction] public var postActions: [ExecutionAction] public init( - config: String, + config: String? = nil, customArchiveName: String? = nil, revealArchiveInOrganizer: Bool = revealArchiveInOrganizerDefault, preActions: [ExecutionAction] = [], @@ -289,16 +414,27 @@ public struct Scheme: Equatable { } public struct BuildTarget: Equatable, Hashable { - public var target: TargetReference + public var target: TestableTargetReference public var buildTypes: [BuildType] - public init(target: TargetReference, buildTypes: [BuildType] = BuildType.all) { + public init(target: TestableTargetReference, buildTypes: [BuildType] = BuildType.all) { self.target = target self.buildTypes = buildTypes } } } +extension Scheme: PathContainer { + + static var pathProperties: [PathProperty] { + [ + .dictionary([ + .object("test", Test.pathProperties), + ]), + ] + } +} + protocol BuildAction: Equatable { var config: String? { get } } @@ -309,6 +445,7 @@ extension Scheme.ExecutionAction: JSONObjectConvertible { script = try jsonDictionary.json(atKeyPath: "script") name = jsonDictionary.json(atKeyPath: "name") ?? "Run Script" settingsTarget = jsonDictionary.json(atKeyPath: "settingsTarget") + shell = jsonDictionary.json(atKeyPath: "shell") } } @@ -318,6 +455,7 @@ extension Scheme.ExecutionAction: JSONEncodable { "script": script, "name": name, "settingsTarget": settingsTarget, + "shell": shell ] } } @@ -344,6 +482,35 @@ extension Scheme.SimulateLocation: JSONEncodable { } } +extension Scheme.Management: JSONObjectConvertible { + + public init(jsonDictionary: JSONDictionary) throws { + shared = jsonDictionary.json(atKeyPath: "shared") ?? Scheme.Management.sharedDefault + orderHint = jsonDictionary.json(atKeyPath: "orderHint") + isShown = jsonDictionary.json(atKeyPath: "isShown") + } +} + +extension Scheme.Management: JSONEncodable { + public func toJSONValue() -> Any { + var dict: [String: Any?] = [:] + + if shared != Scheme.Management.sharedDefault { + dict["shared"] = shared + } + + if let isShown = isShown { + dict["isShown"] = isShown + } + + if let orderHint = orderHint { + dict["orderHint"] = orderHint + } + + return dict + } +} + extension Scheme.Run: JSONObjectConvertible { public init(jsonDictionary: JSONDictionary) throws { @@ -352,12 +519,34 @@ 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 + } + + // support deprecated gpuValidationMode enum that was removed from XcodeProj + if let gpuValidationMode: String = jsonDictionary.json(atKeyPath: "enableGPUValidationMode") { + switch gpuValidationMode { + case "enabled", "extended": enableGPUValidationMode = true + case "disabled": enableGPUValidationMode = false + default: enableGPUValidationMode = Scheme.Run.enableGPUValidationModeDefault + } + } else { + enableGPUValidationMode = jsonDictionary.json(atKeyPath: "enableGPUValidationMode") ?? Scheme.Run.enableGPUValidationModeDefault + } + enableAddressSanitizer = jsonDictionary.json(atKeyPath: "enableAddressSanitizer") ?? Scheme.Run.enableAddressSanitizerDefault + enableASanStackUseAfterReturn = jsonDictionary.json(atKeyPath: "enableASanStackUseAfterReturn") ?? Scheme.Run.enableASanStackUseAfterReturnDefault + enableThreadSanitizer = jsonDictionary.json(atKeyPath: "enableThreadSanitizer") ?? Scheme.Run.enableThreadSanitizerDefault + enableUBSanitizer = jsonDictionary.json(atKeyPath: "enableUBSanitizer") ?? Scheme.Run.enableUBSanitizerDefault disableMainThreadChecker = jsonDictionary.json(atKeyPath: "disableMainThreadChecker") ?? Scheme.Run.disableMainThreadCheckerDefault stopOnEveryMainThreadCheckerIssue = jsonDictionary.json(atKeyPath: "stopOnEveryMainThreadCheckerIssue") ?? Scheme.Run.stopOnEveryMainThreadCheckerIssueDefault + disableThreadPerformanceChecker = jsonDictionary.json(atKeyPath: "disableThreadPerformanceChecker") ?? Scheme.Run.disableThreadPerformanceCheckerDefault language = jsonDictionary.json(atKeyPath: "language") region = jsonDictionary.json(atKeyPath: "region") debugEnabled = jsonDictionary.json(atKeyPath: "debugEnabled") ?? Scheme.Run.debugEnabledDefault simulateLocation = jsonDictionary.json(atKeyPath: "simulateLocation") + storeKitConfiguration = jsonDictionary.json(atKeyPath: "storeKitConfiguration") executable = jsonDictionary.json(atKeyPath: "executable") // launchAutomaticallySubstyle is defined as a String in XcodeProj but its value is often @@ -371,6 +560,9 @@ extension Scheme.Run: JSONObjectConvertible { if let askLaunch: Bool = jsonDictionary.json(atKeyPath: "askForAppToLaunch") { askForAppToLaunch = askLaunch } + customLLDBInit = jsonDictionary.json(atKeyPath: "customLLDBInit") + macroExpansion = jsonDictionary.json(atKeyPath: "macroExpansion") + customWorkingDirectory = jsonDictionary.json(atKeyPath: "customWorkingDirectory") } } @@ -387,8 +579,33 @@ extension Scheme.Run: JSONEncodable { "askForAppToLaunch": askForAppToLaunch, "launchAutomaticallySubstyle": launchAutomaticallySubstyle, "executable": executable, + "macroExpansion": macroExpansion ] + if enableGPUFrameCaptureMode != XCScheme.LaunchAction.defaultGPUFrameCaptureMode { + dict["enableGPUFrameCaptureMode"] = enableGPUFrameCaptureMode.toJSONValue() + } + + if enableGPUValidationMode != Scheme.Run.enableGPUValidationModeDefault { + dict["enableGPUValidationMode"] = enableGPUValidationMode + } + + if enableAddressSanitizer != Scheme.Run.enableAddressSanitizerDefault { + dict["enableAddressSanitizer"] = enableAddressSanitizer + } + + if enableASanStackUseAfterReturn != Scheme.Run.enableASanStackUseAfterReturnDefault { + dict["enableASanStackUseAfterReturn"] = enableASanStackUseAfterReturn + } + + if enableThreadSanitizer != Scheme.Run.enableThreadSanitizerDefault { + dict["enableThreadSanitizer"] = enableThreadSanitizer + } + + if enableUBSanitizer != Scheme.Run.enableUBSanitizerDefault { + dict["enableUBSanitizer"] = enableUBSanitizer + } + if disableMainThreadChecker != Scheme.Run.disableMainThreadCheckerDefault { dict["disableMainThreadChecker"] = disableMainThreadChecker } @@ -397,6 +614,10 @@ extension Scheme.Run: JSONEncodable { dict["stopOnEveryMainThreadCheckerIssue"] = stopOnEveryMainThreadCheckerIssue } + if disableThreadPerformanceChecker != Scheme.Run.disableThreadPerformanceCheckerDefault { + dict["disableThreadPerformanceChecker"] = disableThreadPerformanceChecker + } + if debugEnabled != Scheme.Run.debugEnabledDefault { dict["debugEnabled"] = debugEnabled } @@ -404,22 +625,59 @@ extension Scheme.Run: JSONEncodable { if let simulateLocation = simulateLocation { dict["simulateLocation"] = simulateLocation.toJSONValue() } + if let storeKitConfiguration = storeKitConfiguration { + dict["storeKitConfiguration"] = storeKitConfiguration + } + if let customLLDBInit = customLLDBInit { + dict["customLLDBInit"] = customLLDBInit + } + if let customWorkingDirectory = customWorkingDirectory { + dict["customWorkingDirectory"] = customWorkingDirectory + } return dict } } +extension Scheme.Test: PathContainer { + + static var pathProperties: [PathProperty] { + [ + .object("testPlans", TestPlan.pathProperties), + ] + } +} + extension Scheme.Test: JSONObjectConvertible { public init(jsonDictionary: JSONDictionary) throws { config = jsonDictionary.json(atKeyPath: "config") gatherCoverageData = jsonDictionary.json(atKeyPath: "gatherCoverageData") ?? Scheme.Test.gatherCoverageDataDefault - coverageTargets = try (jsonDictionary.json(atKeyPath: "coverageTargets") ?? []).map { try TargetReference($0) } + + if let coverages = jsonDictionary["coverageTargets"] as? [Any] { + coverageTargets = try coverages.compactMap { target in + if let string = target as? String { + return try TestableTargetReference(string) + } else if let dictionary = target as? JSONDictionary, + let target: TestableTargetReference = try? .init(jsonDictionary: dictionary) { + return target + } else { + return nil + } + } + } else { + coverageTargets = [] + } + + enableAddressSanitizer = jsonDictionary.json(atKeyPath: "enableAddressSanitizer") ?? Scheme.Test.enableAddressSanitizerDefault + enableASanStackUseAfterReturn = jsonDictionary.json(atKeyPath: "enableASanStackUseAfterReturn") ?? Scheme.Test.enableASanStackUseAfterReturnDefault + enableThreadSanitizer = jsonDictionary.json(atKeyPath: "enableThreadSanitizer") ?? Scheme.Test.enableThreadSanitizerDefault + enableUBSanitizer = jsonDictionary.json(atKeyPath: "enableUBSanitizer") ?? Scheme.Test.enableUBSanitizerDefault disableMainThreadChecker = jsonDictionary.json(atKeyPath: "disableMainThreadChecker") ?? Scheme.Test.disableMainThreadCheckerDefault commandLineArguments = jsonDictionary.json(atKeyPath: "commandLineArguments") ?? [:] if let targets = jsonDictionary["targets"] as? [Any] { self.targets = try targets.compactMap { target in if let string = target as? String { - return try TestTarget(targetReference: TargetReference(string)) + return try TestTarget(targetReference: TestableTargetReference(string)) } else if let dictionary = target as? JSONDictionary { return try TestTarget(jsonDictionary: dictionary) } else { @@ -432,9 +690,15 @@ extension Scheme.Test: JSONObjectConvertible { preActions = jsonDictionary.json(atKeyPath: "preActions") ?? [] postActions = jsonDictionary.json(atKeyPath: "postActions") ?? [] environmentVariables = try XCScheme.EnvironmentVariable.parseAll(jsonDictionary: jsonDictionary) + testPlans = try (jsonDictionary.json(atKeyPath: "testPlans") ?? []).map { try TestPlan(jsonDictionary: $0) } language = jsonDictionary.json(atKeyPath: "language") region = jsonDictionary.json(atKeyPath: "region") debugEnabled = jsonDictionary.json(atKeyPath: "debugEnabled") ?? Scheme.Test.debugEnabledDefault + customLLDBInit = jsonDictionary.json(atKeyPath: "customLLDBInit") + captureScreenshotsAutomatically = jsonDictionary.json(atKeyPath: "captureScreenshotsAutomatically") ?? Scheme.Test.captureScreenshotsAutomaticallyDefault + deleteScreenshotsWhenEachTestSucceeds = jsonDictionary.json(atKeyPath: "deleteScreenshotsWhenEachTestSucceeds") ?? Scheme.Test.deleteScreenshotsWhenEachTestSucceedsDefault + macroExpansion = jsonDictionary.json(atKeyPath: "macroExpansion") + preferredScreenCaptureFormat = jsonDictionary.json(atKeyPath: "preferredScreenCaptureFormat") ?? Scheme.Test.preferredScreenCaptureFormatDefault } } @@ -446,16 +710,34 @@ extension Scheme.Test: JSONEncodable { "preActions": preActions.map { $0.toJSONValue() }, "postActions": postActions.map { $0.toJSONValue() }, "environmentVariables": environmentVariables.map { $0.toJSONValue() }, + "testPlans": testPlans.map { $0.toJSONValue() }, "config": config, "language": language, "region": region, "coverageTargets": coverageTargets.map { $0.reference }, + "macroExpansion": macroExpansion ] if gatherCoverageData != Scheme.Test.gatherCoverageDataDefault { dict["gatherCoverageData"] = gatherCoverageData } + if enableAddressSanitizer != Scheme.Test.enableAddressSanitizerDefault { + dict["enableAddressSanitizer"] = enableAddressSanitizer + } + + if enableASanStackUseAfterReturn != Scheme.Test.enableASanStackUseAfterReturnDefault { + dict["enableASanStackUseAfterReturn"] = enableASanStackUseAfterReturn + } + + if enableThreadSanitizer != Scheme.Test.enableThreadSanitizerDefault { + dict["enableThreadSanitizer"] = enableThreadSanitizer + } + + if enableUBSanitizer != Scheme.Test.enableUBSanitizerDefault { + dict["enableUBSanitizer"] = enableUBSanitizer + } + if disableMainThreadChecker != Scheme.Test.disableMainThreadCheckerDefault { dict["disableMainThreadChecker"] = disableMainThreadChecker } @@ -464,6 +746,22 @@ extension Scheme.Test: JSONEncodable { dict["debugEnabled"] = debugEnabled } + if let customLLDBInit = customLLDBInit { + dict["customLLDBInit"] = customLLDBInit + } + + if captureScreenshotsAutomatically != Scheme.Test.captureScreenshotsAutomaticallyDefault { + dict["captureScreenshotsAutomatically"] = captureScreenshotsAutomatically + } + + if deleteScreenshotsWhenEachTestSucceeds != Scheme.Test.deleteScreenshotsWhenEachTestSucceedsDefault { + dict["deleteScreenshotsWhenEachTestSucceeds"] = deleteScreenshotsWhenEachTestSucceeds + } + + if preferredScreenCaptureFormat != Scheme.Test.preferredScreenCaptureFormatDefault { + dict["preferredScreenCaptureFormat"] = preferredScreenCaptureFormat.toJSONValue() + } + return dict } } @@ -471,10 +769,23 @@ extension Scheme.Test: JSONEncodable { extension Scheme.Test.TestTarget: JSONObjectConvertible { public init(jsonDictionary: JSONDictionary) throws { - targetReference = try TargetReference(jsonDictionary.json(atKeyPath: "name")) + if let name: String = jsonDictionary.json(atKeyPath: "name") { + targetReference = try TestableTargetReference(name) + } else if let local: String = jsonDictionary.json(atKeyPath: "local") { + self.targetReference = TestableTargetReference.local(local) + } else if let project: String = jsonDictionary.json(atKeyPath: "project") { + self.targetReference = TestableTargetReference.project(project) + } else if let package: String = jsonDictionary.json(atKeyPath: "package") { + self.targetReference = TestableTargetReference.package(package) + } else { + self.targetReference = try jsonDictionary.json(atKeyPath: "target") + } randomExecutionOrder = jsonDictionary.json(atKeyPath: "randomExecutionOrder") ?? Scheme.Test.TestTarget.randomExecutionOrderDefault parallelizable = jsonDictionary.json(atKeyPath: "parallelizable") ?? Scheme.Test.TestTarget.parallelizableDefault + location = jsonDictionary.json(atKeyPath: "location") ?? nil + skipped = jsonDictionary.json(atKeyPath: "skipped") ?? false skippedTests = jsonDictionary.json(atKeyPath: "skippedTests") ?? [] + selectedTests = jsonDictionary.json(atKeyPath: "selectedTests") ?? [] } } @@ -495,6 +806,12 @@ extension Scheme.Test.TestTarget: JSONEncodable { if parallelizable != Scheme.Test.TestTarget.parallelizableDefault { dict["parallelizable"] = parallelizable } + if let location = location { + dict["location"] = location + } + if skipped { + dict["skipped"] = skipped + } return dict } @@ -508,6 +825,9 @@ extension Scheme.Profile: JSONObjectConvertible { preActions = jsonDictionary.json(atKeyPath: "preActions") ?? [] postActions = jsonDictionary.json(atKeyPath: "postActions") ?? [] environmentVariables = try XCScheme.EnvironmentVariable.parseAll(jsonDictionary: jsonDictionary) + if let askLaunch: Bool = jsonDictionary.json(atKeyPath: "askForAppToLaunch") { + askForAppToLaunch = askLaunch + } } } @@ -519,6 +839,7 @@ extension Scheme.Profile: JSONEncodable { "postActions": postActions.map { $0.toJSONValue() }, "environmentVariables": environmentVariables.map { $0.toJSONValue() }, "config": config, + "askForAppToLaunch": askForAppToLaunch, ] as [String: Any?] } } @@ -576,6 +897,7 @@ extension Scheme: NamedJSONDictionaryConvertible { analyze = jsonDictionary.json(atKeyPath: "analyze") profile = jsonDictionary.json(atKeyPath: "profile") archive = jsonDictionary.json(atKeyPath: "archive") + management = jsonDictionary.json(atKeyPath: "management") } } @@ -588,6 +910,7 @@ extension Scheme: JSONEncodable { "analyze": analyze?.toJSONValue(), "profile": profile?.toJSONValue(), "archive": archive?.toJSONValue(), + "management": management?.toJSONValue(), ] as [String: Any?] } } @@ -614,7 +937,7 @@ extension Scheme.Build: JSONObjectConvertible { } else { buildTypes = BuildType.all } - let target = try TargetReference(targetRepr) + let target = try TestableTargetReference(targetRepr) targets.append(Scheme.BuildTarget(target: target, buildTypes: buildTypes)) } self.targets = targets.sorted { $0.target.name < $1.target.name } @@ -622,6 +945,7 @@ extension Scheme.Build: JSONObjectConvertible { postActions = try jsonDictionary.json(atKeyPath: "postActions")?.map(Scheme.ExecutionAction.init) ?? [] parallelizeBuild = jsonDictionary.json(atKeyPath: "parallelizeBuild") ?? Scheme.Build.parallelizeBuildDefault buildImplicitDependencies = jsonDictionary.json(atKeyPath: "buildImplicitDependencies") ?? Scheme.Build.buildImplicitDependenciesDefault + runPostActionsOnFailure = jsonDictionary.json(atKeyPath: "runPostActionsOnFailure") ?? Scheme.Build.runPostActionsOnFailureDefault } } @@ -641,12 +965,15 @@ extension Scheme.Build: JSONEncodable { if buildImplicitDependencies != Scheme.Build.buildImplicitDependenciesDefault { dict["buildImplicitDependencies"] = buildImplicitDependencies } + if runPostActionsOnFailure != Scheme.Build.runPostActionsOnFailureDefault { + dict["runPostActionsOnFailure"] = runPostActionsOnFailure + } return dict } } -extension BuildType: JSONPrimitiveConvertible { +extension BuildType: JSONUtilities.JSONPrimitiveConvertible { public typealias JSONType = String @@ -678,7 +1005,7 @@ extension BuildType: JSONEncodable { } } -extension XCScheme.EnvironmentVariable: JSONObjectConvertible { +extension XCScheme.EnvironmentVariable: JSONUtilities.JSONObjectConvertible { public static let enabledDefault = true private static func parseValue(_ value: Any) -> String { @@ -730,3 +1057,39 @@ 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") + } + } +} + +extension XCScheme.TestAction.ScreenCaptureFormat: JSONEncodable { + public func toJSONValue() -> Any { + rawValue + } +} diff --git a/Sources/ProjectSpec/Settings.swift b/Sources/ProjectSpec/Settings.swift index 6ac0328c7..b3b366a86 100644 --- a/Sources/ProjectSpec/Settings.swift +++ b/Sources/ProjectSpec/Settings.swift @@ -28,7 +28,8 @@ public struct Settings: Equatable, JSONObjectConvertible, CustomStringConvertibl groups = jsonDictionary.json(atKeyPath: "groups") ?? jsonDictionary.json(atKeyPath: "presets") ?? [] let buildSettingsDictionary: JSONDictionary = jsonDictionary.json(atKeyPath: "base") ?? [:] buildSettings = buildSettingsDictionary - configSettings = jsonDictionary.json(atKeyPath: "configs") ?? [:] + + self.configSettings = try Self.extractValidConfigs(from: jsonDictionary) } else { buildSettings = jsonDictionary configSettings = [:] @@ -36,6 +37,26 @@ public struct Settings: Equatable, JSONObjectConvertible, CustomStringConvertibl } } + /// Extracts and validates the `configs` mapping from the given JSON dictionary. + /// - Parameter jsonDictionary: The JSON dictionary to extract `configs` from. + /// - Returns: A dictionary mapping configuration names to `Settings` objects. + private static func extractValidConfigs(from jsonDictionary: JSONDictionary) throws -> [String: Settings] { + guard let configSettings = jsonDictionary["configs"] as? JSONDictionary else { + return [:] + } + + let invalidConfigKeys = Set( + configSettings.filter { !($0.value is JSONDictionary) } + .map(\.key) + ) + + guard invalidConfigKeys.isEmpty else { + throw SpecParsingError.invalidConfigsMappingFormat(keys: invalidConfigKeys) + } + + return try jsonDictionary.json(atKeyPath: "configs") + } + public static func == (lhs: Settings, rhs: Settings) -> Bool { NSDictionary(dictionary: lhs.buildSettings).isEqual(to: rhs.buildSettings) && lhs.configSettings == rhs.configSettings && @@ -113,7 +134,7 @@ extension Settings: JSONEncodable { "base": buildSettings, "groups": groups, "configs": configSettings.mapValues { $0.toJSONValue() }, - ] + ] as [String : Any] } return buildSettings } diff --git a/Sources/ProjectSpec/SourceType.swift b/Sources/ProjectSpec/SourceType.swift new file mode 100644 index 000000000..9fe009321 --- /dev/null +++ b/Sources/ProjectSpec/SourceType.swift @@ -0,0 +1,15 @@ +// +// File.swift +// +// +// Created by Yonas Kolb on 1/5/20. +// + +import Foundation + +public enum SourceType: String { + case group + case file + case folder + case syncedFolder +} diff --git a/Sources/ProjectSpec/SpecFile.swift b/Sources/ProjectSpec/SpecFile.swift index adf974711..18ea15628 100644 --- a/Sources/ProjectSpec/SpecFile.swift +++ b/Sources/ProjectSpec/SpecFile.swift @@ -1,29 +1,39 @@ import Foundation import JSONUtilities import PathKit +import Yams public struct SpecFile { + /// For the root spec, this is the folder containing the SpecFile. For subSpecs this is the path + /// to the folder of the parent spec that is including this SpecFile. public let basePath: Path - public let relativePath: Path public let jsonDictionary: JSONDictionary public let subSpecs: [SpecFile] + /// The relative path to use when resolving paths in the json dictionary. Is an empty path when + /// included with relativePaths disabled. + private let relativePath: Path + + /// The path to the file relative to the basePath. private let filePath: Path 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,12 +48,26 @@ public struct SpecFile { return [] } } - } - public init(path: Path) throws { - try self.init(filePath: path, basePath: path.parent()) + private static func resolveBoolean(_ dictionary: [String: Any], key: String) -> Bool? { + dictionary[key] as? Bool ?? (dictionary[key] as? NSString)?.boolValue + } } - + + /// Create a SpecFile for a Project + /// - Parameters: + /// - path: The absolute path to the spec file + /// - projectRoot: The root of the project to use as the base path. When nil, uses the parent + /// of the path. + public init(path: Path, projectRoot: Path? = nil, variables: [String: String] = [:]) throws { + let basePath = projectRoot ?? path.parent() + let filePath = try path.relativePath(from: basePath) + var cachedSpecFiles: [Path: SpecFile] = [:] + + try self.init(filePath: filePath, basePath: basePath, cachedSpecFiles: &cachedSpecFiles, variables: variables) + } + + /// Memberwise initializer for SpecFile public init(filePath: Path, jsonDictionary: JSONDictionary, basePath: Path = "", relativePath: Path = "", subSpecs: [SpecFile] = []) { self.basePath = basePath self.relativePath = relativePath @@ -52,23 +76,31 @@ 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() - try self.init(filePath: include.path, basePath: basePath, relativePath: relativePath) + try self.init(filePath: include.path, 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) + private init(filePath: Path, basePath: Path, cachedSpecFiles: inout [Path: SpecFile], variables: [String: String], relativePath: Path = "") throws { + let path = basePath + filePath + if let specFile = cachedSpecFiles[path] { + self = specFile + return + } + + let jsonDictionary = try SpecFile.loadDictionary(path: path).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 + 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[path] = self } static func loadDictionary(path: Path) throws -> JSONDictionary { @@ -85,42 +117,50 @@ 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) + var mergedSpecPaths = Set() + return resolvedSpec.mergedDictionary(set: &mergedSpecPaths) } - func mergedDictionary(set mergedTargets: inout Set) -> JSONDictionary { - let name = filePath.description + private func mergedDictionary(set mergedSpecPaths: inout Set) -> JSONDictionary { + let path = basePath + filePath - guard !mergedTargets.contains(name) else { return [:] } - mergedTargets.insert(name) + guard mergedSpecPaths.insert(path).inserted else { return [:] } return jsonDictionary.merged(onto: subSpecs - .map { $0.mergedDictionary(set: &mergedTargets) } + .map { $0.mergedDictionary(set: &mergedSpecPaths) } .reduce([:]) { $1.merged(onto: $0) }) } - func resolvingPaths(relativeTo basePath: Path = Path()) -> SpecFile { + private func resolvingPaths(cachedSpecFiles: inout [Path: SpecFile], relativeTo basePath: Path = Path()) -> SpecFile { + let path = basePath + filePath + if let cachedSpecFile = cachedSpecFiles[path] { + 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, + basePath: self.basePath, relativePath: self.relativePath, - subSpecs: subSpecs.map { $0.resolvingPaths(relativeTo: relativePath) } + subSpecs: subSpecs.map { $0.resolvingPaths(cachedSpecFiles: &cachedSpecFiles, relativeTo: relativePath) } ) + cachedSpecFiles[path] = specFile + return specFile } } diff --git a/Sources/ProjectSpec/SpecLoader.swift b/Sources/ProjectSpec/SpecLoader.swift index 142d3bf1d..fe93e8403 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) + let projectRoot = projectRoot?.absolute() + let spec = try SpecFile(path: path, projectRoot: projectRoot, variables: variables) + let resolvedDictionary = spec.resolvedDictionary() let project = try Project(basePath: projectRoot ?? spec.basePath, jsonDictionary: resolvedDictionary) self.project = project diff --git a/Sources/ProjectSpec/SpecOptions.swift b/Sources/ProjectSpec/SpecOptions.swift index 237f2b56b..c10c34698 100644 --- a/Sources/ProjectSpec/SpecOptions.swift +++ b/Sources/ProjectSpec/SpecOptions.swift @@ -9,6 +9,8 @@ public struct SpecOptions: Equatable { public static let groupSortPositionDefault = GroupSortPosition.bottom public static let generateEmptyDirectoriesDefault = false public static let findCarthageFrameworksDefault = false + public static let useBaseInternationalizationDefault = true + public static let schemePathPrefixDefault = "../../" public var minimumXcodeGenVersion: Version? public var carthageBuildPath: String? @@ -27,15 +29,20 @@ public struct SpecOptions: Equatable { public var transitivelyLinkDependencies: Bool public var groupSortPosition: GroupSortPosition public var groupOrdering: [GroupOrdering] + public var fileTypes: [String: FileType] public var generateEmptyDirectories: Bool public var findCarthageFrameworks: Bool public var localPackagesGroup: String? public var preGenCommand: String? public var postGenCommand: String? + public var useBaseInternationalization: Bool + public var schemePathPrefix: String + public var defaultSourceDirectoryType: SourceType? public enum ValidationType: String { case missingConfigs case missingConfigFiles + case missingTestPlans } public enum SettingPresets: String { @@ -87,11 +94,15 @@ public struct SpecOptions: Equatable { transitivelyLinkDependencies: Bool = transitivelyLinkDependenciesDefault, groupSortPosition: GroupSortPosition = groupSortPositionDefault, groupOrdering: [GroupOrdering] = [], + fileTypes: [String: FileType] = [:], generateEmptyDirectories: Bool = generateEmptyDirectoriesDefault, findCarthageFrameworks: Bool = findCarthageFrameworksDefault, localPackagesGroup: String? = nil, preGenCommand: String? = nil, - postGenCommand: String? = nil + postGenCommand: String? = nil, + useBaseInternationalization: Bool = useBaseInternationalizationDefault, + schemePathPrefix: String = schemePathPrefixDefault, + defaultSourceDirectoryType: SourceType? = nil ) { self.minimumXcodeGenVersion = minimumXcodeGenVersion self.carthageBuildPath = carthageBuildPath @@ -110,11 +121,15 @@ public struct SpecOptions: Equatable { self.transitivelyLinkDependencies = transitivelyLinkDependencies self.groupSortPosition = groupSortPosition self.groupOrdering = groupOrdering + self.fileTypes = fileTypes self.generateEmptyDirectories = generateEmptyDirectories self.findCarthageFrameworks = findCarthageFrameworks self.localPackagesGroup = localPackagesGroup self.preGenCommand = preGenCommand self.postGenCommand = postGenCommand + self.useBaseInternationalization = useBaseInternationalization + self.schemePathPrefix = schemePathPrefix + self.defaultSourceDirectoryType = defaultSourceDirectoryType } } @@ -146,6 +161,14 @@ extension SpecOptions: JSONObjectConvertible { localPackagesGroup = jsonDictionary.json(atKeyPath: "localPackagesGroup") preGenCommand = jsonDictionary.json(atKeyPath: "preGenCommand") postGenCommand = jsonDictionary.json(atKeyPath: "postGenCommand") + useBaseInternationalization = jsonDictionary.json(atKeyPath: "useBaseInternationalization") ?? SpecOptions.useBaseInternationalizationDefault + schemePathPrefix = jsonDictionary.json(atKeyPath: "schemePathPrefix") ?? SpecOptions.schemePathPrefixDefault + defaultSourceDirectoryType = jsonDictionary.json(atKeyPath: "defaultSourceDirectoryType") + if jsonDictionary["fileTypes"] != nil { + fileTypes = try jsonDictionary.json(atKeyPath: "fileTypes") + } else { + fileTypes = [:] + } } } @@ -169,6 +192,7 @@ extension SpecOptions: JSONEncodable { "localPackagesGroup": localPackagesGroup, "preGenCommand": preGenCommand, "postGenCommand": postGenCommand, + "fileTypes": fileTypes.mapValues { $0.toJSONValue() } ] if settingPresets != SpecOptions.settingPresetsDefault { @@ -183,6 +207,12 @@ extension SpecOptions: JSONEncodable { if findCarthageFrameworks != SpecOptions.findCarthageFrameworksDefault { dict["findCarthageFrameworks"] = findCarthageFrameworks } + if useBaseInternationalization != SpecOptions.useBaseInternationalizationDefault { + dict["useBaseInternationalization"] = useBaseInternationalization + } + if schemePathPrefix != SpecOptions.schemePathPrefixDefault { + dict["schemePathPrefix"] = schemePathPrefix + } return dict } diff --git a/Sources/ProjectSpec/SpecParsingError.swift b/Sources/ProjectSpec/SpecParsingError.swift index da6eadbaf..57db99f2e 100644 --- a/Sources/ProjectSpec/SpecParsingError.swift +++ b/Sources/ProjectSpec/SpecParsingError.swift @@ -7,7 +7,15 @@ public enum SpecParsingError: Error, CustomStringConvertible { case unknownPackageRequirement([String: Any]) case invalidSourceBuildPhase(String) case invalidTargetReference(String) + case invalidTargetPlatformAsArray case invalidVersion(String) + case unknownBreakpointType(String) + case unknownBreakpointScope(String) + case unknownBreakpointStopOnStyle(String) + case unknownBreakpointActionType(String) + case unknownBreakpointActionConveyanceType(String) + case unknownBreakpointActionSoundName(String) + case invalidConfigsMappingFormat(keys: Set) public var description: String { switch self { @@ -21,10 +29,26 @@ public enum SpecParsingError: Error, CustomStringConvertible { return "Invalid Source Build Phase: \(error)" case let .invalidTargetReference(targetReference): return "Invalid Target Reference Syntax: \(targetReference)" + case .invalidTargetPlatformAsArray: + return "Invalid Target platform: Array not allowed with supported destinations" case let .invalidVersion(version): return "Invalid version: \(version)" case let .unknownPackageRequirement(package): return "Unknown package requirement: \(package)" + case let .unknownBreakpointType(type): + return "Unknown Breakpoint type: \(type)" + case let .unknownBreakpointScope(scope): + return "Unknown Breakpoint scope: \(scope)" + case let .unknownBreakpointStopOnStyle(stopOnStyle): + return "Unknown Breakpoint stopOnStyle: \(stopOnStyle)" + case let .unknownBreakpointActionType(type): + return "Unknown Breakpoint Action type: \(type)" + case let .unknownBreakpointActionConveyanceType(type): + return "Unknown Breakpoint Action conveyance type: \(type)" + case let .unknownBreakpointActionSoundName(name): + return "Unknown Breakpoint Action sound name: \(name)" + case let .invalidConfigsMappingFormat(keys): + return "Invalid format: The value for \"\(keys.sorted().joined(separator: ", "))\" in `configs` must be mapping format" } } } diff --git a/Sources/ProjectSpec/SpecValidation.swift b/Sources/ProjectSpec/SpecValidation.swift index 3594e658a..4aa9c7926 100644 --- a/Sources/ProjectSpec/SpecValidation.swift +++ b/Sources/ProjectSpec/SpecValidation.swift @@ -17,27 +17,30 @@ extension Project { errors.append(.invalidSettingsGroup(group)) } } + for config in settings.configSettings.keys { - if !configs.contains(where: { $0.name.lowercased().contains(config.lowercased()) }) { - if !options.disabledValidations.contains(.missingConfigs) { - errors.append(.invalidBuildSettingConfig(config)) - } + if !configs.contains(where: { $0.name.lowercased().contains(config.lowercased()) }), + !options.disabledValidations.contains(.missingConfigs) { + errors.append(.invalidBuildSettingConfig(config)) } } if settings.buildSettings.count == configs.count { var allConfigs = true - for buildSetting in settings.buildSettings.keys { + outerLoop: for buildSetting in settings.buildSettings.keys { var isConfig = false for config in configs { if config.name.lowercased().contains(buildSetting.lowercased()) { isConfig = true + break } } if !isConfig { allConfigs = false + break outerLoop } } + if allConfigs { errors.append(.invalidPerConfigSettings) } @@ -54,7 +57,7 @@ extension Project { } for (name, package) in packages { - if case let .local(path) = package, !(basePath + Path(path).normalize()).exists { + if case let .local(path, _, _) = package, !(basePath + Path(path).normalize()).exists { errors.append(.invalidLocalPackage(name)) } } @@ -81,8 +84,9 @@ extension Project { for target in projectTargets { for (config, configFile) in target.configFiles { - if !options.disabledValidations.contains(.missingConfigFiles) && !(basePath + configFile).exists { - errors.append(.invalidTargetConfigFile(target: target.name, configFile: configFile, config: config)) + let configPath = basePath + configFile + if !options.disabledValidations.contains(.missingConfigFiles) && !configPath.exists { + errors.append(.invalidTargetConfigFile(target: target.name, configFile: configPath.string, config: config)) } if !options.disabledValidations.contains(.missingConfigs) && getConfig(config) == nil { errors.append(.invalidConfigFileConfig(config)) @@ -90,16 +94,16 @@ extension Project { } if let scheme = target.scheme { - + for configVariant in scheme.configVariants { - if !configs.contains(where: { $0.name.contains(configVariant) && $0.type == .debug }) { + if configs.first(including: configVariant, for: .debug) == nil { errors.append(.invalidTargetSchemeConfigVariant( target: target.name, configVariant: configVariant, configType: .debug )) } - if !configs.contains(where: { $0.name.contains(configVariant) && $0.type == .release }) { + if configs.first(including: configVariant, for: .release) == nil { errors.append(.invalidTargetSchemeConfigVariant( target: target.name, configVariant: configVariant, @@ -119,21 +123,36 @@ extension Project { for testTarget in scheme.testTargets { if getTarget(testTarget.name) == nil { + // For test case of local Swift Package + if case .package(let name) = testTarget.targetReference.location, getPackage(name) != nil { + continue + } errors.append(.invalidTargetSchemeTest(target: target.name, testTarget: testTarget.name)) } } + + if !options.disabledValidations.contains(.missingTestPlans) { + let invalidTestPlans: [TestPlan] = scheme.testPlans.filter { !(basePath + $0.path).exists } + errors.append(contentsOf: invalidTestPlans.map{ .invalidTestPlan($0) }) + } } for script in target.buildScripts { if case let .path(pathString) = script.script { let scriptPath = basePath + pathString if !scriptPath.exists { - errors.append(.invalidBuildScriptPath(target: target.name, name: script.name, path: pathString)) + errors.append(.invalidBuildScriptPath(target: target.name, name: script.name, path: scriptPath.string)) } } } errors += validateSettings(target.settings) + + for buildToolPlugin in target.buildToolPlugins { + if packages[buildToolPlugin.package] == nil { + errors.append(.invalidPluginPackageReference(plugin: buildToolPlugin.plugin, package: buildToolPlugin.package)) + } + } } for target in aggregateTargets { @@ -145,38 +164,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) } } @@ -186,6 +183,35 @@ extension Project { errors.append(.invalidTargetSource(target: target.name, source: sourcePath.string)) } } + + if target.supportedDestinations != nil, target.platform == .watchOS { + errors.append(.unexpectedTargetPlatformForSupportedDestinations(target: target.name, platform: target.platform)) + } + + if let supportedDestinations = target.supportedDestinations, + target.type.isApp, + supportedDestinations.contains(.watchOS) { + errors.append(.containsWatchOSDestinationForMultiplatformApp(target: target.name)) + } + + if target.supportedDestinations?.contains(.macOS) == true, + target.supportedDestinations?.contains(.macCatalyst) == true { + + errors.append(.multipleMacPlatformsInSupportedDestinations(target: target.name)) + } + + if target.supportedDestinations?.contains(.macCatalyst) == true, + target.platform != .iOS, target.platform != .auto { + + errors.append(.invalidTargetPlatformForSupportedDestinations(target: target.name)) + } + + if target.platform != .auto, target.platform != .watchOS, + let supportedDestination = SupportedDestination(rawValue: target.platform.rawValue), + target.supportedDestinations?.contains(supportedDestination) == false { + + errors.append(.missingTargetPlatformInSupportedDestinations(target: target.name, platform: target.platform)) + } } for projectReference in projectReferences { @@ -201,6 +227,17 @@ extension Project { if let action = scheme.run, let config = action.config, getConfig(config) == nil { errors.append(.invalidSchemeConfig(scheme: scheme.name, config: config)) } + + if !options.disabledValidations.contains(.missingTestPlans) { + let invalidTestPlans: [TestPlan] = scheme.test?.testPlans.filter { !(basePath + $0.path).exists } ?? [] + errors.append(contentsOf: invalidTestPlans.map{ .invalidTestPlan($0) }) + } + + let defaultPlanCount = scheme.test?.testPlans.filter { $0.defaultPlan }.count ?? 0 + if (defaultPlanCount > 1) { + errors.append(.multipleDefaultTestPlans) + } + if let action = scheme.test, let config = action.config, getConfig(config) == nil { errors.append(.invalidSchemeConfig(scheme: scheme.name, config: config)) } @@ -228,10 +265,50 @@ extension Project { public func validateMinimumXcodeGenVersion(_ xcodeGenVersion: Version) throws { if let minimumXcodeGenVersion = options.minimumXcodeGenVersion, xcodeGenVersion < minimumXcodeGenVersion { - throw SpecValidationError.ValidationError.invalidXcodeGenVersion(minimumVersion: minimumXcodeGenVersion, version: xcodeGenVersion) + throw SpecValidationError(errors: [SpecValidationError.ValidationError.invalidXcodeGenVersion(minimumVersion: minimumXcodeGenVersion, version: xcodeGenVersion)]) } } + // 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 { @@ -243,4 +320,18 @@ extension Project { return nil } } + + /// Returns a descriptive error if the given target reference was invalid otherwise `nil`. + private func validationError(for testableTargetReference: TestableTargetReference, in scheme: Scheme, action: String) -> SpecValidationError.ValidationError? { + switch testableTargetReference.location { + case .local where getProjectTarget(testableTargetReference.name) == nil: + return .invalidSchemeTarget(scheme: scheme.name, target: testableTargetReference.name, action: action) + case .project(let project) where getProjectReference(project) == nil: + return .invalidProjectReference(scheme: scheme.name, reference: project) + case .package(let package) where getPackage(package) == nil: + return .invalidLocalPackage(package) + case .local, .project, .package: + return nil + } + } } diff --git a/Sources/ProjectSpec/SpecValidationError.swift b/Sources/ProjectSpec/SpecValidationError.swift index c19486526..6e93de0ef 100644 --- a/Sources/ProjectSpec/SpecValidationError.swift +++ b/Sources/ProjectSpec/SpecValidationError.swift @@ -9,7 +9,7 @@ public struct SpecValidationError: Error, CustomStringConvertible { self.errors = errors } - public enum ValidationError: Error, CustomStringConvertible { + public enum ValidationError: Hashable, Error, CustomStringConvertible { case invalidXcodeGenVersion(minimumVersion: Version, version: Version) case invalidSDKDependency(target: String, dependency: String) case invalidTargetDependency(target: String, dependency: String) @@ -17,9 +17,15 @@ public struct SpecValidationError: Error, CustomStringConvertible { case invalidTargetConfigFile(target: String, configFile: String, config: String) case invalidTargetSchemeConfigVariant(target: String, configVariant: String, configType: ConfigType) case invalidTargetSchemeTest(target: String, testTarget: String) + case invalidTargetPlatformForSupportedDestinations(target: String) + case unexpectedTargetPlatformForSupportedDestinations(target: String, platform: Platform) + case containsWatchOSDestinationForMultiplatformApp(target: String) + case multipleMacPlatformsInSupportedDestinations(target: String) + case missingTargetPlatformInSupportedDestinations(target: String, platform: Platform) case invalidSchemeTarget(scheme: String, target: String, action: String) case invalidSchemeConfig(scheme: String, config: String) case invalidSwiftPackage(name: String, target: String) + case invalidPackageDependencyReference(name: String) case invalidLocalPackage(String) case invalidConfigFile(configFile: String, config: String) case invalidBuildSettingConfig(String) @@ -32,6 +38,10 @@ public struct SpecValidationError: Error, CustomStringConvertible { case invalidPerConfigSettings case invalidProjectReference(scheme: String, reference: String) case invalidProjectReferencePath(ProjectReference) + case invalidTestPlan(TestPlan) + case multipleDefaultTestPlans + case duplicateDependencies(target: String, dependencyReference: String) + case invalidPluginPackageReference(plugin: String, package: String) public var description: String { switch self { @@ -42,13 +52,23 @@ public struct SpecValidationError: Error, CustomStringConvertible { case let .invalidTargetDependency(target, dependency): return "Target \(target.quoted) has invalid dependency: \(dependency.quoted)" case let .invalidTargetConfigFile(target, configFile, config): - return "Target \(target.quoted) has invalid config file \(configFile.quoted) for config \(config.quoted)" + return "Target \(target.quoted) has invalid config file path \(configFile.quoted) for config \(config.quoted)" case let .invalidTargetSource(target, source): return "Target \(target.quoted) has a missing source directory \(source.quoted)" case let .invalidTargetSchemeConfigVariant(target, configVariant, configType): return "Target \(target.quoted) has an invalid scheme config variant which requires a config that has a \(configType.rawValue.quoted) type and contains the name \(configVariant.quoted)" case let .invalidTargetSchemeTest(target, test): return "Target \(target.quoted) scheme has invalid test \(test.quoted)" + case let .invalidTargetPlatformForSupportedDestinations(target): + return "Target \(target.quoted) has supported destinations that require a target platform iOS or auto" + case let .unexpectedTargetPlatformForSupportedDestinations(target, platform): + return "Target \(target.quoted) has platform \(platform.rawValue.quoted) that does not expect supported destinations" + case let .multipleMacPlatformsInSupportedDestinations(target): + return "Target \(target.quoted) has multiple definitions of mac platforms in supported destinations" + case let .missingTargetPlatformInSupportedDestinations(target, platform): + return "Target \(target.quoted) has platform \(platform.rawValue.quoted) that is missing in supported destinations" + case let .containsWatchOSDestinationForMultiplatformApp(target): + return "Multiplatform app \(target.quoted) cannot contain watchOS in \"supportedDestinations\". Create a separate target using \"platform\" for watchOS apps" case let .invalidConfigFile(configFile, config): return "Invalid config file \(configFile.quoted) for config \(config.quoted)" case let .invalidSchemeTarget(scheme, target, action): @@ -69,6 +89,8 @@ public struct SpecValidationError: Error, CustomStringConvertible { return "Target \(target.quoted) has an invalid package dependency \(name.quoted)" case let .invalidLocalPackage(path): return "Invalid local package \(path.quoted)" + case let .invalidPackageDependencyReference(name): + return "Package reference \(name) must be specified as package dependency, not target" case let .missingConfigForTargetScheme(target, configType): return "Target \(target.quoted) is missing a config of type \(configType.rawValue) to generate its scheme" case let .missingDefaultConfig(name): @@ -79,6 +101,14 @@ public struct SpecValidationError: Error, CustomStringConvertible { return "Scheme \(scheme.quoted) has invalid project reference \(project.quoted)" case let .invalidProjectReferencePath(reference): return "Project reference \(reference.name) has a project file path that doesn't exist \"\(reference.path)\"" + case let .invalidTestPlan(testPlan): + 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" + case let .invalidPluginPackageReference(plugin, package): + return "Plugin \(plugin) has invalid package reference \(package)" } } } diff --git a/Sources/ProjectSpec/SupportedDestination.swift b/Sources/ProjectSpec/SupportedDestination.swift new file mode 100644 index 000000000..6c7ed11a0 --- /dev/null +++ b/Sources/ProjectSpec/SupportedDestination.swift @@ -0,0 +1,50 @@ +import Foundation + +public enum SupportedDestination: String, CaseIterable { + case iOS + case tvOS + case macOS + case macCatalyst + case watchOS + case visionOS +} + +extension SupportedDestination { + + public var string: String { + switch self { + case .iOS: + return "ios" + case .tvOS: + return "tvos" + case .macOS: + return "macos" + case .macCatalyst: + return "maccatalyst" + case .watchOS: + return "watchos" + case .visionOS: + return "xros" + } + } + + // This is used to: + // 1. Get the first one and apply SettingPresets 'Platforms' and 'Product_Platform' if the platform is 'auto' + // 2. Sort, loop and merge together SettingPresets 'SupportedDestinations' + public var priority: Int { + switch self { + case .iOS: + return 0 + case .tvOS: + return 1 + case .watchOS: + return 2 + case .visionOS: + return 3 + case .macOS: + return 4 + case .macCatalyst: + return 5 + } + } +} diff --git a/Sources/ProjectSpec/SwiftPackage.swift b/Sources/ProjectSpec/SwiftPackage.swift index 447d5dfa3..2ec58f6c3 100644 --- a/Sources/ProjectSpec/SwiftPackage.swift +++ b/Sources/ProjectSpec/SwiftPackage.swift @@ -7,8 +7,10 @@ public enum SwiftPackage: Equatable { public typealias VersionRequirement = XCRemoteSwiftPackageReference.VersionRequirement + static let githubPrefix = "https://github.com/" + case remote(url: String, versionRequirement: VersionRequirement) - case local(path: String) + case local(path: String, group: String?, excludeFromProject: Bool) public var isLocal: Bool { if case .local = self { @@ -22,11 +24,20 @@ extension SwiftPackage: JSONObjectConvertible { public init(jsonDictionary: JSONDictionary) throws { if let path: String = jsonDictionary.json(atKeyPath: "path") { - self = .local(path: path) + let customLocation: String? = jsonDictionary.json(atKeyPath: "group") + let excludeFromProject: Bool = jsonDictionary.json(atKeyPath: "excludeFromProject") ?? false + self = .local(path: path, group: customLocation, excludeFromProject: excludeFromProject) } else { let versionRequirement: VersionRequirement = try VersionRequirement(jsonDictionary: jsonDictionary) try Self.validateVersion(versionRequirement: versionRequirement) - self = .remote(url: try jsonDictionary.json(atKeyPath: "url"), versionRequirement: versionRequirement) + let url: String + if jsonDictionary["github"] != nil { + let github: String = try jsonDictionary.json(atKeyPath: "github") + url = "\(Self.githubPrefix)\(github)" + } else { + url = try jsonDictionary.json(atKeyPath: "url") + } + self = .remote(url: url, versionRequirement: versionRequirement) } } @@ -58,7 +69,11 @@ extension SwiftPackage: JSONEncodable { var dictionary: JSONDictionary = [:] switch self { case .remote(let url, let versionRequirement): - dictionary["url"] = url + if url.hasPrefix(Self.githubPrefix) { + dictionary["github"] = url.replacingOccurrences(of: Self.githubPrefix, with: "") + } else { + dictionary["url"] = url + } switch versionRequirement { @@ -77,37 +92,64 @@ extension SwiftPackage: JSONEncodable { dictionary["revision"] = revision } return dictionary - case .local(let path): + case let .local(path, group, excludeFromProject): dictionary["path"] = path + dictionary["group"] = group + dictionary["excludeFromProject"] = excludeFromProject } return dictionary } } -extension SwiftPackage.VersionRequirement: JSONObjectConvertible { +extension SwiftPackage.VersionRequirement: JSONUtilities.JSONObjectConvertible { public init(jsonDictionary: JSONDictionary) throws { - if jsonDictionary["exactVersion"] != nil { - self = try .exact(jsonDictionary.json(atKeyPath: "exactVersion")) - } else if jsonDictionary["version"] != nil { - self = try .exact(jsonDictionary.json(atKeyPath: "version")) - } else if jsonDictionary["revision"] != nil { - self = try .revision(jsonDictionary.json(atKeyPath: "revision")) - } else if jsonDictionary["branch"] != nil { - self = try .branch(jsonDictionary.json(atKeyPath: "branch")) - } else if jsonDictionary["minVersion"] != nil && jsonDictionary["maxVersion"] != nil { - let minimum: String = try jsonDictionary.json(atKeyPath: "minVersion") - let maximum: String = try jsonDictionary.json(atKeyPath: "maxVersion") - self = .range(from: minimum, to: maximum) - } else if jsonDictionary["minorVersion"] != nil { - self = try .upToNextMinorVersion(jsonDictionary.json(atKeyPath: "minorVersion")) - } else if jsonDictionary["majorVersion"] != nil { - self = try .upToNextMajorVersion(jsonDictionary.json(atKeyPath: "majorVersion")) - } else if jsonDictionary["from"] != nil { - self = try .upToNextMajorVersion(jsonDictionary.json(atKeyPath: "from")) + func json(atKeyPath keyPath: String) -> String? { + if jsonDictionary[keyPath] != nil { + do { + let value: String = try jsonDictionary.json(atKeyPath: .init(rawValue: keyPath)) + return value + } catch { + do { + let value: Double = try jsonDictionary.json(atKeyPath: .init(rawValue: keyPath)) + return String(value) + } catch { + return nil + } + } + } + return nil + } + + if let exactVersion = json(atKeyPath: "exactVersion") { + self = .exact(exactVersion) + } else if let version = json(atKeyPath: "version") { + self = .exact(version) + } else if let revision = json(atKeyPath: "revision") { + self = .revision(revision) + } else if let branch = json(atKeyPath: "branch") { + self = .branch(branch) + } else if let minVersion = json(atKeyPath: "minVersion"), let maxVersion = json(atKeyPath: "maxVersion") { + self = .range(from: minVersion, to: maxVersion) + } else if let minorVersion = json(atKeyPath: "minorVersion") { + self = .upToNextMinorVersion(minorVersion) + } else if let majorVersion = json(atKeyPath: "majorVersion") { + self = .upToNextMajorVersion(majorVersion) + } else if let from = json(atKeyPath: "from") { + self = .upToNextMajorVersion(from) } else { throw SpecParsingError.unknownPackageRequirement(jsonDictionary) } } } + +extension SwiftPackage: PathContainer { + static var pathProperties: [PathProperty] { + [ + .dictionary([ + .string("path"), + ]), + ] + } +} diff --git a/Sources/ProjectSpec/Target.swift b/Sources/ProjectSpec/Target.swift index c746129bd..781994f42 100644 --- a/Sources/ProjectSpec/Target.swift +++ b/Sources/ProjectSpec/Target.swift @@ -24,10 +24,20 @@ public struct LegacyTarget: Equatable { } } +extension LegacyTarget: PathContainer { + + static var pathProperties: [PathProperty] { + [ + .string("workingDirectory"), + ] + } +} + public struct Target: ProjectTarget { public var name: String public var type: PBXProductType public var platform: Platform + public var supportedDestinations: [SupportedDestination]? public var settings: Settings public var sources: [TargetSource] public var dependencies: [Dependency] @@ -37,6 +47,7 @@ public struct Target: ProjectTarget { public var directlyEmbedCarthageDependencies: Bool? public var requiresObjCLinking: Bool? public var preBuildScripts: [BuildScript] + public var buildToolPlugins: [BuildToolPlugin] public var postCompileScripts: [BuildScript] public var postBuildScripts: [BuildScript] public var buildRules: [BuildRule] @@ -47,7 +58,8 @@ public struct Target: ProjectTarget { public var attributes: [String: Any] public var productName: String public var onlyCopyFilesOnInstall: Bool - + public var putResourcesBeforeSourcesBuildPhase: Bool + public var isLegacy: Bool { legacy != nil } @@ -67,6 +79,7 @@ public struct Target: ProjectTarget { name: String, type: PBXProductType, platform: Platform, + supportedDestinations: [SupportedDestination]? = nil, productName: String? = nil, deploymentTarget: Version? = nil, settings: Settings = .empty, @@ -79,17 +92,20 @@ public struct Target: ProjectTarget { directlyEmbedCarthageDependencies: Bool? = nil, requiresObjCLinking: Bool? = nil, preBuildScripts: [BuildScript] = [], + buildToolPlugins: [BuildToolPlugin] = [], postCompileScripts: [BuildScript] = [], postBuildScripts: [BuildScript] = [], buildRules: [BuildRule] = [], scheme: TargetScheme? = nil, legacy: LegacyTarget? = nil, attributes: [String: Any] = [:], - onlyCopyFilesOnInstall: Bool = false + onlyCopyFilesOnInstall: Bool = false, + putResourcesBeforeSourcesBuildPhase: Bool = false ) { self.name = name self.type = type self.platform = platform + self.supportedDestinations = supportedDestinations self.deploymentTarget = deploymentTarget self.productName = productName ?? name self.settings = settings @@ -102,6 +118,7 @@ public struct Target: ProjectTarget { self.directlyEmbedCarthageDependencies = directlyEmbedCarthageDependencies self.requiresObjCLinking = requiresObjCLinking self.preBuildScripts = preBuildScripts + self.buildToolPlugins = buildToolPlugins self.postCompileScripts = postCompileScripts self.postBuildScripts = postBuildScripts self.buildRules = buildRules @@ -109,6 +126,7 @@ public struct Target: ProjectTarget { self.legacy = legacy self.attributes = attributes self.onlyCopyFilesOnInstall = onlyCopyFilesOnInstall + self.putResourcesBeforeSourcesBuildPhase = putResourcesBeforeSourcesBuildPhase } } @@ -134,6 +152,8 @@ extension Target: PathContainer { .object("prebuildScripts", BuildScript.pathProperties), .object("postCompileScripts", BuildScript.pathProperties), .object("postBuildScripts", BuildScript.pathProperties), + .object("legacy", LegacyTarget.pathProperties), + .object("scheme", TargetScheme.pathProperties), ]), ] } @@ -145,15 +165,17 @@ extension Target { guard let targetsDictionary: [String: JSONDictionary] = jsonDictionary["targets"] as? [String: JSONDictionary] else { return jsonDictionary } - + var crossPlatformTargets: [String: JSONDictionary] = [:] for (targetName, target) in targetsDictionary { - if let platforms = target["platform"] as? [String] { - for platform in platforms { var platformTarget = target + + /// This value is set to help us to check, in Target init, that there are no conflicts in the definition of the platforms. We want to ensure that the user didn't define, at the same time, + /// the new Xcode 14 supported destinations and the XcodeGen generation of Multiple Platform Targets (when you define the platform field as an array). + platformTarget["isMultiPlatformTarget"] = true platformTarget = platformTarget.expand(variables: ["platform": platform]) @@ -185,8 +207,8 @@ extension Target { crossPlatformTargets[targetName] = target } } + var merged = jsonDictionary - merged["targets"] = crossPlatformTargets return merged } @@ -209,6 +231,7 @@ extension Target: Equatable { lhs.entitlements == rhs.entitlements && lhs.dependencies == rhs.dependencies && lhs.preBuildScripts == rhs.preBuildScripts && + lhs.buildToolPlugins == rhs.buildToolPlugins && lhs.postCompileScripts == rhs.postCompileScripts && lhs.postBuildScripts == rhs.postBuildScripts && lhs.buildRules == rhs.buildRules && @@ -250,19 +273,41 @@ extension Target: NamedJSONDictionaryConvertible { let resolvedName: String = jsonDictionary.json(atKeyPath: "name") ?? name self.name = resolvedName productName = jsonDictionary.json(atKeyPath: "productName") ?? resolvedName - let typeString: String = try jsonDictionary.json(atKeyPath: "type") + + let typeString: String = jsonDictionary.json(atKeyPath: "type") ?? "" if let type = PBXProductType(string: typeString) { self.type = type } else { throw SpecParsingError.unknownTargetType(typeString) } - let platformString: String = try jsonDictionary.json(atKeyPath: "platform") + + if let supportedDestinations: [SupportedDestination] = jsonDictionary.json(atKeyPath: "supportedDestinations") { + self.supportedDestinations = supportedDestinations + } + + let isResolved = jsonDictionary.json(atKeyPath: "isMultiPlatformTarget") ?? false + if isResolved, supportedDestinations != nil { + throw SpecParsingError.invalidTargetPlatformAsArray + } + + var platformString: String = jsonDictionary.json(atKeyPath: "platform") ?? "" + // platform defaults to 'auto' if it is empty and we are using supported destinations + if supportedDestinations != nil, platformString.isEmpty { + platformString = Platform.auto.rawValue + } + // we add 'iOS' in supported destinations if it contains only 'macCatalyst' + if supportedDestinations?.contains(.macCatalyst) == true, + supportedDestinations?.contains(.iOS) == false { + + supportedDestinations?.append(.iOS) + } + if let platform = Platform(rawValue: platformString) { self.platform = platform } else { throw SpecParsingError.unknownTargetPlatform(platformString) } - + if let string: String = jsonDictionary.json(atKeyPath: "deploymentTarget") { deploymentTarget = try Version.parse(string) } else if let double: Double = jsonDictionary.json(atKeyPath: "deploymentTarget") { @@ -271,7 +316,7 @@ extension Target: NamedJSONDictionaryConvertible { deploymentTarget = nil } - settings = jsonDictionary.json(atKeyPath: "settings") ?? .empty + settings = try BuildSettingsParser(jsonDictionary: jsonDictionary).parse() configFiles = jsonDictionary.json(atKeyPath: "configFiles") ?? [:] if let source: String = jsonDictionary.json(atKeyPath: "sources") { sources = [TargetSource(path: source)] @@ -291,9 +336,20 @@ extension Target: NamedJSONDictionaryConvertible { if jsonDictionary["dependencies"] == nil { dependencies = [] } else { - dependencies = try jsonDictionary.json(atKeyPath: "dependencies", invalidItemBehaviour: .fail) + let dependencies: [Dependency] = try jsonDictionary.json(atKeyPath: "dependencies", invalidItemBehaviour: .fail) + self.dependencies = dependencies.filter { [platform] dependency -> Bool in + // If unspecified, all platforms are supported + guard let platforms = dependency.platforms else { return true } + return platforms.contains(platform) + } } - + + if jsonDictionary["buildToolPlugins"] == nil { + buildToolPlugins = [] + } else { + self.buildToolPlugins = try jsonDictionary.json(atKeyPath: "buildToolPlugins", invalidItemBehaviour: .fail) + } + if jsonDictionary["info"] != nil { info = try jsonDictionary.json(atKeyPath: "info") as Plist } @@ -313,6 +369,7 @@ extension Target: NamedJSONDictionaryConvertible { legacy = jsonDictionary.json(atKeyPath: "legacy") attributes = jsonDictionary.json(atKeyPath: "attributes") ?? [:] onlyCopyFilesOnInstall = jsonDictionary.json(atKeyPath: "onlyCopyFilesOnInstall") ?? false + putResourcesBeforeSourcesBuildPhase = jsonDictionary.json(atKeyPath: "putResourcesBeforeSourcesBuildPhase") ?? false } } @@ -321,6 +378,7 @@ extension Target: JSONEncodable { var dict: [String: Any?] = [ "type": type.name, "platform": platform.rawValue, + "supportedDestinations": supportedDestinations?.map { $0.rawValue }, "settings": settings.toJSONValue(), "configFiles": configFiles, "attributes": attributes, @@ -328,6 +386,7 @@ extension Target: JSONEncodable { "dependencies": dependencies.map { $0.toJSONValue() }, "postCompileScripts": postCompileScripts.map { $0.toJSONValue() }, "prebuildScripts": preBuildScripts.map { $0.toJSONValue() }, + "buildToolPlugins": buildToolPlugins.map { $0.toJSONValue() }, "postbuildScripts": postBuildScripts.map { $0.toJSONValue() }, "buildRules": buildRules.map { $0.toJSONValue() }, "deploymentTarget": deploymentTarget?.deploymentTarget, @@ -348,6 +407,10 @@ extension Target: JSONEncodable { dict["onlyCopyFilesOnInstall"] = true } + if putResourcesBeforeSourcesBuildPhase { + dict["putResourcesBeforeSourcesBuildPhase"] = true + } + return dict } } diff --git a/Sources/ProjectSpec/TargetReference.swift b/Sources/ProjectSpec/TargetReference.swift index 1a64e258a..22da0a2e1 100644 --- a/Sources/ProjectSpec/TargetReference.swift +++ b/Sources/ProjectSpec/TargetReference.swift @@ -46,8 +46,8 @@ extension TargetReference: CustomStringConvertible { public var reference: String { switch location { case .local: return name - case .project(let projectPath): - return "\(projectPath)/\(name)" + case .project(let root): + return "\(root)/\(name)" } } diff --git a/Sources/ProjectSpec/TargetScheme.swift b/Sources/ProjectSpec/TargetScheme.swift index ce54f6172..967417b55 100644 --- a/Sources/ProjectSpec/TargetScheme.swift +++ b/Sources/ProjectSpec/TargetScheme.swift @@ -6,47 +6,64 @@ public struct TargetScheme: Equatable { public static let gatherCoverageDataDefault = false public static let disableMainThreadCheckerDefault = false public static let stopOnEveryMainThreadCheckerIssueDefault = false + public static let disableThreadPerformanceCheckerDefault = false public static let buildImplicitDependenciesDefault = true public var testTargets: [Scheme.Test.TestTarget] public var configVariants: [String] public var gatherCoverageData: Bool + public var coverageTargets: [TestableTargetReference] + public var storeKitConfiguration: String? public var language: String? public var region: String? public var disableMainThreadChecker: Bool public var stopOnEveryMainThreadCheckerIssue: Bool + public var disableThreadPerformanceChecker: Bool public var buildImplicitDependencies: Bool public var commandLineArguments: [String: Bool] public var environmentVariables: [XCScheme.EnvironmentVariable] public var preActions: [Scheme.ExecutionAction] public var postActions: [Scheme.ExecutionAction] + public var management: Scheme.Management? + public var testPlans: [TestPlan] public init( testTargets: [Scheme.Test.TestTarget] = [], + testPlans: [TestPlan] = [], configVariants: [String] = [], gatherCoverageData: Bool = gatherCoverageDataDefault, + coverageTargets: [TestableTargetReference] = [], + storeKitConfiguration: String? = nil, language: String? = nil, region: String? = nil, disableMainThreadChecker: Bool = disableMainThreadCheckerDefault, stopOnEveryMainThreadCheckerIssue: Bool = stopOnEveryMainThreadCheckerIssueDefault, + disableThreadPerformanceChecker: Bool = disableThreadPerformanceCheckerDefault, buildImplicitDependencies: Bool = buildImplicitDependenciesDefault, commandLineArguments: [String: Bool] = [:], environmentVariables: [XCScheme.EnvironmentVariable] = [], preActions: [Scheme.ExecutionAction] = [], - postActions: [Scheme.ExecutionAction] = [] + postActions: [Scheme.ExecutionAction] = [], + management: Scheme.Management? = nil ) { self.testTargets = testTargets + self.testPlans = testPlans self.configVariants = configVariants self.gatherCoverageData = gatherCoverageData + self.coverageTargets = coverageTargets + self.storeKitConfiguration = storeKitConfiguration self.language = language self.region = region self.disableMainThreadChecker = disableMainThreadChecker self.stopOnEveryMainThreadCheckerIssue = stopOnEveryMainThreadCheckerIssue + self.disableThreadPerformanceChecker = disableThreadPerformanceChecker self.buildImplicitDependencies = buildImplicitDependencies self.commandLineArguments = commandLineArguments self.environmentVariables = environmentVariables self.preActions = preActions self.postActions = postActions + self.postActions = postActions + self.management = management } } @@ -56,9 +73,10 @@ extension TargetScheme: JSONObjectConvertible { if let targets = jsonDictionary["testTargets"] as? [Any] { testTargets = try targets.compactMap { target in if let string = target as? String { - return .init(targetReference: try TargetReference(string)) - } else if let dictionary = target as? JSONDictionary { - return try .init(jsonDictionary: dictionary) + return .init(targetReference: try TestableTargetReference(string)) + } else if let dictionary = target as? JSONDictionary, + let target: Scheme.Test.TestTarget = try? .init(jsonDictionary: dictionary) { + return target } else { return nil } @@ -66,17 +84,37 @@ extension TargetScheme: JSONObjectConvertible { } else { testTargets = [] } + + if let targets = jsonDictionary["coverageTargets"] as? [Any] { + coverageTargets = try targets.compactMap { target in + if let string = target as? String { + return try TestableTargetReference(string) + } else if let dictionary = target as? JSONDictionary, + let target: TestableTargetReference = try? .init(jsonDictionary: dictionary) { + return target + } else { + return nil + } + } + } else { + coverageTargets = [] + } + + testPlans = try (jsonDictionary.json(atKeyPath: "testPlans") ?? []).map { try TestPlan(jsonDictionary: $0) } configVariants = jsonDictionary.json(atKeyPath: "configVariants") ?? [] gatherCoverageData = jsonDictionary.json(atKeyPath: "gatherCoverageData") ?? TargetScheme.gatherCoverageDataDefault + storeKitConfiguration = jsonDictionary.json(atKeyPath: "storeKitConfiguration") language = jsonDictionary.json(atKeyPath: "language") region = jsonDictionary.json(atKeyPath: "region") disableMainThreadChecker = jsonDictionary.json(atKeyPath: "disableMainThreadChecker") ?? TargetScheme.disableMainThreadCheckerDefault stopOnEveryMainThreadCheckerIssue = jsonDictionary.json(atKeyPath: "stopOnEveryMainThreadCheckerIssue") ?? TargetScheme.stopOnEveryMainThreadCheckerIssueDefault + disableThreadPerformanceChecker = jsonDictionary.json(atKeyPath: "disableThreadPerformanceChecker") ?? TargetScheme.disableThreadPerformanceCheckerDefault buildImplicitDependencies = jsonDictionary.json(atKeyPath: "buildImplicitDependencies") ?? TargetScheme.buildImplicitDependenciesDefault commandLineArguments = jsonDictionary.json(atKeyPath: "commandLineArguments") ?? [:] environmentVariables = try XCScheme.EnvironmentVariable.parseAll(jsonDictionary: jsonDictionary) preActions = jsonDictionary.json(atKeyPath: "preActions") ?? [] postActions = jsonDictionary.json(atKeyPath: "postActions") ?? [] + management = jsonDictionary.json(atKeyPath: "management") } } @@ -84,8 +122,10 @@ extension TargetScheme: JSONEncodable { public func toJSONValue() -> Any { var dict: [String: Any] = [ "configVariants": configVariants, + "coverageTargets": coverageTargets.map { $0.reference }, "commandLineArguments": commandLineArguments, "testTargets": testTargets.map { $0.toJSONValue() }, + "testPlans": testPlans.map { $0.toJSONValue() }, "environmentVariables": environmentVariables.map { $0.toJSONValue() }, "preActions": preActions.map { $0.toJSONValue() }, "postActions": postActions.map { $0.toJSONValue() }, @@ -95,6 +135,10 @@ extension TargetScheme: JSONEncodable { dict["gatherCoverageData"] = gatherCoverageData } + if let storeKitConfiguration = storeKitConfiguration { + dict["storeKitConfiguration"] = storeKitConfiguration + } + if disableMainThreadChecker != TargetScheme.disableMainThreadCheckerDefault { dict["disableMainThreadChecker"] = disableMainThreadChecker } @@ -103,6 +147,10 @@ extension TargetScheme: JSONEncodable { dict["stopOnEveryMainThreadCheckerIssue"] = stopOnEveryMainThreadCheckerIssue } + if disableThreadPerformanceChecker != TargetScheme.disableThreadPerformanceCheckerDefault { + dict["disableThreadPerformanceChecker"] = disableThreadPerformanceChecker + } + if buildImplicitDependencies != TargetScheme.buildImplicitDependenciesDefault { dict["buildImplicitDependencies"] = buildImplicitDependencies } @@ -115,6 +163,19 @@ extension TargetScheme: JSONEncodable { dict["region"] = region } + if let management = management { + dict["management"] = management.toJSONValue() + } + return dict } } + +extension TargetScheme: PathContainer { + + static var pathProperties: [PathProperty] { + [ + .object("testPlans", TestPlan.pathProperties), + ] + } +} diff --git a/Sources/ProjectSpec/TargetSource.swift b/Sources/ProjectSpec/TargetSource.swift index 8c55b7875..f5932c837 100644 --- a/Sources/ProjectSpec/TargetSource.swift +++ b/Sources/ProjectSpec/TargetSource.swift @@ -1,13 +1,16 @@ import Foundation import JSONUtilities import PathKit -import enum XcodeProj.BuildPhase -import class XcodeProj.PBXCopyFilesBuildPhase public struct TargetSource: Equatable { public static let optionalDefault = false - - public var path: String + + public var path: String { + didSet { + path = (path as NSString).standardizingPath + } + } + public var name: String? public var group: String? public var compilerFlags: [String] @@ -15,11 +18,13 @@ public struct TargetSource: Equatable { public var includes: [String] public var type: SourceType? public var optional: Bool - public var buildPhase: BuildPhase? + public var buildPhase: BuildPhaseSpec? public var headerVisibility: HeaderVisibility? public var createIntermediateGroups: Bool? public var attributes: [String] public var resourceTags: [String] + public var inferDestinationFiltersByPath: Bool? + public var destinationFilters: [SupportedDestination]? public enum HeaderVisibility: String { case `public` @@ -35,94 +40,6 @@ public struct TargetSource: Equatable { } } - public enum BuildPhase: Equatable { - case sources - case headers - case resources - case copyFiles(CopyFilesSettings) - case none - // Not currently exposed as selectable options, but used internally - case frameworks - case runScript - case carbonResources - - public struct CopyFilesSettings: Equatable, Hashable { - public static let xpcServices = CopyFilesSettings( - destination: .productsDirectory, - subpath: "$(CONTENTS_FOLDER_PATH)/XPCServices", - phaseOrder: .postCompile - ) - - public enum Destination: String { - case absolutePath - case productsDirectory - case wrapper - case executables - case resources - case javaResources - case frameworks - case sharedFrameworks - case sharedSupport - case plugins - - public var destination: PBXCopyFilesBuildPhase.SubFolder? { - switch self { - case .absolutePath: return .absolutePath - case .productsDirectory: return .productsDirectory - case .wrapper: return .wrapper - case .executables: return .executables - case .resources: return .resources - case .javaResources: return .javaResources - case .frameworks: return .frameworks - case .sharedFrameworks: return .sharedFrameworks - case .sharedSupport: return .sharedSupport - case .plugins: return .plugins - } - } - } - - public enum PhaseOrder: String { - /// Run before the Compile Sources phase - case preCompile - /// Run after the Compile Sources and post-compile Run Script phases - case postCompile - } - - public var destination: Destination - public var subpath: String - public var phaseOrder: PhaseOrder - - public init( - destination: Destination, - subpath: String, - phaseOrder: PhaseOrder - ) { - self.destination = destination - self.subpath = subpath - self.phaseOrder = phaseOrder - } - } - - public var buildPhase: XcodeProj.BuildPhase? { - switch self { - case .sources: return .sources - case .headers: return .headers - case .resources: return .resources - case .copyFiles: return .copyFiles - case .frameworks: return .frameworks - case .runScript: return .runScript - case .carbonResources: return .carbonResources - case .none: return nil - } - } - } - - public enum SourceType: String { - case group - case file - case folder - } - public init( path: String, name: String? = nil, @@ -132,13 +49,15 @@ public struct TargetSource: Equatable { includes: [String] = [], type: SourceType? = nil, optional: Bool = optionalDefault, - buildPhase: BuildPhase? = nil, + buildPhase: BuildPhaseSpec? = nil, headerVisibility: HeaderVisibility? = nil, createIntermediateGroups: Bool? = nil, attributes: [String] = [], - resourceTags: [String] = [] + resourceTags: [String] = [], + inferDestinationFiltersByPath: Bool? = nil, + destinationFilters: [SupportedDestination]? = nil ) { - self.path = path + self.path = (path as NSString).standardizingPath self.name = name self.group = group self.compilerFlags = compilerFlags @@ -151,6 +70,8 @@ public struct TargetSource: Equatable { self.createIntermediateGroups = createIntermediateGroups self.attributes = attributes self.resourceTags = resourceTags + self.inferDestinationFiltersByPath = inferDestinationFiltersByPath + self.destinationFilters = destinationFilters } } @@ -173,6 +94,7 @@ extension TargetSource: JSONObjectConvertible { public init(jsonDictionary: JSONDictionary) throws { path = try jsonDictionary.json(atKeyPath: "path") + path = (path as NSString).standardizingPath // Done in two steps as the compiler can't figure out the types otherwise name = jsonDictionary.json(atKeyPath: "name") group = jsonDictionary.json(atKeyPath: "group") @@ -188,14 +110,20 @@ extension TargetSource: JSONObjectConvertible { optional = jsonDictionary.json(atKeyPath: "optional") ?? TargetSource.optionalDefault if let string: String = jsonDictionary.json(atKeyPath: "buildPhase") { - buildPhase = try BuildPhase(string: string) + buildPhase = try BuildPhaseSpec(string: string) } else if let dict: JSONDictionary = jsonDictionary.json(atKeyPath: "buildPhase") { - buildPhase = try BuildPhase(jsonDictionary: dict) + buildPhase = try BuildPhaseSpec(jsonDictionary: dict) } createIntermediateGroups = jsonDictionary.json(atKeyPath: "createIntermediateGroups") attributes = jsonDictionary.json(atKeyPath: "attributes") ?? [] resourceTags = jsonDictionary.json(atKeyPath: "resourceTags") ?? [] + + inferDestinationFiltersByPath = jsonDictionary.json(atKeyPath: "inferDestinationFiltersByPath") + + if let destinationFilters: [SupportedDestination] = jsonDictionary.json(atKeyPath: "destinationFilters") { + self.destinationFilters = destinationFilters + } } } @@ -212,78 +140,19 @@ extension TargetSource: JSONEncodable { "buildPhase": buildPhase?.toJSONValue(), "createIntermediateGroups": createIntermediateGroups, "resourceTags": resourceTags, + "path": path, + "inferDestinationFiltersByPath": inferDestinationFiltersByPath, + "destinationFilters": destinationFilters?.map { $0.rawValue }, ] if optional != TargetSource.optionalDefault { dict["optional"] = optional } - if dict.count == 0 { - return path - } - - dict["path"] = path - return dict } } -extension TargetSource.BuildPhase { - - public init(string: String) throws { - switch string { - case "sources": self = .sources - case "headers": self = .headers - case "resources": self = .resources - case "copyFiles": - throw SpecParsingError.invalidSourceBuildPhase("copyFiles must specify a \"destination\" and optional \"subpath\"") - case "none": self = .none - default: - throw SpecParsingError.invalidSourceBuildPhase(string.quoted) - } - } -} - -extension TargetSource.BuildPhase: JSONObjectConvertible { - - public init(jsonDictionary: JSONDictionary) throws { - self = .copyFiles(try jsonDictionary.json(atKeyPath: "copyFiles")) - } -} - -extension TargetSource.BuildPhase: JSONEncodable { - public func toJSONValue() -> Any { - switch self { - case .sources: return "sources" - case .headers: return "headers" - case .resources: return "resources" - case .copyFiles(let files): return ["copyFiles": files.toJSONValue()] - case .none: return "none" - case .frameworks: fatalError("invalid build phase") - case .runScript: fatalError("invalid build phase") - case .carbonResources: fatalError("invalid build phase") - } - } -} - -extension TargetSource.BuildPhase.CopyFilesSettings: JSONObjectConvertible { - - public init(jsonDictionary: JSONDictionary) throws { - destination = try jsonDictionary.json(atKeyPath: "destination") - subpath = jsonDictionary.json(atKeyPath: "subpath") ?? "" - phaseOrder = .postCompile - } -} - -extension TargetSource.BuildPhase.CopyFilesSettings: JSONEncodable { - public func toJSONValue() -> Any { - [ - "destination": destination.rawValue, - "subpath": subpath, - ] - } -} - extension TargetSource: PathContainer { static var pathProperties: [PathProperty] { diff --git a/Sources/ProjectSpec/TestPlan.swift b/Sources/ProjectSpec/TestPlan.swift new file mode 100644 index 000000000..c47b17cab --- /dev/null +++ b/Sources/ProjectSpec/TestPlan.swift @@ -0,0 +1,39 @@ +import Foundation +import JSONUtilities + +public struct TestPlan: Hashable { + public var path: String + public var defaultPlan: Bool + + public init(path: String, defaultPlan: Bool = false) { + self.defaultPlan = defaultPlan + self.path = path + } +} + + +extension TestPlan: JSONObjectConvertible { + + public init(jsonDictionary: JSONDictionary) throws { + path = try jsonDictionary.json(atKeyPath: "path") + defaultPlan = jsonDictionary.json(atKeyPath: "defaultPlan") ?? false + } +} + +extension TestPlan: JSONEncodable { + public func toJSONValue() -> Any { + [ + "path": path, + "defaultPlan": defaultPlan, + ] as [String : Any] + } +} + +extension TestPlan: PathContainer { + + static var pathProperties: [PathProperty] { + [ + .string("path"), + ] + } +} diff --git a/Sources/ProjectSpec/TestTargeReference.swift b/Sources/ProjectSpec/TestTargeReference.swift new file mode 100644 index 000000000..17ea557bb --- /dev/null +++ b/Sources/ProjectSpec/TestTargeReference.swift @@ -0,0 +1,112 @@ +import Foundation +import JSONUtilities + +public struct TestableTargetReference: Hashable { + public var name: String + public var location: Location + + public var targetReference: TargetReference { + switch location { + case .local: + return TargetReference(name: name, location: .local) + case .project(let projectName): + return TargetReference(name: name, location: .project(projectName)) + case .package: + fatalError("Package target is only available for testable") + } + } + + public enum Location: Hashable { + case local + case project(String) + case package(String) + } + + public init(name: String, location: Location) { + self.name = name + self.location = location + } +} + +extension TestableTargetReference { + public init(_ string: String) throws { + let paths = string.split(separator: "/") + switch paths.count { + case 2: + location = .project(String(paths[0])) + name = String(paths[1]) + case 1: + location = .local + name = String(paths[0]) + default: + throw SpecParsingError.invalidTargetReference(string) + } + } + + public static func local(_ name: String) -> TestableTargetReference { + TestableTargetReference(name: name, location: .local) + } + + public static func project(_ name: String) -> TestableTargetReference { + let paths = name.split(separator: "/") + return TestableTargetReference(name: String(paths[1]), location: .project(String(paths[0]))) + } + + public static func package(_ name: String) -> TestableTargetReference { + let paths = name.split(separator: "/") + return TestableTargetReference(name: String(paths[1]), location: .package(String(paths[0]))) + } +} + +extension TestableTargetReference: ExpressibleByStringLiteral { + public init(stringLiteral value: String) { + try! self.init(value) + } +} + +extension TestableTargetReference: CustomStringConvertible { + public var reference: String { + switch location { + case .local: return name + case .project(let root), .package(let root): + return "\(root)/\(name)" + } + } + + public var description: String { + reference + } +} + +extension TestableTargetReference: JSONObjectConvertible { + + public init(jsonDictionary: JSONDictionary) throws { + if let project: String = jsonDictionary.json(atKeyPath: "project") { + let paths = project.split(separator: "/") + name = String(paths[1]) + location = .project(String(paths[0])) + } else if let project: String = jsonDictionary.json(atKeyPath: "package") { + let paths = project.split(separator: "/") + name = String(paths[1]) + location = .package(String(paths[0])) + } else { + name = try jsonDictionary.json(atKeyPath: "local") + location = .local + } + } +} + +extension TestableTargetReference: JSONEncodable { + public func toJSONValue() -> Any { + var dictionary: JSONDictionary = [:] + switch self.location { + case .package(let packageName): + dictionary["package"] = "\(packageName)/\(name)" + case .project(let projectName): + dictionary["project"] = "\(projectName)/\(name)" + case .local: + dictionary["local"] = name + } + return dictionary + } +} diff --git a/Sources/ProjectSpec/VersionExtensions.swift b/Sources/ProjectSpec/VersionExtensions.swift index 0b67ce605..3ab52d65a 100644 --- a/Sources/ProjectSpec/VersionExtensions.swift +++ b/Sources/ProjectSpec/VersionExtensions.swift @@ -8,7 +8,7 @@ import Foundation import Version -extension Version: ExpressibleByStringLiteral { +extension Version: Swift.ExpressibleByStringLiteral { public static func parse(_ string: String) throws -> Version { if let version = Version(tolerant: string) { diff --git a/Sources/ProjectSpec/XCProjExtensions.swift b/Sources/ProjectSpec/XCProjExtensions.swift index 089bb4059..e1da8a3b0 100644 --- a/Sources/ProjectSpec/XCProjExtensions.swift +++ b/Sources/ProjectSpec/XCProjExtensions.swift @@ -26,6 +26,10 @@ extension PBXProductType { fileExtension == "appex" } + public var isSystemExtension: Bool { + fileExtension == "dext" || fileExtension == "systemextension" + } + public var isApp: Bool { fileExtension == "app" } @@ -35,7 +39,7 @@ extension PBXProductType { } public var isExecutable: Bool { - isApp || isExtension || isTest || self == .commandLineTool + isApp || isExtension || isSystemExtension || isTest || self == .commandLineTool } public var name: String { @@ -44,8 +48,8 @@ extension PBXProductType { public var canSkipCompileSourcesBuildPhase: Bool { switch self { - case .bundle, .stickerPack, .messagesApplication: - // Bundles, sticker packs and simple messages applications without sources should not include a + case .bundle, .watch2App, .stickerPack, .messagesApplication: + // Bundles, watch apps, sticker packs and simple messages applications without sources should not include a // compile sources build phase. Doing so can cause Xcode to produce an error on build. return true default: @@ -54,17 +58,16 @@ extension PBXProductType { } /// Function to determine when a dependendency should be embedded into the target - public func shouldEmbed(_ dependencyType: PBXProductType) -> Bool { - switch dependencyType { - case .staticLibrary, .staticFramework: - // Some dependendencies should not be embed, independently of the target type + public func shouldEmbed(_ dependencyTarget: Target) -> Bool { + switch dependencyTarget.defaultLinkage { + case .static: + // Static dependencies should never embed return false - - default: + case .dynamic, .none: if isApp { - // If target is an app, all dependencies should be embed (except for the ones mentioned above) + // If target is an app, all dependencies should be embed (unless they're static) return true - } else if isTest, [.framework, .bundle].contains(dependencyType) { + } else if isTest, [.framework, .bundle].contains(dependencyTarget.type) { // If target is test, some dependencies should be embed (depending on their type) return true } else { @@ -79,18 +82,20 @@ extension Platform { public var emoji: String { switch self { + case .auto: return "🤖" case .iOS: return "📱" case .watchOS: return "⌚️" case .tvOS: return "📺" case .macOS: return "🖥" + case .visionOS: return "🕶️" } } } -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 == .commandLineTool + type.isApp || type.isExtension || type.isSystemExtension || type == .commandLineTool } } @@ -103,3 +108,30 @@ extension XCScheme.CommandLineArguments { self.init(arguments: args) } } + +extension BreakpointExtensionID { + + init(string: String) throws { + if let id = BreakpointExtensionID(rawValue: "Xcode.Breakpoint.\(string)Breakpoint") { + self = id + } else if let id = BreakpointExtensionID(rawValue: string) { + self = id + } else { + throw SpecParsingError.unknownBreakpointType(string) + } + } +} + +extension BreakpointActionExtensionID { + + init(string: String) throws { + if let type = BreakpointActionExtensionID(rawValue: "Xcode.BreakpointAction.\(string)") { + self = type + } else if let type = BreakpointActionExtensionID(rawValue: string) { + self = type + } else { + throw SpecParsingError.unknownBreakpointActionType(string) + } + } +} + diff --git a/Sources/TestSupport/TestHelpers.swift b/Sources/TestSupport/TestHelpers.swift index 62cbaab33..757856dff 100644 --- a/Sources/TestSupport/TestHelpers.swift +++ b/Sources/TestSupport/TestHelpers.swift @@ -124,3 +124,11 @@ extension XCTestCase { describe(name, test) } } + + +public func skipIfNecessary() throws { + #if os(Linux) && swift(<6.0.2) + // https://github.com/swiftlang/swift-foundation/pull/1002 + throw XCTSkip("Skipping test on Linux until PropertyListDecoder issues are fixed.") + #endif +} \ No newline at end of file diff --git a/Sources/XcodeGen/main.swift b/Sources/XcodeGen/main.swift index d060e649a..577fe92b1 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.16.0") +let version = Version("2.44.1") let cli = XcodeGenCLI(version: version) cli.execute() diff --git a/Sources/XcodeGenCLI/Arguments.swift b/Sources/XcodeGenCLI/Arguments.swift index fef7c7981..88f6c34f7 100644 --- a/Sources/XcodeGenCLI/Arguments.swift +++ b/Sources/XcodeGenCLI/Arguments.swift @@ -2,7 +2,7 @@ import Foundation import PathKit import SwiftCLI -extension Path: ConvertibleFromString { +extension Path: SwiftCLI.ConvertibleFromString { public init?(input: String) { self.init(input) diff --git a/Sources/XcodeGenCLI/Commands/CacheCommand.swift b/Sources/XcodeGenCLI/Commands/CacheCommand.swift new file mode 100644 index 000000000..70a14a241 --- /dev/null +++ b/Sources/XcodeGenCLI/Commands/CacheCommand.swift @@ -0,0 +1,44 @@ +import Foundation +import PathKit +import ProjectSpec +import SwiftCLI +import XcodeGenKit +import XcodeProj +import Version + +class CacheCommand: ProjectCommand { + + @Key("--cache-path", description: "Where the cache file will be loaded from and save to. Defaults to ~/.xcodegen/cache/{SPEC_PATH_HASH}") + var cacheFilePath: Path? + + init(version: Version) { + super.init(version: version, + name: "cache", + shortDescription: "Write the project cache") + } + + override func execute(specLoader: SpecLoader, projectSpecPath: Path, project: Project) throws { + + let cacheFilePath = self.cacheFilePath ?? Path("~/.xcodegen/cache/\(projectSpecPath.absolute().string.md5)").absolute() + + var cacheFile: CacheFile? + + // generate cache + do { + cacheFile = try specLoader.generateCacheFile() + } catch { + throw GenerationError.projectSpecParsingError(error) + } + + // write cache + if let cacheFile = cacheFile { + do { + try cacheFilePath.parent().mkpath() + try cacheFilePath.write(cacheFile.string) + success("Wrote cache to \(cacheFilePath)") + } catch { + info("Failed to write cache: \(error.localizedDescription)") + } + } + } +} diff --git a/Sources/XcodeGenCLI/Commands/DumpCommand.swift b/Sources/XcodeGenCLI/Commands/DumpCommand.swift index b3da9dcca..b0d59a612 100644 --- a/Sources/XcodeGenCLI/Commands/DumpCommand.swift +++ b/Sources/XcodeGenCLI/Commands/DumpCommand.swift @@ -41,15 +41,13 @@ class DumpCommand: ProjectCommand { output = try Yams.dump(object: project.toJSONDictionary()) case .summary: output = project.debugDescription - case .graphviz: - output = GraphVizGenerator().generateModuleGraphViz(targets: project.targets) } if let file = file { try file.parent().mkpath() try file.write(output) } else { - stdout.print(output) + success(output) } } } @@ -61,7 +59,6 @@ private enum DumpType: String, ConvertibleFromString, CaseIterable { case parsedJSON = "parsed-json" case parsedYaml = "parsed-yaml" case summary - case graphviz static var defaultValue: DumpType { .yaml } } diff --git a/Sources/XcodeGenCLI/Commands/GenerateCommand.swift b/Sources/XcodeGenCLI/Commands/GenerateCommand.swift index bfea587e0..d0e4eabe9 100644 --- a/Sources/XcodeGenCLI/Commands/GenerateCommand.swift +++ b/Sources/XcodeGenCLI/Commands/GenerateCommand.swift @@ -8,9 +8,6 @@ import Version class GenerateCommand: ProjectCommand { - @Flag("-q", "--quiet", description: "Suppress all informational and success output") - var quiet: Bool - @Flag("-c", "--use-cache", description: "Use a cache for the xcodegen spec. This will prevent unnecessarily generating the project if nothing has changed") var useCache: Bool @@ -42,11 +39,16 @@ class GenerateCommand: ProjectCommand { let projectPath = projectDirectory + "\(project.name).xcodeproj" + // run pre gen command before we use the cache as the scripts may change it + if let command = project.options.preGenCommand { + try Task.run(bash: command, directory: projectDirectory.absolute().string) + } + let cacheFilePath = self.cacheFilePath ?? Path("~/.xcodegen/cache/\(projectSpecPath.absolute().string.md5)").absolute() var cacheFile: CacheFile? - // read cache + // generate cache if useCache || self.cacheFilePath != nil { do { cacheFile = try specLoader.generateCacheFile() @@ -64,7 +66,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 { @@ -80,11 +82,6 @@ class GenerateCommand: ProjectCommand { throw GenerationError.validationError(error) } - // run pre gen command - if let command = project.options.preGenCommand { - try Task.run(bash: command, directory: projectDirectory.absolute().string) - } - // generate plists info("⚙️ Generating plists...") let fileWriter = FileWriter(project: project) @@ -102,7 +99,13 @@ class GenerateCommand: ProjectCommand { let xcodeProject: XcodeProj do { let projectGenerator = ProjectGenerator(project: project) - xcodeProject = try projectGenerator.generateXcodeProject(in: projectDirectory) + + guard let userName = ProcessInfo.processInfo.environment["USER"] else { + throw GenerationError.missingUsername + } + + xcodeProject = try projectGenerator.generateXcodeProject(in: projectDirectory, userName: userName) + } catch { throw GenerationError.generationError(error) } @@ -111,6 +114,7 @@ class GenerateCommand: ProjectCommand { info("⚙️ Writing project...") do { try fileWriter.writeXcodeProject(xcodeProject, to: projectPath) + success("Created project at \(projectPath)") } catch { throw GenerationError.writingError(error) @@ -131,22 +135,4 @@ class GenerateCommand: ProjectCommand { try Task.run(bash: command, directory: projectDirectory.absolute().string) } } - - func info(_ string: String) { - if !quiet { - stdout.print(string) - } - } - - func warning(_ string: String) { - if !quiet { - stdout.print(string.yellow) - } - } - - func success(_ string: String) { - if !quiet { - stdout.print(string.green) - } - } } diff --git a/Sources/XcodeGenCLI/Commands/ProjectCommand.swift b/Sources/XcodeGenCLI/Commands/ProjectCommand.swift index 7866661a1..9f3b013c8 100644 --- a/Sources/XcodeGenCLI/Commands/ProjectCommand.swift +++ b/Sources/XcodeGenCLI/Commands/ProjectCommand.swift @@ -3,7 +3,7 @@ import SwiftCLI import ProjectSpec import XcodeGenKit import PathKit -import Core +import XcodeGenCore import Version class ProjectCommand: Command { @@ -12,8 +12,11 @@ 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? + @Flag("-q", "--quiet", description: "Suppress all informational and success output") + var quiet: Bool + + @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? @@ -28,26 +31,52 @@ 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() ] } + + 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) + } + } - let specLoader = SpecLoader(version: version) - let project: Project - - let variables: [String: String] = disableEnvExpansion ? [:] : ProcessInfo.processInfo.environment + func execute(specLoader: SpecLoader, projectSpecPath: Path, project: Project) throws {} - do { - project = try specLoader.loadProject(path: projectSpecPath, projectRoot: projectRoot, variables: variables) - } catch { - throw GenerationError.projectSpecParsingError(error) + func info(_ string: String) { + if !quiet { + stdout.print(string) } + } - try execute(specLoader: specLoader, projectSpecPath: projectSpecPath, project: project) + func warning(_ string: String) { + if !quiet { + stdout.print(string.yellow) + } } - func execute(specLoader: SpecLoader, projectSpecPath: Path, project: Project) throws {} + func success(_ string: String) { + if !quiet { + stdout.print(string.green) + } + } } diff --git a/Sources/XcodeGenCLI/GenerationError.swift b/Sources/XcodeGenCLI/GenerationError.swift index 985246bdb..b9470a93c 100644 --- a/Sources/XcodeGenCLI/GenerationError.swift +++ b/Sources/XcodeGenCLI/GenerationError.swift @@ -10,6 +10,7 @@ enum GenerationError: Error, CustomStringConvertible, ProcessError { case cacheGenerationError(Error) case validationError(SpecValidationError) case generationError(Error) + case missingUsername case writingError(Error) var description: String { @@ -24,6 +25,8 @@ enum GenerationError: Error, CustomStringConvertible, ProcessError { return error.description case let .generationError(error): return String(describing: error) + case .missingUsername: + return "Couldn't find current username" case let .writingError(error): return String(describing: error) } diff --git a/Sources/XcodeGenCLI/XcodeGenCLI.swift b/Sources/XcodeGenCLI/XcodeGenCLI.swift index 42afef037..8d6a69c59 100644 --- a/Sources/XcodeGenCLI/XcodeGenCLI.swift +++ b/Sources/XcodeGenCLI/XcodeGenCLI.swift @@ -15,6 +15,7 @@ public class XcodeGenCLI { description: "Generates Xcode projects", commands: [ generateCommand, + CacheCommand(version: version), DumpCommand(version: version), ] ) diff --git a/Sources/XcodeGenCore/ArrayExtensions.swift b/Sources/XcodeGenCore/ArrayExtensions.swift new file mode 100644 index 000000000..52c87ff77 --- /dev/null +++ b/Sources/XcodeGenCore/ArrayExtensions.swift @@ -0,0 +1,79 @@ +import Foundation + +public extension Array { + + func parallelMap(transform: (Element) -> T) -> [T] { + var result = ContiguousArray(repeating: nil, count: count) + return result.withUnsafeMutableBufferPointer { buffer in + DispatchQueue.concurrentPerform(iterations: buffer.count) { idx in + buffer[idx] = transform(self[idx]) + } + return buffer.map { $0! } + } + } +} + +/// Holds a sorted array, created from specified sequence +/// This structure is needed for the cases, when some part of application requires array to be sorted, but don't trust any inputs :) +public struct SortedArray { + public let value: Array + public init(_ value: S) where S.Element == T { + self.value = value.sorted() + } +} + +public extension SortedArray { + /// Returns the first index in which an element of the collection satisfies the given predicate. + /// The collection assumed to be sorted. If collection is not have sorted values the result is undefined. + /// + /// The idea is to get first index of a function for which the given predicate evaluates to true. + /// + /// let values = [1,2,3,4,5] + /// let idx = values.firstIndexAssumingSorted(where: { $0 > 3 }) + /// + /// // false, false, false, true, true + /// // ^ + /// // therefore idx == 3 + /// + /// - Parameter predicate: A closure that takes an element as its argument + /// and returns a Boolean value that indicates whether the passed element + /// represents a match. + /// + /// - Returns: The index of the first element for which `predicate` returns + /// `true`. If no elements in the collection satisfy the given predicate, + /// returns `nil`. + /// + /// - Complexity: O(log(*n*)), where *n* is the length of the collection. + @inlinable + func firstIndex(where predicate: (T) throws -> Bool) rethrows -> Int? { + // Predicate should divide a collection to two pairs of values + // "bad" values for which predicate returns `false`` + // "good" values for which predicate return `true` + // false false false false false true true true + // ^ + // The idea is to get _first_ index which for which the predicate returns `true` + let lastIndex = value.count + + // The index that represents where bad values start + var badIndex = -1 + + // The index that represents where good values start + var goodIndex = lastIndex + var midIndex = (badIndex + goodIndex) / 2 + + while badIndex + 1 < goodIndex { + if try predicate(value[midIndex]) { + goodIndex = midIndex + } else { + badIndex = midIndex + } + midIndex = (badIndex + goodIndex) / 2 + } + + // We're out of bounds, no good items in array + if midIndex == lastIndex || goodIndex == lastIndex { + return nil + } + return goodIndex + } +} diff --git a/Sources/XcodeGenCore/Atomic.swift b/Sources/XcodeGenCore/Atomic.swift new file mode 100644 index 000000000..b3b1b2940 --- /dev/null +++ b/Sources/XcodeGenCore/Atomic.swift @@ -0,0 +1,52 @@ +// +// Atomic.swift +// +// +// Created by Vladislav Lisianskii on 23.02.2022. +// + +import Foundation + +@propertyWrapper +public final class Atomic { + + private var value: Value + + private let queue = DispatchQueue( + label: "com.xcodegencore.atomic.\(UUID().uuidString)", + qos: .utility, + attributes: .concurrent, + autoreleaseFrequency: .inherit, + target: .global() + ) + + public init(wrappedValue: Value) { + self.value = wrappedValue + } + + public var wrappedValue: Value { + get { + queue.sync { value } + } + set { + queue.async(flags: .barrier) { [weak self] in + self?.value = newValue + } + } + } + + /// Allows us to get the actual `Atomic` instance with the $ + /// prefix. + public var projectedValue: Atomic { + return self + } + + /// Modifies the protected value using `closure`. + public func with( + _ closure: (inout Value) throws -> R + ) rethrows -> R { + try queue.sync(flags: .barrier) { + try closure(&value) + } + } +} diff --git a/Sources/Core/Glob.swift b/Sources/XcodeGenCore/Glob.swift similarity index 74% rename from Sources/Core/Glob.swift rename to Sources/XcodeGenCore/Glob.swift index 9eccc61dc..4cee0a801 100644 --- a/Sources/Core/Glob.swift +++ b/Sources/XcodeGenCore/Glob.swift @@ -57,7 +57,7 @@ public class Glob: Collection { public static let defaultBlacklistedDirectories = ["node_modules", "Pods"] - private var isDirectoryCache = [String: Bool]() + @Atomic private var isDirectoryCache = [String: Bool]() public let behavior: Behavior public let blacklistedDirectories: [String] @@ -89,15 +89,13 @@ public class Glob: Collection { } let patterns = behavior.supportsGlobstar ? expandGlobstar(pattern: adjustedPattern) : [adjustedPattern] - - for pattern in patterns { - var gt = glob_t() - if executeGlob(pattern: pattern, gt: >) { - populateFiles(gt: gt, includeFiles: includeFiles) - } - - globfree(>) - } + + #if os(macOS) + paths = patterns.parallelMap { paths(usingPattern: $0, includeFiles: includeFiles) }.flatMap { $0 } + #else + // Parallel invocations of Glob on Linux seems to be causing unexpected crashes + paths = patterns.map { paths(usingPattern: $0, includeFiles: includeFiles) }.flatMap { $0 } + #endif paths = Array(Set(paths)).sorted { lhs, rhs in lhs.compare(rhs) != ComparisonResult.orderedDescending @@ -136,7 +134,7 @@ public class Glob: Collection { let firstPart = parts.removeFirst() var lastPart = parts.joined(separator: "**") - var directories: [String] + var directories: [URL] if FileManager.default.fileExists(atPath: firstPart) { do { @@ -151,7 +149,7 @@ public class Glob: Collection { if behavior.includesFilesFromRootOfGlobstar { // Check the base directory for the glob star as well. - directories.insert(firstPart, at: 0) + directories.insert(URL(fileURLWithPath: firstPart), at: 0) // Include the globstar root directory ("dir/") in a pattern like "dir/**" or "dir/**/" if lastPart.isEmpty { @@ -163,29 +161,30 @@ public class Glob: Collection { lastPart = "*" } for directory in directories { - let partiallyResolvedPattern = NSString(string: directory).appendingPathComponent(lastPart) - results.append(contentsOf: expandGlobstar(pattern: partiallyResolvedPattern)) + let partiallyResolvedPattern = directory.appendingPathComponent(lastPart) + let standardizedPattern = (partiallyResolvedPattern.relativePath as NSString).standardizingPath + results.append(contentsOf: expandGlobstar(pattern: standardizedPattern)) } return results } - private func exploreDirectories(path: String) throws -> [String] { + private func exploreDirectories(path: String) throws -> [URL] { try FileManager.default.contentsOfDirectory(atPath: path) - .compactMap { subpath -> [String]? in + .compactMap { subpath -> [URL]? in if blacklistedDirectories.contains(subpath) { return nil } - let firstLevelPath = NSString(string: path).appendingPathComponent(subpath) - guard isDirectory(path: firstLevelPath) else { + let firstLevel = URL(fileURLWithPath: path).appendingPathComponent(subpath, isDirectory: true) + guard isDirectory(path: firstLevel.path) else { return nil } - var subDirs: [String] = try FileManager.default.subpathsOfDirectory(atPath: firstLevelPath) - .compactMap { subpath -> String? in - let fullPath = NSString(string: firstLevelPath).appendingPathComponent(subpath) - return isDirectory(path: fullPath) ? fullPath : nil + var subDirs: [URL] = try FileManager.default.subpathsOfDirectory(atPath: firstLevel.path) + .compactMap { subpath -> URL? in + let full = firstLevel.appendingPathComponent(subpath, isDirectory: true) + return isDirectory(path: full.path) ? full : nil } - subDirs.append(firstLevelPath) + subDirs.append(firstLevel) return subDirs } .joined() @@ -199,19 +198,38 @@ public class Glob: Collection { var isDirectoryBool = ObjCBool(false) let isDirectory = FileManager.default.fileExists(atPath: path, isDirectory: &isDirectoryBool) && isDirectoryBool.boolValue - isDirectoryCache[path] = isDirectory + $isDirectoryCache.with { isDirectoryCache in + isDirectoryCache[path] = isDirectory + } return isDirectory } private func clearCaches() { - isDirectoryCache.removeAll() + $isDirectoryCache.with { isDirectoryCache in + isDirectoryCache.removeAll() + } } - private func populateFiles(gt: glob_t, includeFiles: Bool) { + private func paths(usingPattern pattern: String, includeFiles: Bool) -> [String] { + var gt = glob_t() + defer { globfree(>) } + if executeGlob(pattern: pattern, gt: >) { + return populateFiles(gt: gt, includeFiles: includeFiles) + } + return [] + } + + private func populateFiles(gt: glob_t, includeFiles: Bool) -> [String] { + var paths = [String]() let includeDirectories = behavior.includesDirectoriesInResults - for i in 0.. Bool { + let relativePath = try child.relativePath(from: self) + return relativePath.components.allSatisfy { $0 != ".." } + } } diff --git a/Sources/Core/StringDiff.swift b/Sources/XcodeGenCore/StringDiff.swift similarity index 100% rename from Sources/Core/StringDiff.swift rename to Sources/XcodeGenCore/StringDiff.swift diff --git a/Sources/XcodeGenKit/BreakpointGenerator.swift b/Sources/XcodeGenKit/BreakpointGenerator.swift new file mode 100644 index 000000000..bf6b793c9 --- /dev/null +++ b/Sources/XcodeGenKit/BreakpointGenerator.swift @@ -0,0 +1,126 @@ +import Foundation +import ProjectSpec +import XcodeProj + +public class BreakpointGenerator { + + let project: Project + + public init(project: Project) { + self.project = project + } + + func generateBreakpointList() throws -> XCBreakpointList? { + let breakpoints = project.breakpoints + guard !breakpoints.isEmpty else { + return nil + } + return XCBreakpointList(type: "4", version: "2.0", breakpoints: try breakpoints.map({ try generateBreakpointProxy($0) })) + } + + private func generateBreakpointProxy(_ breakpoint: Breakpoint) throws -> XCBreakpointList.BreakpointProxy { + let breakpointExtensionID: BreakpointExtensionID + var filePath: String? + var line: String? + var column: String? + var scope: String? + var stopOnStyle: String? + var symbol: String? + var module: String? + switch breakpoint.type { + case let .file(path, lineNumber, columnNumber): + breakpointExtensionID = .file + filePath = path + line = String(lineNumber) + column = columnNumber.map(String.init) + case let .exception(exception): + breakpointExtensionID = .exception + scope = exception.scope.rawValue + stopOnStyle = exception.stopOnStyle.rawValue + case .swiftError: + breakpointExtensionID = .swiftError + case .openGLError: + breakpointExtensionID = .openGLError + case let .symbolic(symbolName, moduleName): + breakpointExtensionID = .symbolic + symbol = symbolName + module = moduleName + case .ideConstraintError: + breakpointExtensionID = .ideConstraintError + case .ideTestFailure: + breakpointExtensionID = .ideTestFailure + case .runtimeIssue: + breakpointExtensionID = .runtimeIssue + } + let xcbreakpoint = XCBreakpointList.BreakpointProxy.BreakpointContent( + enabled: breakpoint.enabled, + ignoreCount: String(breakpoint.ignoreCount), + continueAfterRunningActions: breakpoint.continueAfterRunningActions, + filePath: filePath, + startingColumn: column, + endingColumn: column, + startingLine: line, + endingLine: line, + symbol: symbol, + module: module, + scope: scope, + stopOnStyle: stopOnStyle, + condition: breakpoint.condition, + actions: try breakpoint.actions.map { try generateBreakpointActionProxy($0) } + ) + + return XCBreakpointList.BreakpointProxy( + breakpointExtensionID: breakpointExtensionID, + breakpointContent: xcbreakpoint + ) + } + + private func generateBreakpointActionProxy(_ breakpointAction: Breakpoint.Action) throws -> XCBreakpointList.BreakpointProxy.BreakpointContent.BreakpointActionProxy { + let actionExtensionID: BreakpointActionExtensionID + var consoleCommand: String? + var message: String? + var conveyanceType: String? + var command: String? + var arguments: String? + var waitUntilDone: Bool? + var script: String? + var soundName: String? + switch breakpointAction { + case let .debuggerCommand(command): + actionExtensionID = .debuggerCommand + consoleCommand = command + case let .log(log): + actionExtensionID = .log + message = log.message + conveyanceType = log.conveyanceType.rawValue + case let .shellCommand(commandPath, commandArguments, waitUntilCommandDone): + actionExtensionID = .shellCommand + command = commandPath + arguments = commandArguments + waitUntilDone = waitUntilCommandDone + case .graphicsTrace: + actionExtensionID = .graphicsTrace + case let .appleScript(appleScript): + actionExtensionID = .appleScript + script = appleScript + case let .sound(sound): + actionExtensionID = .sound + soundName = sound.rawValue + } + let xcaction = XCBreakpointList.BreakpointProxy.BreakpointContent.BreakpointActionProxy.ActionContent( + consoleCommand: consoleCommand, + message: message, + conveyanceType: conveyanceType, + command: command, + arguments: arguments, + waitUntilDone: waitUntilDone, + script: script, + soundName: soundName + ) + + return XCBreakpointList.BreakpointProxy.BreakpointContent.BreakpointActionProxy( + actionExtensionID: actionExtensionID, + actionContent: xcaction + ) + } +} diff --git a/Sources/XcodeGenKit/CarthageDependencyResolver.swift b/Sources/XcodeGenKit/CarthageDependencyResolver.swift index 8a0b256a6..46b83ac90 100644 --- a/Sources/XcodeGenKit/CarthageDependencyResolver.swift +++ b/Sources/XcodeGenKit/CarthageDependencyResolver.swift @@ -68,6 +68,9 @@ public class CarthageDependencyResolver { if let target = projectTarget as? Target { for dependency in target.dependencies { + if case (false, false) = (dependency.link, dependency.embed ?? topLevelTarget.shouldEmbedCarthageDependencies) { + continue + } guard !frameworks.contains(where: { $0.dependency == dependency }) else { continue } @@ -148,6 +151,9 @@ extension Platform { public var carthageName: String { switch self { + case .auto: + // This is a dummy value + return "auto" case .iOS: return "iOS" case .tvOS: @@ -156,6 +162,9 @@ extension Platform { return "watchOS" case .macOS: return "Mac" + case .visionOS: + // This is a dummy value because Carthage doesn't support visionOS. + return "visionOS" } } } diff --git a/Sources/XcodeGenKit/CarthageVersionLoader.swift b/Sources/XcodeGenKit/CarthageVersionLoader.swift index 4a15a634a..20eb26079 100644 --- a/Sources/XcodeGenKit/CarthageVersionLoader.swift +++ b/Sources/XcodeGenKit/CarthageVersionLoader.swift @@ -73,7 +73,7 @@ struct CarthageVersionFile: Decodable { } } -extension Platform: CodingKey { +extension Platform: Swift.CodingKey { public var stringValue: String { carthageName diff --git a/Sources/XcodeGenKit/GraphVizGenerator.swift b/Sources/XcodeGenKit/GraphVizGenerator.swift deleted file mode 100644 index e7e97b02f..000000000 --- a/Sources/XcodeGenKit/GraphVizGenerator.swift +++ /dev/null @@ -1,66 +0,0 @@ -import DOT -import Foundation -import GraphViz -import ProjectSpec - -extension Dependency { - var graphVizName: String { - switch self.type { - case .bundle, .package, .sdk, .framework, .carthage: - return "[\(self.type)]\\n\(reference)" - case .target: - return reference - } - } -} - -extension Dependency.DependencyType: CustomStringConvertible { - public var description: String { - switch self { - case .bundle: return "bundle" - case .package: return "package" - case .framework: return "framework" - case .carthage: return "carthage" - case .sdk: return "sdk" - case .target: return "target" - } - } -} - -extension Node { - init(target: Target) { - self.init(target.name) - self.shape = .box - } - - init(dependency: Dependency) { - self.init(dependency.reference) - self.shape = .box - self.label = dependency.graphVizName - } -} - -public class GraphVizGenerator { - - public init() {} - - public func generateModuleGraphViz(targets: [Target]) -> String { - return DOTEncoder().encode(generateGraph(targets: targets)) - } - - func generateGraph(targets: [Target]) -> Graph { - var graph = Graph(directed: true) - targets.forEach { target in - target.dependencies.forEach { dependency in - let from = Node(target: target) - graph.append(from) - let to = Node(dependency: dependency) - graph.append(to) - var edge = Edge(from: from, to: to) - edge.style = .dashed - graph.append(edge) - } - } - return graph - } -} diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index 8049cdc1d..8dcad5afb 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -13,6 +13,8 @@ public class PBXProjGenerator { let projectDirectory: Path? let carthageResolver: CarthageDependencyResolver + public static let copyFilesActionMask: UInt = 8 + var sourceGenerator: SourceGenerator! var targetObjects: [String: PBXTarget] = [:] @@ -20,6 +22,7 @@ public class PBXProjGenerator { var targetFileReferences: [String: PBXFileReference] = [:] var sdkFileReferences: [String: PBXFileReference] = [:] var packageReferences: [String: XCRemoteSwiftPackageReference] = [:] + var localPackageReferences: [String: XCLocalSwiftPackageReference] = [:] var carthageFrameworksByPlatform: [String: Set] = [:] var frameworkFiles: [PBXFileElement] = [] @@ -93,13 +96,16 @@ public class PBXProjGenerator { ) ) + let developmentRegion = project.options.developmentLanguage ?? "en" let pbxProject = addObject( PBXProject( name: project.name, buildConfigurationList: buildConfigList, compatibilityVersion: project.compatibilityVersion, + preferredProjectObjectVersion: Int(project.objectVersion), + minimizedProjectReferenceProxies: project.minimizedProjectReferenceProxies, mainGroup: mainGroup, - developmentRegion: project.options.developmentLanguage ?? "en" + developmentRegion: developmentRegion ) ) @@ -125,8 +131,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 @@ -165,8 +171,14 @@ public class PBXProjGenerator { let packageReference = XCRemoteSwiftPackageReference(repositoryURL: url, versionRequirement: versionRequirement) packageReferences[name] = packageReference addObject(packageReference) - case let .local(path): - try sourceGenerator.createLocalPackage(path: Path(path)) + case let .local(path, group, excludeFromProject): + let packageReference = XCLocalSwiftPackageReference(relativePath: path) + localPackageReferences[name] = packageReference + + if !excludeFromProject { + addObject(packageReference) + try sourceGenerator.createLocalPackage(path: Path(path), group: group.map { Path($0) }) + } } } @@ -282,17 +294,32 @@ public class PBXProjGenerator { }.flatMap { $0 } ).sorted() - var projectAttributes: [String: Any] = ["LastUpgradeCheck": project.xcodeVersion] - .merged(project.attributes) - + let defaultAttributes: [String: Any] = [ + "BuildIndependentTargetsInParallel": "YES" + ] + var projectAttributes: [String: Any] = defaultAttributes.merged(project.attributes) + + // Set default LastUpgradeCheck if user did not specify + let lastUpgradeKey = "LastUpgradeCheck" + if !projectAttributes.contains(where: { (key, value) -> Bool in + key == lastUpgradeKey && value is String + }) { + projectAttributes[lastUpgradeKey] = project.xcodeVersion + } + if !assetTags.isEmpty { projectAttributes["knownAssetTags"] = assetTags } - let knownRegions = sourceGenerator.knownRegions.sorted() - pbxProject.knownRegions = knownRegions.isEmpty ? ["en"] : knownRegions + var knownRegions = Set(sourceGenerator.knownRegions) + knownRegions.insert(developmentRegion) + if project.options.useBaseInternationalization { + knownRegions.insert("Base") + } + pbxProject.knownRegions = knownRegions.sorted() - pbxProject.packages = packageReferences.sorted { $0.key < $1.key }.map { $1 } + pbxProject.remotePackages = packageReferences.sorted { $0.key < $1.key }.map { $1 } + pbxProject.localPackages = localPackageReferences.sorted { $0.key < $1.key }.map { $1 } let allTargets: [PBXTarget] = targetObjects.valueArray + targetAggregateObjects.valueArray pbxProject.targets = allTargets @@ -322,7 +349,7 @@ public class PBXProjGenerator { return addObject(buildConfig) } - let dependencies = target.targets.map { generateTargetDependency(from: target.name, to: $0) } + var dependencies = target.targets.map { generateTargetDependency(from: target.name, to: $0, platform: nil, platforms: nil) } let defaultConfigurationName = project.options.defaultConfig ?? project.configs.first?.name ?? "" let buildConfigList = addObject(XCConfigurationList( @@ -333,12 +360,15 @@ public class PBXProjGenerator { var buildPhases: [PBXBuildPhase] = [] buildPhases += try target.buildScripts.map { try generateBuildScript(targetName: target.name, buildScript: $0) } + let packagePluginDependencies = makePackagePluginDependency(for: target) + dependencies.append(contentsOf: packagePluginDependencies) + aggregateTarget.buildPhases = buildPhases aggregateTarget.buildConfigurationList = buildConfigList aggregateTarget.dependencies = dependencies } - func generateTargetDependency(from: String, to target: String) -> PBXTargetDependency { + func generateTargetDependency(from: String, to target: String, platform: String?, platforms: [String]?) -> PBXTargetDependency { guard let targetObject = targetObjects[target] ?? targetAggregateObjects[target] else { fatalError("Target dependency not found: from ( \(from) ) to ( \(target) )") } @@ -354,6 +384,8 @@ public class PBXProjGenerator { let targetDependency = addObject( PBXTargetDependency( + platformFilter: platform, + platformFilters: platforms, target: targetObject, targetProxy: targetProxy ) @@ -363,13 +395,13 @@ public class PBXProjGenerator { func generateExternalTargetDependency(from: String, to target: String, in project: String, platform: Platform) throws -> (PBXTargetDependency, Target, PBXReferenceProxy) { guard let projectReference = self.project.getProjectReference(project) else { - fatalError("project not found") + fatalError("project '\(project)' not found") } let pbxProj = try getPBXProj(from: projectReference) guard let targetObject = pbxProj.targets(named: target).first else { - fatalError("target not found") + fatalError("target '\(target)' not found in project '\(project)'") } let projectFileReferenceIndex = self.pbxProj.rootObject! @@ -392,13 +424,11 @@ public class PBXProjGenerator { ) ) - let productProxy = addObject( - PBXContainerItemProxy( - containerPortal: .fileReference(projectFileReference), - remoteGlobalID: .object(targetObject.product!), - proxyType: .reference, - remoteInfo: target - ) + let productProxy = PBXContainerItemProxy( + containerPortal: .fileReference(projectFileReference), + remoteGlobalID: targetObject.product.flatMap(PBXContainerItemProxy.RemoteGlobalID.object), + proxyType: .reference, + remoteInfo: target ) var path = targetObject.productNameWithExtension() @@ -408,16 +438,33 @@ public class PBXProjGenerator { path = "lib\(tmpPath)" } - let productReferenceProxy = addObject( - PBXReferenceProxy( - fileType: Xcode.fileType(path: Path(targetObject.productNameWithExtension()!)), - path: path, - remote: productProxy, - sourceTree: .buildProductsDir + let productReferenceProxyFileType = targetObject.productNameWithExtension() + .flatMap { Xcode.fileType(path: Path($0)) } + + let existingValue = self.pbxProj.referenceProxies.first { referenceProxy in + referenceProxy.path == path && + referenceProxy.remote == productProxy && + referenceProxy.sourceTree == .buildProductsDir && + referenceProxy.fileType == productReferenceProxyFileType + } + + let productReferenceProxy: PBXReferenceProxy + if let existingValue = existingValue { + productReferenceProxy = existingValue + } else { + addObject(productProxy) + productReferenceProxy = addObject( + PBXReferenceProxy( + fileType: productReferenceProxyFileType, + path: path, + remote: productProxy, + sourceTree: .buildProductsDir + ) ) - ) - productsGroup.children.append(productReferenceProxy) + productsGroup.children.append(productReferenceProxy) + } + let targetDependency = addObject( PBXTargetDependency( @@ -426,14 +473,14 @@ public class PBXProjGenerator { ) ) - guard let productType = targetObject.productType, - let buildConfigurations = targetObject.buildConfigurationList?.buildConfigurations, + guard let buildConfigurations = targetObject.buildConfigurationList?.buildConfigurations, let defaultConfigurationName = targetObject.buildConfigurationList?.defaultConfigurationName, let defaultConfiguration = buildConfigurations.first(where: { $0.name == defaultConfigurationName }) ?? buildConfigurations.first else { fatalError("Missing target info") } + let productType: PBXProductType = targetObject.productType ?? .none let buildSettings = defaultConfiguration.buildSettings let settings = Settings(buildSettings: buildSettings, configSettings: [:], groups: []) let deploymentTargetString = buildSettings[platform.deploymentTargetSetting] as? String @@ -471,12 +518,14 @@ public class PBXProjGenerator { shellPath: buildScript.shell ?? "/bin/sh", shellScript: shellScript, runOnlyForDeploymentPostprocessing: buildScript.runOnlyWhenInstalling, - showEnvVarsInLog: buildScript.showEnvVars + showEnvVarsInLog: buildScript.showEnvVars, + alwaysOutOfDate: !buildScript.basedOnDependencyAnalysis, + dependencyFile: buildScript.discoveredDependencyFile ) return addObject(shellScriptPhase) } - func generateCopyFiles(targetName: String, copyFiles: TargetSource.BuildPhase.CopyFilesSettings, buildPhaseFiles: [PBXBuildFile]) -> PBXCopyFilesBuildPhase { + func generateCopyFiles(targetName: String, copyFiles: BuildPhaseSpec.CopyFilesSettings, buildPhaseFiles: [PBXBuildFile]) -> PBXCopyFilesBuildPhase { let copyFilesBuildPhase = PBXCopyFilesBuildPhase( dstPath: copyFiles.subpath, dstSubfolderSpec: copyFiles.destination.destination, @@ -591,8 +640,8 @@ public class PBXProjGenerator { } if let order = groupOrdering?.order { - let files = group.children.filter { $0 is PBXFileReference } - var groups = group.children.filter { $0 is PBXGroup } + let files = group.children.filter { !$0.isGroupOrFolder } + var groups = group.children.filter { $0.isGroupOrFolder } var filteredGroups = [PBXFileElement]() @@ -634,25 +683,29 @@ public class PBXProjGenerator { func generateTarget(_ target: Target) throws { let carthageDependencies = carthageResolver.dependencies(for: target) - let sourceFiles = try sourceGenerator.getAllSourceFiles(targetType: target.type, sources: target.sources) + 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) .sorted { $0.path.lastComponent < $1.path.lastComponent } - var plistPath: Path? - var searchForPlist = true var anyDependencyRequiresObjCLinking = false var dependencies: [PBXTargetDependency] = [] var targetFrameworkBuildFiles: [PBXBuildFile] = [] var frameworkBuildPaths = Set() - var copyFilesBuildPhasesFiles: [TargetSource.BuildPhase.CopyFilesSettings: [PBXBuildFile]] = [:] + var customCopyDependenciesReferences: [PBXBuildFile] = [] + var copyFilesBuildPhasesFiles: [BuildPhaseSpec.CopyFilesSettings: [PBXBuildFile]] = [:] var copyFrameworksReferences: [PBXBuildFile] = [] var copyResourcesReferences: [PBXBuildFile] = [] var copyBundlesReferences: [PBXBuildFile] = [] var copyWatchReferences: [PBXBuildFile] = [] var packageDependencies: [XCSwiftPackageProductDependency] = [] var extensions: [PBXBuildFile] = [] + var extensionKitExtensions: [PBXBuildFile] = [] + var systemExtensions: [PBXBuildFile] = [] + var appClips: [PBXBuildFile] = [] var carthageFrameworksToEmbed: [String] = [] - let localPackageReferences: [String] = project.packages.compactMap { $0.value.isLocal ? $0.key : nil } let targetDependencies = (target.transitivelyLinkDependencies ?? project.options.transitivelyLinkDependencies) ? getAllDependenciesPlusTransitiveNeedingEmbedding(target: target) : target.dependencies @@ -669,7 +722,11 @@ public class PBXProjGenerator { if dependency.removeHeaders { embedAttributes.append("RemoveHeadersOnCopy") } - return ["ATTRIBUTES": embedAttributes] + var retval: [String:Any] = ["ATTRIBUTES": embedAttributes] + if let copyPhase = dependency.copyPhase { + retval["COPY_PHASE"] = copyPhase + } + return retval } func getDependencyFrameworkSettings(dependency: Dependency) -> [String: Any]? { @@ -680,16 +737,17 @@ public class PBXProjGenerator { return !linkingAttributes.isEmpty ? ["ATTRIBUTES": linkingAttributes] : nil } - func processTargetDependency(_ dependency: Dependency, dependencyTarget: Target, embedFileReference: PBXFileElement?) { - let dependencyLinkage = dependencyTarget.type.defaultLinkage + func processTargetDependency(_ dependency: Dependency, dependencyTarget: Target, embedFileReference: PBXFileElement?, platform: String?, platforms: [String]?) { + let dependencyLinkage = dependencyTarget.defaultLinkage let link = dependency.link ?? ((dependencyLinkage == .dynamic && target.type != .staticLibrary) || (dependencyLinkage == .static && target.type.isExecutable)) if link, let dependencyFile = embedFileReference { - let buildFile = addObject( - PBXBuildFile(file: dependencyFile, settings: getDependencyFrameworkSettings(dependency: dependency)) - ) + let pbxBuildFile = PBXBuildFile(file: dependencyFile, settings: getDependencyFrameworkSettings(dependency: dependency)) + pbxBuildFile.platformFilter = platform + pbxBuildFile.platformFilters = platforms + let buildFile = addObject(pbxBuildFile) targetFrameworkBuildFiles.append(buildFile) if !anyDependencyRequiresObjCLinking @@ -698,18 +756,33 @@ public class PBXProjGenerator { } } - let embed = dependency.embed ?? target.type.shouldEmbed(dependencyTarget.type) + let embed = dependency.embed ?? target.type.shouldEmbed(dependencyTarget) if embed { - let embedFile = addObject( - PBXBuildFile( - file: embedFileReference, - settings: getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? !dependencyTarget.type.isExecutable) - ) + let pbxBuildFile = PBXBuildFile( + file: embedFileReference, + settings: getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? !dependencyTarget.type.isExecutable) ) - - if dependencyTarget.type.isExtension { - // embed app extension - extensions.append(embedFile) + pbxBuildFile.platformFilter = platform + pbxBuildFile.platformFilters = platforms + let embedFile = addObject(pbxBuildFile) + + if dependency.copyPhase != nil { + // custom copy takes precedence + customCopyDependenciesReferences.append(embedFile) + } else if dependencyTarget.type.isExtension { + 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) + } else if dependencyTarget.type == .onDemandInstallCapableApplication { + // embed app clip + appClips.append(embedFile) } else if dependencyTarget.type.isFramework { copyFrameworksReferences.append(embedFile) } else if dependencyTarget.type.isApp && dependencyTarget.platform == .watchOS { @@ -725,7 +798,9 @@ public class PBXProjGenerator { for dependency in targetDependencies { let embed = dependency.embed ?? target.shouldEmbedDependencies - + let platform = makePlatformFilter(for: dependency.platformFilter) + let platforms = makeDestinationFilters(for: dependency.destinationFilters) + switch dependency.type { case .target: let dependencyTargetReference = try TargetReference(dependency.reference) @@ -733,15 +808,15 @@ public class PBXProjGenerator { switch dependencyTargetReference.location { case .local: let dependencyTargetName = dependency.reference - let targetDependency = generateTargetDependency(from: target.name, to: dependencyTargetName) + let targetDependency = generateTargetDependency(from: target.name, to: dependencyTargetName, platform: platform, platforms: platforms) dependencies.append(targetDependency) guard let dependencyTarget = project.getTarget(dependencyTargetName) else { continue } - processTargetDependency(dependency, dependencyTarget: dependencyTarget, embedFileReference: targetFileReferences[dependencyTarget.name]) + processTargetDependency(dependency, dependencyTarget: dependencyTarget, embedFileReference: targetFileReferences[dependencyTarget.name], platform: platform, platforms: platforms) case .project(let dependencyProjectName): let dependencyTargetName = dependencyTargetReference.name let (targetDependency, dependencyTarget, dependencyProductProxy) = try generateExternalTargetDependency(from: target.name, to: dependencyTargetName, in: dependencyProjectName, platform: target.platform) dependencies.append(targetDependency) - processTargetDependency(dependency, dependencyTarget: dependencyTarget, embedFileReference: dependencyProductProxy) + processTargetDependency(dependency, dependencyTarget: dependencyTarget, embedFileReference: dependencyProductProxy, platform: platform, platforms: platforms) } case .framework: @@ -765,9 +840,10 @@ public class PBXProjGenerator { } if dependency.link ?? (target.type != .staticLibrary) { - let buildFile = addObject( - PBXBuildFile(file: fileReference, settings: getDependencyFrameworkSettings(dependency: dependency)) - ) + let pbxBuildFile = PBXBuildFile(file: fileReference, settings: getDependencyFrameworkSettings(dependency: dependency)) + pbxBuildFile.platformFilter = platform + pbxBuildFile.platformFilters = platforms + let buildFile = addObject(pbxBuildFile) targetFrameworkBuildFiles.append(buildFile) } @@ -777,10 +853,16 @@ public class PBXProjGenerator { } if embed { - let embedFile = addObject( - PBXBuildFile(file: fileReference, settings: getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? true)) - ) - copyFrameworksReferences.append(embedFile) + let pbxBuildFile = PBXBuildFile(file: fileReference, settings: getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? true)) + pbxBuildFile.platformFilter = platform + pbxBuildFile.platformFilters = platforms + let embedFile = addObject(pbxBuildFile) + + if dependency.copyPhase != nil { + customCopyDependenciesReferences.append(embedFile) + } else { + copyFrameworksReferences.append(embedFile) + } } case .sdk(let root): @@ -819,14 +901,28 @@ public class PBXProjGenerator { frameworkFiles.append(fileReference) } - let buildFile = addObject( - PBXBuildFile( - file: fileReference, - settings: getDependencyFrameworkSettings(dependency: dependency) - ) + let pbxBuildFile = PBXBuildFile( + file: fileReference, + settings: getDependencyFrameworkSettings(dependency: dependency) ) + pbxBuildFile.platformFilter = platform + pbxBuildFile.platformFilters = platforms + let buildFile = addObject(pbxBuildFile) targetFrameworkBuildFiles.append(buildFile) + if dependency.embed == true { + let pbxBuildFile = PBXBuildFile(file: fileReference, settings: getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? true)) + pbxBuildFile.platformFilter = platform + pbxBuildFile.platformFilters = platforms + let embedFile = addObject(pbxBuildFile) + + if dependency.copyPhase != nil { + customCopyDependenciesReferences.append(embedFile) + } else { + copyFrameworksReferences.append(embedFile) + } + } + case .carthage(let findFrameworks, let linkType): let findFrameworks = findFrameworks ?? project.options.findCarthageFrameworks let allDependencies = findFrameworks @@ -845,47 +941,68 @@ public class PBXProjGenerator { let isStaticLibrary = target.type == .staticLibrary let isCarthageStaticLink = dependency.carthageLinkType == .static if dependency.link ?? (!isStaticLibrary && !isCarthageStaticLink) { - let buildFile = self.addObject( - PBXBuildFile(file: fileReference, settings: getDependencyFrameworkSettings(dependency: dependency)) - ) + let pbxBuildFile = PBXBuildFile(file: fileReference, settings: getDependencyFrameworkSettings(dependency: dependency)) + pbxBuildFile.platformFilter = platform + pbxBuildFile.platformFilters = platforms + let buildFile = addObject(pbxBuildFile) targetFrameworkBuildFiles.append(buildFile) } } // Embedding handled by iterating over `carthageDependencies` below - case .package(let product): + case .package(let products): let packageReference = packageReferences[dependency.reference] // If package's reference is none and there is no specified package in localPackages, // then ignore the package specified as dependency. - if packageReference == nil, !localPackageReferences.contains(dependency.reference) { + if packageReference == nil, localPackageReferences[dependency.reference] == nil { continue } - let productName = product ?? dependency.reference - let packageDependency = addObject( - XCSwiftPackageProductDependency(productName: productName, package: packageReference) - ) - packageDependencies.append(packageDependency) - - let link = dependency.link ?? (target.type != .staticLibrary) - if link { - let buildFile = addObject( - PBXBuildFile(product: packageDependency) - ) - targetFrameworkBuildFiles.append(buildFile) - } else { - let targetDependency = addObject( - PBXTargetDependency(product: packageDependency) + func addPackageProductDependency(named productName: String) { + let packageDependency = addObject( + XCSwiftPackageProductDependency(productName: productName, package: packageReference) ) - dependencies.append(targetDependency) + + // Add package dependency if linking is true. + if dependency.link ?? true { + packageDependencies.append(packageDependency) + } + + let link = dependency.link ?? (target.type != .staticLibrary) + if link { + let file = PBXBuildFile(product: packageDependency, settings: getDependencyFrameworkSettings(dependency: dependency)) + file.platformFilter = platform + file.platformFilters = platforms + let buildFile = addObject(file) + targetFrameworkBuildFiles.append(buildFile) + } else { + let targetDependency = addObject( + PBXTargetDependency(platformFilter: platform, platformFilters: platforms, product: packageDependency) + ) + dependencies.append(targetDependency) + } + + if dependency.embed == true { + let pbxBuildFile = PBXBuildFile(product: packageDependency, + settings: getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? true)) + pbxBuildFile.platformFilter = platform + pbxBuildFile.platformFilters = platforms + let embedFile = addObject(pbxBuildFile) + + if dependency.copyPhase != nil { + customCopyDependenciesReferences.append(embedFile) + } else { + copyFrameworksReferences.append(embedFile) + } + } } - if dependency.embed == true { - let embedFile = addObject( - PBXBuildFile(product: packageDependency, - settings: getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? true)) - ) - copyFrameworksReferences.append(embedFile) + if !products.isEmpty { + for product in products { + addPackageProductDependency(named: product) + } + } else { + addPackageProductDependency(named: dependency.reference) } case .bundle: // Static and dynamic libraries can't copy resources @@ -897,7 +1014,12 @@ public class PBXProjGenerator { sourceTree: .buildProductsDir ) - let pbxBuildFile = PBXBuildFile(file: fileReference, settings: nil) + let pbxBuildFile = PBXBuildFile( + file: fileReference, + settings: embed ? getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? true) : nil + ) + pbxBuildFile.platformFilter = platform + pbxBuildFile.platformFilters = platforms let buildFile = addObject(pbxBuildFile) copyBundlesReferences.append(buildFile) @@ -930,13 +1052,22 @@ public class PBXProjGenerator { let embedFile = addObject( PBXBuildFile(file: fileReference, settings: getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? true)) ) - copyFrameworksReferences.append(embedFile) + if dependency.copyPhase != nil { + customCopyDependenciesReferences.append(embedFile) + } else { + copyFrameworksReferences.append(embedFile) + } } else { carthageFrameworksToEmbed.append(dependency.reference) } } } + + carthageFrameworksToEmbed = carthageFrameworksToEmbed.uniqued() + let packagePluginDependencies = makePackagePluginDependency(for: target) + dependencies.append(contentsOf: packagePluginDependencies) + var buildPhases: [PBXBuildPhase] = [] func getBuildFilesForSourceFiles(_ sourceFiles: [SourceFile]) -> [PBXBuildFile] { @@ -955,8 +1086,8 @@ public class PBXProjGenerator { return getBuildFilesForSourceFiles(filteredSourceFiles) } - func getBuildFilesForCopyFilesPhases() -> [TargetSource.BuildPhase.CopyFilesSettings: [PBXBuildFile]] { - var sourceFilesByCopyFiles: [TargetSource.BuildPhase.CopyFilesSettings: [SourceFile]] = [:] + func getBuildFilesForCopyFilesPhases() -> [BuildPhaseSpec.CopyFilesSettings: [PBXBuildFile]] { + var sourceFilesByCopyFiles: [BuildPhaseSpec.CopyFilesSettings: [SourceFile]] = [:] for sourceFile in sourceFiles { guard case let .copyFiles(copyFilesSettings)? = sourceFile.buildPhase else { continue } sourceFilesByCopyFiles[copyFilesSettings, default: []].append(sourceFile) @@ -964,6 +1095,30 @@ public class PBXProjGenerator { return sourceFilesByCopyFiles.mapValues { getBuildFilesForSourceFiles($0) } } + func getPBXCopyFilesBuildPhase(dstSubfolderSpec: PBXCopyFilesBuildPhase.SubFolder, dstPath: String = "", name: String, files: [PBXBuildFile]) -> PBXCopyFilesBuildPhase { + return PBXCopyFilesBuildPhase( + dstPath: dstPath, + dstSubfolderSpec: dstSubfolderSpec, + name: name, + buildActionMask: target.onlyCopyFilesOnInstall ? PBXProjGenerator.copyFilesActionMask : PBXBuildPhase.defaultBuildActionMask, + files: files, + runOnlyForDeploymentPostprocessing: target.onlyCopyFilesOnInstall ? true : false + ) + } + + func splitCopyDepsByDestination(_ references: [PBXBuildFile]) -> [BuildPhaseSpec.CopyFilesSettings : [PBXBuildFile]] { + + var retval = [BuildPhaseSpec.CopyFilesSettings : [PBXBuildFile]]() + for reference in references { + + guard let key = reference.settings?["COPY_PHASE"] as? BuildPhaseSpec.CopyFilesSettings else { continue } + var filesWithSameDestination = retval[key] ?? [PBXBuildFile]() + filesWithSameDestination.append(reference) + retval[key] = filesWithSameDestination + } + return retval + } + copyFilesBuildPhasesFiles.merge(getBuildFilesForCopyFilesPhases()) { $0 + $1 } buildPhases += try target.preBuildScripts.map { try generateBuildScript(targetName: target.name, buildScript: $0) } @@ -982,6 +1137,18 @@ public class PBXProjGenerator { } } + func addResourcesBuildPhase() { + let resourcesBuildPhaseFiles = getBuildFilesForPhase(.resources) + copyResourcesReferences + if !resourcesBuildPhaseFiles.isEmpty { + let resourcesBuildPhase = addObject(PBXResourcesBuildPhase(files: resourcesBuildPhaseFiles)) + buildPhases.append(resourcesBuildPhase) + } + } + + if target.putResourcesBeforeSourcesBuildPhase { + addResourcesBuildPhase() + } + let sourcesBuildPhaseFiles = getBuildFilesForPhase(.sources) let shouldSkipSourcesBuildPhase = sourcesBuildPhaseFiles.isEmpty && target.type.canSkipCompileSourcesBuildPhase if !shouldSkipSourcesBuildPhase { @@ -991,10 +1158,8 @@ public class PBXProjGenerator { buildPhases += try target.postCompileScripts.map { try generateBuildScript(targetName: target.name, buildScript: $0) } - let resourcesBuildPhaseFiles = getBuildFilesForPhase(.resources) + copyResourcesReferences - if !resourcesBuildPhaseFiles.isEmpty { - let resourcesBuildPhase = addObject(PBXResourcesBuildPhase(files: resourcesBuildPhaseFiles)) - buildPhases.append(resourcesBuildPhase) + if !target.putResourcesBeforeSourcesBuildPhase { + addResourcesBuildPhase() } let swiftObjCInterfaceHeader = project.getCombinedBuildSetting("SWIFT_OBJC_INTERFACE_HEADER_NAME", target: target, config: project.configs[0]) as? String @@ -1035,7 +1200,7 @@ public class PBXProjGenerator { name: "Carthage", inputPaths: inputPaths, outputPaths: outputPaths, - shellPath: "/bin/sh", + shellPath: "/bin/sh -l", shellScript: "\(carthageExecutable) copy-frameworks\n" ) ) @@ -1061,12 +1226,39 @@ public class PBXProjGenerator { if !extensions.isEmpty { + let copyFilesPhase = addObject( + getPBXCopyFilesBuildPhase(dstSubfolderSpec: .plugins, name: "Embed Foundation 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( + // With parameters below the Xcode will show "Destination: System Extensions". + getPBXCopyFilesBuildPhase(dstSubfolderSpec: .productsDirectory, dstPath: "$(SYSTEM_EXTENSIONS_FOLDER_PATH)", name: "Embed System Extensions", files: systemExtensions) + ) + + buildPhases.append(copyFilesPhase) + } + + if !appClips.isEmpty { + let copyFilesPhase = addObject( PBXCopyFilesBuildPhase( - dstPath: "", - dstSubfolderSpec: .plugins, - name: "Embed App Extensions", - files: extensions + dstPath: "$(CONTENTS_FOLDER_PATH)/AppClips", + dstSubfolderSpec: .productsDirectory, + name: "Embed App Clips", + files: appClips ) ) @@ -1076,21 +1268,28 @@ public class PBXProjGenerator { copyFrameworksReferences += getBuildFilesForPhase(.frameworks) if !copyFrameworksReferences.isEmpty { - let copyFilesActionMask: UInt = 8 let copyFilesPhase = addObject( - PBXCopyFilesBuildPhase( - dstPath: "", - dstSubfolderSpec: .frameworks, - name: "Embed Frameworks", - buildActionMask: target.onlyCopyFilesOnInstall ? copyFilesActionMask : PBXBuildPhase.defaultBuildActionMask, - files: copyFrameworksReferences, - runOnlyForDeploymentPostprocessing: target.onlyCopyFilesOnInstall ? true : false - ) + getPBXCopyFilesBuildPhase(dstSubfolderSpec: .frameworks, name: "Embed Frameworks", files: copyFrameworksReferences) ) buildPhases.append(copyFilesPhase) } + if !customCopyDependenciesReferences.isEmpty { + + let splitted = splitCopyDepsByDestination(customCopyDependenciesReferences) + for (phase, references) in splitted { + + guard let destination = phase.destination.destination else { continue } + + let copyFilesPhase = addObject( + getPBXCopyFilesBuildPhase(dstSubfolderSpec: destination, dstPath:phase.subpath, name: "Embed Dependencies", files: references) + ) + + buildPhases.append(copyFilesPhase) + } + } + if !copyWatchReferences.isEmpty { let copyFilesPhase = addObject( @@ -1115,7 +1314,8 @@ public class PBXProjGenerator { name: buildRule.name ?? "Build Rule", outputFiles: buildRule.outputFiles, outputFilesCompilerFlags: buildRule.outputFilesCompilerFlags, - script: buildRule.action.script + script: buildRule.action.script, + runOncePerArchitecture: buildRule.runOncePerArchitecture ) ) } @@ -1130,17 +1330,9 @@ public class PBXProjGenerator { buildSettings["CODE_SIGN_ENTITLEMENTS"] = entitlements.path } - // Set INFOPLIST_FILE if not defined in settings - if !project.targetHasBuildSetting("INFOPLIST_FILE", target: target, config: config) { - if let info = target.info { - buildSettings["INFOPLIST_FILE"] = info.path - } else if searchForPlist { - plistPath = getInfoPlist(target.sources) - searchForPlist = false - } - if let plistPath = plistPath { - buildSettings["INFOPLIST_FILE"] = (try? plistPath.relativePath(from: projectDirectory ?? project.basePath)) ?? plistPath - } + // Set INFOPLIST_FILE based on the resolved value + if let infoPlistFile = infoPlistFiles[config] { + buildSettings["INFOPLIST_FILE"] = infoPlistFile } // automatically calculate bundle id @@ -1262,6 +1454,86 @@ public class PBXProjGenerator { if !target.isLegacy { targetObject.productType = target.type } + + // add fileSystemSynchronizedGroups + let synchronizedRootGroups = sourceFiles.compactMap { $0.fileReference as? PBXFileSystemSynchronizedRootGroup } + if !synchronizedRootGroups.isEmpty { + targetObject.fileSystemSynchronizedGroups = synchronizedRootGroups + } + } + + private func makePlatformFilter(for filter: Dependency.PlatformFilter) -> String? { + switch filter { + case .all: + return nil + case .macOS: + return "maccatalyst" + case .iOS: + return "ios" + } + } + + private func makeDestinationFilters(for filters: [SupportedDestination]?) -> [String]? { + guard let filters = filters, !filters.isEmpty else { return nil } + return filters.map { $0.string } + } + + /// Make `Build Tools Plug-ins` as a dependency to the target + /// - Parameter target: ProjectTarget + /// - Returns: Elements for referencing other targets through content proxies. + func makePackagePluginDependency(for target: ProjectTarget) -> [PBXTargetDependency] { + target.buildToolPlugins.compactMap { buildToolPlugin in + let packageReference = packageReferences[buildToolPlugin.package] + if packageReference == nil, localPackageReferences[buildToolPlugin.package] == nil { + return nil + } + + let packageDependency = addObject( + XCSwiftPackageProductDependency(productName: buildToolPlugin.plugin, package: packageReference, isPlugin: true) + ) + let targetDependency = addObject( + PBXTargetDependency(product: packageDependency) + ) + + return targetDependency + } + } + + func getInfoPlists(for target: Target) -> [Config: String] { + var searchForDefaultInfoPlist: Bool = true + var defaultInfoPlist: String? + + let values: [(Config, String)] = project.configs.compactMap { config in + // First, if the plist path was defined by `INFOPLIST_FILE`, use that + let buildSettings = project.getTargetBuildSettings(target: target, config: config) + if let value = buildSettings["INFOPLIST_FILE"] as? String { + return (config, value) + } + + // Otherwise check if the path was defined as part of the `info` spec + if let value = target.info?.path { + return (config, value) + } + + // If we haven't yet looked for the default info plist, try doing so + if searchForDefaultInfoPlist { + searchForDefaultInfoPlist = false + + if let plistPath = getInfoPlist(target.sources) { + let basePath = projectDirectory ?? project.basePath.absolute() + let relative = (try? plistPath.relativePath(from: basePath)) ?? plistPath + defaultInfoPlist = relative.string + } + } + + // Return the default plist if there was one + if let value = defaultInfoPlist { + return (config, value) + } + return nil + } + + return Dictionary(uniqueKeysWithValues: values) } func getInfoPlist(_ sources: [TargetSource]) -> Path? { @@ -1272,7 +1544,7 @@ public class PBXProjGenerator { if path.isFile { return path.lastComponent == "Info.plist" ? path : nil } else { - return path.first(where: { $0.lastComponent == "Info.plist" }) + return path.first(where: { $0.lastComponent == "Info.plist" })?.absolute() } } .first @@ -1360,7 +1632,7 @@ extension Platform { /// - returns: `true` for platforms that the app store requires simulator slices to be stripped. public var requiresSimulatorStripping: Bool { switch self { - case .iOS, .tvOS, .watchOS: + case .auto, .iOS, .tvOS, .watchOS, .visionOS: return true case .macOS: return false @@ -1369,6 +1641,10 @@ extension Platform { } extension PBXFileElement { + /// - returns: `true` if the element is a group or a folder reference. Likely an SPM package. + var isGroupOrFolder: Bool { + self is PBXGroup || (self as? PBXFileReference)?.lastKnownFileType == "folder" + } public func getSortOrder(groupSortPosition: SpecOptions.GroupSortPosition) -> Int { if type(of: self).isa == "PBXGroup" { diff --git a/Sources/XcodeGenKit/ProjectGenerator.swift b/Sources/XcodeGenKit/ProjectGenerator.swift index 8fb149c6f..35a4d1bd1 100644 --- a/Sources/XcodeGenKit/ProjectGenerator.swift +++ b/Sources/XcodeGenKit/ProjectGenerator.swift @@ -13,26 +13,43 @@ public class ProjectGenerator { self.project = project } - public func generateXcodeProject(in projectDirectory: Path? = nil) throws -> XcodeProj { + public func generateXcodeProject(in projectDirectory: Path? = nil, userName: String) throws -> XcodeProj { // generate PBXProj let pbxProjGenerator = PBXProjGenerator(project: project, projectDirectory: projectDirectory) let pbxProj = try pbxProjGenerator.generate() - // generate Schemes - let schemeGenerator = SchemeGenerator(project: project, pbxProj: pbxProj) - let schemes = try schemeGenerator.generateSchemes() - // generate Workspace let workspace = try generateWorkspace() - let sharedData = XCSharedData(schemes: schemes) - return XcodeProj(workspace: workspace, pbxproj: pbxProj, sharedData: sharedData) + // generate Schemes + let schemeGenerator = SchemeGenerator(project: project, pbxProj: pbxProj) + let (sharedSchemes, userSchemes, schemeManagement) = try schemeGenerator.generateSchemes() + + // generate Breakpoints + let breakpointGenerator = BreakpointGenerator(project: project) + let xcbreakpointlist = try breakpointGenerator.generateBreakpointList() + + // generate shared data + let sharedData = XCSharedData(schemes: sharedSchemes, breakpoints: xcbreakpointlist) + + // generate user data + let userData = userSchemes.isEmpty && schemeManagement == nil ? [] : [ + XCUserData(userName: userName, schemes: userSchemes, schemeManagement: schemeManagement) + ] + + return XcodeProj( + workspace: workspace, + pbxproj: pbxProj, + sharedData: sharedData, + userData: userData + ) } func generateWorkspace() throws -> XCWorkspace { - let dataElement: XCWorkspaceDataElement = .file(XCWorkspaceDataFileRef(location: .self(project.defaultProjectPath.lastComponent))) + 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 3eacef4aa..c29faac4b 100644 --- a/Sources/XcodeGenKit/SchemeGenerator.swift +++ b/Sources/XcodeGenKit/SchemeGenerator.swift @@ -40,15 +40,18 @@ public class SchemeGenerator { return pbxproj } - public func generateSchemes() throws -> [XCScheme] { - var xcschemes: [XCScheme] = [] + public func generateSchemes() throws -> ( + shared: [XCScheme], + user: [XCScheme], + management: XCSchemeManagement? + ) { + var schemes: [(Scheme, ProjectTarget?)] = [] for scheme in project.schemes { - let xcscheme = try generateScheme(scheme) - xcschemes.append(xcscheme) + schemes.append((scheme, nil)) } - for target in project.targets { + for target in project.projectTargets { if let targetScheme = target.scheme { if targetScheme.configVariants.isEmpty { let schemeName = target.name @@ -64,17 +67,17 @@ public class SchemeGenerator { debugConfig: debugConfig.name, releaseConfig: releaseConfig.name ) - let xcscheme = try generateScheme(scheme, for: target) - xcschemes.append(xcscheme) + schemes.append((scheme, target)) } else { for configVariant in targetScheme.configVariants { let schemeName = "\(target.name) \(configVariant)" let debugConfig = project.configs - .first { $0.type == .debug && $0.name.contains(configVariant) }! + .first(including: configVariant, for: .debug)! + let releaseConfig = project.configs - .first { $0.type == .release && $0.name.contains(configVariant) }! + .first(including: configVariant, for: .release)! let scheme = Scheme( name: schemeName, @@ -84,17 +87,47 @@ public class SchemeGenerator { debugConfig: debugConfig.name, releaseConfig: releaseConfig.name ) - let xcscheme = try generateScheme(scheme, for: target) - xcschemes.append(xcscheme) + schemes.append((scheme, target)) } } } } - return xcschemes + var sharedSchemes: [XCScheme] = [] + var userSchemes: [XCScheme] = [] + var schemeManagements: [XCSchemeManagement.UserStateScheme] = [] + + for (scheme, projectTarget) in schemes { + let xcscheme = try generateScheme(scheme, for: projectTarget) + + if scheme.management?.shared == false { + userSchemes.append(xcscheme) + } else { + sharedSchemes.append(xcscheme) + } + + if let management = scheme.management { + schemeManagements.append( + XCSchemeManagement.UserStateScheme( + name: scheme.name + ".xcscheme", + shared: management.shared, + orderHint: management.orderHint, + isShown: management.isShown + ) + ) + } + } + + return ( + shared: sharedSchemes, + user: userSchemes, + management: schemeManagements.isEmpty + ? nil + : XCSchemeManagement(schemeUserState: schemeManagements, suppressBuildableAutocreation: nil) + ) } - 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 @@ -135,9 +168,27 @@ public class SchemeGenerator { blueprintName: target.name ) } + + func getBuildableTestableReference(_ target: TestableTargetReference) throws -> XCScheme.BuildableReference { + switch target.location { + case .package(let packageName): + guard let package = self.project.getPackage(packageName), + case let .local(path, _, _) = package else { + throw SchemeGenerationError.missingPackage(packageName) + } + return XCScheme.BuildableReference( + referencedContainer: "container:\(path)", + blueprintIdentifier: target.name, + buildableName: target.name, + blueprintName: target.name + ) + default: + return try getBuildableReference(target.targetReference) + } + } func getBuildEntry(_ buildTarget: Scheme.BuildTarget) throws -> XCScheme.BuildAction.Entry { - let buildableReference = try getBuildableReference(buildTarget.target) + let buildableReference = try getBuildableTestableReference(buildTarget.target) return XCScheme.BuildAction.Entry(buildableReference: buildableReference, buildFor: buildTarget.buildTypes) } @@ -157,15 +208,24 @@ public class SchemeGenerator { .first { settingsTarget == $0.buildableReference.blueprintName }? .buildableReference } - return XCScheme.ExecutionAction(scriptText: action.script, title: action.name, environmentBuildable: environmentBuildable) + return XCScheme.ExecutionAction( + scriptText: action.script, + title: action.name, + shellToInvoke: action.shell, + environmentBuildable: environmentBuildable + ) } - let schemeTarget: Target? + let schemeTarget: ProjectTarget? if let targetName = scheme.run?.executable { schemeTarget = project.getTarget(targetName) } else { - schemeTarget = target ?? project.getTarget(scheme.build.targets.first!.target.name) + guard let firstTarget = scheme.build.targets.first else { + throw SchemeGenerationError.missingBuildTargets(scheme.name) + } + let name = scheme.build.targets.first { $0.buildTypes.contains(.running) }?.target.name ?? firstTarget.target.name + schemeTarget = target ?? project.getTarget(name) } let shouldExecuteOnLaunch = schemeTarget?.shouldExecuteOnLaunch == true @@ -178,21 +238,40 @@ public class SchemeGenerator { preActions: scheme.build.preActions.map(getExecutionAction), postActions: scheme.build.postActions.map(getExecutionAction), parallelizeBuild: scheme.build.parallelizeBuild, - buildImplicitDependencies: scheme.build.buildImplicitDependencies + buildImplicitDependencies: scheme.build.buildImplicitDependencies, + runPostActionsOnFailure: scheme.build.runPostActionsOnFailure ) - let testables = zip(testTargets, testBuildTargetEntries).map { testTarget, testBuilEntries in - XCScheme.TestableReference( - skipped: false, - parallelizable: testTarget.parallelizable, + let testables: [XCScheme.TestableReference] = zip(testTargets, testBuildTargetEntries).map { testTarget, testBuildEntries in + + var locationScenarioReference: XCScheme.LocationScenarioReference? + if var location = testTarget.location { + + if location.contains(".gpx") { + var path = Path(components: [project.options.schemePathPrefix, location]) + path = path.simplifyingParentDirectoryReferences() + location = path.string + } + + let referenceType = location.contains(".gpx") ? "0" : "1" + locationScenarioReference = XCScheme.LocationScenarioReference(identifier: location, referenceType: referenceType) + + } + + return XCScheme.TestableReference( + skipped: testTarget.skipped, + parallelization: testTarget.parallelizable ? .all : .none, randomExecutionOrdering: testTarget.randomExecutionOrder, - buildableReference: testBuilEntries.buildableReference, - skippedTests: testTarget.skippedTests.map(XCScheme.SkippedTest.init) + buildableReference: testBuildEntries.buildableReference, + locationScenarioReference: locationScenarioReference, + skippedTests: testTarget.skippedTests.map(XCScheme.TestItem.init), + selectedTests: testTarget.selectedTests.map(XCScheme.TestItem.init), + useTestSelectionWhitelist: !testTarget.selectedTests.isEmpty ? true : nil ) } let coverageBuildableTargets = try scheme.test?.coverageTargets.map { - try getBuildableReference($0) + try getBuildableTestableReference($0) } ?? [] let testCommandLineArgs = scheme.test.map { XCScheme.CommandLineArguments($0.commandLineArguments) } @@ -203,10 +282,27 @@ public class SchemeGenerator { let launchVariables = scheme.run.flatMap { $0.environmentVariables.isEmpty ? nil : $0.environmentVariables } let profileVariables = scheme.profile.flatMap { $0.environmentVariables.isEmpty ? nil : $0.environmentVariables } + let defaultTestPlanIndex = scheme.test?.testPlans.firstIndex { $0.defaultPlan } ?? 0 + let testPlans = scheme.test?.testPlans.enumerated().map { index, testPlan in + XCScheme.TestPlanReference(reference: "container:\(testPlan.path)", default: defaultTestPlanIndex == index) + } ?? [] + let testBuildableEntries = buildActionEntries.filter({ $0.buildFor.contains(.testing) }) + testBuildTargetEntries + let testMacroExpansionBuildableRef = testBuildableEntries.map(\.buildableReference).contains(buildableReference) ? buildableReference : testBuildableEntries.first?.buildableReference + + let testMacroExpansion: XCScheme.BuildableReference = buildActionEntries.first( + where: { value in + if let macroExpansion = scheme.test?.macroExpansion { + return value.buildableReference.blueprintName == macroExpansion + } + return false + } + )?.buildableReference ?? testMacroExpansionBuildableRef ?? buildableReference + let testAction = XCScheme.TestAction( buildConfiguration: scheme.test?.config ?? defaultDebugConfig.name, - macroExpansion: buildableReference, + macroExpansion: testMacroExpansion, testables: testables, + testPlans: testPlans.isEmpty ? nil : testPlans, preActions: scheme.test?.preActions.map(getExecutionAction) ?? [], postActions: scheme.test?.postActions.map(getExecutionAction) ?? [], selectedDebuggerIdentifier: (scheme.test?.debugEnabled ?? Scheme.Test.debugEnabledDefault) ? XCScheme.defaultDebugger : "", @@ -215,50 +311,84 @@ public class SchemeGenerator { codeCoverageEnabled: scheme.test?.gatherCoverageData ?? Scheme.Test.gatherCoverageDataDefault, codeCoverageTargets: coverageBuildableTargets, onlyGenerateCoverageForSpecifiedTargets: !coverageBuildableTargets.isEmpty, + enableAddressSanitizer: scheme.test?.enableAddressSanitizer ?? Scheme.Test.enableAddressSanitizerDefault, + enableASanStackUseAfterReturn: scheme.test?.enableASanStackUseAfterReturn ?? Scheme.Test.enableASanStackUseAfterReturnDefault, + enableThreadSanitizer: scheme.test?.enableThreadSanitizer ?? Scheme.Test.enableThreadSanitizerDefault, + enableUBSanitizer: scheme.test?.enableUBSanitizer ?? Scheme.Test.enableUBSanitizerDefault, disableMainThreadChecker: scheme.test?.disableMainThreadChecker ?? Scheme.Test.disableMainThreadCheckerDefault, commandlineArguments: testCommandLineArgs, environmentVariables: testVariables, language: scheme.test?.language, - region: scheme.test?.region + region: scheme.test?.region, + systemAttachmentLifetime: scheme.test?.systemAttachmentLifetime, + preferredScreenCaptureFormat: scheme.test?.preferredScreenCaptureFormat, + customLLDBInitFile: scheme.test?.customLLDBInit ) let allowLocationSimulation = scheme.run?.simulateLocation?.allow ?? true var locationScenarioReference: XCScheme.LocationScenarioReference? if let simulateLocation = scheme.run?.simulateLocation, var identifier = simulateLocation.defaultLocation, let referenceType = simulateLocation.referenceType { if referenceType == .gpx { - var path = Path("../\(identifier)") + var path = Path(components: [project.options.schemePathPrefix, identifier]) path = path.simplifyingParentDirectoryReferences() identifier = path.string } locationScenarioReference = XCScheme.LocationScenarioReference(identifier: identifier, referenceType: referenceType.rawValue) } + var storeKitConfigurationFileReference: XCScheme.StoreKitConfigurationFileReference? + if let storeKitConfiguration = scheme.run?.storeKitConfiguration { + let storeKitConfigurationPath = Path(components: [project.options.schemePathPrefix, storeKitConfiguration]).simplifyingParentDirectoryReferences() + storeKitConfigurationFileReference = XCScheme.StoreKitConfigurationFileReference(identifier: storeKitConfigurationPath.string) + } + + let macroExpansion: XCScheme.BuildableReference? + if let macroExpansionName = scheme.run?.macroExpansion, + let resolvedMacroExpansion = buildActionEntries.first(where: { $0.buildableReference.blueprintName == macroExpansionName })?.buildableReference { + macroExpansion = resolvedMacroExpansion + } else { + macroExpansion = shouldExecuteOnLaunch ? nil : buildableReference + } + let launchAction = XCScheme.LaunchAction( runnable: shouldExecuteOnLaunch ? runnables.launch : nil, buildConfiguration: scheme.run?.config ?? defaultDebugConfig.name, preActions: scheme.run?.preActions.map(getExecutionAction) ?? [], postActions: scheme.run?.postActions.map(getExecutionAction) ?? [], - macroExpansion: shouldExecuteOnLaunch ? nil : buildableReference, - selectedDebuggerIdentifier: (scheme.run?.debugEnabled ?? Scheme.Run.debugEnabledDefault) ? XCScheme.defaultDebugger : "", - selectedLauncherIdentifier: (scheme.run?.debugEnabled ?? Scheme.Run.debugEnabledDefault) ? XCScheme.defaultLauncher : "Xcode.IDEFoundation.Launcher.PosixSpawn", + macroExpansion: macroExpansion, + selectedDebuggerIdentifier: selectedDebuggerIdentifier(for: schemeTarget, run: scheme.run), + selectedLauncherIdentifier: selectedLauncherIdentifier(for: schemeTarget, run: scheme.run), askForAppToLaunch: scheme.run?.askForAppToLaunch, + customWorkingDirectory: scheme.run?.customWorkingDirectory, + useCustomWorkingDirectory: scheme.run?.customWorkingDirectory != nil, allowLocationSimulation: allowLocationSimulation, locationScenarioReference: locationScenarioReference, + enableGPUFrameCaptureMode: scheme.run?.enableGPUFrameCaptureMode ?? XCScheme.LaunchAction.defaultGPUFrameCaptureMode, + disableGPUValidationMode: !(scheme.run?.enableGPUValidationMode ?? Scheme.Run.enableGPUValidationModeDefault), + enableAddressSanitizer: scheme.run?.enableAddressSanitizer ?? Scheme.Run.enableAddressSanitizerDefault, + enableASanStackUseAfterReturn: scheme.run?.enableASanStackUseAfterReturn ?? Scheme.Run.enableASanStackUseAfterReturnDefault, + enableThreadSanitizer: scheme.run?.enableThreadSanitizer ?? Scheme.Run.enableThreadSanitizerDefault, + enableUBSanitizer: scheme.run?.enableUBSanitizer ?? Scheme.Run.enableUBSanitizerDefault, disableMainThreadChecker: scheme.run?.disableMainThreadChecker ?? Scheme.Run.disableMainThreadCheckerDefault, + disablePerformanceAntipatternChecker: scheme.run?.disableThreadPerformanceChecker ?? Scheme.Run.disableThreadPerformanceCheckerDefault, stopOnEveryMainThreadCheckerIssue: scheme.run?.stopOnEveryMainThreadCheckerIssue ?? Scheme.Run.stopOnEveryMainThreadCheckerIssueDefault, commandlineArguments: launchCommandLineArgs, environmentVariables: launchVariables, language: scheme.run?.language, region: scheme.run?.region, - launchAutomaticallySubstyle: scheme.run?.launchAutomaticallySubstyle + launchAutomaticallySubstyle: scheme.run?.launchAutomaticallySubstyle ?? launchAutomaticallySubstyle(for: schemeTarget), + storeKitConfigurationFileReference: storeKitConfigurationFileReference, + customLLDBInitFile: scheme.run?.customLLDBInit ) 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, environmentVariables: profileVariables ) @@ -273,9 +403,11 @@ public class SchemeGenerator { postActions: scheme.archive?.postActions.map(getExecutionAction) ?? [] ) + let lastUpgradeVersion = project.attributes["LastUpgradeCheck"] as? String ?? project.xcodeVersion + return XCScheme( name: scheme.name, - lastUpgradeVersion: project.xcodeVersion, + lastUpgradeVersion: lastUpgradeVersion, version: project.schemeVersion, buildAction: buildAction, testAction: testAction, @@ -287,8 +419,16 @@ public class SchemeGenerator { .flatMap { $0.type.isExtension ? true : nil } ) } + + private func launchAutomaticallySubstyle(for target: ProjectTarget?) -> String? { + if target?.type.isExtension == true { + return "2" + } else { + return nil + } + } - 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( @@ -301,12 +441,30 @@ public class SchemeGenerator { return (buildable, buildable) } } + + private func selectedDebuggerIdentifier(for target: ProjectTarget?, run: Scheme.Run?) -> String { + if target?.type.canUseDebugLauncher != false && run?.debugEnabled ?? Scheme.Run.debugEnabledDefault { + return XCScheme.defaultDebugger + } else { + return "" + } + } + + private func selectedLauncherIdentifier(for target: ProjectTarget?, run: Scheme.Run?) -> String { + if target?.type.canUseDebugLauncher != false && run?.debugEnabled ?? Scheme.Run.debugEnabledDefault { + return XCScheme.defaultLauncher + } else { + return "Xcode.IDEFoundation.Launcher.PosixSpawn" + } + } } enum SchemeGenerationError: Error, CustomStringConvertible { case missingTarget(TargetReference, projectPath: String) + case missingPackage(String) case missingProject(String) + case missingBuildTargets(String) var description: String { switch self { @@ -314,12 +472,16 @@ enum SchemeGenerationError: Error, CustomStringConvertible { return "Unable to find target named \"\(target)\" in \"\(projectPath)\"" case .missingProject(let project): return "Unable to find project reference named \"\(project)\" in project.yml" + case .missingBuildTargets(let name): + return "Unable to find at least one build target in scheme \"\(name)\"" + case .missingPackage(let package): + return "Unable to find swift package named \"\(package)\" in project.yml" } } } 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( @@ -334,16 +496,20 @@ extension Scheme { environmentVariables: targetScheme.environmentVariables, disableMainThreadChecker: targetScheme.disableMainThreadChecker, stopOnEveryMainThreadCheckerIssue: targetScheme.stopOnEveryMainThreadCheckerIssue, + disableThreadPerformanceChecker: targetScheme.disableThreadPerformanceChecker, language: targetScheme.language, - region: targetScheme.region + region: targetScheme.region, + storeKitConfiguration: targetScheme.storeKitConfiguration ), test: .init( config: debugConfig, gatherCoverageData: targetScheme.gatherCoverageData, + coverageTargets: targetScheme.coverageTargets, disableMainThreadChecker: targetScheme.disableMainThreadChecker, commandLineArguments: targetScheme.commandLineArguments, targets: targetScheme.testTargets, environmentVariables: targetScheme.environmentVariables, + testPlans: targetScheme.testPlans, language: targetScheme.language, region: targetScheme.region ), @@ -357,19 +523,20 @@ extension Scheme { ), archive: .init( config: releaseConfig - ) + ), + management: targetScheme.management ) } - private static func buildTargets(for target: Target, project: Project) -> [BuildTarget] { - let buildTarget = Scheme.BuildTarget(target: TargetReference.local(target.name)) + 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: let hostTarget = project.targets .first { projectTarget in projectTarget.dependencies.contains { $0.reference == target.name } } - .map { BuildTarget(target: TargetReference.local($0.name)) } + .map { BuildTarget(target: TestableTargetReference.local($0.name)) } return hostTarget.map { [buildTarget, $0] } ?? [buildTarget] default: return [buildTarget] @@ -378,6 +545,11 @@ extension Scheme { } extension PBXProductType { + var canUseDebugLauncher: Bool { + // Extensions don't use the lldb launcher + return !isExtension + } + var isWatchApp: Bool { switch self { case .watchApp, .watch2App: @@ -387,3 +559,16 @@ extension PBXProductType { } } } + +extension Scheme.Test { + var systemAttachmentLifetime: XCScheme.TestAction.AttachmentLifetime? { + switch (captureScreenshotsAutomatically, deleteScreenshotsWhenEachTestSucceeds) { + case (false, _): + return .keepNever + case (true, false): + return .keepAlways + case (true, true): + return nil + } + } +} diff --git a/Sources/XcodeGenKit/SettingPresets b/Sources/XcodeGenKit/SettingPresets new file mode 120000 index 000000000..1137a5ea8 --- /dev/null +++ b/Sources/XcodeGenKit/SettingPresets @@ -0,0 +1 @@ +../../SettingPresets/ \ No newline at end of file diff --git a/Sources/XcodeGenKit/SettingsBuilder.swift b/Sources/XcodeGenKit/SettingsBuilder.swift index 4ac1853c3..b65079b9d 100644 --- a/Sources/XcodeGenKit/SettingsBuilder.swift +++ b/Sources/XcodeGenKit/SettingsBuilder.swift @@ -11,12 +11,10 @@ extension Project { var buildSettings: BuildSettings = [:] // set project SDKROOT is a single platform - if targets.count > 0 { - let platforms = Dictionary(grouping: targets) { $0.platform } - if platforms.count == 1 { - let platform = platforms.first!.key - buildSettings["SDKROOT"] = platform.sdkRoot - } + if let firstPlatform = targets.first?.platform, + targets.allSatisfy({ $0.platform == firstPlatform }) + { + buildSettings["SDKROOT"] = firstPlatform.sdkRoot } if let type = config.type, options.settingPresets.applyProject { @@ -31,7 +29,7 @@ extension Project { } } - // Prevent setting presets from overrwriting settings in project xcconfig files + // Prevent setting presets from overwriting settings in project xcconfig files if let configPath = configFiles[config.name] { buildSettings = removeConfigFileSettings(from: buildSettings, configPath: configPath) } @@ -43,16 +41,63 @@ extension Project { public func getTargetBuildSettings(target: Target, config: Config) -> BuildSettings { var buildSettings = BuildSettings() - + + // list of supported destination sorted by priority + let specSupportedDestinations = target.supportedDestinations?.sorted(by: { $0.priority < $1.priority }) ?? [] + if options.settingPresets.applyTarget { - buildSettings += SettingsPresetFile.platform(target.platform).getBuildSettings() + let platform: Platform + + if target.platform == .auto, + let firstDestination = specSupportedDestinations.first, + let firstDestinationPlatform = Platform(rawValue: firstDestination.rawValue) { + + platform = firstDestinationPlatform + } else { + platform = target.platform + } + + buildSettings += SettingsPresetFile.platform(platform).getBuildSettings() buildSettings += SettingsPresetFile.product(target.type).getBuildSettings() - buildSettings += SettingsPresetFile.productPlatform(target.type, target.platform).getBuildSettings() + buildSettings += SettingsPresetFile.productPlatform(target.type, platform).getBuildSettings() + + if target.platform == .auto { + // this fix is necessary because the platform preset overrides the original value + buildSettings["SDKROOT"] = Platform.auto.rawValue + } } - + + if !specSupportedDestinations.isEmpty { + var supportedPlatforms: [String] = [] + var targetedDeviceFamily: [String] = [] + + for supportedDestination in specSupportedDestinations { + let supportedPlatformBuildSettings = SettingsPresetFile.supportedDestination(supportedDestination).getBuildSettings() + buildSettings += supportedPlatformBuildSettings + + if let value = supportedPlatformBuildSettings?["SUPPORTED_PLATFORMS"] as? String { + supportedPlatforms += value.components(separatedBy: " ") + } + if let value = supportedPlatformBuildSettings?["TARGETED_DEVICE_FAMILY"] as? String { + targetedDeviceFamily += value.components(separatedBy: ",") + } + } + + buildSettings["SUPPORTED_PLATFORMS"] = supportedPlatforms.joined(separator: " ") + buildSettings["TARGETED_DEVICE_FAMILY"] = targetedDeviceFamily.joined(separator: ",") + } + // apply custom platform version if let version = target.deploymentTarget { - buildSettings[target.platform.deploymentTargetSetting] = version.deploymentTarget + if !specSupportedDestinations.isEmpty { + for supportedDestination in specSupportedDestinations { + if let platform = Platform(rawValue: supportedDestination.rawValue) { + buildSettings[platform.deploymentTargetSetting] = version.deploymentTarget + } + } + } else { + buildSettings[target.platform.deploymentTargetSetting] = version.deploymentTarget + } } // Prevent setting presets from overrwriting settings in target xcconfig files @@ -195,15 +240,22 @@ 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, ] + possibleSettingsPaths } + if let moduleResourcePath = Bundle.availableModule?.path(forResource: "SettingPresets", ofType: nil) { + possibleSettingsPaths.append(Path(moduleResourcePath) + "\(path).yml") + } guard let settingsPath = possibleSettingsPaths.first(where: { $0.exists }) else { switch self { - case .base, .config, .platform: + case .base, .config, .platform, .supportedDestination: print("No \"\(name)\" settings found") case .product, .productPlatform: break @@ -220,3 +272,48 @@ extension SettingsPresetFile { return buildSettings } } + +private class BundleFinder {} + +/// The default SPM generated `Bundle.module` crashes on runtime if there is no .bundle file. +/// Below implementation modified from generated `Bundle.module` code which call `fatalError` if .bundle file not found. +private extension Bundle { + /// Returns the resource bundle associated with the current Swift module. + static let availableModule: Bundle? = { + let bundleName = "XcodeGen_XcodeGenKit" + + let overrides: [URL] + #if DEBUG + // The 'PACKAGE_RESOURCE_BUNDLE_PATH' name is preferred since the expected value is a path. The + // check for 'PACKAGE_RESOURCE_BUNDLE_URL' will be removed when all clients have switched over. + // This removal is tracked by rdar://107766372. + if let override = ProcessInfo.processInfo.environment["PACKAGE_RESOURCE_BUNDLE_PATH"] + ?? ProcessInfo.processInfo.environment["PACKAGE_RESOURCE_BUNDLE_URL"] { + overrides = [URL(fileURLWithPath: override)] + } else { + overrides = [] + } + #else + overrides = [] + #endif + + let candidates = overrides + [ + // Bundle should be present here when the package is linked into an App. + Bundle.main.resourceURL, + + // Bundle should be present here when the package is linked into a framework. + Bundle(for: BundleFinder.self).resourceURL, + + // For command-line tools. + Bundle.main.bundleURL, + ] + + for candidate in candidates { + let bundlePath = candidate?.appendingPathComponent(bundleName + ".bundle") + if let bundle = bundlePath.flatMap(Bundle.init(url:)) { + return bundle + } + } + return nil + }() +} diff --git a/Sources/XcodeGenKit/SettingsPresetFile.swift b/Sources/XcodeGenKit/SettingsPresetFile.swift index 8cbffad11..30a1f4103 100644 --- a/Sources/XcodeGenKit/SettingsPresetFile.swift +++ b/Sources/XcodeGenKit/SettingsPresetFile.swift @@ -5,6 +5,7 @@ import XcodeProj public enum SettingsPresetFile { case config(ConfigType) case platform(Platform) + case supportedDestination(SupportedDestination) case product(PBXProductType) case productPlatform(PBXProductType, Platform) case base @@ -13,6 +14,7 @@ public enum SettingsPresetFile { switch self { case let .config(config): return "Configs/\(config.rawValue)" case let .platform(platform): return "Platforms/\(platform.rawValue)" + case let .supportedDestination(supportedDestination): return "SupportedDestinations/\(supportedDestination.rawValue)" case let .product(product): return "Products/\(product.name)" case let .productPlatform(product, platform): return "Product_Platform/\(product.name)_\(platform.rawValue)" case .base: return "base" @@ -23,6 +25,7 @@ public enum SettingsPresetFile { switch self { case let .config(config): return "\(config.rawValue) config" case let .platform(platform): return platform.rawValue + case let .supportedDestination(supportedDestination): return supportedDestination.rawValue case let .product(product): return product.name case let .productPlatform(product, platform): return "\(platform) \(product)" case .base: return "base" diff --git a/Sources/XcodeGenKit/SourceGenerator.swift b/Sources/XcodeGenKit/SourceGenerator.swift index 481ed3b9c..e6c9948f8 100644 --- a/Sources/XcodeGenKit/SourceGenerator.swift +++ b/Sources/XcodeGenKit/SourceGenerator.swift @@ -2,13 +2,13 @@ import Foundation import PathKit import ProjectSpec import XcodeProj -import Core +import XcodeGenCore struct SourceFile { let path: Path let fileReference: PBXFileElement let buildFile: PBXBuildFile - let buildPhase: TargetSource.BuildPhase? + let buildPhase: BuildPhaseSpec? } class SourceGenerator { @@ -18,7 +18,6 @@ class SourceGenerator { private var fileReferencesByPath: [String: PBXFileElement] = [:] private var groupsByPath: [Path: PBXGroup] = [:] private var variantGroupsByPath: [Path: PBXVariantGroup] = [:] - private var localPackageGroup: PBXGroup? private let project: Project let pbxProj: PBXProj @@ -53,12 +52,10 @@ class SourceGenerator { return object } - func createLocalPackage(path: Path) throws { - - if localPackageGroup == nil { - let groupName = project.options.localPackagesGroup ?? "Packages" - localPackageGroup = addObject(PBXGroup(sourceTree: .sourceRoot, name: groupName)) - rootGroups.insert(localPackageGroup!) + func createLocalPackage(path: Path, group: Path?) throws { + var parentGroup: String = project.options.localPackagesGroup ?? "Packages" + if let group { + parentGroup = group.string } let absolutePath = project.basePath + path.normalize() @@ -74,30 +71,70 @@ class SourceGenerator { path: fileReferencePath ) ) - localPackageGroup!.children.append(fileReference) + + if parentGroup == "" { + rootGroups.insert(fileReference) + } else { + let parentGroups = parentGroup.components(separatedBy: "/") + createParentGroups(parentGroups, for: fileReference) + } } - func getAllSourceFiles(targetType: PBXProductType, sources: [TargetSource]) throws -> [SourceFile] { - try sources.flatMap { try getSourceFiles(targetType: targetType, targetSource: $0, path: project.basePath + $0.path) } + /// 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) } } // get groups without build files. Use for Project.fileGroups func getFileGroups(path: String) throws { - let fullPath = project.basePath + path - _ = try getSourceFiles(targetType: .none, targetSource: TargetSource(path: path), path: fullPath) + _ = try getSourceFiles(targetType: .none, targetSource: TargetSource(path: path), buildPhases: [:]) } - func generateSourceFile(targetType: PBXProductType, targetSource: TargetSource, path: Path, buildPhase: TargetSource.BuildPhase? = nil, fileReference: PBXFileElement? = nil) -> SourceFile { + func getFileType(path: Path) -> FileType? { + if let fileExtension = path.extension { + return project.options.fileTypes[fileExtension] ?? FileType.defaultFileTypes[fileExtension] + } else { + return nil + } + } + + private func makeDestinationFilters(for path: Path, with filters: [SupportedDestination]?, or inferDestinationFiltersByPath: Bool?) -> [String]? { + if let filters = filters, !filters.isEmpty { + return filters.map { $0.string } + } else if inferDestinationFiltersByPath == true { + for supportedDestination in SupportedDestination.allCases { + let regex1 = try? NSRegularExpression(pattern: "\\/\(supportedDestination)\\/", options: .caseInsensitive) + let regex2 = try? NSRegularExpression(pattern: "\\_\(supportedDestination)\\.swift$", options: .caseInsensitive) + + if regex1?.isMatch(to: path.string) == true || regex2?.isMatch(to: path.string) == true { + return [supportedDestination.string] + } + } + } + return nil + } + + func generateSourceFile(targetType: PBXProductType, targetSource: TargetSource, path: Path, fileReference: PBXFileElement? = nil, buildPhases: [Path: BuildPhaseSpec]) -> SourceFile { let fileReference = fileReference ?? fileReferencesByPath[path.string.lowercased()]! var settings: [String: Any] = [:] - var attributes: [String] = targetSource.attributes - var chosenBuildPhase: TargetSource.BuildPhase? + let fileType = getFileType(path: path) + var attributes: [String] = targetSource.attributes + (fileType?.attributes ?? []) + var chosenBuildPhase: BuildPhaseSpec? + var compilerFlags: String = "" + let assetTags: [String] = targetSource.resourceTags + (fileType?.resourceTags ?? []) let headerVisibility = targetSource.headerVisibility ?? .public - if let buildPhase = buildPhase { + if let buildPhase = targetSource.buildPhase { chosenBuildPhase = buildPhase - } else if let buildPhase = targetSource.buildPhase { + } else if resolvedTargetSourceType(for: targetSource, at: path) == .folder { + chosenBuildPhase = .resources + } else if let buildPhase = buildPhases[path] { chosenBuildPhase = buildPhase } else { chosenBuildPhase = getDefaultBuildPhase(for: path, targetType: targetType) @@ -107,7 +144,7 @@ class SourceGenerator { // Static libraries don't support the header build phase // For public headers they need to be copied if headerVisibility == .public { - chosenBuildPhase = .copyFiles(TargetSource.BuildPhase.CopyFilesSettings( + chosenBuildPhase = .copyFiles(BuildPhaseSpec.CopyFilesSettings( destination: .productsDirectory, subpath: "include/$(PRODUCT_NAME)", phaseOrder: .preCompile @@ -123,19 +160,33 @@ class SourceGenerator { attributes.append(headerVisibility.settingName) } } - if chosenBuildPhase == .sources && targetSource.compilerFlags.count > 0 { - settings["COMPILER_FLAGS"] = targetSource.compilerFlags.joined(separator: " ") + + if let flags = fileType?.compilerFlags { + compilerFlags += flags.joined(separator: " ") + } + + if !targetSource.compilerFlags.isEmpty { + if !compilerFlags.isEmpty { + compilerFlags += " " + } + compilerFlags += targetSource.compilerFlags.joined(separator: " ") + } + + if chosenBuildPhase == .sources && !compilerFlags.isEmpty { + settings["COMPILER_FLAGS"] = compilerFlags } if !attributes.isEmpty { settings["ATTRIBUTES"] = attributes } - - if chosenBuildPhase == .resources && !targetSource.resourceTags.isEmpty { - settings["ASSET_TAGS"] = targetSource.resourceTags + + if chosenBuildPhase == .resources && !assetTags.isEmpty { + settings["ASSET_TAGS"] = assetTags } - - let buildFile = PBXBuildFile(file: fileReference, settings: settings.isEmpty ? nil : settings) + + let platforms = makeDestinationFilters(for: path, with: targetSource.destinationFilters, or: targetSource.inferDestinationFiltersByPath) + + let buildFile = PBXBuildFile(file: fileReference, settings: settings.isEmpty ? nil : settings, platformFilters: platforms) return SourceFile( path: path, fileReference: fileReference, @@ -226,53 +277,26 @@ class SourceGenerator { } /// returns a default build phase for a given path. This is based off the filename - private func getDefaultBuildPhase(for path: Path, targetType: PBXProductType) -> TargetSource.BuildPhase? { - if path.lastComponent == "Info.plist" { - return nil + private func getDefaultBuildPhase(for path: Path, targetType: PBXProductType) -> BuildPhaseSpec? { + if let buildPhase = getFileType(path: path)?.buildPhase { + return buildPhase } if let fileExtension = path.extension { switch fileExtension { - case "swift", - "m", - "mm", - "cpp", - "c", - "cc", - "S", - "xcdatamodeld", - "xcmappingmodel", - "intentdefinition", - "metal", - "mlmodel", - "rcproject": - return .sources - case "h", - "hh", - "hpp", - "ipp", - "tpp", - "hxx", - "def": - return .headers case "modulemap": guard targetType == .staticLibrary else { return nil } - return .copyFiles(TargetSource.BuildPhase.CopyFilesSettings( + return .copyFiles(BuildPhaseSpec.CopyFilesSettings( destination: .productsDirectory, subpath: "include/$(PRODUCT_NAME)", phaseOrder: .preCompile )) - case "framework": - return .frameworks - case "xpc": - return .copyFiles(.xpcServices) - case "xcconfig", - "entitlements", - "gpx", - "lproj", - "xcfilelist", - "apns", - "pch": - return nil + case "swiftcrossimport": + guard targetType == .framework else { return nil } + return .copyFiles(BuildPhaseSpec.CopyFilesSettings( + destination: .productsDirectory, + subpath: "$(PRODUCT_NAME).framework/Modules", + phaseOrder: .preCompile + )) default: return .resources } @@ -302,11 +326,15 @@ class SourceGenerator { // lives outside the project base path let isOutOfBasePath = !path.absolute().string.contains(project.basePath.absolute().string) + // whether the given path is a strict parent of the project base path + // e.g. foo/bar is a parent of foo/bar/baz, but not foo/baz + let isParentOfBasePath = isOutOfBasePath && ((try? path.isParent(of: project.basePath)) == true) + // has no valid parent paths - let isRootPath = (isBaseGroup && isOutOfBasePath) || path.parent() == project.basePath + let isRootPath = (isBaseGroup && isOutOfBasePath && isParentOfBasePath) || path.parent() == project.basePath // is a top level group in the project - let isTopLevelGroup = !hasCustomParent && ((isBaseGroup && !createIntermediateGroups) || isRootPath) + let isTopLevelGroup = !hasCustomParent && ((isBaseGroup && !createIntermediateGroups) || isRootPath || isParentOfBasePath) let groupName = name ?? path.lastComponent @@ -349,7 +377,7 @@ class SourceGenerator { let rootSourcePath = project.basePath + targetSource.path return Set( - patterns.map { pattern in + patterns.parallelMap { pattern in guard !pattern.isEmpty else { return [] } return Glob(pattern: "\(rootSourcePath)/\(pattern)") .map { Path($0) } @@ -367,19 +395,23 @@ class SourceGenerator { } /// Checks whether the path is not in any default or TargetSource excludes - func isIncludedPath(_ path: Path, excludePaths: Set, includePaths: Set) -> Bool { - !defaultExcludedFiles.contains(where: { path.lastComponent.contains($0) }) + 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.isEmpty || includePaths.contains(where: { includedFile in - if path == includedFile { return true } - return includedFile.description.contains(path.description) - })) + && (includePaths.flatMap { _isIncludedPathSorted(path, sortedPaths: $0) } ?? true) } + + 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: Set) throws -> [Path] { + private func getSourceChildren(targetSource: TargetSource, dirPath: Path, excludePaths: Set, includePaths: SortedArray?) throws -> [Path] { try dirPath.children() .filter { if $0.isDirectory { @@ -408,19 +440,32 @@ class SourceGenerator { isBaseGroup: Bool, hasCustomParent: Bool, excludePaths: Set, - includePaths: Set + includePaths: SortedArray?, + buildPhases: [Path: BuildPhaseSpec] ) throws -> (sourceFiles: [SourceFile], groups: [PBXGroup]) { let children = try getSourceChildren(targetSource: targetSource, dirPath: path, excludePaths: excludePaths, includePaths: includePaths) let createIntermediateGroups = targetSource.createIntermediateGroups ?? project.options.createIntermediateGroups + let nonLocalizedChildren = children.filter { $0.extension != "lproj" } + let stringCatalogChildren = children.filter { $0.extension == "xcstrings" } - let directories = children - .filter { $0.isDirectory && !Xcode.isDirectoryFileWrapper(path: $0) && $0.extension != "lproj" } + let directories = nonLocalizedChildren + .filter { + if let fileType = getFileType(path: $0) { + return !fileType.file + } else { + return $0.isDirectory && !Xcode.isDirectoryFileWrapper(path: $0) + } + } - let filePaths = children - .filter { $0.isFile || $0.isDirectory && $0.extension != "lproj" - && Xcode.isDirectoryFileWrapper(path: $0) + let filePaths = nonLocalizedChildren + .filter { + if let fileType = getFileType(path: $0) { + return fileType.file + } else { + return $0.isFile || $0.isDirectory && Xcode.isDirectoryFileWrapper(path: $0) + } } let localisedDirectories = children @@ -428,7 +473,7 @@ class SourceGenerator { var groupChildren: [PBXFileElement] = filePaths.map { getFileReference(path: $0, inPath: path) } var allSourceFiles: [SourceFile] = filePaths.map { - generateSourceFile(targetType: targetType, targetSource: targetSource, path: $0) + generateSourceFile(targetType: targetType, targetSource: targetSource, path: $0, buildPhases: buildPhases) } var groups: [PBXGroup] = [] @@ -441,7 +486,8 @@ class SourceGenerator { isBaseGroup: false, hasCustomParent: false, excludePaths: excludePaths, - includePaths: includePaths + includePaths: includePaths, + buildPhases: buildPhases ) guard !subGroups.sourceFiles.isEmpty || project.options.generateEmptyDirectories else { @@ -468,6 +514,15 @@ class SourceGenerator { }() knownRegions.formUnion(localisedDirectories.map { $0.lastComponentWithoutExtension }) + + // XCode 15 - Detect known regions from locales present in string catalogs + + let stringCatalogsLocales = stringCatalogChildren + .compactMap { StringCatalog(from: $0) } + .reduce(Set(), { partialResult, stringCatalog in + partialResult.union(stringCatalog.includedLocales) + }) + knownRegions.formUnion(stringCatalogsLocales) // create variant groups of the base localisation first var baseLocalisationVariantGroups: [PBXVariantGroup] = [] @@ -484,7 +539,8 @@ class SourceGenerator { let sourceFile = generateSourceFile(targetType: targetType, targetSource: targetSource, path: filePath, - fileReference: variantGroup) + fileReference: variantGroup, + buildPhases: buildPhases) allSourceFiles.append(sourceFile) } } @@ -521,7 +577,8 @@ class SourceGenerator { let sourceFile = generateSourceFile(targetType: targetType, targetSource: targetSource, path: filePath, - fileReference: fileReference) + fileReference: fileReference, + buildPhases: buildPhases) allSourceFiles.append(sourceFile) groupChildren.append(fileReference) } @@ -544,14 +601,15 @@ class SourceGenerator { } /// creates source files - private func getSourceFiles(targetType: PBXProductType, targetSource: TargetSource, path: Path) throws -> [SourceFile] { + private func getSourceFiles(targetType: PBXProductType, targetSource: TargetSource, buildPhases: [Path: BuildPhaseSpec]) throws -> [SourceFile] { // generate excluded paths + let path = project.basePath + targetSource.path let excludePaths = getSourceMatches(targetSource: targetSource, patterns: targetSource.excludes) // generate included paths. Excluded paths will override this. - let includePaths = getSourceMatches(targetSource: targetSource, patterns: targetSource.includes) + let includePaths = targetSource.includes.isEmpty ? nil : getSourceMatches(targetSource: targetSource, patterns: targetSource.includes) - let type = targetSource.type ?? (path.isFile || path.extension != nil ? .file : .group) + let type = resolvedTargetSourceType(for: targetSource, at: path) let customParentGroups = (targetSource.group ?? "").split(separator: "/").map { String($0) } let hasCustomParent = !customParentGroups.isEmpty @@ -563,11 +621,10 @@ class SourceGenerator { var sourcePath = path switch type { case .folder: - let folderPath = project.basePath + Path(targetSource.path) let fileReference = getFileReference( - path: folderPath, + path: path, inPath: project.basePath, - name: targetSource.name ?? folderPath.lastComponent, + name: targetSource.name ?? path.lastComponent, sourceTree: .sourceRoot, lastKnownFileType: "folder" ) @@ -576,14 +633,7 @@ class SourceGenerator { rootGroups.insert(fileReference) } - let buildPhase: TargetSource.BuildPhase? - if let targetBuildPhase = targetSource.buildPhase { - buildPhase = targetBuildPhase - } else { - buildPhase = .resources - } - - let sourceFile = generateSourceFile(targetType: targetType, targetSource: targetSource, path: folderPath, buildPhase: buildPhase) + let sourceFile = generateSourceFile(targetType: targetType, targetSource: targetSource, path: path, buildPhases: buildPhases) sourceFiles.append(sourceFile) sourceReference = fileReference @@ -591,7 +641,7 @@ class SourceGenerator { let parentPath = path.parent() let fileReference = getFileReference(path: path, inPath: parentPath, name: targetSource.name) - let sourceFile = generateSourceFile(targetType: targetType, targetSource: targetSource, path: path) + let sourceFile = generateSourceFile(targetType: targetType, targetSource: targetSource, path: path, buildPhases: buildPhases) if hasCustomParent { sourcePath = path @@ -614,7 +664,7 @@ class SourceGenerator { sourceFiles.append(sourceFile) case .group: - if targetSource.optional && !Path(targetSource.path).exists { + if targetSource.optional && !path.exists { // This group is missing, so if's optional just return an empty array return [] } @@ -626,7 +676,8 @@ class SourceGenerator { isBaseGroup: true, hasCustomParent: hasCustomParent, excludePaths: excludePaths, - includePaths: includePaths + includePaths: includePaths.flatMap(SortedArray.init(_:)), + buildPhases: buildPhases ) let group = groups.first! @@ -636,6 +687,32 @@ class SourceGenerator { sourceFiles += groupSourceFiles sourceReference = group + case .syncedFolder: + + let relativePath = (try? path.relativePath(from: project.basePath)) ?? path + + let syncedRootGroup = PBXFileSystemSynchronizedRootGroup( + sourceTree: .group, + path: relativePath.string, + name: targetSource.name, + explicitFileTypes: [:], + exceptions: [], + explicitFolders: [] + ) + addObject(syncedRootGroup) + sourceReference = syncedRootGroup + + // TODO: adjust if hasCustomParent == true + rootGroups.insert(syncedRootGroup) + + let sourceFile = generateSourceFile( + targetType: targetType, + targetSource: targetSource, + path: path, + fileReference: syncedRootGroup, + buildPhases: buildPhases + ) + sourceFiles.append(sourceFile) } if hasCustomParent { @@ -648,6 +725,23 @@ class SourceGenerator { return sourceFiles } + /// Returns the resolved `SourceType` for a given `TargetSource`. + /// + /// 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 { + if let chosenType = targetSource.type { + return chosenType + } else { + if path.isFile || path.extension != nil { + return .file + } else if let sourceType = project.options.defaultSourceDirectoryType { + return sourceType + } else { + return .group + } + } + } + private func createParentGroups(_ parentGroups: [String], for fileElement: PBXFileElement) { guard let parentName = parentGroups.last else { return @@ -680,12 +774,26 @@ class SourceGenerator { private func createIntermediaGroups(for fileElement: PBXFileElement, at path: Path) { let parentPath = path.parent() - guard parentPath != project.basePath && path.string.contains(project.basePath.string) else { - // we've reached the top or are out of the root directory + guard parentPath != project.basePath else { + // we've reached the top return } let hasParentGroup = groupsByPath[parentPath] != nil + if !hasParentGroup { + do { + // if the path is a parent of the project base path (or if calculating that fails) + // do not create a parent group + // e.g. for project path foo/bar/baz + // - create foo/baz + // - create baz/ + // - do not create foo + let pathIsParentOfProject = try path.isParent(of: project.basePath) + if pathIsParentOfProject { return } + } catch { + return + } + } let parentGroup = getGroup( path: parentPath, mergingChildren: [fileElement], diff --git a/Sources/XcodeGenKit/StringCatalogDecoding.swift b/Sources/XcodeGenKit/StringCatalogDecoding.swift new file mode 100644 index 000000000..da66c2596 --- /dev/null +++ b/Sources/XcodeGenKit/StringCatalogDecoding.swift @@ -0,0 +1,82 @@ +import Foundation +import JSONUtilities +import PathKit + +struct StringCatalog { + +/** +* Sample string catalog: + +* { +* "sourceLanguage" : "en", +* "strings" : { +* "foo" : { +* "localizations" : { +* "en" : { +* ... +* }, +* "es" : { +* ... +* }, +* "it" : { +* ... +* } +* } +* } +* } +* } +*/ + + private struct CatalogItem { + private enum JSONKeys: String { + case localizations + } + + private let key: String + let locales: Set + + init?(key: String, from jsonDictionary: JSONDictionary) { + guard let localizations = jsonDictionary[JSONKeys.localizations.rawValue] as? JSONDictionary else { + return nil + } + + self.key = key + self.locales = Set(localizations.keys) + } + } + + private enum JSONKeys: String { + case strings + } + + private let strings: [CatalogItem] + + init?(from path: Path) { + guard let catalogDictionary = try? JSONDictionary.from(url: path.url), + let catalog = StringCatalog(from: catalogDictionary) else { + return nil + } + + self = catalog + } + + private init?(from jsonDictionary: JSONDictionary) { + guard let stringsDictionary = jsonDictionary[JSONKeys.strings.rawValue] as? JSONDictionary else { + return nil + } + + self.strings = stringsDictionary.compactMap { key, value -> CatalogItem? in + guard let stringDictionary = value as? JSONDictionary else { + return nil + } + + return CatalogItem(key: key, from: stringDictionary) + } + } + + var includedLocales: Set { + strings.reduce(Set(), { partialResult, catalogItem in + partialResult.union(catalogItem.locales) + }) + } +} diff --git a/Sources/XcodeGenKit/Version.swift b/Sources/XcodeGenKit/Version.swift index ca0e6a39d..7b7246e9b 100644 --- a/Sources/XcodeGenKit/Version.swift +++ b/Sources/XcodeGenKit/Version.swift @@ -3,20 +3,24 @@ import ProjectSpec extension Project { - var xcodeVersion: String { - XCodeVersion.parse(options.xcodeVersion ?? "10.2") + public var xcodeVersion: String { + XCodeVersion.parse(options.xcodeVersion ?? "14.3") } var schemeVersion: String { - "1.3" + "1.7" } var compatibilityVersion: String { - "Xcode 10.0" + "Xcode 14.0" } var objectVersion: UInt { - 51 + 77 + } + + var minimizedProjectReferenceProxies: Int { + 1 } } diff --git a/Sources/XcodeGenKit/XCProjExtensions.swift b/Sources/XcodeGenKit/XCProjExtensions.swift index dc03fe9d5..33d3f5b67 100644 --- a/Sources/XcodeGenKit/XCProjExtensions.swift +++ b/Sources/XcodeGenKit/XCProjExtensions.swift @@ -38,6 +38,8 @@ extension PBXProj { string += "\n 🌎 " + variantGroup.nameOrPath } else if let versionGroup = child as? XCVersionGroup { string += "\n 🔢 " + versionGroup.nameOrPath + } else if let syncedFolder = child as? PBXFileSystemSynchronizedRootGroup { + string += "\n 📁 " + syncedFolder.nameOrPath } } return string @@ -53,10 +55,16 @@ 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" + case ("swiftcrossimport", _): + return "wrapper.swiftcrossimport" + case ("xcstrings", _): + return "text.json.xcstrings" default: // fallback to XcodeProj defaults return Xcode.filetype(extension: fileExtension) diff --git a/Tests/FixtureTests/FixtureTests.swift b/Tests/FixtureTests/FixtureTests.swift index d4ebda332..c638098f7 100644 --- a/Tests/FixtureTests/FixtureTests.swift +++ b/Tests/FixtureTests/FixtureTests.swift @@ -8,7 +8,8 @@ import TestSupport class FixtureTests: XCTestCase { - func testProjectFixture() { + func testProjectFixture() throws { + try skipIfNecessary() describe { $0.it("generates Test Project") { try generateXcodeProject(specPath: fixturePath + "TestProject/AnotherProject/project.yml") @@ -28,7 +29,7 @@ private func generateXcodeProject(specPath: Path, file: String = #file, line: In let project = try Project(path: specPath) let generator = ProjectGenerator(project: project) let writer = FileWriter(project: project) - let xcodeProject = try generator.generateXcodeProject() + let xcodeProject = try generator.generateXcodeProject(userName: "someUser") try writer.writeXcodeProject(xcodeProject) try writer.writePlists() } diff --git a/Tests/Fixtures/CarthageProject/Project.xcodeproj/project.pbxproj b/Tests/Fixtures/CarthageProject/Project.xcodeproj/project.pbxproj index 191fe8a67..5b62b8139 100644 --- a/Tests/Fixtures/CarthageProject/Project.xcodeproj/project.pbxproj +++ b/Tests/Fixtures/CarthageProject/Project.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 77; objects = { /* Begin PBXBuildFile section */ @@ -254,6 +254,8 @@ dependencies = ( ); name = Framework_tvOS; + packageProductDependencies = ( + ); productName = Framework_tvOS; productReference = 7D67F1C1BFBACE101DE7DB51 /* Framework.framework */; productType = "com.apple.product-type.framework"; @@ -270,6 +272,8 @@ dependencies = ( ); name = Framework_macOS; + packageProductDependencies = ( + ); productName = Framework_macOS; productReference = 41FC82ED1C4C3B7B3D7B2FB7 /* Framework.framework */; productType = "com.apple.product-type.framework"; @@ -286,6 +290,8 @@ dependencies = ( ); name = Framework_watchOS; + packageProductDependencies = ( + ); productName = Framework_watchOS; productReference = 6177CC6263783487E93F7F4D /* Framework.framework */; productType = "com.apple.product-type.framework"; @@ -302,6 +308,8 @@ dependencies = ( ); name = Framework_iOS; + packageProductDependencies = ( + ); productName = Framework_iOS; productReference = 8A9274BE42A03DC5DA1FAD04 /* Framework.framework */; productType = "com.apple.product-type.framework"; @@ -312,18 +320,20 @@ 0FBAE303E3CFC2ABAC876A77 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; - TargetAttributes = { - }; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1430; }; buildConfigurationList = D91E14E36EC0B415578456F2 /* Build configuration list for PBXProject "Project" */; - compatibilityVersion = "Xcode 10.0"; + compatibilityVersion = "Xcode 14.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( + Base, en, ); mainGroup = 293D0FF827366B513839236A; + minimizedProjectReferenceProxies = 1; + preferredProjectObjectVersion = 77; projectDirPath = ""; projectRoot = ""; targets = ( @@ -377,6 +387,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -392,6 +403,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -410,10 +422,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; - VALIDATE_PRODUCT = YES; }; name = Release; }; @@ -549,6 +563,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -564,6 +579,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -588,7 +604,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MTL_ENABLE_DEBUG_INFO = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; diff --git a/Tests/Fixtures/CarthageProject/Project.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Tests/Fixtures/CarthageProject/Project.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 881a6dff3..919434a62 100644 --- a/Tests/Fixtures/CarthageProject/Project.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/Tests/Fixtures/CarthageProject/Project.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/Tests/Fixtures/SPM/FooFeature/Package.swift b/Tests/Fixtures/SPM/FooFeature/Package.swift new file mode 100644 index 000000000..2540293c8 --- /dev/null +++ b/Tests/Fixtures/SPM/FooFeature/Package.swift @@ -0,0 +1,20 @@ +// swift-tools-version: 5.8 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "FooFeature", + products: [ + .library(name: "FooDomain", targets: [ + "FooDomain" + ]), + .library(name: "FooUI", targets: [ + "FooUI" + ]) + ], + targets: [ + .target(name: "FooDomain"), + .target(name: "FooUI") + ] +) diff --git a/Tests/Fixtures/SPM/FooFeature/Sources/FooDomain/FooDomain.swift b/Tests/Fixtures/SPM/FooFeature/Sources/FooDomain/FooDomain.swift new file mode 100644 index 000000000..580e98166 --- /dev/null +++ b/Tests/Fixtures/SPM/FooFeature/Sources/FooDomain/FooDomain.swift @@ -0,0 +1 @@ +public struct FooDomain {} diff --git a/Tests/Fixtures/SPM/FooFeature/Sources/FooUI/FooUI.swift b/Tests/Fixtures/SPM/FooFeature/Sources/FooUI/FooUI.swift new file mode 100644 index 000000000..1951b94c7 --- /dev/null +++ b/Tests/Fixtures/SPM/FooFeature/Sources/FooUI/FooUI.swift @@ -0,0 +1 @@ +public struct FooUI {} diff --git a/Tests/Fixtures/SPM/SPM.xcodeproj/project.pbxproj b/Tests/Fixtures/SPM/SPM.xcodeproj/project.pbxproj index 350ddef65..eef5a9d73 100644 --- a/Tests/Fixtures/SPM/SPM.xcodeproj/project.pbxproj +++ b/Tests/Fixtures/SPM/SPM.xcodeproj/project.pbxproj @@ -3,19 +3,38 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 77; objects = { +/* Begin PBXAggregateTarget section */ + ADD3CE771A0D5E996031A193 /* AggTarget */ = { + isa = PBXAggregateTarget; + buildConfigurationList = A7ABF1B35D9170092F822790 /* Build configuration list for PBXAggregateTarget "AggTarget" */; + buildPhases = ( + ); + dependencies = ( + D287BAAB664D1A024D9DD57E /* PBXTargetDependency */, + ); + name = AggTarget; + packageProductDependencies = ( + ); + productName = AggTarget; + }; +/* End PBXAggregateTarget section */ + /* Begin PBXBuildFile section */ + 23C6626698DE560017A89F2F /* XcodeGen in Frameworks */ = {isa = PBXBuildFile; productRef = 6F7DEA2D82649EDF903FBDBD /* XcodeGen */; }; 2DA7998902987953B119E4CE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26F7EFEE613987D1E1258A60 /* AppDelegate.swift */; }; + 36CE2E6187D9709BAD9EF807 /* FooDomain in Frameworks */ = {isa = PBXBuildFile; productRef = 8D2DC638BEF7FDF23907E134 /* FooDomain */; }; 3986ED6965842721C46C0452 /* SwiftRoaringDynamic in Frameworks */ = {isa = PBXBuildFile; productRef = DC73B269C8B0C0BF6912842C /* SwiftRoaringDynamic */; }; 4CC663B42B270404EF5FD037 /* libStaticLibrary.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CAB5625F6FEA668410ED5482 /* libStaticLibrary.a */; }; - 578E78BC3627CF48FB2CE129 /* App.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = A9601593D0AD02931266A4E5 /* App.xctestplan */; }; 9AD886A88D3E4A1B5E900687 /* SPMTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7970A2253B14A9B27C307FAC /* SPMTests.swift */; }; 9C4AD0711D706FD3ED0E436D /* StaticLibrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C17B77601A9D1B7895AB42 /* StaticLibrary.swift */; }; + AF8E362713B9D28EA9A5C9FC /* SwiftLocation in Frameworks */ = {isa = PBXBuildFile; productRef = 04F71F974C4771232AF4FEC2 /* SwiftLocation */; }; B89EA0F3859878A1DCF7BAFD /* SwiftRoaringDynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = DC73B269C8B0C0BF6912842C /* SwiftRoaringDynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - CE46CBA5671B951B546C8673 /* Codability in Frameworks */ = {isa = PBXBuildFile; productRef = 16E6FE01D5BD99F78D4A17E2 /* Codability */; }; + CE46CBA5671B951B546C8673 /* Codability in Frameworks */ = {isa = PBXBuildFile; productRef = 16E6FE01D5BD99F78D4A17E2 /* Codability */; settings = {ATTRIBUTES = (Weak, ); }; }; E368431019ABC696E4FFC0CF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4E22B8BCC18A29EFE1DE3BE4 /* Assets.xcassets */; }; + ECC4F5F3B3D1391712A7AFE3 /* FooUI in Frameworks */ = {isa = PBXBuildFile; productRef = 927CB19D94339CC9960E930C /* FooUI */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -57,9 +76,10 @@ 4E22B8BCC18A29EFE1DE3BE4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 61C17B77601A9D1B7895AB42 /* StaticLibrary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticLibrary.swift; sourceTree = ""; }; 7970A2253B14A9B27C307FAC /* SPMTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPMTests.swift; sourceTree = ""; }; + 979AE1767E2AF6B3B9D7F13D /* FooFeature */ = {isa = PBXFileReference; lastKnownFileType = folder; name = FooFeature; path = FooFeature; sourceTree = SOURCE_ROOT; }; A9601593D0AD02931266A4E5 /* App.xctestplan */ = {isa = PBXFileReference; path = App.xctestplan; sourceTree = ""; }; - C1DE9A872F470EAA65B9B0B0 /* XcodeGen */ = {isa = PBXFileReference; lastKnownFileType = folder; name = XcodeGen; path = ../../..; sourceTree = SOURCE_ROOT; }; CAB5625F6FEA668410ED5482 /* libStaticLibrary.a */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = archive.ar; path = libStaticLibrary.a; sourceTree = BUILT_PRODUCTS_DIR; }; + ED284AB7C13DCC0A95DAA680 /* XcodeGen */ = {isa = PBXFileReference; lastKnownFileType = folder; name = XcodeGen; path = ../../..; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -70,6 +90,10 @@ CE46CBA5671B951B546C8673 /* Codability in Frameworks */, 3986ED6965842721C46C0452 /* SwiftRoaringDynamic in Frameworks */, 4CC663B42B270404EF5FD037 /* libStaticLibrary.a in Frameworks */, + 23C6626698DE560017A89F2F /* XcodeGen in Frameworks */, + AF8E362713B9D28EA9A5C9FC /* SwiftLocation in Frameworks */, + 36CE2E6187D9709BAD9EF807 /* FooDomain in Frameworks */, + ECC4F5F3B3D1391712A7AFE3 /* FooUI in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -83,6 +107,7 @@ 26F7EFEE613987D1E1258A60 /* AppDelegate.swift */, 4E22B8BCC18A29EFE1DE3BE4 /* Assets.xcassets */, 464ACF8D8F2D9F219BCFD3E7 /* Info.plist */, + ED284AB7C13DCC0A95DAA680 /* XcodeGen */, ); path = SPM; sourceTree = ""; @@ -119,10 +144,10 @@ AD0F3623091EEA8D1EA3DFF8 /* Packages */ = { isa = PBXGroup; children = ( - C1DE9A872F470EAA65B9B0B0 /* XcodeGen */, + 979AE1767E2AF6B3B9D7F13D /* FooFeature */, ); name = Packages; - sourceTree = SOURCE_ROOT; + sourceTree = ""; }; CF3BD77AEAA56553289456BA /* SPMTests */ = { isa = PBXGroup; @@ -147,6 +172,8 @@ 8693351DA9DBE579AC9DD513 /* PBXTargetDependency */, ); name = Tests; + packageProductDependencies = ( + ); productName = Tests; productReference = 0613661C0D45064E81E80C37 /* Tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; @@ -164,12 +191,16 @@ D85FFB99444DD260A72DDDA7 /* PBXTargetDependency */, DDD17C561AD5065DF4FA4072 /* PBXTargetDependency */, C6360997FFC102F6725099D4 /* PBXTargetDependency */, + 00B467060F3DEC027711F9C2 /* PBXTargetDependency */, + 7EB17E90A4D8F26FEABEEDF6 /* PBXTargetDependency */, ); name = StaticLibrary; packageProductDependencies = ( AF233B61592982A7F6431FC6 /* Codability */, C816AEB28ED71C3C47F31B98 /* SwiftRoaringDynamic */, 5A36E2FE69703FCAC0BE8064 /* XcodeGen */, + 6B8A6E1EA485E607A1D1DCD1 /* FooDomain */, + 15DB49096E2978F6BCA8D604 /* FooUI */, ); productName = StaticLibrary; productReference = CAB5625F6FEA668410ED5482 /* libStaticLibrary.a */; @@ -188,11 +219,16 @@ ); dependencies = ( 078202CF7B08B66ACF7FEC23 /* PBXTargetDependency */, + E157C6348B8AD6A28C706801 /* PBXTargetDependency */, ); name = App; packageProductDependencies = ( 16E6FE01D5BD99F78D4A17E2 /* Codability */, DC73B269C8B0C0BF6912842C /* SwiftRoaringDynamic */, + 6F7DEA2D82649EDF903FBDBD /* XcodeGen */, + 04F71F974C4771232AF4FEC2 /* SwiftLocation */, + 8D2DC638BEF7FDF23907E134 /* FooDomain */, + 927CB19D94339CC9960E930C /* FooUI */, ); productName = App; productReference = 097F2DB5622B591E21BC3C73 /* App.app */; @@ -204,25 +240,32 @@ F7B09D77DB7447B17DCDA3C4 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; - TargetAttributes = { - }; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1430; }; buildConfigurationList = 425866ADA259DB93FC4AF1E3 /* Build configuration list for PBXProject "SPM" */; - compatibilityVersion = "Xcode 10.0"; + compatibilityVersion = "Xcode 14.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( + Base, en, ); mainGroup = 218F6C96DF9E182F526258CF; + minimizedProjectReferenceProxies = 1; packageReferences = ( 5BA91390AE78D2EE15C60091 /* XCRemoteSwiftPackageReference "Codability" */, + 348C81C327DB1710B742C370 /* XCRemoteSwiftPackageReference "Prefire" */, + 63B845B0C9058076DD19CA85 /* XCRemoteSwiftPackageReference "SwiftLocation" */, E3887F3CB2C069E70D98092F /* XCRemoteSwiftPackageReference "SwiftRoaring" */, + 630A8CE9F2BE39704ED9D461 /* XCLocalSwiftPackageReference "FooFeature" */, + C6539B364583AE96C18CE377 /* XCLocalSwiftPackageReference "../../.." */, ); + preferredProjectObjectVersion = 77; projectDirPath = ""; projectRoot = ""; targets = ( + ADD3CE771A0D5E996031A193 /* AggTarget */, C99E3C420D63D5219CE57E33 /* App */, 3F8D94C4EFC431F646AAFB28 /* StaticLibrary */, 339863E54E2D955C00B56802 /* Tests */, @@ -235,7 +278,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 578E78BC3627CF48FB2CE129 /* App.xctestplan in Resources */, E368431019ABC696E4FFC0CF /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -289,11 +331,19 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 00B467060F3DEC027711F9C2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + productRef = 6B8A6E1EA485E607A1D1DCD1 /* FooDomain */; + }; 078202CF7B08B66ACF7FEC23 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 3F8D94C4EFC431F646AAFB28 /* StaticLibrary */; targetProxy = 29147E1DDAEB1AAC20CB0CF9 /* PBXContainerItemProxy */; }; + 7EB17E90A4D8F26FEABEEDF6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + productRef = 15DB49096E2978F6BCA8D604 /* FooUI */; + }; 8693351DA9DBE579AC9DD513 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = C99E3C420D63D5219CE57E33 /* App */; @@ -303,6 +353,10 @@ isa = PBXTargetDependency; productRef = 5A36E2FE69703FCAC0BE8064 /* XcodeGen */; }; + D287BAAB664D1A024D9DD57E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + productRef = 896D1E2063A93D40F04D7864 /* PrefirePlaybookPlugin */; + }; D85FFB99444DD260A72DDDA7 /* PBXTargetDependency */ = { isa = PBXTargetDependency; productRef = AF233B61592982A7F6431FC6 /* Codability */; @@ -311,9 +365,19 @@ isa = PBXTargetDependency; productRef = C816AEB28ED71C3C47F31B98 /* SwiftRoaringDynamic */; }; + E157C6348B8AD6A28C706801 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + productRef = DC47EF1BFBBD751E3C1C95E3 /* PrefirePlaybookPlugin */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ + 0C023F1AE037C42683029CE9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Debug; + }; 0CCC06807E5CD8361D899B7F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -359,6 +423,12 @@ }; name = Debug; }; + 5E087A904FBC0E623E672507 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Release; + }; 7A384B9B9CF42FCF9EF02057 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -403,6 +473,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -418,6 +489,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -442,7 +514,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MTL_ENABLE_DEBUG_INFO = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; @@ -477,6 +550,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -492,6 +566,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -510,11 +585,13 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; - VALIDATE_PRODUCT = YES; }; name = Release; }; @@ -557,9 +634,37 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; + A7ABF1B35D9170092F822790 /* Build configuration list for PBXAggregateTarget "AggTarget" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0C023F1AE037C42683029CE9 /* Debug */, + 5E087A904FBC0E623E672507 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; /* End XCConfigurationList section */ +/* Begin XCLocalSwiftPackageReference section */ + 630A8CE9F2BE39704ED9D461 /* XCLocalSwiftPackageReference "FooFeature" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = FooFeature; + }; + C6539B364583AE96C18CE377 /* XCLocalSwiftPackageReference "../../.." */ = { + isa = XCLocalSwiftPackageReference; + relativePath = ../../..; + }; +/* End XCLocalSwiftPackageReference section */ + /* Begin XCRemoteSwiftPackageReference section */ + 348C81C327DB1710B742C370 /* XCRemoteSwiftPackageReference "Prefire" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/BarredEwe/Prefire"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.4.1; + }; + }; 5BA91390AE78D2EE15C60091 /* XCRemoteSwiftPackageReference "Codability" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/yonaskolb/Codability"; @@ -568,6 +673,14 @@ minimumVersion = 0.2.1; }; }; + 63B845B0C9058076DD19CA85 /* XCRemoteSwiftPackageReference "SwiftLocation" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/malcommac/SwiftLocation"; + requirement = { + kind = exactVersion; + version = 6.0; + }; + }; E3887F3CB2C069E70D98092F /* XCRemoteSwiftPackageReference "SwiftRoaring" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/piotte13/SwiftRoaring"; @@ -579,6 +692,15 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 04F71F974C4771232AF4FEC2 /* SwiftLocation */ = { + isa = XCSwiftPackageProductDependency; + package = 63B845B0C9058076DD19CA85 /* XCRemoteSwiftPackageReference "SwiftLocation" */; + productName = SwiftLocation; + }; + 15DB49096E2978F6BCA8D604 /* FooUI */ = { + isa = XCSwiftPackageProductDependency; + productName = FooUI; + }; 16E6FE01D5BD99F78D4A17E2 /* Codability */ = { isa = XCSwiftPackageProductDependency; package = 5BA91390AE78D2EE15C60091 /* XCRemoteSwiftPackageReference "Codability" */; @@ -588,6 +710,27 @@ isa = XCSwiftPackageProductDependency; productName = XcodeGen; }; + 6B8A6E1EA485E607A1D1DCD1 /* FooDomain */ = { + isa = XCSwiftPackageProductDependency; + productName = FooDomain; + }; + 6F7DEA2D82649EDF903FBDBD /* XcodeGen */ = { + isa = XCSwiftPackageProductDependency; + productName = XcodeGen; + }; + 896D1E2063A93D40F04D7864 /* PrefirePlaybookPlugin */ = { + isa = XCSwiftPackageProductDependency; + package = 348C81C327DB1710B742C370 /* XCRemoteSwiftPackageReference "Prefire" */; + productName = "plugin:PrefirePlaybookPlugin"; + }; + 8D2DC638BEF7FDF23907E134 /* FooDomain */ = { + isa = XCSwiftPackageProductDependency; + productName = FooDomain; + }; + 927CB19D94339CC9960E930C /* FooUI */ = { + isa = XCSwiftPackageProductDependency; + productName = FooUI; + }; AF233B61592982A7F6431FC6 /* Codability */ = { isa = XCSwiftPackageProductDependency; package = 5BA91390AE78D2EE15C60091 /* XCRemoteSwiftPackageReference "Codability" */; @@ -598,6 +741,11 @@ package = E3887F3CB2C069E70D98092F /* XCRemoteSwiftPackageReference "SwiftRoaring" */; productName = SwiftRoaringDynamic; }; + DC47EF1BFBBD751E3C1C95E3 /* PrefirePlaybookPlugin */ = { + isa = XCSwiftPackageProductDependency; + package = 348C81C327DB1710B742C370 /* XCRemoteSwiftPackageReference "Prefire" */; + productName = "plugin:PrefirePlaybookPlugin"; + }; DC73B269C8B0C0BF6912842C /* SwiftRoaringDynamic */ = { isa = XCSwiftPackageProductDependency; package = E3887F3CB2C069E70D98092F /* XCRemoteSwiftPackageReference "SwiftRoaring" */; diff --git a/Tests/Fixtures/SPM/SPM.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Tests/Fixtures/SPM/SPM.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 4c49d31b6..919434a62 100644 --- a/Tests/Fixtures/SPM/SPM.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/Tests/Fixtures/SPM/SPM.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/Tests/Fixtures/SPM/SPM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Tests/Fixtures/SPM/SPM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index a14eedb25..8d8accfc1 100644 --- a/Tests/Fixtures/SPM/SPM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Tests/Fixtures/SPM/SPM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,106 +1,122 @@ { - "object": { - "pins": [ - { - "package": "AEXML", - "repositoryURL": "https://github.com/tadija/AEXML", - "state": { - "branch": null, - "revision": "e4d517844dd03dac557e35d77a8e9ab438de91a6", - "version": "4.4.0" - } - }, - { - "package": "Codability", - "repositoryURL": "https://github.com/yonaskolb/Codability", - "state": { - "branch": null, - "revision": "eb5bac78e0679f521c3f058c1eb9be0dd657dadd", - "version": "0.2.1" - } - }, - { - "package": "JSONUtilities", - "repositoryURL": "https://github.com/yonaskolb/JSONUtilities.git", - "state": { - "branch": null, - "revision": "128d2ffc22467f69569ef8ff971683e2393191a0", - "version": "4.2.0" - } - }, - { - "package": "PathKit", - "repositoryURL": "https://github.com/kylef/PathKit.git", - "state": { - "branch": null, - "revision": "73f8e9dca9b7a3078cb79128217dc8f2e585a511", - "version": "1.0.0" - } - }, - { - "package": "Rainbow", - "repositoryURL": "https://github.com/onevcat/Rainbow.git", - "state": { - "branch": null, - "revision": "9c52c1952e9b2305d4507cf473392ac2d7c9b155", - "version": "3.1.5" - } - }, - { - "package": "Spectre", - "repositoryURL": "https://github.com/kylef/Spectre.git", - "state": { - "branch": null, - "revision": "f14ff47f45642aa5703900980b014c2e9394b6e5", - "version": "0.9.0" - } - }, - { - "package": "SwiftCLI", - "repositoryURL": "https://github.com/jakeheis/SwiftCLI.git", - "state": { - "branch": null, - "revision": "c72c4564f8c0a24700a59824880536aca45a4cae", - "version": "6.0.1" - } - }, - { - "package": "SwiftRoaring", - "repositoryURL": "https://github.com/piotte13/SwiftRoaring", - "state": { - "branch": null, - "revision": "9104cf3f35e7a38c9fb633084c7adb63a9f27f8b", - "version": "1.0.4" - } - }, - { - "package": "Version", - "repositoryURL": "https://github.com/mxcl/Version", - "state": { - "branch": null, - "revision": "a94b48f36763c05629fc102837398505032dead9", - "version": "2.0.0" - } - }, - { - "package": "XcodeProj", - "repositoryURL": "https://github.com/tuist/XcodeProj.git", - "state": { - "branch": null, - "revision": "f32704e01d2752bdc17cde3963bee4256c1f4df4", - "version": "7.8.0" - } - }, - { - "package": "Yams", - "repositoryURL": "https://github.com/jpsim/Yams.git", - "state": { - "branch": null, - "revision": "c947a306d2e80ecb2c0859047b35c73b8e1ca27f", - "version": "2.0.0" - } + "pins" : [ + { + "identity" : "aexml", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tadija/AEXML.git", + "state" : { + "revision" : "38f7d00b23ecd891e1ee656fa6aeebd6ba04ecc3", + "version" : "4.6.1" } - ] - }, - "version": 1 + }, + { + "identity" : "codability", + "kind" : "remoteSourceControl", + "location" : "https://github.com/yonaskolb/Codability", + "state" : { + "revision" : "eb5bac78e0679f521c3f058c1eb9be0dd657dadd", + "version" : "0.2.1" + } + }, + { + "identity" : "graphviz", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SwiftDocOrg/GraphViz.git", + "state" : { + "revision" : "70bebcf4597b9ce33e19816d6bbd4ba9b7bdf038", + "version" : "0.2.0" + } + }, + { + "identity" : "jsonutilities", + "kind" : "remoteSourceControl", + "location" : "https://github.com/yonaskolb/JSONUtilities.git", + "state" : { + "revision" : "128d2ffc22467f69569ef8ff971683e2393191a0", + "version" : "4.2.0" + } + }, + { + "identity" : "pathkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kylef/PathKit.git", + "state" : { + "revision" : "3bfd2737b700b9a36565a8c94f4ad2b050a5e574", + "version" : "1.0.1" + } + }, + { + "identity" : "prefire", + "kind" : "remoteSourceControl", + "location" : "https://github.com/BarredEwe/Prefire", + "state" : { + "revision" : "abb8dfa44391b4f47edb4937a4ba124e76270a87", + "version" : "1.4.1" + } + }, + { + "identity" : "rainbow", + "kind" : "remoteSourceControl", + "location" : "https://github.com/onevcat/Rainbow.git", + "state" : { + "revision" : "626c3d4b6b55354b4af3aa309f998fae9b31a3d9", + "version" : "3.2.0" + } + }, + { + "identity" : "spectre", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kylef/Spectre.git", + "state" : { + "revision" : "26cc5e9ae0947092c7139ef7ba612e34646086c7", + "version" : "0.10.1" + } + }, + { + "identity" : "swiftcli", + "kind" : "remoteSourceControl", + "location" : "https://github.com/jakeheis/SwiftCLI.git", + "state" : { + "revision" : "2e949055d9797c1a6bddcda0e58dada16cc8e970", + "version" : "6.0.3" + } + }, + { + "identity" : "swiftroaring", + "kind" : "remoteSourceControl", + "location" : "https://github.com/piotte13/SwiftRoaring", + "state" : { + "revision" : "9104cf3f35e7a38c9fb633084c7adb63a9f27f8b", + "version" : "1.0.4" + } + }, + { + "identity" : "version", + "kind" : "remoteSourceControl", + "location" : "https://github.com/mxcl/Version", + "state" : { + "revision" : "1fe824b80d89201652e7eca7c9252269a1d85e25", + "version" : "2.0.1" + } + }, + { + "identity" : "xcodeproj", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tuist/XcodeProj.git", + "state" : { + "revision" : "6e60fb55271c80f83a186c9b1b4982fd991cfc0a", + "version" : "8.13.0" + } + }, + { + "identity" : "yams", + "kind" : "remoteSourceControl", + "location" : "https://github.com/jpsim/Yams.git", + "state" : { + "revision" : "0d9ee7ea8c4ebd4a489ad7a73d5c6cad55d6fed3", + "version" : "5.0.6" + } + } + ], + "version" : 2 } diff --git a/Tests/Fixtures/SPM/SPM.xcodeproj/xcshareddata/xcschemes/App.xcscheme b/Tests/Fixtures/SPM/SPM.xcodeproj/xcshareddata/xcschemes/App.xcscheme index 5547dad3d..298045bf8 100644 --- a/Tests/Fixtures/SPM/SPM.xcodeproj/xcshareddata/xcschemes/App.xcscheme +++ b/Tests/Fixtures/SPM/SPM.xcodeproj/xcshareddata/xcschemes/App.xcscheme @@ -1,10 +1,11 @@ + LastUpgradeVersion = "1430" + version = "1.7"> + buildImplicitDependencies = "YES" + runPostActionsOnFailure = "NO"> - - + shouldUseLaunchSchemeArgsEnv = "YES" + onlyGenerateCoverageForSpecifiedTargets = "NO"> + + + + + + + + + + diff --git a/Tests/Fixtures/SPM/project.yml b/Tests/Fixtures/SPM/project.yml index a34b360a7..7e8b3b064 100644 --- a/Tests/Fixtures/SPM/project.yml +++ b/Tests/Fixtures/SPM/project.yml @@ -6,20 +6,47 @@ packages: SwiftRoaring: url: https://github.com/piotte13/SwiftRoaring majorVersion: 1.0.4 - XcodeGen: + Prefire: + url: https://github.com/BarredEwe/Prefire + majorVersion: 1.4.1 + SwiftLocation: + url: https://github.com/malcommac/SwiftLocation + exactVersion: 6.0 + XcodeGen: path: ../../.. #XcodeGen itself + group: SPM + FooFeature: + path: FooFeature +aggregateTargets: + AggTarget: + buildToolPlugins: + - plugin: PrefirePlaybookPlugin + package: Prefire targets: App: type: application platform: iOS sources: [SPM] - scheme: {} + scheme: + testTargets: + - package: XcodeGen/XcodeGenKitTests + - Tests + buildToolPlugins: + - plugin: PrefirePlaybookPlugin + package: Prefire dependencies: - package: Codability + weak: true - package: SwiftRoaring product: SwiftRoaringDynamic embed: true - target: StaticLibrary + - package: XcodeGen + - package: SwiftLocation + - package: FooFeature + products: + - FooDomain + - FooUI Tests: type: bundle.unit-test platform: iOS @@ -35,3 +62,7 @@ targets: - package: SwiftRoaring product: SwiftRoaringDynamic - package: XcodeGen + - package: FooFeature + products: + - FooDomain + - FooUI diff --git a/Tests/Fixtures/TestProject/.lldbinit b/Tests/Fixtures/TestProject/.lldbinit new file mode 100644 index 000000000..e69de29bb diff --git a/Tests/Fixtures/TestProject/AnotherProject/AnotherProject.xcodeproj/project.pbxproj b/Tests/Fixtures/TestProject/AnotherProject/AnotherProject.xcodeproj/project.pbxproj index 2e4c099f7..50593a11b 100644 --- a/Tests/Fixtures/TestProject/AnotherProject/AnotherProject.xcodeproj/project.pbxproj +++ b/Tests/Fixtures/TestProject/AnotherProject/AnotherProject.xcodeproj/project.pbxproj @@ -3,13 +3,14 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 77; objects = { /* Begin PBXFileReference section */ - 6023D61BF2C57E6AE09CE7A3 /* BundleX.bundle */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "wrapper.plug-in"; path = BundleX.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 6023D61BF2C57E6AE09CE7A3 /* BundleX.bundle */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = BundleX.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 60D6679FB526839EAFEA2EEE /* config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = config.xcconfig; sourceTree = ""; }; D6340FC7DEBC81E0127BAFD6 /* ExternalTarget.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ExternalTarget.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F1EFFCA88BFC3A1DD2D89DA7 /* BundleY.bundle */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = BundleY.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXGroup section */ @@ -34,6 +35,7 @@ isa = PBXGroup; children = ( 6023D61BF2C57E6AE09CE7A3 /* BundleX.bundle */, + F1EFFCA88BFC3A1DD2D89DA7 /* BundleY.bundle */, D6340FC7DEBC81E0127BAFD6 /* ExternalTarget.framework */, ); name = Products; @@ -41,7 +43,42 @@ }; /* End PBXGroup section */ +/* Begin PBXLegacyTarget section */ + A6D9FB94860C005F0B723B5F /* IncludedLegacy */ = { + isa = PBXLegacyTarget; + buildConfigurationList = AC68886F4CEE08D3593D0877 /* Build configuration list for PBXLegacyTarget "IncludedLegacy" */; + buildPhases = ( + 69078D1DA3F942D5BC752081 /* Sources */, + ); + buildToolPath = /usr/bin/true; + buildWorkingDirectory = .; + dependencies = ( + ); + name = IncludedLegacy; + packageProductDependencies = ( + ); + passBuildSettingsInEnvironment = 0; + productName = IncludedLegacy; + }; +/* End PBXLegacyTarget section */ + /* Begin PBXNativeTarget section */ + 201AC870383B8CD218AD0FAB /* BundleY */ = { + isa = PBXNativeTarget; + buildConfigurationList = EF9E2AA4073D3B2EC8195688 /* Build configuration list for PBXNativeTarget "BundleY" */; + buildPhases = ( + ); + buildRules = ( + ); + dependencies = ( + ); + name = BundleY; + packageProductDependencies = ( + ); + productName = BundleY; + productReference = F1EFFCA88BFC3A1DD2D89DA7 /* BundleY.bundle */; + productType = "com.apple.product-type.bundle"; + }; 63A2D4898D974A06E85B07F8 /* BundleX */ = { isa = PBXNativeTarget; buildConfigurationList = 32C09717E388BCD9DB9E513C /* Build configuration list for PBXNativeTarget "BundleX" */; @@ -52,6 +89,8 @@ dependencies = ( ); name = BundleX; + packageProductDependencies = ( + ); productName = BundleX; productReference = 6023D61BF2C57E6AE09CE7A3 /* BundleX.bundle */; productType = "com.apple.product-type.bundle"; @@ -67,6 +106,8 @@ dependencies = ( ); name = ExternalTarget; + packageProductDependencies = ( + ); productName = ExternalTarget; productReference = D6340FC7DEBC81E0127BAFD6 /* ExternalTarget.framework */; productType = "com.apple.product-type.framework"; @@ -77,28 +118,38 @@ 1B166EB49192B73A9DD8E108 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; - TargetAttributes = { - }; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1430; }; buildConfigurationList = 3DFC1105373EDB6483D4BC5D /* Build configuration list for PBXProject "AnotherProject" */; - compatibilityVersion = "Xcode 10.0"; + compatibilityVersion = "Xcode 14.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = 4E8CFA4275C972686621210C; + minimizedProjectReferenceProxies = 1; + preferredProjectObjectVersion = 77; projectDirPath = ""; projectRoot = ""; targets = ( 63A2D4898D974A06E85B07F8 /* BundleX */, + 201AC870383B8CD218AD0FAB /* BundleY */, E76A5F5E363E470416D3B487 /* ExternalTarget */, + A6D9FB94860C005F0B723B5F /* IncludedLegacy */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ + 69078D1DA3F942D5BC752081 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; F08051CAC5E72EEEB8FB447B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -120,6 +171,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -135,6 +187,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -153,11 +206,13 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; - VALIDATE_PRODUCT = YES; }; name = "Test Release"; }; @@ -171,6 +226,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -186,6 +242,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -204,11 +261,13 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; - VALIDATE_PRODUCT = YES; }; name = "Production Release"; }; @@ -223,6 +282,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -238,6 +298,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -256,11 +317,13 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; - VALIDATE_PRODUCT = YES; }; name = "Staging Release"; }; @@ -273,11 +336,13 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.external; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; @@ -285,6 +350,19 @@ }; name = "Test Debug"; }; + 1CE986A8B593E707AB71BDBA /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Production Release"; + }; 270E1D32776D2D196D435FDA /* Staging Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -296,6 +374,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -311,6 +390,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -335,7 +415,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MTL_ENABLE_DEBUG_INFO = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; @@ -345,6 +426,18 @@ }; name = "Staging Debug"; }; + 2D7C07F1D50007A04EF6C0EE /* Staging Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Staging Debug"; + }; 30E2E954A636A240B1CE5C15 /* Staging Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -354,11 +447,13 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.external; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; @@ -375,11 +470,13 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.external; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; @@ -396,11 +493,13 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.external; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; @@ -411,6 +510,7 @@ 49FA7F235A6CA1F941192151 /* Staging Release */ = { isa = XCBuildConfiguration; buildSettings = { + GENERATE_INFOPLIST_FILE = YES; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -423,6 +523,7 @@ 4D621C4C28C8614EA5D6ADC2 /* Production Debug */ = { isa = XCBuildConfiguration; buildSettings = { + GENERATE_INFOPLIST_FILE = YES; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -432,9 +533,22 @@ }; name = "Production Debug"; }; + 5280A75613CFD83BA7EE6AD4 /* Test Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Test Release"; + }; 56ADF89C9058B2C25F6C80CE /* Staging Debug */ = { isa = XCBuildConfiguration; buildSettings = { + GENERATE_INFOPLIST_FILE = YES; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -454,6 +568,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -469,6 +584,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -493,7 +609,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MTL_ENABLE_DEBUG_INFO = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; @@ -503,9 +620,23 @@ }; name = "Production Debug"; }; + 58F418B6745A09C6479FDD6E /* Staging Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Staging Release"; + }; 5F14CE04E33ACD729A0EE6B6 /* Test Debug */ = { isa = XCBuildConfiguration; buildSettings = { + GENERATE_INFOPLIST_FILE = YES; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -524,11 +655,13 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.external; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; @@ -536,6 +669,30 @@ }; name = "Production Release"; }; + 683A510C4120CF5D216E1667 /* Test Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Test Debug"; + }; + 6C48009F842BEC2467546ADF /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Production Debug"; + }; 7919FDD28F9A535EA26FB151 /* Test Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -545,11 +702,13 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.external; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; @@ -557,9 +716,23 @@ }; name = "Test Release"; }; + 816E80EA88CB645CE988138C /* Staging Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Staging Debug"; + }; 9BD6CAD5463121A1C3FED138 /* Production Release */ = { isa = XCBuildConfiguration; buildSettings = { + GENERATE_INFOPLIST_FILE = YES; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -581,6 +754,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -596,6 +770,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -620,7 +795,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MTL_ENABLE_DEBUG_INFO = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; @@ -633,6 +809,57 @@ C7A4FCD4E277AD34B36E5185 /* Test Release */ = { isa = XCBuildConfiguration; buildSettings = { + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Test Release"; + }; + CB49A0C6C6CF7FC894E453BE /* Staging Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Staging Release"; + }; + E1A76975608AFAA966038B93 /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Production Release"; + }; + E7907C46C6282D78E009083B /* Test Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Test Debug"; + }; + FB66976FF75B2B0B255D5AA4 /* Test Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GENERATE_INFOPLIST_FILE = YES; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -642,6 +869,19 @@ }; name = "Test Release"; }; + FD9323224BE5A91248B7BEF2 /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Production Debug"; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -671,6 +911,19 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = "Production Debug"; }; + AC68886F4CEE08D3593D0877 /* Build configuration list for PBXLegacyTarget "IncludedLegacy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6C48009F842BEC2467546ADF /* Production Debug */, + E1A76975608AFAA966038B93 /* Production Release */, + 2D7C07F1D50007A04EF6C0EE /* Staging Debug */, + CB49A0C6C6CF7FC894E453BE /* Staging Release */, + 683A510C4120CF5D216E1667 /* Test Debug */, + 5280A75613CFD83BA7EE6AD4 /* Test Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Production Debug"; + }; B5049D72EC10A5C87F29B6B1 /* Build configuration list for PBXNativeTarget "ExternalTarget" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -684,6 +937,19 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = "Production Debug"; }; + EF9E2AA4073D3B2EC8195688 /* Build configuration list for PBXNativeTarget "BundleY" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FD9323224BE5A91248B7BEF2 /* Production Debug */, + 1CE986A8B593E707AB71BDBA /* Production Release */, + 816E80EA88CB645CE988138C /* Staging Debug */, + 58F418B6745A09C6479FDD6E /* Staging Release */, + E7907C46C6282D78E009083B /* Test Debug */, + FB66976FF75B2B0B255D5AA4 /* Test Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Production Debug"; + }; /* End XCConfigurationList section */ }; rootObject = 1B166EB49192B73A9DD8E108 /* Project object */; diff --git a/Tests/Fixtures/TestProject/AnotherProject/AnotherProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Tests/Fixtures/TestProject/AnotherProject/AnotherProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 21190769f..919434a62 100644 --- a/Tests/Fixtures/TestProject/AnotherProject/AnotherProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/Tests/Fixtures/TestProject/AnotherProject/AnotherProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/Tests/Fixtures/TestProject/AnotherProject/project.yml b/Tests/Fixtures/TestProject/AnotherProject/project.yml index 5dbb17be0..f86b69aec 100644 --- a/Tests/Fixtures/TestProject/AnotherProject/project.yml +++ b/Tests/Fixtures/TestProject/AnotherProject/project.yml @@ -1,11 +1,30 @@ name: AnotherProject include: [../environments.yml] +options: + useBaseInternationalization: false configFiles: Test Debug: ../Configs/config.xcconfig targets: BundleX: type: bundle platform: iOS + settings: + GENERATE_INFOPLIST_FILE: YES + BundleY: + type: bundle + platform: iOS + settings: + GENERATE_INFOPLIST_FILE: YES ExternalTarget: type: framework platform: iOS + settings: + GENERATE_INFOPLIST_FILE: YES + PRODUCT_BUNDLE_IDENTIFIER: com.project.external + IncludedLegacy: + type: "" + platform: iOS + legacy: + toolPath: /usr/bin/true + workingDirectory: . + diff --git a/Tests/Fixtures/TestProject/App_Clip/AppDelegate.swift b/Tests/Fixtures/TestProject/App_Clip/AppDelegate.swift new file mode 100644 index 000000000..cbe822167 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_Clip/AppDelegate.swift @@ -0,0 +1,14 @@ +import Framework +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + _ = FrameworkStruct() + return true + } +} diff --git a/Tests/Fixtures/TestProject/App_Clip/Assets.xcassets/AppIcon.appiconset/Contents.json b/Tests/Fixtures/TestProject/App_Clip/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..d8db8d65f --- /dev/null +++ b/Tests/Fixtures/TestProject/App_Clip/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Tests/Fixtures/TestProject/App_Clip/Base.lproj/LaunchScreen.storyboard b/Tests/Fixtures/TestProject/App_Clip/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 000000000..fdf3f97d1 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_Clip/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/Fixtures/TestProject/App_Clip/Base.lproj/Main.storyboard b/Tests/Fixtures/TestProject/App_Clip/Base.lproj/Main.storyboard new file mode 100644 index 000000000..42545a50d --- /dev/null +++ b/Tests/Fixtures/TestProject/App_Clip/Base.lproj/Main.storyboard @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/Fixtures/TestProject/App_Clip/Clip.entitlements b/Tests/Fixtures/TestProject/App_Clip/Clip.entitlements new file mode 100644 index 000000000..92112b0ee --- /dev/null +++ b/Tests/Fixtures/TestProject/App_Clip/Clip.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.developer.parent-application-identifiers + + $(AppIdentifierPrefix)com.project.appwithclip + + com.apple.security.application-groups + group.com.app + + diff --git a/Tests/Fixtures/TestProject/App_Clip/Info.plist b/Tests/Fixtures/TestProject/App_Clip/Info.plist new file mode 100644 index 000000000..2989640a8 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_Clip/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 42.1 + CFBundleVersion + 2 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Tests/Fixtures/TestProject/App_Clip/ViewController.swift b/Tests/Fixtures/TestProject/App_Clip/ViewController.swift new file mode 100644 index 000000000..a44b02a48 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_Clip/ViewController.swift @@ -0,0 +1,15 @@ +import Contacts +import UIKit + +class ViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + _ = CNContact() + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } +} diff --git a/Tests/Fixtures/TestProject/App_Clip_Tests/Info.plist b/Tests/Fixtures/TestProject/App_Clip_Tests/Info.plist new file mode 100644 index 000000000..6c6c23c43 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_Clip_Tests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Tests/Fixtures/TestProject/App_Clip_Tests/TestProjectTests.swift b/Tests/Fixtures/TestProject/App_Clip_Tests/TestProjectTests.swift new file mode 100644 index 000000000..f5c77a544 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_Clip_Tests/TestProjectTests.swift @@ -0,0 +1,26 @@ +import XCTest + +class TestProjectTests: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() { + // This is an example of a performance test case. + measure { + // Put the code you want to measure the time of here. + } + } +} diff --git a/Tests/Fixtures/TestProject/App_Clip_UITests/Info.plist b/Tests/Fixtures/TestProject/App_Clip_UITests/Info.plist new file mode 100644 index 000000000..6c6c23c43 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_Clip_UITests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Tests/Fixtures/TestProject/App_Clip_UITests/TestProjectUITests.swift b/Tests/Fixtures/TestProject/App_Clip_UITests/TestProjectUITests.swift new file mode 100644 index 000000000..357046659 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_Clip_UITests/TestProjectUITests.swift @@ -0,0 +1,26 @@ +import XCTest + +class TestProjectUITests: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() { + // This is an example of a performance test case. + measure { + // Put the code you want to measure the time of here. + } + } +} diff --git a/Tests/Fixtures/TestProject/App_iOS/AppDelegate.swift b/Tests/Fixtures/TestProject/App_iOS/AppDelegate.swift index 2c79185ee..10c98bab3 100644 --- a/Tests/Fixtures/TestProject/App_iOS/AppDelegate.swift +++ b/Tests/Fixtures/TestProject/App_iOS/AppDelegate.swift @@ -7,10 +7,16 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. + + // file from a framework _ = FrameworkStruct() + // Standalone files added to project by path-to-file. _ = standaloneHello() + + // file in a synced folder + _ = SyncedStruct() + return true } } diff --git a/Tests/Fixtures/TestProject/App_iOS/App_iOS.xctestplan b/Tests/Fixtures/TestProject/App_iOS/App_iOS.xctestplan new file mode 100644 index 000000000..53056d698 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_iOS/App_iOS.xctestplan @@ -0,0 +1,45 @@ +{ + "configurations" : [ + { + "id" : "AC4AE1EF-F65C-4037-8994-D607D2E5841E", + "name" : "Configuration 1", + "options" : { + + } + } + ], + "defaultOptions" : { + "commandLineArgumentEntries" : [ + { + "argument" : "MyDisabledArgument", + "enabled" : false + }, + { + "argument" : "MyEnabledArgument" + } + ], + "mainThreadCheckerEnabled" : false, + "targetForVariableExpansion" : { + "containerPath" : "container:Project.xcodeproj", + "identifier" : "0867B0DACEF28C11442DE8F7", + "name" : "App_iOS" + } + }, + "testTargets" : [ + { + "target" : { + "containerPath" : "container:Project.xcodeproj", + "identifier" : "DC2F16BAA6E13B44AB62F888", + "name" : "App_iOS_Tests" + } + }, + { + "target" : { + "containerPath" : "container:Project.xcodeproj", + "identifier" : "F674B2CFC4738EEC49BAD0DA", + "name" : "App_iOS_UITests" + } + } + ], + "version" : 1 +} diff --git a/Tests/Fixtures/TestProject/App_iOS/Configuration.storekit b/Tests/Fixtures/TestProject/App_iOS/Configuration.storekit new file mode 100644 index 000000000..aa066b3fe --- /dev/null +++ b/Tests/Fixtures/TestProject/App_iOS/Configuration.storekit @@ -0,0 +1,29 @@ +{ + "products" : [ + { + "displayPrice" : "0.00", + "familyShareable" : false, + "internalID" : "6D7919A3", + "localizations" : [ + { + "description" : "", + "displayName" : "", + "locale" : "en_US" + } + ], + "productID" : "com.xcodegen.0", + "referenceName" : null, + "type" : "Consumable" + } + ], + "settings" : { + + }, + "subscriptionGroups" : [ + + ], + "version" : { + "major" : 1, + "minor" : 0 + } +} diff --git a/Tests/Fixtures/TestProject/App_iOS/Documentation.docc/Documentation.md b/Tests/Fixtures/TestProject/App_iOS/Documentation.docc/Documentation.md new file mode 100644 index 000000000..7afe5dd3d --- /dev/null +++ b/Tests/Fixtures/TestProject/App_iOS/Documentation.docc/Documentation.md @@ -0,0 +1,7 @@ +# ``App_Clip`` + +Test + +## Overview + +Test diff --git a/Tests/Fixtures/TestProject/App_iOS/Documentation.docc/Resources/resource.png b/Tests/Fixtures/TestProject/App_iOS/Documentation.docc/Resources/resource.png new file mode 100644 index 000000000..e69de29bb diff --git a/Tests/Fixtures/TestProject/App_iOS/Resource.abc b/Tests/Fixtures/TestProject/App_iOS/Resource.abc new file mode 100644 index 000000000..e69de29bb diff --git a/Tests/Fixtures/TestProject/App_iOS/Resource.abcd/File.json b/Tests/Fixtures/TestProject/App_iOS/Resource.abcd/File.json new file mode 100644 index 000000000..e69de29bb diff --git a/Tests/Fixtures/TestProject/App_macOS/Info.plist b/Tests/Fixtures/TestProject/App_macOS/App-Info.plist similarity index 100% rename from Tests/Fixtures/TestProject/App_macOS/Info.plist rename to Tests/Fixtures/TestProject/App_macOS/App-Info.plist diff --git a/Tests/Fixtures/TestProject/App_supportedDestinations/Info.generated.plist b/Tests/Fixtures/TestProject/App_supportedDestinations/Info.generated.plist new file mode 100644 index 000000000..8bed04c06 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_supportedDestinations/Info.generated.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + TestApp + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1.0.0 + + diff --git a/Tests/Fixtures/TestProject/App_supportedDestinations/Sources/MyAppApp.swift b/Tests/Fixtures/TestProject/App_supportedDestinations/Sources/MyAppApp.swift new file mode 100644 index 000000000..2db0d8841 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_supportedDestinations/Sources/MyAppApp.swift @@ -0,0 +1,10 @@ +import SwiftUI + +@main +struct MyAppApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/Tests/Fixtures/TestProject/App_supportedDestinations/Sources/iOS/ContentView.swift b/Tests/Fixtures/TestProject/App_supportedDestinations/Sources/iOS/ContentView.swift new file mode 100644 index 000000000..1e32a55a0 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_supportedDestinations/Sources/iOS/ContentView.swift @@ -0,0 +1,13 @@ +import SwiftUI + +struct ContentView: View { + var body: some View { + VStack { + Image(systemName: "globe") + .imageScale(.large) + .foregroundColor(.accentColor) + Text("Hello, world! on iOS") + } + .padding() + } +} diff --git a/Tests/Fixtures/TestProject/App_supportedDestinations/Sources/tvOS/ContentView.swift b/Tests/Fixtures/TestProject/App_supportedDestinations/Sources/tvOS/ContentView.swift new file mode 100644 index 000000000..f0512afc0 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_supportedDestinations/Sources/tvOS/ContentView.swift @@ -0,0 +1,13 @@ +import SwiftUI + +struct ContentView: View { + var body: some View { + VStack { + Image(systemName: "house") + .imageScale(.large) + .foregroundColor(.accentColor) + Text("Hello, world! tvOS") + } + .padding() + } +} diff --git a/Tests/Fixtures/TestProject/App_supportedDestinations/Storyboards/LaunchScreen.storyboard b/Tests/Fixtures/TestProject/App_supportedDestinations/Storyboards/LaunchScreen.storyboard new file mode 100644 index 000000000..865e9329f --- /dev/null +++ b/Tests/Fixtures/TestProject/App_supportedDestinations/Storyboards/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/File_MACCATALYST.swift b/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/File_MACCATALYST.swift new file mode 100644 index 000000000..fecc4ab44 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/File_MACCATALYST.swift @@ -0,0 +1 @@ +import Foundation diff --git a/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/File_ios.swift b/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/File_ios.swift new file mode 100644 index 000000000..fecc4ab44 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/File_ios.swift @@ -0,0 +1 @@ +import Foundation diff --git a/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/File_macOS.swift b/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/File_macOS.swift new file mode 100644 index 000000000..fecc4ab44 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/File_macOS.swift @@ -0,0 +1 @@ +import Foundation diff --git a/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/File_tvOs.swift b/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/File_tvOs.swift new file mode 100644 index 000000000..fecc4ab44 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/File_tvOs.swift @@ -0,0 +1 @@ +import Foundation diff --git a/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/TVOS/File_B.swift b/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/TVOS/File_B.swift new file mode 100644 index 000000000..fecc4ab44 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/TVOS/File_B.swift @@ -0,0 +1 @@ +import Foundation diff --git a/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/iOs/File_A.swift b/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/iOs/File_A.swift new file mode 100644 index 000000000..fecc4ab44 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/iOs/File_A.swift @@ -0,0 +1 @@ +import Foundation diff --git a/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/macCatalyst/File_D.swift b/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/macCatalyst/File_D.swift new file mode 100644 index 000000000..fecc4ab44 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/macCatalyst/File_D.swift @@ -0,0 +1 @@ +import Foundation diff --git a/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/macos/File_C.swift b/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/macos/File_C.swift new file mode 100644 index 000000000..fecc4ab44 --- /dev/null +++ b/Tests/Fixtures/TestProject/App_supportedDestinations/TestResources/macos/File_C.swift @@ -0,0 +1 @@ +import Foundation diff --git a/Tests/Fixtures/TestProject/CrossOverlayFramework/CrossOverlayFramework.swiftcrossimport/Framework.swiftoverlay b/Tests/Fixtures/TestProject/CrossOverlayFramework/CrossOverlayFramework.swiftcrossimport/Framework.swiftoverlay new file mode 100644 index 000000000..f186c2740 --- /dev/null +++ b/Tests/Fixtures/TestProject/CrossOverlayFramework/CrossOverlayFramework.swiftcrossimport/Framework.swiftoverlay @@ -0,0 +1,5 @@ +%YAML 1.2 +--- +version: 1 +modules: + - name: _CrossOverlayFramework_Framework diff --git a/Tests/Fixtures/TestProject/CrossOverlayFramework/FrameworkFile.swift b/Tests/Fixtures/TestProject/CrossOverlayFramework/FrameworkFile.swift new file mode 100644 index 000000000..f003efd55 --- /dev/null +++ b/Tests/Fixtures/TestProject/CrossOverlayFramework/FrameworkFile.swift @@ -0,0 +1,6 @@ +import Foundation + +public struct FrameworkStruct { + + public init() {} +} diff --git a/Tests/Fixtures/TestProject/CrossOverlayFramework/Info.plist b/Tests/Fixtures/TestProject/CrossOverlayFramework/Info.plist new file mode 100644 index 000000000..37c17ea7f --- /dev/null +++ b/Tests/Fixtures/TestProject/CrossOverlayFramework/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.2 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/Tests/Fixtures/TestProject/CrossOverlayFramework/MyFramework.h b/Tests/Fixtures/TestProject/CrossOverlayFramework/MyFramework.h new file mode 100644 index 000000000..739f2414b --- /dev/null +++ b/Tests/Fixtures/TestProject/CrossOverlayFramework/MyFramework.h @@ -0,0 +1,9 @@ +// +// MyFramework.h +// MyFramework +// +// Created by Yonas Kolb on 21/7/17. +// Copyright © 2017 Yonas Kolb. All rights reserved. +// + + diff --git a/Tests/Fixtures/TestProject/CrossOverlayFramework/Project.xcodeproj/project.pbxproj b/Tests/Fixtures/TestProject/CrossOverlayFramework/Project.xcodeproj/project.pbxproj new file mode 100644 index 000000000..e69de29bb diff --git a/Tests/Fixtures/TestProject/DriverKit Driver/Driver.cpp b/Tests/Fixtures/TestProject/DriverKit Driver/Driver.cpp new file mode 100644 index 000000000..875a03948 --- /dev/null +++ b/Tests/Fixtures/TestProject/DriverKit Driver/Driver.cpp @@ -0,0 +1,22 @@ +// +// Driver.cpp +// Driver +// +// Created by Vlad Gorlov on 18.06.21. +// + +#include + +#include +#include + +#include "Driver.h" + +kern_return_t +IMPL(Driver, Start) +{ + kern_return_t ret; + ret = Start(provider, SUPERDISPATCH); + os_log(OS_LOG_DEFAULT, "Hello World"); + return ret; +} diff --git a/Tests/Fixtures/TestProject/DriverKit Driver/Driver.entitlements b/Tests/Fixtures/TestProject/DriverKit Driver/Driver.entitlements new file mode 100644 index 000000000..852fa1a47 --- /dev/null +++ b/Tests/Fixtures/TestProject/DriverKit Driver/Driver.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/Tests/Fixtures/TestProject/DriverKit Driver/Driver.iig b/Tests/Fixtures/TestProject/DriverKit Driver/Driver.iig new file mode 100644 index 000000000..886a04c91 --- /dev/null +++ b/Tests/Fixtures/TestProject/DriverKit Driver/Driver.iig @@ -0,0 +1,21 @@ +// +// Driver.iig +// Driver +// +// Created by Vlad Gorlov on 18.06.21. +// + +#ifndef Driver_h +#define Driver_h + +#include +#include + +class Driver: public IOService +{ +public: + virtual kern_return_t + Start(IOService * provider) override; +}; + +#endif /* Driver_h */ diff --git a/Tests/Fixtures/TestProject/DriverKit Driver/Info.plist b/Tests/Fixtures/TestProject/DriverKit Driver/Info.plist new file mode 100644 index 000000000..fd5d03af8 --- /dev/null +++ b/Tests/Fixtures/TestProject/DriverKit Driver/Info.plist @@ -0,0 +1,46 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + IOKitPersonalities + + Driver + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleIdentifierKernel + com.apple.kpi.iokit + IOClass + IOUserService + IOMatchCategory + com.apple.null.driver + IOProviderClass + IOUserResources + IOResourceMatch + IOKit + IOUserClass + Driver + IOUserServerName + com.apple.null.driver + + + OSBundleUsageDescription + + + diff --git a/Tests/Fixtures/TestProject/EndpointSecurity Extension/EndpointSecurity.entitlements b/Tests/Fixtures/TestProject/EndpointSecurity Extension/EndpointSecurity.entitlements new file mode 100644 index 000000000..03a3d8341 --- /dev/null +++ b/Tests/Fixtures/TestProject/EndpointSecurity Extension/EndpointSecurity.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.developer.endpoint-security.client + + com.apple.security.application-groups + + $(TeamIdentifierPrefix)com.example.app-group + + + diff --git a/Tests/Fixtures/TestProject/EndpointSecurity Extension/Info.plist b/Tests/Fixtures/TestProject/EndpointSecurity Extension/Info.plist new file mode 100644 index 000000000..d787bc3cd --- /dev/null +++ b/Tests/Fixtures/TestProject/EndpointSecurity Extension/Info.plist @@ -0,0 +1,28 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + EndpointSecurity + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSSystemExtensionUsageDescription + + + diff --git a/Tests/Fixtures/TestProject/EndpointSecurity Extension/main.swift b/Tests/Fixtures/TestProject/EndpointSecurity Extension/main.swift new file mode 100644 index 000000000..d163fadda --- /dev/null +++ b/Tests/Fixtures/TestProject/EndpointSecurity Extension/main.swift @@ -0,0 +1,22 @@ +// +// main.swift +// EndpointSecurity +// +// Created by Vlad Gorlov on 18.06.21. +// + +import Foundation +import EndpointSecurity + +var client: OpaquePointer? + +// Create the client +let res = es_new_client(&client) { (client, message) in + // Do processing on the message received +} + +if res != ES_NEW_CLIENT_RESULT_SUCCESS { + exit(EXIT_FAILURE) +} + +dispatchMain() diff --git a/Tests/Fixtures/TestProject/ExtensionKit Extension/EntryPoint.swift b/Tests/Fixtures/TestProject/ExtensionKit Extension/EntryPoint.swift new file mode 100644 index 000000000..0e665c55f --- /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 000000000..8d15acbed --- /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 000000000..0449c505c --- /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/Network Extension/FilterDataProvider.swift b/Tests/Fixtures/TestProject/Network Extension/FilterDataProvider.swift new file mode 100644 index 000000000..5a5d4dd38 --- /dev/null +++ b/Tests/Fixtures/TestProject/Network Extension/FilterDataProvider.swift @@ -0,0 +1,26 @@ +// +// FilterDataProvider.swift +// NetworkExtension +// +// Created by Vlad Gorlov on 18.06.21. +// + +import NetworkExtension + +class FilterDataProvider: NEFilterDataProvider { + + override func startFilter(completionHandler: @escaping (Error?) -> Void) { + // Add code to initialize the filter. + completionHandler(nil) + } + + override func stopFilter(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { + // Add code to clean up filter resources. + completionHandler() + } + + override func handleNewFlow(_ flow: NEFilterFlow) -> NEFilterNewFlowVerdict { + // Add code to determine if the flow should be dropped or not, downloading new rules if required. + return .allow() + } +} diff --git a/Tests/Fixtures/TestProject/Network Extension/Info.plist b/Tests/Fixtures/TestProject/Network Extension/Info.plist new file mode 100644 index 000000000..88c7ae8f5 --- /dev/null +++ b/Tests/Fixtures/TestProject/Network Extension/Info.plist @@ -0,0 +1,38 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + NetworkExtension + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSSystemExtensionUsageDescription + + NetworkExtension + + NEMachServiceName + $(TeamIdentifierPrefix)com.example.app-group.MySystemExtension + NEProviderClasses + + com.apple.networkextension.filter-data + $(PRODUCT_MODULE_NAME).FilterDataProvider + + + + diff --git a/Tests/Fixtures/TestProject/Network Extension/NetworkExtension.entitlements b/Tests/Fixtures/TestProject/Network Extension/NetworkExtension.entitlements new file mode 100644 index 000000000..b8ae39612 --- /dev/null +++ b/Tests/Fixtures/TestProject/Network Extension/NetworkExtension.entitlements @@ -0,0 +1,19 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.application-groups + + $(TeamIdentifierPrefix)com.example.app-group + + com.apple.developer.networking.networkextension + + packet-tunnel-provider + app-proxy-provider + content-filter-provider + dns-proxy + + + diff --git a/Tests/Fixtures/TestProject/Network Extension/main.swift b/Tests/Fixtures/TestProject/Network Extension/main.swift new file mode 100644 index 000000000..2313f84f4 --- /dev/null +++ b/Tests/Fixtures/TestProject/Network Extension/main.swift @@ -0,0 +1,15 @@ +// +// main.swift +// NetworkExtension +// +// Created by Vlad Gorlov on 18.06.21. +// + +import Foundation +import NetworkExtension + +autoreleasepool { + NEProvider.startSystemExtensionMode() +} + +dispatchMain() diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj b/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj index 7fe07ec4b..10ff1c3a2 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 77; objects = { /* Begin PBXAggregateTarget section */ @@ -18,6 +18,8 @@ 106CDB4BCFD183241A565E6C /* PBXTargetDependency */, ); name = SuperTarget; + packageProductDependencies = ( + ); productName = SuperTarget; }; /* End PBXAggregateTarget section */ @@ -25,24 +27,35 @@ /* Begin PBXBuildFile section */ 01BFA2C4D9C5BBC72C015AA8 /* MyFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A58A16491CDDF968B0D56DE /* MyFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; 02F9D686CBA6068A8EE58026 /* StaticLibrary_ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D0C79A8C750EC0DE748C463 /* StaticLibrary_ObjC.m */; }; + 03D1147528CED90EC1D844CE /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C7F9636B706AC92629D0B48 /* XCTest.framework */; }; + 03FFCE664129864A8F167C2F /* FrameworkFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81E4CCE342955E0E934BE533 /* FrameworkFile.swift */; }; + 052D6B4572FBF002286865D7 /* CrossOverlayFramework.swiftcrossimport in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8DD7A61B07AD2F91BDECC255 /* CrossOverlayFramework.swiftcrossimport */; }; + 06F1750F0E45E4822F806523 /* MyFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 576675973B56A96047CB4944 /* MyFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0786F9C725AD215C4F915BB5 /* MyFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A58A16491CDDF968B0D56DE /* MyFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 078FAAF5C2B851C7D5EA714F /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D296BB7355994040E197A1EE /* Result.framework */; }; 079B6E02AF21664AB08E621C /* TestProjectUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 587B9E9A3533E965CA602B76 /* TestProjectUITests.swift */; }; + 0927149520F12314CE8B4079 /* TestFramework.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E43116070AFEF5D8C3A5A957 /* TestFramework.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 0932FB6FB887D7D6F7727CB7 /* Driver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 432E2C071A4B6B3757BEA13E /* Driver.cpp */; }; 09617AB755651FFEB2564CBC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F1A2F579A6F79C62DDA0571 /* AppDelegate.swift */; settings = {COMPILER_FLAGS = "-Werror"; }; }; 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, ); }; }; - 1551370B0ACAC632E15C853B /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF47010E7368583405AA50CB /* SwiftyJSON.framework */; }; + 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 */; }; + 1B485D6584C3B47AC58831C6 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18722C61B05FFF4CC63D5755 /* ContentView.swift */; platformFilters = (tvos, ); }; 1BC891D89980D82738D963F3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 74FBDFA5CB063F6001AD8ACD /* Main.storyboard */; }; 1E03FC7312293997599C6435 /* Empty.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 068EDF47F0B087F6A4052AC0 /* Empty.h */; }; 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, ); }; }; + 1EFFFE113C5E54A91148D3EB /* FrameworkFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81E4CCE342955E0E934BE533 /* FrameworkFile.swift */; }; + 1F9168A43FD8E2FCC2699E14 /* Documentation.docc in Sources */ = {isa = PBXBuildFile; fileRef = B5C943D39DD7812CAB94B614 /* Documentation.docc */; settings = {COMPILER_FLAGS = "-Werror"; }; }; + 204958B9AD868004CCE6B779 /* App_watchOS Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 0D09D243DBCF9D32E239F1E8 /* App_watchOS Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 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 */; }; 21425F6DE3D493B6F1E33D21 /* Framework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 41FC82ED1C4C3B7B3D7B2FB7 /* Framework.framework */; }; 216B220EC7961DF7CA9188B7 /* StaticLibrary_ObjC.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5A2B916A11DCC2565241359F /* StaticLibrary_ObjC.h */; }; - 21CA04F29CD0DEB0DD27B808 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C5AC2545AE4D4F7F44E2E9B /* Result.framework */; }; - 262891CCD5F74316610437FA /* Framework2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3EF21DF245F66BEF5446AAEF /* Framework2.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 262891CCD5F74316610437FA /* Framework2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3EF21DF245F66BEF5446AAEF /* Framework2.framework */; platformFilter = ios; settings = {ATTRIBUTES = (Weak, ); }; }; 265B6A05C0198FD2EB485173 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93C033648A37D95027845BD3 /* main.swift */; }; + 2698ED273D0A5820B28CAD20 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D52EC9AA9FFD3B690C355068 /* LaunchScreen.storyboard */; platformFilters = (ios, ); }; 2730C6D0A35AED4ADD6EDF17 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0704B6CAFBB53E0EBB08F6B3 /* ViewController.swift */; settings = {COMPILER_FLAGS = "-Werror"; }; }; 28A96EBC76D53817AABDA91C /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 8AF20308873AEEEC4D8C45D1 /* Settings.bundle */; }; 2A5356FCC03EE312F1738C61 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09B82F603D981398F38D762E /* AppDelegate.swift */; }; @@ -50,80 +63,110 @@ 2B940E57041A72E6A39B6BF0 /* Interface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C872631362DDBAFCE71E5C66 /* Interface.storyboard */; }; 2C7C03B45571A13D472D6B23 /* iMessageApp.app in Resources */ = {isa = PBXBuildFile; fileRef = 9A87A926D563773658FB87FE /* iMessageApp.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 2FAE950E8FF2E7C0F7FF1FE9 /* Framework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8A9274BE42A03DC5DA1FAD04 /* Framework.framework */; }; - 307B5322FC5A220652BA6FE0 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D296BB7355994040E197A1EE /* Result.framework */; }; 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 */; }; 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, ); }; }; - 3BBCA6F76E5F212E9C55FB78 /* BundleX.bundle in Copy Bundle Resources */ = {isa = PBXBuildFile; fileRef = 45C12576F5AA694DD0CE2132 /* BundleX.bundle */; }; + 3A3BA9F91994D8B472C71F04 /* Swinject in Frameworks */ = {isa = PBXBuildFile; platformFilters = (tvos, ); productRef = C7F9B7EDE85527EFEA85D46D /* Swinject */; }; + 3BBCA6F76E5F212E9C55FB78 /* BundleX.bundle in Copy Bundle Resources */ = {isa = PBXBuildFile; fileRef = 45C12576F5AA694DD0CE2132 /* BundleX.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 3C5134EE524310ACF7B7CD6E /* ExtensionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CAF6C55B555E3E1352645B6 /* ExtensionDelegate.swift */; }; - 42BC5788871D1D838B253952 /* App_watchOS Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 0D09D243DBCF9D32E239F1E8 /* App_watchOS Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 3DF22C477446669094AC7C8C /* ExternalTarget.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = F6ADE654A3459AFDA2CC0CD3 /* ExternalTarget.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 447D59BE2E0993D7245EA247 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3797E591F302ECC0AA2FC607 /* Assets.xcassets */; }; 45E6702CD9C088FF1FC25F34 /* App_watchOS.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = A680BE9F68A255B0FB291AE6 /* App_watchOS.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 470D3493CDBFE56E2083A5FD /* BundleY.bundle in Copy Bundle Resources */ = {isa = PBXBuildFile; fileRef = E3958AB20082EA12D4D5E60C /* BundleY.bundle */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 47D1F439B8E6D287B3F3E8D1 /* MyFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A58A16491CDDF968B0D56DE /* MyFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; 47FC57B04A3AD83359F433EA /* StaticLibrary_ObjC.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5A2B916A11DCC2565241359F /* StaticLibrary_ObjC.h */; }; 49A4B8937BB5520B36EA33F0 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 814D72C2B921F60B759C2D4B /* Main.storyboard */; }; + 4B862F11762F6BB54E97E401 /* MyFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 576675973B56A96047CB4944 /* MyFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4C1504A05321046B3ED7A839 /* Framework2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB055761199DF36DB0C629A6 /* Framework2.framework */; }; 4CB673A7C0C11E04F8544BDB /* Contacts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FDB2B6A77D39CD5602F2125F /* Contacts.framework */; }; + 4DA7140FF84DBF39961F3409 /* NetworkSystemExtension.systemextension in Embed System Extensions */ = {isa = PBXBuildFile; fileRef = 2049B6DD2AFE85F9DC9F3EB3 /* NetworkSystemExtension.systemextension */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 4F6481557E2BEF8D749C37E3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 187E665975BB5611AF0F27E1 /* main.m */; }; + 5126CD91C2CB41C9B14B6232 /* DriverKitDriver.dext in Embed System Extensions */ = {isa = PBXBuildFile; fileRef = 83B5EC7EF81F7E4B6F426D4E /* DriverKitDriver.dext */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 52AD3276E068EB3396A292BB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D8A016580A3B8F72B820BFBF /* Assets.xcassets */; }; 535A98A3E3B74E09891D977F /* TestFramework.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E43116070AFEF5D8C3A5A957 /* TestFramework.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 5447AD526B2A1FD4262E2B61 /* FrameworkFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5F527F2590C14956518174 /* FrameworkFile.swift */; }; - 54A255D331B04F08583F5417 /* iMessageExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = D629E142AB87C681D4EC90F7 /* iMessageExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 5748F702ADFB9D85D0F97862 /* FrameworkFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5F527F2590C14956518174 /* FrameworkFile.swift */; }; + 57DC116CE5C9F93FBA529C2F /* MyFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 576675973B56A96047CB4944 /* MyFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; 58C18019E71E372F635A3FB4 /* MoreUnder.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA8718C7CD3BE86D9B1F5120 /* MoreUnder.swift */; }; 5D10822B0E7C33DD6979F656 /* Standalone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F5BD97AF0F94A15A5B7DDB7 /* Standalone.swift */; }; + 5E0369B907E239D1E6884ECF /* TestFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E43116070AFEF5D8C3A5A957 /* TestFramework.framework */; }; + 61401517ECCEB2362582B5DA /* libEndpointSecurity.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 0BC75409252FF15F540FBB7B /* libEndpointSecurity.tbd */; }; + 61516CAC12B2843FBC4572E6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 59DA55A04FA2366B5D0BEEFF /* Assets.xcassets */; }; 61601545B6BE00CA74A4E38F /* SceneKitCatalog.scnassets in Resources */ = {isa = PBXBuildFile; fileRef = C9E358FBE2B54D2B5C7FD609 /* SceneKitCatalog.scnassets */; }; 6241507B4947B0B65429587C /* ExternalTarget.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = F6ADE654A3459AFDA2CC0CD3 /* ExternalTarget.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 632774E7F21CCB386A76B2A8 /* MessagesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B198242976C3395E31FE000A /* MessagesViewController.swift */; }; - 63D8E7F00276736EDA62D227 /* Framework2.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3EF21DF245F66BEF5446AAEF /* Framework2.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 63D8E7F00276736EDA62D227 /* Framework2.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3EF21DF245F66BEF5446AAEF /* Framework2.framework */; platformFilter = ios; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 65B3BAC02D5FAE632719C984 /* Model.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = BF59AC868D227C92CA8B1B57 /* Model.xcmappingmodel */; }; 666AA5F3F63C8FD7C68A6CC5 /* MyFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A58A16491CDDF968B0D56DE /* MyFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; 666DEC173BC78C7641AB22EC /* File1.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE1343F2238429D4DA9D830B /* File1.swift */; }; 66C3C5E3C13325F351A3008F /* module.modulemap in CopyFiles */ = {isa = PBXBuildFile; fileRef = F2950763C4C568CC85021D18 /* module.modulemap */; }; + 6B0BCD3573931F7BE133B301 /* TestProjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D132EA69984F32DA9DC727B6 /* TestProjectTests.swift */; }; + 6C02002A4EE169CEBEC7BA7F /* FrameworkFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81E4CCE342955E0E934BE533 /* FrameworkFile.swift */; }; 6E8F8303759824631C8D9DA3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9E17D598D98065767A04740F /* Localizable.strings */; }; + 713F57A10C62F70058D7FB0A /* FrameworkFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81E4CCE342955E0E934BE533 /* FrameworkFile.swift */; }; 7148A4172BFA1CC22E6ED5DB /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 753001CDCEAA4C4E1AFF8E87 /* MainInterface.storyboard */; }; + 71A2AAC5934BDC9EDB6F0D9E /* libStaticLibrary_ObjC.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B221F5A689AD7D3AD52F56B8 /* libStaticLibrary_ObjC.a */; }; 747CAE14D196F5652E93353C /* Headers in Headers */ = {isa = PBXBuildFile; fileRef = 2E1E747C7BC434ADB80CC269 /* Headers */; settings = {ATTRIBUTES = (Public, ); }; }; 75F2774F183838AF34CA9B8A /* StaticLibrary_ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D0C79A8C750EC0DE748C463 /* StaticLibrary_ObjC.m */; }; + 76156B580B30704346296641 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C7F9636B706AC92629D0B48 /* XCTest.framework */; }; 768648ED7E93B6D888574144 /* module.modulemap in CopyFiles */ = {isa = PBXBuildFile; fileRef = F2950763C4C568CC85021D18 /* module.modulemap */; }; + 76DC6A4B18F434BAC239CC4A /* DriverKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0A428E67153BB40184F37BE /* DriverKit.framework */; }; + 76F3F9A5E2A4623430374F31 /* LocalizableStrings.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = E66ABD3EB14C9D63DEF5C532 /* LocalizableStrings.xcstrings */; }; + 77C3CB285572EA4BB7E201A7 /* App_Clip.app in Embed App Clips */ = {isa = PBXBuildFile; fileRef = 38DB679FF1CF4E379D1AB103 /* App_Clip.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 7A0DABBEA55B06E148C665A8 /* StaticLibrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC91042453E18DF74BA1C0F /* StaticLibrary.swift */; }; 7A8C78212CEAC6452DFAB00E /* FrameworkFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5F527F2590C14956518174 /* FrameworkFile.swift */; }; - 7C8FF0B857E390417134C10F /* Result.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D296BB7355994040E197A1EE /* Result.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 7F658343A505B824321E086B /* Headers in Headers */ = {isa = PBXBuildFile; fileRef = 2E1E747C7BC434ADB80CC269 /* Headers */; settings = {ATTRIBUTES = (Public, ); }; }; 803B7CE086CFBA409F9D1ED7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 108BB29172D27BE3BD1E7F35 /* Assets.xcassets */; }; 818D448D4DDD6649B5B26098 /* example.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = 28360ECA4D727FAA58557A81 /* example.mp4 */; settings = {ASSET_TAGS = (tag1, tag2, ); }; }; + 81DFAB3A7633CE97929B9B2A /* Framework.framework in Embed Dependencies */ = {isa = PBXBuildFile; fileRef = 41FC82ED1C4C3B7B3D7B2FB7 /* Framework.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 8267B75289E9D6C7B38FC426 /* DriverKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0A428E67153BB40184F37BE /* DriverKit.framework */; }; 87927928A8A3460166ACB819 /* SwiftFileInDotPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F430AABE04B7499B458D9DB /* SwiftFileInDotPath.swift */; settings = {COMPILER_FLAGS = "-Werror"; }; }; 900CFAD929CAEE3861127627 /* MyBundle.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 7B5068D64404C61A67A18458 /* MyBundle.bundle */; }; + 94FD20C3EA5EBCEC8783740C /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = BDCA996D141DD8A16B18D68F /* GoogleService-Info.plist */; }; 95DD9941E1529FD2AE1A191D /* StaticLibrary_ObjC.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5A2B916A11DCC2565241359F /* StaticLibrary_ObjC.h */; }; 96B55C0F660235FE6BDD8869 /* MyFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A58A16491CDDF968B0D56DE /* MyFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; 998CCB995347CBB8EDC95FB5 /* FrameworkFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5F527F2590C14956518174 /* FrameworkFile.swift */; }; 9AB50B81C29243936BB419E4 /* FrameworkFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5F527F2590C14956518174 /* FrameworkFile.swift */; }; + 9C92B7C89E5F0A10A34F5AA4 /* Framework.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8A9274BE42A03DC5DA1FAD04 /* Framework.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 9D80BD5FAE6BE61CFD74CF1B /* FrameworkFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5F527F2590C14956518174 /* FrameworkFile.swift */; }; - 9DF5931DAD58C35B830A0A75 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B76E17CE3574081D5BF45B44 /* Result.framework */; }; - A1AEAAB53EAEDA1C307871FA /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB178D03E75929F3F5B10C56 /* Result.framework */; }; + A1588BF3BFFE1DF7409CBA10 /* Framework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8A9274BE42A03DC5DA1FAD04 /* Framework.framework */; }; + A496E1DB82E16DA4099D1411 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C7F9636B706AC92629D0B48 /* XCTest.framework */; }; A59B3F08914812573AFF6C2D /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FD4A16C7B8FEB7F97F3CBE3F /* libz.dylib */; }; - A7D1A9942302569A9515696A /* Result.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D296BB7355994040E197A1EE /* Result.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + A7438C77A05D83E7016CF044 /* Framework2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A0DC40025AB59B688E758829 /* Framework2.framework */; }; + 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 */; }; AFF19412E9B35635D3AF48CB /* XPC_Service.m in Sources */ = {isa = PBXBuildFile; fileRef = 148B7C933698BCC4F1DBA979 /* XPC_Service.m */; }; - B142965C5AE9C6200BF65802 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C5AC2545AE4D4F7F44E2E9B /* Result.framework */; }; + B18C121B0A4D43ED8149D8E2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 79325B44B19B83EC6CEDBCC5 /* LaunchScreen.storyboard */; }; B20617116B230DED1F7AF5E5 /* libStaticLibrary_ObjC.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B221F5A689AD7D3AD52F56B8 /* libStaticLibrary_ObjC.a */; }; B2D43A31C184E34EF9CB743C /* Framework.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8A9274BE42A03DC5DA1FAD04 /* Framework.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + B358AB913543E62237FCC4E3 /* MyAppApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15A4363D659A58DA835DE8BA /* MyAppApp.swift */; }; B47F2629BFE5853767C8BB5E /* Contacts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FDB2B6A77D39CD5602F2125F /* Contacts.framework */; }; B49D3A51787E362DE4D0E78A /* SomeXPCService.xpc in CopyFiles */ = {isa = PBXBuildFile; fileRef = 70A8E15C81E454DC950C59F0 /* SomeXPCService.xpc */; }; + B502EF8F7605CBD038298F23 /* CrossOverlayFramework.swiftcrossimport in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8DD7A61B07AD2F91BDECC255 /* CrossOverlayFramework.swiftcrossimport */; }; B9F3C9E77019EC3423A7F5D8 /* TestProjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87DF9DCA8399E3214A7E27CF /* TestProjectTests.swift */; }; BAA1C1E3828F5D43546AF997 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 0BB1B49A91B892152D68ED76 /* libc++.tbd */; }; - BD1419893577E6CEDF8CBA83 /* Result.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0C5AC2545AE4D4F7F44E2E9B /* Result.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - BD95416F2005199F6B3572CF /* Framework.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 41FC82ED1C4C3B7B3D7B2FB7 /* Framework.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; BFCCC56337A5D9D513C1C791 /* module.modulemap in CopyFiles */ = {isa = PBXBuildFile; fileRef = F2950763C4C568CC85021D18 /* module.modulemap */; }; + C093BF20B99FE892D0F06B2D /* libEndpointSecurity.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 0BC75409252FF15F540FBB7B /* libEndpointSecurity.tbd */; }; C3672B561F456794151C047C /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4C3FE6B986506724DAB5D0F /* ViewController.swift */; }; C400EBD25886ACB5CD9035EB /* module.modulemap in CopyFiles */ = {isa = PBXBuildFile; fileRef = F2950763C4C568CC85021D18 /* module.modulemap */; }; + C4378E3DAF5E0B2F7AB60E03 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFE6A6FAAFF701FE729293DE /* ViewController.swift */; }; C836F09B677937EFF69B1FCE /* NotificationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C934C1F7A68CCD0AB6B38478 /* NotificationController.swift */; }; C88598A49087A212990F4E8B /* ResourceFolder in Resources */ = {isa = PBXBuildFile; fileRef = 6B1603BA83AA0C7B94E45168 /* ResourceFolder */; }; + CAE18A2194B57C830A297F83 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6680EFE4E908CDBDCE405C8 /* main.swift */; }; + CAF8470C7F1BF207DBE6AEE3 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEEFDE76B5FEC833403C0869 /* ContentView.swift */; platformFilters = (ios, ); }; CCA17097382757012B58C17C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1BC32A813B80A53962A1F365 /* Assets.xcassets */; }; + D058D241BDF5FB0C919BBECA /* CrossOverlayFramework.swiftcrossimport in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8DD7A61B07AD2F91BDECC255 /* CrossOverlayFramework.swiftcrossimport */; }; D5458D67C3596943114C3205 /* Standalone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F5BD97AF0F94A15A5B7DDB7 /* Standalone.swift */; }; + D5D493E4A7AD63860E1399DD /* ExternalTarget.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6ADE654A3459AFDA2CC0CD3 /* ExternalTarget.framework */; }; D61BEABD5B26B2DE67D0C2EC /* FrameworkFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5F527F2590C14956518174 /* FrameworkFile.swift */; }; + D62AB3A85B32F353ABBD57BC /* iMessageExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D629E142AB87C681D4EC90F7 /* iMessageExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; D8ED40ED61AD912385CFF5F0 /* StaticLibrary_ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D0C79A8C750EC0DE748C463 /* StaticLibrary_ObjC.m */; }; + DBCA8149E5C4183AB52B8D99 /* MyFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 576675973B56A96047CB4944 /* MyFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DD5FBFC3C1B2DB3D0D1CF210 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B785B1161553A7DD6DA4255 /* NetworkExtension.framework */; }; + E0B27599D701E6BB0223D0A8 /* FilterDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16AA52945B70B1BF9E246350 /* FilterDataProvider.swift */; }; E1836941C13CC7F13650C317 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3ED831531AA349CCC19B258B /* Assets.xcassets */; }; E34351AC0049221C167A60AC /* MyFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A58A16491CDDF968B0D56DE /* MyFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; E4B41CB5C796DD2C3C2E564C /* MyFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A58A16491CDDF968B0D56DE /* MyFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -132,14 +175,24 @@ E7B40B34D8807F43A3805381 /* ExternalTarget.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6ADE654A3459AFDA2CC0CD3 /* ExternalTarget.framework */; }; E8A135F768448632F8D77C8F /* StandaloneAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3571E41E19A5AB8AAAB04109 /* StandaloneAssets.xcassets */; }; EDB55692D392FD09C3FCFBF6 /* libStaticLibrary_ObjC.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 86169DEEDEAF09AB89C8A31D /* libStaticLibrary_ObjC.a */; }; + F4D77E81B0539EA5F4F141A6 /* EndpointSecuritySystemExtension.systemextension in Embed System Extensions */ = {isa = PBXBuildFile; fileRef = E5E0A80CCE8F8DB662DCD2D0 /* EndpointSecuritySystemExtension.systemextension */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; F5D71267BB5A326BDD69D532 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E55F45EACB0F382722D61C8D /* Assets.xcassets */; }; F6537CE373C94809E6653758 /* Headers in Headers */ = {isa = PBXBuildFile; fileRef = 2E1E747C7BC434ADB80CC269 /* Headers */; settings = {ATTRIBUTES = (Public, ); }; }; + F6734680031310575CDE9F23 /* CrossOverlayFramework.swiftcrossimport in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8DD7A61B07AD2F91BDECC255 /* CrossOverlayFramework.swiftcrossimport */; }; F7423E8738EECF04795C7601 /* InterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F6BCB5FEFB16F1BA368059 /* InterfaceController.swift */; }; F788A3FA1CE6489BC257C1C3 /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 306796628DD52FA55E833B65 /* Model.xcdatamodeld */; settings = {COMPILER_FLAGS = "-Werror"; }; }; + FB6DA0DB62C425066D51767E /* Driver.iig in Sources */ = {isa = PBXBuildFile; fileRef = 5A3A73F307648F58213E4EA1 /* Driver.iig */; }; FF030751A47C85F082C7EDB9 /* TestProjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D132EA69984F32DA9DC727B6 /* TestProjectTests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 01630C98B755921A79418B08 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 13E8C5AB873CEE21E18E552F; + remoteInfo = StaticLibrary_ObjC_iOS; + }; 02FC8A8CFD5676EA402CCCBC /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */; @@ -147,6 +200,20 @@ remoteGlobalIDString = 13E8C5AB873CEE21E18E552F; remoteInfo = StaticLibrary_ObjC_iOS; }; + 0B37F7A37D610FCFE187A6B7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D137C04B64B7052419A2DF4E; + remoteInfo = App_Clip; + }; + 25714659454527D9511C6093 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D137C04B64B7052419A2DF4E; + remoteInfo = App_Clip; + }; 2CA19347816754250A29DA32 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */; @@ -168,6 +235,13 @@ remoteGlobalIDString = 0867B0DACEF28C11442DE8F7; remoteInfo = App_iOS; }; + 45907115465077029040BF29 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8B9A14DC280CCE013CC86440; + remoteInfo = Framework2_tvOS; + }; 469D922BE967C6D52ED84552 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */; @@ -189,6 +263,13 @@ remoteGlobalIDString = 13E8C5AB873CEE21E18E552F; remoteInfo = StaticLibrary_ObjC_iOS; }; + 59BFAC272F73B46E97B74426 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6ED01BC471A8C3642258E178; + remoteInfo = Framework2_watchOS; + }; 610412261F48A0A36C32FC5C /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */; @@ -196,6 +277,34 @@ remoteGlobalIDString = 020A320BB3736FCDE6CC4E70; remoteInfo = App_macOS; }; + 69E205A3F578A8FFE3ECF3F9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0636AAF06498C336E1CEEDE4; + remoteInfo = TestFramework; + }; + 6ED42BD51E8832232E58D9C1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 428715FBC1D86458DA70CBDE; + remoteInfo = DriverKitDriver; + }; + 747773057270E6F58470B5FA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D137C04B64B7052419A2DF4E; + remoteInfo = App_Clip; + }; + 7E37A3C0A67C3B6363029A18 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */; + proxyType = 1; + remoteGlobalIDString = AE3F93DB94E7208F2F1D9A78; + remoteInfo = Framework_iOS; + }; 7F4EAACE4AD6CF285B7D3308 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */; @@ -252,6 +361,13 @@ remoteGlobalIDString = 0867B0DACEF28C11442DE8F7; remoteInfo = App_iOS; }; + CA16090DFCA7842CB4E20265 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = F192E783CCA898FBAA5C34EA /* AnotherProject */; + proxyType = 1; + remoteGlobalIDString = E76A5F5E363E470416D3B487; + remoteInfo = ExternalTarget; + }; CB8F4B3FDD84A2A6F3CA7F4C /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */; @@ -266,6 +382,20 @@ remoteGlobalIDString = CE7D183D3752B5B35D2D8E6D; remoteInfo = Framework2_iOS; }; + D4A7C57F6272F44F2E69A5DB /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */; + proxyType = 1; + remoteGlobalIDString = AD28397BCC984F769EE8A937; + remoteInfo = NetworkSystemExtension; + }; + DD32A97CFD2016BF1477CF6C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 9F551F66949B55E8328EB995; + remoteInfo = EndpointSecuritySystemExtension; + }; DECF0B88B325A158E4E1D9AE /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0FBAE303E3CFC2ABAC876A77 /* Project object */; @@ -297,6 +427,16 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ + 04D94C495E299B50EB0DC7C4 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "$(PRODUCT_NAME).framework/Modules"; + dstSubfolderSpec = 16; + files = ( + B502EF8F7605CBD038298F23 /* CrossOverlayFramework.swiftcrossimport in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 06FAE8D6834F982AA934B3E8 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -308,26 +448,25 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 08DA9F1F0ED13AC054003B27 /* Embed Frameworks */ = { + 096753D5DAA26D110F699A7F /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; + dstPath = "$(PRODUCT_NAME).framework/Modules"; + dstSubfolderSpec = 16; files = ( - 1E457F55331FD2C3E8E00BE2 /* Result.framework in Embed Frameworks */, + F6734680031310575CDE9F23 /* CrossOverlayFramework.swiftcrossimport in CopyFiles */, ); - name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; - 2F0735A423E554B267BBA0A5 /* Embed App Extensions */ = { + 30A8F3568B05F3DB13D8B466 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; - dstSubfolderSpec = 13; + dstSubfolderSpec = 10; files = ( - 54A255D331B04F08583F5417 /* iMessageExtension.appex in Embed App Extensions */, + 0927149520F12314CE8B4079 /* TestFramework.framework in Embed Frameworks */, ); - name = "Embed App Extensions"; + name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; 3217EBDE07BBCBDE3C16CEDC /* CopyFiles */ = { @@ -341,15 +480,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 6CB76DFA8662672C4245AF41 /* Embed Frameworks */ = { + 661E0CEEEC2395C39375961F /* Embed Foundation Extensions */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; - dstSubfolderSpec = 10; + dstSubfolderSpec = 13; files = ( - 7C8FF0B857E390417134C10F /* Result.framework in Embed Frameworks */, + 204958B9AD868004CCE6B779 /* App_watchOS Extension.appex in Embed Foundation Extensions */, ); - name = "Embed Frameworks"; + name = "Embed Foundation Extensions"; runOnlyForDeploymentPostprocessing = 0; }; 7FAF0BBB3DE701EBE5DBE810 /* CopyFiles */ = { @@ -374,6 +513,18 @@ name = "Embed Watch Content"; runOnlyForDeploymentPostprocessing = 0; }; + 848740AD60C4329197FF876B /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 3DF22C477446669094AC7C8C /* ExternalTarget.framework in Embed Frameworks */, + 9C92B7C89E5F0A10A34F5AA4 /* Framework.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; 865AAD9909027AC34D1374EA /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -395,6 +546,17 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 94FF9CA021C43301BA069930 /* Embed App Clips */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "$(CONTENTS_FOLDER_PATH)/AppClips"; + dstSubfolderSpec = 16; + files = ( + 77C3CB285572EA4BB7E201A7 /* App_Clip.app in Embed App Clips */, + ); + name = "Embed App Clips"; + runOnlyForDeploymentPostprocessing = 0; + }; A8688B5E0D1C2F35AD20BB85 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -402,20 +564,52 @@ dstSubfolderSpec = 10; files = ( 535A98A3E3B74E09891D977F /* TestFramework.framework in Embed Frameworks */, - BD1419893577E6CEDF8CBA83 /* Result.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; - C765431E5FF4B02F59DE79B0 /* Embed App Extensions */ = { + ADD98000970B8907F73BFD92 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; - dstPath = ""; + dstPath = "$(PRODUCT_NAME).framework/Modules"; + dstSubfolderSpec = 16; + files = ( + 052D6B4572FBF002286865D7 /* CrossOverlayFramework.swiftcrossimport in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CF6B94E7B2D2312582A526F5 /* Embed Dependencies */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = test; dstSubfolderSpec = 13; files = ( - 42BC5788871D1D838B253952 /* App_watchOS Extension.appex in Embed App Extensions */, + 81DFAB3A7633CE97929B9B2A /* Framework.framework in Embed Dependencies */, + ); + name = "Embed Dependencies"; + runOnlyForDeploymentPostprocessing = 0; + }; + DE875E9A37F7CB9C347AEFA0 /* Embed System Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "$(SYSTEM_EXTENSIONS_FOLDER_PATH)"; + dstSubfolderSpec = 16; + files = ( + 5126CD91C2CB41C9B14B6232 /* DriverKitDriver.dext in Embed System Extensions */, + F4D77E81B0539EA5F4F141A6 /* EndpointSecuritySystemExtension.systemextension in Embed System Extensions */, + 4DA7140FF84DBF39961F3409 /* NetworkSystemExtension.systemextension in Embed System Extensions */, + ); + name = "Embed System Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; + E1C04BDC65F3DC88D6D0473F /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "$(PRODUCT_NAME).framework/Modules"; + dstSubfolderSpec = 16; + files = ( + D058D241BDF5FB0C919BBECA /* CrossOverlayFramework.swiftcrossimport in CopyFiles */, ); - name = "Embed App Extensions"; runOnlyForDeploymentPostprocessing = 0; }; E8BC0F358D693454E5027ECC /* Copy Bundle Resources */ = { @@ -424,20 +618,20 @@ dstSubfolderSpec = 7; files = ( 3BBCA6F76E5F212E9C55FB78 /* BundleX.bundle in Copy Bundle Resources */, + 470D3493CDBFE56E2083A5FD /* BundleY.bundle in Copy Bundle Resources */, ); name = "Copy Bundle Resources"; runOnlyForDeploymentPostprocessing = 0; }; - F8CDEFED6ED131A09041F995 /* Embed Frameworks */ = { + EB212BCB1E2E1D2667233F98 /* Embed Foundation Extensions */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; - dstSubfolderSpec = 10; + dstSubfolderSpec = 13; files = ( - BD95416F2005199F6B3572CF /* Framework.framework in Embed Frameworks */, - A7D1A9942302569A9515696A /* Result.framework in Embed Frameworks */, + D62AB3A85B32F353ABBD57BC /* iMessageExtension.appex in Embed Foundation Extensions */, ); - name = "Embed Frameworks"; + name = "Embed Foundation Extensions"; runOnlyForDeploymentPostprocessing = 0; }; FB79B30FEA6073A29B4D9FCC /* CopyFiles */ = { @@ -467,8 +661,11 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0095836FE59395511E0CB4F0 /* CrossOverlayFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CrossOverlayFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 01E6934B571B91EAAFF0EDCB /* Resource.abc */ = {isa = PBXFileReference; path = Resource.abc; sourceTree = ""; }; 020E4DA91C9132845CAFDC5D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = ""; }; 039F208D1138598CE060F140 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 03CD22B8CD2E91BB97CC534E /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 03D6D1E34022DA9524E5B38D /* Mintfile */ = {isa = PBXFileReference; path = Mintfile; sourceTree = ""; }; 0510CEA09E3BFD387E3EDE28 /* MyPlayground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = MyPlayground.playground; sourceTree = ""; }; 068EDF47F0B087F6A4052AC0 /* Empty.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Empty.h; sourceTree = ""; }; @@ -477,85 +674,122 @@ 0B193CC6D2B3003418A550B6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/LocalizedStoryboard.strings; sourceTree = ""; }; 0B9D98D935F2C69A1F5BA539 /* App_macOS_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = App_macOS_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 0BB1B49A91B892152D68ED76 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; }; - 0C5AC2545AE4D4F7F44E2E9B /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Result.framework; sourceTree = ""; }; + 0BC75409252FF15F540FBB7B /* libEndpointSecurity.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libEndpointSecurity.tbd; path = usr/lib/libEndpointSecurity.tbd; sourceTree = SDKROOT; }; 0D09D243DBCF9D32E239F1E8 /* App_watchOS Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "App_watchOS Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; - 0E4841131C451A658AC8596C /* swift-tagged.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = "swift-tagged.framework"; sourceTree = ""; }; 0F5BD97AF0F94A15A5B7DDB7 /* Standalone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Standalone.swift; sourceTree = ""; }; 102A08142A31E44F4ED52649 /* base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = base.xcconfig; sourceTree = ""; }; 108BB29172D27BE3BD1E7F35 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 13EEAB58665D79C15184D9D0 /* App_iOS_UITests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = App_iOS_UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 148B7C933698BCC4F1DBA979 /* XPC_Service.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XPC_Service.m; sourceTree = ""; }; + 15A4363D659A58DA835DE8BA /* MyAppApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyAppApp.swift; sourceTree = ""; }; + 16AA52945B70B1BF9E246350 /* FilterDataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterDataProvider.swift; sourceTree = ""; }; 16D662EE577E4CD6AFF39D66 /* config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = config.xcconfig; sourceTree = ""; }; + 18722C61B05FFF4CC63D5755 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 187E665975BB5611AF0F27E1 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 1BC32A813B80A53962A1F365 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 1D0C79A8C750EC0DE748C463 /* StaticLibrary_ObjC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StaticLibrary_ObjC.m; sourceTree = ""; }; + 1FA5E208EC184E3030D2A21D /* Clip.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Clip.entitlements; sourceTree = ""; }; + 2049B6DD2AFE85F9DC9F3EB3 /* NetworkSystemExtension.systemextension */ = {isa = PBXFileReference; explicitFileType = "wrapper.system-extension"; includeInIndex = 0; path = NetworkSystemExtension.systemextension; sourceTree = BUILT_PRODUCTS_DIR; }; 22237B8EBD9E6BE8EBC8735F /* XPC Service.xpc */ = {isa = PBXFileReference; explicitFileType = "wrapper.xpc-service"; includeInIndex = 0; path = "XPC Service.xpc"; sourceTree = BUILT_PRODUCTS_DIR; }; 2233774B86539B1574D206B0 /* Framework2.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Framework2.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 2385A62F6C6EE8D461EE19F2 /* ExternalTarget.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ExternalTarget.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 23A2F16890ECF2EE3FED72AE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 28360ECA4D727FAA58557A81 /* example.mp4 */ = {isa = PBXFileReference; path = example.mp4; sourceTree = ""; }; 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 = ""; }; 3571E41E19A5AB8AAAB04109 /* StandaloneAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = StandaloneAssets.xcassets; sourceTree = ""; }; 3797E591F302ECC0AA2FC607 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 38F1191E5B85DC882B8ABE85 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 382E11E88B12BCB30F575686 /* Driver.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Driver.entitlements; sourceTree = ""; }; + 38DB679FF1CF4E379D1AB103 /* App_Clip.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = App_Clip.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 3A7BEFAB4710735CF169B1E8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 3D8A2D4363866877B9140156 /* XPC_ServiceProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPC_ServiceProtocol.h; sourceTree = ""; }; 3ED831531AA349CCC19B258B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 3EF21DF245F66BEF5446AAEF /* Framework2.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Framework2.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3FC04772130400920D68A167 /* App_Clip_Tests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = App_Clip_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 407C3F0009FDCE5B1B7DC2A8 /* App_supportedDestinations.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = App_supportedDestinations.app; sourceTree = BUILT_PRODUCTS_DIR; }; 40863AE6202CFCD0529D8438 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 41FC82ED1C4C3B7B3D7B2FB7 /* Framework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Framework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 45C12576F5AA694DD0CE2132 /* BundleX.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = BundleX.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 432E2C071A4B6B3757BEA13E /* Driver.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Driver.cpp; sourceTree = ""; }; + 45BBB9A7599490883491C808 /* NetworkExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NetworkExtension.entitlements; sourceTree = ""; }; + 45C12576F5AA694DD0CE2132 /* BundleX.bundle */ = {isa = PBXFileReference; lastKnownFileType = wrapper.cfbundle; path = BundleX.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 469B630D28015F0EDC456F6B /* libStaticLibrary_ObjC.a */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = archive.ar; path = libStaticLibrary_ObjC.a; sourceTree = BUILT_PRODUCTS_DIR; }; 46DD8F9AAC104BDB63793625 /* libStaticLibrary_ObjC.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libStaticLibrary_ObjC.a; sourceTree = BUILT_PRODUCTS_DIR; }; 4BF4D16042A80576D259160C /* Model 3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Model 3.xcdatamodel"; sourceTree = ""; }; + 4C7F9636B706AC92629D0B48 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 5116B3B58070BCD09F1487BA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 553D289724905857912C7A1D /* outputList.xcfilelist */ = {isa = PBXFileReference; lastKnownFileType = text.xcfilelist; path = outputList.xcfilelist; sourceTree = ""; }; + 576675973B56A96047CB4944 /* MyFramework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyFramework.h; sourceTree = ""; }; 57FF8864B8EBAB5777DC12E6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 587B9E9A3533E965CA602B76 /* TestProjectUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestProjectUITests.swift; sourceTree = ""; }; + 59DA55A04FA2366B5D0BEEFF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 5A2B916A11DCC2565241359F /* StaticLibrary_ObjC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StaticLibrary_ObjC.h; sourceTree = ""; }; + 5A3A73F307648F58213E4EA1 /* Driver.iig */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.iig; path = Driver.iig; sourceTree = ""; }; + 5B785B1161553A7DD6DA4255 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; }; + 5D13DDAB46F80D94D7345063 /* EndpointSecurity.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = EndpointSecurity.entitlements; sourceTree = ""; }; 6177CC6263783487E93F7F4D /* Framework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Framework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 6A58A16491CDDF968B0D56DE /* MyFramework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyFramework.h; sourceTree = ""; }; 6AC91042453E18DF74BA1C0F /* StaticLibrary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticLibrary.swift; sourceTree = ""; }; 6B1603BA83AA0C7B94E45168 /* ResourceFolder */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ResourceFolder; path = Resources/ResourceFolder; sourceTree = SOURCE_ROOT; }; 6BBE762F36D94AB6FFBFE834 /* SomeFile */ = {isa = PBXFileReference; path = SomeFile; sourceTree = ""; }; + 6F165CDD5BCC13AFF50B65E2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 70A8E15C81E454DC950C59F0 /* SomeXPCService.xpc */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.xpc-service"; path = SomeXPCService.xpc; sourceTree = ""; }; 72A14C887EF7E9C8CBE914AC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 77C0C341F1865224E0596086 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; - 7B5068D64404C61A67A18458 /* MyBundle.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = MyBundle.bundle; sourceTree = ""; }; + 7B5068D64404C61A67A18458 /* MyBundle.bundle */ = {isa = PBXFileReference; lastKnownFileType = wrapper.cfbundle; path = MyBundle.bundle; sourceTree = ""; }; 7C176A8297AC2F5207352BA8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; + 7C7EC00B53FF878007F6ECAB /* App_Clip_UITests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = App_Clip_UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 7D67F1C1BFBACE101DE7DB51 /* Framework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Framework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7D700FA699849D2F95216883 /* EntitledApp.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = EntitledApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 7DE38C10AB71A47B786D5BF2 /* Model.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model.xcdatamodel; sourceTree = ""; }; 7F1A2F579A6F79C62DDA0571 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7FDC16E1938AA114B67D87A9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Interface.storyboard; sourceTree = ""; }; 814822136AF3C64428D69DD6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 81E4CCE342955E0E934BE533 /* FrameworkFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrameworkFile.swift; sourceTree = ""; }; + 83B5EC7EF81F7E4B6F426D4E /* DriverKitDriver.dext */ = {isa = PBXFileReference; explicitFileType = "wrapper.driver-extension"; includeInIndex = 0; path = DriverKitDriver.dext; sourceTree = BUILT_PRODUCTS_DIR; }; + 84317819C92F78425870E483 /* BundleX.bundle */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = BundleX.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 86169DEEDEAF09AB89C8A31D /* libStaticLibrary_ObjC.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libStaticLibrary_ObjC.a; sourceTree = BUILT_PRODUCTS_DIR; }; 87DF9DCA8399E3214A7E27CF /* TestProjectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestProjectTests.swift; sourceTree = ""; }; + 89EB41A001D8BF26431C5798 /* CrossOverlayFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CrossOverlayFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8A9274BE42A03DC5DA1FAD04 /* Framework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Framework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 8AF20308873AEEEC4D8C45D1 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; }; + 8AF20308873AEEEC4D8C45D1 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = wrapper.cfbundle; path = Settings.bundle; sourceTree = ""; }; + 8C62E8644AC5070AFC737BCC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 8CAF6C55B555E3E1352645B6 /* ExtensionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionDelegate.swift; sourceTree = ""; }; 8CB86294FB939FE6E90932E1 /* libStaticLibrary_Swift.a */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = archive.ar; path = libStaticLibrary_Swift.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 8D88C6BF7355702B74396791 /* TestProjectUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestProjectUITests.swift; sourceTree = ""; }; + 8DD7A61B07AD2F91BDECC255 /* CrossOverlayFramework.swiftcrossimport */ = {isa = PBXFileReference; lastKnownFileType = wrapper.swiftcrossimport; path = CrossOverlayFramework.swiftcrossimport; sourceTree = ""; }; + 8FE05BF7897ECFD58B7AC8B1 /* CrossOverlayFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CrossOverlayFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 93C033648A37D95027845BD3 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; + 9528528C989D24FE3E6C533E /* App-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "App-Info.plist"; sourceTree = ""; }; 9A87A926D563773658FB87FE /* iMessageApp.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = iMessageApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 9D4AB3FCF725428EFB56F542 /* Configuration.storekit */ = {isa = PBXFileReference; path = Configuration.storekit; sourceTree = ""; }; 9F27382DD66E26C059E26EFE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; A0DC40025AB59B688E758829 /* Framework2.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Framework2.framework; sourceTree = BUILT_PRODUCTS_DIR; }; A220DE4EB3CB2E598D034D9D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; A3F6BCB5FEFB16F1BA368059 /* InterfaceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceController.swift; sourceTree = ""; }; A4C3FE6B986506724DAB5D0F /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + A6680EFE4E908CDBDCE405C8 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; A680BE9F68A255B0FB291AE6 /* App_watchOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App_watchOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; AAA49985DFFE797EE8416887 /* inputList.xcfilelist */ = {isa = PBXFileReference; lastKnownFileType = text.xcfilelist; path = inputList.xcfilelist; sourceTree = ""; }; AB055761199DF36DB0C629A6 /* Framework2.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Framework2.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + AEBCA8CFF769189C0D52031E /* App_iOS.xctestplan */ = {isa = PBXFileReference; path = App_iOS.xctestplan; sourceTree = ""; }; + AEEFDE76B5FEC833403C0869 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; B17B8D9C9B391332CD176A35 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LocalizedStoryboard.storyboard; sourceTree = ""; }; B198242976C3395E31FE000A /* MessagesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesViewController.swift; sourceTree = ""; }; B1C33BB070583BE3B0EC0E68 /* App_iOS.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = App_iOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; B221F5A689AD7D3AD52F56B8 /* libStaticLibrary_ObjC.a */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = archive.ar; path = libStaticLibrary_ObjC.a; sourceTree = BUILT_PRODUCTS_DIR; }; - B76E17CE3574081D5BF45B44 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Result.framework; sourceTree = ""; }; + B5C943D39DD7812CAB94B614 /* Documentation.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = Documentation.docc; sourceTree = ""; }; BA040F1F7D6CA08878323A55 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; - BB178D03E75929F3F5B10C56 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Result.framework; sourceTree = ""; }; + BB677D970923F663D846D7E0 /* BundleY.bundle */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = BundleY.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; BC56891DA7446EAC8C2F27EB /* File2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = File2.swift; path = Group2/File2.swift; sourceTree = ""; }; + BDCA996D141DD8A16B18D68F /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "GoogleService-Info.plist"; sourceTree = ""; }; BECEA4A483ADEB8158F640B3 /* Tool */ = {isa = PBXFileReference; includeInIndex = 0; path = Tool; sourceTree = BUILT_PRODUCTS_DIR; }; BF59AC868D227C92CA8B1B57 /* Model.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = Model.xcmappingmodel; sourceTree = ""; }; + C0A428E67153BB40184F37BE /* DriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DriverKit.framework; path = System/Library/Frameworks/DriverKit.framework; sourceTree = SDKROOT; }; C53ACB2962FED621389C36A2 /* iMessageStickersExtension.appex */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "wrapper.app-extension"; path = iMessageStickersExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; C7809CE9FE9852C2AA87ACE5 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; C934C1F7A68CCD0AB6B38478 /* NotificationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationController.swift; sourceTree = ""; }; @@ -564,19 +798,28 @@ CA8718C7CD3BE86D9B1F5120 /* MoreUnder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoreUnder.swift; sourceTree = ""; }; CB77A637470A3CDA2BDDBE99 /* App_iOS_Tests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = App_iOS_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D132EA69984F32DA9DC727B6 /* TestProjectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestProjectTests.swift; sourceTree = ""; }; - D296BB7355994040E197A1EE /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Result.framework; sourceTree = ""; }; + D21BB1B6FA5A025305B223BA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; D51CC8BCCBD68A90E90A3207 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + D52EC9AA9FFD3B690C355068 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; D629E142AB87C681D4EC90F7 /* iMessageExtension.appex */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "wrapper.app-extension"; path = iMessageExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; D6C89D80B5458D8929F5C127 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; D70BE0C05E5779A077793BE6 /* Model 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Model 2.xcdatamodel"; sourceTree = ""; }; + D7E73F4E11A4B74449E7FDFE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; D8A016580A3B8F72B820BFBF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; DAA7880242A9DE61E68026CC /* Folder */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Folder; sourceTree = SOURCE_ROOT; }; + DFE6A6FAAFF701FE729293DE /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + E0F31A9DE15B210D101AFC81 /* CrossOverlayFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CrossOverlayFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E3958AB20082EA12D4D5E60C /* BundleY.bundle */ = {isa = PBXFileReference; lastKnownFileType = wrapper.cfbundle; path = BundleY.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; E42335D1200CB7B8B91E962F /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = Base; path = Base.lproj/Localizable.stringsdict; sourceTree = ""; }; 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; }; + E66ABD3EB14C9D63DEF5C532 /* LocalizableStrings.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = LocalizableStrings.xcstrings; 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 = ""; }; F0D48A913C087D049C8EDDD7 /* App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = App.entitlements; sourceTree = ""; }; + F15E5C60B7E05D06B1B8E18E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 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 = ""; }; @@ -585,9 +828,20 @@ FD4A16C7B8FEB7F97F3CBE3F /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; FDB2B6A77D39CD5602F2125F /* Contacts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Contacts.framework; path = System/Library/Frameworks/Contacts.framework; sourceTree = SDKROOT; }; FED40A89162E446494DDE7C7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; - FF47010E7368583405AA50CB /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SwiftyJSON.framework; sourceTree = ""; }; /* End PBXFileReference section */ +/* Begin PBXFileSystemSynchronizedRootGroup section */ + AE2AB2772F70DFFF402AA02B /* SyncedFolder */ = { + isa = PBXFileSystemSynchronizedRootGroup; + explicitFileTypes = { + }; + explicitFolders = ( + ); + path = SyncedFolder; + sourceTree = ""; + }; +/* End PBXFileSystemSynchronizedRootGroup section */ + /* Begin PBXFrameworksBuildPhase section */ 117840B4DBC04099F6779D00 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; @@ -597,9 +851,8 @@ 4CB673A7C0C11E04F8544BDB /* Contacts.framework in Frameworks */, 262891CCD5F74316610437FA /* Framework2.framework in Frameworks */, 2FAE950E8FF2E7C0F7FF1FE9 /* Framework.framework in Frameworks */, - B142965C5AE9C6200BF65802 /* Result.framework in Frameworks */, B20617116B230DED1F7AF5E5 /* libStaticLibrary_ObjC.a in Frameworks */, - 1551370B0ACAC632E15C853B /* SwiftyJSON.framework in Frameworks */, + 0D0E2466833FC2636B92C43D /* Swinject in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -607,7 +860,15 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A1AEAAB53EAEDA1C307871FA /* Result.framework in Frameworks */, + 4C1504A05321046B3ED7A839 /* Framework2.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 36418B6CABA06BA9B206556E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3A3BA9F91994D8B472C71F04 /* Swinject in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -615,15 +876,32 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9DF5931DAD58C35B830A0A75 /* Result.framework in Frameworks */, + A7438C77A05D83E7016CF044 /* Framework2.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6D6C0891A16EFF2FDA9D25AF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A496E1DB82E16DA4099D1411 /* XCTest.framework in Frameworks */, + 5E0369B907E239D1E6884ECF /* TestFramework.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7448069D11FB1A170F943C90 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + DD5FBFC3C1B2DB3D0D1CF210 /* NetworkExtension.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - 9B861C58E640BD4AD391900C /* Frameworks */ = { + 8189054F985D26094EE77069 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 21CA04F29CD0DEB0DD27B808 /* Result.framework in Frameworks */, + 03D1147528CED90EC1D844CE /* XCTest.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -631,8 +909,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 76156B580B30704346296641 /* XCTest.framework in Frameworks */, E4D0F435405DABCB51C5B684 /* TestFramework.framework in Frameworks */, - 32956CD11BD6B02E64F5D8D1 /* swift-tagged.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -641,19 +919,39 @@ buildActionMask = 2147483647; files = ( B47F2629BFE5853767C8BB5E /* Contacts.framework in Frameworks */, + 76DC6A4B18F434BAC239CC4A /* DriverKit.framework in Frameworks */, 21425F6DE3D493B6F1E33D21 /* Framework.framework in Frameworks */, - 078FAAF5C2B851C7D5EA714F /* Result.framework in Frameworks */, + A949422315536EACDF8DD78A /* NetworkExtension.framework in Frameworks */, EDB55692D392FD09C3FCFBF6 /* libStaticLibrary_ObjC.a in Frameworks */, + C093BF20B99FE892D0F06B2D /* libEndpointSecurity.tbd in Frameworks */, BAA1C1E3828F5D43546AF997 /* libc++.tbd in Frameworks */, A59B3F08914812573AFF6C2D /* libz.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - C2323597C6777A02E1FF671C /* Frameworks */ = { + DFDFD9EDAD45D89D1080FC5D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D5D493E4A7AD63860E1399DD /* ExternalTarget.framework in Frameworks */, + A1588BF3BFFE1DF7409CBA10 /* Framework.framework in Frameworks */, + 71A2AAC5934BDC9EDB6F0D9E /* libStaticLibrary_ObjC.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E63B2ED6C095617F6F53C14A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 307B5322FC5A220652BA6FE0 /* Result.framework in Frameworks */, + 61401517ECCEB2362582B5DA /* libEndpointSecurity.tbd in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EA2F63A326C56F6ECA7F5D7D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8267B75289E9D6C7B38FC426 /* DriverKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -686,18 +984,6 @@ path = App_iOS_UITests; sourceTree = ""; }; - 12809A79ACE69F501A5FE815 /* Carthage */ = { - isa = PBXGroup; - children = ( - DBF93518FC96D95A54552713 /* iOS */, - 912A7321F662FE41BAAEED67 /* Mac */, - D557819B1EE5B42A0A3DD4D1 /* tvOS */, - 2935454D05445817952E145D /* watchOS */, - ); - name = Carthage; - path = Carthage/Build; - sourceTree = ""; - }; 1A57D1EE1FBC13598F6B5CB0 /* Framework */ = { isa = PBXGroup; children = ( @@ -712,9 +998,12 @@ isa = PBXGroup; children = ( 2F80635127D17ECB7748067B /* FolderWithDot2.0 */, + AEBCA8CFF769189C0D52031E /* App_iOS.xctestplan */, F0D48A913C087D049C8EDDD7 /* App.entitlements */, 7F1A2F579A6F79C62DDA0571 /* AppDelegate.swift */, 3797E591F302ECC0AA2FC607 /* Assets.xcassets */, + 9D4AB3FCF725428EFB56F542 /* Configuration.storekit */, + B5C943D39DD7812CAB94B614 /* Documentation.docc */, C9DDE1B06BCC1CDE0ECF1589 /* Info.plist */, AAA49985DFFE797EE8416887 /* inputList.xcfilelist */, CE1F06D99242F4223D081F0D /* LaunchScreen.storyboard */, @@ -726,6 +1015,8 @@ BF59AC868D227C92CA8B1B57 /* Model.xcmappingmodel */, C7809CE9FE9852C2AA87ACE5 /* module.modulemap */, 553D289724905857912C7A1D /* outputList.xcfilelist */, + 01E6934B571B91EAAFF0EDCB /* Resource.abc */, + 325F18855099386B08DD309B /* Resource.abcd */, 8AF20308873AEEEC4D8C45D1 /* Settings.bundle */, 0704B6CAFBB53E0EBB08F6B3 /* ViewController.swift */, ); @@ -733,36 +1024,36 @@ path = App_iOS; sourceTree = ""; }; - 2935454D05445817952E145D /* watchOS */ = { - isa = PBXGroup; - children = ( - BB178D03E75929F3F5B10C56 /* Result.framework */, - ); - path = watchOS; - sourceTree = ""; - }; 293D0FF827366B513839236A = { isa = PBXGroup; children = ( 1F2DE413CF2CB54988158172 /* App */, + C81493FAD71E9A9A19E00AD5 /* App_Clip */, + 6BD8F0932CCAD4BBE752866B /* App_Clip_UITests */, FC81A3ED177CE9DA68D09941 /* App_iOS_Tests */, 0D039F2E62354C7C8E283BE6 /* App_iOS_UITests */, EE78B4FBD0137D1975C47D76 /* App_macOS */, 6DE1C805DC13547F27FD86C6 /* App_macOS_Tests */, + D27117FBA2920408002F0B4C /* App_supportedDestinations */, BAE6C12745737019DC9E98BF /* App_watchOS */, 795B8D70B674C850B57DD39D /* App_watchOS Extension */, 6DBE0EE90642BB3F6E58AD43 /* Configs */, 3F2E22B7AB20FA42CD205C2A /* CopyFiles */, + ED8625A7E716E1BA50AB88AB /* CrossOverlayFramework */, FCC084D4F8992BBC49983A38 /* CustomGroup */, + 7979F5A04B370C36415EFB11 /* DriverKit Driver */, + 99EF37D6DEE914E180236A91 /* EndpointSecurity Extension */, 5CBCE0E2A145046265FE99E2 /* FileGroup */, 1A57D1EE1FBC13598F6B5CB0 /* Framework */, A3DCF90D9B1EF4E27CF54B19 /* iMessageApp */, BF58996786F85CB77BEE72EF /* iMessageExtension */, 018CC36B301BFA9965780BD9 /* iMessageStickers */, + A0F4C565134899E0C5EB2EA7 /* Network Extension */, 9EDF27BB8A57733E6639D36D /* Resources */, 9DB22CB08CFAA455518700DB /* StandaloneFiles */, BDA839814AF73F01F7710518 /* StaticLibrary_ObjC */, CBDAC144248EE9D3838C6AAA /* StaticLibrary_Swift */, + 6E0D17C5B4E6F01B89254309 /* String Catalogs */, 8CFD8AD4820FAB9265663F92 /* Tool */, 4C7F5EB7D6F3E0E9B426AB4A /* Utilities */, 3FEA12CF227D41EF50E5C2DB /* Vendor */, @@ -771,6 +1062,7 @@ 2E1E747C7BC434ADB80CC269 /* Headers */, 6B1603BA83AA0C7B94E45168 /* ResourceFolder */, 6BBE762F36D94AB6FFBFE834 /* SomeFile */, + AE2AB2772F70DFFF402AA02B /* SyncedFolder */, 79DC4A1E4D2E0D3A215179BC /* Bundles */, FC1515684236259C50A7747F /* Frameworks */, AC523591AC7BE9275003D2DB /* Products */, @@ -837,6 +1129,32 @@ path = UnderFileGroup; sourceTree = ""; }; + 69C61547C081D04364A5DE42 /* Storyboards */ = { + isa = PBXGroup; + children = ( + D52EC9AA9FFD3B690C355068 /* LaunchScreen.storyboard */, + ); + name = Storyboards; + path = Storyboards; + sourceTree = ""; + }; + 6A90AFD865B13D26DA108CAB /* tvOS */ = { + isa = PBXGroup; + children = ( + 18722C61B05FFF4CC63D5755 /* ContentView.swift */, + ); + path = tvOS; + sourceTree = ""; + }; + 6BD8F0932CCAD4BBE752866B /* App_Clip_UITests */ = { + isa = PBXGroup; + children = ( + 3A7BEFAB4710735CF169B1E8 /* Info.plist */, + 8D88C6BF7355702B74396791 /* TestProjectUITests.swift */, + ); + path = App_Clip_UITests; + sourceTree = ""; + }; 6DBE0EE90642BB3F6E58AD43 /* Configs */ = { isa = PBXGroup; children = ( @@ -855,6 +1173,14 @@ path = App_macOS_Tests; sourceTree = ""; }; + 6E0D17C5B4E6F01B89254309 /* String Catalogs */ = { + isa = PBXGroup; + children = ( + E66ABD3EB14C9D63DEF5C532 /* LocalizableStrings.xcstrings */, + ); + path = "String Catalogs"; + sourceTree = ""; + }; 795B8D70B674C850B57DD39D /* App_watchOS Extension */ = { isa = PBXGroup; children = ( @@ -868,10 +1194,22 @@ path = "App_watchOS Extension"; sourceTree = ""; }; + 7979F5A04B370C36415EFB11 /* DriverKit Driver */ = { + isa = PBXGroup; + children = ( + 432E2C071A4B6B3757BEA13E /* Driver.cpp */, + 382E11E88B12BCB30F575686 /* Driver.entitlements */, + 5A3A73F307648F58213E4EA1 /* Driver.iig */, + D7E73F4E11A4B74449E7FDFE /* Info.plist */, + ); + path = "DriverKit Driver"; + sourceTree = ""; + }; 79DC4A1E4D2E0D3A215179BC /* Bundles */ = { isa = PBXGroup; children = ( 45C12576F5AA694DD0CE2132 /* BundleX.bundle */, + E3958AB20082EA12D4D5E60C /* BundleY.bundle */, ); name = Bundles; sourceTree = ""; @@ -888,6 +1226,17 @@ path = "XPC Service"; sourceTree = ""; }; + 85FEBB7D2103B020423407A2 /* Sources */ = { + isa = PBXGroup; + children = ( + 9E5249A284275B0CDF4E5DDA /* iOS */, + 6A90AFD865B13D26DA108CAB /* tvOS */, + 15A4363D659A58DA835DE8BA /* MyAppApp.swift */, + ); + name = Sources; + path = Sources; + sourceTree = ""; + }; 8CFD8AD4820FAB9265663F92 /* Tool */ = { isa = PBXGroup; children = ( @@ -896,12 +1245,14 @@ path = Tool; sourceTree = ""; }; - 912A7321F662FE41BAAEED67 /* Mac */ = { + 99EF37D6DEE914E180236A91 /* EndpointSecurity Extension */ = { isa = PBXGroup; children = ( - D296BB7355994040E197A1EE /* Result.framework */, + 5D13DDAB46F80D94D7345063 /* EndpointSecurity.entitlements */, + 8C62E8644AC5070AFC737BCC /* Info.plist */, + A6680EFE4E908CDBDCE405C8 /* main.swift */, ); - path = Mac; + path = "EndpointSecurity Extension"; sourceTree = ""; }; 9DB22CB08CFAA455518700DB /* StandaloneFiles */ = { @@ -913,16 +1264,36 @@ path = StandaloneFiles; sourceTree = ""; }; + 9E5249A284275B0CDF4E5DDA /* iOS */ = { + isa = PBXGroup; + children = ( + AEEFDE76B5FEC833403C0869 /* ContentView.swift */, + ); + path = iOS; + sourceTree = ""; + }; 9EDF27BB8A57733E6639D36D /* Resources */ = { isa = PBXGroup; children = ( 28360ECA4D727FAA58557A81 /* example.mp4 */, + BDCA996D141DD8A16B18D68F /* GoogleService-Info.plist */, 7B5068D64404C61A67A18458 /* MyBundle.bundle */, C9E358FBE2B54D2B5C7FD609 /* SceneKitCatalog.scnassets */, ); path = Resources; sourceTree = ""; }; + A0F4C565134899E0C5EB2EA7 /* Network Extension */ = { + isa = PBXGroup; + children = ( + 16AA52945B70B1BF9E246350 /* FilterDataProvider.swift */, + EDCC70978B8AD49373DA0DE0 /* Info.plist */, + 03CD22B8CD2E91BB97CC534E /* main.swift */, + 45BBB9A7599490883491C808 /* NetworkExtension.entitlements */, + ); + path = "Network Extension"; + sourceTree = ""; + }; A3DCF90D9B1EF4E27CF54B19 /* iMessageApp */ = { isa = PBXGroup; children = ( @@ -935,14 +1306,27 @@ AC523591AC7BE9275003D2DB /* Products */ = { isa = PBXGroup; children = ( + 3FC04772130400920D68A167 /* App_Clip_Tests.xctest */, + 7C7EC00B53FF878007F6ECAB /* App_Clip_UITests.xctest */, + 38DB679FF1CF4E379D1AB103 /* App_Clip.app */, CB77A637470A3CDA2BDDBE99 /* App_iOS_Tests.xctest */, 13EEAB58665D79C15184D9D0 /* App_iOS_UITests.xctest */, B1C33BB070583BE3B0EC0E68 /* App_iOS.app */, 0B9D98D935F2C69A1F5BA539 /* App_macOS_Tests.xctest */, 33F6DCDC37D2E66543D4965D /* App_macOS.app */, + 407C3F0009FDCE5B1B7DC2A8 /* App_supportedDestinations.app */, 0D09D243DBCF9D32E239F1E8 /* App_watchOS Extension.appex */, A680BE9F68A255B0FB291AE6 /* App_watchOS.app */, + 84317819C92F78425870E483 /* BundleX.bundle */, + BB677D970923F663D846D7E0 /* BundleY.bundle */, + 8FE05BF7897ECFD58B7AC8B1 /* CrossOverlayFramework.framework */, + E0F31A9DE15B210D101AFC81 /* CrossOverlayFramework.framework */, + 0095836FE59395511E0CB4F0 /* CrossOverlayFramework.framework */, + 89EB41A001D8BF26431C5798 /* CrossOverlayFramework.framework */, + 83B5EC7EF81F7E4B6F426D4E /* DriverKitDriver.dext */, + E5E0A80CCE8F8DB662DCD2D0 /* EndpointSecuritySystemExtension.systemextension */, 7D700FA699849D2F95216883 /* EntitledApp.app */, + 2385A62F6C6EE8D461EE19F2 /* ExternalTarget.framework */, 8A9274BE42A03DC5DA1FAD04 /* Framework.framework */, 41FC82ED1C4C3B7B3D7B2FB7 /* Framework.framework */, 7D67F1C1BFBACE101DE7DB51 /* Framework.framework */, @@ -959,6 +1343,7 @@ 469B630D28015F0EDC456F6B /* libStaticLibrary_ObjC.a */, 46DD8F9AAC104BDB63793625 /* libStaticLibrary_ObjC.a */, 8CB86294FB939FE6E90932E1 /* libStaticLibrary_Swift.a */, + 2049B6DD2AFE85F9DC9F3EB3 /* NetworkSystemExtension.systemextension */, E43116070AFEF5D8C3A5A957 /* TestFramework.framework */, BECEA4A483ADEB8158F640B3 /* Tool */, 22237B8EBD9E6BE8EBC8735F /* XPC Service.xpc */, @@ -997,6 +1382,20 @@ path = iMessageExtension; sourceTree = ""; }; + C81493FAD71E9A9A19E00AD5 /* App_Clip */ = { + isa = PBXGroup; + children = ( + 23A2F16890ECF2EE3FED72AE /* AppDelegate.swift */, + 59DA55A04FA2366B5D0BEEFF /* Assets.xcassets */, + 1FA5E208EC184E3030D2A21D /* Clip.entitlements */, + 6F165CDD5BCC13AFF50B65E2 /* Info.plist */, + 79325B44B19B83EC6CEDBCC5 /* LaunchScreen.storyboard */, + 2FC2A8A829CE71B1CF415FF7 /* Main.storyboard */, + DFE6A6FAAFF701FE729293DE /* ViewController.swift */, + ); + path = App_Clip; + sourceTree = ""; + }; CBDAC144248EE9D3838C6AAA /* StaticLibrary_Swift */ = { isa = PBXGroup; children = ( @@ -1005,12 +1404,13 @@ path = StaticLibrary_Swift; sourceTree = ""; }; - D557819B1EE5B42A0A3DD4D1 /* tvOS */ = { + D27117FBA2920408002F0B4C /* App_supportedDestinations */ = { isa = PBXGroup; children = ( - B76E17CE3574081D5BF45B44 /* Result.framework */, + 85FEBB7D2103B020423407A2 /* Sources */, + 69C61547C081D04364A5DE42 /* Storyboards */, ); - path = tvOS; + path = App_supportedDestinations; sourceTree = ""; }; D7929BCBA599BD85A3B8A039 /* Projects */ = { @@ -1021,22 +1421,23 @@ name = Projects; sourceTree = ""; }; - DBF93518FC96D95A54552713 /* iOS */ = { + ED8625A7E716E1BA50AB88AB /* CrossOverlayFramework */ = { isa = PBXGroup; children = ( - 0C5AC2545AE4D4F7F44E2E9B /* Result.framework */, - 0E4841131C451A658AC8596C /* swift-tagged.framework */, - FF47010E7368583405AA50CB /* SwiftyJSON.framework */, + 8DD7A61B07AD2F91BDECC255 /* CrossOverlayFramework.swiftcrossimport */, + 81E4CCE342955E0E934BE533 /* FrameworkFile.swift */, + D21BB1B6FA5A025305B223BA /* Info.plist */, + 576675973B56A96047CB4944 /* MyFramework.h */, ); - path = iOS; + path = CrossOverlayFramework; sourceTree = ""; }; EE78B4FBD0137D1975C47D76 /* App_macOS */ = { isa = PBXGroup; children = ( + 9528528C989D24FE3E6C533E /* App-Info.plist */, 09B82F603D981398F38D762E /* AppDelegate.swift */, E55F45EACB0F382722D61C8D /* Assets.xcassets */, - 38F1191E5B85DC882B8ABE85 /* Info.plist */, 74FBDFA5CB063F6001AD8ACD /* Main.storyboard */, A4C3FE6B986506724DAB5D0F /* ViewController.swift */, ); @@ -1046,10 +1447,13 @@ FC1515684236259C50A7747F /* Frameworks */ = { isa = PBXGroup; children = ( - 12809A79ACE69F501A5FE815 /* Carthage */, FDB2B6A77D39CD5602F2125F /* Contacts.framework */, + C0A428E67153BB40184F37BE /* DriverKit.framework */, 0BB1B49A91B892152D68ED76 /* libc++.tbd */, + 0BC75409252FF15F540FBB7B /* libEndpointSecurity.tbd */, FD4A16C7B8FEB7F97F3CBE3F /* libz.dylib */, + 5B785B1161553A7DD6DA4255 /* NetworkExtension.framework */, + 4C7F9636B706AC92629D0B48 /* XCTest.framework */, ); name = Frameworks; sourceTree = ""; @@ -1136,6 +1540,22 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 942F7B856687815A6B056194 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 06F1750F0E45E4822F806523 /* MyFramework.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A24F1A0AC15CAE82CD3EDFE2 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 4B862F11762F6BB54E97E401 /* MyFramework.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; AEC8E1CFD02926FADE734D82 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -1144,6 +1564,22 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + C5BCD048B70E4D35B14AA8E9 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + DBCA8149E5C4183AB52B8D99 /* MyFramework.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DA6BC7F9BB12AC09AB3AF202 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 57DC116CE5C9F93FBA529C2F /* MyFramework.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; F21F013CBD830972394A3A13 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -1156,6 +1592,22 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXLegacyTarget section */ + 700328EE1570207608D6ADB3 /* IncludedLegacy */ = { + isa = PBXLegacyTarget; + buildConfigurationList = 02B721AF7361EBCFA91410BF /* Build configuration list for PBXLegacyTarget "IncludedLegacy" */; + buildPhases = ( + 82E24A8257F299AC04F44A8F /* Sources */, + ); + buildToolPath = /usr/bin/true; + buildWorkingDirectory = AnotherProject; + dependencies = ( + ); + name = IncludedLegacy; + packageProductDependencies = ( + ); + passBuildSettingsInEnvironment = 0; + productName = IncludedLegacy; + }; 72C923899DE05F1281872160 /* Legacy */ = { isa = PBXLegacyTarget; buildConfigurationList = BE0FF81B67730F081F45BC78 /* Build configuration list for PBXLegacyTarget "Legacy" */; @@ -1166,6 +1618,8 @@ dependencies = ( ); name = Legacy; + packageProductDependencies = ( + ); passBuildSettingsInEnvironment = 1; productName = Legacy; }; @@ -1176,20 +1630,26 @@ isa = PBXNativeTarget; buildConfigurationList = 77CE5B5E5DEAC820254D484C /* Build configuration list for PBXNativeTarget "App_macOS" */; buildPhases = ( - 96BB43F4706B031DA45166E8 /* Sources */, 77D35586228BF8AB74152BB5 /* Resources */, + 96BB43F4706B031DA45166E8 /* Sources */, FB79B30FEA6073A29B4D9FCC /* CopyFiles */, A6E1C88C073F8CC6B5B072B6 /* Frameworks */, - F8CDEFED6ED131A09041F995 /* Embed Frameworks */, + DE875E9A37F7CB9C347AEFA0 /* Embed System Extensions */, + CF6B94E7B2D2312582A526F5 /* Embed Dependencies */, ); buildRules = ( ); dependencies = ( + 6BE35B7C058BE1B6F3B906C0 /* PBXTargetDependency */, + 1652DB87B43B72B5DE0601C4 /* PBXTargetDependency */, F3930A0708A7EB1BDA25B31B /* PBXTargetDependency */, + F7532D3474E04037FF26E9BC /* PBXTargetDependency */, 7EFC0278E67CD35F8981993C /* PBXTargetDependency */, B95DA92D1265C094E71B4A5D /* PBXTargetDependency */, ); name = App_macOS; + packageProductDependencies = ( + ); productName = App_macOS; productReference = 33F6DCDC37D2E66543D4965D /* App_macOS.app */; productType = "com.apple.product-type.application"; @@ -1200,12 +1660,15 @@ buildPhases = ( 2F72F6483B3356C11F79ACCF /* Headers */, 902C8700CD150C726365CB8A /* Sources */, + 8189054F985D26094EE77069 /* Frameworks */, ); buildRules = ( ); dependencies = ( ); name = TestFramework; + packageProductDependencies = ( + ); productName = TestFramework; productReference = E43116070AFEF5D8C3A5A957 /* TestFramework.framework */; productType = "com.apple.product-type.framework"; @@ -1217,9 +1680,9 @@ 6F573D15DE1F149EF128C492 /* Sources */, 8508BA1B733839E314AF2853 /* Resources */, 865AAD9909027AC34D1374EA /* CopyFiles */, - 37182EC208DBF03DB1BAF452 /* Carthage */, 117840B4DBC04099F6779D00 /* Frameworks */, E8BC0F358D693454E5027ECC /* Copy Bundle Resources */, + 94FF9CA021C43301BA069930 /* Embed App Clips */, FE78CC3322C9C2DB1D64EAAA /* Embed Frameworks */, 807155B9081529D99AAB4743 /* Embed Watch Content */, 71A4CC6ECC8522178F566E7B /* Strip Unused Architectures from Frameworks */, @@ -1229,13 +1692,20 @@ ); dependencies = ( 4FA29DA80DA668224AED741F /* PBXTargetDependency */, + 8B6243D8D47A6ADA4CA0D7BD /* PBXTargetDependency */, 0D33D01C71E8002A07F02122 /* PBXTargetDependency */, A94F38390A74E215EC107BB5 /* PBXTargetDependency */, E84285243DE0BB361A708079 /* PBXTargetDependency */, E8C078B0A2A2B0E1D35694D5 /* PBXTargetDependency */, 981D116D40DBA0407D0E0E94 /* PBXTargetDependency */, ); + fileSystemSynchronizedGroups = ( + AE2AB2772F70DFFF402AA02B /* SyncedFolder */, + ); name = App_iOS; + packageProductDependencies = ( + D7917D10F77DA9D69937D493 /* Swinject */, + ); productName = App_iOS; productReference = B1C33BB070583BE3B0EC0E68 /* App_iOS.app */; productType = "com.apple.product-type.application"; @@ -1251,25 +1721,48 @@ dependencies = ( ); name = Tool; + packageProductDependencies = ( + ); productName = Tool; productReference = BECEA4A483ADEB8158F640B3 /* Tool */; productType = "com.apple.product-type.tool"; }; - 13E8C5AB873CEE21E18E552F /* StaticLibrary_ObjC_iOS */ = { + 0CE8BE7C80651629EC056066 /* CrossOverlayFramework_iOS */ = { isa = PBXNativeTarget; - buildConfigurationList = 56BF985F253DD84AD7C37538 /* Build configuration list for PBXNativeTarget "StaticLibrary_ObjC_iOS" */; + buildConfigurationList = 641D1B2D88B93FAD0EA09187 /* Build configuration list for PBXNativeTarget "CrossOverlayFramework_iOS" */; buildPhases = ( - 7FAF0BBB3DE701EBE5DBE810 /* CopyFiles */, - EA88FE285DA490166635BE98 /* Sources */, + 096753D5DAA26D110F699A7F /* CopyFiles */, + C5BCD048B70E4D35B14AA8E9 /* Headers */, + 84FEBA4F84620938800D12A4 /* Sources */, ); buildRules = ( ); dependencies = ( ); - name = StaticLibrary_ObjC_iOS; - productName = StaticLibrary_ObjC_iOS; - productReference = B221F5A689AD7D3AD52F56B8 /* libStaticLibrary_ObjC.a */; - productType = "com.apple.product-type.library.static"; + name = CrossOverlayFramework_iOS; + packageProductDependencies = ( + ); + productName = CrossOverlayFramework_iOS; + productReference = 8FE05BF7897ECFD58B7AC8B1 /* CrossOverlayFramework.framework */; + productType = "com.apple.product-type.framework"; + }; + 13E8C5AB873CEE21E18E552F /* StaticLibrary_ObjC_iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 56BF985F253DD84AD7C37538 /* Build configuration list for PBXNativeTarget "StaticLibrary_ObjC_iOS" */; + buildPhases = ( + 7FAF0BBB3DE701EBE5DBE810 /* CopyFiles */, + EA88FE285DA490166635BE98 /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = StaticLibrary_ObjC_iOS; + packageProductDependencies = ( + ); + productName = StaticLibrary_ObjC_iOS; + productReference = B221F5A689AD7D3AD52F56B8 /* libStaticLibrary_ObjC.a */; + productType = "com.apple.product-type.library.static"; }; 192C574D74079A99AF1AD0B1 /* iMessageStickersExtension */ = { isa = PBXNativeTarget; @@ -1282,6 +1775,8 @@ dependencies = ( ); name = iMessageStickersExtension; + packageProductDependencies = ( + ); productName = iMessageStickersExtension; productReference = C53ACB2962FED621389C36A2 /* iMessageStickersExtension.appex */; productType = "com.apple.product-type.app-extension.messages-sticker-pack"; @@ -1298,6 +1793,8 @@ dependencies = ( ); name = StaticLibrary_Swift; + packageProductDependencies = ( + ); productName = StaticLibrary_Swift; productReference = 8CB86294FB939FE6E90932E1 /* libStaticLibrary_Swift.a */; productType = "com.apple.product-type.library.static"; @@ -1314,6 +1811,8 @@ dependencies = ( ); name = iMessageExtension; + packageProductDependencies = ( + ); productName = iMessageExtension; productReference = D629E142AB87C681D4EC90F7 /* iMessageExtension.appex */; productType = "com.apple.product-type.app-extension.messages"; @@ -1322,9 +1821,8 @@ isa = PBXNativeTarget; buildConfigurationList = 6B5C5F08C0EF06457756E379 /* Build configuration list for PBXNativeTarget "App_watchOS" */; buildPhases = ( - 91C895DE8170C96A75D29426 /* Sources */, B7B71FA7D279029BF7A7FC7C /* Resources */, - C765431E5FF4B02F59DE79B0 /* Embed App Extensions */, + 661E0CEEEC2395C39375961F /* Embed Foundation Extensions */, ); buildRules = ( ); @@ -1332,27 +1830,102 @@ 62DA64F61B337719A2CF993D /* PBXTargetDependency */, ); name = App_watchOS; + packageProductDependencies = ( + ); productName = App_watchOS; productReference = A680BE9F68A255B0FB291AE6 /* App_watchOS.app */; productType = "com.apple.product-type.application.watchapp2"; }; + 271CAC331D24F4F7E12C819C /* BundleY */ = { + isa = PBXNativeTarget; + buildConfigurationList = DA49CF5A1AC4FC1A7EE979E8 /* Build configuration list for PBXNativeTarget "BundleY" */; + buildPhases = ( + ); + buildRules = ( + ); + dependencies = ( + ); + name = BundleY; + packageProductDependencies = ( + ); + productName = BundleY; + productReference = BB677D970923F663D846D7E0 /* BundleY.bundle */; + productType = "com.apple.product-type.bundle"; + }; + 2F4FEAEFD7EE82DC49D899FC /* CrossOverlayFramework_macOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9C9913AAE0ABA99337F0C069 /* Build configuration list for PBXNativeTarget "CrossOverlayFramework_macOS" */; + buildPhases = ( + E1C04BDC65F3DC88D6D0473F /* CopyFiles */, + 942F7B856687815A6B056194 /* Headers */, + A87FBABC2AA10F8D044526BD /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = CrossOverlayFramework_macOS; + packageProductDependencies = ( + ); + productName = CrossOverlayFramework_macOS; + productReference = E0F31A9DE15B210D101AFC81 /* CrossOverlayFramework.framework */; + productType = "com.apple.product-type.framework"; + }; 307AE3FA155FFD09B74AE351 /* App_watchOS Extension */ = { isa = PBXNativeTarget; buildConfigurationList = 3F3C272D2EA61F6B88B80D44 /* Build configuration list for PBXNativeTarget "App_watchOS Extension" */; buildPhases = ( AE7971E1CA54D23C264E6541 /* Sources */, 4A6E8F3A477AA5F67A8EB733 /* Resources */, - 8F8EE32AFABD8FEF97625325 /* Carthage */, ); buildRules = ( ); dependencies = ( ); name = "App_watchOS Extension"; + packageProductDependencies = ( + ); productName = "App_watchOS Extension"; productReference = 0D09D243DBCF9D32E239F1E8 /* App_watchOS Extension.appex */; productType = "com.apple.product-type.watchkit2-extension"; }; + 3BF66A4668DFAF9338791F60 /* CrossOverlayFramework_tvOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = E3D23AF56C29471E48CA9A11 /* Build configuration list for PBXNativeTarget "CrossOverlayFramework_tvOS" */; + buildPhases = ( + 04D94C495E299B50EB0DC7C4 /* CopyFiles */, + DA6BC7F9BB12AC09AB3AF202 /* Headers */, + E9BE8745FD5B1ACBE43B9E0C /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = CrossOverlayFramework_tvOS; + packageProductDependencies = ( + ); + productName = CrossOverlayFramework_tvOS; + productReference = 0095836FE59395511E0CB4F0 /* CrossOverlayFramework.framework */; + productType = "com.apple.product-type.framework"; + }; + 428715FBC1D86458DA70CBDE /* DriverKitDriver */ = { + isa = PBXNativeTarget; + buildConfigurationList = 412FA71CA97AD6851A1828DD /* Build configuration list for PBXNativeTarget "DriverKitDriver" */; + buildPhases = ( + 3422D8A97652F33BA3AEAD6E /* Sources */, + EA2F63A326C56F6ECA7F5D7D /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DriverKitDriver; + packageProductDependencies = ( + ); + productName = DriverKitDriver; + productReference = 83B5EC7EF81F7E4B6F426D4E /* DriverKitDriver.dext */; + productType = "com.apple.product-type.driver-extension"; + }; 536ACF18E4603B59207D43CE /* Framework_tvOS */ = { isa = PBXNativeTarget; buildConfigurationList = 658628E35283172E17BFC6A3 /* Build configuration list for PBXNativeTarget "Framework_tvOS" */; @@ -1365,9 +1938,12 @@ buildRules = ( ); dependencies = ( + D6C733BEB62EAA62CCC68556 /* PBXTargetDependency */, CE96B0951433713033A03DCD /* PBXTargetDependency */, ); name = Framework_tvOS; + packageProductDependencies = ( + ); productName = Framework_tvOS; productReference = 7D67F1C1BFBACE101DE7DB51 /* Framework.framework */; productType = "com.apple.product-type.framework"; @@ -1378,7 +1954,6 @@ buildPhases = ( 54B4D7ADCE0441B5A91DE22D /* Headers */, D1F422E9C4DD531AA88418C9 /* Sources */, - C2323597C6777A02E1FF671C /* Frameworks */, 3D0637F4554EAD6FA48105BF /* MyScript */, ); buildRules = ( @@ -1387,6 +1962,8 @@ AD555A4814F2D294E2AC72D8 /* PBXTargetDependency */, ); name = Framework_macOS; + packageProductDependencies = ( + ); productName = Framework_macOS; productReference = 41FC82ED1C4C3B7B3D7B2FB7 /* Framework.framework */; productType = "com.apple.product-type.framework"; @@ -1403,10 +1980,33 @@ dependencies = ( ); name = StaticLibrary_ObjC_macOS; + packageProductDependencies = ( + ); productName = StaticLibrary_ObjC_macOS; productReference = 86169DEEDEAF09AB89C8A31D /* libStaticLibrary_ObjC.a */; productType = "com.apple.product-type.library.static"; }; + 63BFF75AA22335E3DDD5E26A /* App_Clip_Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 498FA7414845B8834E48496F /* Build configuration list for PBXNativeTarget "App_Clip_Tests" */; + buildPhases = ( + F39FAD4CC93306087D129EBD /* Sources */, + 6D6C0891A16EFF2FDA9D25AF /* Frameworks */, + 30A8F3568B05F3DB13D8B466 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + A19BEE3154D879101F865BB2 /* PBXTargetDependency */, + 2D1B4333107E10912508724E /* PBXTargetDependency */, + ); + name = App_Clip_Tests; + packageProductDependencies = ( + ); + productName = App_Clip_Tests; + productReference = 3FC04772130400920D68A167 /* App_Clip_Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 6ED01BC471A8C3642258E178 /* Framework2_watchOS */ = { isa = PBXNativeTarget; buildConfigurationList = 7E4887637B4FA5B8E2F349CA /* Build configuration list for PBXNativeTarget "Framework2_watchOS" */; @@ -1419,6 +2019,8 @@ dependencies = ( ); name = Framework2_watchOS; + packageProductDependencies = ( + ); productName = Framework2_watchOS; productReference = AB055761199DF36DB0C629A6 /* Framework2.framework */; productType = "com.apple.product-type.framework"; @@ -1435,9 +2037,12 @@ buildRules = ( ); dependencies = ( + 0C99705018337CE91AA34CBA /* PBXTargetDependency */, 35DF16CA4A1F88140CF69620 /* PBXTargetDependency */, ); name = Framework_watchOS; + packageProductDependencies = ( + ); productName = Framework_watchOS; productReference = 6177CC6263783487E93F7F4D /* Framework.framework */; productType = "com.apple.product-type.framework"; @@ -1447,7 +2052,6 @@ buildConfigurationList = 62C52A55CB8D3BD9A055FD14 /* Build configuration list for PBXNativeTarget "App_macOS_Tests" */; buildPhases = ( 8A616537E6E1BEAB59E069C7 /* Sources */, - 6CB76DFA8662672C4245AF41 /* Embed Frameworks */, ); buildRules = ( ); @@ -1455,6 +2059,8 @@ 8B1B6143B8996B3CF0FE61C5 /* PBXTargetDependency */, ); name = App_macOS_Tests; + packageProductDependencies = ( + ); productName = App_macOS_Tests; productReference = 0B9D98D935F2C69A1F5BA539 /* App_macOS_Tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; @@ -1471,6 +2077,8 @@ dependencies = ( ); name = StaticLibrary_ObjC_watchOS; + packageProductDependencies = ( + ); productName = StaticLibrary_ObjC_watchOS; productReference = 46DD8F9AAC104BDB63793625 /* libStaticLibrary_ObjC.a */; productType = "com.apple.product-type.library.static"; @@ -1480,7 +2088,7 @@ buildConfigurationList = 1FC6945BE13C2202A2BCA3BC /* Build configuration list for PBXNativeTarget "iMessageApp" */; buildPhases = ( 61001E265009194959C2CF36 /* Resources */, - 2F0735A423E554B267BBA0A5 /* Embed App Extensions */, + EB212BCB1E2E1D2667233F98 /* Embed Foundation Extensions */, ); buildRules = ( ); @@ -1488,6 +2096,8 @@ 053FF4219E7A0E38E90071B0 /* PBXTargetDependency */, ); name = iMessageApp; + packageProductDependencies = ( + ); productName = iMessageApp; productReference = 9A87A926D563773658FB87FE /* iMessageApp.app */; productType = "com.apple.product-type.application.messages"; @@ -1504,10 +2114,30 @@ dependencies = ( ); name = Framework2_tvOS; + packageProductDependencies = ( + ); productName = Framework2_tvOS; productReference = A0DC40025AB59B688E758829 /* Framework2.framework */; productType = "com.apple.product-type.framework"; }; + 91C3E922A8482E07649971B9 /* App_Clip_UITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 129D9E77D45A66B1C78578F2 /* Build configuration list for PBXNativeTarget "App_Clip_UITests" */; + buildPhases = ( + 2E1429F0FB524A2BCFC61DF1 /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + 1341A437B2D0402F4F4CEA51 /* PBXTargetDependency */, + ); + name = App_Clip_UITests; + packageProductDependencies = ( + ); + productName = App_Clip_UITests; + productReference = 7C7EC00B53FF878007F6ECAB /* App_Clip_UITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; 93542A75A613F00FDB5C9C63 /* StaticLibrary_ObjC_tvOS */ = { isa = PBXNativeTarget; buildConfigurationList = 906B8E5233EE4169E84ABAF3 /* Build configuration list for PBXNativeTarget "StaticLibrary_ObjC_tvOS" */; @@ -1520,17 +2150,54 @@ dependencies = ( ); name = StaticLibrary_ObjC_tvOS; + packageProductDependencies = ( + ); productName = StaticLibrary_ObjC_tvOS; productReference = 469B630D28015F0EDC456F6B /* libStaticLibrary_ObjC.a */; productType = "com.apple.product-type.library.static"; }; + 9F551F66949B55E8328EB995 /* EndpointSecuritySystemExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = C4FB84AAA6F6974CEA51D359 /* Build configuration list for PBXNativeTarget "EndpointSecuritySystemExtension" */; + buildPhases = ( + EAFB6030AE5D2E4D9ACA6ECC /* Sources */, + E63B2ED6C095617F6F53C14A /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = EndpointSecuritySystemExtension; + packageProductDependencies = ( + ); + productName = EndpointSecuritySystemExtension; + productReference = E5E0A80CCE8F8DB662DCD2D0 /* EndpointSecuritySystemExtension.systemextension */; + productType = "com.apple.product-type.system-extension"; + }; + AD28397BCC984F769EE8A937 /* NetworkSystemExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 78DB808B74D58314279E7FD7 /* Build configuration list for PBXNativeTarget "NetworkSystemExtension" */; + buildPhases = ( + DEB2782C650F563EB8C62B28 /* Sources */, + 7448069D11FB1A170F943C90 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = NetworkSystemExtension; + packageProductDependencies = ( + ); + productName = NetworkSystemExtension; + productReference = 2049B6DD2AFE85F9DC9F3EB3 /* NetworkSystemExtension.systemextension */; + productType = "com.apple.product-type.system-extension"; + }; AE3F93DB94E7208F2F1D9A78 /* Framework_iOS */ = { isa = PBXNativeTarget; buildConfigurationList = 50DA67E9A951C40D9536609D /* Build configuration list for PBXNativeTarget "Framework_iOS" */; buildPhases = ( 0D09E5BA6B8442DC0ABB8AA6 /* Headers */, 40A4456A24F99A01E340C032 /* Sources */, - 9B861C58E640BD4AD391900C /* Frameworks */, 43E9CD3CEA3FE8944C659368 /* MyScript */, ); buildRules = ( @@ -1539,6 +2206,8 @@ 486D84E583999BAA22C679EC /* PBXTargetDependency */, ); name = Framework_iOS; + packageProductDependencies = ( + ); productName = Framework_iOS; productReference = 8A9274BE42A03DC5DA1FAD04 /* Framework.framework */; productType = "com.apple.product-type.framework"; @@ -1554,10 +2223,51 @@ dependencies = ( ); name = EntitledApp; + packageProductDependencies = ( + ); productName = EntitledApp; productReference = 7D700FA699849D2F95216883 /* EntitledApp.app */; productType = "com.apple.product-type.application"; }; + C0570E2FB50D830D8D423396 /* App_supportedDestinations */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5EC789CCE1928A4CDA00DD1E /* Build configuration list for PBXNativeTarget "App_supportedDestinations" */; + buildPhases = ( + CF8BAE171BAAFB2E5DDB9C19 /* Sources */, + 97119CD9F01D9A9522EF3526 /* Resources */, + 36418B6CABA06BA9B206556E /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = App_supportedDestinations; + packageProductDependencies = ( + C7F9B7EDE85527EFEA85D46D /* Swinject */, + ); + productName = App_supportedDestinations; + productReference = 407C3F0009FDCE5B1B7DC2A8 /* App_supportedDestinations.app */; + productType = "com.apple.product-type.application"; + }; + C7F90FD0FAAF232B3E015D38 /* CrossOverlayFramework_watchOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = C483BD5456B09C276DE6EFC1 /* Build configuration list for PBXNativeTarget "CrossOverlayFramework_watchOS" */; + buildPhases = ( + ADD98000970B8907F73BFD92 /* CopyFiles */, + A24F1A0AC15CAE82CD3EDFE2 /* Headers */, + C975C5F0085D232AF63E0F3E /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = CrossOverlayFramework_watchOS; + packageProductDependencies = ( + ); + productName = CrossOverlayFramework_watchOS; + productReference = 89EB41A001D8BF26431C5798 /* CrossOverlayFramework.framework */; + productType = "com.apple.product-type.framework"; + }; CE7D183D3752B5B35D2D8E6D /* Framework2_iOS */ = { isa = PBXNativeTarget; buildConfigurationList = 9A0EF0B71AD44055E8749C42 /* Build configuration list for PBXNativeTarget "Framework2_iOS" */; @@ -1570,10 +2280,51 @@ dependencies = ( ); name = Framework2_iOS; + packageProductDependencies = ( + ); productName = Framework2_iOS; productReference = 3EF21DF245F66BEF5446AAEF /* Framework2.framework */; productType = "com.apple.product-type.framework"; }; + D137C04B64B7052419A2DF4E /* App_Clip */ = { + isa = PBXNativeTarget; + buildConfigurationList = 07B4E73E56B7C2C80DE2A378 /* Build configuration list for PBXNativeTarget "App_Clip" */; + buildPhases = ( + 6F11C066A401E4F02A1188EB /* Sources */, + AFA07EE1616E0EE7065760C9 /* Resources */, + DFDFD9EDAD45D89D1080FC5D /* Frameworks */, + 848740AD60C4329197FF876B /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + FD2D68EC95DC231C4007FB08 /* PBXTargetDependency */, + BE9300E427142E634A8A91B8 /* PBXTargetDependency */, + CFEACC1CED73B52EA1CCD054 /* PBXTargetDependency */, + ); + name = App_Clip; + packageProductDependencies = ( + ); + productName = App_Clip; + productReference = 38DB679FF1CF4E379D1AB103 /* App_Clip.app */; + productType = "com.apple.product-type.application.on-demand-install-capable"; + }; + DA40AB367B606CCE2FDD398D /* BundleX */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2C39D94CF9C8B1CB79F04AC8 /* Build configuration list for PBXNativeTarget "BundleX" */; + buildPhases = ( + ); + buildRules = ( + ); + dependencies = ( + ); + name = BundleX; + packageProductDependencies = ( + ); + productName = BundleX; + productReference = 84317819C92F78425870E483 /* BundleX.bundle */; + productType = "com.apple.product-type.bundle"; + }; DC2F16BAA6E13B44AB62F888 /* App_iOS_Tests */ = { isa = PBXNativeTarget; buildConfigurationList = F888428CB91ACDDAAE8C8F21 /* Build configuration list for PBXNativeTarget "App_iOS_Tests" */; @@ -1589,10 +2340,29 @@ 6AE62A40F64046B597B07801 /* PBXTargetDependency */, ); name = App_iOS_Tests; + packageProductDependencies = ( + ); productName = App_iOS_Tests; productReference = CB77A637470A3CDA2BDDBE99 /* App_iOS_Tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + E7454C10EA126A93537DD57E /* ExternalTarget */ = { + isa = PBXNativeTarget; + buildConfigurationList = D9EF39CA9A17477264F02057 /* Build configuration list for PBXNativeTarget "ExternalTarget" */; + buildPhases = ( + E3C67D44BD5D2820592267FD /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ExternalTarget; + packageProductDependencies = ( + ); + productName = ExternalTarget; + productReference = 2385A62F6C6EE8D461EE19F2 /* ExternalTarget.framework */; + productType = "com.apple.product-type.framework"; + }; E7815F2F0D9CDECF9185AAF3 /* XPC Service */ = { isa = PBXNativeTarget; buildConfigurationList = D379D1BBEF24ED05EB6ADEB3 /* Build configuration list for PBXNativeTarget "XPC Service" */; @@ -1604,6 +2374,8 @@ dependencies = ( ); name = "XPC Service"; + packageProductDependencies = ( + ); productName = "XPC Service"; productReference = 22237B8EBD9E6BE8EBC8735F /* XPC Service.xpc */; productType = "com.apple.product-type.xpc-service"; @@ -1613,7 +2385,6 @@ buildConfigurationList = 68CC35789B0DB020E2CFC517 /* Build configuration list for PBXNativeTarget "App_iOS_UITests" */; buildPhases = ( 7334BD12862A3CED4BE1C6B5 /* Sources */, - 08DA9F1F0ED13AC054003B27 /* Embed Frameworks */, ); buildRules = ( ); @@ -1621,6 +2392,8 @@ 49587048934568C2182DA825 /* PBXTargetDependency */, ); name = App_iOS_UITests; + packageProductDependencies = ( + ); productName = App_iOS_UITests; productReference = 13EEAB58665D79C15184D9D0 /* App_iOS_UITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; @@ -1637,6 +2410,8 @@ dependencies = ( ); name = Framework2_macOS; + packageProductDependencies = ( + ); productName = Framework2_macOS; productReference = 2233774B86539B1574D206B0 /* Framework2.framework */; productType = "com.apple.product-type.framework"; @@ -1647,7 +2422,8 @@ 0FBAE303E3CFC2ABAC876A77 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1430; TargetAttributes = { 020A320BB3736FCDE6CC4E70 = { ProvisioningStyle = Automatic; @@ -1655,6 +2431,9 @@ 0867B0DACEF28C11442DE8F7 = { ProvisioningStyle = Automatic; }; + 91C3E922A8482E07649971B9 = { + TestTargetID = D137C04B64B7052419A2DF4E; + }; BF3693DCA6182D7AEC410AFC = { CUSTOM = value; }; @@ -1668,7 +2447,7 @@ ); }; buildConfigurationList = D91E14E36EC0B415578456F2 /* Build configuration list for PBXProject "Project" */; - compatibilityVersion = "Xcode 10.0"; + compatibilityVersion = "Xcode 14.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -1676,6 +2455,11 @@ en, ); mainGroup = 293D0FF827366B513839236A; + minimizedProjectReferenceProxies = 1; + packageReferences = ( + 4EDA79334592CBBA0E507AD2 /* XCRemoteSwiftPackageReference "Swinject" */, + ); + preferredProjectObjectVersion = 77; projectDirPath = ""; projectReferences = ( { @@ -1685,14 +2469,27 @@ ); projectRoot = ""; targets = ( + D137C04B64B7052419A2DF4E /* App_Clip */, + 63BFF75AA22335E3DDD5E26A /* App_Clip_Tests */, + 91C3E922A8482E07649971B9 /* App_Clip_UITests */, 0867B0DACEF28C11442DE8F7 /* App_iOS */, DC2F16BAA6E13B44AB62F888 /* App_iOS_Tests */, F674B2CFC4738EEC49BAD0DA /* App_iOS_UITests */, 020A320BB3736FCDE6CC4E70 /* App_macOS */, 71E2BDAC4B8E8FC2BBF75C55 /* App_macOS_Tests */, + C0570E2FB50D830D8D423396 /* App_supportedDestinations */, 208179651927D1138D19B5AD /* App_watchOS */, 307AE3FA155FFD09B74AE351 /* App_watchOS Extension */, + DA40AB367B606CCE2FDD398D /* BundleX */, + 271CAC331D24F4F7E12C819C /* BundleY */, + 0CE8BE7C80651629EC056066 /* CrossOverlayFramework_iOS */, + 2F4FEAEFD7EE82DC49D899FC /* CrossOverlayFramework_macOS */, + 3BF66A4668DFAF9338791F60 /* CrossOverlayFramework_tvOS */, + C7F90FD0FAAF232B3E015D38 /* CrossOverlayFramework_watchOS */, + 428715FBC1D86458DA70CBDE /* DriverKitDriver */, + 9F551F66949B55E8328EB995 /* EndpointSecuritySystemExtension */, B61ED4688789B071275E2B7A /* EntitledApp */, + E7454C10EA126A93537DD57E /* ExternalTarget */, CE7D183D3752B5B35D2D8E6D /* Framework2_iOS */, FC26AF2506D3B2B40DE8A5F8 /* Framework2_macOS */, 8B9A14DC280CCE013CC86440 /* Framework2_tvOS */, @@ -1701,7 +2498,9 @@ 53A3B531E3947D8A8722745E /* Framework_macOS */, 536ACF18E4603B59207D43CE /* Framework_tvOS */, 71B5187E710718C1A205D4DC /* Framework_watchOS */, + 700328EE1570207608D6ADB3 /* IncludedLegacy */, 72C923899DE05F1281872160 /* Legacy */, + AD28397BCC984F769EE8A937 /* NetworkSystemExtension */, 13E8C5AB873CEE21E18E552F /* StaticLibrary_ObjC_iOS */, 578C80E461E675508CED5DC3 /* StaticLibrary_ObjC_macOS */, 93542A75A613F00FDB5C9C63 /* StaticLibrary_ObjC_tvOS */, @@ -1768,9 +2567,11 @@ buildActionMask = 2147483647; files = ( 447D59BE2E0993D7245EA247 /* Assets.xcassets in Resources */, + 94FD20C3EA5EBCEC8783740C /* GoogleService-Info.plist in Resources */, A9548E5DCFE92236494164DF /* LaunchScreen.storyboard in Resources */, 6E8F8303759824631C8D9DA3 /* Localizable.strings in Resources */, E5DD0AD6F7AE1DD4AF98B83E /* Localizable.stringsdict in Resources */, + 76F3F9A5E2A4623430374F31 /* LocalizableStrings.xcstrings in Resources */, 2A7EB1A9A365A7EC5D49AFCF /* LocalizedStoryboard.storyboard in Resources */, 49A4B8937BB5520B36EA33F0 /* Main.storyboard in Resources */, 900CFAD929CAEE3861127627 /* MyBundle.bundle in Resources */, @@ -1783,6 +2584,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 97119CD9F01D9A9522EF3526 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2698ED273D0A5820B28CAD20 /* LaunchScreen.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; AA12B5909FEE45016F469C78 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -1791,6 +2600,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + AFA07EE1616E0EE7065760C9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 61516CAC12B2843FBC4572E6 /* Assets.xcassets in Resources */, + B18C121B0A4D43ED8149D8E2 /* LaunchScreen.storyboard in Resources */, + 0F99AECCB4691803C791CDCE /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; B7B71FA7D279029BF7A7FC7C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -1819,22 +2638,6 @@ shellPath = /bin/sh; shellScript = "ditto \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\n"; }; - 37182EC208DBF03DB1BAF452 /* Carthage */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "$(SRCROOT)/Carthage/Build/iOS/Result.framework", - ); - name = Carthage; - outputPaths = ( - "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Result.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "carthage copy-frameworks\n"; - }; 3D0637F4554EAD6FA48105BF /* MyScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1873,6 +2676,7 @@ }; 71A4CC6ECC8522178F566E7B /* Strip Unused Architectures from Frameworks */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -1907,22 +2711,6 @@ shellPath = /bin/sh; shellScript = "echo \"You ran a script\"\n"; }; - 8F8EE32AFABD8FEF97625325 /* Carthage */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "$(SRCROOT)/Carthage/Build/watchOS/Result.framework", - ); - name = Carthage; - outputPaths = ( - "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Result.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "carthage copy-frameworks\n"; - }; BA454AAC926EDFCDA9226CBC /* MyScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1944,6 +2732,7 @@ CBE633966E8F3819F15270A3 /* MyScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; + dependencyFile = "$(DERIVED_FILE_DIR)/target.d"; files = ( ); inputFileListPaths = ( @@ -1959,7 +2748,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "echo \"You ran a script!\"\n"; + shellScript = "echo \"You ran a script!\"\ntouch \"${DERIVED_FILE_DIR}/target.d\"\n"; }; CF3AABFD4A48983B322677DA /* MyScript */ = { isa = PBXShellScriptBuildPhase; @@ -2023,6 +2812,23 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 2E1429F0FB524A2BCFC61DF1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2116F89CF5A04EA0EFA30A89 /* TestProjectUITests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3422D8A97652F33BA3AEAD6E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0932FB6FB887D7D6F7727CB7 /* Driver.cpp in Sources */, + FB6DA0DB62C425066D51767E /* Driver.iig in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 40A4456A24F99A01E340C032 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -2055,11 +2861,21 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 6F11C066A401E4F02A1188EB /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 15129B8D9ED000BDA1FEEC27 /* AppDelegate.swift in Sources */, + C4378E3DAF5E0B2F7AB60E03 /* ViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 6F573D15DE1F149EF128C492 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 09617AB755651FFEB2564CBC /* AppDelegate.swift in Sources */, + 1F9168A43FD8E2FCC2699E14 /* Documentation.docc in Sources */, 666DEC173BC78C7641AB22EC /* File1.swift in Sources */, 339578307B9266AB3D7722D9 /* File2.swift in Sources */, F788A3FA1CE6489BC257C1C3 /* Model.xcdatamodeld in Sources */, @@ -2079,34 +2895,42 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 8A616537E6E1BEAB59E069C7 /* Sources */ = { + 82E24A8257F299AC04F44A8F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - B9F3C9E77019EC3423A7F5D8 /* TestProjectTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 8FD76C583F8C166F974F4BE2 /* Sources */ = { + 84FEBA4F84620938800D12A4 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - D61BEABD5B26B2DE67D0C2EC /* FrameworkFile.swift in Sources */, + 1EFFFE113C5E54A91148D3EB /* FrameworkFile.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 902C8700CD150C726365CB8A /* Sources */ = { + 8A616537E6E1BEAB59E069C7 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 9D80BD5FAE6BE61CFD74CF1B /* FrameworkFile.swift in Sources */, + B9F3C9E77019EC3423A7F5D8 /* TestProjectTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8FD76C583F8C166F974F4BE2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D61BEABD5B26B2DE67D0C2EC /* FrameworkFile.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 91C895DE8170C96A75D29426 /* Sources */ = { + 902C8700CD150C726365CB8A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9D80BD5FAE6BE61CFD74CF1B /* FrameworkFile.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2167,6 +2991,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + A87FBABC2AA10F8D044526BD /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6C02002A4EE169CEBEC7BA7F /* FrameworkFile.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; AE7971E1CA54D23C264E6541 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -2184,30 +3016,93 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - D1F422E9C4DD531AA88418C9 /* Sources */ = { + C975C5F0085D232AF63E0F3E /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 998CCB995347CBB8EDC95FB5 /* FrameworkFile.swift in Sources */, + 713F57A10C62F70058D7FB0A /* FrameworkFile.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - EA88FE285DA490166635BE98 /* Sources */ = { + CF8BAE171BAAFB2E5DDB9C19 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 3318F40C855184C18197ED30 /* StaticLibrary_ObjC.m in Sources */, + CAF8470C7F1BF207DBE6AEE3 /* ContentView.swift in Sources */, + 1B485D6584C3B47AC58831C6 /* ContentView.swift in Sources */, + B358AB913543E62237FCC4E3 /* MyAppApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 053FF4219E7A0E38E90071B0 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 1C26A6A0BC446191F311D470 /* iMessageExtension */; - targetProxy = C8FD369800D87311EC532712 /* PBXContainerItemProxy */; - }; + D1F422E9C4DD531AA88418C9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 998CCB995347CBB8EDC95FB5 /* FrameworkFile.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DEB2782C650F563EB8C62B28 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E0B27599D701E6BB0223D0A8 /* FilterDataProvider.swift in Sources */, + A90C4C147AD175DB9F7B5114 /* main.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E3C67D44BD5D2820592267FD /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E9BE8745FD5B1ACBE43B9E0C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 03FFCE664129864A8F167C2F /* FrameworkFile.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EA88FE285DA490166635BE98 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3318F40C855184C18197ED30 /* StaticLibrary_ObjC.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EAFB6030AE5D2E4D9ACA6ECC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CAE18A2194B57C830A297F83 /* main.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F39FAD4CC93306087D129EBD /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6B0BCD3573931F7BE133B301 /* TestProjectTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 053FF4219E7A0E38E90071B0 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1C26A6A0BC446191F311D470 /* iMessageExtension */; + targetProxy = C8FD369800D87311EC532712 /* PBXContainerItemProxy */; + }; + 0C99705018337CE91AA34CBA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 6ED01BC471A8C3642258E178 /* Framework2_watchOS */; + targetProxy = 59BFAC272F73B46E97B74426 /* PBXContainerItemProxy */; + }; 0D33D01C71E8002A07F02122 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 208179651927D1138D19B5AD /* App_watchOS */; @@ -2218,6 +3113,21 @@ target = AE3F93DB94E7208F2F1D9A78 /* Framework_iOS */; targetProxy = 2FA0A954833DB0981CDE58E1 /* PBXContainerItemProxy */; }; + 1341A437B2D0402F4F4CEA51 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D137C04B64B7052419A2DF4E /* App_Clip */; + targetProxy = 0B37F7A37D610FCFE187A6B7 /* PBXContainerItemProxy */; + }; + 1652DB87B43B72B5DE0601C4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 9F551F66949B55E8328EB995 /* EndpointSecuritySystemExtension */; + targetProxy = DD32A97CFD2016BF1477CF6C /* PBXContainerItemProxy */; + }; + 2D1B4333107E10912508724E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 0636AAF06498C336E1CEEDE4 /* TestFramework */; + targetProxy = 69E205A3F578A8FFE3ECF3F9 /* PBXContainerItemProxy */; + }; 35DF16CA4A1F88140CF69620 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 7D3D92034F4F203C140574F0 /* StaticLibrary_ObjC_watchOS */; @@ -2253,6 +3163,11 @@ target = 0636AAF06498C336E1CEEDE4 /* TestFramework */; targetProxy = C42BA4EA0239AF536F0F0993 /* PBXContainerItemProxy */; }; + 6BE35B7C058BE1B6F3B906C0 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 428715FBC1D86458DA70CBDE /* DriverKitDriver */; + targetProxy = 6ED42BD51E8832232E58D9C1 /* PBXContainerItemProxy */; + }; 7EFC0278E67CD35F8981993C /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 578C80E461E675508CED5DC3 /* StaticLibrary_ObjC_macOS */; @@ -2263,13 +3178,24 @@ target = 020A320BB3736FCDE6CC4E70 /* App_macOS */; targetProxy = 610412261F48A0A36C32FC5C /* PBXContainerItemProxy */; }; + 8B6243D8D47A6ADA4CA0D7BD /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D137C04B64B7052419A2DF4E /* App_Clip */; + targetProxy = 25714659454527D9511C6093 /* PBXContainerItemProxy */; + }; 981D116D40DBA0407D0E0E94 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 834F55973F05AC8A18144DB0 /* iMessageApp */; targetProxy = 57F1BE74D4C4252529F97984 /* PBXContainerItemProxy */; }; + A19BEE3154D879101F865BB2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D137C04B64B7052419A2DF4E /* App_Clip */; + targetProxy = 747773057270E6F58470B5FA /* PBXContainerItemProxy */; + }; A94F38390A74E215EC107BB5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; + platformFilter = ios; target = CE7D183D3752B5B35D2D8E6D /* Framework2_iOS */; targetProxy = D3E1EE9F1E22A388123A116D /* PBXContainerItemProxy */; }; @@ -2283,16 +3209,31 @@ target = E7815F2F0D9CDECF9185AAF3 /* XPC Service */; targetProxy = 8BAA7F3717FCBE0B8D6669B3 /* PBXContainerItemProxy */; }; + BE9300E427142E634A8A91B8 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = AE3F93DB94E7208F2F1D9A78 /* Framework_iOS */; + targetProxy = 7E37A3C0A67C3B6363029A18 /* PBXContainerItemProxy */; + }; CE96B0951433713033A03DCD /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 93542A75A613F00FDB5C9C63 /* StaticLibrary_ObjC_tvOS */; targetProxy = CB8F4B3FDD84A2A6F3CA7F4C /* PBXContainerItemProxy */; }; + CFEACC1CED73B52EA1CCD054 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 13E8C5AB873CEE21E18E552F /* StaticLibrary_ObjC_iOS */; + targetProxy = 01630C98B755921A79418B08 /* PBXContainerItemProxy */; + }; D19F2660FAD44CCC4390265C /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 0867B0DACEF28C11442DE8F7 /* App_iOS */; targetProxy = 3A81C6D6875469889D53A2C5 /* PBXContainerItemProxy */; }; + D6C733BEB62EAA62CCC68556 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8B9A14DC280CCE013CC86440 /* Framework2_tvOS */; + targetProxy = 45907115465077029040BF29 /* PBXContainerItemProxy */; + }; E84285243DE0BB361A708079 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = AE3F93DB94E7208F2F1D9A78 /* Framework_iOS */; @@ -2308,6 +3249,16 @@ target = 53A3B531E3947D8A8722745E /* Framework_macOS */; targetProxy = 7F4EAACE4AD6CF285B7D3308 /* PBXContainerItemProxy */; }; + F7532D3474E04037FF26E9BC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = AD28397BCC984F769EE8A937 /* NetworkSystemExtension */; + targetProxy = D4A7C57F6272F44F2E69A5DB /* PBXContainerItemProxy */; + }; + FD2D68EC95DC231C4007FB08 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = ExternalTarget; + targetProxy = CA16090DFCA7842CB4E20265 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -2320,6 +3271,14 @@ name = LocalizedStoryboard.storyboard; sourceTree = ""; }; + 2FC2A8A829CE71B1CF415FF7 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 3096A0760969873D46F80A92 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; 65C8D6D1DDC1512D396C07B7 /* Localizable.stringsdict */ = { isa = PBXVariantGroup; children = ( @@ -2345,6 +3304,14 @@ name = MainInterface.storyboard; sourceTree = ""; }; + 79325B44B19B83EC6CEDBCC5 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + F15E5C60B7E05D06B1B8E18E /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; 814D72C2B921F60B759C2D4B /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -2408,10 +3375,6 @@ 00FD318C7418F3351FC00744 /* Test Debug */ = { isa = XCBuildConfiguration; buildSettings = { - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/watchOS", - ); INFOPLIST_FILE = App_watchOS/Info.plist; PRODUCT_BUNDLE_IDENTIFIER = com.project.app.watch; SDKROOT = watchos; @@ -2430,10 +3393,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/watchOS", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.project.Framework-watchOS"; @@ -2460,6 +3419,30 @@ }; name = "Staging Release"; }; + 02E38E444E372E89E589E022 /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-tvOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 3; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Production Debug"; + }; 02EB0C0230E6616EC8057F1C /* Staging Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -2475,15 +3458,42 @@ }; name = "Staging Debug"; }; - 04172E0BDC7C512A23A51C76 /* Staging Release */ = { + 035FC5362AE3E9696248DFD0 /* Production Debug */ = { isa = XCBuildConfiguration; buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( + CODE_SIGN_ENTITLEMENTS = "DriverKit Driver/Driver.entitlements"; + COMBINE_HIDPI_IMAGES = YES; + DRIVERKIT_DEPLOYMENT_TARGET = 20.4; + INFOPLIST_FILE = "DriverKit Driver/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-macOS.Driver"; + SDKROOT = driverkit; + }; + name = "Production Debug"; + }; + 03B133682B8BEF8B1D647C76 /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = "DriverKit Driver/Driver.entitlements"; + COMBINE_HIDPI_IMAGES = YES; + DRIVERKIT_DEPLOYMENT_TARGET = 20.4; + INFOPLIST_FILE = "DriverKit Driver/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", + "@executable_path/../Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-macOS.Driver"; + SDKROOT = driverkit; + }; + name = "Production Release"; + }; + 04172E0BDC7C512A23A51C76 /* Staging Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; INFOPLIST_FILE = App_iOS_UITests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -2497,6 +3507,48 @@ }; name = "Staging Release"; }; + 045CB2D74D9A3532E128BDD2 /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.external; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Production Release"; + }; + 0579BA94EA238151DAFC2FFC /* Test Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = App_Clip/Clip.entitlements; + INFOPLIST_FILE = App_Clip/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.app.clip; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Test Release"; + }; 058734C3B593A26E24211133 /* Test Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -2508,16 +3560,26 @@ }; name = "Test Release"; }; + 06D6C7ED89937E7891E70B55 /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = "EndpointSecurity Extension/EndpointSecurity.entitlements"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "EndpointSecurity Extension/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-macOS.EndpointSecurity"; + SDKROOT = macosx; + }; + name = "Production Release"; + }; 06E4383A2687EAD5877836CD /* Staging Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", - ); INFOPLIST_FILE = App_iOS/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -2553,15 +3615,27 @@ }; name = "Production Debug"; }; - 082A10B9E5EAC6E783EAB9B0 /* Production Debug */ = { + 07DF024D82D64A8D76209B90 /* Production Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( + INFOPLIST_FILE = App_Clip_UITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", + "@executable_path/Frameworks", + "@loader_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-Clip-UITests"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = App_Clip; + }; + name = "Production Debug"; + }; + 082A10B9E5EAC6E783EAB9B0 /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; INFOPLIST_FILE = App_iOS_UITests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -2579,11 +3653,6 @@ isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", - ); INFOPLIST_FILE = App_iOS_UITests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -2597,14 +3666,25 @@ }; name = "Test Debug"; }; - 0C66F8A2D0CB0D802A327EB4 /* Test Release */ = { + 0C18EEAE68FBEBCF066E0CD9 /* Test Release */ = { isa = XCBuildConfiguration; buildSettings = { - ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; - FRAMEWORK_SEARCH_PATHS = ( + CODE_SIGN_ENTITLEMENTS = "Network Extension/NetworkExtension.entitlements"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "Network Extension/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/watchOS", + "@executable_path/../Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-macOS.NetworkExtension"; + SDKROOT = macosx; + }; + name = "Test Release"; + }; + 0C66F8A2D0CB0D802A327EB4 /* Test Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; INFOPLIST_FILE = "App_watchOS Extension/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -2637,11 +3717,6 @@ isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", - ); INFOPLIST_FILE = App_iOS_Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -2679,15 +3754,26 @@ }; name = "Test Debug"; }; - 12BCDE0EFCEE621B881E424C /* Test Release */ = { + 11919FD24AA8A110C24C0FEF /* Test Release */ = { isa = XCBuildConfiguration; buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_ENTITLEMENTS = "EndpointSecurity Extension/EndpointSecurity.entitlements"; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( + INFOPLIST_FILE = "EndpointSecurity Extension/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", + "@executable_path/../Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-macOS.EndpointSecurity"; + SDKROOT = macosx; + }; + name = "Test Release"; + }; + 12BCDE0EFCEE621B881E424C /* Test Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = App_macOS_Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -2734,10 +3820,6 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/watchOS", - ); INFOPLIST_FILE = "App_watchOS Extension/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -2795,11 +3877,6 @@ isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", - ); INFOPLIST_FILE = App_iOS_UITests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -2831,11 +3908,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", - ); - INFOPLIST_FILE = App_macOS/Info.plist; + INFOPLIST_FILE = "App_macOS/App-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", @@ -2849,27 +3922,111 @@ }; name = "Test Debug"; }; - 1D61DC7F5309F4C8B7692D85 /* Test Release */ = { + 19BF18E6EAA8B30F894EAB4E /* Test Release */ = { isa = XCBuildConfiguration; buildSettings = { - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.project.StaticLibrary-Swift"; - SDKROOT = iphoneos; + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-watchOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = watchos; SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 4; + VERSIONING_SYSTEM = "apple-generic"; }; name = "Test Release"; }; - 20803EC42C26E4EA13474E5A /* Production Debug */ = { + 1C63C4A728212D903E4F2CBB /* Test Release */ = { isa = XCBuildConfiguration; buildSettings = { - FRAMEWORK_SEARCH_PATHS = ( + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-iOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Test Release"; + }; + 1C644E47F1C539F2B95160B8 /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-watchOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = watchos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 4; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Production Debug"; + }; + 1D61DC7F5309F4C8B7692D85 /* Test Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/watchOS", + "@executable_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.StaticLibrary-Swift"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Test Release"; + }; + 1FB2AFB2F45076B4A047499E /* Staging Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-iOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Staging Debug"; + }; + 20803EC42C26E4EA13474E5A /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { INFOPLIST_FILE = App_watchOS/Info.plist; PRODUCT_BUNDLE_IDENTIFIER = com.project.app.watch; SDKROOT = watchos; @@ -2879,6 +4036,19 @@ }; name = "Production Debug"; }; + 221A50372FFB2F1202940FDC /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.IncludedLegacy; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Production Debug"; + }; 234640A811EF6EB9CC9081CA /* Staging Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -2915,6 +4085,26 @@ }; name = "Staging Debug"; }; + 24CFBB3ABB9E14E85035B892 /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + INFOPLIST_FILE = App_supportedDestinations/Info.generated.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.test.TestApp; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator appletvos appletvsimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES; + TARGETED_DEVICE_FAMILY = "1,2,3"; + }; + name = "Production Debug"; + }; 2569D399CA3C4828EF87AD78 /* Test Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -2924,10 +4114,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/tvOS", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -2953,10 +4139,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -3007,15 +4189,66 @@ }; name = "Production Release"; }; - 2F1CDD64CD0684A2B09D6ED3 /* Staging Debug */ = { + 291A37106E83E5C30890F422 /* Staging Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = "DriverKit Driver/Driver.entitlements"; + COMBINE_HIDPI_IMAGES = YES; + DRIVERKIT_DEPLOYMENT_TARGET = 20.4; + INFOPLIST_FILE = "DriverKit Driver/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-macOS.Driver"; + SDKROOT = driverkit; + }; + name = "Staging Debug"; + }; + 2C6AB16720ADFB2436337A8F /* Test Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.external; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Test Debug"; + }; + 2E5159957368A9CF77A3C9FC /* Test Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( + INFOPLIST_FILE = App_iOS_Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", + "@executable_path/Frameworks", + "@loader_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-Clip-Tests"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/App_Clip.app/App_Clip"; + }; + name = "Test Debug"; + }; + 2F1CDD64CD0684A2B09D6ED3 /* Staging Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; INFOPLIST_FILE = App_iOS_Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3033,11 +4266,6 @@ isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", - ); INFOPLIST_FILE = App_iOS_Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3051,6 +4279,85 @@ }; name = "Test Debug"; }; + 31931061043C66589547105C /* Staging Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.BundleX; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Staging Debug"; + }; + 321D6FAF1E7AA977008359C7 /* Staging Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-tvOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 3; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Staging Debug"; + }; + 3236B7B20520584116A96C0D /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = App_Clip_UITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-Clip-UITests"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = App_Clip; + }; + name = "Production Release"; + }; + 34ED16009A759D256D7ECB53 /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-macOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = macosx; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Production Release"; + }; 366C92A637FDA940E6BCB591 /* Staging Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -3096,6 +4403,42 @@ }; name = "Production Release"; }; + 3BDE7967B50F4358BD4702AD /* Test Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = App_Clip_UITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-Clip-UITests"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = App_Clip; + }; + name = "Test Debug"; + }; + 3BE60579CA725E23659AEA80 /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = App_Clip/Clip.entitlements; + INFOPLIST_FILE = App_Clip/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.app.clip; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Production Release"; + }; 3DEEA480EDDC83405CFB9BBA /* Test Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -3114,11 +4457,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", - ); - INFOPLIST_FILE = App_macOS/Info.plist; + INFOPLIST_FILE = "App_macOS/App-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", @@ -3165,10 +4504,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/tvOS", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -3191,6 +4526,20 @@ }; name = "Production Debug"; }; + 414544E2FA4DE102442A71CD /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.BundleY; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Production Release"; + }; 436FB4981A66822DAF6F22AC /* Production Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -3232,10 +4581,6 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", - ); INFOPLIST_FILE = App_macOS_Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3248,16 +4593,32 @@ }; name = "Test Debug"; }; + 45FD151DC9928DE066A3B1AD /* Staging Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-watchOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = watchos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 4; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Staging Release"; + }; 4621C6C8A78FBB1CF4078178 /* Production Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", - ); - INFOPLIST_FILE = App_macOS/Info.plist; + INFOPLIST_FILE = "App_macOS/App-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", @@ -3287,6 +4648,21 @@ }; name = "Staging Release"; }; + 46DAC1602BF6BEBCD177342F /* Staging Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = "EndpointSecurity Extension/EndpointSecurity.entitlements"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "EndpointSecurity Extension/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-macOS.EndpointSecurity"; + SDKROOT = macosx; + }; + name = "Staging Debug"; + }; 49322BF02F4F345A1339EF7A /* Test Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -3298,6 +4674,23 @@ }; name = "Test Debug"; }; + 498F2DC7204423CCCABAEE80 /* Test Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = App_Clip_UITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-Clip-UITests"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = App_Clip; + }; + name = "Test Release"; + }; 4A0624A4FC88A7E232411C95 /* Staging Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -3350,10 +4743,6 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/watchOS", - ); INFOPLIST_FILE = "App_watchOS Extension/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3367,6 +4756,46 @@ }; name = "Production Release"; }; + 4C11A3E7EA48B5FB556D4614 /* Staging Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + INFOPLIST_FILE = App_supportedDestinations/Info.generated.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.test.TestApp; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator appletvos appletvsimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES; + TARGETED_DEVICE_FAMILY = "1,2,3"; + }; + name = "Staging Debug"; + }; + 4D5DC2028DC046B8AF0B9B83 /* Test Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-watchOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = watchos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 4; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Test Debug"; + }; 4D86BBA6893D41140152B8CC /* Staging Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -3381,14 +4810,26 @@ }; name = "Staging Release"; }; - 4EBCDEB4013FDB0720343467 /* Production Debug */ = { + 4DA924C751AD8FAF891F953D /* Test Release */ = { isa = XCBuildConfiguration; buildSettings = { - ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; - FRAMEWORK_SEARCH_PATHS = ( + CODE_SIGN_ENTITLEMENTS = "DriverKit Driver/Driver.entitlements"; + COMBINE_HIDPI_IMAGES = YES; + DRIVERKIT_DEPLOYMENT_TARGET = 20.4; + INFOPLIST_FILE = "DriverKit Driver/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/watchOS", + "@executable_path/../Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-macOS.Driver"; + SDKROOT = driverkit; + }; + name = "Test Release"; + }; + 4EBCDEB4013FDB0720343467 /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; INFOPLIST_FILE = "App_watchOS Extension/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3400,17 +4841,32 @@ SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = 4; }; - name = "Production Debug"; + name = "Production Debug"; + }; + 4EDC77FA8569D4AB3135780D /* Staging Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = App_Clip/Clip.entitlements; + INFOPLIST_FILE = App_Clip/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.app.clip; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Staging Release"; }; 4F029A78B7BAB85B1E284798 /* Production Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", - ); INFOPLIST_FILE = App_macOS_Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3428,10 +4884,6 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", - ); INFOPLIST_FILE = App_macOS_Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3488,10 +4940,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -3524,11 +4972,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", - ); INFOPLIST_FILE = App_iOS/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3544,6 +4987,23 @@ }; name = "Production Release"; }; + 554E51BF9C8020AFC98E2EEF /* Staging Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = App_Clip_UITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-Clip-UITests"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = App_Clip; + }; + name = "Staging Release"; + }; 55DA94C85E0E63D3AD593A08 /* Staging Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -3553,10 +5013,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -3596,6 +5052,19 @@ }; name = "Test Release"; }; + 57CEA8537C6F3E5B425C5A8E /* Test Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.IncludedLegacy; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Test Debug"; + }; 580039D71F71A98572051157 /* Production Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -3605,10 +5074,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -3633,10 +5098,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/tvOS", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -3675,10 +5136,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/tvOS", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -3759,10 +5216,6 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/watchOS", - ); INFOPLIST_FILE = "App_watchOS Extension/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3785,10 +5238,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -3818,6 +5267,20 @@ }; name = "Production Release"; }; + 64EC1B53D612851D51D18FD2 /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.BundleX; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Production Debug"; + }; 65A21512F2B980615DF51D77 /* Staging Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -3828,10 +5291,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -3919,6 +5378,68 @@ }; name = "Test Debug"; }; + 6E93ACBBB608F386C0EB0F40 /* Staging Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-iOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Staging Release"; + }; + 6FCE7B896519D4B364BD3A71 /* Staging Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-macOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = macosx; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Staging Release"; + }; + 71529460FB00BCDF2064C57F /* Staging Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.BundleY; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Staging Debug"; + }; 72EDF2E14A4CE916F4E2B01B /* Staging Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -3943,6 +5464,26 @@ }; name = "Staging Debug"; }; + 75B3C83C754AA9C12ABF5E54 /* Staging Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + INFOPLIST_FILE = App_supportedDestinations/Info.generated.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.test.TestApp; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator appletvos appletvsimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES; + TARGETED_DEVICE_FAMILY = "1,2,3"; + }; + name = "Staging Release"; + }; 77B8B41EBA5D778EB3AF89DC /* Production Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -3967,16 +5508,26 @@ }; name = "Production Debug"; }; + 77C426E60C6FCB5A01EFC401 /* Staging Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = "Network Extension/NetworkExtension.entitlements"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "Network Extension/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-macOS.NetworkExtension"; + SDKROOT = macosx; + }; + name = "Staging Release"; + }; 7931F229200F89B8CDC8A5E3 /* Test Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", - ); INFOPLIST_FILE = App_iOS/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -4011,10 +5562,6 @@ 7B2A1BE6CA654E9903A4C680 /* Staging Release */ = { isa = XCBuildConfiguration; buildSettings = { - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/watchOS", - ); INFOPLIST_FILE = App_watchOS/Info.plist; PRODUCT_BUNDLE_IDENTIFIER = com.project.app.watch; SDKROOT = watchos; @@ -4028,11 +5575,6 @@ isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", - ); INFOPLIST_FILE = App_iOS_Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -4070,6 +5612,39 @@ }; name = "Staging Release"; }; + 7C9FE720B05E0120F78B81AF /* Test Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = App_Clip/Clip.entitlements; + INFOPLIST_FILE = App_Clip/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.app.clip; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Test Debug"; + }; + 7D73A7FB339A39293BD2DB9E /* Staging Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.BundleY; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Staging Release"; + }; 7E101F97604A0990174A46CD /* Staging Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -4095,6 +5670,26 @@ }; name = "Production Release"; }; + 7F3F6A813F8B126258780E8D /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + INFOPLIST_FILE = App_supportedDestinations/Info.generated.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.test.TestApp; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator appletvos appletvsimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES; + TARGETED_DEVICE_FAMILY = "1,2,3"; + }; + name = "Production Release"; + }; 7F86E00770E76CA3412A03BD /* Staging Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -4130,10 +5725,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -4149,7 +5740,95 @@ }; name = "Production Debug"; }; - 8269ABE82BCBF550C38494DF /* Staging Debug */ = { + 8269ABE82BCBF550C38494DF /* Staging Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Framework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.Framework2-macOS"; + PRODUCT_NAME = Framework2; + SDKROOT = macosx; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Staging Debug"; + }; + 84404129017F8D027A24136A /* Staging Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = App_Clip/Clip.entitlements; + INFOPLIST_FILE = App_Clip/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.app.clip; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Staging Debug"; + }; + 85E6B40848AC2A0B1F921553 /* Test Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.BundleX; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Test Debug"; + }; + 862658ACA3BF7AE7FA22870C /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "iMessage App Icon"; + INFOPLIST_FILE = iMessageExtension/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.iMessageApp.extension; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Production Debug"; + }; + 86BDA2C16646B065BDE01177 /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = "EndpointSecurity Extension/EndpointSecurity.entitlements"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "EndpointSecurity Extension/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-macOS.EndpointSecurity"; + SDKROOT = macosx; + }; + name = "Production Debug"; + }; + 8705629C56ACC795F1DDB96D /* Staging Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = ""; @@ -4159,34 +5838,46 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = Framework/Info.plist; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = "com.project.Framework2-macOS"; - PRODUCT_NAME = Framework2; + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-macOS"; + PRODUCT_NAME = CrossOverlayFramework; SDKROOT = macosx; SKIP_INSTALL = YES; VERSIONING_SYSTEM = "apple-generic"; }; name = "Staging Debug"; }; - 862658ACA3BF7AE7FA22870C /* Production Debug */ = { + 8A380D322263800338FA5139 /* Test Release */ = { isa = XCBuildConfiguration; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = "iMessage App Icon"; - INFOPLIST_FILE = iMessageExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", - "@executable_path/../../Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.project.iMessageApp.extension; + PRODUCT_BUNDLE_IDENTIFIER = com.project.IncludedLegacy; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; + name = "Test Release"; + }; + 8BAC4B81735DDF8537709B8D /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = "Network Extension/NetworkExtension.entitlements"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "Network Extension/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-macOS.NetworkExtension"; + SDKROOT = macosx; + }; name = "Production Debug"; }; 8C9F67C7AA56DBE79F0F2640 /* Test Debug */ = { @@ -4198,10 +5889,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -4217,6 +5904,44 @@ }; name = "Test Debug"; }; + 8FEAEB3CB45479405F52D3AF /* Test Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-tvOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 3; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Test Release"; + }; + 917341F64B3A9B883FE942AD /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.BundleX; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Production Release"; + }; 921EC740167F616C38809275 /* Production Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -4230,6 +5955,20 @@ }; name = "Production Release"; }; + 924BB9ED8B14A02ABF88CC23 /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.BundleY; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Production Debug"; + }; 92602C025633FBA848F91812 /* Production Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -4266,11 +6005,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", - ); - INFOPLIST_FILE = App_macOS/Info.plist; + INFOPLIST_FILE = "App_macOS/App-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", @@ -4284,19 +6019,86 @@ }; name = "Production Debug"; }; - 9666BFAAA42CE2DC7E368E7D /* Production Release */ = { + 94C7D2D3D0907DF146EFC13C /* Test Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-macOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = macosx; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Test Debug"; + }; + 94ECCEFE29DB30C48B227A16 /* Staging Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.external; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Staging Release"; + }; + 96130B9B35FEC2FEA00AFDB9 /* Test Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/watchOS", + "@executable_path/../Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-macOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = macosx; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Test Release"; + }; + 9666BFAAA42CE2DC7E368E7D /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.project.Framework-watchOS"; @@ -4328,11 +6130,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", - ); - INFOPLIST_FILE = App_macOS/Info.plist; + INFOPLIST_FILE = "App_macOS/App-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", @@ -4356,10 +6154,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -4403,6 +6197,26 @@ }; name = "Staging Debug"; }; + 98EE00BF46FAE62F16C25E9C /* Test Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + INFOPLIST_FILE = App_supportedDestinations/Info.generated.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.test.TestApp; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator appletvos appletvsimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES; + TARGETED_DEVICE_FAMILY = "1,2,3"; + }; + name = "Test Release"; + }; 9A891313A139893990989BDD /* Test Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -4454,7 +6268,7 @@ }; name = "Staging Debug"; }; - 9E38571B33C3CE5CA10C8452 /* Staging Debug */ = { + 9E1F620F233A34DE80D84356 /* Staging Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = ""; @@ -4463,10 +6277,30 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/tvOS", + "@executable_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-tvOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 3; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Staging Release"; + }; + 9E38571B33C3CE5CA10C8452 /* Staging Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -4524,6 +6358,23 @@ }; name = "Test Release"; }; + A0CBB78FB8E4FB0004B05DE0 /* Test Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = App_iOS_Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-Clip-Tests"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/App_Clip.app/App_Clip"; + }; + name = "Test Release"; + }; A2EBD902E6DE2B2BD12C4484 /* Production Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -4538,6 +6389,26 @@ }; name = "Production Debug"; }; + A4015127D0A01FE60CF5621B /* Test Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + INFOPLIST_FILE = App_supportedDestinations/Info.generated.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.test.TestApp; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator appletvos appletvsimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES; + TARGETED_DEVICE_FAMILY = "1,2,3"; + }; + name = "Test Debug"; + }; A59DDFBFCF18C44A993CFB00 /* Test Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -4585,10 +6456,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -4617,6 +6484,30 @@ }; name = "Production Release"; }; + A9483E827FAD142F28A0E16D /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-iOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Production Debug"; + }; AA4F4236D960D3ACE683A815 /* Staging Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -4632,13 +6523,25 @@ }; name = "Staging Release"; }; - AABC1E325EADF86C5137D659 /* Production Release */ = { + AA6BC5199D9705F3182D0C00 /* Test Debug */ = { isa = XCBuildConfiguration; buildSettings = { - FRAMEWORK_SEARCH_PATHS = ( + CODE_SIGN_ENTITLEMENTS = "DriverKit Driver/Driver.entitlements"; + COMBINE_HIDPI_IMAGES = YES; + DRIVERKIT_DEPLOYMENT_TARGET = 20.4; + INFOPLIST_FILE = "DriverKit Driver/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/watchOS", + "@executable_path/../Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-macOS.Driver"; + SDKROOT = driverkit; + }; + name = "Test Debug"; + }; + AABC1E325EADF86C5137D659 /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { INFOPLIST_FILE = App_watchOS/Info.plist; PRODUCT_BUNDLE_IDENTIFIER = com.project.app.watch; SDKROOT = watchos; @@ -4648,6 +6551,21 @@ }; name = "Production Release"; }; + AB455120CB69CF0A7E128221 /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = "Network Extension/NetworkExtension.entitlements"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "Network Extension/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-macOS.NetworkExtension"; + SDKROOT = macosx; + }; + name = "Production Release"; + }; AC8E8FEA35961580D23185B2 /* Test Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -4667,11 +6585,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", - ); INFOPLIST_FILE = App_iOS/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -4725,18 +6638,49 @@ TARGETED_DEVICE_FAMILY = 4; VERSIONING_SYSTEM = "apple-generic"; }; - name = "Staging Release"; + name = "Staging Release"; + }; + AF3DD6DCF141F35D4129FFF5 /* Test Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.external; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Test Release"; + }; + AF4B5E2FF8B6C883C40737C6 /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.IncludedLegacy; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Production Release"; }; B008685BA25BB8FD771F0AE3 /* Staging Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", - ); INFOPLIST_FILE = App_iOS/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -4772,6 +6716,20 @@ }; name = "Production Release"; }; + B227B91964080DEF6C426483 /* Test Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.BundleY; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Test Debug"; + }; B24243F387A725EAFE802321 /* Production Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -4793,6 +6751,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -4808,6 +6767,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -4832,7 +6792,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MTL_ENABLE_DEBUG_INFO = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; @@ -4856,7 +6817,31 @@ }; name = "Staging Release"; }; - B928E061A126AC8D17D81D1E /* Staging Debug */ = { + B4464446E556BA3E731D3D25 /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-tvOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 3; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Production Release"; + }; + B5E1584A197C52FC47245FC8 /* Staging Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = ""; @@ -4865,10 +6850,63 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( + GENERATE_INFOPLIST_FILE = YES; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.external; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Staging Debug"; + }; + B7EBD1A3A3A7E66100F5C845 /* Test Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/watchOS", + "@executable_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.BundleX; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Test Release"; + }; + B8CC52B6DC03DACD9B1309E0 /* Staging Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-watchOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = watchos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 4; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Staging Debug"; + }; + B928E061A126AC8D17D81D1E /* Staging Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.project.Framework-watchOS"; @@ -4880,6 +6918,21 @@ }; name = "Staging Debug"; }; + B987E9BED4B423A049202386 /* Staging Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = "Network Extension/NetworkExtension.entitlements"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "Network Extension/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-macOS.NetworkExtension"; + SDKROOT = macosx; + }; + name = "Staging Debug"; + }; B9AF2E89FE3E9E03E0029607 /* Test Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -4907,11 +6960,6 @@ isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", - ); INFOPLIST_FILE = App_iOS_Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -4925,6 +6973,20 @@ }; name = "Production Release"; }; + BA21E149424C2D03E5E50EC1 /* Test Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.BundleY; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Test Release"; + }; BA5AD3137CD90C50E5E1BDA0 /* Production Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -4945,11 +7007,6 @@ isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", - ); INFOPLIST_FILE = App_iOS_UITests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -4990,6 +7047,23 @@ }; name = "Test Release"; }; + C0BE0797A2AD213D59FF13F8 /* Staging Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = App_iOS_Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-Clip-Tests"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/App_Clip.app/App_Clip"; + }; + name = "Staging Release"; + }; C0D5765142C68AF68B954B3F /* Production Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5000,6 +7074,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -5015,6 +7090,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -5033,10 +7109,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; - VALIDATE_PRODUCT = YES; WATCHOS_DEPLOYMENT_TARGET = 4.0; }; name = "Production Release"; @@ -5044,10 +7122,6 @@ C4397CDA0D458BAD55C911B0 /* Staging Debug */ = { isa = XCBuildConfiguration; buildSettings = { - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/watchOS", - ); INFOPLIST_FILE = App_watchOS/Info.plist; PRODUCT_BUNDLE_IDENTIFIER = com.project.app.watch; SDKROOT = watchos; @@ -5057,6 +7131,21 @@ }; name = "Staging Debug"; }; + C44EBD74DF4B95E30983A798 /* Staging Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = "EndpointSecurity Extension/EndpointSecurity.entitlements"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "EndpointSecurity Extension/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-macOS.EndpointSecurity"; + SDKROOT = macosx; + }; + name = "Staging Release"; + }; C59E649CEDC0E973B28B57A4 /* Test Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5068,6 +7157,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -5083,6 +7173,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -5101,10 +7192,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; - VALIDATE_PRODUCT = YES; WATCHOS_DEPLOYMENT_TARGET = 4.0; }; name = "Test Release"; @@ -5132,15 +7225,52 @@ }; name = "Test Debug"; }; - C7EF8D96FA7893ADD61CF4C0 /* Production Debug */ = { + C734956B0E352751B5DA14A6 /* Production Debug */ = { isa = XCBuildConfiguration; buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( + CODE_SIGN_ENTITLEMENTS = App_Clip/Clip.entitlements; + INFOPLIST_FILE = App_Clip/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.app.clip; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Production Debug"; + }; + C745E36B41A4ABD1E24A69AF /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", + "@executable_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.external; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Production Debug"; + }; + C7EF8D96FA7893ADD61CF4C0 /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; INFOPLIST_FILE = App_iOS_Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -5163,10 +7293,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/watchOS", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.project.Framework-watchOS"; @@ -5178,6 +7304,30 @@ }; name = "Test Debug"; }; + C9D8E28D29695DF97266F229 /* Test Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-tvOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 3; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Test Debug"; + }; CA08CB7E7DBBC99CDC7F2C2E /* Test Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5227,11 +7377,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", - ); - INFOPLIST_FILE = App_macOS/Info.plist; + INFOPLIST_FILE = "App_macOS/App-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", @@ -5245,6 +7391,46 @@ }; name = "Staging Release"; }; + CF25791E297417E38800A521 /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-macOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = macosx; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Production Debug"; + }; + CF7D27DBBF0667D789D53D29 /* Staging Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = "DriverKit Driver/Driver.entitlements"; + COMBINE_HIDPI_IMAGES = YES; + DRIVERKIT_DEPLOYMENT_TARGET = 20.4; + INFOPLIST_FILE = "DriverKit Driver/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-macOS.Driver"; + SDKROOT = driverkit; + }; + name = "Staging Release"; + }; D24E68EE5DE052219B036D63 /* Production Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5265,7 +7451,37 @@ buildSettings = { MY_SETTING = hello; }; - name = "Test Release"; + name = "Test Release"; + }; + D4A6D5FE11C6652E092629BF /* Staging Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.IncludedLegacy; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Staging Debug"; + }; + D70B7AB6D219453ABF475EED /* Production Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = App_iOS_Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-Clip-Tests"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/App_Clip.app/App_Clip"; + }; + name = "Production Debug"; }; D8267FD376089FF4497ED3F1 /* Staging Release */ = { isa = XCBuildConfiguration; @@ -5277,10 +7493,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -5295,6 +7507,21 @@ }; name = "Staging Release"; }; + D93982FB34335E2D1B9751FE /* Test Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = "EndpointSecurity Extension/EndpointSecurity.entitlements"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "EndpointSecurity Extension/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-macOS.EndpointSecurity"; + SDKROOT = macosx; + }; + name = "Test Debug"; + }; D9A0609EE6F341CD4E8758C1 /* Test Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5304,10 +7531,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/watchOS", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.project.Framework-watchOS"; @@ -5324,11 +7547,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", - ); INFOPLIST_FILE = App_iOS/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -5360,6 +7578,26 @@ }; name = "Production Debug"; }; + DE81296F5A364B236643A3B9 /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-watchOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = watchos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 4; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Production Release"; + }; DF558E25A4E143219DF4AA51 /* Staging Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5383,7 +7621,7 @@ }; name = "Staging Debug"; }; - E24703CFCCBD727B3FE08F51 /* Test Release */ = { + E0DF26EA764106961DEC59C9 /* Test Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = ""; @@ -5392,10 +7630,30 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/tvOS", + "@executable_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-iOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Test Debug"; + }; + E24703CFCCBD727B3FE08F51 /* Test Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -5422,6 +7680,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -5437,6 +7696,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -5461,7 +7721,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MTL_ENABLE_DEBUG_INFO = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; @@ -5481,10 +7742,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -5526,11 +7783,6 @@ isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - "$(PROJECT_DIR)/Carthage/Build/iOS/Static", - ); INFOPLIST_FILE = App_iOS_UITests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -5568,10 +7820,6 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/watchOS", - ); INFOPLIST_FILE = Framework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.project.Framework-watchOS"; @@ -5611,6 +7859,30 @@ }; name = "Staging Release"; }; + E5EB6CE05568645829D40384 /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = CrossOverlayFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.CrossOverlayFramework-iOS"; + PRODUCT_NAME = CrossOverlayFramework; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Production Release"; + }; E683F74557A3FC7BD78CAB2B /* Production Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5635,6 +7907,40 @@ }; name = "Production Debug"; }; + E7E05E5BC42C73136CDC5CFE /* Production Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = App_iOS_Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-Clip-Tests"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/App_Clip.app/App_Clip"; + }; + name = "Production Release"; + }; + E8F5F216BCFE54CB22B80237 /* Staging Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = App_iOS_Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-Clip-Tests"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/App_Clip.app/App_Clip"; + }; + name = "Staging Debug"; + }; E95B2CE470959F04BE6AACA9 /* Test Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 16D662EE577E4CD6AFF39D66 /* config.xcconfig */; @@ -5647,6 +7953,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -5662,6 +7969,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -5686,7 +7994,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MTL_ENABLE_DEBUG_INFO = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; @@ -5696,6 +8005,21 @@ }; name = "Test Debug"; }; + E9C964F0189C68721012002B /* Test Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = "Network Extension/NetworkExtension.entitlements"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "Network Extension/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-macOS.NetworkExtension"; + SDKROOT = macosx; + }; + name = "Test Debug"; + }; EA62022185E4BCDA6786EC0D /* Production Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5710,15 +8034,25 @@ }; name = "Production Release"; }; + EBA3332D0144AAAA57630865 /* Staging Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.BundleX; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Staging Release"; + }; EBD2F70285E21FFAB1C23D01 /* Staging Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", - ); INFOPLIST_FILE = App_macOS_Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -5785,13 +8119,22 @@ }; name = "Production Release"; }; - F3AC6A112F81D0958A316D82 /* Test Release */ = { + EF6AB18F2D803CB530422BAE /* Staging Release */ = { isa = XCBuildConfiguration; buildSettings = { - FRAMEWORK_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/watchOS", + "@executable_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = com.project.IncludedLegacy; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Staging Release"; + }; + F3AC6A112F81D0958A316D82 /* Test Release */ = { + isa = XCBuildConfiguration; + buildSettings = { INFOPLIST_FILE = App_watchOS/Info.plist; PRODUCT_BUNDLE_IDENTIFIER = com.project.app.watch; SDKROOT = watchos; @@ -5825,14 +8168,27 @@ }; name = "Staging Release"; }; - F75CC02D1BB9B39C329A9B43 /* Staging Release */ = { + F48A0BCE0F515E3472B34F66 /* Staging Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; - FRAMEWORK_SEARCH_PATHS = ( + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = App_Clip_UITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/watchOS", + "@executable_path/Frameworks", + "@loader_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = "com.project.App-Clip-UITests"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = App_Clip; + }; + name = "Staging Debug"; + }; + F75CC02D1BB9B39C329A9B43 /* Staging Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; INFOPLIST_FILE = "App_watchOS Extension/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -5896,10 +8252,6 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", - ); INFOPLIST_FILE = App_macOS_Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -5923,6 +8275,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -5938,6 +8291,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -5956,10 +8310,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; - VALIDATE_PRODUCT = YES; WATCHOS_DEPLOYMENT_TARGET = 4.0; }; name = "Staging Release"; @@ -6032,6 +8388,19 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = "Production Debug"; }; + 02B721AF7361EBCFA91410BF /* Build configuration list for PBXLegacyTarget "IncludedLegacy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 221A50372FFB2F1202940FDC /* Production Debug */, + AF4B5E2FF8B6C883C40737C6 /* Production Release */, + D4A6D5FE11C6652E092629BF /* Staging Debug */, + EF6AB18F2D803CB530422BAE /* Staging Release */, + 57CEA8537C6F3E5B425C5A8E /* Test Debug */, + 8A380D322263800338FA5139 /* Test Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Production Debug"; + }; 02E5A42C8065AF7CCB48FACE /* Build configuration list for PBXNativeTarget "Framework2_macOS" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -6045,6 +8414,32 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = "Production Debug"; }; + 07B4E73E56B7C2C80DE2A378 /* Build configuration list for PBXNativeTarget "App_Clip" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C734956B0E352751B5DA14A6 /* Production Debug */, + 3BE60579CA725E23659AEA80 /* Production Release */, + 84404129017F8D027A24136A /* Staging Debug */, + 4EDC77FA8569D4AB3135780D /* Staging Release */, + 7C9FE720B05E0120F78B81AF /* Test Debug */, + 0579BA94EA238151DAFC2FFC /* Test Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Production Debug"; + }; + 129D9E77D45A66B1C78578F2 /* Build configuration list for PBXNativeTarget "App_Clip_UITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 07DF024D82D64A8D76209B90 /* Production Debug */, + 3236B7B20520584116A96C0D /* Production Release */, + F48A0BCE0F515E3472B34F66 /* Staging Debug */, + 554E51BF9C8020AFC98E2EEF /* Staging Release */, + 3BDE7967B50F4358BD4702AD /* Test Debug */, + 498F2DC7204423CCCABAEE80 /* Test Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Production Debug"; + }; 1FC6945BE13C2202A2BCA3BC /* Build configuration list for PBXNativeTarget "iMessageApp" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -6058,6 +8453,19 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = "Production Debug"; }; + 2C39D94CF9C8B1CB79F04AC8 /* Build configuration list for PBXNativeTarget "BundleX" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 64EC1B53D612851D51D18FD2 /* Production Debug */, + 917341F64B3A9B883FE942AD /* Production Release */, + 31931061043C66589547105C /* Staging Debug */, + EBA3332D0144AAAA57630865 /* Staging Release */, + 85E6B40848AC2A0B1F921553 /* Test Debug */, + B7EBD1A3A3A7E66100F5C845 /* Test Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Production Debug"; + }; 3F3C272D2EA61F6B88B80D44 /* Build configuration list for PBXNativeTarget "App_watchOS Extension" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -6071,6 +8479,32 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = "Production Debug"; }; + 412FA71CA97AD6851A1828DD /* Build configuration list for PBXNativeTarget "DriverKitDriver" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 035FC5362AE3E9696248DFD0 /* Production Debug */, + 03B133682B8BEF8B1D647C76 /* Production Release */, + 291A37106E83E5C30890F422 /* Staging Debug */, + CF7D27DBBF0667D789D53D29 /* Staging Release */, + AA6BC5199D9705F3182D0C00 /* Test Debug */, + 4DA924C751AD8FAF891F953D /* Test Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Production Debug"; + }; + 498FA7414845B8834E48496F /* Build configuration list for PBXNativeTarget "App_Clip_Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D70B7AB6D219453ABF475EED /* Production Debug */, + E7E05E5BC42C73136CDC5CFE /* Production Release */, + E8F5F216BCFE54CB22B80237 /* Staging Debug */, + C0BE0797A2AD213D59FF13F8 /* Staging Release */, + 2E5159957368A9CF77A3C9FC /* Test Debug */, + A0CBB78FB8E4FB0004B05DE0 /* Test Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Production Debug"; + }; 4A036BD16A0E9D22AE065AC9 /* Build configuration list for PBXNativeTarget "StaticLibrary_Swift" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -6123,6 +8557,19 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = "Production Debug"; }; + 5EC789CCE1928A4CDA00DD1E /* Build configuration list for PBXNativeTarget "App_supportedDestinations" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 24CFBB3ABB9E14E85035B892 /* Production Debug */, + 7F3F6A813F8B126258780E8D /* Production Release */, + 4C11A3E7EA48B5FB556D4614 /* Staging Debug */, + 75B3C83C754AA9C12ABF5E54 /* Staging Release */, + A4015127D0A01FE60CF5621B /* Test Debug */, + 98EE00BF46FAE62F16C25E9C /* Test Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Production Debug"; + }; 62C52A55CB8D3BD9A055FD14 /* Build configuration list for PBXNativeTarget "App_macOS_Tests" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -6149,6 +8596,19 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = "Production Debug"; }; + 641D1B2D88B93FAD0EA09187 /* Build configuration list for PBXNativeTarget "CrossOverlayFramework_iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + A9483E827FAD142F28A0E16D /* Production Debug */, + E5EB6CE05568645829D40384 /* Production Release */, + 1FB2AFB2F45076B4A047499E /* Staging Debug */, + 6E93ACBBB608F386C0EB0F40 /* Staging Release */, + E0DF26EA764106961DEC59C9 /* Test Debug */, + 1C63C4A728212D903E4F2CBB /* Test Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Production Debug"; + }; 658628E35283172E17BFC6A3 /* Build configuration list for PBXNativeTarget "Framework_tvOS" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -6227,6 +8687,19 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = "Production Debug"; }; + 78DB808B74D58314279E7FD7 /* Build configuration list for PBXNativeTarget "NetworkSystemExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8BAC4B81735DDF8537709B8D /* Production Debug */, + AB455120CB69CF0A7E128221 /* Production Release */, + B987E9BED4B423A049202386 /* Staging Debug */, + 77C426E60C6FCB5A01EFC401 /* Staging Release */, + E9C964F0189C68721012002B /* Test Debug */, + 0C18EEAE68FBEBCF066E0CD9 /* Test Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Production Debug"; + }; 7CBF487CACC0BBFB530D7963 /* Build configuration list for PBXAggregateTarget "SuperTarget" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -6292,6 +8765,19 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = "Production Debug"; }; + 9C9913AAE0ABA99337F0C069 /* Build configuration list for PBXNativeTarget "CrossOverlayFramework_macOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CF25791E297417E38800A521 /* Production Debug */, + 34ED16009A759D256D7ECB53 /* Production Release */, + 8705629C56ACC795F1DDB96D /* Staging Debug */, + 6FCE7B896519D4B364BD3A71 /* Staging Release */, + 94C7D2D3D0907DF146EFC13C /* Test Debug */, + 96130B9B35FEC2FEA00AFDB9 /* Test Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Production Debug"; + }; 9F4CBE5D909D2757B3D334B3 /* Build configuration list for PBXNativeTarget "TestFramework" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -6331,6 +8817,32 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = "Production Debug"; }; + C483BD5456B09C276DE6EFC1 /* Build configuration list for PBXNativeTarget "CrossOverlayFramework_watchOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1C644E47F1C539F2B95160B8 /* Production Debug */, + DE81296F5A364B236643A3B9 /* Production Release */, + B8CC52B6DC03DACD9B1309E0 /* Staging Debug */, + 45FD151DC9928DE066A3B1AD /* Staging Release */, + 4D5DC2028DC046B8AF0B9B83 /* Test Debug */, + 19BF18E6EAA8B30F894EAB4E /* Test Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Production Debug"; + }; + C4FB84AAA6F6974CEA51D359 /* Build configuration list for PBXNativeTarget "EndpointSecuritySystemExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 86BDA2C16646B065BDE01177 /* Production Debug */, + 06D6C7ED89937E7891E70B55 /* Production Release */, + 46DAC1602BF6BEBCD177342F /* Staging Debug */, + C44EBD74DF4B95E30983A798 /* Staging Release */, + D93982FB34335E2D1B9751FE /* Test Debug */, + 11919FD24AA8A110C24C0FEF /* Test Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Production Debug"; + }; D379D1BBEF24ED05EB6ADEB3 /* Build configuration list for PBXNativeTarget "XPC Service" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -6370,6 +8882,45 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = "Production Debug"; }; + D9EF39CA9A17477264F02057 /* Build configuration list for PBXNativeTarget "ExternalTarget" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C745E36B41A4ABD1E24A69AF /* Production Debug */, + 045CB2D74D9A3532E128BDD2 /* Production Release */, + B5E1584A197C52FC47245FC8 /* Staging Debug */, + 94ECCEFE29DB30C48B227A16 /* Staging Release */, + 2C6AB16720ADFB2436337A8F /* Test Debug */, + AF3DD6DCF141F35D4129FFF5 /* Test Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Production Debug"; + }; + DA49CF5A1AC4FC1A7EE979E8 /* Build configuration list for PBXNativeTarget "BundleY" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 924BB9ED8B14A02ABF88CC23 /* Production Debug */, + 414544E2FA4DE102442A71CD /* Production Release */, + 71529460FB00BCDF2064C57F /* Staging Debug */, + 7D73A7FB339A39293BD2DB9E /* Staging Release */, + B227B91964080DEF6C426483 /* Test Debug */, + BA21E149424C2D03E5E50EC1 /* Test Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Production Debug"; + }; + E3D23AF56C29471E48CA9A11 /* Build configuration list for PBXNativeTarget "CrossOverlayFramework_tvOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 02E38E444E372E89E589E022 /* Production Debug */, + B4464446E556BA3E731D3D25 /* Production Release */, + 321D6FAF1E7AA977008359C7 /* Staging Debug */, + 9E1F620F233A34DE80D84356 /* Staging Release */, + C9D8E28D29695DF97266F229 /* Test Debug */, + 8FEAEB3CB45479405F52D3AF /* Test Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Production Debug"; + }; ED1A174BA92C6E5172B519B7 /* Build configuration list for PBXNativeTarget "iMessageExtension" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -6411,6 +8962,30 @@ }; /* End XCConfigurationList section */ +/* Begin XCRemoteSwiftPackageReference section */ + 4EDA79334592CBBA0E507AD2 /* XCRemoteSwiftPackageReference "Swinject" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/Swinject/Swinject"; + requirement = { + kind = exactVersion; + version = 2.8.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + C7F9B7EDE85527EFEA85D46D /* Swinject */ = { + isa = XCSwiftPackageProductDependency; + package = 4EDA79334592CBBA0E507AD2 /* XCRemoteSwiftPackageReference "Swinject" */; + productName = Swinject; + }; + D7917D10F77DA9D69937D493 /* Swinject */ = { + isa = XCSwiftPackageProductDependency; + package = 4EDA79334592CBBA0E507AD2 /* XCRemoteSwiftPackageReference "Swinject" */; + productName = Swinject; + }; +/* End XCSwiftPackageProductDependency section */ + /* Begin XCVersionGroup section */ 306796628DD52FA55E833B65 /* Model.xcdatamodeld */ = { isa = XCVersionGroup; diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Tests/Fixtures/TestProject/Project.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 881a6dff3..919434a62 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcdebugger/Breakpoints_v2.xcbkptlist b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 000000000..4b3e82723 --- /dev/null +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_Clip.xcscheme b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_Clip.xcscheme new file mode 100644 index 000000000..6959dff88 --- /dev/null +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_Clip.xcscheme @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 55f0c6c92..7da7c0252 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_Scheme.xcscheme +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_Scheme.xcscheme @@ -1,10 +1,11 @@ + LastUpgradeVersion = "1430" + version = "1.7"> + buildImplicitDependencies = "YES" + runPostActionsOnFailure = "NO"> + onlyGenerateCoverageForSpecifiedTargets = "NO"> + + + + + + + + + skipped = "NO" + parallelizable = "NO"> + + - - - - @@ -69,11 +82,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" + enableGPUFrameCaptureMode = "3" + enableGPUValidationMode = "1" allowLocationSimulation = "YES"> @@ -89,8 +105,20 @@ identifier = "Honolulu, HI, USA" referenceType = "1"> + + + + + + + LastUpgradeVersion = "1430" + version = "1.7"> + buildImplicitDependencies = "YES" + runPostActionsOnFailure = "NO"> + disableMainThreadChecker = "YES" + codeCoverageEnabled = "YES" + onlyGenerateCoverageForSpecifiedTargets = "YES"> + + + + + skipped = "NO" + parallelizable = "NO"> + skipped = "NO" + parallelizable = "NO"> - - - - + + + + @@ -104,6 +116,9 @@ isEnabled = "YES"> + + + LastUpgradeVersion = "1430" + version = "1.7"> + buildImplicitDependencies = "YES" + runPostActionsOnFailure = "NO"> + disableMainThreadChecker = "YES" + codeCoverageEnabled = "YES" + onlyGenerateCoverageForSpecifiedTargets = "YES"> + + + + + skipped = "NO" + parallelizable = "NO"> + skipped = "NO" + parallelizable = "NO"> - - - - + + + + @@ -104,6 +116,9 @@ isEnabled = "YES"> + + + LastUpgradeVersion = "1430" + version = "1.7"> + buildImplicitDependencies = "YES" + runPostActionsOnFailure = "NO"> + disableMainThreadChecker = "YES" + codeCoverageEnabled = "YES" + onlyGenerateCoverageForSpecifiedTargets = "YES"> + + + + + skipped = "NO" + parallelizable = "NO"> + skipped = "NO" + parallelizable = "NO"> - - - - + + + + @@ -104,6 +116,9 @@ isEnabled = "YES"> + + + LastUpgradeVersion = "1430" + version = "1.7"> + buildImplicitDependencies = "YES" + runPostActionsOnFailure = "NO"> - - + 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 23d795d42..e19038b3a 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_watchOS.xcscheme +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/App_watchOS.xcscheme @@ -1,10 +1,11 @@ + LastUpgradeVersion = "1430" + version = "1.7"> + buildImplicitDependencies = "YES" + runPostActionsOnFailure = "NO"> - - + shouldUseLaunchSchemeArgsEnv = "YES" + onlyGenerateCoverageForSpecifiedTargets = "NO"> + + @@ -67,8 +68,8 @@ debugServiceExtension = "internal" allowLocationSimulation = "YES"> + runnableDebuggingMode = "2" + BundleIdentifier = "com.apple.Carousel"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/EndpointSecuritySystemExtension.xcscheme b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/EndpointSecuritySystemExtension.xcscheme new file mode 100644 index 000000000..1414a8f0c --- /dev/null +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/EndpointSecuritySystemExtension.xcscheme @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/Framework.xcscheme b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/Framework.xcscheme index 9f7b37ac3..4536d01f1 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/Framework.xcscheme +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/Framework.xcscheme @@ -1,10 +1,11 @@ + LastUpgradeVersion = "1430" + version = "1.7"> + buildImplicitDependencies = "NO" + runPostActionsOnFailure = "YES"> @@ -45,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"> + + @@ -99,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 new file mode 100644 index 000000000..385767c39 --- /dev/null +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/NetworkSystemExtension.xcscheme @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/Tool.xcscheme b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/Tool.xcscheme index de8aab8b8..84996bd94 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/Tool.xcscheme +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/Tool.xcscheme @@ -1,10 +1,11 @@ + LastUpgradeVersion = "1430" + version = "1.7"> + buildImplicitDependencies = "YES" + runPostActionsOnFailure = "NO"> - - + 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 2c84d7750..b95abc49c 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/iMessageApp.xcscheme +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/iMessageApp.xcscheme @@ -1,10 +1,11 @@ + LastUpgradeVersion = "1430" + version = "1.7"> + buildImplicitDependencies = "YES" + runPostActionsOnFailure = "NO"> - - + 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 3cc5c5fad..070c48e20 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/iMessageExtension.xcscheme +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/xcshareddata/xcschemes/iMessageExtension.xcscheme @@ -1,11 +1,12 @@ + LastUpgradeVersion = "1430" + wasCreatedForAppExtension = "YES" + version = "1.7"> + buildImplicitDependencies = "YES" + runPostActionsOnFailure = "NO"> - - + shouldUseLaunchSchemeArgsEnv = "YES" + onlyGenerateCoverageForSpecifiedTargets = "NO"> + + + allowLocationSimulation = "YES" + launchAutomaticallySubstyle = "2"> + + + + AD_UNIT_ID_FOR_BANNER_TEST + ca-app-pub-0000000000000000/1111111111 + AD_UNIT_ID_FOR_INTERSTITIAL_TEST + ca-app-pub-9999999999999999/2222222222 + CLIENT_ID + AAAAAAA + REVERSED_CLIENT_ID + BBBBBBB + API_KEY + CCCCCCC + GCM_SENDER_ID + 000000000000000 + PLIST_VERSION + 1 + BUNDLE_ID + com.project.app + PROJECT_ID + abcdef:app-000000000 + STORAGE_BUCKET + abcdef:app-000000000.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 000000000000000 + DATABASE_URL + https://github.com/yonaskolb/XcodeGen/ + + diff --git a/Tests/Fixtures/TestProject/String Catalogs/LocalizableStrings.xcstrings b/Tests/Fixtures/TestProject/String Catalogs/LocalizableStrings.xcstrings new file mode 100644 index 000000000..14c34efb9 --- /dev/null +++ b/Tests/Fixtures/TestProject/String Catalogs/LocalizableStrings.xcstrings @@ -0,0 +1,24 @@ +{ + "sourceLanguage" : "en", + "strings" : { + "sampleText" : { + "comment" : "Sample string in an asset catalog", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This is a localized string" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Esta es una cadena de texto localizable." + } + } + } + } + }, + "version" : "1.0" +} \ No newline at end of file diff --git a/Tests/Fixtures/TestProject/SyncedFolder/SyncedFile.swift b/Tests/Fixtures/TestProject/SyncedFolder/SyncedFile.swift new file mode 100644 index 000000000..331644108 --- /dev/null +++ b/Tests/Fixtures/TestProject/SyncedFolder/SyncedFile.swift @@ -0,0 +1,4 @@ + +struct SyncedStruct { + +} diff --git a/Tests/Fixtures/TestProject/Workspace.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Tests/Fixtures/TestProject/Workspace.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 000000000..7bde3b823 --- /dev/null +++ b/Tests/Fixtures/TestProject/Workspace.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,15 @@ +{ + "originHash" : "43ca8cdf31efddefed0c1a55ebf00893877282d5a9bda294cd149edd4e559706", + "pins" : [ + { + "identity" : "swinject", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Swinject/Swinject", + "state" : { + "revision" : "b1d92a53159fe45e162c307183aec9be15e4e7ae", + "version" : "2.8.0" + } + } + ], + "version" : 3 +} diff --git a/Tests/Fixtures/TestProject/build.sh b/Tests/Fixtures/TestProject/build.sh index 4609b2b57..ab575c203 100755 --- a/Tests/Fixtures/TestProject/build.sh +++ b/Tests/Fixtures/TestProject/build.sh @@ -1,24 +1,12 @@ #!/bin/bash set -e -CARTHAGE_DYNAMIC_FRAMEWORKS=(Result) -CARTHAGE_STATIC_FRAMEWORKS=(SwiftyJSON swift-nonempty) - -carthage bootstrap $CARTHAGE_DYNAMIC_FRAMEWORKS --cache-builds - -# Prepare xcconfig for static bootstrapping -STATIC_CONFIG=$(mktemp -d)/static.xcconfig -echo "MACH_O_TYPE = staticlib" > $STATIC_CONFIG - -XCODE_XCCONFIG_FILE=$STATIC_CONFIG \ - carthage bootstrap $CARTHAGE_STATIC_FRAMEWORKS --cache-builds - echo " ⚙️ Building iOS app" -xcodebuild -quiet -workspace Workspace.xcworkspace -scheme "App_iOS Test" -configuration "Test Debug" CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGN_ENTITLEMENTS="" CODE_SIGNING_ALLOWED="NO" +xcodebuild -quiet -workspace Workspace.xcworkspace -scheme "App_iOS Test" -configuration "Test Debug" -xcconfig fixtures.xcconfig -destination 'generic/platform=iOS Simulator' echo "✅ Successfully built iOS app" echo " ⚙️ Building macOS app" -xcodebuild -quiet -workspace Workspace.xcworkspace -scheme "App_macOS" -configuration "Test Debug" CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGN_ENTITLEMENTS="" CODE_SIGNING_ALLOWED="NO" +xcodebuild -quiet -workspace Workspace.xcworkspace -scheme "App_macOS" -configuration "Test Debug" -xcconfig fixtures.xcconfig -destination 'generic/platform=macOS' echo "✅ Successfully built macOS app" diff --git a/Tests/Fixtures/TestProject/carthage_dynamic.xcconfig b/Tests/Fixtures/TestProject/carthage_dynamic.xcconfig new file mode 100644 index 000000000..c21ace608 --- /dev/null +++ b/Tests/Fixtures/TestProject/carthage_dynamic.xcconfig @@ -0,0 +1,6 @@ +#include "xcode12_13_and_14_workaround.xcconfig" + +IPHONEOS_DEPLOYMENT_TARGET=14.0 +MACOSX_DEPLOYMENT_TARGET=10.15 +TVOS_DEPLOYMENT_TARGET=14.0 +WATCHOS_DEPLOYMENT_TARGET=7.0 diff --git a/Tests/Fixtures/TestProject/carthage_static.xcconfig b/Tests/Fixtures/TestProject/carthage_static.xcconfig new file mode 100644 index 000000000..86bcfeba6 --- /dev/null +++ b/Tests/Fixtures/TestProject/carthage_static.xcconfig @@ -0,0 +1,8 @@ +#include "xcode12_13_and_14_workaround.xcconfig" + +MACH_O_TYPE = staticlib + +IPHONEOS_DEPLOYMENT_TARGET=14.0 +MACOSX_DEPLOYMENT_TARGET=10.15 +TVOS_DEPLOYMENT_TARGET=14.0 +WATCHOS_DEPLOYMENT_TARGET=7.0 diff --git a/Tests/Fixtures/TestProject/fixtures.xcconfig b/Tests/Fixtures/TestProject/fixtures.xcconfig new file mode 100644 index 000000000..c272c840f --- /dev/null +++ b/Tests/Fixtures/TestProject/fixtures.xcconfig @@ -0,0 +1,7 @@ +#include "xcode12_13_and_14_workaround.xcconfig" + +// Common settings for fixtures +CODE_SIGN_IDENTITY = +CODE_SIGNING_REQUIRED = NO +CODE_SIGN_ENTITLEMENTS = +CODE_SIGNING_ALLOWED = NO diff --git a/Tests/Fixtures/TestProject/project.yml b/Tests/Fixtures/TestProject/project.yml index fe352a0c8..801d4275a 100644 --- a/Tests/Fixtures/TestProject/project.yml +++ b/Tests/Fixtures/TestProject/project.yml @@ -1,5 +1,5 @@ name: Project -include: [environments.yml] +include: [environments.yml, AnotherProject/project.yml] options: bundleIdPrefix: com.project usesTabs: false @@ -11,16 +11,67 @@ options: groupSortPosition: top preGenCommand: echo "This is a pre-gen command" postGenCommand: scripts/script.sh + fileTypes: + abc: + buildPhase: none + abcd: + buildPhase: none fileGroups: - Configs - FileGroup - SomeFile - Utilities + - App_iOS/Configuration.storekit projectReferences: AnotherProject: path: ./AnotherProject/AnotherProject.xcodeproj configFiles: Test Debug: Configs/config.xcconfig +packages: + Swinject: + url: https://github.com/Swinject/Swinject + version: 2.8.0 +breakpoints: + - type: File + path: App_iOS/AppDelegate.swift + line: 7 + condition: launchOptions == nil + actions: + - type: Log + message: message + conveyanceType: speak + - type: File + path: App_iOS/AppDelegate.swift + line: 11 + column: 13 + - type: Exception + scope: All + stopOnStype: Catch + actions: + - type: DebuggerCommand + command: po $arg1 + - type: AppleScript + script: display alert "Exception happened!" + - type: Sound + sound: Blow + - type: SwiftError + enabled: false + - type: OpenGLError + ignoreCount: 2 + actions: + - type: ShellCommand + path: script.sh + arguments: argument1, argument2 + waitUntilDone: true + - type: Symbolic + symbol: UIViewAlertForUnsatisfiableConstraints + module: UIKitCore + actions: + - type: GraphicsTrace + - type: IDEConstraintError + continueAfterRunningActions: true + - type: IDETestFailure + - type: RuntimeIssue targets: Legacy: type: "" @@ -34,7 +85,7 @@ targets: platform: macOS scheme: {} info: - path: App_macOS/Info.plist + path: App_macOS/App-Info.plist properties: LSMinimumSystemVersion: $(MACOSX_DEPLOYMENT_TARGET) NSMainStoryboardFile: Main @@ -51,10 +102,17 @@ targets: optional: true dependencies: - target: Framework_macOS + copy: + destination: plugins + subpath: "test" - target: XPC Service + - target: NetworkSystemExtension + - target: EndpointSecuritySystemExtension + - target: DriverKitDriver - sdk: Contacts.framework - sdk: libc++.tbd - sdk: libz.dylib + putResourcesBeforeSourcesBuildPhase: true App_iOS: type: application @@ -71,6 +129,7 @@ targets: - "**/excluded-file" - "excluded-file" - "Model.xcmappingmodel" + - "Configuration.storekit" - path: App_iOS name: App includes: @@ -79,6 +138,7 @@ targets: - FileGroup/UnderFileGroup - Resources/MyBundle.bundle - Resources/SceneKitCatalog.scnassets + - Resources/GoogleService-Info.plist - path: Resources/ResourceFolder type: folder - path: Folder @@ -103,28 +163,40 @@ targets: resourceTags: - tag1 - tag2 + - String Catalogs/LocalizableStrings.xcstrings + - path: SyncedFolder + type: syncedFolder settings: INFOPLIST_FILE: App_iOS/Info.plist PRODUCT_BUNDLE_IDENTIFIER: com.project.app dependencies: - target: Framework_iOS + platformFilter: all - target: StaticLibrary_ObjC_iOS - - carthage: Result - - carthage: SwiftyJSON - linkType: static - target: Framework2_iOS weak: true + platformFilter: iOS - target: App_watchOS - target: iMessageApp - sdk: Contacts.framework - bundle: BundleX.bundle + - { bundle: BundleY.bundle, codeSign: false } - target: AnotherProject/ExternalTarget + - target: App_Clip + - 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: - App_iOS_Tests - App_iOS_UITests gatherCoverageData: true + coverageTargets: + - App_iOS disableMainThreadChecker: true stopOnEveryMainThreadCheckerIssue: true configVariants: @@ -134,17 +206,21 @@ targets: commandLineArguments: MyEnabledArgument: true MyDisabledArgument: false + storeKitConfiguration: "App_iOS/Configuration.storekit" postbuildScripts: - path: scripts/strip-frameworks.sh name: Strip Unused Architectures from Frameworks runOnlyWhenInstalling: true + basedOnDependencyAnalysis: false - name: MyScript script: | echo "You ran a script!" + touch "${DERIVED_FILE_DIR}/target.d" inputFileLists: - App_iOS/inputList.xcfilelist outputFileLists: - App_iOS/outputList.xcfilelist + discoveredDependencyFile: $(DERIVED_FILE_DIR)/target.d EntitledApp: type: application @@ -154,6 +230,29 @@ targets: properties: com.apple.security.application-groups: group.com.app + App_supportedDestinations: + type: application + supportedDestinations: [iOS, tvOS] + info: + path: App_supportedDestinations/Info.generated.plist + properties: + CFBundleDisplayName: "TestApp" + CFBundleVersion: "1.0.0" + settings: + base: + PRODUCT_BUNDLE_IDENTIFIER: com.test.TestApp + sources: + - path: App_supportedDestinations/Sources + group: App_supportedDestinations + inferDestinationFiltersByPath: true + - path: App_supportedDestinations/Storyboards + group: App_supportedDestinations + destinationFilters: [iOS] + dependencies: + - package: Swinject + product: Swinject + destinationFilters: [tvOS] + App_watchOS: type: application.watchapp2 platform: watchOS @@ -173,9 +272,6 @@ targets: App_watchOS Extension settings: PRODUCT_BUNDLE_IDENTIFIER: com.project.app.watch.extension - dependencies: - - carthage: Result - link: false iMessageApp: type: application.messages @@ -196,9 +292,47 @@ targets: iMessageStickersExtension: type: app-extension.messages-sticker-pack platform: iOS - sources: + sources: - path: iMessageStickers + DriverKitDriver: + platform: macOS + type: driver-extension + sources: + - DriverKit Driver + settings: + PRODUCT_BUNDLE_IDENTIFIER: com.project.App-macOS.Driver + CODE_SIGN_ENTITLEMENTS: DriverKit Driver/Driver.entitlements + SDKROOT: driverkit + DRIVERKIT_DEPLOYMENT_TARGET: 20.4 + scheme: {} + dependencies: + - sdk: DriverKit.framework + + NetworkSystemExtension: + platform: macOS + type: system-extension + sources: + - Network Extension + settings: + PRODUCT_BUNDLE_IDENTIFIER: com.project.App-macOS.NetworkExtension + CODE_SIGN_ENTITLEMENTS: Network Extension/NetworkExtension.entitlements + scheme: {} + dependencies: + - sdk: NetworkExtension.framework + + EndpointSecuritySystemExtension: + platform: macOS + type: system-extension + sources: + - EndpointSecurity Extension + settings: + PRODUCT_BUNDLE_IDENTIFIER: com.project.App-macOS.EndpointSecurity + CODE_SIGN_ENTITLEMENTS: EndpointSecurity Extension/EndpointSecurity.entitlements + scheme: {} + dependencies: + - sdk: libEndpointSecurity.tbd + StaticLibrary_ObjC: type: library.static platform: [iOS, tvOS, watchOS, macOS] @@ -224,8 +358,9 @@ targets: - name: MyScript path: scripts/script.sh dependencies: - - carthage: Result - target: StaticLibrary_ObjC_${platform} + - target: Framework2_${platform} + platforms: [tvOS, watchOS] Framework2: type: framework @@ -241,10 +376,18 @@ targets: - path: Framework excludes: - "*.xcodeproj" - depencencies: + dependencies: - sdk: Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework root: DEVELOPER_DIR + CrossOverlayFramework: + type: framework + platform: [iOS, tvOS, watchOS, macOS] + sources: + - path: CrossOverlayFramework + excludes: + - "*.xcodeproj" + App_iOS_Tests: type: bundle.unit-test platform: iOS @@ -252,15 +395,13 @@ targets: dependencies: - target: App_iOS - target: TestFramework - - carthage: swift-tagged - linkType: static App_iOS_UITests: type: bundle.ui-testing platform: iOS sources: App_iOS_UITests dependencies: - target: App_iOS - + App_macOS_Tests: type: bundle.unit-test platform: macOS @@ -280,6 +421,49 @@ targets: sources: [Tool] scheme: {} + App_Clip: + type: application.on-demand-install-capable + platform: iOS + entitlements: + path: App_Clip/Clip.entitlements + properties: + com.apple.developer.parent-application-identifiers: [$(AppIdentifierPrefix)com.project.appwithclip] + com.apple.security.application-groups: group.com.app + sources: + App_Clip + settings: + INFOPLIST_FILE: App_Clip/Info.plist + PRODUCT_BUNDLE_IDENTIFIER: com.project.app.clip + dependencies: + - target: Framework_iOS + - target: StaticLibrary_ObjC_iOS + - target: AnotherProject/ExternalTarget + scheme: + testTargets: + - App_Clip_Tests + - App_Clip_UITests + + App_Clip_Tests: + type: bundle.unit-test + platform: iOS + sources: App_iOS_Tests + dependencies: + - target: App_Clip + - target: TestFramework + + App_Clip_UITests: + type: bundle.ui-testing + platform: iOS + sources: App_Clip_UITests + 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: build: @@ -290,6 +474,7 @@ schemes: preActions: - script: echo Starting Framework Build settingsTarget: Framework_iOS + runPostActionsOnFailure: true run: commandLineArguments: argument: YES @@ -301,11 +486,16 @@ schemes: App_Scheme: build: targets: - App_iOS: all + App_iOS: all run: simulateLocation: allow: true defaultLocation: Honolulu, HI, USA + customLLDBInit: ${SRCROOT}/.lldbinit + enableGPUFrameCaptureMode: "disabled" + enableGPUValidationMode: false + storeKitConfiguration: "App_iOS/Configuration.storekit" + macroExpansion: App_iOS test: gatherCoverageData: true targets: @@ -313,6 +503,10 @@ schemes: - name: App_iOS_Tests parallelizable: true randomExecutionOrder: true + location: New York, NY, USA + customLLDBInit: ${SRCROOT}/.lldbinit + testPlans: + - path: App_iOS/App_iOS.xctestplan targetTemplates: MyTemplate: scheme: {} diff --git a/Tests/Fixtures/TestProject/xcode12_13_and_14_workaround.xcconfig b/Tests/Fixtures/TestProject/xcode12_13_and_14_workaround.xcconfig new file mode 100644 index 000000000..1622037ab --- /dev/null +++ b/Tests/Fixtures/TestProject/xcode12_13_and_14_workaround.xcconfig @@ -0,0 +1,11 @@ +// +// See https://github.com/Carthage/Carthage/issues/3019 +// +// Skips building ARM slices for simulators until Carthage can support it +// + +EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64=arm64 arm64e armv7 armv7s armv6 armv8 +EXCLUDED_ARCHS_1200=$(inherited) $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_$(EFFECTIVE_PLATFORM_SUFFIX)__NATIVE_ARCH_64_BIT_$(NATIVE_ARCH_64_BIT)) +EXCLUDED_ARCHS_1300=$(inherited) $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_$(EFFECTIVE_PLATFORM_SUFFIX)__NATIVE_ARCH_64_BIT_$(NATIVE_ARCH_64_BIT)) +EXCLUDED_ARCHS_1400=$(inherited) $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_$(EFFECTIVE_PLATFORM_SUFFIX)__NATIVE_ARCH_64_BIT_$(NATIVE_ARCH_64_BIT)) +EXCLUDED_ARCHS=$(inherited) $(EXCLUDED_ARCHS_$(XCODE_VERSION_MAJOR)) diff --git a/Tests/Fixtures/duplicated_include/duplicated_import_sut.yml b/Tests/Fixtures/duplicated_include/duplicated_import_sut.yml index 5ade0abe7..5a1ea7603 100644 --- a/Tests/Fixtures/duplicated_include/duplicated_import_sut.yml +++ b/Tests/Fixtures/duplicated_include/duplicated_import_sut.yml @@ -2,7 +2,8 @@ include: - duplicated_import_transitive.yml - duplicated_import_root.yml - duplicated_import_root.yml - - different_path/duplicated_import_root.yml + - path: different_path/duplicated_import_root.yml + relativePaths: false name: DuplicatedImportDependent targets: IncludedTarget: diff --git a/Tests/Fixtures/include_test.yml b/Tests/Fixtures/include_test.yml index 6affefa6d..796db3226 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_additional.yml + enable: ${INCLUDE_ADDITIONAL_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_additional.yml b/Tests/Fixtures/included_additional.yml new file mode 100644 index 000000000..8fda263d6 --- /dev/null +++ b/Tests/Fixtures/included_additional.yml @@ -0,0 +1,12 @@ +name: Included_Additional +settingGroups: + test: + MY_SETTING5: ADDITIONAL +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/invalid_configs/invalid_configs_value_non_mapping_aggregate_targets.yml b/Tests/Fixtures/invalid_configs/invalid_configs_value_non_mapping_aggregate_targets.yml new file mode 100644 index 000000000..293e384df --- /dev/null +++ b/Tests/Fixtures/invalid_configs/invalid_configs_value_non_mapping_aggregate_targets.yml @@ -0,0 +1,24 @@ +name: InvalidConfigsValueNonMappingAggregateTargets + +# This fixture tests validation of `settings.configs` under an aggregate target. +# Here, `invalid_key0` and `invalid_key1` are scalar values (not mappings), +# so parsing should throw SpecParsingError.invalidConfigsMappingFormat. +targets: + valid_target1: + type: application + platform: iOS + valid_target2: + type: application + platform: iOS + +aggregateTargets: + invalid_target: + targets: + - valid_target1 + - valid_target2 + settings: + configs: + invalid_key0: value0 + debug: + valid_key: value1 + invalid_key1: value2 diff --git a/Tests/Fixtures/invalid_configs/invalid_configs_value_non_mapping_setting_groups.yml b/Tests/Fixtures/invalid_configs/invalid_configs_value_non_mapping_setting_groups.yml new file mode 100644 index 000000000..90822c24f --- /dev/null +++ b/Tests/Fixtures/invalid_configs/invalid_configs_value_non_mapping_setting_groups.yml @@ -0,0 +1,19 @@ +name: InvalidConfigsValueNonMappingSettingGroups + +# This fixture tests validation of `settings.configs` under an aggregate target. +# Here, `invalid_key0` and `invalid_key1` are scalar values (not mappings), +# so parsing should throw SpecParsingError.invalidConfigsMappingFormat. +settingGroups: + invalid_preset: + configs: + invalid_key0: value0 + debug: + valid_key: value1 + invalid_key1: value2 +targets: + invalid_target: + type: application + platform: iOS + settings: + groups: + - invalid_preset diff --git a/Tests/Fixtures/invalid_configs/invalid_configs_value_non_mapping_settings.yml b/Tests/Fixtures/invalid_configs/invalid_configs_value_non_mapping_settings.yml new file mode 100644 index 000000000..431804b70 --- /dev/null +++ b/Tests/Fixtures/invalid_configs/invalid_configs_value_non_mapping_settings.yml @@ -0,0 +1,11 @@ +name: InvalidConfigsValueNonMappingSettings + +# This fixture tests validation of `settings.configs` at the top level. +# Here, `invalid_key0` and `invalid_key1` are scalar values (not mappings), +# so parsing should throw SpecParsingError.invalidConfigsMappingFormat. +settings: + configs: + invalid_key0: value0 + debug: + valid_key: value1 + invalid_key1: value2 diff --git a/Tests/Fixtures/invalid_configs/invalid_configs_value_non_mapping_targets.yml b/Tests/Fixtures/invalid_configs/invalid_configs_value_non_mapping_targets.yml new file mode 100644 index 000000000..84a803bce --- /dev/null +++ b/Tests/Fixtures/invalid_configs/invalid_configs_value_non_mapping_targets.yml @@ -0,0 +1,15 @@ +name: InvalidConfigsValueNonMappingTargets + +# This fixture tests nested validation of `settings.configs` under a target. +# Here, `invalid_key0` and `invalid_key1` are scalar values (not mappings), +# so parsing should throw SpecParsingError.invalidConfigsMappingFormat. +targets: + invalid_target: + type: application + platform: iOS + settings: + configs: + invalid_key0: value0 + debug: + valid_key: value1 + invalid_key1: value2 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 de8cce3c4..7156ff0f1 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 000000000..0da21bd99 --- /dev/null +++ b/Tests/Fixtures/legacy_paths_test/recursive_include.yml @@ -0,0 +1,4 @@ +targets: + IncludedTarget: + sources: + - source diff --git a/Tests/Fixtures/paths_test/included_paths_test.yml b/Tests/Fixtures/paths_test/included_paths_test.yml index 75e084a63..93a400fd4 100644 --- a/Tests/Fixtures/paths_test/included_paths_test.yml +++ b/Tests/Fixtures/paths_test/included_paths_test.yml @@ -1,4 +1,11 @@ -include: recursive_test/recursive_test.yml +name: IncludedPathsTest +include: + - recursive_test/recursive_test.yml + - same_relative_path_test/same_relative_path_test.yml + - path: relative_local_package/inc.yml + relativePaths: true + - path: relative_file_groups/inc.yml + relativePaths: true configFiles: IncludedConfig: config projectReferences: @@ -20,11 +27,14 @@ targets: entitlements: path: entitlements preBuildScripts: - - path: preBuildScript + - path: preBuildScript postCompileScripts: - - path: postCompileScript + - path: postCompileScript postBuildScripts: - - path: postBuildScript + - path: postBuildScript + scheme: + testPlans: + - path: TestPlan.xctestplan aggregateTargets: IncludedAggregateTarget: targets: @@ -37,3 +47,11 @@ targetTemplates: Template1: sources: - template_source +schemes: + Scheme: + build: + targets: + NewTarget: all + test: + testPlans: + - path: TestPlan.xctestplan diff --git a/Tests/Fixtures/paths_test/relative_file_groups/TestFile.md b/Tests/Fixtures/paths_test/relative_file_groups/TestFile.md new file mode 100644 index 000000000..49de0ae4e --- /dev/null +++ b/Tests/Fixtures/paths_test/relative_file_groups/TestFile.md @@ -0,0 +1 @@ +This is a test file for relative file groups diff --git a/Tests/Fixtures/paths_test/relative_file_groups/inc.yml b/Tests/Fixtures/paths_test/relative_file_groups/inc.yml new file mode 100644 index 000000000..bd89ac32e --- /dev/null +++ b/Tests/Fixtures/paths_test/relative_file_groups/inc.yml @@ -0,0 +1,2 @@ +fileGroups: + - TestFile.md diff --git a/Tests/Fixtures/paths_test/relative_local_package/LocalPackage/.gitignore b/Tests/Fixtures/paths_test/relative_local_package/LocalPackage/.gitignore new file mode 100644 index 000000000..0023a5340 --- /dev/null +++ b/Tests/Fixtures/paths_test/relative_local_package/LocalPackage/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +/.build +/Packages +xcuserdata/ +DerivedData/ +.swiftpm/configuration/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/Tests/Fixtures/paths_test/relative_local_package/LocalPackage/Package.swift b/Tests/Fixtures/paths_test/relative_local_package/LocalPackage/Package.swift new file mode 100644 index 000000000..84af3c9f8 --- /dev/null +++ b/Tests/Fixtures/paths_test/relative_local_package/LocalPackage/Package.swift @@ -0,0 +1,20 @@ +// swift-tools-version: 5.7 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "LocalPackage", + products: [ + // Products define the executables and libraries a package produces, making them visible to other packages. + .library( + name: "LocalPackage", + targets: ["LocalPackage"] + ) + ], + targets: [ + // Targets are the basic building blocks of a package, defining a module or a test suite. + // Targets can depend on other targets in this package and products from dependencies. + .target(name: "LocalPackage") + ] +) diff --git a/Tests/Fixtures/paths_test/relative_local_package/LocalPackage/Sources/LocalPackage/LocalPackage.swift b/Tests/Fixtures/paths_test/relative_local_package/LocalPackage/Sources/LocalPackage/LocalPackage.swift new file mode 100644 index 000000000..08b22b80f --- /dev/null +++ b/Tests/Fixtures/paths_test/relative_local_package/LocalPackage/Sources/LocalPackage/LocalPackage.swift @@ -0,0 +1,2 @@ +// The Swift Programming Language +// https://docs.swift.org/swift-book diff --git a/Tests/Fixtures/paths_test/relative_local_package/inc.yml b/Tests/Fixtures/paths_test/relative_local_package/inc.yml new file mode 100644 index 000000000..5f3bd94be --- /dev/null +++ b/Tests/Fixtures/paths_test/relative_local_package/inc.yml @@ -0,0 +1,3 @@ +packages: + LocalPackage: + path: LocalPackage diff --git a/Tests/Fixtures/paths_test/same_relative_path_test/parent1/parent1.yml b/Tests/Fixtures/paths_test/same_relative_path_test/parent1/parent1.yml new file mode 100644 index 000000000..745601f6e --- /dev/null +++ b/Tests/Fixtures/paths_test/same_relative_path_test/parent1/parent1.yml @@ -0,0 +1,2 @@ +include: +- same/same.yml diff --git a/Tests/Fixtures/paths_test/same_relative_path_test/parent1/same/same.yml b/Tests/Fixtures/paths_test/same_relative_path_test/parent1/same/same.yml new file mode 100644 index 000000000..57792c6f5 --- /dev/null +++ b/Tests/Fixtures/paths_test/same_relative_path_test/parent1/same/same.yml @@ -0,0 +1,2 @@ +include: +- target1/target1.yml diff --git a/Tests/Fixtures/paths_test/same_relative_path_test/parent1/same/target1/target1.yml b/Tests/Fixtures/paths_test/same_relative_path_test/parent1/same/target1/target1.yml new file mode 100644 index 000000000..9889fd2fb --- /dev/null +++ b/Tests/Fixtures/paths_test/same_relative_path_test/parent1/same/target1/target1.yml @@ -0,0 +1,6 @@ +targets: + target1: + type: framework + platform: macOS + sources: + - source diff --git a/Tests/Fixtures/paths_test/same_relative_path_test/parent2/parent2.yml b/Tests/Fixtures/paths_test/same_relative_path_test/parent2/parent2.yml new file mode 100644 index 000000000..745601f6e --- /dev/null +++ b/Tests/Fixtures/paths_test/same_relative_path_test/parent2/parent2.yml @@ -0,0 +1,2 @@ +include: +- same/same.yml diff --git a/Tests/Fixtures/paths_test/same_relative_path_test/parent2/same/same.yml b/Tests/Fixtures/paths_test/same_relative_path_test/parent2/same/same.yml new file mode 100644 index 000000000..39b16e6d4 --- /dev/null +++ b/Tests/Fixtures/paths_test/same_relative_path_test/parent2/same/same.yml @@ -0,0 +1,2 @@ +include: +- target2/target2.yml diff --git a/Tests/Fixtures/paths_test/same_relative_path_test/parent2/same/target2/target2.yml b/Tests/Fixtures/paths_test/same_relative_path_test/parent2/same/target2/target2.yml new file mode 100644 index 000000000..88e47edff --- /dev/null +++ b/Tests/Fixtures/paths_test/same_relative_path_test/parent2/same/target2/target2.yml @@ -0,0 +1,6 @@ +targets: + target2: + type: framework + platform: macOS + sources: + - source diff --git a/Tests/Fixtures/paths_test/same_relative_path_test/same_relative_path_test.yml b/Tests/Fixtures/paths_test/same_relative_path_test/same_relative_path_test.yml new file mode 100644 index 000000000..e87e1d46d --- /dev/null +++ b/Tests/Fixtures/paths_test/same_relative_path_test/same_relative_path_test.yml @@ -0,0 +1,12 @@ +include: +- parent1/parent1.yml +- parent2/parent2.yml +targets: + app: + type: application + platform: macOS + sources: + - source + dependencies: + - target: target1 + - target: target2 diff --git a/Tests/Fixtures/scheme_test/TestProject.xcodeproj/project.pbxproj b/Tests/Fixtures/scheme_test/TestProject.xcodeproj/project.pbxproj index e907f8e29..baed78ca9 100644 --- a/Tests/Fixtures/scheme_test/TestProject.xcodeproj/project.pbxproj +++ b/Tests/Fixtures/scheme_test/TestProject.xcodeproj/project.pbxproj @@ -3,10 +3,11 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 77; objects = { /* Begin PBXFileReference section */ + 5FE827133AD803E389008F92 /* Shared_TargetScheme.bundle */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = Shared_TargetScheme.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 9194D98A5CC4C58074AED541 /* ExternalTarget.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ExternalTarget.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -22,6 +23,7 @@ isa = PBXGroup; children = ( 9194D98A5CC4C58074AED541 /* ExternalTarget.framework */, + 5FE827133AD803E389008F92 /* Shared_TargetScheme.bundle */, ); name = Products; sourceTree = ""; @@ -40,32 +42,53 @@ dependencies = ( ); name = ExternalTarget; + packageProductDependencies = ( + ); productName = ExternalTarget; productReference = 9194D98A5CC4C58074AED541 /* ExternalTarget.framework */; productType = "com.apple.product-type.framework"; }; + 7D5ECBED52C0D723572BDC7A /* Shared_TargetScheme */ = { + isa = PBXNativeTarget; + buildConfigurationList = FF87BC5AF9E43A6A84F165D0 /* Build configuration list for PBXNativeTarget "Shared_TargetScheme" */; + buildPhases = ( + ); + buildRules = ( + ); + dependencies = ( + ); + name = Shared_TargetScheme; + packageProductDependencies = ( + ); + productName = Shared_TargetScheme; + productReference = 5FE827133AD803E389008F92 /* Shared_TargetScheme.bundle */; + productType = "com.apple.product-type.bundle"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 8702E0566EC7EF0ABE948569 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; - TargetAttributes = { - }; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1430; }; buildConfigurationList = E903F6E8184E2A86CEC31778 /* Build configuration list for PBXProject "TestProject" */; - compatibilityVersion = "Xcode 10.0"; + compatibilityVersion = "Xcode 14.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( + Base, en, ); mainGroup = 2D08B11F4EE060D112B7BCA1; + minimizedProjectReferenceProxies = 1; + preferredProjectObjectVersion = 77; projectDirPath = ""; projectRoot = ""; targets = ( 370BCE474732AA3FDEE3019C /* ExternalTarget */, + 7D5ECBED52C0D723572BDC7A /* Shared_TargetScheme */, ); }; /* End PBXProject section */ @@ -91,6 +114,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -106,6 +130,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -124,11 +149,13 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; - VALIDATE_PRODUCT = YES; }; name = Release; }; @@ -184,6 +211,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; @@ -199,6 +227,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -223,7 +252,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MTL_ENABLE_DEBUG_INFO = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; @@ -233,6 +263,30 @@ }; name = Debug; }; + EC8D269E955A03687C9CC471 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + EFFEE19ADA3596D4D0EDD264 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -254,6 +308,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; + FF87BC5AF9E43A6A84F165D0 /* Build configuration list for PBXNativeTarget "Shared_TargetScheme" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EC8D269E955A03687C9CC471 /* Debug */, + EFFEE19ADA3596D4D0EDD264 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; /* End XCConfigurationList section */ }; rootObject = 8702E0566EC7EF0ABE948569 /* Project object */; diff --git a/Tests/Fixtures/scheme_test/TestProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Tests/Fixtures/scheme_test/TestProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 2bf8bd93d..919434a62 100644 --- a/Tests/Fixtures/scheme_test/TestProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/Tests/Fixtures/scheme_test/TestProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/Tests/Fixtures/scheme_test/TestProject.xcodeproj/xcshareddata/xcschemes/ExternalTarget.xcscheme b/Tests/Fixtures/scheme_test/TestProject.xcodeproj/xcshareddata/xcschemes/ExternalTarget.xcscheme new file mode 100644 index 000000000..1ffbdd086 --- /dev/null +++ b/Tests/Fixtures/scheme_test/TestProject.xcodeproj/xcshareddata/xcschemes/ExternalTarget.xcscheme @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/Fixtures/scheme_test/TestProject.xcodeproj/xcshareddata/xcschemes/Shared_TargetScheme.xcscheme b/Tests/Fixtures/scheme_test/TestProject.xcodeproj/xcshareddata/xcschemes/Shared_TargetScheme.xcscheme new file mode 100644 index 000000000..6210c087e --- /dev/null +++ b/Tests/Fixtures/scheme_test/TestProject.xcodeproj/xcshareddata/xcschemes/Shared_TargetScheme.xcscheme @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/Fixtures/scheme_test/TestProject.xcodeproj/xcuserdata/someUser.xcuserdatad/xcschemes/User_ProjectScheme.xcscheme b/Tests/Fixtures/scheme_test/TestProject.xcodeproj/xcuserdata/someUser.xcuserdatad/xcschemes/User_ProjectScheme.xcscheme new file mode 100644 index 000000000..c9cc528de --- /dev/null +++ b/Tests/Fixtures/scheme_test/TestProject.xcodeproj/xcuserdata/someUser.xcuserdatad/xcschemes/User_ProjectScheme.xcscheme @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/Fixtures/scheme_test/TestProject.xcodeproj/xcuserdata/someUser.xcuserdatad/xcschemes/xcschememanagement.plist b/Tests/Fixtures/scheme_test/TestProject.xcodeproj/xcuserdata/someUser.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 000000000..f92f56495 --- /dev/null +++ b/Tests/Fixtures/scheme_test/TestProject.xcodeproj/xcuserdata/someUser.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,26 @@ + + + + + SchemeUserState + + ExternalTarget.xcscheme_^#shared#^_ + + isShown + + + Shared_TargetScheme.xcscheme_^#shared#^_ + + orderHint + 0 + + User_ProjectScheme.xcscheme + + isShown + + orderHint + 1 + + + + diff --git a/Tests/Fixtures/scheme_test/test_project.yml b/Tests/Fixtures/scheme_test/test_project.yml index 846fb53f2..8faedc0ee 100644 --- a/Tests/Fixtures/scheme_test/test_project.yml +++ b/Tests/Fixtures/scheme_test/test_project.yml @@ -1,5 +1,24 @@ name: TestProject +schemes: + User_ProjectScheme: + build: + targets: + ExternalTarget: all + management: + shared: false + orderHint: 1 + isShown: true targets: ExternalTarget: type: framework platform: iOS + scheme: + management: + shared: true + isShown: false + Shared_TargetScheme: + type: bundle + platform: iOS + scheme: + management: + orderHint: 0 \ No newline at end of file diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift new file mode 100644 index 000000000..711a949e9 --- /dev/null +++ b/Tests/LinuxMain.swift @@ -0,0 +1,3 @@ +// LinuxMain.swift +fatalError("Run the tests with `swift test --enable-test-discovery`.") + diff --git a/Tests/PerformanceTests/PerformanceTests.swift b/Tests/PerformanceTests/PerformanceTests.swift index 294b1b9ce..c1a3d2b03 100644 --- a/Tests/PerformanceTests/PerformanceTests.swift +++ b/Tests/PerformanceTests/PerformanceTests.swift @@ -1,6 +1,7 @@ import Foundation import PathKit import ProjectSpec +import TestSupport import XcodeGenKit import XcodeProj import XCTest @@ -15,8 +16,9 @@ class GeneratedPerformanceTests: XCTestCase { try dumpYamlDictionary(project.toJSONDictionary(), path: specPath) measure { - let spec = try! SpecFile(path: specPath) - _ = spec.resolvedDictionary(variables: ProcessInfo.processInfo.environment) + let spec = try! SpecFile(path: specPath, + variables: ProcessInfo.processInfo.environment) + _ = spec.resolvedDictionary() } } @@ -24,14 +26,14 @@ class GeneratedPerformanceTests: XCTestCase { let project = try Project.testProject(basePath: basePath) measure { let generator = ProjectGenerator(project: project) - _ = try! generator.generateXcodeProject() + _ = try! generator.generateXcodeProject(userName: "someUser") } } func testWriting() throws { let project = try Project.testProject(basePath: basePath) let generator = ProjectGenerator(project: project) - let xcodeProject = try generator.generateXcodeProject() + let xcodeProject = try generator.generateXcodeProject(userName: "someUser") measure { xcodeProject.pbxproj.invalidateUUIDs() try! xcodeProject.write(path: project.defaultProjectPath) @@ -61,17 +63,19 @@ class FixturePerformanceTests: XCTestCase { } func testFixtureGeneration() throws { + try skipIfNecessary() let project = try Project(path: specPath) measure { let generator = ProjectGenerator(project: project) - _ = try! generator.generateXcodeProject() + _ = try! generator.generateXcodeProject(userName: "someUser") } } func testFixtureWriting() throws { + try skipIfNecessary() let project = try Project(path: specPath) let generator = ProjectGenerator(project: project) - let xcodeProject = try generator.generateXcodeProject() + let xcodeProject = try generator.generateXcodeProject(userName: "someUser") measure { xcodeProject.pbxproj.invalidateUUIDs() try! xcodeProject.write(path: project.defaultProjectPath) diff --git a/Tests/PerformanceTests/TestProject.swift b/Tests/PerformanceTests/TestProject.swift index e2e7b3727..4ce17072e 100644 --- a/Tests/PerformanceTests/TestProject.swift +++ b/Tests/PerformanceTests/TestProject.swift @@ -18,6 +18,7 @@ extension Project { testTargets: [], configVariants: ["Test", "Staging", "Prod"], gatherCoverageData: true, + storeKitConfiguration: "Configuration.storekit", disableMainThreadChecker: true, stopOnEveryMainThreadCheckerIssue: false, commandLineArguments: [ @@ -29,7 +30,8 @@ extension Project { XCScheme.EnvironmentVariable(variable: "ENV2", value: "HELLO", enabled: false), ], preActions: [Scheme.ExecutionAction(name: "run", script: "script")], - postActions: [Scheme.ExecutionAction(name: "run", script: "script")] + postActions: [Scheme.ExecutionAction(name: "run", script: "script")], + management: Scheme.Management(shared: false, orderHint: 1, isShown: true) ) for platform in Platform.allCases { let appTarget = Target( @@ -115,8 +117,8 @@ extension Project { Config(name: "Release Test", type: .release), Config(name: "Debug Staging", type: .debug), Config(name: "Release Staging", type: .release), - Config(name: "Debug Production", type: .debug), - Config(name: "Release Production", type: .release), + Config(name: "Debug Prod", type: .debug), + Config(name: "Release Prod", type: .release), ], targets: targets, aggregateTargets: [], diff --git a/Tests/ProjectSpecTests/InvalidConfigsFormatTests.swift b/Tests/ProjectSpecTests/InvalidConfigsFormatTests.swift new file mode 100644 index 000000000..96a7540d1 --- /dev/null +++ b/Tests/ProjectSpecTests/InvalidConfigsFormatTests.swift @@ -0,0 +1,43 @@ +import ProjectSpec +import Testing +import TestSupport +import PathKit + +struct InvalidConfigsMappingFormatTests { + struct InvalidConfigsTestArguments { + var fixturePath: Path + var expectedError: SpecParsingError + } + + private static var testArguments: [InvalidConfigsTestArguments] { + let invalidConfigsFixturePath: Path = fixturePath + "invalid_configs" + return [ + InvalidConfigsTestArguments( + fixturePath: invalidConfigsFixturePath + "invalid_configs_value_non_mapping_settings.yml", + expectedError: SpecParsingError.invalidConfigsMappingFormat(keys: ["invalid_key0", "invalid_key1"]) + ), + InvalidConfigsTestArguments( + fixturePath: invalidConfigsFixturePath + "invalid_configs_value_non_mapping_targets.yml", + expectedError: SpecParsingError.invalidConfigsMappingFormat(keys: ["invalid_key0", "invalid_key1"]) + ), + InvalidConfigsTestArguments( + fixturePath: invalidConfigsFixturePath + "invalid_configs_value_non_mapping_aggregate_targets.yml", + expectedError: SpecParsingError.invalidConfigsMappingFormat(keys: ["invalid_key0", "invalid_key1"]) + ), + InvalidConfigsTestArguments( + fixturePath: invalidConfigsFixturePath + "invalid_configs_value_non_mapping_setting_groups.yml", + expectedError: SpecParsingError.invalidConfigsMappingFormat(keys: ["invalid_key0", "invalid_key1"]) + ) + ] + } + + @Test("throws invalidConfigsMappingFormat for non-mapping configs entries", arguments: testArguments) + func testInvalidConfigsMappingFormat(_ arguments: InvalidConfigsTestArguments) throws { + #expect { + try Project(path: arguments.fixturePath) + } throws: { actualError in + (actualError as any CustomStringConvertible).description + == arguments.expectedError.description + } + } +} diff --git a/Tests/ProjectSpecTests/ProjectSpecTests.swift b/Tests/ProjectSpecTests/ProjectSpecTests.swift index 22944d4fe..3ae878ac4 100644 --- a/Tests/ProjectSpecTests/ProjectSpecTests.swift +++ b/Tests/ProjectSpecTests/ProjectSpecTests.swift @@ -73,12 +73,23 @@ class ProjectSpecTests: XCTestCase { describe { $0.it("has correct build setting") { + try expect(Platform.auto.deploymentTargetSetting) == "" try expect(Platform.iOS.deploymentTargetSetting) == "IPHONEOS_DEPLOYMENT_TARGET" try expect(Platform.tvOS.deploymentTargetSetting) == "TVOS_DEPLOYMENT_TARGET" try expect(Platform.watchOS.deploymentTargetSetting) == "WATCHOS_DEPLOYMENT_TARGET" try expect(Platform.macOS.deploymentTargetSetting) == "MACOSX_DEPLOYMENT_TARGET" + try expect(Platform.visionOS.deploymentTargetSetting) == "XROS_DEPLOYMENT_TARGET" } + $0.it("has correct sdk root") { + try expect(Platform.auto.sdkRoot) == "auto" + try expect(Platform.iOS.sdkRoot) == "iphoneos" + try expect(Platform.tvOS.sdkRoot) == "appletvos" + try expect(Platform.watchOS.sdkRoot) == "watchos" + try expect(Platform.macOS.sdkRoot) == "macosx" + try expect(Platform.visionOS.sdkRoot) == "xros" + } + $0.it("parses version correctly") { try expect(Version.parse("2").deploymentTarget) == "2.0" try expect(Version.parse("2.0").deploymentTarget) == "2.0" @@ -111,7 +122,7 @@ class ProjectSpecTests: XCTestCase { project.options = SpecOptions(minimumXcodeGenVersion: minimumVersion) func expectMinimumXcodeGenVersionError(_ project: Project, minimumVersion: Version, xcodeGenVersion: Version, file: String = #file, line: Int = #line) throws { - try expectError(SpecValidationError.ValidationError.invalidXcodeGenVersion(minimumVersion: minimumVersion, version: xcodeGenVersion), file: file, line: line) { + try expectError(SpecValidationError(errors: [SpecValidationError.ValidationError.invalidXcodeGenVersion(minimumVersion: minimumVersion, version: xcodeGenVersion)]), file: file, line: line) { try project.validateMinimumXcodeGenVersion(xcodeGenVersion) } } @@ -126,7 +137,7 @@ class ProjectSpecTests: XCTestCase { project.settings = invalidSettings project.configFiles = ["invalidConfig": "invalidConfigFile"] project.fileGroups = ["invalidFileGroup"] - project.packages = ["invalidLocalPackage": .local(path: "invalidLocalPackage")] + project.packages = ["invalidLocalPackage": .local(path: "invalidLocalPackage", group: nil, excludeFromProject: false)] project.settingGroups = ["settingGroup1": Settings( configSettings: ["invalidSettingGroupConfig": [:]], groups: ["invalidSettingGroupSettingGroup"] @@ -142,6 +153,121 @@ 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, + dependencies: [ + Dependency(type: .target, reference: "dependency1"), + Dependency(type: .target, reference: "dependency1"), + Dependency(type: .framework, reference: "dependency2"), + Dependency(type: .framework, reference: "dependency2"), + + // multiple package dependencies with different products should be allowed + Dependency(type: .package(products: ["one"]), reference: "package1"), + Dependency(type: .package(products: ["two"]), reference: "package1"), + ] + ), + Target( + name: "target2", + type: .framework, + platform: .iOS, + 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")) + + try expectNoValidationError(project, .duplicateDependencies(target: "target1", dependencyReference: "package1")) + } + + $0.it("unexpected supported destinations for watch app") { + var project = baseProject + project.targets = [ + Target( + name: "target1", + type: .application, + platform: .watchOS, + supportedDestinations: [.macOS] + ) + ] + try expectValidationError(project, .unexpectedTargetPlatformForSupportedDestinations(target: "target1", platform: .watchOS)) + } + + $0.it("watchOS in multiplatform app's supported destinations") { + var project = baseProject + project.targets = [ + Target( + name: "target1", + type: .application, + platform: .auto, + supportedDestinations: [.watchOS] + ) + ] + try expectValidationError(project, .containsWatchOSDestinationForMultiplatformApp(target: "target1")) + } + + $0.it("watchOS in non-app's supported destinations") { + var project = baseProject + project.targets = [ + Target( + name: "target1", + type: .framework, + platform: .auto, + supportedDestinations: [.watchOS] + ) + ] + try expectNoValidationError(project, .containsWatchOSDestinationForMultiplatformApp(target: "target1")) + } + + $0.it("multiple definitions of mac platform in supported destinations") { + var project = baseProject + project.targets = [ + Target( + name: "target1", + type: .application, + platform: .iOS, + supportedDestinations: [.macOS, .macCatalyst] + ) + ] + try expectValidationError(project, .multipleMacPlatformsInSupportedDestinations(target: "target1")) + } + + $0.it("invalid target platform for macCatalyst supported destinations") { + var project = baseProject + project.targets = [ + Target( + name: "target1", + type: .application, + platform: .tvOS, + supportedDestinations: [.tvOS, .macCatalyst] + ) + ] + try expectValidationError(project, .invalidTargetPlatformForSupportedDestinations(target: "target1")) + } + + $0.it("missing target platform in supported destinations") { + var project = baseProject + project.targets = [ + Target( + name: "target1", + type: .application, + platform: .iOS, + supportedDestinations: [.tvOS] + ) + ] + try expectValidationError(project, .missingTargetPlatformInSupportedDestinations(target: "target1", platform: .iOS)) + } + $0.it("allows non-existent configurations") { var project = baseProject project.options = SpecOptions(disabledValidations: [.missingConfigs]) @@ -168,7 +294,7 @@ class ProjectSpecTests: XCTestCase { sources: ["invalidSource"], dependencies: [ Dependency(type: .target, reference: "invalidDependency"), - Dependency(type: .package(product: nil), reference: "invalidPackage"), + Dependency(type: .package(products: []), reference: "invalidPackage"), ], preBuildScripts: [BuildScript(script: .path("invalidPreBuildScript"), name: "preBuildScript1")], postCompileScripts: [BuildScript(script: .path("invalidPostCompileScript"))], @@ -339,6 +465,118 @@ class ProjectSpecTests: XCTestCase { project.schemes = [scheme] try project.validate() } + + $0.it("validates scheme variants") { + + func expectVariant(_ variant: String, type: ConfigType = .debug, for config: Config, matches: Bool, file: String = #file, line: Int = #line) throws { + let configs = [Config(name: "xxxxxxxxxxx", type: .debug), config] + let foundConfig = configs.first(including: variant, for: type) + let found = foundConfig != nil && foundConfig != configs[0] + try expect(found, file: file, line: line) == matches + } + + try expectVariant("Dev", for: Config(name: "DevDebug", type: .debug), matches: true) + try expectVariant("Dev", for: Config(name: "Dev debug", type: .debug), matches: true) + try expectVariant("Dev", for: Config(name: "DEV DEBUG", type: .debug), matches: true) + try expectVariant("Dev", for: Config(name: "Debug Dev", type: .debug), matches: true) + try expectVariant("Dev", for: Config(name: "dev Debug", type: .debug), matches: true) + try expectVariant("Dev", for: Config(name: "Dev debug", type: .release), matches: false) + try expectVariant("Dev", for: Config(name: "Dev-debug", type: .debug), matches: true) + try expectVariant("Dev", for: Config(name: "Dev_debug", type: .debug), matches: true) + try expectVariant("Prod", for: Config(name: "PreProd debug", type: .debug), matches: false) + try expectVariant("Develop", for: Config(name: "Dev debug", type: .debug), matches: false) + try expectVariant("Development", for: Config(name: "Debug (Development)", type: .debug), matches: true) + try expectVariant("Staging", for: Config(name: "Debug (Staging)", type: .debug), matches: true) + try expectVariant("Production", for: Config(name: "Debug (Production)", type: .debug), matches: true) + } + + $0.it("fails on missing test plan file") { + var project = baseProject + + project.configs = Config.defaultConfigs + + project.targets = [Target( + name: "target1", + type: .application, + platform: .iOS + )] + + let testPlan = TestPlan(path: "does-not-exist.xctestplan") + + let scheme = Scheme( + name: "xctestplan-scheme", + build: Scheme.Build(targets: [ + Scheme.BuildTarget(target: "target1") + ]), + test: Scheme.Test(config: "Debug", + testPlans: [testPlan] + ) + ) + + project.schemes = [scheme] + + try expectValidationError(project, .invalidTestPlan(testPlan)) + } + + $0.it("fails on multiple default test plans") { + var project = baseProject + + project.configs = Config.defaultConfigs + + project.targets = [Target( + name: "target1", + type: .application, + platform: .iOS + )] + + let testPlan1 = TestPlan(path: "\(fixturePath.string)/TestProject/App_iOS/App_iOS.xctestplan", defaultPlan: true) + let testPlan2 = TestPlan(path: "\(fixturePath.string)/TestProject/App_iOS/App_iOS.xctestplan", defaultPlan: true) + + let scheme = Scheme( + name: "xctestplan-scheme", + build: Scheme.Build(targets: [ + Scheme.BuildTarget(target: "target1") + ]), + test: Scheme.Test(config: "Debug", + testPlans: [testPlan1, testPlan2] + ) + ) + + project.schemes = [scheme] + + try expectValidationError(project, .multipleDefaultTestPlans) + } + + $0.it("fails on packages has not plugin package reference") { + var project = baseProject + project.targets = [ + Target( + name: "target", + type: .application, + platform: .iOS, + buildToolPlugins: [ + BuildToolPlugin(plugin: "plugin", package: "package") + ] + ) + ] + try expectValidationError(project, .invalidPluginPackageReference(plugin: "plugin", package: "package")) + } + + $0.it("allow on packages has plugin package reference") { + var project = baseProject + project.packages["package"] = .remote(url: "url", versionRequirement: .branch("branch")) + project.targets = [ + Target( + name: "target", + type: .application, + platform: .iOS, + buildToolPlugins: [ + BuildToolPlugin(plugin: "plugin", package: "package") + ] + ) + ] + try expectNoValidationError(project, .invalidPluginPackageReference(plugin: "plugin", package: "package")) + } } } @@ -374,7 +612,8 @@ class ProjectSpecTests: XCTestCase { codeSign: true, link: true, implicit: true, - weakLink: true)], + weakLink: true, + copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .frameworks, subpath: "example", phaseOrder: .postCompile))], info: Plist(path: "info.plist", attributes: ["foo": "bar"]), entitlements: Plist(path: "entitlements.plist", attributes: ["foo": "bar"]), transitivelyLinkDependencies: true, @@ -388,7 +627,9 @@ class ProjectSpecTests: XCTestCase { outputFileLists: ["bar.xcfilelist"], shell: "/bin/bash", runOnlyWhenInstalling: true, - showEnvVars: true)], + showEnvVars: true, + basedOnDependencyAnalysis: false)], + buildToolPlugins: [BuildToolPlugin(plugin: "plugin", package: "Yams")], postCompileScripts: [BuildScript(script: .path("cmd.sh"), name: "Bar script", inputFiles: ["foo"], @@ -397,7 +638,8 @@ class ProjectSpecTests: XCTestCase { outputFileLists: ["bar.xcfilelist"], shell: "/bin/bash", runOnlyWhenInstalling: true, - showEnvVars: true)], + showEnvVars: true, + basedOnDependencyAnalysis: false)], postBuildScripts: [BuildScript(script: .path("cmd.sh"), name: "an another script", inputFiles: ["foo"], @@ -406,24 +648,41 @@ class ProjectSpecTests: XCTestCase { outputFileLists: ["bar.xcfilelist"], shell: "/bin/bash", runOnlyWhenInstalling: true, - showEnvVars: true)], + showEnvVars: true, + basedOnDependencyAnalysis: false), + BuildScript(script: .path("cmd.sh"), + name: "Dependency script", + inputFiles: ["foo"], + outputFiles: ["bar"], + inputFileLists: ["foo.xcfilelist"], + outputFileLists: ["bar.xcfilelist"], + shell: "/bin/bash", + runOnlyWhenInstalling: true, + showEnvVars: true, + basedOnDependencyAnalysis: true, + discoveredDependencyFile: "dep.d")], buildRules: [BuildRule(fileType: .pattern("*.xcassets"), action: .script("pre_process_swift.py"), name: "My Build Rule", outputFiles: ["$(SRCROOT)/Generated.swift"], - outputFilesCompilerFlags: ["foo"]), + outputFilesCompilerFlags: ["foo"], + runOncePerArchitecture: false), BuildRule(fileType: .type("sourcecode.swift"), action: .compilerSpec("com.apple.xcode.tools.swift.compiler"), name: nil, outputFiles: ["bar"], - outputFilesCompilerFlags: ["foo"])], + outputFilesCompilerFlags: ["foo"], + runOncePerArchitecture: true)], scheme: TargetScheme(testTargets: [Scheme.Test.TestTarget(targetReference: "test target", randomExecutionOrder: false, parallelizable: false)], configVariants: ["foo"], gatherCoverageData: true, + coverageTargets: ["App"], + storeKitConfiguration: "Configuration.storekit", disableMainThreadChecker: true, stopOnEveryMainThreadCheckerIssue: false, + disableThreadPerformanceChecker: true, commandLineArguments: ["foo": true], environmentVariables: [XCScheme.EnvironmentVariable(variable: "environmentVariable", value: "bar", @@ -438,7 +697,8 @@ class ProjectSpecTests: XCTestCase { passSettings: true, arguments: "bar", workingDirectory: "foo"), - attributes: ["foo": "bar"])], + attributes: ["foo": "bar"], + putResourcesBeforeSourcesBuildPhase: true)], aggregateTargets: [AggregateTarget(name: "aggregate target", targets: ["App"], settings: Settings(buildSettings: ["buildSettings": "bar"], @@ -455,13 +715,15 @@ class ProjectSpecTests: XCTestCase { outputFileLists: ["bar.xcfilelist"], shell: "/bin/bash", runOnlyWhenInstalling: true, - showEnvVars: false)], + showEnvVars: false, + basedOnDependencyAnalysis: false)], scheme: TargetScheme(testTargets: [Scheme.Test.TestTarget(targetReference: "test target", randomExecutionOrder: false, parallelizable: false)], configVariants: ["foo"], gatherCoverageData: true, disableMainThreadChecker: true, + disableThreadPerformanceChecker: true, commandLineArguments: ["foo": true], environmentVariables: [XCScheme.EnvironmentVariable(variable: "environmentVariable", value: "bar", @@ -505,9 +767,19 @@ class ProjectSpecTests: XCTestCase { environmentVariables: [XCScheme.EnvironmentVariable(variable: "foo", value: "bar", enabled: false)], - launchAutomaticallySubstyle: "2"), + enableGPUFrameCaptureMode: .openGL, + enableAddressSanitizer: true, + enableASanStackUseAfterReturn: true, + enableThreadSanitizer: true, + enableUBSanitizer: true, + launchAutomaticallySubstyle: "2", + storeKitConfiguration: "Configuration.storekit"), test: Scheme.Test(config: "Config", gatherCoverageData: true, + enableAddressSanitizer: true, + enableASanStackUseAfterReturn: true, + enableThreadSanitizer: true, + enableUBSanitizer: true, disableMainThreadChecker: true, randomExecutionOrder: false, parallelizable: false, @@ -597,17 +869,47 @@ class ProjectSpecTests: XCTestCase { } } +private func expectValidationErrors(_ project: Project, _ expectedErrors: Set, file: String = #file, line: Int = #line) throws { + let expectedErrorString = expectedErrors + .map { $0.description } + .sorted() + .joined(separator: "\n") + do { + try project.validate() + if !expectedErrors.isEmpty { + throw failure("Supposed to fail with:\n\(expectedErrorString)", file: file, line: line) + } + } catch let error as SpecValidationError { + if Set(error.errors) != expectedErrors { + throw failure("Supposed to fail with:\n\(expectedErrorString)\nbut got:\n\(error.errors.map { $0.description }.sorted().joined(separator: "\n"))", file: file, line: line) + } + return + } catch { + throw failure("Supposed to fail with:\n\(expectedErrorString)", file: file, line: line) + } +} + private func expectValidationError(_ project: Project, _ expectedError: SpecValidationError.ValidationError, file: String = #file, line: Int = #line) throws { do { try project.validate() + throw failure("Supposed to fail with \"\(expectedError)\"", file: file, line: line) } catch let error as SpecValidationError { - if !error.errors - .contains(where: { $0.description == expectedError.description }) { + if !error.errors.contains(expectedError) { throw failure("Supposed to fail with:\n\(expectedError)\nbut got:\n\(error.errors.map { $0.description }.joined(separator: "\n"))", file: file, line: line) } - return } catch { throw failure("Supposed to fail with \"\(expectedError)\"", file: file, line: line) } - throw failure("Supposed to fail with \"\(expectedError)\"", file: file, line: line) +} + +private func expectNoValidationError(_ project: Project, _ error: SpecValidationError.ValidationError, file: String = #file, line: Int = #line) throws { + do { + try project.validate() + } catch let validationError as SpecValidationError { + if validationError.errors.contains(error) { + throw failure("Failed with:\n\(error.description)", file: file, line: line) + } + } catch { + throw failure("Failed with:\n\(error)", file: file, line: line) + } } diff --git a/Tests/ProjectSpecTests/SpecLoadingTests.swift b/Tests/ProjectSpecTests/SpecLoadingTests.swift index 82e5a1826..c0bbb281d 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(products: []), reference: "Yams")]), + Target(name: "NewTarget", type: .application, platform: .iOS, sources: ["template", "target"]), + ] + } + + $0.it("merges includes with additional") { + let path = fixturePath + "include_test.yml" + let project = try loadSpec(path: path, variables: ["INCLUDE_ADDITIONAL_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": "ADDITIONAL"]), + "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(products: []), reference: "SwiftPM"), Dependency(type: .package(products: []), reference: "Yams")]), + Target(name: "NewTarget", type: .application, platform: .iOS, sources: ["template", "target"]), + ] + } + + $0.it("merges includes without additional by environment variable") { + let path = fixturePath + "include_test.yml" + let project = try loadSpec(path: path, variables: ["INCLUDE_ADDITIONAL_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(products: []), reference: "Yams")]), Target(name: "NewTarget", type: .application, platform: .iOS, sources: ["template", "target"]), ] } @@ -98,7 +130,8 @@ class SpecLoadingTests: XCTestCase { entitlements: Plist(path: "paths_test/entitlements"), preBuildScripts: [BuildScript(script: .path("paths_test/preBuildScript"))], postCompileScripts: [BuildScript(script: .path("paths_test/postCompileScript"))], - postBuildScripts: [BuildScript(script: .path("paths_test/postBuildScript"))] + postBuildScripts: [BuildScript(script: .path("paths_test/postBuildScript"))], + scheme: TargetScheme(testPlans: [.init(path: "paths_test/TestPlan.xctestplan")]) ), Target( name: "NewTarget", @@ -129,7 +162,43 @@ class SpecLoadingTests: XCTestCase { postCompileScripts: [BuildScript(script: .path("paths_test/recursive_test/postCompileScript"))], postBuildScripts: [BuildScript(script: .path("paths_test/recursive_test/postBuildScript"))] ), + Target( + name: "app", + type: .application, + platform: .macOS, + sources: ["paths_test/same_relative_path_test/source"], + dependencies: [ + Dependency(type: .target, reference: "target1"), + Dependency(type: .target, reference: "target2") + ] + ), + Target( + name: "target1", + type: .framework, + platform: .macOS, + sources: ["paths_test/same_relative_path_test/parent1/same/target1/source"] + ), + Target( + name: "target2", + type: .framework, + platform: .macOS, + sources: ["paths_test/same_relative_path_test/parent2/same/target2/source"] + ) + ] + + try expect(project.schemes) == [ + Scheme( + name: "Scheme", + build: .init(targets: [.init(target: "NewTarget")]), + test: .init(testPlans: [.init(path: "paths_test/TestPlan.xctestplan")]) + ) + ] + + try expect(project.packages) == [ + "LocalPackage": .local(path: "paths_test/relative_local_package/LocalPackage", group: nil, excludeFromProject: false), ] + + try expect(project.fileGroups.contains("paths_test/relative_file_groups/TestFile.md")) == true } $0.it("respects directory expansion preference") { @@ -202,7 +271,7 @@ class SpecLoadingTests: XCTestCase { throw failure("\(key): \(parsedValue) does not equal \(expectedValue)") } } - if !(dictionary as NSDictionary).isEqual(expectedDictionary) { + if !(dictionary as NSDictionary).isEqual(expectedDictionary as NSDictionary) { throw failure("parsed yaml types don't match:\n\nParsed:\n\t\(dictionary.map { "\($0.key): \($0.value)" }.joined(separator: "\n\t"))\nExpected:\n\t\(expectedDictionary.map { "\($0.key): \($0.value)" }.joined(separator: "\n\t"))") } } @@ -316,6 +385,7 @@ class SpecLoadingTests: XCTestCase { func testProjectSpecParser() { let validTarget: [String: Any] = ["type": "application", "platform": "iOS"] + let validBreakpoint: [String: Any] = ["type": "Exception", "scope": "All", "stopOnStyle": "Catch"] let invalid = "invalid" describe { @@ -338,6 +408,93 @@ class SpecLoadingTests: XCTestCase { try expectTargetError(target, .invalidDependency([invalid: "name"])) } + $0.it("fails with incorrect breakpoint type") { + var breakpoint = validBreakpoint + breakpoint["type"] = invalid + try expectBreakpointError(breakpoint, .unknownBreakpointType(invalid)) + } + + $0.it("fails with incorrect breakpoint scope") { + var target = validBreakpoint + target["scope"] = invalid + try expectBreakpointError(target, .unknownBreakpointScope(invalid)) + } + + $0.it("fails with incorrect breakpoint stop on style") { + var target = validBreakpoint + target["stopOnStyle"] = invalid + try expectBreakpointError(target, .unknownBreakpointStopOnStyle(invalid)) + } + + $0.it("fails with incorrect breakpoint action type") { + var breakpoint = validBreakpoint + breakpoint["actions"] = [["type": invalid]] + try expectBreakpointError(breakpoint, .unknownBreakpointActionType(invalid)) + } + + $0.it("fails with incorrect breakpoint action conveyance type") { + var breakpoint = validBreakpoint + breakpoint["actions"] = [["type": "Log", "conveyanceType": invalid]] + try expectBreakpointError(breakpoint, .unknownBreakpointActionConveyanceType(invalid)) + } + + $0.it("fails with incorrect breakpoint action sound name") { + var breakpoint = validBreakpoint + breakpoint["actions"] = [["type": "Sound", "sound": invalid]] + try expectBreakpointError(breakpoint, .unknownBreakpointActionSoundName(invalid)) + } + + $0.it("parses breakpoints") { + let breakpointDictionaries = [ + ["type": "File", "path": "Foo.swift", "line": 7, "column": 14, "condition": "bar == nil"], + ["type": "Exception", "scope": "All", "stopOnStyle": "Catch"], + ["type": "SwiftError", "enabled": false], + ["type": "OpenGLError", "ignoreCount": 2], + ["type": "Symbolic", "symbol": "UIViewAlertForUnsatisfiableConstraints", "module": "UIKitCore"], + ["type": "IDEConstraintError", "continueAfterRunningActions": true], + ["type": "IDETestFailure"], + ] + + let project = try getProjectSpec(["breakpoints": breakpointDictionaries]) + + let expectedBreakpoints = [ + Breakpoint(type: .file(path: "Foo.swift", line: 7, column: 14), condition: "bar == nil"), + Breakpoint(type: .exception(.init(scope: .all, stopOnStyle: .catch))), + Breakpoint(type: .swiftError, enabled: false), + Breakpoint(type: .openGLError, ignoreCount: 2), + Breakpoint(type: .symbolic(symbol: "UIViewAlertForUnsatisfiableConstraints", module: "UIKitCore")), + Breakpoint(type: .ideConstraintError, continueAfterRunningActions: true), + Breakpoint(type: .ideTestFailure), + ] + + try expect(project.breakpoints) == expectedBreakpoints + } + + $0.it("parses breakpoint actions") { + var breakpointDicationary = validBreakpoint + breakpointDicationary["actions"] = [ + ["type": "DebuggerCommand", "command": "po $arg1"], + ["type": "Log", "message": "message", "conveyanceType": "speak"], + ["type": "ShellCommand", "path": "script.sh", "arguments": "argument1, argument2", "waitUntilDone": true], + ["type": "GraphicsTrace"], + ["type": "AppleScript", "script": #"display alert "Hello!""#], + ["type": "Sound", "sound": "Hero"], + ] + + let breakpoint = try Breakpoint(jsonDictionary: breakpointDicationary) + + let expectedActions: [Breakpoint.Action] = [ + .debuggerCommand("po $arg1"), + .log(.init(message: "message", conveyanceType: .speak)), + .shellCommand(path: "script.sh", arguments: "argument1, argument2", waitUntilDone: true), + .graphicsTrace, + .appleScript(#"display alert "Hello!""#), + .sound(.hero), + ] + + try expect(breakpoint.actions) == expectedActions + } + $0.it("parses sources") { var targetDictionary1 = validTarget targetDictionary1["sources"] = [ @@ -376,9 +533,9 @@ class SpecLoadingTests: XCTestCase { $0.it("parses target dependencies") { var targetDictionary = validTarget targetDictionary["dependencies"] = [ - ["target": "name", "embed": false], - ["target": "project/name", "embed": false], - ["carthage": "name", "findFrameworks": true], + ["target": "name", "embed": false, "platformFilter": "all"], + ["target": "project/name", "embed": false, "platformFilter": "macOS"], + ["carthage": "name", "findFrameworks": true, "platformFilter": "iOS"], ["carthage": "name", "findFrameworks": true, "linkType": "static"], ["framework": "path", "weak": true], ["sdk": "Contacts.framework"], @@ -386,16 +543,19 @@ class SpecLoadingTests: XCTestCase { "sdk": "Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework", "root": "DEVELOPER_DIR", ], + ["target": "conditionalMatch", "platforms": ["iOS"]], + ["target": "conditionalMiss", "platforms": ["watchOS"]], ] let target = try Target(name: "test", jsonDictionary: targetDictionary) - try expect(target.dependencies.count) == 7 - try expect(target.dependencies[0]) == Dependency(type: .target, reference: "name", embed: false) - try expect(target.dependencies[1]) == Dependency(type: .target, reference: "project/name", embed: false) - try expect(target.dependencies[2]) == Dependency(type: .carthage(findFrameworks: true, linkType: .dynamic), reference: "name") + try expect(target.dependencies.count) == 8 + try expect(target.dependencies[0]) == Dependency(type: .target, reference: "name", embed: false, platformFilter: .all) + try expect(target.dependencies[1]) == Dependency(type: .target, reference: "project/name", embed: false, platformFilter: .macOS) + try expect(target.dependencies[2]) == Dependency(type: .carthage(findFrameworks: true, linkType: .dynamic), reference: "name", platformFilter: .iOS) try expect(target.dependencies[3]) == Dependency(type: .carthage(findFrameworks: true, linkType: .static), reference: "name") try expect(target.dependencies[4]) == Dependency(type: .framework, reference: "path", weakLink: true) try expect(target.dependencies[5]) == Dependency(type: .sdk(root: nil), reference: "Contacts.framework") try expect(target.dependencies[6]) == Dependency(type: .sdk(root: "DEVELOPER_DIR"), reference: "Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework") + try expect(target.dependencies[7]) == Dependency(type: .target, reference: "conditionalMatch", platforms: [.iOS]) } $0.it("parses info plist") { @@ -450,10 +610,66 @@ class SpecLoadingTests: XCTestCase { target_iOS.deploymentTarget = Version(major: 9, minor: 0, patch: 0) target_tvOS.deploymentTarget = Version(major: 10, minor: 0, patch: 0) - try expect(project.targets.count) == 2 try expect(project.targets) == [target_iOS, target_tvOS] } + + $0.it("parses no platform fallbacks to auto if we are using supported destinations") { + let targetDictionary: [String: Any] = [ + "type": "framework", + "supportedDestinations": ["iOS", "tvOS"] + ] + let project = try getProjectSpec(["targets": ["Framework": targetDictionary]]) + let target = Target(name: "Framework", type: .framework, platform: .auto) + + try expect(project.targets) == [target] + } + + $0.it("parses no platform fails if we are not using supported destinations") { + let expectedError = SpecParsingError.unknownTargetPlatform("") + + let projectDictionary: [String: Any] = [ + "name": "test", + "targets": ["target1": [ + "type": "application" + ] as [String : Any]] + ] + + try expectError(expectedError) { + _ = try Project(jsonDictionary: projectDictionary) + } + } + + $0.it("parses supported destinations with macCatalyst but not iOS, we add iOS") { + let targetDictionary: [String: Any] = [ + "type": "framework", + "supportedDestinations": ["macCatalyst"] + ] + + let project = try getProjectSpec(["targets": ["Framework": targetDictionary]]) + let target = Target(name: "Framework", type: .framework, platform: .auto) + + try expect(project.targets) == [target] + try expect(project.targets.first?.supportedDestinations) == [.macCatalyst, .iOS] + } + + $0.it("invalid target platform because platform is an array and supported destinations is in use") { + let expectedError = SpecParsingError.invalidTargetPlatformAsArray + + let projectDictionary: [String: Any] = [ + "name": "test", + "targets": ["target1": [ + "type": "application", + "platform": ["iOS", "tvOS"], + "supportedDestinations": ["iOS", "tvOS"] + ] as [String : Any]] + ] + + try expectError(expectedError) { + _ = try Project(jsonDictionary: projectDictionary) + } + } + $0.it("parses target templates") { let targetDictionary: [String: Any] = [ @@ -709,10 +925,13 @@ class SpecLoadingTests: XCTestCase { "ENV1": true, ], "gatherCoverageData": true, + "coverageTargets": ["t1"], + "storeKitConfiguration": "Configuration.storekit", "language": "en", "region": "US", "disableMainThreadChecker": true, "stopOnEveryMainThreadCheckerIssue": true, + "disableThreadPerformanceChecker": true, "environmentVariables": [ "TEST_VAR": "TEST_VAL", ], @@ -728,6 +947,11 @@ class SpecLoadingTests: XCTestCase { "script": "hello", ], ], + "management": [ + "shared": false, + "isShown": true, + "orderHint": 10 + ], ] let target = try Target(name: "test", jsonDictionary: targetDictionary) @@ -736,14 +960,18 @@ class SpecLoadingTests: XCTestCase { testTargets: ["t1", "t2"], configVariants: ["dev", "app-store"], gatherCoverageData: true, + coverageTargets: ["t1"], + storeKitConfiguration: "Configuration.storekit", language: "en", region: "US", disableMainThreadChecker: true, stopOnEveryMainThreadCheckerIssue: true, + disableThreadPerformanceChecker: true, commandLineArguments: ["ENV1": true], environmentVariables: [XCScheme.EnvironmentVariable(variable: "TEST_VAR", value: "TEST_VAL", enabled: true)], preActions: [.init(name: "Do Thing", script: "dothing", settingsTarget: "test")], - postActions: [.init(name: "Run Script", script: "hello")] + postActions: [.init(name: "Run Script", script: "hello")], + management: Scheme.Management(shared: false, orderHint: 10, isShown: true) ) try expect(target.scheme) == scheme @@ -754,6 +982,7 @@ class SpecLoadingTests: XCTestCase { "build": [ "parallelizeBuild": false, "buildImplicitDependencies": false, + "runPostActionsOnFailure": true, "targets": [ "Target1": "all", "Target2": "testing", @@ -774,6 +1003,9 @@ class SpecLoadingTests: XCTestCase { "run": [ "config": "debug", "launchAutomaticallySubstyle": 2, + "enableGPUFrameCaptureMode": "disabled", + "storeKitConfiguration": "Configuration.storekit", + "disableThreadPerformanceChecker": true, ], "test": [ "config": "debug", @@ -782,6 +1014,8 @@ class SpecLoadingTests: XCTestCase { [ "name": "ExternalProject/Target2", "parallelizable": true, + "skipped": true, + "location": "test.gpx", "randomExecutionOrder": true, "skippedTests": ["Test/testExample()"], ], @@ -789,6 +1023,19 @@ class SpecLoadingTests: XCTestCase { "gatherCoverageData": true, "disableMainThreadChecker": true, "stopOnEveryMainThreadCheckerIssue": true, + "testPlans": [ + [ + "path": "Path/Plan.xctestplan" + ], + [ + "path": "Path/Plan2.xctestplan" + ] + ], + "preferredScreenCaptureFormat": "screenshots", + ], + "management": [ + "isShown": false, + "orderHint": 4 ], ] let scheme = try Scheme(name: "Scheme", jsonDictionary: schemeDictionary) @@ -809,10 +1056,14 @@ class SpecLoadingTests: XCTestCase { try expect(scheme.build.parallelizeBuild) == false try expect(scheme.build.buildImplicitDependencies) == false + try expect(scheme.build.runPostActionsOnFailure) == true let expectedRun = Scheme.Run( config: "debug", - launchAutomaticallySubstyle: "2" + enableGPUFrameCaptureMode: .disabled, + disableThreadPerformanceChecker: true, + launchAutomaticallySubstyle: "2", + storeKitConfiguration: "Configuration.storekit" ) try expect(scheme.run) == expectedRun @@ -826,11 +1077,69 @@ class SpecLoadingTests: XCTestCase { targetReference: "ExternalProject/Target2", randomExecutionOrder: true, parallelizable: true, + location: "test.gpx", + skipped: true, skippedTests: ["Test/testExample()"] ), + ], + testPlans: [ + .init(path: "Path/Plan.xctestplan"), + .init(path: "Path/Plan2.xctestplan") + ], + preferredScreenCaptureFormat: .screenshots + ) + try expect(scheme.test) == expectedTest + + let expectedManagement = Scheme.Management(shared: true, orderHint: 4, isShown: false) + try expect(scheme.management) == expectedManagement + } + + $0.it("parses alternate test schemes") { + let schemeDictionary: [String: Any] = [ + "build": [ + "targets": ["Target1": "all"], + ], + "test": [ + "config": "debug", + "targets": [ + "Target1", + [ + "name": "ExternalProject/Target2", + "parallelizable": true, + "location": "New York, NY, USA", + "randomExecutionOrder": true, + "selectedTests": ["Test/testExample()"], + ], + ], + "gatherCoverageData": true, + "disableMainThreadChecker": true, + "stopOnEveryMainThreadCheckerIssue": true, + ], + "management": [ + "isShown": false + ], + ] + let scheme = try Scheme(name: "Scheme", jsonDictionary: schemeDictionary) + + let expectedTest = Scheme.Test( + config: "debug", + gatherCoverageData: true, + disableMainThreadChecker: true, + targets: [ + "Target1", + Scheme.Test.TestTarget( + targetReference: "ExternalProject/Target2", + randomExecutionOrder: true, + parallelizable: true, + location: "New York, NY, USA", + selectedTests: ["Test/testExample()"] + ), ] ) try expect(scheme.test) == expectedTest + + let expectedManagement = Scheme.Management(shared: true, orderHint: nil, isShown: false) + try expect(scheme.management) == expectedManagement } $0.it("parses schemes variables") { @@ -846,6 +1155,7 @@ class SpecLoadingTests: XCTestCase { ["variable": "OTHER_ENV_VAR", "value": "VAL", "isEnabled": false], ], "launchAutomaticallySubstyle": "2", + "storeKitConfiguration": "Configuration.storekit", ], "test": [ "environmentVariables": [ @@ -876,6 +1186,7 @@ class SpecLoadingTests: XCTestCase { try expect(scheme.run?.environmentVariables) == expectedRunVariables try expect(scheme.run?.launchAutomaticallySubstyle) == "2" + try expect(scheme.run?.storeKitConfiguration) == "Configuration.storekit" try expect(scheme.test?.environmentVariables) == expectedTestVariables try expect(scheme.profile?.config) == "Release" try expect(scheme.profile?.environmentVariables.isEmpty) == true @@ -888,11 +1199,13 @@ class SpecLoadingTests: XCTestCase { ], "run": [ "launchAutomaticallySubstyle": 2, // Both integer and string supported + "storeKitConfiguration": "Configuration.storekit", ], ] let scheme = try Scheme(name: "Scheme", jsonDictionary: schemeDictionary) try expect(scheme.run?.launchAutomaticallySubstyle) == "2" + try expect(scheme.run?.storeKitConfiguration) == "Configuration.storekit" } $0.it("parses scheme templates") { @@ -931,6 +1244,7 @@ class SpecLoadingTests: XCTestCase { "build": [ "parallelizeBuild": false, "buildImplicitDependencies": false, + "runPostActionsOnFailure": true, "targets": [ "Target${name_1}": "all", "Target2": "testing", @@ -947,6 +1261,9 @@ class SpecLoadingTests: XCTestCase { ], ], ], + "run": [ + "storeKitConfiguration": "Configuration.storekit", + ], "test": [ "config": "debug", "targets": [ @@ -962,6 +1279,10 @@ class SpecLoadingTests: XCTestCase { "disableMainThreadChecker": true, "stopOnEveryMainThreadCheckerIssue": false, ], + "management": [ + "shared": false, + "orderHint": 8 + ], ], ], "schemes": [ @@ -993,6 +1314,9 @@ class SpecLoadingTests: XCTestCase { try expect(scheme.build.parallelizeBuild) == false try expect(scheme.build.buildImplicitDependencies) == false + try expect(scheme.build.runPostActionsOnFailure) == true + + try expect(scheme.run?.storeKitConfiguration) == "Configuration.storekit" let expectedTest = Scheme.Test( config: "debug", @@ -1009,6 +1333,9 @@ class SpecLoadingTests: XCTestCase { ] ) try expect(scheme.test) == expectedTest + + let expectedManagement = Scheme.Management(shared: false, orderHint: 8, isShown: nil) + try expect(scheme.management) == expectedManagement } $0.it("parses copy files on install") { @@ -1018,6 +1345,13 @@ class SpecLoadingTests: XCTestCase { try expect(target.onlyCopyFilesOnInstall) == true } + $0.it("parses put resources before Sources Build Phase") { + var targetSource = validTarget + targetSource["putResourcesBeforeSourcesBuildPhase"] = true + let target = try Target(name: "Embed Frameworks", jsonDictionary: targetSource) + try expect(target.putResourcesBeforeSourcesBuildPhase) == true + } + $0.it("parses settings") { let project = try Project(path: fixturePath + "settings_test.yml") let buildSettings: BuildSettings = ["SETTING": "value"] @@ -1050,8 +1384,10 @@ class SpecLoadingTests: XCTestCase { ["path": "script.sh"], ["script": "shell script\ndo thing", "name": "myscript", "inputFiles": ["file", "file2"], "outputFiles": ["file", "file2"], "shell": "bin/customshell", "runOnlyWhenInstalling": true], ["script": "shell script\ndo thing", "name": "myscript", "inputFiles": ["file", "file2"], "outputFiles": ["file", "file2"], "shell": "bin/customshell", "showEnvVars": false], + ["script": "shell script\ndo thing", "name": "myscript", "inputFiles": ["file", "file2"], "outputFiles": ["file", "file2"], "shell": "bin/customshell", "basedOnDependencyAnalysis": false], ["script": "shell script\nwith file lists", "name": "myscript", "inputFileLists": ["inputList.xcfilelist"], "outputFileLists": ["outputList.xcfilelist"], "shell": "bin/customshell", "runOnlyWhenInstalling": true], ["script": "shell script\nwith file lists", "name": "myscript", "inputFileLists": ["inputList.xcfilelist"], "outputFileLists": ["outputList.xcfilelist"], "shell": "bin/customshell", "showEnvVars": false], + ["script": "shell script\nwith file lists", "name": "myscript", "inputFileLists": ["inputList.xcfilelist"], "outputFileLists": ["outputList.xcfilelist"], "shell": "bin/customshell", "basedOnDependencyAnalysis": false], ] target["preBuildScripts"] = scripts target["postCompileScripts"] = scripts @@ -1059,10 +1395,12 @@ class SpecLoadingTests: XCTestCase { let expectedScripts = [ BuildScript(script: .path("script.sh")), - BuildScript(script: .script("shell script\ndo thing"), name: "myscript", inputFiles: ["file", "file2"], outputFiles: ["file", "file2"], shell: "bin/customshell", runOnlyWhenInstalling: true, showEnvVars: true), - BuildScript(script: .script("shell script\ndo thing"), name: "myscript", inputFiles: ["file", "file2"], outputFiles: ["file", "file2"], shell: "bin/customshell", runOnlyWhenInstalling: false, showEnvVars: false), - BuildScript(script: .script("shell script\nwith file lists"), name: "myscript", inputFileLists: ["inputList.xcfilelist"], outputFileLists: ["outputList.xcfilelist"], shell: "bin/customshell", runOnlyWhenInstalling: true, showEnvVars: true), - BuildScript(script: .script("shell script\nwith file lists"), name: "myscript", inputFileLists: ["inputList.xcfilelist"], outputFileLists: ["outputList.xcfilelist"], shell: "bin/customshell", runOnlyWhenInstalling: false, showEnvVars: false), + BuildScript(script: .script("shell script\ndo thing"), name: "myscript", inputFiles: ["file", "file2"], outputFiles: ["file", "file2"], shell: "bin/customshell", runOnlyWhenInstalling: true, showEnvVars: true, basedOnDependencyAnalysis: true), + BuildScript(script: .script("shell script\ndo thing"), name: "myscript", inputFiles: ["file", "file2"], outputFiles: ["file", "file2"], shell: "bin/customshell", runOnlyWhenInstalling: false, showEnvVars: false, basedOnDependencyAnalysis: true), + BuildScript(script: .script("shell script\ndo thing"), name: "myscript", inputFiles: ["file", "file2"], outputFiles: ["file", "file2"], shell: "bin/customshell", runOnlyWhenInstalling: false, showEnvVars: true, basedOnDependencyAnalysis: false), + BuildScript(script: .script("shell script\nwith file lists"), name: "myscript", inputFileLists: ["inputList.xcfilelist"], outputFileLists: ["outputList.xcfilelist"], shell: "bin/customshell", runOnlyWhenInstalling: true, showEnvVars: true, basedOnDependencyAnalysis: true), + BuildScript(script: .script("shell script\nwith file lists"), name: "myscript", inputFileLists: ["inputList.xcfilelist"], outputFileLists: ["outputList.xcfilelist"], shell: "bin/customshell", runOnlyWhenInstalling: false, showEnvVars: false, basedOnDependencyAnalysis: true), + BuildScript(script: .script("shell script\nwith file lists"), name: "myscript", inputFileLists: ["inputList.xcfilelist"], outputFileLists: ["outputList.xcfilelist"], shell: "bin/customshell", runOnlyWhenInstalling: false, showEnvVars: true, basedOnDependencyAnalysis: false), ] let parsedTarget = try Target(name: "test", jsonDictionary: target) @@ -1110,9 +1448,16 @@ class SpecLoadingTests: XCTestCase { watchOS: "3.0", macOS: "10.12.1" ), + fileTypes: ["abc": FileType( + file: false, + buildPhase: .sources, + attributes: ["a1", "a2"], + resourceTags: ["r1", "r2"], + compilerFlags: ["c1", "c2"])], findCarthageFrameworks: true, preGenCommand: "swiftgen", - postGenCommand: "pod install" + postGenCommand: "pod install", + schemePathPrefix: "../" ) let expected = Project(name: "test", options: options) let dictionary: [String: Any] = ["options": [ @@ -1125,6 +1470,14 @@ class SpecLoadingTests: XCTestCase { "findCarthageFrameworks": true, "preGenCommand": "swiftgen", "postGenCommand": "pod install", + "fileTypes": ["abc": [ + "file": false, + "buildPhase": "sources", + "attributes": ["a1", "a2"], + "resourceTags": ["r1", "r2"], + "compilerFlags": ["c1", "c2"], + ]], + "schemePathPrefix": "../", ]] let parsedSpec = try getProjectSpec(dictionary) try expect(parsedSpec) == expected @@ -1140,8 +1493,10 @@ class SpecLoadingTests: XCTestCase { "package6": .remote(url: "package.git", versionRequirement: .range(from: "1.2.0", to: "1.2.5")), "package7": .remote(url: "package.git", versionRequirement: .exact("1.2.2")), "package8": .remote(url: "package.git", versionRequirement: .upToNextMajorVersion("4.0.0-beta.5")), - "package9": .local(path: "package/package"), - "XcodeGen": .local(path: "../XcodeGen"), + "package9": .local(path: "package/package", group: nil, excludeFromProject: false), + "package10": .remote(url: "https://github.com/yonaskolb/XcodeGen", versionRequirement: .exact("1.2.2")), + "XcodeGen": .local(path: "../XcodeGen", group: nil, excludeFromProject: false), + "package11": .local(path: "../XcodeGen", group: "Packages/Feature", excludeFromProject: false), ], options: .init(localPackagesGroup: "MyPackages")) let dictionary: [String: Any] = [ @@ -1159,6 +1514,8 @@ class SpecLoadingTests: XCTestCase { "package7": ["url": "package.git", "version": "1.2.2"], "package8": ["url": "package.git", "majorVersion": "4.0.0-beta.5"], "package9": ["path": "package/package"], + "package10": ["github": "yonaskolb/XcodeGen", "exactVersion": "1.2.2"], + "package11": ["path": "../XcodeGen", "group": "Packages/Feature"], ], "localPackages": ["../XcodeGen"], ] @@ -1168,8 +1525,8 @@ class SpecLoadingTests: XCTestCase { $0.it("parses old local package format") { let project = Project(name: "spm", packages: [ - "XcodeGen": .local(path: "../XcodeGen"), - "Yams": .local(path: "Yams"), + "XcodeGen": .local(path: "../XcodeGen", group: nil, excludeFromProject: false), + "Yams": .local(path: "Yams", group: nil, excludeFromProject: false), ], options: .init(localPackagesGroup: "MyPackages")) let dictionary: [String: Any] = [ @@ -1182,6 +1539,64 @@ class SpecLoadingTests: XCTestCase { let parsedSpec = try getProjectSpec(dictionary) try expect(parsedSpec) == project } + + $0.it("parses TargetScheme storeKitConfiguration as string") { + var targetDictionary = validTarget + targetDictionary["scheme"] = [ + "storeKitConfiguration": "Configuration.storekit", + ] + + let target = try Target(name: "test", jsonDictionary: targetDictionary) + + let scheme = TargetScheme( + storeKitConfiguration: "Configuration.storekit" + ) + + try expect(target.scheme) == scheme + } + + $0.it("parses Scheme.Run storeKitConfiguration as string") { + let schemeDictionary: [String: Any] = [ + "build": [ + "targets": [:], + ], + "run": [ + "config": "debug", + "storeKitConfiguration": "Configuration.storekit", + ], + ] + let scheme = try Scheme(name: "Scheme", jsonDictionary: schemeDictionary) + + let runAction = Scheme.Run( + config: "debug", + storeKitConfiguration: "Configuration.storekit" + ) + + try expect(scheme.run) == runAction + } + + $0.it("parses buildToolPlugins") { + var target = validTarget + let buildToolPlugins: [[String: Any]] = [ + [ + "plugin": "FirstPlugin", + "package": "FirstPackage" + ], + [ + "plugin": "SecondPlugin", + "package": "SecondPackage" + ] + ] + target["buildToolPlugins"] = buildToolPlugins + + let expectedBuildToolPlugins = [ + BuildToolPlugin(plugin: "FirstPlugin", package: "FirstPackage"), + BuildToolPlugin(plugin: "SecondPlugin", package: "SecondPackage") + ] + + let parsedTarget = try Target(name: "test", jsonDictionary: target) + try expect(parsedTarget.buildToolPlugins) == expectedBuildToolPlugins + } } } @@ -1198,7 +1613,7 @@ class SpecLoadingTests: XCTestCase { $0.it("is an invalid package version") { for dictionary in invalidPackages { - try expect { _ = try SwiftPackage(jsonDictionary: dictionary) }.toThrow() + try expect(expression: { _ = try SwiftPackage(jsonDictionary: dictionary) }).toThrow() } } } @@ -1253,3 +1668,9 @@ private func expectTargetError(_ target: [String: Any], _ expectedError: SpecPar _ = try Target(name: "test", jsonDictionary: target) } } + +private func expectBreakpointError(_ breakpoint: [String: Any], _ expectedError: SpecParsingError, file: String = #file, line: Int = #line) throws { + try expectError(expectedError, file: file, line: line) { + _ = try Breakpoint(jsonDictionary: breakpoint) + } +} diff --git a/Tests/XcodeGenCoreTests/ArrayExtensionsTests.swift b/Tests/XcodeGenCoreTests/ArrayExtensionsTests.swift new file mode 100644 index 000000000..f15831477 --- /dev/null +++ b/Tests/XcodeGenCoreTests/ArrayExtensionsTests.swift @@ -0,0 +1,40 @@ +import XCTest +@testable import XcodeGenCore + +class ArrayExtensionsTests: XCTestCase { + + func testSearchingForFirstIndex() { + let array = SortedArray([1, 2, 3, 4 ,5]) + XCTAssertEqual(array.firstIndex(where: { $0 > 2 }), 2) + } + + func testIndexCannotBeFound() { + let array = SortedArray([1, 2, 3, 4, 5]) + XCTAssertEqual(array.firstIndex(where: { $0 > 10 }), nil) + } + + func testEmptyArray() { + let array = SortedArray([Int]()) + XCTAssertEqual(array.firstIndex(where: { $0 > 0 }), nil) + } + + func testSearchingReturnsFirstIndexWhenMultipleElementsHaveSameValue() { + let array = SortedArray([1, 2, 3, 3 ,3]) + XCTAssertEqual(array.firstIndex(where: { $0 == 3 }), 2) + } +} + + +class SortedArrayTests: XCTestCase { + + func testSortingOnInitialization() { + let array = [1, 5, 4, 2] + let sortedArray = SortedArray(array) + XCTAssertEqual([1, 2, 4, 5], sortedArray.value) + } + + func testEmpty() { + XCTAssertEqual([Int](), SortedArray([Int]()).value) + } + +} diff --git a/Tests/XcodeGenCoreTests/AtomicTests.swift b/Tests/XcodeGenCoreTests/AtomicTests.swift new file mode 100644 index 000000000..470aeca35 --- /dev/null +++ b/Tests/XcodeGenCoreTests/AtomicTests.swift @@ -0,0 +1,39 @@ +// +// AtomicTests.swift +// +// +// Created by Vladislav Lisianskii on 27.03.2022. +// + +import XCTest +@testable import XcodeGenCore + +final class AtomicTests: XCTestCase { + + @Atomic private var atomicDictionary = [String: Int]() + + func testSimultaneousWriteOrder() { + let group = DispatchGroup() + + for index in (0..<100) { + group.enter() + DispatchQueue.global().async { + self.$atomicDictionary.with { atomicDictionary in + atomicDictionary["\(index)"] = index + } + group.leave() + } + } + + group.notify(queue: .main, execute: { + var expectedValue = [String: Int]() + for index in (0..<100) { + expectedValue["\(index)"] = index + } + XCTAssertEqual( + self.atomicDictionary, + expectedValue + ) + }) + } +} diff --git a/Tests/CoreTests/GlobTests.swift b/Tests/XcodeGenCoreTests/GlobTests.swift similarity index 98% rename from Tests/CoreTests/GlobTests.swift rename to Tests/XcodeGenCoreTests/GlobTests.swift index 5b7e5e201..101479515 100644 --- a/Tests/CoreTests/GlobTests.swift +++ b/Tests/XcodeGenCoreTests/GlobTests.swift @@ -7,7 +7,7 @@ // Adapted from https://gist.github.com/efirestone/ce01ae109e08772647eb061b3bb387c3 import XCTest -@testable import Core +@testable import XcodeGenCore class GlobTests: XCTestCase { @@ -42,7 +42,7 @@ class GlobTests: XCTestCase { } private func newTmpDir() -> String { - var tmpDirTmpl = "/tmp/glob-test.XXXXX".cString(using: .utf8)! + var tmpDirTmpl = "/tmp/glob-test.XXXXXX".cString(using: .utf8)! return String(validatingUTF8: mkdtemp(&tmpDirTmpl))! } diff --git a/Tests/CoreTests/PathExtensionsTests.swift b/Tests/XcodeGenCoreTests/PathExtensionsTests.swift similarity index 96% rename from Tests/CoreTests/PathExtensionsTests.swift rename to Tests/XcodeGenCoreTests/PathExtensionsTests.swift index 83d2da399..d3bdc8b7e 100644 --- a/Tests/CoreTests/PathExtensionsTests.swift +++ b/Tests/XcodeGenCoreTests/PathExtensionsTests.swift @@ -1,7 +1,7 @@ import Spectre import PathKit import XCTest -import Core +import XcodeGenCore import TestSupport class PathExtensionsTests: XCTestCase { @@ -48,6 +48,7 @@ class PathExtensionsTests: XCTestCase { try expect(relativePath(to: "/a/../../b", from: "/b")) == "." try expect(relativePath(to: "a/..", from: "a")) == ".." try expect(relativePath(to: "a/../b", from: "b")) == "." + try expect(relativePath(to: "/a/c", from: "/a/b/c")) == "../../c" } $0.it("backtracks on a non-normalized base path") { diff --git a/Tests/XcodeGenKitTests/BreakpointGeneratorTests.swift b/Tests/XcodeGenKitTests/BreakpointGeneratorTests.swift new file mode 100644 index 000000000..a1d3152a3 --- /dev/null +++ b/Tests/XcodeGenKitTests/BreakpointGeneratorTests.swift @@ -0,0 +1,20 @@ +import ProjectSpec +import Spectre +import TestSupport +import XCTest + +class BreakpointGeneratorTests: XCTestCase { + + func testBreakpoints() { + describe { + + $0.it("generates breakpoint") { + let breakpoint = Breakpoint(type: .exception(.init())) + let project = Project(basePath: "", name: "test", targets: [], breakpoints: [breakpoint]) + let xcodeProject = try project.generateXcodeProject() + let xcbreakpoint = try unwrap(xcodeProject.sharedData?.breakpoints?.breakpoints.first) + try expect(xcbreakpoint.breakpointExtensionID.rawValue) == "Xcode.Breakpoint.ExceptionBreakpoint" + } + } + } +} diff --git a/Tests/XcodeGenKitTests/CarthageDependencyResolverTests.swift b/Tests/XcodeGenKitTests/CarthageDependencyResolverTests.swift index 935c8842a..0e160ea99 100644 --- a/Tests/XcodeGenKitTests/CarthageDependencyResolverTests.swift +++ b/Tests/XcodeGenKitTests/CarthageDependencyResolverTests.swift @@ -146,6 +146,29 @@ class CarthageDependencyResolverTests: XCTestCase { try expect(related) == expectedDependencies } + + $0.it("skips dependencies which are not embedded") { + let resolver = CarthageDependencyResolver(project: makeTestProject()) + + let target = Target(name: "1", type: .application, platform: .iOS, dependencies: [ + Dependency(type: .carthage(findFrameworks: false, linkType: .dynamic), reference: dependencyFixtureName, embed: false, link: false) + ]) + try expect(resolver.dependencies(for: target)) == [] + } + + $0.it("skips dependencies nested in targets which are not embedded") { + let nestedTarget = Target(name: "1", type: .framework, platform: .iOS, dependencies: [ + Dependency(type: .carthage(findFrameworks: false, linkType: .dynamic), reference: dependencyFixtureName) + ]) + + let resolver = CarthageDependencyResolver(project: makeTestProject(with: [nestedTarget])) + + let target = Target(name: "2", type: .application, platform: .iOS, dependencies: [ + Dependency(type: .target, reference: "1", embed: false, link: false) + ]) + try expect(resolver.dependencies(for: target)) == [] + + } } } diff --git a/Tests/XcodeGenKitTests/GraphVizGeneratorTests.swift b/Tests/XcodeGenKitTests/GraphVizGeneratorTests.swift deleted file mode 100644 index 7bf3597a1..000000000 --- a/Tests/XcodeGenKitTests/GraphVizGeneratorTests.swift +++ /dev/null @@ -1,104 +0,0 @@ -import ProjectSpec -import Spectre -@testable import XcodeGenKit -import XCTest - -private let app = Target( - name: "MyApp", - type: .application, - platform: .iOS, - settings: Settings(buildSettings: ["SETTING_1": "VALUE"]), - dependencies: [ - Dependency(type: .target, reference: "MyInternalFramework"), - Dependency(type: .bundle, reference: "Resources"), - Dependency(type: .carthage(findFrameworks: true, linkType: .static), reference: "MyStaticFramework"), - Dependency(type: .carthage(findFrameworks: true, linkType: .dynamic), reference: "MyDynamicFramework"), - Dependency(type: .framework, reference: "MyExternalFramework"), - Dependency(type: .package(product: "MyPackage"), reference: "MyPackage"), - Dependency(type: .sdk(root: "MySDK"), reference: "MySDK"), - ] -) - -private let framework = Target( - name: "MyFramework", - type: .framework, - platform: .iOS, - settings: Settings(buildSettings: ["SETTING_2": "VALUE"]) -) - -private let uiTest = Target( - name: "MyAppUITests", - type: .uiTestBundle, - platform: .iOS, - settings: Settings(buildSettings: ["SETTING_3": "VALUE"]), - dependencies: [Dependency(type: .target, reference: "MyApp")] -) - -private let targets = [app, framework, uiTest] - -class GraphVizGeneratorTests: XCTestCase { - - func testGraphOutput() throws { - describe { - let graph = GraphVizGenerator().generateGraph(targets: targets) - $0.it("generates the expected number of nodes") { - try expect(graph.nodes.count) == 16 - } - $0.it("generates box nodes") { - try expect(graph.nodes.filter { $0.shape == .box }.count) == 16 - } - $0.it("generates the expected carthage nodes") { - try expect(graph.nodes.filter { $0.label?.contains("[carthage]") ?? false }.count) == 2 - } - $0.it("generates the expected sdk nodes") { - try expect(graph.nodes.filter { $0.label?.contains("[sdk]") ?? false }.count) == 1 - } - $0.it("generates the expected Framework nodes") { - try expect(graph.nodes.filter { $0.label?.contains("[framework]") ?? false }.count) == 1 - } - $0.it("generates the expected package nodes") { - try expect(graph.nodes.filter { $0.label?.contains("[package]") ?? false }.count) == 1 - } - $0.it("generates the expected bundle nodes") { - try expect(graph.nodes.filter { $0.label?.contains("[bundle]") ?? false }.count) == 1 - } - $0.it("generates the expected edges") { - try expect(graph.edges.count) == 8 - } - $0.it("generates dashed edges") { - try expect(graph.edges.filter { $0.style == .dashed }.count) == 8 - } - $0.it("generates the expected output") { - let output = GraphVizGenerator().generateModuleGraphViz(targets: targets) - try expect(output) == """ - digraph { - MyApp [shape=box] - MyInternalFramework [label=MyInternalFramework shape=box] - MyApp [shape=box] - Resources [label="[bundle]\\nResources" shape=box] - MyApp [shape=box] - MyStaticFramework [label="[carthage]\\nMyStaticFramework" shape=box] - MyApp [shape=box] - MyDynamicFramework [label="[carthage]\\nMyDynamicFramework" shape=box] - MyApp [shape=box] - MyExternalFramework [label="[framework]\\nMyExternalFramework" shape=box] - MyApp [shape=box] - MyPackage [label="[package]\\nMyPackage" shape=box] - MyApp [shape=box] - MySDK [label="[sdk]\\nMySDK" shape=box] - MyAppUITests [shape=box] - MyApp [label=MyApp shape=box] - MyApp -> MyInternalFramework [style=dashed] - MyApp -> Resources [style=dashed] - MyApp -> MyStaticFramework [style=dashed] - MyApp -> MyDynamicFramework [style=dashed] - MyApp -> MyExternalFramework [style=dashed] - MyApp -> MyPackage [style=dashed] - MyApp -> MySDK [style=dashed] - MyAppUITests -> MyApp [style=dashed] - } - """ - } - } - } -} diff --git a/Tests/XcodeGenKitTests/PBXProjGeneratorTests.swift b/Tests/XcodeGenKitTests/PBXProjGeneratorTests.swift index 9be66e26d..31873cdcf 100644 --- a/Tests/XcodeGenKitTests/PBXProjGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/PBXProjGeneratorTests.swift @@ -15,7 +15,7 @@ extension Project { try self.validate() } let generator = ProjectGenerator(project: self) - return try generator.generateXcodeProject() + return try generator.generateXcodeProject(userName: "someUser") } } @@ -259,6 +259,249 @@ class PBXProjGeneratorTests: XCTestCase { .map { $0.nameOrPath } try expect(screenGroups) == ["mainScreen1.swift", "mainScreen2.swift", "View", "Presenter", "Interactor", "Entities", "Assembly"] } + + $0.it("sorts SPM packages") { + var options = SpecOptions() + options.groupSortPosition = .top + options.groupOrdering = [ + GroupOrdering( + order: [ + "Sources", + "Resources", + "Tests", + "Packages", + "Support files", + "Configurations", + ] + ), + GroupOrdering( + pattern: "Packages", + order: [ + "FeatureA", + "FeatureB", + "Common", + ] + ), + ] + + let directories = """ + Configurations: + - file.swift + Resources: + - file.swift + Sources: + - MainScreen: + - mainScreen1.swift + - mainScreen2.swift + - Assembly: + - file.swift + - Entities: + - file.swift + - Interactor: + - file.swift + - Presenter: + - file.swift + - View: + - file.swift + Support files: + - file.swift + Packages: + - Common: + - Package.swift + - FeatureA: + - Package.swift + - FeatureB: + - Package.swift + Tests: + - file.swift + UITests: + - file.swift + """ + try createDirectories(directories) + + let target = Target(name: "Test", type: .application, platform: .iOS, sources: ["Configurations", "Resources", "Sources", "Support files", "Tests", "UITests"]) + let project = Project( + basePath: directoryPath, + name: "Test", + targets: [target], + packages: [ + "Common": .local(path: "Packages/Common", group: nil, excludeFromProject: false), + "FeatureA": .local(path: "Packages/FeatureA", group: nil, excludeFromProject: false), + "FeatureB": .local(path: "Packages/FeatureB", group: nil, excludeFromProject: false), + ], + options: options + ) + let projGenerator = PBXProjGenerator(project: project) + + let pbxProj = try project.generatePbxProj() + let group = try pbxProj.getMainGroup() + + projGenerator.setupGroupOrdering(group: group) + + let mainGroups = group.children.map { $0.nameOrPath } + try expect(mainGroups) == ["Sources", "Resources", "Tests", "Packages", "Support files", "Configurations", "UITests", "Products"] + + let packages = group.children + .first { $0.nameOrPath == "Packages" } + .flatMap { $0 as? PBXGroup }? + .children + .map(\.nameOrPath) + + try expect(packages) == ["FeatureA", "FeatureB", "Common"] + } + } + } + + func testDefaultLastUpgradeCheckWhenUserDidSpecifyInvalidValue() throws { + let lastUpgradeKey = "LastUpgradeCheck" + let attributes: [String: Any] = [lastUpgradeKey: 1234] + let project = Project(name: "Test", attributes: attributes) + let projGenerator = PBXProjGenerator(project: project) + + let pbxProj = try projGenerator.generate() + + for pbxProject in pbxProj.projects { + XCTAssertEqual(pbxProject.attributes[lastUpgradeKey] as? String, project.xcodeVersion) + } + } + + func testOverrideLastUpgradeCheckWhenUserDidSpecifyValue() throws { + let lastUpgradeKey = "LastUpgradeCheck" + let lastUpgradeValue = "1234" + let attributes: [String: Any] = [lastUpgradeKey: lastUpgradeValue] + let project = Project(name: "Test", attributes: attributes) + let projGenerator = PBXProjGenerator(project: project) + + let pbxProj = try projGenerator.generate() + + for pbxProject in pbxProj.projects { + XCTAssertEqual(pbxProject.attributes[lastUpgradeKey] as? String, lastUpgradeValue) + } + } + + func testDefaultLastUpgradeCheckWhenUserDidNotSpecifyValue() throws { + let lastUpgradeKey = "LastUpgradeCheck" + let project = Project(name: "Test") + let projGenerator = PBXProjGenerator(project: project) + + let pbxProj = try projGenerator.generate() + + for pbxProject in pbxProj.projects { + XCTAssertEqual(pbxProject.attributes[lastUpgradeKey] as? String, project.xcodeVersion) + } + } + + func testPlatformDependencies() { + describe { + let directoryPath = Path("TestDirectory") + + func createDirectories(_ directories: String) throws { + let yaml = try Yams.load(yaml: directories)! + + func getFiles(_ file: Any, path: Path) -> [Path] { + if let array = file as? [Any] { + return array.flatMap { getFiles($0, path: path) } + } else if let string = file as? String { + return [path + string] + } else if let dictionary = file as? [String: Any] { + var array: [Path] = [] + for (key, value) in dictionary { + array += getFiles(value, path: path + key) + } + return array + } else { + return [] + } + } + + let files = getFiles(yaml, path: directoryPath).filter { $0.extension != nil } + for file in files { + try file.parent().mkpath() + try file.write("") + } + } + + func removeDirectories() { + try? directoryPath.delete() + } + + $0.before { + removeDirectories() + } + + $0.after { + removeDirectories() + } + + $0.it("setups target with different dependencies") { + let directories = """ + Sources: + - MainScreen: + - Entities: + - file.swift + """ + try createDirectories(directories) + let target1 = Target(name: "TestAll", type: .application, platform: .iOS, sources: ["Sources"]) + let target2 = Target(name: "TestiOS", type: .application, platform: .iOS, sources: ["Sources"]) + let target3 = Target(name: "TestmacOS", type: .application, platform: .iOS, sources: ["Sources"]) + let dependency1 = Dependency(type: .target, reference: "TestAll", platformFilter: .all) + let dependency2 = Dependency(type: .target, reference: "TestiOS", platformFilter: .iOS) + let dependency3 = Dependency(type: .target, reference: "TestmacOS", platformFilter: .macOS) + let dependency4 = Dependency(type: .package(products: ["Swinject"]), reference: "Swinject", platformFilter: .iOS) + let target = Target(name: "Test", type: .application, platform: .iOS, sources: ["Sources"], dependencies: [dependency1, dependency2, dependency3, dependency4]) + let swinjectPackage = SwiftPackage.remote(url: "https://github.com/Swinject/Swinject", versionRequirement: .exact("2.8.0")) + let project = Project(basePath: directoryPath, name: "Test", targets: [target, target1, target2, target3], packages: ["Swinject": swinjectPackage]) + + let pbxProj = try project.generatePbxProj() + + let targets = pbxProj.projects.first?.targets + let testTarget = pbxProj.projects.first?.targets.first(where: { $0.name == "Test" }) + let testTargetDependencies = testTarget?.dependencies + try expect(targets?.count) == 4 + try expect(testTargetDependencies?.count) == 3 + try expect(testTargetDependencies?[0].platformFilter).beNil() + try expect(testTargetDependencies?[1].platformFilter) == "ios" + try expect(testTargetDependencies?[2].platformFilter) == "maccatalyst" + try expect(testTarget?.frameworksBuildPhase()?.files?.count) == 1 + try expect(testTarget?.frameworksBuildPhase()?.files?[0].platformFilter) == "ios" + } + + $0.it("places resources before sources buildPhase") { + let directories = """ + Sources: + - MainScreen: + - Entities: + - file.swift + - image.jpg + """ + try createDirectories(directories) + let target1 = Target( + name: "TestAll", + type: .application, + platform: .iOS, + sources: ["Sources"], + putResourcesBeforeSourcesBuildPhase: true + ) + let target2 = Target( + name: "TestiOS", + type: .application, + platform: .iOS, + sources: ["Sources"], + putResourcesBeforeSourcesBuildPhase: false + ) + + let project = Project(basePath: directoryPath, name: "Test", targets: [target1, target2]) + + let pbxProj = try project.generatePbxProj() + + let targets = pbxProj.projects.first?.targets + try expect(targets?.count) == 2 + try expect(targets?.first?.buildPhases.first).to.beOfType(PBXResourcesBuildPhase.self) + try expect(targets?.first?.buildPhases.last).to.beOfType(PBXSourcesBuildPhase.self) + + try expect(targets?.last?.buildPhases.first).to.beOfType(PBXSourcesBuildPhase.self) + try expect(targets?.last?.buildPhases.last).to.beOfType(PBXResourcesBuildPhase.self) + } } } diff --git a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift index b48e2b964..7a42dcb9d 100644 --- a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift @@ -275,7 +275,8 @@ class ProjectGeneratorTests: XCTestCase { } } - func testTargets() { + func testTargets() throws { + try skipIfNecessary() describe { let project = Project(name: "test", targets: targets) @@ -335,6 +336,181 @@ class ProjectGeneratorTests: XCTestCase { try expect(targetConfig.buildSettings["WATCHOS_DEPLOYMENT_TARGET"] as? String) == "2.0" try expect(targetConfig.buildSettings["TVOS_DEPLOYMENT_TARGET"]).beNil() } + + $0.it("supportedDestinations merges settings - iOS, tvOS") { + let target = Target(name: "Target", type: .application, platform: .auto, supportedDestinations: [.tvOS, .iOS]) + let project = Project(name: "", targets: [target]) + + let pbxProject = try project.generatePbxProj() + let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) + + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "iphoneos iphonesimulator appletvos appletvsimulator" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "1,2,3" + try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"] as? Bool) == false + try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true + try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true + + try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "@executable_path/Frameworks"] + try expect(targetConfig1.buildSettings["SDKROOT"] as? String) == "auto" + try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"] as? String) == "AppIcon" + try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"] as? String) == "iPhone Developer" + } + + $0.it("supportedDestinations merges settings - iOS, visionOS") { + let target = Target(name: "Target", type: .application, platform: .auto, supportedDestinations: [.visionOS, .iOS]) + let project = Project(name: "", targets: [target]) + + let pbxProject = try project.generatePbxProj() + let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) + + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "iphoneos iphonesimulator xros xrsimulator" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "1,2,7" + try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"] as? Bool) == false + try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true + try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == false + + try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "@executable_path/Frameworks"] + try expect(targetConfig1.buildSettings["SDKROOT"] as? String) == "auto" + try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"] as? String) == "AppIcon" + try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"] as? String) == "iPhone Developer" + } + + $0.it("supportedDestinations merges settings - iOS, tvOS, macOS") { + let target = Target(name: "Target", type: .application, platform: .auto, supportedDestinations: [.iOS, .tvOS, .macOS]) + let project = Project(name: "", targets: [target]) + + let pbxProject = try project.generatePbxProj() + let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) + + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "iphoneos iphonesimulator appletvos appletvsimulator macosx" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "1,2,3" + try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"] as? Bool) == false + try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == false + try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true + + try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "@executable_path/Frameworks"] + try expect(targetConfig1.buildSettings["SDKROOT"] as? String) == "auto" + try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"] as? String) == "AppIcon" + try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"] as? String) == "iPhone Developer" + } + + $0.it("supportedDestinations merges settings - iOS, tvOS, macCatalyst") { + let target = Target(name: "Target", type: .application, platform: .auto, supportedDestinations: [.iOS, .tvOS, .macCatalyst]) + let project = Project(name: "", targets: [target]) + + let pbxProject = try project.generatePbxProj() + let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) + + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "iphoneos iphonesimulator appletvos appletvsimulator" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "1,2,3" + try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"] as? Bool) == true + try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == false + try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true + + try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "@executable_path/Frameworks"] + try expect(targetConfig1.buildSettings["SDKROOT"] as? String) == "auto" + try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"] as? String) == "AppIcon" + try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"] as? String) == "iPhone Developer" + } + + $0.it("supportedDestinations merges settings - iOS, macOS") { + let target = Target(name: "Target", type: .application, platform: .auto, supportedDestinations: [.iOS, .macOS]) + let project = Project(name: "", targets: [target]) + + let pbxProject = try project.generatePbxProj() + let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) + + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "iphoneos iphonesimulator macosx" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "1,2" + try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"] as? Bool) == false + try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == false + try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true + + try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "@executable_path/Frameworks"] + try expect(targetConfig1.buildSettings["SDKROOT"] as? String) == "auto" + try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"] as? String) == "AppIcon" + try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"] as? String) == "iPhone Developer" + } + + $0.it("supportedDestinations merges settings - tvOS, macOS") { + let target = Target(name: "Target", type: .application, platform: .auto, supportedDestinations: [.tvOS, .macOS]) + let project = Project(name: "", targets: [target]) + + let pbxProject = try project.generatePbxProj() + let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) + + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "appletvos appletvsimulator macosx" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "3" + try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"] as? Bool) == false + try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == false + + try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "@executable_path/Frameworks"] + try expect(targetConfig1.buildSettings["SDKROOT"] as? String) == "auto" + try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"] as? String) == "App Icon & Top Shelf Image" + try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME"] as? String) == "LaunchImage" + } + + $0.it("supportedDestinations merges settings - visionOS, macOS") { + let target = Target(name: "Target", type: .application, platform: .auto, supportedDestinations: [.visionOS, .macOS]) + let project = Project(name: "", targets: [target]) + + let pbxProject = try project.generatePbxProj() + let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) + + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "xros xrsimulator macosx" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "7" + try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"] as? Bool) == false + try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == false + try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == false + + try expect(targetConfig1.buildSettings["SDKROOT"] as? String) == "auto" + try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"] as? String) == "AppIcon" + } + + $0.it("supportedDestinations merges settings - iOS, macCatalyst") { + let target = Target(name: "Target", type: .application, platform: .auto, supportedDestinations: [.iOS, .macCatalyst]) + let project = Project(name: "", targets: [target]) + + let pbxProject = try project.generatePbxProj() + let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) + + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "iphoneos iphonesimulator" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "1,2" + try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"] as? Bool) == true + try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == false + try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true + + try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "@executable_path/Frameworks"] + try expect(targetConfig1.buildSettings["SDKROOT"] as? String) == "auto" + try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"] as? String) == "AppIcon" + try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"] as? String) == "iPhone Developer" + } + + $0.it("supportedDestinations merges settings - iOS, watchOS (framework)") { + let target = Target(name: "Target", type: .framework, platform: .auto, supportedDestinations: [.iOS, .watchOS]) + let project = Project(name: "", targets: [target]) + + let pbxProject = try project.generatePbxProj() + let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) + + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "iphoneos iphonesimulator watchos watchsimulator" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "1,2,4" + try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"] as? Bool) == false + try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true + try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true + } + + $0.it("supportedDestinations merges settings - visionOS, watchOS (framework)") { + let target = Target(name: "Target", type: .framework, platform: .auto, supportedDestinations: [.visionOS, .watchOS]) + let project = Project(name: "", targets: [target]) + + let pbxProject = try project.generatePbxProj() + let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) + + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "watchos watchsimulator xros xrsimulator" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "4,7" + try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == false + } $0.it("generates dependencies") { let pbxProject = try project.generatePbxProj() @@ -355,7 +531,7 @@ class ProjectGeneratorTests: XCTestCase { let project = try! Project(path: fixturePath + "TestProject/AnotherProject/project.yml") let generator = ProjectGenerator(project: project) let writer = FileWriter(project: project) - let xcodeProject = try! generator.generateXcodeProject() + let xcodeProject = try! generator.generateXcodeProject(userName: "someUser") try! writer.writeXcodeProject(xcodeProject) try! writer.writePlists() subproject = xcodeProject.pbxproj @@ -555,9 +731,12 @@ class ProjectGeneratorTests: XCTestCase { Dependency(type: .target, reference: resourceBundle.name), Dependency(type: .framework, reference: "FrameworkC.framework"), Dependency(type: .carthage(findFrameworks: false, linkType: .dynamic), reference: "CarthageA"), - Dependency(type: .package(product: "RxSwift"), reference: "RxSwift"), - Dependency(type: .package(product: "RxCocoa"), reference: "RxSwift"), - Dependency(type: .package(product: "RxRelay"), reference: "RxSwift"), + Dependency(type: .package(products: ["RxSwift"]), reference: "RxSwift"), + Dependency(type: .package(products: ["RxCocoa"]), reference: "RxSwift"), + Dependency(type: .package(products: ["RxRelay"]), reference: "RxSwift"), + + // Validate - Do not link package + Dependency(type: .package(products: ["KeychainAccess"]), reference: "KeychainAccess", link: false), // Statically linked, so don't embed into test Dependency(type: .target, reference: staticLibrary.name), @@ -679,25 +858,37 @@ class ProjectGeneratorTests: XCTestCase { iosFrameworkB.filename, ]) + let XCTestPath = "Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework" + let GXToolsPath = "Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/GXTools.framework" + let XCTAutomationPath = "Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/XCTAutomationSupport.framework" let stickerPack = Target( name: "MyStickerApp", type: .stickerPack, platform: .iOS, dependencies: [ Dependency(type: .sdk(root: nil), reference: "NotificationCenter.framework"), - Dependency(type: .sdk(root: "DEVELOPER_DIR"), reference: "Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework"), + Dependency(type: .sdk(root: "DEVELOPER_DIR"), reference: XCTestPath), + Dependency(type: .sdk(root: "DEVELOPER_DIR"), reference: GXToolsPath, embed: true), + Dependency(type: .sdk(root: "DEVELOPER_DIR"), reference: XCTAutomationPath, embed: true, codeSign: true), ] ) expectedResourceFiles[stickerPack.name] = nil expectedLinkedFiles[stickerPack.name] = Set([ "XCTest.framework", "NotificationCenter.framework", + "GXTools.framework", + "XCTAutomationSupport.framework" + ]) + expectedEmbeddedFrameworks[stickerPack.name] = Set([ + "GXTools.framework", + "XCTAutomationSupport.framework" ]) let targets = [app, iosFrameworkZ, iosFrameworkX, staticLibrary, resourceBundle, iosFrameworkA, iosFrameworkB, appTest, appTestWithoutTransitive, stickerPack] let packages: [String: SwiftPackage] = [ "RxSwift": .remote(url: "https://github.com/ReactiveX/RxSwift", versionRequirement: .upToNextMajorVersion("5.1.1")), + "KeychainAccess": .remote(url: "https://github.com/kishikawakatsumi/KeychainAccess", versionRequirement: .upToNextMajorVersion("4.2.0")) ] let project = Project( @@ -771,6 +962,102 @@ class ProjectGeneratorTests: XCTestCase { try expect(copyFilesPhases.count) == expectedCopyFilesPhasesCount } } + + $0.it("ensures static frameworks are not embedded by default") { + + let app = Target( + name: "App", + type: .application, + platform: .iOS, + dependencies: [ + Dependency(type: .target, reference: "DynamicFramework"), + Dependency(type: .target, reference: "DynamicFrameworkNotEmbedded", embed: false), + Dependency(type: .target, reference: "StaticFramework"), + Dependency(type: .target, reference: "StaticFrameworkExplicitlyEmbedded", embed: true), + Dependency(type: .target, reference: "StaticFramework2"), + Dependency(type: .target, reference: "StaticFramework2ExplicitlyEmbedded", embed: true), + Dependency(type: .target, reference: "StaticLibrary"), + ] + ) + + let targets = [ + app, + Target( + name: "DynamicFramework", + type: .framework, + platform: .iOS + ), + Target( + name: "DynamicFrameworkNotEmbedded", + type: .framework, + platform: .iOS + ), + Target( + name: "StaticFramework", + type: .framework, + platform: .iOS, + settings: Settings(buildSettings: ["MACH_O_TYPE": "staticlib"]) + ), + Target( + name: "StaticFrameworkExplicitlyEmbedded", + type: .framework, + platform: .iOS, + settings: Settings(buildSettings: ["MACH_O_TYPE": "staticlib"]) + ), + Target( + name: "StaticFramework2", + type: .staticFramework, + platform: .iOS + ), + Target( + name: "StaticFramework2ExplicitlyEmbedded", + type: .staticFramework, + platform: .iOS + ), + Target( + name: "StaticLibrary", + type: .staticLibrary, + platform: .iOS + ), + ] + + let expectedLinkedFiles = Set([ + "DynamicFramework.framework", + "DynamicFrameworkNotEmbedded.framework", + "StaticFramework.framework", + "StaticFrameworkExplicitlyEmbedded.framework", + "StaticFramework2.framework", + "StaticFramework2ExplicitlyEmbedded.framework", + "libStaticLibrary.a", + ]) + + let expectedEmbeddedFrameworks = Set([ + "DynamicFramework.framework", + "StaticFrameworkExplicitlyEmbedded.framework", + "StaticFramework2ExplicitlyEmbedded.framework" + ]) + + let project = Project( + name: "test", + targets: targets + ) + let pbxProject = try project.generatePbxProj() + + let appTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name })) + let buildPhases = appTarget.buildPhases + let frameworkPhases = pbxProject.frameworksBuildPhases.filter { buildPhases.contains($0) } + let copyFilesPhases = pbxProject.copyFilesBuildPhases.filter { buildPhases.contains($0) } + let embedFrameworkPhase = copyFilesPhases.first { $0.dstSubfolderSpec == .frameworks } + + // Ensure all targets are linked + let linkFrameworks = (frameworkPhases[0].files ?? []).compactMap { $0.file?.nameOrPath } + let linkPackages = (frameworkPhases[0].files ?? []).compactMap { $0.product?.productName } + try expect(Set(linkFrameworks + linkPackages)) == expectedLinkedFiles + + // Ensure only dynamic frameworks are embedded (unless there's an explicit override) + let embeddedFrameworks = Set((embedFrameworkPhase?.files ?? []).compactMap { $0.file?.nameOrPath }) + try expect(embeddedFrameworks) == expectedEmbeddedFrameworks + } $0.it("copies files only on install in the Embed Frameworks step") { let app = Target( @@ -790,16 +1077,91 @@ class ProjectGeneratorTests: XCTestCase { let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name })) let buildPhases = nativeTarget.buildPhases - let embedFrameworkPhase = pbxProject + let embedFrameworksPhase = pbxProject .copyFilesBuildPhases .filter { buildPhases.contains($0) } .first { $0.dstSubfolderSpec == .frameworks } - let phase = try unwrap(embedFrameworkPhase) - try expect(phase.buildActionMask) == 8 + let phase = try unwrap(embedFrameworksPhase) + try expect(phase.buildActionMask) == PBXProjGenerator.copyFilesActionMask + try expect(phase.runOnlyForDeploymentPostprocessing) == true + } + + $0.it("copies files only on install in the Embed App Extensions step") { + let appExtension = Target( + name: "AppExtension", + type: .appExtension, + platform: .tvOS + ) + + let app = Target( + name: "App", + type: .application, + platform: .tvOS, + dependencies: [ + Dependency(type: .target, reference: "AppExtension") + ], + onlyCopyFilesOnInstall: true + ) + + let project = Project(name: "test", targets: [app, appExtension]) + let pbxProject = try project.generatePbxProj() + let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name })) + let buildPhases = nativeTarget.buildPhases + + let embedAppExtensionsPhase = pbxProject + .copyFilesBuildPhases + .filter { buildPhases.contains($0) } + .first { $0.dstSubfolderSpec == .plugins } + + let phase = try unwrap(embedAppExtensionsPhase) + try expect(phase.buildActionMask) == PBXProjGenerator.copyFilesActionMask try expect(phase.runOnlyForDeploymentPostprocessing) == true } + $0.it("copies files only on install in the Embed Frameworks and Embed App Extensions steps") { + let appExtension = Target( + name: "AppExtension", + type: .appExtension, + platform: .tvOS + ) + + let app = Target( + name: "App", + type: .application, + platform: .tvOS, + dependencies: [ + Dependency(type: .target, reference: "AppExtension"), + Dependency(type: .framework, reference: "FrameworkA.framework"), + Dependency(type: .framework, reference: "FrameworkB.framework", embed: false), + ], + onlyCopyFilesOnInstall: true + ) + + let project = Project(name: "test", targets: [app, appExtension]) + let pbxProject = try project.generatePbxProj() + let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name })) + let buildPhases = nativeTarget.buildPhases + + let embedFrameworksPhase = pbxProject + .copyFilesBuildPhases + .filter { buildPhases.contains($0) } + .first { $0.dstSubfolderSpec == .frameworks } + + let embedFrameworksPhaseValue = try unwrap(embedFrameworksPhase) + try expect(embedFrameworksPhaseValue.buildActionMask) == PBXProjGenerator.copyFilesActionMask + try expect(embedFrameworksPhaseValue.runOnlyForDeploymentPostprocessing) == true + + let embedAppExtensionsPhase = pbxProject + .copyFilesBuildPhases + .filter { buildPhases.contains($0) } + .first { $0.dstSubfolderSpec == .plugins } + + let embedAppExtensionsPhaseValue = try unwrap(embedAppExtensionsPhase) + try expect(embedAppExtensionsPhaseValue.buildActionMask) == PBXProjGenerator.copyFilesActionMask + try expect(embedAppExtensionsPhaseValue.runOnlyForDeploymentPostprocessing) == true + } + $0.it("sets -ObjC for targets that depend on requiresObjCLinking targets") { let requiresObjCLinking = Target( name: "requiresObjCLinking", @@ -880,7 +1242,108 @@ class ProjectGeneratorTests: XCTestCase { try expect(app2OtherLinkerSettings.contains("-ObjC")) == false try expect(app3OtherLinkerSettings.contains("-ObjC")) == true } - + + $0.it("filter sources with inferDestinationFiltersByPath") { + let sourceFiles = TargetSource(path: "App_supportedDestinations/TestResources", inferDestinationFiltersByPath: true) + + let target = Target( + name: "test", + type: .application, + platform: .auto, + sources: [sourceFiles], + dependencies: [] + ) + + let project = Project( + basePath: fixturePath + "TestProject", + name: "test", + targets: [target] + ) + + let pbxProject = try project.generatePbxProj() + let buildFiles = pbxProject.buildFiles + + try expect(buildFiles.count) == 8 + + for buildFile in buildFiles { + let name = buildFile.file?.nameOrPath + + if buildFile.platformFilters == [SupportedDestination.iOS.string] && + (name == "File_ios.swift" || name == "File_A.swift") { + continue + } else if buildFile.platformFilters == [SupportedDestination.tvOS.string] && + (name == "File_tvOs.swift" || name == "File_B.swift") { + continue + } else if buildFile.platformFilters == [SupportedDestination.macOS.string] && + (name == "File_macOS.swift" || name == "File_C.swift") { + continue + } else if buildFile.platformFilters == [SupportedDestination.macCatalyst.string] && + (name == "File_MACCATALYST.swift" || name == "File_D.swift") { + continue + } + + throw failure("Unexpected source file / destinationFilters") + } + } + + $0.it("filter sources with destinationFilters") { + let sourceFile1 = TargetSource(path: "App_supportedDestinations/TestResources/iOs", + destinationFilters: [.iOS]) + let sourceFile2 = TargetSource(path: "App_supportedDestinations/TestResources/TVOS", + destinationFilters: [.tvOS]) + let sourceFile3 = TargetSource(path: "App_supportedDestinations/TestResources/macos", + destinationFilters: [.macOS, .macCatalyst]) + let sourceFile4 = TargetSource(path: "App_supportedDestinations/TestResources/macCatalyst", + destinationFilters: [.macOS, .macCatalyst]) + let sourceFile5 = TargetSource(path: "App_supportedDestinations/TestResources/File_ios.swift", + destinationFilters: [.iOS]) + let sourceFile6 = TargetSource(path: "App_supportedDestinations/TestResources/File_tvOs.swift", + destinationFilters: [.tvOS]) + let sourceFile7 = TargetSource(path: "App_supportedDestinations/TestResources/File_macOS.swift", + destinationFilters: [.macOS, .macCatalyst]) + let sourceFile8 = TargetSource(path: "App_supportedDestinations/TestResources/File_MACCATALYST.swift", + destinationFilters: [.macOS, .macCatalyst]) + + let target = Target( + name: "test", + type: .application, + platform: .auto, + sources: [sourceFile1, sourceFile2, sourceFile3, sourceFile4, sourceFile5, sourceFile6, sourceFile7, sourceFile8], + dependencies: [] + ) + + let project = Project( + basePath: fixturePath + "TestProject", + name: "test", + targets: [target] + ) + + let pbxProject = try project.generatePbxProj() + let buildFiles = pbxProject.buildFiles + + try expect(buildFiles.count) == 8 + + for buildFile in buildFiles { + let name = buildFile.file?.nameOrPath + + if buildFile.platformFilters == [SupportedDestination.iOS.string] && + (name == "File_ios.swift" || name == "File_A.swift") { + continue + } else if buildFile.platformFilters == [SupportedDestination.tvOS.string] && + (name == "File_tvOs.swift" || name == "File_B.swift") { + continue + } else if buildFile.platformFilters == [SupportedDestination.macOS.string, SupportedDestination.macCatalyst.string] && + (name == "File_C.swift" || name == "File_D.swift") { + continue + } else if buildFile.platformFilters == [SupportedDestination.macOS.string, SupportedDestination.macCatalyst.string] && + (name == "File_macOS.swift" || name == "File_MACCATALYST.swift") { + continue + } + + throw failure("Unexpected source file / destinationFilters") + } + } + $0.it("copies Swift Objective-C Interface Header") { let swiftStaticLibraryWithHeader = Target( name: "swiftStaticLibraryWithHeader", @@ -959,20 +1422,29 @@ class ProjectGeneratorTests: XCTestCase { var scriptSpec = project scriptSpec.targets[0].preBuildScripts = [BuildScript(script: .script("script1"))] scriptSpec.targets[0].postCompileScripts = [BuildScript(script: .script("script2"))] - scriptSpec.targets[0].postBuildScripts = [BuildScript(script: .script("script3"))] + scriptSpec.targets[0].postBuildScripts = [ + BuildScript(script: .script("script3")), + BuildScript(script: .script("script4"), discoveredDependencyFile: "$(DERIVED_FILE_DIR)/target.d") + ] let pbxProject = try scriptSpec.generatePbxProj() - let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.buildPhases.count >= 3 })) + let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.buildPhases.count >= 4 })) let buildPhases = nativeTarget.buildPhases let scripts = pbxProject.shellScriptBuildPhases - try expect(scripts.count) == 3 + try expect(scripts.count) == 4 let script1 = scripts.first { $0.shellScript == "script1" }! let script2 = scripts.first { $0.shellScript == "script2" }! let script3 = scripts.first { $0.shellScript == "script3" }! + let script4 = scripts.first { $0.shellScript == "script4" }! try expect(buildPhases.contains(script1)) == true try expect(buildPhases.contains(script2)) == true try expect(buildPhases.contains(script3)) == true + try expect(buildPhases.contains(script4)) == true + try expect(script1.dependencyFile).beNil() + try expect(script2.dependencyFile).beNil() + try expect(script3.dependencyFile).beNil() + try expect(script4.dependencyFile) == "$(DERIVED_FILE_DIR)/target.d" } $0.it("generates targets with cylical dependencies") { @@ -1068,26 +1540,26 @@ class ProjectGeneratorTests: XCTestCase { type: .application, platform: .iOS, dependencies: [ - Dependency(type: .package(product: "ProjectSpec"), reference: "XcodeGen"), - Dependency(type: .package(product: nil), reference: "Codability"), + Dependency(type: .package(products: ["ProjectSpec"]), reference: "XcodeGen"), + Dependency(type: .package(products: []), reference: "Codability"), ] ) let project = Project(name: "test", targets: [app], packages: [ "XcodeGen": .remote(url: "http://github.com/yonaskolb/XcodeGen", versionRequirement: .branch("master")), "Codability": .remote(url: "http://github.com/yonaskolb/Codability", versionRequirement: .exact("1.0.0")), - "Yams": .local(path: "../Yams"), + "Yams": .local(path: "../Yams", group: nil, excludeFromProject: false), ], options: .init(localPackagesGroup: "MyPackages")) let pbxProject = try project.generatePbxProj(specValidate: false) let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name })) - let projectSpecDependency = try unwrap(nativeTarget.packageProductDependencies.first(where: { $0.productName == "ProjectSpec" })) + let projectSpecDependency = try unwrap(nativeTarget.packageProductDependencies?.first(where: { $0.productName == "ProjectSpec" })) try expect(projectSpecDependency.package?.name) == "XcodeGen" try expect(projectSpecDependency.package?.versionRequirement) == .branch("master") - let codabilityDependency = try unwrap(nativeTarget.packageProductDependencies.first(where: { $0.productName == "Codability" })) + let codabilityDependency = try unwrap(nativeTarget.packageProductDependencies?.first(where: { $0.productName == "Codability" })) try expect(codabilityDependency.package?.name) == "Codability" try expect(codabilityDependency.package?.versionRequirement) == .exact("1.0.0") @@ -1105,16 +1577,20 @@ class ProjectGeneratorTests: XCTestCase { type: .application, platform: .iOS, dependencies: [ - Dependency(type: .package(product: nil), reference: "XcodeGen"), + Dependency(type: .package(products: []), reference: "XcodeGen"), ] ) - let project = Project(name: "test", targets: [app], packages: ["XcodeGen": .local(path: "../XcodeGen")]) + let project = Project(name: "test", targets: [app], packages: ["XcodeGen": .local(path: "../XcodeGen", group: nil, excludeFromProject: false)]) let pbxProject = try project.generatePbxProj(specValidate: false) let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name })) let localPackageFile = try unwrap(pbxProject.fileReferences.first(where: { $0.path == "../XcodeGen" })) try expect(localPackageFile.lastKnownFileType) == "folder" + + let localPackageReference = try unwrap(pbxProject.rootObject?.localPackages.first) + try expect(pbxProject.rootObject?.localPackages.count) == 1 + try expect(localPackageReference.relativePath) == "../XcodeGen" let frameworkPhases = nativeTarget.buildPhases.compactMap { $0 as? PBXFrameworksBuildPhase } @@ -1129,79 +1605,231 @@ class ProjectGeneratorTests: XCTestCase { try expect(file.product?.productName) == "XcodeGen" } - $0.it("generates info.plist") { - let plist = Plist(path: "Info.plist", attributes: ["UISupportedInterfaceOrientations": ["UIInterfaceOrientationPortrait", "UIInterfaceOrientationLandscapeLeft"]]) - let tempPath = Path.temporary + "info" - let project = Project(basePath: tempPath, name: "", targets: [Target(name: "", type: .application, platform: .iOS, info: plist)]) - let pbxProject = try project.generatePbxProj() - let writer = FileWriter(project: project) - try writer.writePlists() + $0.it("excludes local swift packages from generated project if needed") { + let app = Target( + name: "MyApp", + type: .application, + platform: .iOS, + dependencies: [ + Dependency(type: .package(products: ["XcodeGen"]), reference: "XcodeGen"), + ] + ) - let targetConfig = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) + let project = Project( + name: "test", + targets: [app], + packages: [ + "XcodeGen": .local( + path: "../XcodeGen", + group: nil, + excludeFromProject: true + ) + ] + ) - try expect(targetConfig.buildSettings["INFOPLIST_FILE"] as? String) == plist.path + let pbxProject = try project.generatePbxProj(specValidate: false) + let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name })) + let localPackageFile = pbxProject.fileReferences.first(where: { $0.path == "../XcodeGen" }) - let infoPlistFile = tempPath + plist.path - let data: Data = try infoPlistFile.read() - let infoPlist = try PropertyListSerialization.propertyList(from: data, options: [], format: nil) as! [String: Any] - let expectedInfoPlist: [String: Any] = [ - "CFBundleIdentifier": "$(PRODUCT_BUNDLE_IDENTIFIER)", - "CFBundleInfoDictionaryVersion": "6.0", - "CFBundleName": "$(PRODUCT_NAME)", - "CFBundleExecutable": "$(EXECUTABLE_NAME)", - "CFBundleDevelopmentRegion": "$(DEVELOPMENT_LANGUAGE)", - "CFBundleShortVersionString": "1.0", - "CFBundleVersion": "1", - "CFBundlePackageType": "APPL", - "UISupportedInterfaceOrientations": ["UIInterfaceOrientationPortrait", "UIInterfaceOrientationLandscapeLeft"], - ] + try expect(localPackageFile).to.beNil() + try expect(pbxProject.rootObject?.localPackages.count) == 0 - try expect(NSDictionary(dictionary: expectedInfoPlist).isEqual(to: infoPlist)).beTrue() - } + let frameworkPhases = nativeTarget.buildPhases.compactMap { $0 as? PBXFrameworksBuildPhase } - $0.it("info doesn't override info.plist setting") { - let predefinedPlistPath = "Predefined.plist" - // generate plist - let plist = Plist(path: "Info.plist", attributes: ["UISupportedInterfaceOrientations": ["UIInterfaceOrientationPortrait", "UIInterfaceOrientationLandscapeLeft"]]) - let tempPath = Path.temporary + "info" - // create project with a predefined plist - let project = Project(basePath: tempPath, name: "", targets: [Target(name: "", type: .application, platform: .iOS, settings: Settings(buildSettings: ["INFOPLIST_FILE": predefinedPlistPath]), info: plist)]) - let pbxProject = try project.generatePbxProj() - let writer = FileWriter(project: project) - try writer.writePlists() + guard let frameworkPhase = frameworkPhases.first else { + return XCTFail("frameworkPhases should have more than one") + } - let targetConfig = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) - // generated plist should not be in buildsettings - try expect(targetConfig.buildSettings["INFOPLIST_FILE"] as? String) == predefinedPlistPath - } + guard let file = frameworkPhase.files?.first else { + return XCTFail("frameworkPhase should have file") + } - describe("Carthage dependencies") { - $0.context("with static dependency") { - $0.it("should set dependencies") { - let app = Target( - name: "MyApp", - type: .application, - platform: .iOS, - dependencies: [ - Dependency(type: .carthage(findFrameworks: true, linkType: .static), reference: "MyStaticFramework"), - ] - ) - let project = Project(name: "test", targets: [app]) - let pbxProject = try project.generatePbxProj() + try expect(file.product?.productName) == "XcodeGen" + } - let target = pbxProject.nativeTargets.first! - let configuration = target.buildConfigurationList!.buildConfigurations.first! - try expect(configuration.buildSettings["FRAMEWORK_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS/Static"] - let frameworkBuildPhase = try target.frameworksBuildPhase() - guard let files = frameworkBuildPhase?.files, let file = files.first else { - return XCTFail("frameworkBuildPhase should have files") - } - try expect(files.count) == 1 - try expect(file.file?.nameOrPath) == "MyStaticFramework.framework" + $0.it("generates local swift packages with custom xcode path") { + let app = Target( + name: "MyApp", + type: .application, + platform: .iOS, + dependencies: [ + Dependency(type: .package(products: []), reference: "XcodeGen"), + ] + ) - try expect(target.carthageCopyFrameworkBuildPhase).beNil() - } - } + let customLocalPackageGroup = "Packages/Feature" + let project = Project(name: "test", targets: [app], packages: ["XcodeGen": .local(path: "../XcodeGen", group: customLocalPackageGroup, excludeFromProject: false)]) + + let pbxProject = try project.generatePbxProj(specValidate: false) + let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name })) + let localPackageFile = try unwrap(pbxProject.fileReferences.first(where: { $0.path == "../XcodeGen" })) + try expect(localPackageFile.lastKnownFileType) == "folder" + + let frameworkPhases = nativeTarget.buildPhases.compactMap { $0 as? PBXFrameworksBuildPhase } + + let packagesGroup = try unwrap(pbxProject.groups.first(where: { $0.name == "Packages" })) + let featureGroup = try unwrap(pbxProject.groups.first(where: { $0.name == "Feature" })) + + guard featureGroup.parent?.uuid == packagesGroup.uuid else { + return XCTFail("Packages group should be parent of Feature group") + } + + guard localPackageFile.parent?.uuid == featureGroup.uuid else { + return XCTFail("Packages group should be parent of Feature group") + } + + guard let frameworkPhase = frameworkPhases.first else { + return XCTFail("frameworkPhases should have more than one") + } + + guard let file = frameworkPhase.files?.first else { + return XCTFail("frameworkPhase should have file") + } + + try expect(file.product?.productName) == "XcodeGen" + } + + $0.it("generates local swift packages at the top level") { + let app = Target( + name: "MyApp", + type: .application, + platform: .iOS, + dependencies: [ + Dependency(type: .package(products: []), reference: "XcodeGen"), + ] + ) + + let project = Project(name: "test", targets: [app], packages: ["XcodeGen": .local(path: "../XcodeGen", group: "", excludeFromProject: false)]) + + let pbxProject = try project.generatePbxProj(specValidate: false) + let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name })) + let localPackageFile = try unwrap(pbxProject.fileReferences.first(where: { $0.path == "../XcodeGen" })) + try expect(localPackageFile.lastKnownFileType) == "folder" + + let mainGroup = try pbxProject.getMainGroup() + + try expect(mainGroup.children.contains(localPackageFile)) == true + + let frameworkPhases = nativeTarget.buildPhases.compactMap { $0 as? PBXFrameworksBuildPhase } + + guard let frameworkPhase = frameworkPhases.first else { + return XCTFail("frameworkPhases should have more than one") + } + + guard let file = frameworkPhase.files?.first else { + return XCTFail("frameworkPhase should have file") + } + + try expect(file.product?.productName) == "XcodeGen" + } + + $0.it("generates local swift package group at the top level") { + let app = Target( + name: "MyApp", + type: .application, + platform: .iOS, + dependencies: [ + Dependency(type: .package(products: []), reference: "XcodeGen"), + ] + ) + + let project = Project(name: "test", targets: [app], packages: ["XcodeGen": .local(path: "../XcodeGen", group: nil, excludeFromProject: false)], options: .init(localPackagesGroup: "")) + + let pbxProject = try project.generatePbxProj(specValidate: false) + let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name })) + let localPackageFile = try unwrap(pbxProject.fileReferences.first(where: { $0.path == "../XcodeGen" })) + try expect(localPackageFile.lastKnownFileType) == "folder" + + let mainGroup = try pbxProject.getMainGroup() + + try expect(mainGroup.children.contains(localPackageFile)) == true + + let frameworkPhases = nativeTarget.buildPhases.compactMap { $0 as? PBXFrameworksBuildPhase } + + guard let frameworkPhase = frameworkPhases.first else { + return XCTFail("frameworkPhases should have more than one") + } + + guard let file = frameworkPhase.files?.first else { + return XCTFail("frameworkPhase should have file") + } + + try expect(file.product?.productName) == "XcodeGen" + } + + $0.it("generates info.plist") { + let plist = Plist(path: "Info.plist", attributes: ["UISupportedInterfaceOrientations": ["UIInterfaceOrientationPortrait", "UIInterfaceOrientationLandscapeLeft"]]) + let tempPath = Path.temporary + "info" + let project = Project(basePath: tempPath, name: "", targets: [Target(name: "", type: .application, platform: .iOS, info: plist)]) + let pbxProject = try project.generatePbxProj() + let writer = FileWriter(project: project) + try writer.writePlists() + + let targetConfig = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) + + try expect(targetConfig.buildSettings["INFOPLIST_FILE"] as? String) == plist.path + + let infoPlistFile = tempPath + plist.path + let data: Data = try infoPlistFile.read() + let infoPlist = try PropertyListSerialization.propertyList(from: data, options: [], format: nil) as! [String: Any] + let expectedInfoPlist: [String: Any] = [ + "CFBundleIdentifier": "$(PRODUCT_BUNDLE_IDENTIFIER)", + "CFBundleInfoDictionaryVersion": "6.0", + "CFBundleName": "$(PRODUCT_NAME)", + "CFBundleExecutable": "$(EXECUTABLE_NAME)", + "CFBundleDevelopmentRegion": "$(DEVELOPMENT_LANGUAGE)", + "CFBundleShortVersionString": "1.0", + "CFBundleVersion": "1", + "CFBundlePackageType": "APPL", + "UISupportedInterfaceOrientations": ["UIInterfaceOrientationPortrait", "UIInterfaceOrientationLandscapeLeft"], + ] + + try expect(NSDictionary(dictionary: expectedInfoPlist).isEqual(to: infoPlist)).beTrue() + } + + $0.it("info doesn't override info.plist setting") { + let predefinedPlistPath = "Predefined.plist" + // generate plist + let plist = Plist(path: "Info.plist", attributes: ["UISupportedInterfaceOrientations": ["UIInterfaceOrientationPortrait", "UIInterfaceOrientationLandscapeLeft"]]) + let tempPath = Path.temporary + "info" + // create project with a predefined plist + let project = Project(basePath: tempPath, name: "", targets: [Target(name: "", type: .application, platform: .iOS, settings: Settings(buildSettings: ["INFOPLIST_FILE": predefinedPlistPath]), info: plist)]) + let pbxProject = try project.generatePbxProj() + let writer = FileWriter(project: project) + try writer.writePlists() + + let targetConfig = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) + // generated plist should not be in buildsettings + try expect(targetConfig.buildSettings["INFOPLIST_FILE"] as? String) == predefinedPlistPath + } + + describe("Carthage dependencies") { + $0.context("with static dependency") { + $0.it("should set dependencies") { + let app = Target( + name: "MyApp", + type: .application, + platform: .iOS, + dependencies: [ + Dependency(type: .carthage(findFrameworks: true, linkType: .static), reference: "MyStaticFramework"), + ] + ) + let project = Project(name: "test", targets: [app]) + let pbxProject = try project.generatePbxProj() + + let target = pbxProject.nativeTargets.first! + let configuration = target.buildConfigurationList!.buildConfigurations.first! + try expect(configuration.buildSettings["FRAMEWORK_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS/Static"] + let frameworkBuildPhase = try target.frameworksBuildPhase() + guard let files = frameworkBuildPhase?.files, let file = files.first else { + return XCTFail("frameworkBuildPhase should have files") + } + try expect(files.count) == 1 + try expect(file.file?.nameOrPath) == "MyStaticFramework.framework" + + try expect(target.carthageCopyFrameworkBuildPhase).beNil() + } + } $0.context("with mixed dependencies") { $0.it("should set dependencies") { @@ -1269,6 +1897,40 @@ class ProjectGeneratorTests: XCTestCase { try expect(NSDictionary(dictionary: expectedInfoPlist).isEqual(to: infoPlist)).beTrue() } + + $0.it("generates local swift packages with multiple products") { + let app = Target( + name: "MyApp", + type: .application, + platform: .iOS, + dependencies: [ + Dependency(type: .package(products: ["FooDomain", "FooUI"]), reference: "FooFeature") + ] + ) + + let project = Project(name: "test", targets: [app], packages: [ + "FooFeature": .local(path: "../FooFeature", group: nil, excludeFromProject: false) + ], options: .init(localPackagesGroup: "MyPackages")) + + let pbxProject = try project.generatePbxProj(specValidate: false) + let nativeTarget = try unwrap(pbxProject.nativeTargets.first(where: { $0.name == app.name })) + let localPackageFile = try unwrap(pbxProject.fileReferences.first(where: { $0.path == "../FooFeature" })) + try expect(localPackageFile.lastKnownFileType) == "folder" + + let frameworkPhases = nativeTarget.buildPhases.compactMap { $0 as? PBXFrameworksBuildPhase } + + guard let frameworkPhase = frameworkPhases.first else { + return XCTFail("frameworkPhases should have more than one") + } + + guard let files = frameworkPhase.files, files.count == 2 else { + return XCTFail("frameworkPhase should have exactly two files") + } + + let productNames = files.compactMap(\.product?.productName) + try expect(productNames).contains { $0 == "FooDomain" } + try expect(productNames).contains { $0 == "FooUI" } + } } } @@ -1287,7 +1949,7 @@ class ProjectGeneratorTests: XCTestCase { $0.it("generate groups") { let project = Project(name: "test", targets: [frameworkWithSources]) let generator = ProjectGenerator(project: project) - let generatedProject = try generator.generateXcodeProject() + let generatedProject = try generator.generateXcodeProject(userName: "someUser") let group = generatedProject.pbxproj.groups.first(where: { $0.nameOrPath == groupName }) try expect(group?.path) == "App_iOS" } @@ -1298,7 +1960,7 @@ class ProjectGeneratorTests: XCTestCase { let destinationPath = fixturePath let project = Project(name: "test", targets: [frameworkWithSources]) let generator = ProjectGenerator(project: project) - let generatedProject = try generator.generateXcodeProject(in: destinationPath) + let generatedProject = try generator.generateXcodeProject(in: destinationPath, userName: "someUser") let group = generatedProject.pbxproj.groups.first(where: { $0.nameOrPath == groupName }) try expect(group?.path) == "TestProject/App_iOS" } @@ -1307,8 +1969,8 @@ class ProjectGeneratorTests: XCTestCase { let destinationPath = fixturePath let project = Project(name: "test", targets: [frameworkWithSources]) let generator = ProjectGenerator(project: project) - let generatedProject = try generator.generateXcodeProject(in: destinationPath) - let plists = generatedProject.pbxproj.buildConfigurations.compactMap { $0.buildSettings["INFOPLIST_FILE"] as? Path } + let generatedProject = try generator.generateXcodeProject(in: destinationPath, userName: "someUser") + let plists = generatedProject.pbxproj.buildConfigurations.compactMap { $0.buildSettings["INFOPLIST_FILE"] as? String } try expect(plists.count) == 2 for plist in plists { try expect(plist) == "TestProject/App_iOS/Info.plist" @@ -1386,6 +2048,1657 @@ class ProjectGeneratorTests: XCTestCase { } } } + + func testGenerateXcodeProjectWithPlatformFilteredDependencies() throws { + + describe("generateXcodeProject with destinationFilters") { + + func generateProjectForApp(withDependencies: [Dependency], targets: [Target], packages: [String: SwiftPackage] = [:]) throws -> PBXProj { + + let app = Target( + name: "App", + type: .application, + platform: .iOS, + dependencies: withDependencies + ) + + let project = Project( + name: "test", + targets: targets + [app], + packages: packages + ) + + return try project.generatePbxProj() + } + + func expectLinkedDependecies(_ expectedLinkedFiles: [String: [String]], in project: PBXProj) throws { + let buildPhases = project.buildPhases + let frameworkPhases = project.frameworksBuildPhases.filter { buildPhases.contains($0) } + + var linkedFiles: [String: [String]] = [:] + + for link in frameworkPhases[0].files ?? [] { + if let name = link.file?.nameOrPath ?? link.product?.productName { + linkedFiles[name] = link.platformFilters + } + } + + try expect(linkedFiles) == expectedLinkedFiles + } + + func expectCopiedBundles(_ expectedCopiedBundleFiles: [String: [String]], in project: PBXProj) throws { + let buildPhases = project.buildPhases + let copyBundlesPhase = project.copyFilesBuildPhases.filter { buildPhases.contains($0) } + + var copiedFiles: [String: [String]] = [:] + + for copy in copyBundlesPhase[0].files ?? [] { + if let name = copy.file?.nameOrPath { + copiedFiles[name] = copy.platformFilters + } + } + + try expect(copiedFiles) == expectedCopiedBundleFiles + } + + $0.it("target dependencies") { + + let frameworkA = Target( + name: "frameworkA", + type: .framework, + platform: .iOS + ) + + let frameworkB = Target( + name: "frameworkB", + type: .framework, + platform: .iOS + ) + + let expectedLinkedFiles = [ + "frameworkA.framework": [SupportedDestination.iOS.string], + "frameworkB.framework": [SupportedDestination.iOS.string, SupportedDestination.tvOS.string] + ] + + // given + let dependencies = [ + Dependency(type: .target, reference: frameworkA.name, destinationFilters: [.iOS]), + Dependency(type: .target, reference: frameworkB.name, destinationFilters: [.iOS, .tvOS]), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [frameworkA, frameworkB]) + + // then ensure that everything is linked + try expectLinkedDependecies(expectedLinkedFiles, in: pbxProject) + } + + $0.it("framework dependencies") { + + let expectedLinkedFiles = [ + "frameworkA.framework": [SupportedDestination.iOS.string], + "frameworkB.framework": [SupportedDestination.iOS.string, SupportedDestination.tvOS.string] + ] + + // given + let dependencies = [ + Dependency(type: .framework, reference: "frameworkA.framework", destinationFilters: [.iOS]), + Dependency(type: .framework, reference: "frameworkB.framework", destinationFilters: [.iOS, .tvOS]), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: []) + + // then ensure that everything is linked + try expectLinkedDependecies(expectedLinkedFiles, in: pbxProject) + } + + $0.it("carthage dependencies") { + + let expectedLinkedFiles = [ + "frameworkA.framework": [SupportedDestination.iOS.string], + "frameworkB.framework": [SupportedDestination.iOS.string, SupportedDestination.tvOS.string] + ] + + // given + let dependencies = [ + Dependency(type: .carthage(findFrameworks: false, linkType: .dynamic), reference: "frameworkA.framework", destinationFilters: [.iOS]), + Dependency(type: .carthage(findFrameworks: false, linkType: .dynamic), reference: "frameworkB.framework", destinationFilters: [.iOS, .tvOS]), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: []) + + // then ensure that everything is linked + try expectLinkedDependecies(expectedLinkedFiles, in: pbxProject) + } + + $0.it("sdk dependencies") { + + let expectedLinkedFiles = [ + "sdkA.framework": [SupportedDestination.iOS.string], + "sdkB.framework": [SupportedDestination.iOS.string, SupportedDestination.tvOS.string] + ] + + // given + let dependencies = [ + Dependency(type: .sdk(root: nil), reference: "sdkA.framework", destinationFilters: [.iOS]), + Dependency(type: .sdk(root: nil), reference: "sdkB.framework", destinationFilters: [.iOS, .tvOS]), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: []) + + // then ensure that everything is linked + try expectLinkedDependecies(expectedLinkedFiles, in: pbxProject) + } + + $0.it("package dependencies") { + + let packages: [String: SwiftPackage] = [ + "RxSwift": .remote(url: "https://github.com/ReactiveX/RxSwift", versionRequirement: .upToNextMajorVersion("5.1.1")), + ] + + let expectedLinkedFiles = [ + "RxSwift": [SupportedDestination.iOS.string], + "RxCocoa": [SupportedDestination.iOS.string, SupportedDestination.tvOS.string] + ] + + // given + let dependencies = [ + Dependency(type: .package(products: ["RxSwift"]), reference: "RxSwift", destinationFilters: [.iOS]), + Dependency(type: .package(products: ["RxCocoa"]), reference: "RxSwift", destinationFilters: [.iOS, .tvOS]), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [], packages: packages) + + // then ensure that everything is linked + try expectLinkedDependecies(expectedLinkedFiles, in: pbxProject) + } + + $0.it("bundle dependencies") { + + let expectedCopiedBundleFiles = [ + "bundleA.bundle": [SupportedDestination.iOS.string], + "bundleB.bundle": [SupportedDestination.iOS.string, SupportedDestination.tvOS.string] + ] + + // given + let dependencies = [ + Dependency(type: .bundle, reference: "bundleA.bundle", destinationFilters: [.iOS]), + Dependency(type: .bundle, reference: "bundleB.bundle", destinationFilters: [.iOS, .tvOS]), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: []) + + // then ensure that everything is linked + try expectCopiedBundles(expectedCopiedBundleFiles, in: pbxProject) + } + } + } + + func testGenerateXcodeProjectWithCustomDependencyDestinations() throws { + + describe("generateXcodeProject") { + + func generateProjectForApp(withDependencies: [Dependency], targets: [Target], packages: [String: SwiftPackage] = [:]) throws -> PBXProj { + + let app = Target( + name: "App", + type: .application, + platform: .macOS, + dependencies: withDependencies + ) + + let project = Project( + name: "test", + targets: targets + [app], + packages: packages + ) + + return try project.generatePbxProj() + } + + func expectCopyPhase(in project:PBXProj, withFilePaths: [String]? = nil, withProductPaths: [String]? = nil, toSubFolder subfolder: PBXCopyFilesBuildPhase.SubFolder, dstPath: String? = nil) throws { + + let phases = project.copyFilesBuildPhases + try expect(phases.count) == 1 + let phase = phases.first! + try expect(phase.dstSubfolderSpec) == subfolder + try expect(phase.dstPath) == dstPath + if let paths = withFilePaths { + try expect(phase.files?.count) == paths.count + let filePaths = phase.files!.map { $0.file!.path } + try expect(filePaths) == paths + } + if let paths = withProductPaths { + try expect(phase.files?.count) == paths.count + let filePaths = phase.files!.map { $0.product!.productName } + try expect(filePaths) == paths + } + } + + $0.context("with target dependencies") { + $0.context("application") { + + let appA = Target( + name: "appA", + type: .application, + platform: .macOS + ) + let appB = Target( + name: "appB", + type: .application, + platform: .macOS + ) + + $0.it("does not embed them without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: appA.name, embed: true), + Dependency(type: .target, reference: appB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [ appA, appB ]) + + // then + try expect(pbxProject.copyFilesBuildPhases.count) == 0 + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: appA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: appB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [appA, appB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["appA.app"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("framework") { + + let frameworkA = Target( + name: "frameworkA", + type: .framework, + platform: .macOS + ) + let frameworkB = Target( + name: "frameworkB", + type: .framework, + platform: .macOS + ) + + $0.it("embeds them into frameworks without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: frameworkA.name, embed: true), + Dependency(type: .target, reference: frameworkB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [frameworkA, frameworkB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["frameworkA.framework"], toSubFolder: .frameworks, dstPath: "") + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: frameworkA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: frameworkB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [frameworkA, frameworkB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["frameworkA.framework"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("staticFramework") { + + let frameworkA = Target( + name: "frameworkA", + type: .staticFramework, + platform: .macOS + ) + let frameworkB = Target( + name: "frameworkB", + type: .staticFramework, + platform: .macOS + ) + + $0.it("embeds them into frameworks without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: frameworkA.name, embed: true), + Dependency(type: .target, reference: frameworkB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [frameworkA, frameworkB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["frameworkA.framework"], toSubFolder: .frameworks, dstPath: "") + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: frameworkA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: frameworkB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [frameworkA, frameworkB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["frameworkA.framework"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("xcFramework") { + + let frameworkA = Target( + name: "frameworkA", + type: .xcFramework, + platform: .macOS + ) + let frameworkB = Target( + name: "frameworkB", + type: .xcFramework, + platform: .macOS + ) + + $0.it("does not embed them without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: frameworkA.name, embed: true), + Dependency(type: .target, reference: frameworkB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [frameworkA, frameworkB]) + + // then + try expect(pbxProject.copyFilesBuildPhases.count) == 0 + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: frameworkA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: frameworkB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [frameworkA, frameworkB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["frameworkA.xcframework"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("Dynamic Library") { + + let libraryA = Target( + name: "libraryA", + type: .dynamicLibrary, + platform: .macOS + ) + let libraryB = Target( + name: "libraryB", + type: .dynamicLibrary, + platform: .macOS + ) + + $0.it("does not embed them without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: libraryA.name, embed: true), + Dependency(type: .target, reference: libraryB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [libraryA, libraryB]) + + // then + try expect(pbxProject.copyFilesBuildPhases.count) == 0 + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: libraryA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: libraryB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [libraryA, libraryB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["libraryA.dylib"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("Static Library") { + + let libraryA = Target( + name: "libraryA", + type: .staticLibrary, + platform: .macOS + ) + let libraryB = Target( + name: "libraryB", + type: .staticLibrary, + platform: .macOS + ) + + $0.it("does not embed them without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: libraryA.name, embed: true), + Dependency(type: .target, reference: libraryB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [libraryA, libraryB]) + + // then + try expect(pbxProject.copyFilesBuildPhases.count) == 0 + } + + $0.it("embeds them to custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: libraryA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: libraryB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [libraryA, libraryB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["liblibraryA.a"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("bundle") { + + let bundleA = Target( + name: "bundleA", + type: .bundle, + platform: .macOS + ) + let bundleB = Target( + name: "bundleB", + type: .bundle, + platform: .macOS + ) + + $0.it("does not embed them without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: bundleA.name, embed: true), + Dependency(type: .target, reference: bundleB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [bundleA, bundleB]) + + // then + try expect(pbxProject.copyFilesBuildPhases.count) == 0 + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: bundleA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: bundleB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [bundleA, bundleB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["bundleA.bundle"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("unitTestBundle") { + + let bundleA = Target( + name: "bundleA", + type: .unitTestBundle, + platform: .macOS + ) + let bundleB = Target( + name: "bundleB", + type: .unitTestBundle, + platform: .macOS + ) + + $0.it("does not embed them without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: bundleA.name, embed: true), + Dependency(type: .target, reference: bundleB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [bundleA, bundleB]) + + // then + try expect(pbxProject.copyFilesBuildPhases.count) == 0 + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: bundleA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: bundleB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [bundleA, bundleB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["bundleA.xctest"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("uitTestBundle") { + + let bundleA = Target( + name: "bundleA", + type: .uiTestBundle, + platform: .macOS + ) + let bundleB = Target( + name: "bundleB", + type: .uiTestBundle, + platform: .macOS + ) + + $0.it("does not embed them without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: bundleA.name, embed: true), + Dependency(type: .target, reference: bundleB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [bundleA, bundleB]) + + // then + try expect(pbxProject.copyFilesBuildPhases.count) == 0 + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: bundleA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: bundleB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [bundleA, bundleB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["bundleA.xctest"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("appExtension") { + + let extA = Target( + name: "extA", + type: .appExtension, + platform: .macOS + ) + let extB = Target( + name: "extB", + type: .appExtension, + 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: .plugins, dstPath: "") + } + + $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: .executables, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: extB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .executables, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [extA, extB]) + + // then + 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") { + + let toolA = Target( + name: "toolA", + type: .commandLineTool, + platform: .macOS + ) + let toolB = Target( + name: "toolB", + type: .commandLineTool, + platform: .macOS + ) + + $0.it("does not embed them without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: toolA.name, embed: true), + Dependency(type: .target, reference: toolB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [toolA, toolB]) + + // then + try expect(pbxProject.copyFilesBuildPhases.count) == 0 + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: toolA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: toolB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [toolA, toolB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["toolA"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("watchApp") { + + let appA = Target( + name: "appA", + type: .watchApp, + platform: .macOS + ) + let appB = Target( + name: "appB", + type: .watchApp, + platform: .macOS + ) + + $0.it("does not embed them without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: appA.name, embed: true), + Dependency(type: .target, reference: appB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [appA, appB]) + + // then + try expect(pbxProject.copyFilesBuildPhases.count) == 0 + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: appA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: appB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [appA, appB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["appA.app"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("watch2App") { + + let appA = Target( + name: "appA", + type: .watch2App, + platform: .macOS + ) + let appB = Target( + name: "appB", + type: .watch2App, + platform: .macOS + ) + + $0.it("does not embed them without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: appA.name, embed: true), + Dependency(type: .target, reference: appB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [appA, appB]) + + // then + try expect(pbxProject.copyFilesBuildPhases.count) == 0 + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: appA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: appB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [appA, appB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["appA.app"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("watch2AppContainer") { + + let appA = Target( + name: "appA", + type: .watch2AppContainer, + platform: .macOS + ) + let appB = Target( + name: "appB", + type: .watch2AppContainer, + platform: .macOS + ) + + $0.it("does not embed them without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: appA.name, embed: true), + Dependency(type: .target, reference: appB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [appA, appB]) + + // then + try expect(pbxProject.copyFilesBuildPhases.count) == 0 + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: appA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: appB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [appA, appB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["appA.app"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("watchExtension") { + + let extA = Target( + name: "extA", + type: .watchExtension, + platform: .macOS + ) + let extB = Target( + name: "extB", + type: .watchExtension, + 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: .plugins, dstPath: "") + } + + $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: .frameworks, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: extB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .frameworks, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [extA, extB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["extA.appex"], toSubFolder: .frameworks, dstPath: "test") + } + } + + $0.context("watch2Extension") { + + let extA = Target( + name: "extA", + type: .watch2Extension, + platform: .macOS + ) + let extB = Target( + name: "extB", + type: .watch2Extension, + 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: .plugins, dstPath: "") + } + + $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: .frameworks, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: extB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .frameworks, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [extA, extB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["extA.appex"], toSubFolder: .frameworks, dstPath: "test") + } + } + + $0.context("tvExtension") { + + let extA = Target( + name: "extA", + type: .tvExtension, + platform: .macOS + ) + let extB = Target( + name: "extB", + type: .tvExtension, + 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: .plugins, dstPath: "") + } + + $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: .frameworks, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: extB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .frameworks, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [extA, extB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["extA.appex"], toSubFolder: .frameworks, dstPath: "test") + } + } + + $0.context("messagesApplication") { + + let appA = Target( + name: "appA", + type: .messagesApplication, + platform: .macOS + ) + let appB = Target( + name: "appB", + type: .messagesApplication, + platform: .macOS + ) + + $0.it("does not embed them without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: appA.name, embed: true), + Dependency(type: .target, reference: appB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [appA, appB]) + + // then + try expect(pbxProject.copyFilesBuildPhases.count) == 0 + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: appA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: appB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [appA, appB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["appA.app"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("messagesExtension") { + + let extA = Target( + name: "extA", + type: .messagesExtension, + platform: .macOS + ) + let extB = Target( + name: "extB", + type: .messagesExtension, + 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: .plugins, dstPath: "") + } + + $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: .frameworks, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: extB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .frameworks, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [extA, extB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["extA.appex"], toSubFolder: .frameworks, dstPath: "test") + } + } + + $0.context("stickerPack") { + + let extA = Target( + name: "extA", + type: .stickerPack, + platform: .macOS + ) + let extB = Target( + name: "extB", + type: .stickerPack, + 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: .plugins, dstPath: "") + } + + $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: .frameworks, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: extB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .frameworks, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [extA, extB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["extA.appex"], toSubFolder: .frameworks, dstPath: "test") + } + } + + $0.context("xpcService") { + + let xpcA = Target( + name: "xpcA", + type: .xpcService, + platform: .macOS + ) + let xpcB = Target( + name: "xpcB", + type: .xpcService, + platform: .macOS + ) + + $0.it("embeds them into plugins without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: xpcA.name, embed: true), + Dependency(type: .target, reference: xpcB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [xpcA, xpcB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["xpcA.xpc"], toSubFolder: .productsDirectory, dstPath: "$(CONTENTS_FOLDER_PATH)/XPCServices") + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: xpcA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .frameworks, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: xpcB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .frameworks, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [xpcA, xpcB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["xpcA.xpc"], toSubFolder: .frameworks, dstPath: "test") + } + } + + $0.context("ocUnitTestBundle") { + + let bundleA = Target( + name: "bundleA", + type: .ocUnitTestBundle, + platform: .macOS + ) + let bundleB = Target( + name: "bundleB", + type: .ocUnitTestBundle, + platform: .macOS + ) + + $0.it("does not embed them without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: bundleA.name, embed: true), + Dependency(type: .target, reference: bundleB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [bundleA, bundleB]) + + // then + try expect(pbxProject.copyFilesBuildPhases.count) == 0 + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: bundleA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .frameworks, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: bundleB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .frameworks, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [bundleA, bundleB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["bundleA.octest"], toSubFolder: .frameworks, dstPath: "test") + } + } + + $0.context("xcodeExtension") { + + let extA = Target( + name: "extA", + type: .xcodeExtension, + platform: .macOS + ) + let extB = Target( + name: "extB", + type: .xcodeExtension, + 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: .plugins, dstPath: "") + } + + $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: .frameworks, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: extB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .frameworks, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [extA, extB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["extA.appex"], toSubFolder: .frameworks, dstPath: "test") + } + } + + $0.context("instrumentsPackage") { + + let pkgA = Target( + name: "pkgA", + type: .instrumentsPackage, + platform: .macOS + ) + let pkgB = Target( + name: "pkgB", + type: .instrumentsPackage, + platform: .macOS + ) + + $0.it("does not embed them without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: pkgA.name, embed: true), + Dependency(type: .target, reference: pkgB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [pkgA, pkgB]) + + // then + try expect(pbxProject.copyFilesBuildPhases.count) == 0 + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: pkgA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .frameworks, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: pkgB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .frameworks, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [pkgA, pkgB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["pkgA.instrpkg"], toSubFolder: .frameworks, dstPath: "test") + } + } + + $0.context("intentsServiceExtension") { + + let extA = Target( + name: "extA", + type: .intentsServiceExtension, + platform: .macOS + ) + let extB = Target( + name: "extB", + type: .intentsServiceExtension, + 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: .plugins, dstPath: "") + } + + $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: .frameworks, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: extB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .frameworks, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [extA, extB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["extA.appex"], toSubFolder: .frameworks, dstPath: "test") + } + } + + $0.context("appClip") { + + let clipA = Target( + name: "clipA", + type: .onDemandInstallCapableApplication, + platform: .macOS + ) + let clipB = Target( + name: "clipB", + type: .onDemandInstallCapableApplication, + platform: .macOS + ) + + $0.it("does embed them into products directory without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: clipA.name, embed: true), + Dependency(type: .target, reference: clipB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [clipA, clipB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["clipA.app"], toSubFolder: .productsDirectory, dstPath: "$(CONTENTS_FOLDER_PATH)/AppClips") + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: clipA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: clipB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [clipA, clipB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["clipA.app"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("Metal Library") { + + let libraryA = Target( + name: "libraryA", + type: .metalLibrary, + platform: .macOS + ) + let libraryB = Target( + name: "libraryB", + type: .metalLibrary, + platform: .macOS + ) + + $0.it("does not embed them without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: libraryA.name, embed: true), + Dependency(type: .target, reference: libraryB.name, embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [libraryA, libraryB]) + + // then + try expect(pbxProject.copyFilesBuildPhases.count) == 0 + } + + $0.it("embeds them to custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .target, reference: libraryA.name, embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .target, reference: libraryB.name, embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [libraryA, libraryB]) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["libraryA.metallib"], toSubFolder: .plugins, dstPath: "test") + } + } + } + + $0.context("with framework dependencies") { + $0.it("embeds them into frameworks without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .framework, reference: "frameworkA.framework", embed: true), + Dependency(type: .framework, reference: "frameworkB.framework", embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: []) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["frameworkA.framework"], toSubFolder: .frameworks, dstPath: "") + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .framework, reference: "frameworkA.framework", embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .framework, reference: "frameworkB.framework", embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: []) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["frameworkA.framework"], toSubFolder: .plugins, dstPath: "test") + } + + $0.it("generates single copy phase for multiple frameworks with same copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .framework, reference: "frameworkA.framework", embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .framework, reference: "frameworkB.framework", embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: []) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["frameworkA.framework", "frameworkB.framework"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("with sdk dependencies") { + + $0.it("embeds them into frameworks without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .sdk(root: nil), reference: "sdkA.framework", embed: true), + Dependency(type: .sdk(root: nil), reference: "sdkB.framework", embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: []) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["System/Library/Frameworks/sdkA.framework"], toSubFolder: .frameworks, dstPath: "") + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .sdk(root: nil), reference: "sdkA.framework", embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .sdk(root: nil), reference: "sdkB.framework", embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: []) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["System/Library/Frameworks/sdkA.framework"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("with package dependencies") { + + let packages: [String: SwiftPackage] = [ + "RxSwift": .remote(url: "https://github.com/ReactiveX/RxSwift", versionRequirement: .upToNextMajorVersion("5.1.1")), + ] + + $0.it("embeds them into frameworks without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .package(products: ["RxSwift"]), reference: "RxSwift", embed: true), + Dependency(type: .package(products: ["RxCocoa"]), reference: "RxSwift", embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [], packages: packages) + + // then + try expectCopyPhase(in: pbxProject, withProductPaths: ["RxSwift"], toSubFolder: .frameworks, dstPath: "") + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .package(products: ["RxSwift"]), reference: "RxSwift", embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .package(products: ["RxCocoa"]), reference: "RxSwift", embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: [], packages: packages) + + // then + try expectCopyPhase(in: pbxProject, withProductPaths: ["RxSwift"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("with carthage dependencies") { + + $0.it("embeds them into frameworks without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .carthage(findFrameworks: false, linkType: .dynamic), reference: "frameworkA.framework", embed: true), + Dependency(type: .carthage(findFrameworks: false, linkType: .dynamic), reference: "frameworkB.framework", embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: []) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["frameworkA.framework"], toSubFolder: .frameworks, dstPath: "") + } + + $0.it("embeds them into custom location with copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .carthage(findFrameworks: false, linkType: .dynamic), reference: "frameworkA.framework", embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .carthage(findFrameworks: false, linkType: .static), reference: "frameworkB.framework", embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: []) + + // then + try expectCopyPhase(in: pbxProject, withFilePaths: ["frameworkA.framework"], toSubFolder: .plugins, dstPath: "test") + } + } + + $0.context("with bundle dependencies") { + $0.it("embeds them into resources without copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .bundle, reference: "bundleA.bundle", embed: true), + Dependency(type: .bundle, reference: "bundleB.bundle", embed: false), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: []) + + // then + /// XcodeGen ignores embed: false for bundles + try expectCopyPhase(in: pbxProject, withFilePaths: ["bundleA.bundle", "bundleB.bundle"], toSubFolder: .resources) + } + + $0.it("ignores custom copy phase spec") { + + // given + let dependencies = [ + Dependency(type: .bundle, reference: "bundleA.bundle", embed: true, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + Dependency(type: .bundle, reference: "bundleB.bundle", embed: false, copyPhase: BuildPhaseSpec.CopyFilesSettings(destination: .plugins, subpath: "test", phaseOrder: .postCompile)), + ] + + // when + let pbxProject = try generateProjectForApp(withDependencies: dependencies, targets: []) + + // then + /// XcodeGen ignores embed: false for bundles + try expectCopyPhase(in: pbxProject, withFilePaths: ["bundleA.bundle", "bundleB.bundle"], toSubFolder: .resources) + } + } + } + } } private extension PBXTarget { diff --git a/Tests/XcodeGenKitTests/SchemeGeneratorTests.swift b/Tests/XcodeGenKitTests/SchemeGeneratorTests.swift index 541d4cd5b..d876b3f8b 100644 --- a/Tests/XcodeGenKitTests/SchemeGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/SchemeGeneratorTests.swift @@ -41,22 +41,30 @@ private let uiTest = Target( class SchemeGeneratorTests: XCTestCase { - func testSchemes() { + func testSchemes() throws { + try skipIfNecessary() describe { let buildTarget = Scheme.BuildTarget(target: .local(app.name)) $0.it("generates scheme") { let preAction = Scheme.ExecutionAction(name: "Script", script: "echo Starting", settingsTarget: app.name) let simulateLocation = Scheme.SimulateLocation(allow: true, defaultLocation: "New York, NY, USA") - let scheme = Scheme( + let storeKitConfiguration = "Configuration.storekit" + let scheme = try Scheme( name: "MyScheme", build: Scheme.Build(targets: [buildTarget], preActions: [preAction]), - run: Scheme.Run(config: "Debug", askForAppToLaunch: true, launchAutomaticallySubstyle: "2", simulateLocation: simulateLocation) + run: Scheme.Run(config: "Debug", enableGPUFrameCaptureMode: .metal, askForAppToLaunch: true, launchAutomaticallySubstyle: "2", simulateLocation: simulateLocation, storeKitConfiguration: storeKitConfiguration, customLLDBInit: "/sample/.lldbinit", customWorkingDirectory: "/test"), + 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") + ], customLLDBInit: "/test/.lldbinit"), + profile: Scheme.Profile(config: "Release", askForAppToLaunch: true) ) let project = Project( name: "test", targets: [app, framework], - schemes: [scheme] + schemes: [scheme], + options: .init(schemePathPrefix: "../") ) let xcodeProject = try project.generateXcodeProject() let target = try unwrap(xcodeProject.pbxproj.nativeTargets @@ -65,6 +73,7 @@ class SchemeGeneratorTests: XCTestCase { try expect(scheme.name) == "MyScheme" try expect(xcscheme.buildAction?.buildImplicitDependencies) == true try expect(xcscheme.buildAction?.parallelizeBuild) == true + try expect(xcscheme.buildAction?.runPostActionsOnFailure) == false try expect(xcscheme.buildAction?.preActions.first?.title) == "Script" try expect(xcscheme.buildAction?.preActions.first?.scriptText) == "echo Starting" try expect(xcscheme.buildAction?.preActions.first?.environmentBuildable?.buildableName) == "MyApp.app" @@ -95,10 +104,43 @@ class SchemeGeneratorTests: XCTestCase { try expect(xcscheme.testAction?.selectedDebuggerIdentifier) == XCScheme.defaultDebugger try expect(xcscheme.launchAction?.askForAppToLaunch) == true + try expect(xcscheme.profileAction?.askForAppToLaunch) == true try expect(xcscheme.launchAction?.launchAutomaticallySubstyle) == "2" try expect(xcscheme.launchAction?.allowLocationSimulation) == true + try expect(xcscheme.launchAction?.storeKitConfigurationFileReference?.identifier) == "../Configuration.storekit" 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() + + try expect(xcscheme.launchAction?.useCustomWorkingDirectory) == true + try expect(xcscheme.launchAction?.customWorkingDirectory) == "/test" + + try expect(xcscheme.testAction?.testables[0].locationScenarioReference?.referenceType) == "0" + try expect(xcscheme.testAction?.testables[0].locationScenarioReference?.identifier) == "../test.gpx" + + try expect(xcscheme.testAction?.testables[1].locationScenarioReference?.referenceType) == "1" + try expect(xcscheme.testAction?.testables[1].locationScenarioReference?.identifier) == "New York, NY, USA" + } + + let frameworkTarget = Scheme.BuildTarget(target: .local(framework.name), buildTypes: [.archiving]) + $0.it("generates a scheme with the first runnable selected") { + let scheme = Scheme( + name: "MyScheme", + build: Scheme.Build(targets: [frameworkTarget, buildTarget]) + ) + let project = Project( + name: "test", + targets: [framework, app], + schemes: [scheme] + ) + let xcodeProject = try project.generateXcodeProject() + let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first) + + let buildableReference = xcscheme.launchAction?.runnable?.buildableReference + try expect(buildableReference?.buildableName) == "MyApp.app" } $0.it("generates scheme with multiple configs") { @@ -112,17 +154,19 @@ class SchemeGeneratorTests: XCTestCase { name: "MyFramework", type: .application, platform: .iOS, - scheme: TargetScheme(testTargets: ["MyFrameworkTests"]) + scheme: TargetScheme(testTargets: ["MyFrameworkTests"], storeKitConfiguration: "Configuration.storekit") ) let project = Project( name: "test", configs: configs, - targets: [framework, frameworkTest] + targets: [framework, frameworkTest], + options: .init(schemePathPrefix: "../../") ) let xcodeProject = try project.generateXcodeProject() let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first) try expect(xcscheme.launchAction?.buildConfiguration) == "Debug" + try expect(xcscheme.launchAction?.storeKitConfigurationFileReference?.identifier) == "../../Configuration.storekit" try expect(xcscheme.testAction?.buildConfiguration) == "Debug" try expect(xcscheme.profileAction?.buildConfiguration) == "Release" try expect(xcscheme.analyzeAction?.buildConfiguration) == "Debug" @@ -138,14 +182,15 @@ class SchemeGeneratorTests: XCTestCase { let scheme = Scheme( name: "EnvironmentVariablesScheme", build: Scheme.Build(targets: [buildTarget]), - run: Scheme.Run(config: "Debug", environmentVariables: runVariables), + run: Scheme.Run(config: "Debug", environmentVariables: runVariables, simulateLocation: .init(allow: true, defaultLocation: "File.gpx"), storeKitConfiguration: "Configuration.storekit"), test: Scheme.Test(config: "Debug"), profile: Scheme.Profile(config: "Debug") ) let project = Project( name: "test", targets: [app, framework], - schemes: [scheme] + schemes: [scheme], + options: .init(schemePathPrefix: "../") ) let xcodeProject = try project.generateXcodeProject() @@ -156,37 +201,52 @@ class SchemeGeneratorTests: XCTestCase { .contains(where: { $0.name == app.name }) ).beTrue() try expect(xcscheme.launchAction?.environmentVariables) == runVariables + 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.testAction?.environmentVariables).to.beNil() try expect(xcscheme.profileAction?.environmentVariables).to.beNil() } $0.it("generates target schemes from config variant") { - let configVariants = ["Test", "Production"] + let configVariants = ["Test", "PreProd", "Prod"] var target = app target.scheme = TargetScheme(configVariants: configVariants) + + // Including here a double test for custom upper/lowercase, and dash delimited in config types let configs: [Config] = [ - Config(name: "Test Debug", type: .debug), - Config(name: "Production Debug", type: .debug), + Config(name: "Test-Debug", type: .debug), + Config(name: "PreProd debug", type: .debug), + Config(name: "Prod-Debug", type: .debug), Config(name: "Test Release", type: .release), - Config(name: "Production Release", type: .release), + Config(name: "PreProd release", type: .release), + Config(name: "Prod Release", type: .release), ] let project = Project(name: "test", configs: configs, targets: [target, framework]) let xcodeProject = try project.generateXcodeProject() - try expect(xcodeProject.sharedData?.schemes.count) == 2 - - let xcscheme = try unwrap(xcodeProject.sharedData?.schemes - .first(where: { $0.name == "\(target.name) Test" })) - let buildActionEntry = try unwrap(xcscheme.buildAction?.buildActionEntries.first) - - try expect(buildActionEntry.buildableReference.blueprintIdentifier.count > 0) == true - - try expect(xcscheme.launchAction?.buildConfiguration) == "Test Debug" - try expect(xcscheme.testAction?.buildConfiguration) == "Test Debug" - try expect(xcscheme.profileAction?.buildConfiguration) == "Test Release" - try expect(xcscheme.analyzeAction?.buildConfiguration) == "Test Debug" - try expect(xcscheme.archiveAction?.buildConfiguration) == "Test Release" + try expect(xcodeProject.sharedData?.schemes.count) == 3 + try configVariants.forEach { variantName in + let xcscheme = try unwrap(xcodeProject.sharedData?.schemes + .first(where: { $0.name == "\(target.name) \(variantName)" })) + let buildActionEntry = try unwrap(xcscheme.buildAction?.buildActionEntries.first) + + try expect((buildActionEntry.buildableReference.blueprintIdentifier?.count ?? 0) > 0) == true + if variantName == "PreProd" { + try expect(xcscheme.launchAction?.buildConfiguration) == "\(variantName) debug" + try expect(xcscheme.testAction?.buildConfiguration) == "\(variantName) debug" + try expect(xcscheme.profileAction?.buildConfiguration) == "\(variantName) release" + try expect(xcscheme.analyzeAction?.buildConfiguration) == "\(variantName) debug" + try expect(xcscheme.archiveAction?.buildConfiguration) == "\(variantName) release" + } else { + try expect(xcscheme.launchAction?.buildConfiguration) == "\(variantName)-Debug" + try expect(xcscheme.testAction?.buildConfiguration) == "\(variantName)-Debug" + try expect(xcscheme.profileAction?.buildConfiguration) == "\(variantName) Release" + try expect(xcscheme.analyzeAction?.buildConfiguration) == "\(variantName)-Debug" + try expect(xcscheme.archiveAction?.buildConfiguration) == "\(variantName) Release" + } + } } $0.it("generates environment variables for target schemes") { @@ -210,7 +270,7 @@ class SchemeGeneratorTests: XCTestCase { let scheme = Scheme( name: "TestScheme", build: Scheme.Build(targets: [buildTarget]), - run: Scheme.Run(config: "Debug", debugEnabled: false) + run: Scheme.Run(config: "Debug", enableGPUFrameCaptureMode: .metal, debugEnabled: false, simulateLocation: .init(allow: true, defaultLocation: "File.gpx"), storeKitConfiguration: "Configuration.storekit") ) let project = Project( name: "test", @@ -223,6 +283,10 @@ class SchemeGeneratorTests: XCTestCase { try expect(xcscheme.launchAction?.selectedDebuggerIdentifier) == "" try expect(xcscheme.launchAction?.selectedLauncherIdentifier) == "Xcode.IDEFoundation.Launcher.PosixSpawn" + 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") { @@ -267,12 +331,31 @@ class SchemeGeneratorTests: XCTestCase { try expect(xcscheme.testAction?.postActions.count) == 0 } + $0.it("generates target schemes with code coverage options") { + var target = app + target.scheme = try TargetScheme( + gatherCoverageData: true, + coverageTargets: [ + TestableTargetReference(framework.name), + ] + ) + + let project = Project(name: "test", targets: [target, framework]) + let xcodeProject = try project.generateXcodeProject() + try expect(xcodeProject.sharedData?.schemes.count) == 1 + + let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first) + try expect(xcscheme.testAction?.codeCoverageEnabled) == true + try expect(xcscheme.testAction?.codeCoverageTargets.count) == 1 + try expect(xcscheme.testAction?.codeCoverageTargets.first?.blueprintName) == framework.name + } + $0.it("generates scheme using external project file") { prepareXcodeProj: do { let project = try! Project(path: fixturePath + "scheme_test/test_project.yml") let generator = ProjectGenerator(project: project) let writer = FileWriter(project: project) - let xcodeProject = try! generator.generateXcodeProject() + let xcodeProject = try! generator.generateXcodeProject(userName: "someUser") try! writer.writeXcodeProject(xcodeProject) try! writer.writePlists() } @@ -303,7 +386,7 @@ class SchemeGeneratorTests: XCTestCase { let project = try! Project(path: fixturePath + "scheme_test/test_project.yml") let generator = ProjectGenerator(project: project) let writer = FileWriter(project: project) - let xcodeProject = try! generator.generateXcodeProject() + let xcodeProject = try! generator.generateXcodeProject(userName: "someUser") try! writer.writeXcodeProject(xcodeProject) try! writer.writePlists() } @@ -317,7 +400,8 @@ class SchemeGeneratorTests: XCTestCase { gatherCoverageData: true, coverageTargets: [ "TestProject/ExternalTarget", - TargetReference(framework.name), + TestableTargetReference(framework.name), + TestableTargetReference(name: "XcodeGenKitTests", location: .package("XcodeGen")) ] ) ) @@ -325,6 +409,7 @@ class SchemeGeneratorTests: XCTestCase { name: "test", targets: [framework], schemes: [scheme], + packages: ["XcodeGen": .local(path: "../", group: nil, excludeFromProject: false)], projectReferences: [ ProjectReference(name: "TestProject", path: externalProject.string), ] @@ -332,7 +417,7 @@ class SchemeGeneratorTests: XCTestCase { let xcodeProject = try project.generateXcodeProject() let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first) try expect(xcscheme.testAction?.codeCoverageEnabled) == true - try expect(xcscheme.testAction?.codeCoverageTargets.count) == 2 + try expect(xcscheme.testAction?.codeCoverageTargets.count) == 3 let buildableReference = xcscheme.testAction?.codeCoverageTargets.first try expect(buildableReference?.blueprintName) == "ExternalTarget" try expect(buildableReference?.referencedContainer) == "container:\(externalProject.string)" @@ -354,6 +439,7 @@ class SchemeGeneratorTests: XCTestCase { $0.it("generates scheme with remote runnable for watch app target") { let xcscheme = try self.makeWatchScheme(appType: .watch2App, extensionType: .watch2Extension) try expect(xcscheme.launchAction?.runnable).beOfType(XCScheme.RemoteRunnable.self) + try expect(xcscheme.launchAction?.storeKitConfigurationFileReference?.identifier) == "../Configuration.storekit" } $0.it("generates scheme with host target build action for watch") { @@ -362,9 +448,283 @@ class SchemeGeneratorTests: XCTestCase { try expect(buildEntries.count) == 2 try expect(buildEntries.first?.buildableReference.blueprintName) == "WatchApp" try expect(buildEntries.last?.buildableReference.blueprintName) == "HostApp" + try expect(xcscheme.launchAction?.storeKitConfigurationFileReference?.identifier) == "../Configuration.storekit" + } + + $0.it("generates scheme with extension target and specify macroExpansion") { + let app = Target( + name: "MyApp", + type: .application, + platform: .iOS, + dependencies: [Dependency(type: .target, reference: "MyAppExtension", embed: false)] + ) + + let `extension` = Target( + name: "MyAppExtension", + type: .appExtension, + platform: .iOS + ) + let appTarget = Scheme.BuildTarget(target: .local(app.name), buildTypes: [.running]) + let extensionTarget = Scheme.BuildTarget(target: .local(`extension`.name), buildTypes: [.running]) + + let scheme = Scheme( + name: "TestScheme", + build: Scheme.Build(targets: [appTarget, extensionTarget]), + run: Scheme.Run(config: "Debug", macroExpansion: "MyApp") + ) + let project = Project( + name: "test", + targets: [app, `extension`], + schemes: [scheme] + ) + let xcodeProject = try project.generateXcodeProject() + + let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first) + try expect(xcscheme.testAction?.macroExpansion?.buildableName) == "MyApp.app" + try expect(xcscheme.launchAction?.macroExpansion?.buildableName) == "MyApp.app" + } + + $0.it("allows to override test macroExpansion") { + let app = Target( + name: "MyApp", + type: .application, + platform: .iOS, + dependencies: [Dependency(type: .target, reference: "MyAppExtension", embed: false)] + ) + + let `extension` = Target( + name: "MyAppExtension", + type: .appExtension, + platform: .iOS + ) + let appTarget = Scheme.BuildTarget(target: .local(app.name), buildTypes: [.running]) + let extensionTarget = Scheme.BuildTarget(target: .local(`extension`.name), buildTypes: [.running]) + + let scheme = Scheme( + name: "TestScheme", + build: Scheme.Build(targets: [appTarget, extensionTarget]), + run: Scheme.Run(config: "Debug", macroExpansion: "MyApp"), + test: .init(macroExpansion: "MyAppExtension") + ) + let project = Project( + name: "test", + targets: [app, `extension`], + schemes: [scheme] + ) + let xcodeProject = try project.generateXcodeProject() + + let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first) + try expect(xcscheme.testAction?.macroExpansion?.buildableName) == "MyAppExtension.appex" + try expect(xcscheme.launchAction?.macroExpansion?.buildableName) == "MyApp.app" + } + + $0.it("generates scheme with macroExpansion from tests when the main target is not part of the scheme") { + let app = Target( + name: "MyApp", + type: .application, + platform: .iOS, + dependencies: [] + ) + + let mockApp = Target( + name: "MockApp", + type: .application, + platform: .iOS, + dependencies: [] + ) + + let testBundle = Target( + name: "TestBundle", + type: .unitTestBundle, + platform: .iOS + ) + let appTarget = Scheme.BuildTarget(target: .local(app.name), buildTypes: [.running]) + let mockAppTarget = Scheme.BuildTarget(target: .local(mockApp.name), buildTypes: [.testing]) + let testBundleTarget = Scheme.BuildTarget(target: .local(testBundle.name), buildTypes: [.testing]) + + let scheme = Scheme( + name: "TestScheme", + build: Scheme.Build(targets: [appTarget, mockAppTarget, testBundleTarget]), + run: Scheme.Run(config: "Debug", macroExpansion: "MyApp") + ) + let project = Project( + name: "test", + targets: [app, mockApp, testBundle], + schemes: [scheme] + ) + let xcodeProject = try project.generateXcodeProject() + + let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first) + try expect(xcscheme.testAction?.macroExpansion?.buildableName) == "MockApp.app" + } + + $0.it("generates scheme with test target of local swift package") { + let targetScheme = TargetScheme( + testTargets: [Scheme.Test.TestTarget(targetReference: TestableTargetReference(name: "XcodeGenKitTests", location: .package("XcodeGen")))]) + let app = Target( + name: "MyApp", + type: .application, + platform: .iOS, + dependencies: [ + Dependency(type: .package(products: []), reference: "XcodeGen") + ], + scheme: targetScheme + ) + let project = Project( + name: "ios_test", + targets: [app], + packages: ["XcodeGen": .local(path: "../", group: nil, excludeFromProject: false)] + ) + let xcodeProject = try project.generateXcodeProject() + let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first) + let buildableReference = try unwrap(xcscheme.testAction?.testables.first?.buildableReference) + + try expect(buildableReference.blueprintIdentifier) == "XcodeGenKitTests" + try expect(buildableReference.blueprintName) == "XcodeGenKitTests" + try expect(buildableReference.buildableName) == "XcodeGenKitTests" + try expect(buildableReference.referencedContainer) == "container:../" + } + + $0.it("generates scheme capturing screenshots automatically and deleting on success") { + let xcscheme = try self.makeSnapshotScheme( + buildTarget: buildTarget, + captureScreenshotsAutomatically: true, + deleteScreenshotsWhenEachTestSucceeds: true) + + try expect(xcscheme.testAction?.systemAttachmentLifetime).to.beNil() + } + + $0.it("generates scheme capturing screenshots and not deleting") { + let xcscheme = try self.makeSnapshotScheme( + buildTarget: buildTarget, + captureScreenshotsAutomatically: true, + deleteScreenshotsWhenEachTestSucceeds: false) + + try expect(xcscheme.testAction?.systemAttachmentLifetime) == .keepAlways + } + + $0.it("generates scheme not capturing screenshots") { + let xcscheme = try self.makeSnapshotScheme( + buildTarget: buildTarget, + captureScreenshotsAutomatically: false, + deleteScreenshotsWhenEachTestSucceeds: false) + + try expect(xcscheme.testAction?.systemAttachmentLifetime) == .keepNever + } + + $0.it("ignores screenshot delete preference when not capturing screenshots") { + let xcscheme = try self.makeSnapshotScheme( + buildTarget: buildTarget, + captureScreenshotsAutomatically: false, + deleteScreenshotsWhenEachTestSucceeds: true) + + try expect(xcscheme.testAction?.systemAttachmentLifetime) == .keepNever + } + + $0.it("generate test plans ") { + + let testPlanPath1 = "\(fixturePath.string)/TestProject/App_iOS/App_iOS.xctestplan" + let testPlanPath2 = "\(fixturePath.string)/TestProject/App_iOS/App_iOS.xctestplan" + + let scheme = Scheme( + name: "TestScheme", + build: Scheme.Build(targets: [buildTarget]), + test: Scheme.Test(config: "Debug", testPlans: [ + .init(path: testPlanPath1, defaultPlan: false), + .init(path: testPlanPath2, defaultPlan: true), + ]) + ) + let project = Project( + name: "test", + targets: [app, framework], + schemes: [scheme] + ) + let xcodeProject = try project.generateXcodeProject() + + let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first) + try expect(xcscheme.testAction?.testPlans) == [ + .init(reference: "container:\(testPlanPath1)", default: false), + .init(reference: "container:\(testPlanPath2)", default: true), + ] + } + + $0.it("generates scheme with screenshots as preferred screen capture format") { + let scheme = Scheme( + name: "MyScheme", + build: Scheme.Build(targets: [buildTarget]), + run: Scheme.Run(config: "Debug"), + test: Scheme.Test(config: "Debug", preferredScreenCaptureFormat: .screenshots) + ) + let project = Project( + name: "test", + targets: [app, framework], + schemes: [scheme] + ) + let xcodeProject = try project.generateXcodeProject() + + let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first) + try expect(xcscheme.testAction?.preferredScreenCaptureFormat) == .screenshots + } + + $0.it("generates scheme with screen recording as preferred screen capture format") { + let scheme = Scheme( + name: "MyScheme", + build: Scheme.Build(targets: [buildTarget]), + run: Scheme.Run(config: "Debug"), + test: Scheme.Test(config: "Debug", preferredScreenCaptureFormat: .screenRecording) + ) + let project = Project( + name: "test", + targets: [app, framework], + schemes: [scheme] + ) + let xcodeProject = try project.generateXcodeProject() + + let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first) + try expect(xcscheme.testAction?.preferredScreenCaptureFormat) == .screenRecording } } } + + func testOverrideLastUpgradeVersionWhenUserDidSpecify() throws { + var target = app + target.scheme = TargetScheme() + + let lastUpgradeKey = "LastUpgradeCheck" + let lastUpgradeValue = "1234" + let attributes: [String: Any] = [lastUpgradeKey: lastUpgradeValue] + let project = Project(name: "test", targets: [target, framework], attributes: attributes) + let xcodeProject = try project.generateXcodeProject() + + let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first) + XCTAssertEqual(xcscheme.lastUpgradeVersion, lastUpgradeValue) + } + + + func testDefaultLastUpgradeVersionWhenUserDidNotSpecify() throws { + var target = app + target.scheme = TargetScheme() + + let project = Project(name: "test", targets: [target, framework]) + let xcodeProject = try project.generateXcodeProject() + + let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first) + XCTAssertEqual(xcscheme.lastUpgradeVersion, project.xcodeVersion) + } + + func testGenerateSchemeManagementOnHiddenTargetScheme() throws { + var target = app + target.scheme = TargetScheme(management: Scheme.Management(isShown: false)) + + let project = Project(name: "test", targets: [target, framework]) + let xcodeProject = try project.generateXcodeProject() + + let xcSchemeManagement = try XCTUnwrap(xcodeProject.userData.first?.schemeManagement) + XCTAssertEqual(xcSchemeManagement.schemeUserState![0].name, "MyApp.xcscheme") + XCTAssertEqual(xcSchemeManagement.schemeUserState![0].shared, true) + XCTAssertEqual(xcSchemeManagement.schemeUserState![0].isShown, false) + XCTAssertEqual(xcSchemeManagement.schemeUserState![0].orderHint, nil) + } // MARK: - Helpers @@ -379,7 +739,7 @@ class SchemeGeneratorTests: XCTestCase { type: appType, platform: .watchOS, dependencies: [Dependency(type: .target, reference: watchExtension.name)], - scheme: TargetScheme() + scheme: TargetScheme(storeKitConfiguration: "Configuration.storekit") ) let hostApp = Target( name: "HostApp", @@ -389,7 +749,24 @@ class SchemeGeneratorTests: XCTestCase { ) let project = Project( name: "watch_test", - targets: [hostApp, watchApp, watchExtension] + targets: [hostApp, watchApp, watchExtension], + options: .init(schemePathPrefix: "../") + ) + let xcodeProject = try project.generateXcodeProject() + return try unwrap(xcodeProject.sharedData?.schemes.first) + } + + private func makeSnapshotScheme(buildTarget: Scheme.BuildTarget, captureScreenshotsAutomatically: Bool, deleteScreenshotsWhenEachTestSucceeds: Bool) throws -> XCScheme { + let scheme = Scheme( + name: "MyScheme", + build: Scheme.Build(targets: [buildTarget]), + run: Scheme.Run(config: "Debug"), + test: Scheme.Test(config: "Debug", captureScreenshotsAutomatically: captureScreenshotsAutomatically, deleteScreenshotsWhenEachTestSucceeds: deleteScreenshotsWhenEachTestSucceeds) + ) + let project = Project( + name: "test", + targets: [app, framework], + schemes: [scheme] ) let xcodeProject = try project.generateXcodeProject() return try unwrap(xcodeProject.sharedData?.schemes.first) diff --git a/Tests/XcodeGenKitTests/SourceGeneratorTests.swift b/Tests/XcodeGenKitTests/SourceGeneratorTests.swift index 162ac17cf..4e109ab2f 100644 --- a/Tests/XcodeGenKitTests/SourceGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/SourceGeneratorTests.swift @@ -1,7 +1,7 @@ import PathKit import ProjectSpec import Spectre -import XcodeGenKit +@testable import XcodeGenKit import XcodeProj import XCTest import Yams @@ -9,7 +9,8 @@ import TestSupport class SourceGeneratorTests: XCTestCase { - func testSourceGenerator() { + func testSourceGenerator() throws { + try skipIfNecessary() describe { let directoryPath = Path("TestDirectory") @@ -41,6 +42,13 @@ class SourceGeneratorTests: XCTestCase { try file.write("") } } + + func createFile(at relativePath: Path, content: String) throws -> Path { + let filePath = directoryPath + relativePath + try filePath.parent().mkpath() + try filePath.write(content) + return filePath + } func removeDirectories() { try? directoryPath.delete() @@ -76,6 +84,42 @@ class SourceGeneratorTests: XCTestCase { try pbxProj.expectFile(paths: ["Sources", "A", "C2.0", "c.swift"], buildPhase: .sources) } + $0.it("generates synced folder") { + let directories = """ + Sources: + A: + - a.swift + """ + try createDirectories(directories) + + let target = Target(name: "Test", type: .application, platform: .iOS, sources: [.init(path: "Sources", type: .syncedFolder)]) + let project = Project(basePath: directoryPath, name: "Test", targets: [target]) + + let pbxProj = try project.generatePbxProj() + let syncedFolders = try pbxProj.getMainGroup().children.compactMap { $0 as? PBXFileSystemSynchronizedRootGroup } + let syncedFolder = try unwrap(syncedFolders.first) + + try expect([syncedFolder]) == pbxProj.nativeTargets.first?.fileSystemSynchronizedGroups + } + + $0.it("respects defaultSourceDirectoryType") { + let directories = """ + Sources: + A: + - a.swift + """ + try createDirectories(directories) + + let target = Target(name: "Test", type: .application, platform: .iOS, sources: ["Sources"]) + let project = Project(basePath: directoryPath, name: "Test", targets: [target], options: .init(defaultSourceDirectoryType: .syncedFolder)) + + let pbxProj = try project.generatePbxProj() + let syncedFolders = try pbxProj.getMainGroup().children.compactMap { $0 as? PBXFileSystemSynchronizedRootGroup } + let syncedFolder = try unwrap(syncedFolders.first) + + try expect([syncedFolder]) == pbxProj.nativeTargets.first?.fileSystemSynchronizedGroups + } + $0.it("supports frameworks in sources") { let directories = """ Sources: @@ -492,7 +536,7 @@ class SourceGeneratorTests: XCTestCase { let pbxProj = try project.generatePbxProj() try pbxProj.expectFile(paths: ["Sources", "A", "b.swift"], buildPhase: .sources) try pbxProj.expectFile(paths: ["Sources", "F", "G", "h.swift"], buildPhase: .sources) - try pbxProj.expectFile(paths: ["../OtherDirectory/C/D", "e.swift"], names: ["D", "e.swift"], buildPhase: .sources) + try pbxProj.expectFile(paths: ["..", "OtherDirectory", "C", "D", "e.swift"], names: [".", "OtherDirectory", "C", "D", "e.swift"], buildPhase: .sources) try pbxProj.expectFile(paths: ["Sources/B", "b.swift"], names: ["B", "b.swift"], buildPhase: .sources) } @@ -559,13 +603,14 @@ class SourceGeneratorTests: XCTestCase { - file.swift - file.xcassets - file.h - - Info.plist + - GoogleService-Info.plist - file.xcconfig + - Localizable.xcstrings B: - file.swift - file.xcassets - file.h - - Info.plist + - Sample.plist - file.xcconfig C: - file.swift @@ -589,20 +634,24 @@ class SourceGeneratorTests: XCTestCase { - file.xcassets - file.metal - file.mlmodel + - file.mlpackage + - file.mlmodelc - Info.plist - Intent.intentdefinition + - Configuration.storekit - Settings.bundle: - en.lproj: - Root.strings - Root.plist - WithPeriod2.0: - file.swift + - Documentation.docc """ try createDirectories(directories) let target = Target(name: "Test", type: .framework, platform: .iOS, sources: [ TargetSource(path: "A", buildPhase: .resources), - TargetSource(path: "B", buildPhase: TargetSource.BuildPhase.none), + TargetSource(path: "B", buildPhase: BuildPhaseSpec.none), TargetSource(path: "C", buildPhase: nil), ]) let project = Project(basePath: directoryPath, name: "Test", targets: [target]) @@ -611,14 +660,15 @@ class SourceGeneratorTests: XCTestCase { try pbxProj.expectFile(paths: ["A", "file.swift"], buildPhase: .resources) try pbxProj.expectFile(paths: ["A", "file.xcassets"], buildPhase: .resources) try pbxProj.expectFile(paths: ["A", "file.h"], buildPhase: .resources) - try pbxProj.expectFile(paths: ["A", "Info.plist"], buildPhase: .resources) + try pbxProj.expectFile(paths: ["A", "GoogleService-Info.plist"], buildPhase: .resources) try pbxProj.expectFile(paths: ["A", "file.xcconfig"], buildPhase: .resources) + try pbxProj.expectFile(paths: ["A", "Localizable.xcstrings"], buildPhase: .resources) - try pbxProj.expectFile(paths: ["B", "file.swift"], buildPhase: TargetSource.BuildPhase.none) - try pbxProj.expectFile(paths: ["B", "file.xcassets"], buildPhase: TargetSource.BuildPhase.none) - try pbxProj.expectFile(paths: ["B", "file.h"], buildPhase: TargetSource.BuildPhase.none) - try pbxProj.expectFile(paths: ["B", "Info.plist"], buildPhase: TargetSource.BuildPhase.none) - try pbxProj.expectFile(paths: ["B", "file.xcconfig"], buildPhase: TargetSource.BuildPhase.none) + try pbxProj.expectFile(paths: ["B", "file.swift"], buildPhase: BuildPhaseSpec.none) + try pbxProj.expectFile(paths: ["B", "file.xcassets"], buildPhase: BuildPhaseSpec.none) + try pbxProj.expectFile(paths: ["B", "file.h"], buildPhase: BuildPhaseSpec.none) + try pbxProj.expectFile(paths: ["B", "Sample.plist"], buildPhase: BuildPhaseSpec.none) + try pbxProj.expectFile(paths: ["B", "file.xcconfig"], buildPhase: BuildPhaseSpec.none) try pbxProj.expectFile(paths: ["C", "file.swift"], buildPhase: .sources) try pbxProj.expectFile(paths: ["C", "file.m"], buildPhase: .sources) @@ -633,25 +683,150 @@ class SourceGeneratorTests: XCTestCase { try pbxProj.expectFile(paths: ["C", "file.tpp"], buildPhase: .headers) try pbxProj.expectFile(paths: ["C", "file.hxx"], buildPhase: .headers) try pbxProj.expectFile(paths: ["C", "file.def"], buildPhase: .headers) - try pbxProj.expectFile(paths: ["C", "file.xcconfig"], buildPhase: TargetSource.BuildPhase.none) - try pbxProj.expectFile(paths: ["C", "file.entitlements"], buildPhase: TargetSource.BuildPhase.none) - try pbxProj.expectFile(paths: ["C", "file.gpx"], buildPhase: TargetSource.BuildPhase.none) - try pbxProj.expectFile(paths: ["C", "file.apns"], buildPhase: TargetSource.BuildPhase.none) - try pbxProj.expectFile(paths: ["C", "file.xcconfig"], buildPhase: TargetSource.BuildPhase.none) - try pbxProj.expectFile(paths: ["C", "file.xcconfig"], buildPhase: TargetSource.BuildPhase.none) - try pbxProj.expectFile(paths: ["C", "file.xcconfig"], buildPhase: TargetSource.BuildPhase.none) + try pbxProj.expectFile(paths: ["C", "file.xcconfig"], buildPhase: BuildPhaseSpec.none) + try pbxProj.expectFile(paths: ["C", "file.entitlements"], buildPhase: BuildPhaseSpec.none) + try pbxProj.expectFile(paths: ["C", "file.gpx"], buildPhase: BuildPhaseSpec.none) + try pbxProj.expectFile(paths: ["C", "file.apns"], buildPhase: BuildPhaseSpec.none) + try pbxProj.expectFile(paths: ["C", "file.xcconfig"], buildPhase: BuildPhaseSpec.none) + try pbxProj.expectFile(paths: ["C", "file.xcconfig"], buildPhase: BuildPhaseSpec.none) + try pbxProj.expectFile(paths: ["C", "file.xcconfig"], buildPhase: BuildPhaseSpec.none) try pbxProj.expectFile(paths: ["C", "file.xcassets"], buildPhase: .resources) try pbxProj.expectFile(paths: ["C", "file.123"], buildPhase: .resources) - try pbxProj.expectFile(paths: ["C", "Info.plist"], buildPhase: TargetSource.BuildPhase.none) + 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.mlpackage"], 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) try pbxProj.expectFileMissing(paths: ["C", "Settings.bundle", "en.lproj"]) try pbxProj.expectFileMissing(paths: ["C", "Settings.bundle", "en.lproj", "Root.strings"]) try pbxProj.expectFileMissing(paths: ["C", "Settings.bundle", "Root.plist"]) try pbxProj.expectFileMissing(paths: ["C", "WithPeriod2.0"]) try pbxProj.expectFile(paths: ["C", "WithPeriod2.0", "file.swift"], buildPhase: .sources) + try pbxProj.expectFile(paths: ["C", "Documentation.docc"], buildPhase: .sources) + } + + $0.it("only omits the defined Info.plist from resource build phases but not other plists") { + try createDirectories(""" + A: + - A-Info.plist + B: + - Info.plist + - GoogleServices-Info.plist + C: + - Info.plist + - Info-Production.plist + D: + - Info-Staging.plist + - Info-Production.plist + """) + + // Explicit plist.path value is respected + let targetA = Target( + name: "A", + type: .application, + platform: .iOS, + sources: ["A"], + info: Plist(path: "A/A-Info.plist") + ) + + // Automatically picks first 'Info.plist' at the top-level + let targetB = Target( + name: "B", + type: .application, + platform: .iOS, + sources: ["B"] + ) + + // Also respects INFOPLIST_FILE, ignores other files named Info.plist + let targetC = Target( + name: "C", + type: .application, + platform: .iOS, + settings: Settings(dictionary: [ + "INFOPLIST_FILE": "C/Info-Production.plist" + ]), + sources: ["C"] + ) + + // Does not support INFOPLIST_FILE value that requires expanding + let targetD = Target( + name: "D", + type: .application, + platform: .iOS, + settings: Settings(dictionary: [ + "ENVIRONMENT": "Production", + "INFOPLIST_FILE": "D/Info-${ENVIRONMENT}.plist" + ]), + sources: ["D"] + ) + + let project = Project(basePath: directoryPath.absolute(), name: "Test", targets: [targetA, targetB, targetC, targetD]) + let pbxProj = try project.generatePbxProj() + + try pbxProj.expectFile(paths: ["A", "A-Info.plist"], buildPhase: BuildPhaseSpec.none) + + try pbxProj.expectFile(paths: ["B", "Info.plist"], buildPhase: BuildPhaseSpec.none) + try pbxProj.expectFile(paths: ["B", "GoogleServices-Info.plist"], buildPhase: .resources) + + try pbxProj.expectFile(paths: ["C", "Info.plist"], buildPhase: .resources) + try pbxProj.expectFile(paths: ["C", "Info-Production.plist"], buildPhase: BuildPhaseSpec.none) + + try pbxProj.expectFile(paths: ["D", "Info-Staging.plist"], buildPhase: .resources) + try pbxProj.expectFile(paths: ["D", "Info-Production.plist"], buildPhase: .resources) + } + + $0.it("sets file type properties") { + let directories = """ + A: + - file.resource1 + - file.source1 + - file.abc: + - file.a + - file.exclude1 + - file.unphased1 + - ignored.swift + """ + try createDirectories(directories) + + let target = Target(name: "Test", type: .framework, platform: .iOS, sources: [ + TargetSource(path: "A"), + ]) + let project = Project(basePath: directoryPath, name: "Test", targets: [target], options: .init(fileTypes: [ + "abc": FileType(buildPhase: .sources), + "source1": FileType(buildPhase: .sources, attributes: ["a1", "a2"], resourceTags: ["r1", "r2"], compilerFlags: ["-c1", "-c2"]), + "resource1": FileType(buildPhase: .resources, attributes: ["a1", "a2"], resourceTags: ["r1", "r2"], compilerFlags: ["-c1", "-c2"]), + "unphased1": FileType(buildPhase: BuildPhaseSpec.none), + "swift": FileType(buildPhase: .resources), + ])) + + let pbxProj = try project.generatePbxProj() + try pbxProj.expectFile(paths: ["A", "file.abc"], buildPhase: .sources) + try pbxProj.expectFile(paths: ["A", "file.source1"], buildPhase: .sources) + try pbxProj.expectFile(paths: ["A", "file.resource1"], buildPhase: .resources) + try pbxProj.expectFile(paths: ["A", "file.unphased1"], buildPhase: BuildPhaseSpec.none) + try pbxProj.expectFile(paths: ["A", "ignored.swift"], buildPhase: .resources) + + do { + let fileReference = try unwrap(pbxProj.getFileReference(paths: ["A", "file.resource1"], names: ["A", "file.resource1"])) + let buildFile = try unwrap(pbxProj.buildFiles.first(where: { $0.file === fileReference })) + let settings = NSDictionary(dictionary: buildFile.settings ?? [:]) + try expect(settings) == [ + "ATTRIBUTES": ["a1", "a2"], + "ASSET_TAGS": ["r1", "r2"], + ] + } + do { + let fileReference = try unwrap(pbxProj.getFileReference(paths: ["A", "file.source1"], names: ["A", "file.source1"])) + let buildFile = try unwrap(pbxProj.buildFiles.first(where: { $0.file === fileReference })) + let settings = NSDictionary(dictionary: buildFile.settings ?? [:]) + try expect(settings) == [ + "ATTRIBUTES": ["a1", "a2"], + "COMPILER_FLAGS": "-c1 -c2", + ] + } } $0.it("duplicate TargetSource is included once in sources build phase") { @@ -915,6 +1090,39 @@ class SourceGeneratorTests: XCTestCase { try pbxProj.expectFileMissing(paths: ["Sources", "group", "file.swift"]) } + $0.it("handles includes with no matches correctly") { + let directories = """ + Sources: + - file3.swift + - file3Tests.swift + - file2.swift + - file2Tests.swift + - group2: + - file.swift + - fileTests.swift + - group: + - file.swift + """ + try createDirectories(directories) + + let includes = [ + "**/*NonExistent.*", + ] + + let target = Target(name: "Test", type: .application, platform: .iOS, sources: [TargetSource(path: "Sources", includes: includes)]) + + let project = Project(basePath: directoryPath, name: "Test", targets: [target]) + let pbxProj = try project.generatePbxProj() + + try pbxProj.expectFileMissing(paths: ["Sources", "file2.swift"]) + try pbxProj.expectFileMissing(paths: ["Sources", "file3.swift"]) + try pbxProj.expectFileMissing(paths: ["Sources", "file2Tests.swift"]) + try pbxProj.expectFileMissing(paths: ["Sources", "file3Tests.swift"]) + try pbxProj.expectFileMissing(paths: ["Sources", "group2", "file.swift"]) + try pbxProj.expectFileMissing(paths: ["Sources", "group2", "fileTests.swift"]) + try pbxProj.expectFileMissing(paths: ["Sources", "group", "file.swift"]) + } + $0.it("prioritizes excludes over includes when both are present") { let directories = """ Sources: @@ -1076,6 +1284,69 @@ class SourceGeneratorTests: XCTestCase { try expect(pbxProj.rootObject!.attributes["knownAssetTags"] as? [String]) == ["tag1", "tag2", "tag3"] } + + $0.it("Detects all locales present in a String Catalog") { + /// This is a catalog with gaps: + /// - String "foo" is translated into English (en) and Spanish (es) + /// - String "bar" is translated into English (en) and Italian (it) + /// + /// It is aimed at representing real world scenarios where translators have not finished translating all strings into their respective languages. + /// The expectation in this kind of cases is that `includedLocales` returns all locales found at least once in the catalog. + /// In this example, `includedLocales` is expected to be a set only containing "en", "es" and "it". + let stringCatalogContent = """ + { + "sourceLanguage" : "en", + "strings" : { + "foo" : { + "comment" : "Sample string in an asset catalog", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Foo English" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Foo Spanish" + } + } + } + }, + "bar" : { + "comment" : "Another sample string in an asset catalog", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bar English" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bar Italian" + } + } + } + } + }, + "version" : "1.0" + } + """ + + let testStringCatalogRelativePath = Path("Localizable.xcstrings") + let testStringCatalogPath = try createFile(at: testStringCatalogRelativePath, content: stringCatalogContent) + + guard let stringCatalog = StringCatalog(from: testStringCatalogPath) else { + throw failure("Failed decoding string catalog from \(testStringCatalogPath)") + } + + try expect(stringCatalog.includedLocales.sorted(by: { $0 < $1 })) == ["en", "es", "it"] + } } } } @@ -1084,7 +1355,7 @@ class SourceGeneratorTests: XCTestCase { extension PBXProj { /// expect a file within groups of the paths, using optional different names - func expectFile(paths: [String], names: [String]? = nil, buildPhase: TargetSource.BuildPhase? = nil, file: String = #file, line: Int = #line) throws { + func expectFile(paths: [String], names: [String]? = nil, buildPhase: BuildPhaseSpec? = nil, file: String = #file, line: Int = #line) throws { guard let fileReference = getFileReference(paths: paths, names: names ?? paths) else { var error = "Could not find file at path \(paths.joined(separator: "/").quoted)" if let names = names, names != paths { diff --git a/scripts/archive.sh b/scripts/archive.sh index 7ec329e49..0a9ebb585 100755 --- a/scripts/archive.sh +++ b/scripts/archive.sh @@ -10,7 +10,7 @@ LICENSE=LICENSE # copy mkdir -p $BINDIR -cp -f .build/release/$EXECUTABLE_NAME $BINDIR +cp -f "$1" $BINDIR mkdir -p $SHAREDIR cp -R SettingPresets $SHAREDIR/SettingPresets diff --git a/scripts/diff-fixtures.sh b/scripts/diff-fixtures.sh index d7a2f041a..5b5a7919f 100755 --- a/scripts/diff-fixtures.sh +++ b/scripts/diff-fixtures.sh @@ -3,7 +3,7 @@ set -e if [[ `git status --porcelain Tests/Fixtures` ]]; then echo "" - echo "⚠️ Generated fixturess have changed." + echo "⚠️ Generated fixtures have changed." echo "⚠️ If this is a valid change please run the tests and commit the updates." echo "" git --no-pager diff --color=always Tests/Fixtures