mirror of
https://github.com/yonaskolb/XcodeGen.git
synced 2026-03-18 20:02:25 +00:00
Merge branch 'master' into copy-files-ordering
This commit is contained in:
+15
-11
@@ -1,23 +1,27 @@
|
||||
version: 2
|
||||
jobs:
|
||||
macOS_swift_4.1:
|
||||
macos:
|
||||
xcode: "9.3.0"
|
||||
steps:
|
||||
- checkout
|
||||
- run: swift build
|
||||
- run: swift test
|
||||
- run: make build
|
||||
macOS_swift_4.2:
|
||||
macos:
|
||||
xcode: "10.0.0"
|
||||
steps:
|
||||
- checkout
|
||||
- run: swift build
|
||||
- run: make build
|
||||
- run:
|
||||
name: Build
|
||||
command: swift build
|
||||
- run:
|
||||
name: Test
|
||||
command: swift test 2>&1 | xcpretty
|
||||
- run:
|
||||
name: Check Project Diff
|
||||
command: ./diff-fixtures.sh
|
||||
- run:
|
||||
name: Build Test Project
|
||||
command: ./build-fixtures.sh
|
||||
- run:
|
||||
name: Build release
|
||||
command: make build
|
||||
workflows:
|
||||
version: 2
|
||||
workflow:
|
||||
jobs:
|
||||
- macOS_swift_4.1
|
||||
- macOS_swift_4.2
|
||||
|
||||
@@ -6,3 +6,4 @@ xcuserdata
|
||||
*.xccheckout
|
||||
*.xcuserstate
|
||||
XcodeGen.xcodeproj
|
||||
xcodegen.zip
|
||||
|
||||
+200
-173
@@ -6,23 +6,50 @@
|
||||
- Allow more granular phase ordering for Copy File and Run Script phases. [402](https://github.com/yonaskolb/XcodeGen/pull/402) @brentleyjones
|
||||
|
||||
#### Fixed
|
||||
- Fixed XPC Service package type [#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
|
||||
|
||||
#### Changed
|
||||
- Changed spelling of build phases to **preBuildPhase** and **postBuildPhase**. [402](https://github.com/yonaskolb/XcodeGen/pull/402) @brentleyjones
|
||||
|
||||
## 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
|
||||
|
||||
#### 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
|
||||
|
||||
#### 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)
|
||||
|
||||
## 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](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
|
||||
|
||||
#### Changed
|
||||
- Added `en` as default value for knownRegions [390](https://github.com/yonaskolb/XcodeGen/pull/390) @Saik0s
|
||||
- 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)
|
||||
@@ -30,43 +57,43 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil
|
||||
## 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
|
||||
- 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)
|
||||
|
||||
## 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
|
||||
- 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
|
||||
- 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
|
||||
- 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
|
||||
|
||||
#### Internal
|
||||
- Moved brew formula to homebrew core
|
||||
@@ -77,7 +104,7 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil
|
||||
## 1.10.3
|
||||
|
||||
#### Fixed
|
||||
- Fixed Mint installations finding `SettingPresets` [338](https://github.com/yonaskolb/XcodeGen/pull/338) @yonaskolb
|
||||
- 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)
|
||||
|
||||
@@ -91,72 +118,72 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil
|
||||
## 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](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
|
||||
|
||||
#### Changed
|
||||
- Code sign all dependencies by default except target executables [332](https://github.com/yonaskolb/XcodeGen/pull/332) @yonaskolb
|
||||
- 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)
|
||||
|
||||
## 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](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
|
||||
|
||||
#### 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
|
||||
- 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
|
||||
- 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
|
||||
- Fixed generated framework schemes from being executable [#328](https://github.com/yonaskolb/XcodeGen/pull/328) @brentleyjones
|
||||
|
||||
[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.9.0...1.10.0)
|
||||
|
||||
## 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](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
|
||||
|
||||
#### 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](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
|
||||
|
||||
#### 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
|
||||
- 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)
|
||||
|
||||
## 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](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
|
||||
|
||||
#### 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](https://github.com/yonaskolb/XcodeGen/pull/272) @LinusU
|
||||
|
||||
#### Internal
|
||||
- Make `LegacyTarget` init public [264](https://github.com/yonaskolb/XcodeGen/pull/264) @jerrymarino
|
||||
- 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)
|
||||
@@ -165,113 +192,113 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil
|
||||
|
||||
#### 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](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
|
||||
@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](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
|
||||
- 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
|
||||
- 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)
|
||||
|
||||
## 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](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
|
||||
|
||||
#### 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](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
|
||||
- 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)
|
||||
- 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)
|
||||
|
||||
## 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](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
|
||||
|
||||
#### 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](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
|
||||
|
||||
#### 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 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
|
||||
- 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)
|
||||
|
||||
## 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](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
|
||||
|
||||
#### 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](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
|
||||
|
||||
#### 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](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
|
||||
|
||||
#### Internal
|
||||
- refactoring
|
||||
@@ -283,26 +310,26 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil
|
||||
## 1.3.0
|
||||
|
||||
#### Added
|
||||
- generate output files for Carthage copy-frameworks script [84](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](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
|
||||
|
||||
#### 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](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
|
||||
- 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
|
||||
- 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)
|
||||
@@ -322,8 +349,8 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil
|
||||
## 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](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
|
||||
- Added some missing default settings for framework targets. `SKIP_INSTALL: YES` fixes archiving
|
||||
- Filter out nulls from setting presets if specifying an empty string
|
||||
|
||||
@@ -345,17 +372,17 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil
|
||||
|
||||
#### Added
|
||||
- `include` now supports a single string as well as a list
|
||||
- add support setting xcconfig files on a project with `configFiles` [PR#64](https://github.com/yonaskolb/XcodeGen/pull/64)
|
||||
- add `fileGroups` to project spec for adding groups of files that aren't target source files [PR#64](https://github.com/yonaskolb/XcodeGen/pull/64)
|
||||
- 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)
|
||||
- better output (more info, emoji, colors)
|
||||
- add `options.bundleIdPrefix` for autogenerating `PRODUCT_BUNDLE_IDENTIFIER` [PR#67](https://github.com/yonaskolb/XcodeGen/pull/67)
|
||||
- add `:REPLACE` syntax when merging `include` [PR#68](https://github.com/yonaskolb/XcodeGen/pull/68)
|
||||
- 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 `mint` installation support
|
||||
|
||||
#### Fixed
|
||||
- fixed homebrew installation
|
||||
- fixed target xcconfig files not working via `configFiles` [PR#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 [PR#64](https://github.com/yonaskolb/XcodeGen/pull/64)
|
||||
- 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)
|
||||
- exit with error on failure
|
||||
|
||||
[Commits](https://github.com/yonaskolb/XcodeGen/compare/1.1.0...1.2.0)
|
||||
@@ -379,16 +406,16 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil
|
||||
## 1.0.0
|
||||
|
||||
#### Added
|
||||
- Swift 4 support [PR#52](https://github.com/yonaskolb/XcodeGen/pull/52)
|
||||
- Support for C and C++ files [PR#48](https://github.com/yonaskolb/XcodeGen/pull/48) by @antoniocasero
|
||||
- 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
|
||||
- Xcode 9 default settings
|
||||
|
||||
#### Fixed
|
||||
- fixed empty string in YAML not being parsed properly [PR#50](https://github.com/yonaskolb/XcodeGen/pull/50) by @antoniocasero
|
||||
- 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 [PR#56](https://github.com/yonaskolb/XcodeGen/pull/56)
|
||||
- **BREAKING**: changed target definitions from list to map [PR#54](https://github.com/yonaskolb/XcodeGen/pull/54) See [Project Spec](docs/ProjectSpec.md)
|
||||
- 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)
|
||||
|
||||
|
||||
[Commits](https://github.com/yonaskolb/XcodeGen/compare/0.6.1...1.0.0)
|
||||
@@ -396,18 +423,18 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil
|
||||
## 0.6.1
|
||||
|
||||
#### Added
|
||||
- Ability to set PBXProject attributes [PR#45](https://github.com/yonaskolb/XcodeGen/pull/45)
|
||||
- Ability to set PBXProject attributes [#45](https://github.com/yonaskolb/XcodeGen/pull/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 [PR#46](https://github.com/yonaskolb/XcodeGen/pull/46)
|
||||
- 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)
|
||||
|
||||
## 0.6.0
|
||||
|
||||
#### Added
|
||||
- Allow a project spec to include other project specs [PR#44](https://github.com/yonaskolb/XcodeGen/pull/44)
|
||||
- Allow a project spec to include other project specs [#44](https://github.com/yonaskolb/XcodeGen/pull/44)
|
||||
|
||||
#### Changed
|
||||
- Changed default spec path to `project.yml`
|
||||
@@ -420,16 +447,16 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil
|
||||
#### Fixed
|
||||
- Fix embedded framework dependencies
|
||||
- Add `CODE_SIGN_IDENTITY[sdk=iphoneos*]` back to iOS targets
|
||||
- Fix build scripts with "" generating invalid projects [PR#43](https://github.com/yonaskolb/XcodeGen/pull/43)
|
||||
- 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)
|
||||
|
||||
## 0.5.0
|
||||
#### Added
|
||||
- Added multi platform targets [PR#35](https://github.com/yonaskolb/XcodeGen/pull/35)
|
||||
- Automatically generate platform specific `FRAMEWORK_SEARCH_PATHS` for Carthage dependencies [PR#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 [PR#40](https://github.com/yonaskolb/XcodeGen/pull/40)
|
||||
- Add options for controlling embedding of dependencies [PR#37](https://github.com/yonaskolb/XcodeGen/pull/37)
|
||||
- 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)
|
||||
|
||||
#### Fixed
|
||||
- Fixed localized files not being added to a target's resources
|
||||
@@ -443,23 +470,23 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil
|
||||
## 0.4.0
|
||||
|
||||
##### Added
|
||||
- Homebrew support [PR#16](https://github.com/yonaskolb/XcodeGen/pull/16) by @pepibumur
|
||||
- Added `runOnlyWhenInstalling` to build scripts [PR#32](https://github.com/yonaskolb/XcodeGen/pull/32)
|
||||
- Added `carthageBuildPath` option [PR#34](https://github.com/yonaskolb/XcodeGen/pull/34)
|
||||
- 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)
|
||||
|
||||
#### 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 [PR#33](https://github.com/yonaskolb/XcodeGen/pull/33)
|
||||
- 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)
|
||||
|
||||
## 0.3.0 - Extensions and Scheme Tests
|
||||
|
||||
#### Added
|
||||
- Support for app extension dependencies, using the same `target: MyExtension` syntax [PR#19](https://github.com/yonaskolb/XcodeGen/pull/19)
|
||||
- Added test targets to generated target schemes via `Target.scheme.testTargets` [PR#21](https://github.com/yonaskolb/XcodeGen/pull/21)
|
||||
- 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)
|
||||
|
||||
#### Changed
|
||||
- Updated xcodeproj to 0.0.9
|
||||
@@ -475,7 +502,7 @@ If XcodeGen is compiled with Swift 4.2, then UUID's in the generated project wil
|
||||
## 0.2.0 - Build scripts
|
||||
|
||||
#### Added
|
||||
- Added Target build scripts with `Target.prebuildScripts` and `Target.postbuildScripts` [PR#17](https://github.com/yonaskolb/XcodeGen/pull/17)
|
||||
- Added Target build scripts with `Target.prebuildScripts` and `Target.postbuildScripts` [#17](https://github.com/yonaskolb/XcodeGen/pull/17)
|
||||
- Support for absolute paths in target sources, run script files, and config files
|
||||
- Add validation for incorrect `Target.configFiles`
|
||||
|
||||
|
||||
+41
-5
@@ -171,6 +171,16 @@ Settings are merged in the following order: groups, base, configs.
|
||||
- `FRAMEWORK_SEARCH_PATHS`: If carthage dependencies are used, the platform build path will be added to this setting
|
||||
- `OTHER_LDFLAGS`: See `requiresObjCLinking` below
|
||||
- [ ] **dependencies**: **[[Dependency](#dependency)]** - Dependencies for the target
|
||||
- [ ] **info**: **[Plist](#plist)** - If defined, this will generate and write an `Info.plist` to the specified path and use it by setting the `INFOPLIST_FILE` build setting for every configuration. The following properties are generated automatically, the rest will have to be provided.
|
||||
- `CFBundleIdentifier`
|
||||
- `CFBundleInfoDictionaryVersion`
|
||||
- `CFBundleExecutable`
|
||||
- `CFBundleName`
|
||||
- `CFBundleDevelopmentRegion`
|
||||
- `CFBundleShortVersionString`
|
||||
- `CFBundleVersion`
|
||||
- `CFBundlePackageType`
|
||||
- [ ] **entitlements**: **[Plist](#plist)** - If defined this will generate and write a `.entitlements` file, and use it by setting `CODE_SIGN_ENTITLEMENTS` build setting for every configuration. All properties must be provided
|
||||
- [ ] **templates**: **[String]** - A list of target templates that will be merged in order
|
||||
- [ ] **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.
|
||||
@@ -323,15 +333,15 @@ A dependency can be one of a 3 types:
|
||||
- `target: name` - links to another target
|
||||
- `framework: path` - links to a framework
|
||||
- `carthage: name` - helper for linking to a Carthage framework
|
||||
- `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)
|
||||
|
||||
**Embed options**:
|
||||
|
||||
These only applied to `target` and `framework` dependencies.
|
||||
**Linking options**:
|
||||
|
||||
- [ ] **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
|
||||
|
||||
**Implicit Framework options**:
|
||||
|
||||
@@ -356,6 +366,8 @@ targets:
|
||||
- target: MyFramework
|
||||
- framework: path/to/framework.framework
|
||||
- carthage: Result
|
||||
- sdk: Contacts.framework
|
||||
- sdk: libc++.tbd
|
||||
MyFramework:
|
||||
type: framework
|
||||
```
|
||||
@@ -374,6 +386,25 @@ targets:
|
||||
Debug: App/debug.xcconfig
|
||||
Release: App/release.xcconfig
|
||||
```
|
||||
### Plist
|
||||
Plists are created on disk on every generation of the project. They can be used as a way to define `Info.plist` or `.entitlement` files. Some `Info.plist` properties are generated automatically.
|
||||
|
||||
- [x] **path**: **String** - This is the path where the plist will be written to
|
||||
- [x] **properties**: **[String: Any]** - This is a map of all the plist keys and values
|
||||
|
||||
```yml
|
||||
targets:
|
||||
App:
|
||||
info:
|
||||
path: App/Info.plist
|
||||
properties:
|
||||
UISupportedInterfaceOrientations: [UIInterfaceOrientationPortrait]
|
||||
UILaunchStoryboardName: LaunchScreen
|
||||
entitlements:
|
||||
path: App/App.entitlements
|
||||
properties:
|
||||
com.apple.security.application-groups: group.com.app
|
||||
```
|
||||
|
||||
### Build Script
|
||||
|
||||
@@ -437,7 +468,7 @@ targets:
|
||||
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**: **[String]** - a list of test targets that should be included in the scheme. These will be added to the build targets and the test entries
|
||||
- [ ] **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
|
||||
- [ ] **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.
|
||||
@@ -561,7 +592,12 @@ A multiline script can be written using the various YAML multiline methods, for
|
||||
### Test Action
|
||||
|
||||
- [ ] **gatherCoverageData**: **Bool** - a boolean that indicates if this scheme should gather coverage data. This defaults to false
|
||||
- [ ] **targets**: **[String]** - a list of targets to test
|
||||
- [ ] **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)
|
||||
|
||||
#### Test Target
|
||||
- [x] **name**: **String** - The name of the target
|
||||
- [ ] **parallelizable**: **Bool** - Whether to run tests in parallel. Defaults to false
|
||||
- [ ] **randomExecutionOrder**: **Bool** - Whether to run tests in a random order. Defaults to false
|
||||
|
||||
### Archive Action
|
||||
|
||||
|
||||
+29
-3
@@ -7,6 +7,7 @@
|
||||
- [Use dependencies](#use-dependencies)
|
||||
- [Cocoapods](#cocoapods)
|
||||
- [Carthage](#carthage)
|
||||
- [SDK](#sdk)
|
||||
|
||||
# Configuring build settings
|
||||
There are various ways of configuring build settings
|
||||
@@ -92,7 +93,7 @@ DEVELOPMENT_TEAM=XXXXXXXXX xcodebuild ...
|
||||
|
||||
# Use dependencies
|
||||
|
||||
Each target can declare one or more dependencies. See [Dependency](#dependency) for more info
|
||||
Each target can declare one or more dependencies. See [Dependency](ProjectSpec.md#dependency) in the ProjectSpec for more info about all the properties
|
||||
|
||||
### Cocoapods
|
||||
Use your `podfile` as normal. The pods themselves don't need to be referenced in the project spec. After you generate your project simply run `pod install` which will integrate with your project and create a workspace.
|
||||
@@ -100,7 +101,7 @@ Use your `podfile` as normal. The pods themselves don't need to be referenced in
|
||||
### Carthage
|
||||
XcodeGen makes integrating Carthage dependencies super easy!
|
||||
|
||||
You simply reference them in each target that requires them and XcodeGen does the rest by automatically linking and embedding the carthage frameworks where neccessary.
|
||||
You simply reference them in each target that requires them and XcodeGen does the rest by automatically linking and embedding the carthage frameworks where necessary.
|
||||
|
||||
```yaml
|
||||
targets:
|
||||
@@ -111,4 +112,29 @@ targets:
|
||||
Framework:
|
||||
dependencies:
|
||||
- carthage: Alamofire
|
||||
```
|
||||
```
|
||||
|
||||
XcodeGen automatically creates the build phase that Carthage requires which lists all the files and runs `carthage copy-frameworks`. You can change the invocation of carthage to something different, for example if you are running it with [Mint](https://github.com/yonaskolb/mint). This is then prepended to ` copy frameworks`
|
||||
|
||||
```yaml
|
||||
options:
|
||||
carthageExecutablePath: mint run Carthage/Carthage carthage
|
||||
```
|
||||
|
||||
By default XcodeGen looks for carthage frameworks in `Carthage/Build`. You can change this with the `carthageBuildPath` option
|
||||
|
||||
```yaml
|
||||
options:
|
||||
carthageBuildPath: ../../Carthage/Build
|
||||
```
|
||||
|
||||
### SDK
|
||||
System frameworks and libs can be linked by using the `sdk` dependency type. You can either specify frameworks or libs by using a `.framework` or `.tbd` filename, respectively
|
||||
|
||||
```yaml
|
||||
targets:
|
||||
App:
|
||||
dependencies:
|
||||
- sdk: Contacts.framework
|
||||
- sdk: libc++.tbd
|
||||
```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
TOOL_NAME = XcodeGen
|
||||
export EXECUTABLE_NAME = xcodegen
|
||||
VERSION = 1.11.2
|
||||
VERSION = 2.0.0
|
||||
|
||||
PREFIX = /usr/local
|
||||
INSTALL_PATH = $(PREFIX)/bin/$(EXECUTABLE_NAME)
|
||||
|
||||
+17
-17
@@ -3,11 +3,11 @@
|
||||
"pins": [
|
||||
{
|
||||
"package": "AEXML",
|
||||
"repositoryURL": "https://github.com/tadija/AEXML.git",
|
||||
"repositoryURL": "https://github.com/tadija/AEXML",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "6eea665515d079c338690147082a8084a36484b0",
|
||||
"version": "4.3.0"
|
||||
"revision": "54bb8ea6fb693dd3f92a89e5fcc19e199fdeedd0",
|
||||
"version": "4.3.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -24,8 +24,8 @@
|
||||
"repositoryURL": "https://github.com/yonaskolb/JSONUtilities.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "d9f957b1b2a078c93f96c723040d4cbffcb7d3f9",
|
||||
"version": "4.0.2"
|
||||
"revision": "db238f4858ac2ac3fff228b5b71ce90488a6a9b3",
|
||||
"version": "4.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -46,15 +46,6 @@
|
||||
"version": "3.1.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "ShellOut",
|
||||
"repositoryURL": "https://github.com/JohnSundell/ShellOut.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "f1c253a34a40df4bfd268b09fdb101b059f6d52d",
|
||||
"version": "2.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Spectre",
|
||||
"repositoryURL": "https://github.com/kylef/Spectre.git",
|
||||
@@ -65,12 +56,21 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "xcproj",
|
||||
"package": "SwiftShell",
|
||||
"repositoryURL": "https://github.com/kareman/SwiftShell",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "beebe43c986d89ea5359ac3adcb42dac94e5e08a",
|
||||
"version": "4.1.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "xcodeproj",
|
||||
"repositoryURL": "https://github.com/tuist/xcodeproj.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "5253c22f208558264e3a64a3a29f11537ca1b41a",
|
||||
"version": "4.3.1"
|
||||
"revision": "23da51abd3de3bedaad59a0afbb150b48504b5b0",
|
||||
"version": "6.3.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
+9
-5
@@ -1,4 +1,4 @@
|
||||
// swift-tools-version:4.0
|
||||
// swift-tools-version:4.2
|
||||
|
||||
import PackageDescription
|
||||
|
||||
@@ -13,10 +13,10 @@ let package = Package(
|
||||
.package(url: "https://github.com/kylef/PathKit.git", from: "0.9.0"),
|
||||
.package(url: "https://github.com/kylef/Commander.git", from: "0.8.0"),
|
||||
.package(url: "https://github.com/jpsim/Yams.git", from: "1.0.0"),
|
||||
.package(url: "https://github.com/yonaskolb/JSONUtilities.git", from: "4.0.0"),
|
||||
.package(url: "https://github.com/yonaskolb/JSONUtilities.git", from: "4.1.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", from: "4.3.1"),
|
||||
.package(url: "https://github.com/tuist/xcodeproj.git", from: "6.3.0"),
|
||||
],
|
||||
targets: [
|
||||
.target(name: "XcodeGen", dependencies: [
|
||||
@@ -27,17 +27,21 @@ let package = Package(
|
||||
.target(name: "XcodeGenKit", dependencies: [
|
||||
"ProjectSpec",
|
||||
"JSONUtilities",
|
||||
"xcproj",
|
||||
"xcodeproj",
|
||||
"PathKit",
|
||||
]),
|
||||
.target(name: "ProjectSpec", dependencies: [
|
||||
"JSONUtilities",
|
||||
"xcproj",
|
||||
"xcodeproj",
|
||||
"Yams",
|
||||
]),
|
||||
.testTarget(name: "XcodeGenKitTests", dependencies: [
|
||||
"XcodeGenKit",
|
||||
"Spectre",
|
||||
]),
|
||||
.testTarget(name: "PerformanceTests", dependencies: [
|
||||
"XcodeGenKit",
|
||||
"Spectre",
|
||||
])
|
||||
]
|
||||
)
|
||||
|
||||
@@ -49,13 +49,17 @@ targets:
|
||||
deploymentTarget: "10.0"
|
||||
sources: [MyApp]
|
||||
settings:
|
||||
debug:
|
||||
CUSTOM_BUILD_SETTING: my_debug_value
|
||||
release:
|
||||
CUSTOM_BUILD_SETTING: my_release_value
|
||||
configs:
|
||||
debug:
|
||||
CUSTOM_BUILD_SETTING: my_debug_value
|
||||
release:
|
||||
CUSTOM_BUILD_SETTING: my_release_value
|
||||
dependencies:
|
||||
- target: MyFramework
|
||||
- carthage: Alamofire
|
||||
- framework: Vendor/MyFramework.framework
|
||||
- sdk: Contacts.framework
|
||||
- sdk: libc++.tbd
|
||||
MyFramework:
|
||||
type: framework
|
||||
platform: iOS
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
CODE_SIGN_IDENTITY[sdk=iphoneos*]: iPhone Developer
|
||||
CODE_SIGN_IDENTITY: iPhone Developer
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
|
||||
|
||||
@@ -42,4 +42,4 @@ GCC_WARN_UNUSED_VARIABLE: YES
|
||||
|
||||
# Swift Settings
|
||||
PRODUCT_NAME: $(TARGET_NAME)
|
||||
SWIFT_VERSION: '4.0'
|
||||
SWIFT_VERSION: '4.2'
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
|
||||
public struct Config: Equatable {
|
||||
public var name: String
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
|
||||
public struct Dependency: Equatable {
|
||||
|
||||
@@ -11,6 +10,7 @@ public struct Dependency: Equatable {
|
||||
public var removeHeaders: Bool = true
|
||||
public var link: Bool?
|
||||
public var implicit: Bool = false
|
||||
public var weakLink: Bool = false
|
||||
|
||||
public init(
|
||||
type: DependencyType,
|
||||
@@ -18,7 +18,8 @@ public struct Dependency: Equatable {
|
||||
embed: Bool? = nil,
|
||||
codeSign: Bool? = nil,
|
||||
link: Bool? = nil,
|
||||
implicit: Bool = false
|
||||
implicit: Bool = false,
|
||||
weakLink: Bool = false
|
||||
) {
|
||||
self.type = type
|
||||
self.reference = reference
|
||||
@@ -26,12 +27,14 @@ public struct Dependency: Equatable {
|
||||
self.codeSign = codeSign
|
||||
self.link = link
|
||||
self.implicit = implicit
|
||||
self.weakLink = weakLink
|
||||
}
|
||||
|
||||
public enum DependencyType {
|
||||
case target
|
||||
case framework
|
||||
case carthage
|
||||
case sdk
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +50,9 @@ extension Dependency: JSONObjectConvertible {
|
||||
} else if let carthage: String = jsonDictionary.json(atKeyPath: "carthage") {
|
||||
type = .carthage
|
||||
reference = carthage
|
||||
} else if let sdk: String = jsonDictionary.json(atKeyPath: "sdk") {
|
||||
type = .sdk
|
||||
reference = sdk
|
||||
} else {
|
||||
throw SpecParsingError.invalidDependency(jsonDictionary)
|
||||
}
|
||||
@@ -61,5 +67,8 @@ extension Dependency: JSONObjectConvertible {
|
||||
if let bool: Bool = jsonDictionary.json(atKeyPath: "implicit") {
|
||||
implicit = bool
|
||||
}
|
||||
if let bool: Bool = jsonDictionary.json(atKeyPath: "weak") {
|
||||
weakLink = bool
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
|
||||
public struct DeploymentTarget: Equatable {
|
||||
|
||||
@@ -41,6 +40,15 @@ extension Platform {
|
||||
case .macOS: return "MACOSX_DEPLOYMENT_TARGET"
|
||||
}
|
||||
}
|
||||
|
||||
public var sdkRoot: String {
|
||||
switch self {
|
||||
case .iOS: return "iphoneos"
|
||||
case .tvOS: return "appletvos"
|
||||
case .watchOS: return "watchos"
|
||||
case .macOS: return "macosx"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Version {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
|
||||
public struct Plist: Equatable {
|
||||
|
||||
public let path: String
|
||||
public let properties: [String: Any]
|
||||
|
||||
public init(path: String, attributes: [String: Any] = [:]) {
|
||||
self.path = path
|
||||
properties = attributes
|
||||
}
|
||||
|
||||
public static func == (lhs: Plist, rhs: Plist) -> Bool {
|
||||
return lhs.path == rhs.path &&
|
||||
NSDictionary(dictionary: lhs.properties).isEqual(to: rhs.properties)
|
||||
}
|
||||
}
|
||||
|
||||
extension Plist: JSONObjectConvertible {
|
||||
|
||||
public init(jsonDictionary: JSONDictionary) throws {
|
||||
path = try jsonDictionary.json(atKeyPath: "path")
|
||||
properties = jsonDictionary.json(atKeyPath: "properties") ?? [:]
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import PathKit
|
||||
import xcproj
|
||||
import Yams
|
||||
|
||||
public struct Project: BuildSettingsContainer {
|
||||
@@ -78,6 +77,10 @@ public struct Project: BuildSettingsContainer {
|
||||
public func getConfig(_ configName: String) -> Config? {
|
||||
return configs.first { $0.name == configName }
|
||||
}
|
||||
|
||||
public var defaultProjectPath: Path {
|
||||
return basePath + "\(name).xcodeproj"
|
||||
}
|
||||
}
|
||||
|
||||
extension Project: CustomDebugStringConvertible {
|
||||
@@ -86,7 +89,7 @@ extension Project: CustomDebugStringConvertible {
|
||||
var string = "Name: \(name)"
|
||||
let indent = " "
|
||||
if !include.isEmpty {
|
||||
string += "\nInclude:\n\(indent)" + include.map { "📄 \($0)" }.joined(separator: "\n\(indent)")
|
||||
string += "\nInclude:\n\(indent)" + include.map { $0.description }.joined(separator: "\n\(indent)")
|
||||
}
|
||||
|
||||
if !settingGroups.isEmpty {
|
||||
@@ -102,6 +105,10 @@ extension Project: CustomDebugStringConvertible {
|
||||
if !aggregateTargets.isEmpty {
|
||||
string += "\nAggregate Targets:\n\(indent)" + aggregateTargets.map { $0.description }.joined(separator: "\n\(indent)")
|
||||
}
|
||||
if !schemes.isEmpty {
|
||||
let allSchemes = targets.filter { $0.scheme != nil }.map { $0.name } + schemes.map { $0.name }
|
||||
string += "\nSchemes:\n\(indent)" + allSchemes.joined(separator: "\n\(indent)")
|
||||
}
|
||||
|
||||
return string
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
public typealias BuildType = XCScheme.BuildAction.Entry.BuildFor
|
||||
|
||||
@@ -89,15 +89,40 @@ public struct Scheme: Equatable {
|
||||
public var config: String?
|
||||
public var gatherCoverageData: Bool
|
||||
public var commandLineArguments: [String: Bool]
|
||||
public var targets: [String]
|
||||
public var targets: [TestTarget]
|
||||
public var preActions: [ExecutionAction]
|
||||
public var postActions: [ExecutionAction]
|
||||
public var environmentVariables: [XCScheme.EnvironmentVariable]
|
||||
|
||||
public struct TestTarget: Equatable, ExpressibleByStringLiteral {
|
||||
public let name: String
|
||||
public var randomExecutionOrder: Bool
|
||||
public var parallelizable: Bool
|
||||
|
||||
public init(
|
||||
name: String,
|
||||
randomExecutionOrder: Bool = false,
|
||||
parallelizable: Bool = false
|
||||
) {
|
||||
self.name = name
|
||||
self.randomExecutionOrder = randomExecutionOrder
|
||||
self.parallelizable = parallelizable
|
||||
}
|
||||
|
||||
public init(stringLiteral value: String) {
|
||||
name = value
|
||||
randomExecutionOrder = false
|
||||
parallelizable = false
|
||||
}
|
||||
}
|
||||
|
||||
public init(
|
||||
config: String,
|
||||
gatherCoverageData: Bool = false,
|
||||
randomExecutionOrder: Bool = false,
|
||||
parallelizable: Bool = false,
|
||||
commandLineArguments: [String: Bool] = [:],
|
||||
targets: [String] = [],
|
||||
targets: [TestTarget] = [],
|
||||
preActions: [ExecutionAction] = [],
|
||||
postActions: [ExecutionAction] = [],
|
||||
environmentVariables: [XCScheme.EnvironmentVariable] = []
|
||||
@@ -210,13 +235,34 @@ extension Scheme.Test: JSONObjectConvertible {
|
||||
config = jsonDictionary.json(atKeyPath: "config")
|
||||
gatherCoverageData = jsonDictionary.json(atKeyPath: "gatherCoverageData") ?? false
|
||||
commandLineArguments = jsonDictionary.json(atKeyPath: "commandLineArguments") ?? [:]
|
||||
targets = jsonDictionary.json(atKeyPath: "targets") ?? []
|
||||
if let targets = jsonDictionary["targets"] as? [Any] {
|
||||
self.targets = try targets.compactMap { target in
|
||||
if let string = target as? String {
|
||||
return TestTarget(name: string)
|
||||
} else if let dictionary = target as? JSONDictionary {
|
||||
return try TestTarget(jsonDictionary: dictionary)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
targets = []
|
||||
}
|
||||
preActions = jsonDictionary.json(atKeyPath: "preActions") ?? []
|
||||
postActions = jsonDictionary.json(atKeyPath: "postActions") ?? []
|
||||
environmentVariables = try XCScheme.EnvironmentVariable.parseAll(jsonDictionary: jsonDictionary)
|
||||
}
|
||||
}
|
||||
|
||||
extension Scheme.Test.TestTarget: JSONObjectConvertible {
|
||||
|
||||
public init(jsonDictionary: JSONDictionary) throws {
|
||||
name = try jsonDictionary.json(atKeyPath: "name")
|
||||
randomExecutionOrder = jsonDictionary.json(atKeyPath: "randomExecutionOrder") ?? false
|
||||
parallelizable = jsonDictionary.json(atKeyPath: "parallelizable") ?? false
|
||||
}
|
||||
}
|
||||
|
||||
extension Scheme.Profile: JSONObjectConvertible {
|
||||
|
||||
public init(jsonDictionary: JSONDictionary) throws {
|
||||
@@ -311,7 +357,7 @@ extension BuildType: JSONPrimitiveConvertible {
|
||||
}
|
||||
}
|
||||
|
||||
extension XCScheme.EnvironmentVariable: JSONObjectConvertible, Equatable {
|
||||
extension XCScheme.EnvironmentVariable: JSONObjectConvertible {
|
||||
|
||||
private static func parseValue(_ value: Any) -> String {
|
||||
if let bool = value as? Bool {
|
||||
@@ -346,10 +392,4 @@ extension XCScheme.EnvironmentVariable: JSONObjectConvertible, Equatable {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
public static func == (lhs: XCScheme.EnvironmentVariable, rhs: XCScheme.EnvironmentVariable) -> Bool {
|
||||
return lhs.variable == rhs.variable &&
|
||||
lhs.value == rhs.value &&
|
||||
lhs.enabled == rhs.enabled
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import PathKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
public struct Settings: Equatable, JSONObjectConvertible, CustomStringConvertible {
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
|
||||
public struct SpecOptions: Equatable {
|
||||
|
||||
|
||||
@@ -22,6 +22,24 @@ extension Project {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if settings.buildSettings.count == configs.count {
|
||||
var allConfigs = true
|
||||
for buildSetting in settings.buildSettings.keys {
|
||||
var isConfig = false
|
||||
for config in configs {
|
||||
if config.name.lowercased().contains(buildSetting.lowercased()) {
|
||||
isConfig = true
|
||||
}
|
||||
}
|
||||
if !isConfig {
|
||||
allConfigs = false
|
||||
}
|
||||
}
|
||||
if allConfigs {
|
||||
errors.append(.invalidPerConfigSettings)
|
||||
}
|
||||
}
|
||||
return errors
|
||||
}
|
||||
|
||||
@@ -92,8 +110,8 @@ extension Project {
|
||||
}
|
||||
|
||||
for testTarget in scheme.testTargets {
|
||||
if getTarget(testTarget) == nil {
|
||||
errors.append(.invalidTargetSchemeTest(target: target.name, testTarget: testTarget))
|
||||
if getTarget(testTarget.name) == nil {
|
||||
errors.append(.invalidTargetSchemeTest(target: target.name, testTarget: testTarget.name))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,8 +138,23 @@ extension Project {
|
||||
|
||||
for target in targets {
|
||||
for dependency in target.dependencies {
|
||||
if dependency.type == .target, getProjectTarget(dependency.reference) == nil {
|
||||
errors.append(.invalidTargetDependency(target: target.name, dependency: dependency.reference))
|
||||
switch dependency.type {
|
||||
case .target:
|
||||
if getProjectTarget(dependency.reference) == 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"?:
|
||||
break
|
||||
default:
|
||||
errors.append(.invalidSDKDependency(target: target.name, dependency: dependency.reference))
|
||||
}
|
||||
}
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ public struct SpecValidationError: Error, CustomStringConvertible {
|
||||
|
||||
public enum ValidationError: Error, CustomStringConvertible {
|
||||
case invalidXcodeGenVersion(minimumVersion: Version, version: Version)
|
||||
case invalidSDKDependency(target: String, dependency: String)
|
||||
case invalidTargetDependency(target: String, dependency: String)
|
||||
case invalidTargetSource(target: String, source: String)
|
||||
case invalidTargetConfigFile(target: String, configFile: String, config: String)
|
||||
@@ -21,11 +22,14 @@ public struct SpecValidationError: Error, CustomStringConvertible {
|
||||
case invalidConfigFileConfig(String)
|
||||
case missingConfigForTargetScheme(target: String, configType: ConfigType)
|
||||
case missingDefaultConfig(configName: String)
|
||||
case invalidPerConfigSettings
|
||||
|
||||
public var description: String {
|
||||
switch self {
|
||||
case let .invalidXcodeGenVersion(minimumVersion, version):
|
||||
return "XcodeGen version is \(version), but minimum required version specified as \(minimumVersion)"
|
||||
case let .invalidSDKDependency(target, dependency):
|
||||
return "Target \(target.quoted) has invalid sdk dependency: \(dependency.quoted). It must be a full path or have the following extensions: .framework, .dylib, .tbd"
|
||||
case let .invalidTargetDependency(target, dependency):
|
||||
return "Target \(target.quoted) has invalid dependency: \(dependency.quoted)"
|
||||
case let .invalidTargetConfigFile(target, configFile, config):
|
||||
@@ -56,6 +60,8 @@ public struct SpecValidationError: Error, CustomStringConvertible {
|
||||
return "Target \(target.quoted) is missing a config of type \(configType.rawValue) to generate its scheme"
|
||||
case let .missingDefaultConfig(name):
|
||||
return "Default configuration \(name) doesn't exist"
|
||||
case .invalidPerConfigSettings:
|
||||
return "Settings that are for a specific config must go in \"configs\". \"base\" can be used for common settings"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
public struct LegacyTarget: Equatable {
|
||||
public var toolPath: String
|
||||
@@ -28,6 +28,8 @@ public struct Target: ProjectTarget {
|
||||
public var settings: Settings
|
||||
public var sources: [TargetSource]
|
||||
public var dependencies: [Dependency]
|
||||
public var info: Plist?
|
||||
public var entitlements: Plist?
|
||||
public var transitivelyLinkDependencies: Bool?
|
||||
public var directlyEmbedCarthageDependencies: Bool?
|
||||
public var requiresObjCLinking: Bool?
|
||||
@@ -40,14 +42,14 @@ public struct Target: ProjectTarget {
|
||||
public var legacy: LegacyTarget?
|
||||
public var deploymentTarget: Version?
|
||||
public var attributes: [String: Any]
|
||||
internal var productName: String?
|
||||
public var productName: String
|
||||
|
||||
public var isLegacy: Bool {
|
||||
return legacy != nil
|
||||
}
|
||||
|
||||
public var filename: String {
|
||||
var filename = productName ?? name
|
||||
var filename = productName
|
||||
if let fileExtension = type.fileExtension {
|
||||
filename += ".\(fileExtension)"
|
||||
}
|
||||
@@ -58,11 +60,14 @@ public struct Target: ProjectTarget {
|
||||
name: String,
|
||||
type: PBXProductType,
|
||||
platform: Platform,
|
||||
productName: String? = nil,
|
||||
deploymentTarget: Version? = nil,
|
||||
settings: Settings = .empty,
|
||||
configFiles: [String: String] = [:],
|
||||
sources: [TargetSource] = [],
|
||||
dependencies: [Dependency] = [],
|
||||
info: Plist? = nil,
|
||||
entitlements: Plist? = nil,
|
||||
transitivelyLinkDependencies: Bool? = nil,
|
||||
directlyEmbedCarthageDependencies: Bool? = nil,
|
||||
requiresObjCLinking: Bool? = nil,
|
||||
@@ -78,10 +83,13 @@ public struct Target: ProjectTarget {
|
||||
self.type = type
|
||||
self.platform = platform
|
||||
self.deploymentTarget = deploymentTarget
|
||||
self.productName = productName ?? name
|
||||
self.settings = settings
|
||||
self.configFiles = configFiles
|
||||
self.sources = sources
|
||||
self.dependencies = dependencies
|
||||
self.info = info
|
||||
self.entitlements = entitlements
|
||||
self.transitivelyLinkDependencies = transitivelyLinkDependencies
|
||||
self.directlyEmbedCarthageDependencies = directlyEmbedCarthageDependencies
|
||||
self.requiresObjCLinking = requiresObjCLinking
|
||||
@@ -98,7 +106,7 @@ public struct Target: ProjectTarget {
|
||||
extension Target: CustomStringConvertible {
|
||||
|
||||
public var description: String {
|
||||
return "\(platform.emoji) \(name): \(type)"
|
||||
return "\(name): \(platform.rawValue) \(type)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,6 +218,8 @@ extension Target: Equatable {
|
||||
lhs.settings == rhs.settings &&
|
||||
lhs.configFiles == rhs.configFiles &&
|
||||
lhs.sources == rhs.sources &&
|
||||
lhs.info == rhs.info &&
|
||||
lhs.entitlements == rhs.entitlements &&
|
||||
lhs.dependencies == rhs.dependencies &&
|
||||
lhs.preBuildScripts == rhs.preBuildScripts &&
|
||||
lhs.postCompileScripts == rhs.postCompileScripts &&
|
||||
@@ -234,8 +244,9 @@ extension LegacyTarget: JSONObjectConvertible {
|
||||
extension Target: NamedJSONDictionaryConvertible {
|
||||
|
||||
public init(name: String, jsonDictionary: JSONDictionary) throws {
|
||||
self.name = jsonDictionary.json(atKeyPath: "name") ?? name
|
||||
productName = jsonDictionary.json(atKeyPath: "productName")
|
||||
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")
|
||||
if let type = PBXProductType(string: typeString) {
|
||||
self.type = type
|
||||
@@ -279,6 +290,14 @@ extension Target: NamedJSONDictionaryConvertible {
|
||||
} else {
|
||||
dependencies = try jsonDictionary.json(atKeyPath: "dependencies", invalidItemBehaviour: .fail)
|
||||
}
|
||||
|
||||
if jsonDictionary["info"] != nil {
|
||||
info = try jsonDictionary.json(atKeyPath: "info") as Plist
|
||||
}
|
||||
if jsonDictionary["entitlements"] != nil {
|
||||
entitlements = try jsonDictionary.json(atKeyPath: "entitlements") as Plist
|
||||
}
|
||||
|
||||
transitivelyLinkDependencies = jsonDictionary.json(atKeyPath: "transitivelyLinkDependencies")
|
||||
directlyEmbedCarthageDependencies = jsonDictionary.json(atKeyPath: "directlyEmbedCarthageDependencies")
|
||||
requiresObjCLinking = jsonDictionary.json(atKeyPath: "requiresObjCLinking")
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
public struct TargetScheme: Equatable {
|
||||
public var testTargets: [String]
|
||||
public var testTargets: [Scheme.Test.TestTarget]
|
||||
public var configVariants: [String]
|
||||
public var gatherCoverageData: Bool
|
||||
public var commandLineArguments: [String: Bool]
|
||||
@@ -12,7 +12,7 @@ public struct TargetScheme: Equatable {
|
||||
public var postActions: [Scheme.ExecutionAction]
|
||||
|
||||
public init(
|
||||
testTargets: [String] = [],
|
||||
testTargets: [Scheme.Test.TestTarget] = [],
|
||||
configVariants: [String] = [],
|
||||
gatherCoverageData: Bool = false,
|
||||
commandLineArguments: [String: Bool] = [:],
|
||||
@@ -33,7 +33,19 @@ public struct TargetScheme: Equatable {
|
||||
extension TargetScheme: JSONObjectConvertible {
|
||||
|
||||
public init(jsonDictionary: JSONDictionary) throws {
|
||||
testTargets = jsonDictionary.json(atKeyPath: "testTargets") ?? []
|
||||
if let targets = jsonDictionary["testTargets"] as? [Any] {
|
||||
testTargets = try targets.compactMap { target in
|
||||
if let string = target as? String {
|
||||
return .init(name: string)
|
||||
} else if let dictionary = target as? JSONDictionary {
|
||||
return try .init(jsonDictionary: dictionary)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
testTargets = []
|
||||
}
|
||||
configVariants = jsonDictionary.json(atKeyPath: "configVariants") ?? []
|
||||
gatherCoverageData = jsonDictionary.json(atKeyPath: "gatherCoverageData") ?? false
|
||||
commandLineArguments = jsonDictionary.json(atKeyPath: "commandLineArguments") ?? [:]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import PathKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
public struct TargetSource: Equatable {
|
||||
|
||||
@@ -58,7 +58,7 @@ public struct TargetSource: Equatable {
|
||||
case sharedSupport
|
||||
case plugins
|
||||
|
||||
public var destination: xcproj.PBXCopyFilesBuildPhase.SubFolder? {
|
||||
public var destination: xcodeproj.PBXCopyFilesBuildPhase.SubFolder? {
|
||||
switch self {
|
||||
case .absolutePath: return .absolutePath
|
||||
case .productsDirectory: return .productsDirectory
|
||||
@@ -96,7 +96,7 @@ public struct TargetSource: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public var buildPhase: xcproj.BuildPhase? {
|
||||
public var buildPhase: xcodeproj.BuildPhase? {
|
||||
switch self {
|
||||
case .sources: return .sources
|
||||
case .headers: return .headers
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import PathKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
extension PBXProductType {
|
||||
|
||||
@@ -60,7 +60,7 @@ extension XCScheme.CommandLineArguments {
|
||||
public convenience init(_ dict: [String: Bool]) {
|
||||
let args = dict.map { tuple in
|
||||
XCScheme.CommandLineArguments.CommandLineArgument(name: tuple.key, enabled: tuple.value)
|
||||
}
|
||||
}.sorted { $0.name < $1.name }
|
||||
self.init(arguments: args)
|
||||
}
|
||||
}
|
||||
|
||||
+10
-17
@@ -4,9 +4,9 @@ import JSONUtilities
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
let version = try Version("1.11.2")
|
||||
let version = try Version("2.0.0")
|
||||
|
||||
func generate(spec: String, project: String, isQuiet: Bool, justVersion: Bool) {
|
||||
if justVersion {
|
||||
@@ -22,7 +22,7 @@ func generate(spec: String, project: String, isQuiet: Bool, justVersion: Bool) {
|
||||
}
|
||||
|
||||
let projectSpecPath = Path(spec).absolute()
|
||||
let projectPath = project == "" ? projectSpecPath.parent() : Path(project).absolute()
|
||||
var projectPath = project == "" ? projectSpecPath.parent() : Path(project).absolute()
|
||||
|
||||
if !projectSpecPath.exists {
|
||||
fatalError("No project spec found at \(projectSpecPath.absolute())")
|
||||
@@ -39,27 +39,20 @@ func generate(spec: String, project: String, isQuiet: Bool, justVersion: Bool) {
|
||||
}
|
||||
|
||||
do {
|
||||
logger.info("⚙️ Generating project...")
|
||||
|
||||
try project.validateMinimumXcodeGenVersion(version)
|
||||
try project.validate()
|
||||
|
||||
logger.info("⚙️ Generating project...")
|
||||
let projectGenerator = ProjectGenerator(project: project)
|
||||
let xcodeProject = try projectGenerator.generateXcodeProject()
|
||||
|
||||
logger.info("⚙️ Writing project...")
|
||||
let fileWriter = FileWriter(project: project)
|
||||
projectPath = projectPath + "\(project.name).xcodeproj"
|
||||
try fileWriter.writeXcodeProject(xcodeProject, to: projectPath)
|
||||
try fileWriter.writePlists()
|
||||
|
||||
let projectFile = projectPath + "\(project.name).xcodeproj"
|
||||
let tempPath = Path.temporary + "XcodeGen_\(Int(NSTimeIntervalSince1970))"
|
||||
try? tempPath.delete()
|
||||
if projectFile.exists {
|
||||
try projectFile.copy(tempPath)
|
||||
}
|
||||
try xcodeProject.write(path: tempPath, override: true)
|
||||
try? projectFile.delete()
|
||||
try tempPath.copy(projectFile)
|
||||
try? tempPath.delete()
|
||||
|
||||
logger.success("💾 Saved project to \(projectFile.string)")
|
||||
logger.success("💾 Saved project to \(projectPath)")
|
||||
} catch let error as SpecValidationError {
|
||||
fatalError(error.description)
|
||||
} catch {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import Foundation
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import xcodeproj
|
||||
|
||||
public class FileWriter {
|
||||
|
||||
let project: Project
|
||||
|
||||
public init(project: Project) {
|
||||
self.project = project
|
||||
}
|
||||
|
||||
public func writeXcodeProject(_ xcodeProject: XcodeProj, to projectPath: Path? = nil) throws {
|
||||
let projectPath = project.defaultProjectPath
|
||||
let tempPath = Path.temporary + "XcodeGen_\(Int(NSTimeIntervalSince1970))"
|
||||
try? tempPath.delete()
|
||||
if projectPath.exists {
|
||||
try projectPath.copy(tempPath)
|
||||
}
|
||||
try xcodeProject.write(path: tempPath, override: true)
|
||||
try? projectPath.delete()
|
||||
try tempPath.copy(projectPath)
|
||||
try? tempPath.delete()
|
||||
}
|
||||
|
||||
public func writePlists() throws {
|
||||
|
||||
let infoPlistGenerator = InfoPlistGenerator()
|
||||
for target in project.targets {
|
||||
// write Info.plist
|
||||
if let plist = target.info {
|
||||
let properties = infoPlistGenerator.generateProperties(target: target).merged(plist.properties)
|
||||
try writePlist(properties, path: plist.path)
|
||||
}
|
||||
|
||||
// write entitlements
|
||||
if let plist = target.entitlements {
|
||||
try writePlist(plist.properties, path: plist.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func writePlist(_ plist: [String: Any], path: String) throws {
|
||||
let path = project.basePath + path
|
||||
if path.exists, let data: Data = try? path.read(),
|
||||
let existingPlist = (try? PropertyListSerialization.propertyList(from: data, format: nil)) as? [String: Any], NSDictionary(dictionary: plist).isEqual(to: existingPlist) {
|
||||
// file is the same
|
||||
return
|
||||
}
|
||||
let data = try PropertyListSerialization.data(fromPropertyList: plist, format: .xml, options: 0)
|
||||
try? path.delete()
|
||||
try path.parent().mkpath()
|
||||
try path.write(data)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import Foundation
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
|
||||
public class InfoPlistGenerator {
|
||||
|
||||
/**
|
||||
Default info plist attributes taken from:
|
||||
/Applications/Xcode.app/Contents/Developer/Library/Xcode/Templates/Project Templates/Base/Base_DefinitionsInfoPlist.xctemplate/TemplateInfo.plist
|
||||
*/
|
||||
var defaultInfoPlist: [String: Any] = {
|
||||
var dictionary: [String: Any] = [:]
|
||||
dictionary["CFBundleIdentifier"] = "$(PRODUCT_BUNDLE_IDENTIFIER)"
|
||||
dictionary["CFBundleInfoDictionaryVersion"] = "6.0"
|
||||
dictionary["CFBundleExecutable"] = "$(EXECUTABLE_NAME)"
|
||||
dictionary["CFBundleName"] = "$(PRODUCT_NAME)"
|
||||
dictionary["CFBundleDevelopmentRegion"] = "$(DEVELOPMENT_LANGUAGE)"
|
||||
dictionary["CFBundleShortVersionString"] = "1.0"
|
||||
dictionary["CFBundleVersion"] = "1"
|
||||
return dictionary
|
||||
}()
|
||||
|
||||
public func generateProperties(target: Target) -> [String: Any] {
|
||||
var targetInfoPlist = defaultInfoPlist
|
||||
switch target.type {
|
||||
case .uiTestBundle,
|
||||
.unitTestBundle:
|
||||
targetInfoPlist["CFBundlePackageType"] = "BNDL"
|
||||
case .application,
|
||||
.watch2App:
|
||||
targetInfoPlist["CFBundlePackageType"] = "APPL"
|
||||
case .framework:
|
||||
targetInfoPlist["CFBundlePackageType"] = "FMWK"
|
||||
case .bundle:
|
||||
targetInfoPlist["CFBundlePackageType"] = "BNDL"
|
||||
case .xpcService,
|
||||
.appExtension:
|
||||
targetInfoPlist["CFBundlePackageType"] = "XPC!"
|
||||
default: break
|
||||
}
|
||||
return targetInfoPlist
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@ import Foundation
|
||||
import JSONUtilities
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import Yams
|
||||
|
||||
public class ProjectGenerator {
|
||||
@@ -13,21 +13,21 @@ public class ProjectGenerator {
|
||||
self.project = project
|
||||
}
|
||||
|
||||
var defaultDebugConfig: Config {
|
||||
return project.configs.first { $0.type == .debug }!
|
||||
}
|
||||
|
||||
var defaultReleaseConfig: Config {
|
||||
return project.configs.first { $0.type == .release }!
|
||||
}
|
||||
|
||||
public func generateXcodeProject() throws -> XcodeProj {
|
||||
try project.validate()
|
||||
|
||||
// generate PBXProj
|
||||
let pbxProjGenerator = PBXProjGenerator(project: project)
|
||||
let pbxProject = try pbxProjGenerator.generate()
|
||||
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 = try generateSharedData(pbxProject: pbxProject)
|
||||
return XcodeProj(workspace: workspace, pbxproj: pbxProject, sharedData: sharedData)
|
||||
|
||||
let sharedData = XCSharedData(schemes: schemes)
|
||||
return XcodeProj(workspace: workspace, pbxproj: pbxProj, sharedData: sharedData)
|
||||
}
|
||||
|
||||
func generateWorkspace() throws -> XCWorkspace {
|
||||
@@ -35,219 +35,4 @@ public class ProjectGenerator {
|
||||
let workspaceData = XCWorkspaceData(children: [dataElement])
|
||||
return XCWorkspace(data: workspaceData)
|
||||
}
|
||||
|
||||
func generateScheme(_ scheme: Scheme, pbxProject: PBXProj) throws -> XCScheme {
|
||||
|
||||
func getBuildEntry(_ buildTarget: Scheme.BuildTarget) -> XCScheme.BuildAction.Entry {
|
||||
|
||||
guard let targetReference = pbxProject.objects.targets(named: buildTarget.target).first else {
|
||||
fatalError("Unable to find target named \"\(buildTarget.target)\" in \"PBXProj.objects.targets\"")
|
||||
}
|
||||
|
||||
guard let buildableName =
|
||||
project.getTarget(buildTarget.target)?.filename ??
|
||||
project.getAggregateTarget(buildTarget.target)?.name else {
|
||||
fatalError("Unable to determinate \"buildableName\" for build target: \(buildTarget.target)")
|
||||
}
|
||||
let buildableReference = XCScheme.BuildableReference(
|
||||
referencedContainer: "container:\(project.name).xcodeproj",
|
||||
blueprintIdentifier: targetReference.reference,
|
||||
buildableName: buildableName,
|
||||
blueprintName: buildTarget.target
|
||||
)
|
||||
return XCScheme.BuildAction.Entry(buildableReference: buildableReference, buildFor: buildTarget.buildTypes)
|
||||
}
|
||||
|
||||
let testTargetNames = scheme.test?.targets ?? []
|
||||
let testBuildTargets = testTargetNames.map {
|
||||
Scheme.BuildTarget(target: $0, buildTypes: BuildType.testOnly)
|
||||
}
|
||||
|
||||
let testBuildTargetEntries = testBuildTargets.map(getBuildEntry)
|
||||
|
||||
let buildActionEntries: [XCScheme.BuildAction.Entry] = scheme.build.targets.map(getBuildEntry)
|
||||
|
||||
func getExecutionAction(_ action: Scheme.ExecutionAction) -> XCScheme.ExecutionAction {
|
||||
// ExecutionActions can require the use of build settings. Xcode allows the settings to come from a build or test target.
|
||||
let environmentBuildable = action.settingsTarget.flatMap { settingsTarget in
|
||||
return (buildActionEntries + testBuildTargetEntries)
|
||||
.first { settingsTarget == $0.buildableReference.blueprintName }?
|
||||
.buildableReference
|
||||
}
|
||||
return XCScheme.ExecutionAction(scriptText: action.script, title: action.name, environmentBuildable: environmentBuildable)
|
||||
}
|
||||
|
||||
let target = project.getTarget(scheme.build.targets.first!.target)
|
||||
let shouldExecuteOnLaunch = target?.type.isExecutable == true
|
||||
|
||||
let buildableReference = buildActionEntries.first!.buildableReference
|
||||
let productRunable = XCScheme.BuildableProductRunnable(buildableReference: buildableReference)
|
||||
|
||||
let buildAction = XCScheme.BuildAction(
|
||||
buildActionEntries: buildActionEntries,
|
||||
preActions: scheme.build.preActions.map(getExecutionAction),
|
||||
postActions: scheme.build.postActions.map(getExecutionAction),
|
||||
parallelizeBuild: scheme.build.parallelizeBuild,
|
||||
buildImplicitDependencies: scheme.build.buildImplicitDependencies
|
||||
)
|
||||
|
||||
let testables = testBuildTargetEntries.map {
|
||||
XCScheme.TestableReference(skipped: false, buildableReference: $0.buildableReference)
|
||||
}
|
||||
|
||||
let testCommandLineArgs = scheme.test.map { XCScheme.CommandLineArguments($0.commandLineArguments) }
|
||||
let launchCommandLineArgs = scheme.run.map { XCScheme.CommandLineArguments($0.commandLineArguments) }
|
||||
let profileCommandLineArgs = scheme.profile.map { XCScheme.CommandLineArguments($0.commandLineArguments) }
|
||||
|
||||
let testVariables = scheme.test.flatMap { $0.environmentVariables.isEmpty ? nil : $0.environmentVariables }
|
||||
let launchVariables = scheme.run.flatMap { $0.environmentVariables.isEmpty ? nil : $0.environmentVariables }
|
||||
let profileVariables = scheme.profile.flatMap { $0.environmentVariables.isEmpty ? nil : $0.environmentVariables }
|
||||
|
||||
let testAction = XCScheme.TestAction(
|
||||
buildConfiguration: scheme.test?.config ?? defaultDebugConfig.name,
|
||||
macroExpansion: buildableReference,
|
||||
testables: testables,
|
||||
preActions: scheme.test?.preActions.map(getExecutionAction) ?? [],
|
||||
postActions: scheme.test?.postActions.map(getExecutionAction) ?? [],
|
||||
shouldUseLaunchSchemeArgsEnv: scheme.test?.shouldUseLaunchSchemeArgsEnv ?? true,
|
||||
codeCoverageEnabled: scheme.test?.gatherCoverageData ?? false,
|
||||
commandlineArguments: testCommandLineArgs,
|
||||
environmentVariables: testVariables
|
||||
)
|
||||
|
||||
let launchAction = XCScheme.LaunchAction(
|
||||
buildableProductRunnable: shouldExecuteOnLaunch ? productRunable : nil,
|
||||
buildConfiguration: scheme.run?.config ?? defaultDebugConfig.name,
|
||||
preActions: scheme.run?.preActions.map(getExecutionAction) ?? [],
|
||||
postActions: scheme.run?.postActions.map(getExecutionAction) ?? [],
|
||||
macroExpansion: shouldExecuteOnLaunch ? nil : buildableReference,
|
||||
commandlineArguments: launchCommandLineArgs,
|
||||
environmentVariables: launchVariables
|
||||
)
|
||||
|
||||
let profileAction = XCScheme.ProfileAction(
|
||||
buildableProductRunnable: productRunable,
|
||||
buildConfiguration: scheme.profile?.config ?? defaultReleaseConfig.name,
|
||||
preActions: scheme.profile?.preActions.map(getExecutionAction) ?? [],
|
||||
postActions: scheme.profile?.postActions.map(getExecutionAction) ?? [],
|
||||
shouldUseLaunchSchemeArgsEnv: scheme.profile?.shouldUseLaunchSchemeArgsEnv ?? true,
|
||||
commandlineArguments: profileCommandLineArgs,
|
||||
environmentVariables: profileVariables
|
||||
)
|
||||
|
||||
let analyzeAction = XCScheme.AnalyzeAction(buildConfiguration: scheme.analyze?.config ?? defaultDebugConfig.name)
|
||||
|
||||
let archiveAction = XCScheme.ArchiveAction(
|
||||
buildConfiguration: scheme.archive?.config ?? defaultReleaseConfig.name,
|
||||
revealArchiveInOrganizer: scheme.archive?.revealArchiveInOrganizer ?? true,
|
||||
customArchiveName: scheme.archive?.customArchiveName,
|
||||
preActions: scheme.archive?.preActions.map(getExecutionAction) ?? [],
|
||||
postActions: scheme.archive?.postActions.map(getExecutionAction) ?? []
|
||||
)
|
||||
|
||||
return XCScheme(
|
||||
name: scheme.name,
|
||||
lastUpgradeVersion: project.xcodeVersion,
|
||||
version: project.schemeVersion,
|
||||
buildAction: buildAction,
|
||||
testAction: testAction,
|
||||
launchAction: launchAction,
|
||||
profileAction: profileAction,
|
||||
analyzeAction: analyzeAction,
|
||||
archiveAction: archiveAction
|
||||
)
|
||||
}
|
||||
|
||||
func generateSharedData(pbxProject: PBXProj) throws -> XCSharedData {
|
||||
var xcschemes: [XCScheme] = []
|
||||
|
||||
for scheme in project.schemes {
|
||||
let xcscheme = try generateScheme(scheme, pbxProject: pbxProject)
|
||||
xcschemes.append(xcscheme)
|
||||
}
|
||||
|
||||
for target in project.targets {
|
||||
if let targetScheme = target.scheme {
|
||||
|
||||
if targetScheme.configVariants.isEmpty {
|
||||
let schemeName = target.name
|
||||
|
||||
let debugConfig = project.configs.first { $0.type == .debug }!
|
||||
let releaseConfig = project.configs.first { $0.type == .release }!
|
||||
|
||||
let scheme = Scheme(
|
||||
name: schemeName,
|
||||
target: target,
|
||||
targetScheme: targetScheme,
|
||||
debugConfig: debugConfig.name,
|
||||
releaseConfig: releaseConfig.name
|
||||
)
|
||||
let xcscheme = try generateScheme(scheme, pbxProject: pbxProject)
|
||||
xcschemes.append(xcscheme)
|
||||
} else {
|
||||
for configVariant in targetScheme.configVariants {
|
||||
|
||||
let schemeName = "\(target.name) \(configVariant)"
|
||||
|
||||
let debugConfig = project.configs
|
||||
.first { $0.type == .debug && $0.name.contains(configVariant) }!
|
||||
let releaseConfig = project.configs
|
||||
.first { $0.type == .release && $0.name.contains(configVariant) }!
|
||||
|
||||
let scheme = Scheme(
|
||||
name: schemeName,
|
||||
target: target,
|
||||
targetScheme: targetScheme,
|
||||
debugConfig: debugConfig.name,
|
||||
releaseConfig: releaseConfig.name
|
||||
)
|
||||
let xcscheme = try generateScheme(scheme, pbxProject: pbxProject)
|
||||
xcschemes.append(xcscheme)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return XCSharedData(schemes: xcschemes)
|
||||
}
|
||||
}
|
||||
|
||||
extension Scheme {
|
||||
public init(name: String, target: Target, targetScheme: TargetScheme, debugConfig: String, releaseConfig: String) {
|
||||
self.init(
|
||||
name: name,
|
||||
build: .init(targets: [Scheme.BuildTarget(target: target.name)]),
|
||||
run: .init(
|
||||
config: debugConfig,
|
||||
commandLineArguments: targetScheme.commandLineArguments,
|
||||
preActions: targetScheme.preActions,
|
||||
postActions: targetScheme.postActions,
|
||||
environmentVariables: targetScheme.environmentVariables
|
||||
),
|
||||
test: .init(
|
||||
config: debugConfig,
|
||||
gatherCoverageData: targetScheme.gatherCoverageData,
|
||||
commandLineArguments: targetScheme.commandLineArguments,
|
||||
targets: targetScheme.testTargets,
|
||||
preActions: targetScheme.preActions,
|
||||
postActions: targetScheme.postActions,
|
||||
environmentVariables: targetScheme.environmentVariables
|
||||
),
|
||||
profile: .init(
|
||||
config: releaseConfig,
|
||||
commandLineArguments: targetScheme.commandLineArguments,
|
||||
preActions: targetScheme.preActions,
|
||||
postActions: targetScheme.postActions,
|
||||
environmentVariables: targetScheme.environmentVariables
|
||||
),
|
||||
analyze: .init(
|
||||
config: debugConfig
|
||||
),
|
||||
archive: .init(
|
||||
config: releaseConfig,
|
||||
preActions: targetScheme.preActions,
|
||||
postActions: targetScheme.postActions
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
import Foundation
|
||||
import ProjectSpec
|
||||
import xcodeproj
|
||||
|
||||
public class SchemeGenerator {
|
||||
|
||||
let project: Project
|
||||
let pbxProj: PBXProj
|
||||
|
||||
var defaultDebugConfig: Config {
|
||||
return project.configs.first { $0.type == .debug }!
|
||||
}
|
||||
|
||||
var defaultReleaseConfig: Config {
|
||||
return project.configs.first { $0.type == .release }!
|
||||
}
|
||||
|
||||
public init(project: Project, pbxProj: PBXProj) {
|
||||
self.project = project
|
||||
self.pbxProj = pbxProj
|
||||
}
|
||||
|
||||
public func generateSchemes() throws -> [XCScheme] {
|
||||
var xcschemes: [XCScheme] = []
|
||||
|
||||
for scheme in project.schemes {
|
||||
let xcscheme = try generateScheme(scheme)
|
||||
xcschemes.append(xcscheme)
|
||||
}
|
||||
|
||||
for target in project.targets {
|
||||
if let targetScheme = target.scheme {
|
||||
|
||||
if targetScheme.configVariants.isEmpty {
|
||||
let schemeName = target.name
|
||||
|
||||
let debugConfig = project.configs.first { $0.type == .debug }!
|
||||
let releaseConfig = project.configs.first { $0.type == .release }!
|
||||
|
||||
let scheme = Scheme(
|
||||
name: schemeName,
|
||||
target: target,
|
||||
targetScheme: targetScheme,
|
||||
debugConfig: debugConfig.name,
|
||||
releaseConfig: releaseConfig.name
|
||||
)
|
||||
let xcscheme = try generateScheme(scheme)
|
||||
xcschemes.append(xcscheme)
|
||||
} else {
|
||||
for configVariant in targetScheme.configVariants {
|
||||
|
||||
let schemeName = "\(target.name) \(configVariant)"
|
||||
|
||||
let debugConfig = project.configs
|
||||
.first { $0.type == .debug && $0.name.contains(configVariant) }!
|
||||
let releaseConfig = project.configs
|
||||
.first { $0.type == .release && $0.name.contains(configVariant) }!
|
||||
|
||||
let scheme = Scheme(
|
||||
name: schemeName,
|
||||
target: target,
|
||||
targetScheme: targetScheme,
|
||||
debugConfig: debugConfig.name,
|
||||
releaseConfig: releaseConfig.name
|
||||
)
|
||||
let xcscheme = try generateScheme(scheme)
|
||||
xcschemes.append(xcscheme)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return xcschemes
|
||||
}
|
||||
|
||||
public func generateScheme(_ scheme: Scheme) throws -> XCScheme {
|
||||
|
||||
func getBuildEntry(_ buildTarget: Scheme.BuildTarget) -> XCScheme.BuildAction.Entry {
|
||||
|
||||
guard let pbxTarget = pbxProj.targets(named: buildTarget.target).first else {
|
||||
fatalError("Unable to find target named \"\(buildTarget.target)\" in \"PBXProj.targets\"")
|
||||
}
|
||||
|
||||
guard let buildableName =
|
||||
project.getTarget(buildTarget.target)?.filename ??
|
||||
project.getAggregateTarget(buildTarget.target)?.name else {
|
||||
fatalError("Unable to determinate \"buildableName\" for build target: \(buildTarget.target)")
|
||||
}
|
||||
let buildableReference = XCScheme.BuildableReference(
|
||||
referencedContainer: "container:\(project.name).xcodeproj",
|
||||
blueprint: pbxTarget,
|
||||
buildableName: buildableName,
|
||||
blueprintName: buildTarget.target
|
||||
)
|
||||
return XCScheme.BuildAction.Entry(buildableReference: buildableReference, buildFor: buildTarget.buildTypes)
|
||||
}
|
||||
|
||||
let testTargets = scheme.test?.targets ?? []
|
||||
let testBuildTargets = testTargets.map {
|
||||
Scheme.BuildTarget(target: $0.name, buildTypes: BuildType.testOnly)
|
||||
}
|
||||
|
||||
let testBuildTargetEntries = testBuildTargets.map(getBuildEntry)
|
||||
|
||||
let buildActionEntries: [XCScheme.BuildAction.Entry] = scheme.build.targets.map(getBuildEntry)
|
||||
|
||||
func getExecutionAction(_ action: Scheme.ExecutionAction) -> XCScheme.ExecutionAction {
|
||||
// ExecutionActions can require the use of build settings. Xcode allows the settings to come from a build or test target.
|
||||
let environmentBuildable = action.settingsTarget.flatMap { settingsTarget in
|
||||
return (buildActionEntries + testBuildTargetEntries)
|
||||
.first { settingsTarget == $0.buildableReference.blueprintName }?
|
||||
.buildableReference
|
||||
}
|
||||
return XCScheme.ExecutionAction(scriptText: action.script, title: action.name, environmentBuildable: environmentBuildable)
|
||||
}
|
||||
|
||||
let target = project.getTarget(scheme.build.targets.first!.target)
|
||||
let shouldExecuteOnLaunch = target?.type.isExecutable == true
|
||||
|
||||
let buildableReference = buildActionEntries.first!.buildableReference
|
||||
let productRunable = XCScheme.BuildableProductRunnable(buildableReference: buildableReference)
|
||||
|
||||
let buildAction = XCScheme.BuildAction(
|
||||
buildActionEntries: buildActionEntries,
|
||||
preActions: scheme.build.preActions.map(getExecutionAction),
|
||||
postActions: scheme.build.postActions.map(getExecutionAction),
|
||||
parallelizeBuild: scheme.build.parallelizeBuild,
|
||||
buildImplicitDependencies: scheme.build.buildImplicitDependencies
|
||||
)
|
||||
|
||||
let testables = zip(testTargets, testBuildTargetEntries).map { testTarget, testBuilEntries in
|
||||
XCScheme.TestableReference(
|
||||
skipped: false,
|
||||
parallelizable: testTarget.parallelizable,
|
||||
randomExecutionOrdering: testTarget.randomExecutionOrder,
|
||||
buildableReference: testBuilEntries.buildableReference
|
||||
)
|
||||
}
|
||||
|
||||
let testCommandLineArgs = scheme.test.map { XCScheme.CommandLineArguments($0.commandLineArguments) }
|
||||
let launchCommandLineArgs = scheme.run.map { XCScheme.CommandLineArguments($0.commandLineArguments) }
|
||||
let profileCommandLineArgs = scheme.profile.map { XCScheme.CommandLineArguments($0.commandLineArguments) }
|
||||
|
||||
let testVariables = scheme.test.flatMap { $0.environmentVariables.isEmpty ? nil : $0.environmentVariables }
|
||||
let launchVariables = scheme.run.flatMap { $0.environmentVariables.isEmpty ? nil : $0.environmentVariables }
|
||||
let profileVariables = scheme.profile.flatMap { $0.environmentVariables.isEmpty ? nil : $0.environmentVariables }
|
||||
|
||||
let testAction = XCScheme.TestAction(
|
||||
buildConfiguration: scheme.test?.config ?? defaultDebugConfig.name,
|
||||
macroExpansion: buildableReference,
|
||||
testables: testables,
|
||||
preActions: scheme.test?.preActions.map(getExecutionAction) ?? [],
|
||||
postActions: scheme.test?.postActions.map(getExecutionAction) ?? [],
|
||||
shouldUseLaunchSchemeArgsEnv: scheme.test?.shouldUseLaunchSchemeArgsEnv ?? true,
|
||||
codeCoverageEnabled: scheme.test?.gatherCoverageData ?? false,
|
||||
commandlineArguments: testCommandLineArgs,
|
||||
environmentVariables: testVariables
|
||||
)
|
||||
|
||||
let launchAction = XCScheme.LaunchAction(
|
||||
buildableProductRunnable: shouldExecuteOnLaunch ? productRunable : nil,
|
||||
buildConfiguration: scheme.run?.config ?? defaultDebugConfig.name,
|
||||
preActions: scheme.run?.preActions.map(getExecutionAction) ?? [],
|
||||
postActions: scheme.run?.postActions.map(getExecutionAction) ?? [],
|
||||
macroExpansion: shouldExecuteOnLaunch ? nil : buildableReference,
|
||||
commandlineArguments: launchCommandLineArgs,
|
||||
environmentVariables: launchVariables
|
||||
)
|
||||
|
||||
let profileAction = XCScheme.ProfileAction(
|
||||
buildableProductRunnable: productRunable,
|
||||
buildConfiguration: scheme.profile?.config ?? defaultReleaseConfig.name,
|
||||
preActions: scheme.profile?.preActions.map(getExecutionAction) ?? [],
|
||||
postActions: scheme.profile?.postActions.map(getExecutionAction) ?? [],
|
||||
shouldUseLaunchSchemeArgsEnv: scheme.profile?.shouldUseLaunchSchemeArgsEnv ?? true,
|
||||
commandlineArguments: profileCommandLineArgs,
|
||||
environmentVariables: profileVariables
|
||||
)
|
||||
|
||||
let analyzeAction = XCScheme.AnalyzeAction(buildConfiguration: scheme.analyze?.config ?? defaultDebugConfig.name)
|
||||
|
||||
let archiveAction = XCScheme.ArchiveAction(
|
||||
buildConfiguration: scheme.archive?.config ?? defaultReleaseConfig.name,
|
||||
revealArchiveInOrganizer: scheme.archive?.revealArchiveInOrganizer ?? true,
|
||||
customArchiveName: scheme.archive?.customArchiveName,
|
||||
preActions: scheme.archive?.preActions.map(getExecutionAction) ?? [],
|
||||
postActions: scheme.archive?.postActions.map(getExecutionAction) ?? []
|
||||
)
|
||||
|
||||
return XCScheme(
|
||||
name: scheme.name,
|
||||
lastUpgradeVersion: project.xcodeVersion,
|
||||
version: project.schemeVersion,
|
||||
buildAction: buildAction,
|
||||
testAction: testAction,
|
||||
launchAction: launchAction,
|
||||
profileAction: profileAction,
|
||||
analyzeAction: analyzeAction,
|
||||
archiveAction: archiveAction
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension Scheme {
|
||||
public init(name: String, target: Target, targetScheme: TargetScheme, debugConfig: String, releaseConfig: String) {
|
||||
self.init(
|
||||
name: name,
|
||||
build: .init(targets: [Scheme.BuildTarget(target: target.name)]),
|
||||
run: .init(
|
||||
config: debugConfig,
|
||||
commandLineArguments: targetScheme.commandLineArguments,
|
||||
preActions: targetScheme.preActions,
|
||||
postActions: targetScheme.postActions,
|
||||
environmentVariables: targetScheme.environmentVariables
|
||||
),
|
||||
test: .init(
|
||||
config: debugConfig,
|
||||
gatherCoverageData: targetScheme.gatherCoverageData,
|
||||
commandLineArguments: targetScheme.commandLineArguments,
|
||||
targets: targetScheme.testTargets,
|
||||
preActions: targetScheme.preActions,
|
||||
postActions: targetScheme.postActions,
|
||||
environmentVariables: targetScheme.environmentVariables
|
||||
),
|
||||
profile: .init(
|
||||
config: releaseConfig,
|
||||
commandLineArguments: targetScheme.commandLineArguments,
|
||||
preActions: targetScheme.preActions,
|
||||
postActions: targetScheme.postActions,
|
||||
environmentVariables: targetScheme.environmentVariables
|
||||
),
|
||||
analyze: .init(
|
||||
config: debugConfig
|
||||
),
|
||||
archive: .init(
|
||||
config: releaseConfig,
|
||||
preActions: targetScheme.preActions,
|
||||
postActions: targetScheme.postActions
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import Foundation
|
||||
import JSONUtilities
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import Yams
|
||||
|
||||
extension Project {
|
||||
@@ -10,6 +10,15 @@ extension Project {
|
||||
public func getProjectBuildSettings(config: Config) -> BuildSettings {
|
||||
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 type = config.type, options.settingPresets.applyProject {
|
||||
buildSettings += SettingsPresetFile.base.getBuildSettings()
|
||||
buildSettings += SettingsPresetFile.config(type).getBuildSettings()
|
||||
@@ -81,31 +90,27 @@ extension Project {
|
||||
}
|
||||
|
||||
// combines all levels of a target's settings: target, target config, project, project config
|
||||
public func getCombinedBuildSettings(basePath: Path, target: ProjectTarget, config: Config, includeProject: Bool = true) -> BuildSettings {
|
||||
var buildSettings: BuildSettings = [:]
|
||||
if includeProject {
|
||||
if let configFilePath = configFiles[config.name] {
|
||||
buildSettings += loadConfigFileBuildSettings(path: configFilePath)
|
||||
}
|
||||
buildSettings += getProjectBuildSettings(config: config)
|
||||
public func getCombinedBuildSetting(_ setting: String, target: ProjectTarget, config: Config) -> Any? {
|
||||
if let target = target as? Target,
|
||||
let value = getTargetBuildSettings(target: target, config: config)[setting] {
|
||||
return value
|
||||
}
|
||||
if let configFilePath = target.configFiles[config.name] {
|
||||
buildSettings += loadConfigFileBuildSettings(path: configFilePath)
|
||||
if let configFilePath = target.configFiles[config.name],
|
||||
let value = loadConfigFileBuildSettings(path: configFilePath)?[setting] {
|
||||
return value
|
||||
}
|
||||
if let target = target as? Target {
|
||||
buildSettings += getTargetBuildSettings(target: target, config: config)
|
||||
if let value = getProjectBuildSettings(config: config)[setting] {
|
||||
return value
|
||||
}
|
||||
return buildSettings
|
||||
if let configFilePath = configFiles[config.name],
|
||||
let value = loadConfigFileBuildSettings(path: configFilePath)?[setting] {
|
||||
return value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public func targetHasBuildSetting(_ setting: String, basePath: Path, target: Target, config: Config, includeProject: Bool = true) -> Bool {
|
||||
let buildSettings = getCombinedBuildSettings(
|
||||
basePath: basePath,
|
||||
target: target,
|
||||
config: config,
|
||||
includeProject: includeProject
|
||||
)
|
||||
return buildSettings[setting] != nil
|
||||
public func targetHasBuildSetting(_ setting: String, target: Target, config: Config) -> Bool {
|
||||
return getCombinedBuildSetting(setting, target: target, config: config) != nil
|
||||
}
|
||||
|
||||
/// Removes values from build settings if they are defined in an xcconfig file
|
||||
@@ -126,28 +131,43 @@ extension Project {
|
||||
/// Returns cached build settings from a config file
|
||||
private func loadConfigFileBuildSettings(path: String) -> BuildSettings? {
|
||||
let configFilePath = basePath + path
|
||||
if let settings = configFileSettings[configFilePath.string] {
|
||||
return settings
|
||||
if let cached = configFileSettings[configFilePath.string] {
|
||||
return cached.value
|
||||
} else {
|
||||
guard let configFile = try? XCConfig(path: configFilePath) else { return nil }
|
||||
guard let configFile = try? XCConfig(path: configFilePath) else {
|
||||
configFileSettings[configFilePath.string] = .nothing
|
||||
return nil
|
||||
}
|
||||
let settings = configFile.flattenedBuildSettings()
|
||||
configFileSettings[configFilePath.string] = settings
|
||||
configFileSettings[configFilePath.string] = .cached(settings)
|
||||
return settings
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum Cached<T> {
|
||||
case cached(T)
|
||||
case nothing
|
||||
|
||||
var value: T? {
|
||||
switch self {
|
||||
case let .cached(value): return value
|
||||
case .nothing: return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// cached flattened xcconfig file settings
|
||||
private var configFileSettings: [String: BuildSettings] = [:]
|
||||
private var configFileSettings: [String: Cached<BuildSettings>] = [:]
|
||||
|
||||
// cached setting preset settings
|
||||
private var settingPresetSettings: [String: BuildSettings] = [:]
|
||||
private var settingPresetSettings: [String: Cached<BuildSettings>] = [:]
|
||||
|
||||
extension SettingsPresetFile {
|
||||
|
||||
public func getBuildSettings() -> BuildSettings? {
|
||||
if let group = settingPresetSettings[path] {
|
||||
return group
|
||||
if let cached = settingPresetSettings[path] {
|
||||
return cached.value
|
||||
}
|
||||
let bundlePath = Path(Bundle.main.bundlePath)
|
||||
let relativePath = Path("SettingPresets/\(path).yml")
|
||||
@@ -171,6 +191,7 @@ extension SettingsPresetFile {
|
||||
case .product, .productPlatform:
|
||||
break
|
||||
}
|
||||
settingPresetSettings[path] = .nothing
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -178,7 +199,7 @@ extension SettingsPresetFile {
|
||||
print("Error parsing \"\(name)\" settings")
|
||||
return nil
|
||||
}
|
||||
settingPresetSettings[path] = buildSettings
|
||||
settingPresetSettings[path] = .cached(buildSettings)
|
||||
return buildSettings
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import ProjectSpec
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
public enum SettingsPresetFile {
|
||||
case config(ConfigType)
|
||||
|
||||
@@ -1,45 +1,41 @@
|
||||
import Foundation
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
|
||||
struct SourceFile {
|
||||
let path: Path
|
||||
let fileReference: String
|
||||
let fileReference: PBXFileElement
|
||||
let buildFile: PBXBuildFile
|
||||
let buildPhase: TargetSource.BuildPhase?
|
||||
}
|
||||
|
||||
class SourceGenerator {
|
||||
|
||||
var rootGroups: Set<String> = []
|
||||
private var fileReferencesByPath: [String: String] = [:]
|
||||
private var groupsByPath: [Path: ObjectReference<PBXGroup>] = [:]
|
||||
private var variantGroupsByPath: [Path: ObjectReference<PBXVariantGroup>] = [:]
|
||||
var rootGroups: Set<PBXFileElement> = []
|
||||
private var fileReferencesByPath: [String: PBXFileElement] = [:]
|
||||
private var groupsByPath: [Path: PBXGroup] = [:]
|
||||
private var variantGroupsByPath: [Path: PBXVariantGroup] = [:]
|
||||
|
||||
private let project: Project
|
||||
var addObjectClosure: (String, PBXObject) -> String
|
||||
let pbxProj: PBXProj
|
||||
|
||||
var targetSourceExcludePaths: Set<Path> = []
|
||||
var defaultExcludedFiles = [
|
||||
".DS_Store",
|
||||
]
|
||||
|
||||
var targetName: String = ""
|
||||
|
||||
private(set) var knownRegions: Set<String> = []
|
||||
|
||||
init(project: Project, addObjectClosure: @escaping (String, PBXObject) -> String) {
|
||||
init(project: Project, pbxProj: PBXProj) {
|
||||
self.project = project
|
||||
self.addObjectClosure = addObjectClosure
|
||||
self.pbxProj = pbxProj
|
||||
}
|
||||
|
||||
func addObject(id: String, _ object: PBXObject) -> String {
|
||||
return addObjectClosure(id, object)
|
||||
}
|
||||
|
||||
func createObject<T: PBXObject>(id: String, _ object: T) -> ObjectReference<T> {
|
||||
let reference = addObject(id: id, object)
|
||||
return ObjectReference(reference: reference, object: object)
|
||||
func addObject<T: PBXObject>(_ object: T, context: String? = nil) -> T {
|
||||
pbxProj.add(object: object)
|
||||
object.context = context
|
||||
return object
|
||||
}
|
||||
|
||||
func getAllSourceFiles(targetType: PBXProductType, sources: [TargetSource]) throws -> [SourceFile] {
|
||||
@@ -91,7 +87,7 @@ class SourceGenerator {
|
||||
settings["COMPILER_FLAGS"] = targetSource.compilerFlags.joined(separator: " ")
|
||||
}
|
||||
|
||||
let buildFile = PBXBuildFile(fileRef: fileReference, settings: settings.isEmpty ? nil : settings)
|
||||
let buildFile = PBXBuildFile(file: fileReference, settings: settings.isEmpty ? nil : settings)
|
||||
return SourceFile(
|
||||
path: path,
|
||||
fileReference: fileReference,
|
||||
@@ -100,7 +96,7 @@ class SourceGenerator {
|
||||
)
|
||||
}
|
||||
|
||||
func getContainedFileReference(path: Path) -> String {
|
||||
func getContainedFileReference(path: Path) -> PBXFileElement {
|
||||
let createIntermediateGroups = project.options.createIntermediateGroups
|
||||
|
||||
let parentPath = path.parent()
|
||||
@@ -113,12 +109,12 @@ class SourceGenerator {
|
||||
)
|
||||
|
||||
if createIntermediateGroups {
|
||||
createIntermediaGroups(for: parentGroup.reference, at: parentPath)
|
||||
createIntermediaGroups(for: parentGroup, at: parentPath)
|
||||
}
|
||||
return fileReference
|
||||
}
|
||||
|
||||
func getFileReference(path: Path, inPath: Path, name: String? = nil, sourceTree: PBXSourceTree = .group, lastKnownFileType: String? = nil) -> String {
|
||||
func getFileReference(path: Path, inPath: Path, name: String? = nil, sourceTree: PBXSourceTree = .group, lastKnownFileType: String? = nil) -> PBXFileElement {
|
||||
let fileReferenceKey = path.string.lowercased()
|
||||
if let fileReference = fileReferencesByPath[fileReferenceKey] {
|
||||
return fileReference
|
||||
@@ -128,7 +124,7 @@ class SourceGenerator {
|
||||
if fileReferencePath.string == fileReferenceName {
|
||||
fileReferenceName = nil
|
||||
}
|
||||
let lastKnownFileType = lastKnownFileType ?? PBXFileReference.fileType(path: path)
|
||||
let lastKnownFileType = lastKnownFileType ?? Xcode.fileType(path: path)
|
||||
|
||||
if path.extension == "xcdatamodeld" {
|
||||
let versionedModels = (try? path.children()) ?? []
|
||||
@@ -138,10 +134,9 @@ class SourceGenerator {
|
||||
.filter { $0.extension == "xcdatamodel" }
|
||||
.sorted { $0.string.localizedStandardCompare($1.string) == .orderedAscending }
|
||||
|
||||
let modelFileReference =
|
||||
let modelFileReferences =
|
||||
sortedPaths.map { path in
|
||||
createObject(
|
||||
id: path.byRemovingBase(path: project.basePath).string,
|
||||
addObject(
|
||||
PBXFileReference(
|
||||
sourceTree: .group,
|
||||
lastKnownFileType: "wrapper.xcdatamodel",
|
||||
@@ -152,23 +147,22 @@ class SourceGenerator {
|
||||
// If no current version path is found we fall back to alphabetical
|
||||
// order by taking the last item in the sortedPaths array
|
||||
let currentVersionPath = findCurrentCoreDataModelVersionPath(using: versionedModels) ?? sortedPaths.last
|
||||
let currentVersion: ObjectReference<PBXFileReference>? = {
|
||||
let currentVersion: PBXFileReference? = {
|
||||
guard let indexOf = sortedPaths.index(where: { $0 == currentVersionPath }) else { return nil }
|
||||
return modelFileReference[indexOf]
|
||||
return modelFileReferences[indexOf]
|
||||
}()
|
||||
let versionGroup = addObject(id: fileReferencePath.string, XCVersionGroup(
|
||||
currentVersion: currentVersion?.reference,
|
||||
let versionGroup = addObject(XCVersionGroup(
|
||||
currentVersion: currentVersion,
|
||||
path: fileReferencePath.string,
|
||||
sourceTree: sourceTree,
|
||||
versionGroupType: "wrapper.xcdatamodel",
|
||||
children: modelFileReference.map { $0.reference }
|
||||
children: modelFileReferences
|
||||
))
|
||||
fileReferencesByPath[fileReferenceKey] = versionGroup
|
||||
return versionGroup
|
||||
} else {
|
||||
// For all extensions other than `xcdatamodeld`
|
||||
let fileReference = createObject(
|
||||
id: path.byRemovingBase(path: project.basePath).string,
|
||||
let fileReference = addObject(
|
||||
PBXFileReference(
|
||||
sourceTree: sourceTree,
|
||||
name: fileReferenceName,
|
||||
@@ -176,8 +170,8 @@ class SourceGenerator {
|
||||
path: fileReferencePath.string
|
||||
)
|
||||
)
|
||||
fileReferencesByPath[fileReferenceKey] = fileReference.reference
|
||||
return fileReference.reference
|
||||
fileReferencesByPath[fileReferenceKey] = fileReference
|
||||
return fileReference
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,12 +203,16 @@ class SourceGenerator {
|
||||
|
||||
/// Create a group or return an existing one at the path.
|
||||
/// Any merged children are added to a new group or merged into an existing one.
|
||||
private func getGroup(path: Path, name: String? = nil, mergingChildren children: [String], createIntermediateGroups: Bool, isBaseGroup: Bool) -> ObjectReference<PBXGroup> {
|
||||
let groupReference: ObjectReference<PBXGroup>
|
||||
private func getGroup(path: Path, name: String? = nil, mergingChildren children: [PBXFileElement], createIntermediateGroups: Bool, isBaseGroup: Bool) -> PBXGroup {
|
||||
let groupReference: PBXGroup
|
||||
|
||||
if let cachedGroup = groupsByPath[path] {
|
||||
// only add the children that aren't already in the cachedGroup
|
||||
cachedGroup.object.children = Array(Set(cachedGroup.object.children + children))
|
||||
for child in children {
|
||||
// only add the children that aren't already in the cachedGroup
|
||||
if !cachedGroup.children.contains(child) {
|
||||
cachedGroup.children.append(child)
|
||||
}
|
||||
}
|
||||
groupReference = cachedGroup
|
||||
} else {
|
||||
|
||||
@@ -237,28 +235,27 @@ class SourceGenerator {
|
||||
name: groupName != groupPath ? groupName : nil,
|
||||
path: groupPath
|
||||
)
|
||||
groupReference = createObject(id: path.byRemovingBase(path: project.basePath).string, group)
|
||||
groupReference = addObject(group)
|
||||
groupsByPath[path] = groupReference
|
||||
|
||||
if isTopLevelGroup {
|
||||
rootGroups.insert(groupReference.reference)
|
||||
rootGroups.insert(groupReference)
|
||||
}
|
||||
}
|
||||
return groupReference
|
||||
}
|
||||
|
||||
/// Creates a variant group or returns an existing one at the path
|
||||
private func getVariantGroup(path: Path, inPath: Path) -> ObjectReference<PBXVariantGroup> {
|
||||
let variantGroup: ObjectReference<PBXVariantGroup>
|
||||
private func getVariantGroup(path: Path, inPath: Path) -> PBXVariantGroup {
|
||||
let variantGroup: PBXVariantGroup
|
||||
if let cachedGroup = variantGroupsByPath[path] {
|
||||
variantGroup = cachedGroup
|
||||
} else {
|
||||
let group = PBXVariantGroup(
|
||||
children: [],
|
||||
sourceTree: .group,
|
||||
name: path.lastComponent
|
||||
)
|
||||
variantGroup = createObject(id: path.byRemovingBase(path: project.basePath).string, group)
|
||||
variantGroup = addObject(group)
|
||||
variantGroupsByPath[path] = variantGroup
|
||||
}
|
||||
return variantGroup
|
||||
@@ -307,27 +304,24 @@ class SourceGenerator {
|
||||
|
||||
/// creates all the source files and groups they belong to for a given targetSource
|
||||
private func getGroupSources(targetType: PBXProductType, targetSource: TargetSource, path: Path, isBaseGroup: Bool)
|
||||
throws -> (sourceFiles: [SourceFile], groups: [ObjectReference<PBXGroup>]) {
|
||||
throws -> (sourceFiles: [SourceFile], groups: [PBXGroup]) {
|
||||
|
||||
let children = try getSourceChildren(targetSource: targetSource, dirPath: path)
|
||||
|
||||
let directories = children
|
||||
.filter { $0.isDirectory && $0.extension == nil && $0.extension != "lproj" }
|
||||
.sorted { $0.lastComponent < $1.lastComponent }
|
||||
|
||||
let filePaths = children
|
||||
.filter { $0.isFile || $0.extension != nil && $0.extension != "lproj" }
|
||||
.sorted { $0.lastComponent < $1.lastComponent }
|
||||
|
||||
let localisedDirectories = children
|
||||
.filter { $0.extension == "lproj" }
|
||||
.sorted { $0.lastComponent < $1.lastComponent }
|
||||
|
||||
var groupChildren: [String] = filePaths.map { getFileReference(path: $0, inPath: path) }
|
||||
var groupChildren: [PBXFileElement] = filePaths.map { getFileReference(path: $0, inPath: path) }
|
||||
var allSourceFiles: [SourceFile] = filePaths.map {
|
||||
generateSourceFile(targetType: targetType, targetSource: targetSource, path: $0)
|
||||
}
|
||||
var groups: [ObjectReference<PBXGroup>] = []
|
||||
var groups: [PBXGroup] = []
|
||||
|
||||
for path in directories {
|
||||
let subGroups = try getGroupSources(targetType: targetType, targetSource: targetSource, path: path, isBaseGroup: false)
|
||||
@@ -338,11 +332,11 @@ class SourceGenerator {
|
||||
|
||||
allSourceFiles += subGroups.sourceFiles
|
||||
|
||||
guard let first = subGroups.groups.first else {
|
||||
guard let firstGroup = subGroups.groups.first else {
|
||||
continue
|
||||
}
|
||||
|
||||
groupChildren.append(first.reference)
|
||||
groupChildren.append(firstGroup)
|
||||
groups += subGroups.groups
|
||||
}
|
||||
|
||||
@@ -365,13 +359,13 @@ class SourceGenerator {
|
||||
.filter(isIncludedPath)
|
||||
.sorted() {
|
||||
let variantGroup = getVariantGroup(path: filePath, inPath: path)
|
||||
groupChildren.append(variantGroup.reference)
|
||||
baseLocalisationVariantGroups.append(variantGroup.object)
|
||||
groupChildren.append(variantGroup)
|
||||
baseLocalisationVariantGroups.append(variantGroup)
|
||||
|
||||
let sourceFile = SourceFile(
|
||||
path: filePath,
|
||||
fileReference: variantGroup.reference,
|
||||
buildFile: PBXBuildFile(fileRef: variantGroup.reference),
|
||||
fileReference: variantGroup,
|
||||
buildFile: PBXBuildFile(file: variantGroup),
|
||||
buildPhase: .resources
|
||||
)
|
||||
allSourceFiles.append(sourceFile)
|
||||
@@ -409,7 +403,7 @@ class SourceGenerator {
|
||||
let sourceFile = SourceFile(
|
||||
path: filePath,
|
||||
fileReference: fileReference,
|
||||
buildFile: PBXBuildFile(fileRef: fileReference),
|
||||
buildFile: PBXBuildFile(file: fileReference),
|
||||
buildPhase: .resources
|
||||
)
|
||||
allSourceFiles.append(sourceFile)
|
||||
@@ -425,7 +419,7 @@ class SourceGenerator {
|
||||
isBaseGroup: isBaseGroup
|
||||
)
|
||||
if project.options.createIntermediateGroups {
|
||||
createIntermediaGroups(for: group.reference, at: path)
|
||||
createIntermediaGroups(for: group, at: path)
|
||||
}
|
||||
|
||||
groups.insert(group, at: 0)
|
||||
@@ -442,7 +436,7 @@ class SourceGenerator {
|
||||
let createIntermediateGroups = project.options.createIntermediateGroups
|
||||
|
||||
var sourceFiles: [SourceFile] = []
|
||||
let sourceReference: String
|
||||
let sourceReference: PBXFileElement
|
||||
var sourcePath = path
|
||||
switch type {
|
||||
case .folder:
|
||||
@@ -483,7 +477,7 @@ class SourceGenerator {
|
||||
} else {
|
||||
let parentGroup = getGroup(path: parentPath, mergingChildren: [fileReference], createIntermediateGroups: createIntermediateGroups, isBaseGroup: true)
|
||||
sourcePath = parentPath
|
||||
sourceReference = parentGroup.reference
|
||||
sourceReference = parentGroup
|
||||
}
|
||||
sourceFiles.append(sourceFile)
|
||||
|
||||
@@ -491,11 +485,11 @@ class SourceGenerator {
|
||||
let (groupSourceFiles, groups) = try getGroupSources(targetType: targetType, targetSource: targetSource, path: path, isBaseGroup: true)
|
||||
let group = groups.first!
|
||||
if let name = targetSource.name {
|
||||
group.object.name = name
|
||||
group.name = name
|
||||
}
|
||||
|
||||
sourceFiles += groupSourceFiles
|
||||
sourceReference = group.reference
|
||||
sourceReference = group
|
||||
}
|
||||
|
||||
if createIntermediateGroups {
|
||||
@@ -506,7 +500,7 @@ class SourceGenerator {
|
||||
}
|
||||
|
||||
// Add groups for all parents recursively
|
||||
private func createIntermediaGroups(for groupReference: String, at path: Path) {
|
||||
private func createIntermediaGroups(for fileElement: PBXFileElement, at path: Path) {
|
||||
|
||||
let parentPath = path.parent()
|
||||
guard parentPath != project.basePath && path.string.contains(project.basePath.string) else {
|
||||
@@ -515,10 +509,10 @@ class SourceGenerator {
|
||||
}
|
||||
|
||||
let hasParentGroup = groupsByPath[parentPath] != nil
|
||||
let parentGroup = getGroup(path: parentPath, mergingChildren: [groupReference], createIntermediateGroups: true, isBaseGroup: false)
|
||||
let parentGroup = getGroup(path: parentPath, mergingChildren: [fileElement], createIntermediateGroups: true, isBaseGroup: false)
|
||||
|
||||
if !hasParentGroup {
|
||||
createIntermediaGroups(for: parentGroup.reference, at: parentPath)
|
||||
createIntermediaGroups(for: parentGroup, at: parentPath)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import ProjectSpec
|
||||
extension Project {
|
||||
|
||||
var xcodeVersion: String {
|
||||
return XCodeVersion.parse(options.xcodeVersion ?? "9.3")
|
||||
return XCodeVersion.parse(options.xcodeVersion ?? "10.0")
|
||||
}
|
||||
|
||||
var schemeVersion: String {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Foundation
|
||||
import xcproj
|
||||
import PathKit
|
||||
import xcodeproj
|
||||
|
||||
extension PBXFileElement {
|
||||
|
||||
@@ -11,8 +12,8 @@ extension PBXFileElement {
|
||||
extension PBXProj {
|
||||
|
||||
public func printGroups() -> String {
|
||||
guard let project = objects.projects.first?.value,
|
||||
let mainGroup = objects.groups.getReference(project.mainGroup) else {
|
||||
guard let project = projects.first,
|
||||
let mainGroup = project.mainGroup else {
|
||||
return ""
|
||||
}
|
||||
return printGroup(group: mainGroup)
|
||||
@@ -20,17 +21,31 @@ extension PBXProj {
|
||||
|
||||
public func printGroup(group: PBXGroup) -> String {
|
||||
var string = group.nameOrPath
|
||||
for reference in group.children {
|
||||
if let group = objects.groups.getReference(reference) {
|
||||
for child in group.children {
|
||||
if let group = child as? PBXGroup {
|
||||
string += "\n 📁 " + printGroup(group: group).replacingOccurrences(of: "\n ", with: "\n ")
|
||||
} else if let fileReference = objects.fileReferences.getReference(reference) {
|
||||
} else if let fileReference = child as? PBXFileReference {
|
||||
string += "\n 📄 " + fileReference.nameOrPath
|
||||
} else if let variantGroup = objects.variantGroups.getReference(reference) {
|
||||
} else if let variantGroup = child as? PBXVariantGroup {
|
||||
string += "\n 🌎 " + variantGroup.nameOrPath
|
||||
} else if let versionGroup = objects.versionGroups.getReference(reference) {
|
||||
} else if let versionGroup = child as? XCVersionGroup {
|
||||
string += "\n 🔢 " + versionGroup.nameOrPath
|
||||
}
|
||||
}
|
||||
return string
|
||||
}
|
||||
}
|
||||
|
||||
extension Dictionary {
|
||||
|
||||
public var valueArray: Array<Value> {
|
||||
return Array(values)
|
||||
}
|
||||
}
|
||||
|
||||
extension Xcode {
|
||||
|
||||
public static func fileType(path: Path) -> String? {
|
||||
return path.extension.flatMap { Xcode.filetype(extension: $0) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<string>group.com.app</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -6,7 +6,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
_ = FrameworkStruct()
|
||||
// Standalone files added to project by path-to-file.
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import Contacts
|
||||
import UIKit
|
||||
|
||||
class ViewController: UIViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
_ = CNContact()
|
||||
}
|
||||
|
||||
override func didReceiveMemoryWarning() {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import Cocoa
|
||||
|
||||
@NSApplicationMain
|
||||
class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
|
||||
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
||||
// Insert code here to initialize your application
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ aNotification: Notification) {
|
||||
// Insert code here to tear down your application
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "16x16",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "16x16",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "32x32",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "32x32",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "128x128",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "128x128",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "256x256",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "256x256",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "512x512",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "512x512",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,717 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="11134" systemVersion="15F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11134"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Application-->
|
||||
<scene sceneID="JPo-4y-FX3">
|
||||
<objects>
|
||||
<application id="hnw-xV-0zn" sceneMemberID="viewController">
|
||||
<menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
|
||||
<items>
|
||||
<menuItem title="dfg" id="1Xt-HY-uBw">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="dfg" systemMenu="apple" id="uQy-DD-JDr">
|
||||
<items>
|
||||
<menuItem title="About dfg" id="5kV-Vb-QxS">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
|
||||
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
|
||||
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
|
||||
<menuItem title="Services" id="NMo-om-nkz">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
|
||||
<menuItem title="Hide dfg" keyEquivalent="h" id="Olw-nP-bQN">
|
||||
<connections>
|
||||
<action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Show All" id="Kd2-mp-pUS">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
|
||||
<menuItem title="Quit dfg" keyEquivalent="q" id="4sb-4s-VLi">
|
||||
<connections>
|
||||
<action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="File" id="dMs-cI-mzQ">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="File" id="bib-Uj-vzu">
|
||||
<items>
|
||||
<menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
|
||||
<connections>
|
||||
<action selector="newDocument:" target="Ady-hI-5gd" id="4Si-XN-c54"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
|
||||
<connections>
|
||||
<action selector="openDocument:" target="Ady-hI-5gd" id="bVn-NM-KNZ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Open Recent" id="tXI-mr-wws">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
|
||||
<items>
|
||||
<menuItem title="Clear Menu" id="vNY-rz-j42">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="clearRecentDocuments:" target="Ady-hI-5gd" id="Daa-9d-B3U"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
|
||||
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
|
||||
<connections>
|
||||
<action selector="performClose:" target="Ady-hI-5gd" id="HmO-Ls-i7Q"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
|
||||
<connections>
|
||||
<action selector="saveDocument:" target="Ady-hI-5gd" id="teZ-XB-qJY"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
|
||||
<connections>
|
||||
<action selector="saveDocumentAs:" target="Ady-hI-5gd" id="mDf-zr-I0C"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Revert to Saved" keyEquivalent="r" id="KaW-ft-85H">
|
||||
<connections>
|
||||
<action selector="revertDocumentToSaved:" target="Ady-hI-5gd" id="iJ3-Pv-kwq"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
|
||||
<menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
|
||||
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="runPageLayout:" target="Ady-hI-5gd" id="Din-rz-gC5"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
|
||||
<connections>
|
||||
<action selector="print:" target="Ady-hI-5gd" id="qaZ-4w-aoO"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Edit" id="5QF-Oa-p0T">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
|
||||
<items>
|
||||
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
|
||||
<connections>
|
||||
<action selector="undo:" target="Ady-hI-5gd" id="M6e-cu-g7V"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
|
||||
<connections>
|
||||
<action selector="redo:" target="Ady-hI-5gd" id="oIA-Rs-6OD"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
|
||||
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
|
||||
<connections>
|
||||
<action selector="cut:" target="Ady-hI-5gd" id="YJe-68-I9s"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
|
||||
<connections>
|
||||
<action selector="copy:" target="Ady-hI-5gd" id="G1f-GL-Joy"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
|
||||
<connections>
|
||||
<action selector="paste:" target="Ady-hI-5gd" id="UvS-8e-Qdg"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="pasteAsPlainText:" target="Ady-hI-5gd" id="cEh-KX-wJQ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Delete" id="pa3-QI-u2k">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="delete:" target="Ady-hI-5gd" id="0Mk-Ml-PaM"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
|
||||
<connections>
|
||||
<action selector="selectAll:" target="Ady-hI-5gd" id="VNm-Mi-diN"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
|
||||
<menuItem title="Find" id="4EN-yA-p0u">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Find" id="1b7-l0-nxx">
|
||||
<items>
|
||||
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="cD7-Qs-BN4"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="WD3-Gg-5AJ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="NDo-RZ-v9R"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="HOh-sY-3ay"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="U76-nv-p5D"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
|
||||
<connections>
|
||||
<action selector="centerSelectionInVisibleArea:" target="Ady-hI-5gd" id="IOG-6D-g5B"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
|
||||
<items>
|
||||
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
|
||||
<connections>
|
||||
<action selector="showGuessPanel:" target="Ady-hI-5gd" id="vFj-Ks-hy3"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
|
||||
<connections>
|
||||
<action selector="checkSpelling:" target="Ady-hI-5gd" id="fz7-VC-reM"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
|
||||
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleContinuousSpellChecking:" target="Ady-hI-5gd" id="7w6-Qz-0kB"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleGrammarChecking:" target="Ady-hI-5gd" id="muD-Qn-j4w"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticSpellingCorrection:" target="Ady-hI-5gd" id="2lM-Qi-WAP"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Substitutions" id="9ic-FL-obx">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
|
||||
<items>
|
||||
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="orderFrontSubstitutionsPanel:" target="Ady-hI-5gd" id="oku-mr-iSq"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
|
||||
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleSmartInsertDelete:" target="Ady-hI-5gd" id="3IJ-Se-DZD"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticQuoteSubstitution:" target="Ady-hI-5gd" id="ptq-xd-QOA"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticDashSubstitution:" target="Ady-hI-5gd" id="oCt-pO-9gS"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Links" id="cwL-P1-jid">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticLinkDetection:" target="Ady-hI-5gd" id="Gip-E3-Fov"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Data Detectors" id="tRr-pd-1PS">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticDataDetection:" target="Ady-hI-5gd" id="R1I-Nq-Kbl"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticTextReplacement:" target="Ady-hI-5gd" id="DvP-Fe-Py6"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Transformations" id="2oI-Rn-ZJC">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
|
||||
<items>
|
||||
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="uppercaseWord:" target="Ady-hI-5gd" id="sPh-Tk-edu"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="lowercaseWord:" target="Ady-hI-5gd" id="iUZ-b5-hil"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="capitalizeWord:" target="Ady-hI-5gd" id="26H-TL-nsh"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Speech" id="xrE-MZ-jX0">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
|
||||
<items>
|
||||
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="startSpeaking:" target="Ady-hI-5gd" id="654-Ng-kyl"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="stopSpeaking:" target="Ady-hI-5gd" id="dX8-6p-jy9"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Format" id="jxT-CU-nIS">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Format" id="GEO-Iw-cKr">
|
||||
<items>
|
||||
<menuItem title="Font" id="Gi5-1S-RQB">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq">
|
||||
<items>
|
||||
<menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq">
|
||||
<connections>
|
||||
<action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27">
|
||||
<connections>
|
||||
<action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq">
|
||||
<connections>
|
||||
<action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S">
|
||||
<connections>
|
||||
<action selector="underline:" target="Ady-hI-5gd" id="FYS-2b-JAY"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/>
|
||||
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL">
|
||||
<connections>
|
||||
<action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST">
|
||||
<connections>
|
||||
<action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/>
|
||||
<menuItem title="Kern" id="jBQ-r6-VK2">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Kern" id="tlD-Oa-oAM">
|
||||
<items>
|
||||
<menuItem title="Use Default" id="GUa-eO-cwY">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="useStandardKerning:" target="Ady-hI-5gd" id="6dk-9l-Ckg"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Use None" id="cDB-IK-hbR">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="turnOffKerning:" target="Ady-hI-5gd" id="U8a-gz-Maa"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Tighten" id="46P-cB-AYj">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="tightenKerning:" target="Ady-hI-5gd" id="hr7-Nz-8ro"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Loosen" id="ogc-rX-tC1">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="loosenKerning:" target="Ady-hI-5gd" id="8i4-f9-FKE"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Ligatures" id="o6e-r0-MWq">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Ligatures" id="w0m-vy-SC9">
|
||||
<items>
|
||||
<menuItem title="Use Default" id="agt-UL-0e3">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="useStandardLigatures:" target="Ady-hI-5gd" id="7uR-wd-Dx6"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Use None" id="J7y-lM-qPV">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="turnOffLigatures:" target="Ady-hI-5gd" id="iX2-gA-Ilz"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Use All" id="xQD-1f-W4t">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="useAllLigatures:" target="Ady-hI-5gd" id="KcB-kA-TuK"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Baseline" id="OaQ-X3-Vso">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Baseline" id="ijk-EB-dga">
|
||||
<items>
|
||||
<menuItem title="Use Default" id="3Om-Ey-2VK">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="unscript:" target="Ady-hI-5gd" id="0vZ-95-Ywn"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Superscript" id="Rqc-34-cIF">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="superscript:" target="Ady-hI-5gd" id="3qV-fo-wpU"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Subscript" id="I0S-gh-46l">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="subscript:" target="Ady-hI-5gd" id="Q6W-4W-IGz"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Raise" id="2h7-ER-AoG">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="raiseBaseline:" target="Ady-hI-5gd" id="4sk-31-7Q9"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Lower" id="1tx-W0-xDw">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="lowerBaseline:" target="Ady-hI-5gd" id="OF1-bc-KW4"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/>
|
||||
<menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk">
|
||||
<connections>
|
||||
<action selector="orderFrontColorPanel:" target="Ady-hI-5gd" id="mSX-Xz-DV3"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/>
|
||||
<menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="copyFont:" target="Ady-hI-5gd" id="GJO-xA-L4q"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="pasteFont:" target="Ady-hI-5gd" id="JfD-CL-leO"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Text" id="Fal-I4-PZk">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Text" id="d9c-me-L2H">
|
||||
<items>
|
||||
<menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1">
|
||||
<connections>
|
||||
<action selector="alignLeft:" target="Ady-hI-5gd" id="zUv-R1-uAa"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb">
|
||||
<connections>
|
||||
<action selector="alignCenter:" target="Ady-hI-5gd" id="spX-mk-kcS"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Justify" id="J5U-5w-g23">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="alignJustified:" target="Ady-hI-5gd" id="ljL-7U-jND"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4">
|
||||
<connections>
|
||||
<action selector="alignRight:" target="Ady-hI-5gd" id="r48-bG-YeY"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/>
|
||||
<menuItem title="Writing Direction" id="H1b-Si-o9J">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd">
|
||||
<items>
|
||||
<menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem id="YGs-j5-SAR">
|
||||
<string key="title"> Default</string>
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="makeBaseWritingDirectionNatural:" target="Ady-hI-5gd" id="qtV-5e-UBP"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem id="Lbh-J2-qVU">
|
||||
<string key="title"> Left to Right</string>
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="makeBaseWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="S0X-9S-QSf"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem id="jFq-tB-4Kx">
|
||||
<string key="title"> Right to Left</string>
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="makeBaseWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="5fk-qB-AqJ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="swp-gr-a21"/>
|
||||
<menuItem title="Selection" enabled="NO" id="cqv-fj-IhA">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem id="Nop-cj-93Q">
|
||||
<string key="title"> Default</string>
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="makeTextWritingDirectionNatural:" target="Ady-hI-5gd" id="lPI-Se-ZHp"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem id="BgM-ve-c93">
|
||||
<string key="title"> Left to Right</string>
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="makeTextWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="caW-Bv-w94"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem id="RB4-Sm-HuC">
|
||||
<string key="title"> Right to Left</string>
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="makeTextWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="EXD-6r-ZUu"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/>
|
||||
<menuItem title="Show Ruler" id="vLm-3I-IUL">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleRuler:" target="Ady-hI-5gd" id="FOx-HJ-KwY"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5">
|
||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="copyRuler:" target="Ady-hI-5gd" id="71i-fW-3W2"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI">
|
||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="pasteRuler:" target="Ady-hI-5gd" id="cSh-wd-qM2"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="View" id="H8h-7b-M4v">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="View" id="HyV-fh-RgO">
|
||||
<items>
|
||||
<menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="toggleToolbarShown:" target="Ady-hI-5gd" id="BXY-wc-z0C"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="runToolbarCustomizationPalette:" target="Ady-hI-5gd" id="pQI-g3-MTW"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/>
|
||||
<menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE">
|
||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="toggleSourceList:" target="Ady-hI-5gd" id="iwa-gc-5KM"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
|
||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="toggleFullScreen:" target="Ady-hI-5gd" id="dU3-MA-1Rq"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Window" id="aUF-d1-5bR">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
|
||||
<items>
|
||||
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
|
||||
<connections>
|
||||
<action selector="performMiniaturize:" target="Ady-hI-5gd" id="VwT-WD-YPe"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Zoom" id="R4o-n2-Eq4">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="performZoom:" target="Ady-hI-5gd" id="DIl-cC-cCs"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
|
||||
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="arrangeInFront:" target="Ady-hI-5gd" id="DRN-fu-gQh"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Help" id="wpr-3q-Mcd">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
|
||||
<items>
|
||||
<menuItem title="dfg Help" keyEquivalent="?" id="FKE-Sm-Kum">
|
||||
<connections>
|
||||
<action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
|
||||
</connections>
|
||||
</application>
|
||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModuleProvider="target"/>
|
||||
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
||||
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="75" y="0.0"/>
|
||||
</scene>
|
||||
<!--Window Controller-->
|
||||
<scene sceneID="R2V-B0-nI4">
|
||||
<objects>
|
||||
<windowController id="B8D-0N-5wS" sceneMemberID="viewController">
|
||||
<window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="196" y="240" width="480" height="270"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="B8D-0N-5wS" id="98r-iN-zZc"/>
|
||||
</connections>
|
||||
</window>
|
||||
<connections>
|
||||
<segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/>
|
||||
</connections>
|
||||
</windowController>
|
||||
<customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="75" y="250"/>
|
||||
</scene>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="hIz-AP-VOD">
|
||||
<objects>
|
||||
<viewController id="XfG-lQ-9wD" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" wantsLayer="YES" id="m2S-Jp-Qdl">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="75" y="655"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>CustomSetting</key>
|
||||
<string>$CUSTOM_SETTING</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,16 @@
|
||||
import Cocoa
|
||||
|
||||
class ViewController: NSViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
override var representedObject: Any? {
|
||||
didSet {
|
||||
// Update the view, if already loaded.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
import Alamofire
|
||||
import Foundation
|
||||
import Result
|
||||
import WatchKit
|
||||
|
||||
class InterfaceController: WKInterfaceController {
|
||||
|
||||
override func awake(withContext context: Any?) {
|
||||
super.awake(withContext: context)
|
||||
let method = HTTPMethod.get
|
||||
_ = Result<String, NoError>.success("value")
|
||||
// Configure interface objects here.
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<string>1.2</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
|
||||
@@ -1 +1 @@
|
||||
github "Alamofire/Alamofire"
|
||||
github "antitypical/Result"
|
||||
@@ -1 +1 @@
|
||||
github "Alamofire/Alamofire" "4.7.2"
|
||||
github "antitypical/Result" "4.0.0"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+116
@@ -0,0 +1,116 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Production Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
codeCoverageEnabled = "YES"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_D4BAEEEC88124103C8DFF41FCE206DCE"
|
||||
BuildableName = "App_iOS_UITests.xctest"
|
||||
BlueprintName = "App_iOS_UITests"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES"
|
||||
testExecutionOrdering = "random">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_193BAF154270D1C21E269EDF2A1BD3F6"
|
||||
BuildableName = "App_iOS_Tests.xctest"
|
||||
BlueprintName = "App_iOS_Tests"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Production Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Production Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Production Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Production Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
+19
-19
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0930"
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -14,7 +14,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -33,7 +33,7 @@
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_783122899910"
|
||||
BlueprintIdentifier = "NT_193BAF154270D1C21E269EDF2A1BD3F6"
|
||||
BuildableName = "App_iOS_Tests.xctest"
|
||||
BlueprintName = "App_iOS_Tests"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -43,7 +43,7 @@
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_123503999387"
|
||||
BlueprintIdentifier = "NT_D4BAEEEC88124103C8DFF41FCE206DCE"
|
||||
BuildableName = "App_iOS_UITests.xctest"
|
||||
BlueprintName = "App_iOS_UITests"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -53,21 +53,21 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "MyDisabledArgument"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
@@ -86,21 +86,21 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "MyDisabledArgument"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
@@ -115,21 +115,21 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_825232110500"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "MyDisabledArgument"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Staging Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
codeCoverageEnabled = "YES"
|
||||
shouldUseLaunchSchemeArgsEnv = "NO">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_193BAF154270D1C21E269EDF2A1BD3F6"
|
||||
BuildableName = "App_iOS_Tests.xctest"
|
||||
BlueprintName = "App_iOS_Tests"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_D4BAEEEC88124103C8DFF41FCE206DCE"
|
||||
BuildableName = "App_iOS_UITests.xctest"
|
||||
BlueprintName = "App_iOS_UITests"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "MyDisabledArgument"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Staging Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "MyDisabledArgument"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Staging Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "NO"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "MyDisabledArgument"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Staging Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Staging Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Test Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
codeCoverageEnabled = "YES"
|
||||
shouldUseLaunchSchemeArgsEnv = "NO">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_193BAF154270D1C21E269EDF2A1BD3F6"
|
||||
BuildableName = "App_iOS_Tests.xctest"
|
||||
BlueprintName = "App_iOS_Tests"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_D4BAEEEC88124103C8DFF41FCE206DCE"
|
||||
BuildableName = "App_iOS_UITests.xctest"
|
||||
BlueprintName = "App_iOS_UITests"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "MyDisabledArgument"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Test Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "MyDisabledArgument"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Test Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "NO"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
|
||||
BuildableName = "App_iOS.app"
|
||||
BlueprintName = "App_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "MyDisabledArgument"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "MyEnabledArgument"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Test Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Test Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0930"
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -14,7 +14,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_324671077936"
|
||||
BlueprintIdentifier = "NT_38A9FE87056942A2746E0FF025B52A91"
|
||||
BuildableName = "App_watchOS.app"
|
||||
BlueprintName = "App_watchOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -32,7 +32,7 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_324671077936"
|
||||
BlueprintIdentifier = "NT_38A9FE87056942A2746E0FF025B52A91"
|
||||
BuildableName = "App_watchOS.app"
|
||||
BlueprintName = "App_watchOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -57,7 +57,7 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_324671077936"
|
||||
BlueprintIdentifier = "NT_38A9FE87056942A2746E0FF025B52A91"
|
||||
BuildableName = "App_watchOS.app"
|
||||
BlueprintName = "App_watchOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -78,7 +78,7 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_324671077936"
|
||||
BlueprintIdentifier = "NT_38A9FE87056942A2746E0FF025B52A91"
|
||||
BuildableName = "App_watchOS.app"
|
||||
BlueprintName = "App_watchOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
|
||||
+9
-6
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0930"
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "NO"
|
||||
@@ -14,7 +14,7 @@
|
||||
<EnvironmentBuildable>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_472296042419"
|
||||
BlueprintIdentifier = "NT_7D108AE86BED8C9CCF52C2646FA4C5DE"
|
||||
BuildableName = "Framework.framework"
|
||||
BlueprintName = "Framework_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -32,7 +32,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_472296042419"
|
||||
BlueprintIdentifier = "NT_7D108AE86BED8C9CCF52C2646FA4C5DE"
|
||||
BuildableName = "Framework.framework"
|
||||
BlueprintName = "Framework_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -44,18 +44,21 @@
|
||||
buildConfiguration = "Production Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
codeCoverageEnabled = "YES"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_472296042419"
|
||||
BlueprintIdentifier = "NT_7D108AE86BED8C9CCF52C2646FA4C5DE"
|
||||
BuildableName = "Framework.framework"
|
||||
BlueprintName = "Framework_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
@@ -72,7 +75,7 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_472296042419"
|
||||
BlueprintIdentifier = "NT_7D108AE86BED8C9CCF52C2646FA4C5DE"
|
||||
BuildableName = "Framework.framework"
|
||||
BlueprintName = "Framework_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -101,7 +104,7 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_472296042419"
|
||||
BlueprintIdentifier = "NT_7D108AE86BED8C9CCF52C2646FA4C5DE"
|
||||
BuildableName = "Framework.framework"
|
||||
BlueprintName = "Framework_iOS"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0930"
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -14,7 +14,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_935153865209"
|
||||
BlueprintIdentifier = "NT_6BD068FAAC6AA35C090C48147B94EC6E"
|
||||
BuildableName = "iMessageApp.app"
|
||||
BlueprintName = "iMessageApp"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -32,7 +32,7 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_935153865209"
|
||||
BlueprintIdentifier = "NT_6BD068FAAC6AA35C090C48147B94EC6E"
|
||||
BuildableName = "iMessageApp.app"
|
||||
BlueprintName = "iMessageApp"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -57,7 +57,7 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_935153865209"
|
||||
BlueprintIdentifier = "NT_6BD068FAAC6AA35C090C48147B94EC6E"
|
||||
BuildableName = "iMessageApp.app"
|
||||
BlueprintName = "iMessageApp"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
@@ -78,7 +78,7 @@
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NT_935153865209"
|
||||
BlueprintIdentifier = "NT_6BD068FAAC6AA35C090C48147B94EC6E"
|
||||
BuildableName = "iMessageApp.app"
|
||||
BlueprintName = "iMessageApp"
|
||||
ReferencedContainer = "container:Project.xcodeproj">
|
||||
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
carthage bootstrap --cache-builds
|
||||
echo "
|
||||
Building iOS app"
|
||||
xcodebuild -project Project.xcodeproj -scheme "App_iOS Test" -configuration "Test Debug" CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO | xcpretty
|
||||
echo "
|
||||
Building macOS app"
|
||||
xcodebuild -project Project.xcodeproj -scheme "App_macOS" -configuration "Test Debug" CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO | xcpretty
|
||||
@@ -26,18 +26,33 @@ targets:
|
||||
App_macOS:
|
||||
type: application
|
||||
platform: macOS
|
||||
info:
|
||||
path: App_macOS/Info.plist
|
||||
properties:
|
||||
LSMinimumSystemVersion: $(MACOSX_DEPLOYMENT_TARGET)
|
||||
NSMainStoryboardFile: Main
|
||||
NSPrincipalClass: NSApplication
|
||||
CFBundleIconFile: ""
|
||||
CustomSetting: $CUSTOM_SETTING
|
||||
attributes:
|
||||
ProvisioningStyle: Automatic
|
||||
sources:
|
||||
- path: App_macOS
|
||||
- path: StandaloneFiles/Standalone.swift
|
||||
- path: Vendor/SomeXPCService.xpc
|
||||
dependencies:
|
||||
- target: Framework_macOS
|
||||
- target: XPC Service
|
||||
- sdk: Contacts.framework
|
||||
- sdk: libc++.tbd
|
||||
|
||||
App_iOS:
|
||||
type: application
|
||||
platform: iOS
|
||||
entitlements:
|
||||
path: App_iOS/App.entitlements
|
||||
properties:
|
||||
com.apple.security.application-groups: group.com.app
|
||||
attributes:
|
||||
ProvisioningStyle: Automatic
|
||||
sources:
|
||||
@@ -70,16 +85,23 @@ targets:
|
||||
PRODUCT_BUNDLE_IDENTIFIER: com.project.app
|
||||
dependencies:
|
||||
- target: Framework_iOS
|
||||
- target: StaticLibrary_ObjC
|
||||
- carthage: Alamofire
|
||||
- target: StaticLibrary_ObjC_iOS
|
||||
- carthage: Result
|
||||
- target: Framework2_iOS
|
||||
weak: true
|
||||
- target: App_watchOS
|
||||
- target: iMessageApp
|
||||
- framework: Vendor/SomeFramework.framework
|
||||
- sdk: Contacts.framework
|
||||
scheme:
|
||||
testTargets:
|
||||
- App_iOS_Tests
|
||||
- App_iOS_UITests
|
||||
gatherCoverageData: true
|
||||
configVariants:
|
||||
- Test
|
||||
- Staging
|
||||
- Production
|
||||
commandLineArguments:
|
||||
MyEnabledArgument: true
|
||||
MyDisabledArgument: false
|
||||
@@ -111,7 +133,8 @@ targets:
|
||||
settings:
|
||||
PRODUCT_BUNDLE_IDENTIFIER: com.project.app.watch.extension
|
||||
dependencies:
|
||||
- carthage: Alamofire
|
||||
- carthage: Result
|
||||
link: false
|
||||
|
||||
iMessageApp:
|
||||
type: application.messages
|
||||
@@ -130,7 +153,7 @@ targets:
|
||||
|
||||
StaticLibrary_ObjC:
|
||||
type: library.static
|
||||
platform: iOS
|
||||
platform: [iOS, tvOS, watchOS, macOS]
|
||||
sources: StaticLibrary_ObjC
|
||||
|
||||
StaticLibrary_Swift:
|
||||
@@ -153,8 +176,17 @@ targets:
|
||||
- name: MyScript
|
||||
path: scripts/script.sh
|
||||
dependencies:
|
||||
- carthage: Alamofire
|
||||
- target: StaticLibrary_ObjC
|
||||
- carthage: Result
|
||||
- target: StaticLibrary_ObjC_$platform
|
||||
|
||||
Framework2:
|
||||
type: framework
|
||||
platform: [iOS, tvOS, watchOS, macOS]
|
||||
sources:
|
||||
- path: Framework
|
||||
excludes:
|
||||
- "*.xcodeproj"
|
||||
|
||||
App_iOS_Tests:
|
||||
type: bundle.unit-test
|
||||
platform: iOS
|
||||
@@ -188,6 +220,19 @@ schemes:
|
||||
commandLineArguments:
|
||||
argument: YES
|
||||
argument.with.dot: YES
|
||||
test:
|
||||
gatherCoverageData: true
|
||||
App_Scheme:
|
||||
build:
|
||||
targets:
|
||||
App_iOS: all
|
||||
test:
|
||||
gatherCoverageData: true
|
||||
targets:
|
||||
- App_iOS_UITests
|
||||
- name: App_iOS_Tests
|
||||
parallelizable: true
|
||||
randomExecutionOrder: true
|
||||
targetTemplates:
|
||||
MyTemplate:
|
||||
scheme: {}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import Foundation
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import XcodeGenKit
|
||||
import xcodeproj
|
||||
import XCTest
|
||||
|
||||
class GeneratedPerformanceTests: XCTestCase {
|
||||
|
||||
let basePath = Path.temporary + "XcodeGenPeformanceTests"
|
||||
|
||||
func testGeneration() throws {
|
||||
let project = try Project.testProject(basePath: basePath)
|
||||
measure {
|
||||
let generator = ProjectGenerator(project: project)
|
||||
_ = try! generator.generateXcodeProject()
|
||||
}
|
||||
}
|
||||
|
||||
func testWriting() throws {
|
||||
let project = try Project.testProject(basePath: basePath)
|
||||
let generator = ProjectGenerator(project: project)
|
||||
let xcodeProject = try generator.generateXcodeProject()
|
||||
measure {
|
||||
xcodeProject.pbxproj.invalidateUUIDs()
|
||||
try! xcodeProject.write(path: project.defaultProjectPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let fixturePath = Path(#file).parent().parent() + "Fixtures"
|
||||
|
||||
class FixturePerformanceTests: XCTestCase {
|
||||
|
||||
let specPath = fixturePath + "TestProject/project.yml"
|
||||
|
||||
func testFixtureDecoding() throws {
|
||||
measure {
|
||||
_ = try! Project(path: specPath)
|
||||
}
|
||||
}
|
||||
|
||||
func testFixtureGeneration() throws {
|
||||
let project = try Project(path: specPath)
|
||||
measure {
|
||||
let generator = ProjectGenerator(project: project)
|
||||
_ = try! generator.generateXcodeProject()
|
||||
}
|
||||
}
|
||||
|
||||
func testFixtureWriting() throws {
|
||||
let project = try Project(path: specPath)
|
||||
let generator = ProjectGenerator(project: project)
|
||||
let xcodeProject = try generator.generateXcodeProject()
|
||||
measure {
|
||||
xcodeProject.pbxproj.invalidateUUIDs()
|
||||
try! xcodeProject.write(path: project.defaultProjectPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
import Foundation
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import xcodeproj
|
||||
|
||||
extension Project {
|
||||
|
||||
static func testProject(basePath: Path, createSources: Bool = true) throws -> Project {
|
||||
|
||||
if createSources {
|
||||
try? basePath.delete()
|
||||
try basePath.mkpath()
|
||||
}
|
||||
|
||||
var paths: [Path] = []
|
||||
var targets: [Target] = []
|
||||
let scheme = TargetScheme(
|
||||
testTargets: [],
|
||||
configVariants: ["Test", "Staging", "Prod"],
|
||||
gatherCoverageData: true,
|
||||
commandLineArguments: [
|
||||
"--command": true,
|
||||
"--command2": false,
|
||||
],
|
||||
environmentVariables: [
|
||||
XCScheme.EnvironmentVariable(variable: "ENV", value: "HELLO", enabled: true),
|
||||
XCScheme.EnvironmentVariable(variable: "ENV2", value: "HELLO", enabled: false),
|
||||
],
|
||||
preActions: [Scheme.ExecutionAction(name: "run", script: "script")],
|
||||
postActions: [Scheme.ExecutionAction(name: "run", script: "script")]
|
||||
)
|
||||
for platform in Platform.all {
|
||||
let appTarget = Target(
|
||||
name: "App_\(platform)",
|
||||
type: .application,
|
||||
platform: platform,
|
||||
sources: [TargetSource(path: "App_\(platform)")],
|
||||
dependencies: [
|
||||
Dependency(type: .target, reference: "Framework_\(platform)"),
|
||||
Dependency(type: .target, reference: "Framework2_\(platform)"),
|
||||
Dependency(type: .carthage, reference: "Alamofire"),
|
||||
Dependency(type: .carthage, reference: "BrightFutures"),
|
||||
],
|
||||
scheme: scheme
|
||||
)
|
||||
targets.append(appTarget)
|
||||
if createSources {
|
||||
paths += try createTargetSources(path: basePath, target: appTarget)
|
||||
}
|
||||
|
||||
let testTarget = Target(
|
||||
name: "App_Test_\(platform)",
|
||||
type: .unitTestBundle,
|
||||
platform: platform,
|
||||
sources: [TargetSource(path: "App_Test_\(platform)")],
|
||||
dependencies: [
|
||||
Dependency(type: .target, reference: "App_\(platform)"),
|
||||
Dependency(type: .target, reference: "Framework_\(platform)"),
|
||||
Dependency(type: .target, reference: "Framework2_\(platform)"),
|
||||
],
|
||||
scheme: scheme
|
||||
)
|
||||
targets.append(testTarget)
|
||||
if createSources {
|
||||
paths += try createTargetSources(path: basePath, target: testTarget)
|
||||
}
|
||||
|
||||
let frameworkTarget = Target(
|
||||
name: "Framework_\(platform)",
|
||||
type: .framework,
|
||||
platform: platform,
|
||||
sources: [
|
||||
TargetSource(path: "Framework_\(platform)"),
|
||||
],
|
||||
dependencies: [
|
||||
Dependency(type: .carthage, reference: "Alamofire"),
|
||||
],
|
||||
scheme: scheme
|
||||
)
|
||||
targets.append(frameworkTarget)
|
||||
if createSources {
|
||||
paths += try createTargetSources(path: basePath, target: frameworkTarget)
|
||||
}
|
||||
|
||||
let frameworkTarget2 = Target(
|
||||
name: "Framework2_\(platform)",
|
||||
type: .framework,
|
||||
platform: platform,
|
||||
sources: [TargetSource(path: "Framework2_\(platform)")],
|
||||
dependencies: [
|
||||
Dependency(type: .target, reference: "Framework_\(platform)"),
|
||||
Dependency(type: .carthage, reference: "Alamofire"),
|
||||
Dependency(type: .carthage, reference: "BrightFutures"),
|
||||
],
|
||||
scheme: scheme
|
||||
)
|
||||
targets.append(frameworkTarget2)
|
||||
if createSources {
|
||||
paths += try createTargetSources(path: basePath, target: frameworkTarget2)
|
||||
}
|
||||
}
|
||||
if createSources {
|
||||
let files = paths.filter { $0.isFile }
|
||||
let directories = paths.filter { $0.isDirectory }
|
||||
print("Generated \(files.count) files and \(directories.count) directories")
|
||||
}
|
||||
|
||||
return Project(
|
||||
basePath: basePath,
|
||||
name: "Project",
|
||||
configs: [
|
||||
Config(name: "Debug Test", type: .debug),
|
||||
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),
|
||||
],
|
||||
targets: targets,
|
||||
aggregateTargets: [],
|
||||
settings: [:],
|
||||
settingGroups: [:],
|
||||
schemes: [],
|
||||
options: SpecOptions(),
|
||||
fileGroups: [],
|
||||
configFiles: [:],
|
||||
attributes: [:]
|
||||
)
|
||||
}
|
||||
|
||||
fileprivate static func createTargetSources(path: Path, target: Target) throws -> [Path] {
|
||||
let levels = 3
|
||||
let directoriesPerLevel = 1
|
||||
let swiftFilesPerDirectory = 5
|
||||
let objFilesPerDirectory = 2
|
||||
let resourcesPerDirectory = 2
|
||||
var paths: [Path] = []
|
||||
|
||||
func createDirectory(_ path: Path, depth: Int = 0) throws {
|
||||
try path.mkpath()
|
||||
paths.append(path)
|
||||
|
||||
for swiftFile in 1 ... swiftFilesPerDirectory {
|
||||
let file = path + "file_\(swiftFile).swift"
|
||||
try file.write("")
|
||||
paths.append(file)
|
||||
}
|
||||
|
||||
for resourceFile in 1 ... resourcesPerDirectory {
|
||||
let file = path + "file_\(resourceFile).png"
|
||||
try file.write("")
|
||||
paths.append(file)
|
||||
}
|
||||
|
||||
for objFile in 1 ... objFilesPerDirectory {
|
||||
let header = path + "file_\(objFile).h"
|
||||
try header.write("")
|
||||
paths.append(header)
|
||||
|
||||
let implementation = path + "file_\(objFile).m"
|
||||
try implementation.write("")
|
||||
paths.append(implementation)
|
||||
}
|
||||
|
||||
if depth < levels - 1 {
|
||||
for directory in 1 ... directoriesPerLevel {
|
||||
try createDirectory(path + "directory_\(directory)", depth: depth + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for source in target.sources {
|
||||
try createDirectory(path + source.path)
|
||||
}
|
||||
return paths
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import XCTest
|
||||
import Yams
|
||||
|
||||
@@ -10,6 +10,7 @@ extension Project {
|
||||
|
||||
func generateXcodeProject(file: String = #file, line: Int = #line) throws -> XcodeProj {
|
||||
return try doThrowing(file: file, line: line) {
|
||||
try validate()
|
||||
let generator = ProjectGenerator(project: self)
|
||||
return try generator.generateXcodeProject()
|
||||
}
|
||||
@@ -32,12 +33,15 @@ extension PBXProj {
|
||||
let mainGroup = try getMainGroup()
|
||||
|
||||
func validateGroup(_ group: PBXGroup) throws {
|
||||
let hasDuplicatedChildren = group.children.count != Set(group.children).count
|
||||
if hasDuplicatedChildren {
|
||||
throw failure("Group \"\(group.nameOrPath)\" has duplicated children:\n - \(group.children.sorted().joined(separator: "\n - "))")
|
||||
|
||||
// check for duplicte children
|
||||
let dictionary = Dictionary(grouping: group.children) { $0.hashValue }
|
||||
let mostChildren = dictionary.sorted { $0.value.count > $1.value.count }
|
||||
if let first = mostChildren.first, first.value.count > 1 {
|
||||
throw failure("Group \"\(group.nameOrPath)\" has duplicated children:\n - \(group.children.map { $0.nameOrPath }.joined(separator: "\n - "))")
|
||||
}
|
||||
for child in group.children {
|
||||
if let group = objects.groups.getReference(child) {
|
||||
if let group = child as? PBXGroup {
|
||||
try validateGroup(group)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,81 +2,25 @@ import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import XCTest
|
||||
|
||||
class ProjectFixtureTests: XCTestCase {
|
||||
|
||||
func testProjectFixture() {
|
||||
describe {
|
||||
var xcodeProject: XcodeProj?
|
||||
|
||||
$0.it("generates") {
|
||||
xcodeProject = try generateXcodeProject(specPath: fixturePath + "TestProject/project.yml", projectPath: fixturePath + "TestProject/Project.xcodeproj")
|
||||
}
|
||||
|
||||
$0.it("generates variant group") {
|
||||
guard let xcodeProject = xcodeProject else { return }
|
||||
|
||||
func getFileReferences(_ path: String) -> [ObjectReference<PBXFileReference>] {
|
||||
return xcodeProject.pbxproj.objects.fileReferences.objectReferences.filter { $0.object.path == path }
|
||||
}
|
||||
|
||||
func getVariableGroups(_ name: String?) -> [PBXVariantGroup] {
|
||||
return xcodeProject.pbxproj.objects.variantGroups.referenceValues.filter { $0.name == name }
|
||||
}
|
||||
|
||||
let resourceName = "LocalizedStoryboard.storyboard"
|
||||
let baseResource = "Base.lproj/LocalizedStoryboard.storyboard"
|
||||
let localizedResource = "en.lproj/LocalizedStoryboard.strings"
|
||||
|
||||
guard let variableGroup = getVariableGroups(resourceName).first else { throw failure("Couldn't find the variable group") }
|
||||
|
||||
do {
|
||||
let refs = getFileReferences(baseResource)
|
||||
try expect(refs.count) == 1
|
||||
try expect(variableGroup.children.filter { $0 == refs.first?.reference }.count) == 1
|
||||
}
|
||||
|
||||
do {
|
||||
let refs = getFileReferences(localizedResource)
|
||||
try expect(refs.count) == 1
|
||||
try expect(variableGroup.children.filter { $0 == refs.first?.reference }.count) == 1
|
||||
}
|
||||
}
|
||||
|
||||
$0.it("generates scheme execution actions") {
|
||||
guard let xcodeProject = xcodeProject else { return }
|
||||
|
||||
let frameworkScheme = xcodeProject.sharedData?.schemes.first { $0.name == "Framework" }
|
||||
try expect(frameworkScheme?.buildAction?.preActions.first?.scriptText) == "echo Starting Framework Build"
|
||||
try expect(frameworkScheme?.buildAction?.preActions.first?.title) == "Run Script"
|
||||
try expect(frameworkScheme?.buildAction?.preActions.first?.environmentBuildable?.blueprintName) == "Framework_iOS"
|
||||
try expect(frameworkScheme?.buildAction?.preActions.first?.environmentBuildable?.buildableName) == "Framework.framework"
|
||||
try generateXcodeProject(specPath: fixturePath + "TestProject/project.yml")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func generateXcodeProject(specPath: Path, projectPath: Path, file: String = #file, line: Int = #line) throws -> XcodeProj {
|
||||
fileprivate func generateXcodeProject(specPath: Path, file: String = #file, line: Int = #line) throws {
|
||||
let project = try Project(path: specPath)
|
||||
let generator = ProjectGenerator(project: project)
|
||||
let writer = FileWriter(project: project)
|
||||
let xcodeProject = try generator.generateXcodeProject()
|
||||
let oldProject = try XcodeProj(path: projectPath)
|
||||
let pbxProjPath = projectPath + XcodeProj.pbxprojPath(projectPath)
|
||||
let oldProjectString: String = try pbxProjPath.read()
|
||||
try xcodeProject.write(path: projectPath, override: true)
|
||||
let newProjectString: String = try pbxProjPath.read()
|
||||
|
||||
let newProject = try XcodeProj(path: projectPath)
|
||||
let stringDiff = newProjectString != oldProjectString
|
||||
if newProject != oldProject || stringDiff {
|
||||
var message = "\(projectPath.string) has changed. If change is legitimate commit the change and run test again"
|
||||
if stringDiff {
|
||||
message += ":\n\n\(pbxProjPath):\n\(prettyFirstDifferenceBetweenStrings(oldProjectString, newProjectString))"
|
||||
}
|
||||
throw failure(message, file: file, line: line)
|
||||
}
|
||||
|
||||
return newProject
|
||||
try writer.writeXcodeProject(xcodeProject)
|
||||
try writer.writePlists()
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import XCTest
|
||||
import Yams
|
||||
|
||||
@@ -21,6 +21,12 @@ fileprivate let framework = Target(
|
||||
settings: Settings(buildSettings: ["SETTING_2": "VALUE"])
|
||||
)
|
||||
|
||||
fileprivate let optionalFramework = Target(
|
||||
name: "MyOptionalFramework",
|
||||
type: .framework,
|
||||
platform: .iOS
|
||||
)
|
||||
|
||||
fileprivate let uiTest = Target(
|
||||
name: "MyAppUITests",
|
||||
type: .uiTestBundle,
|
||||
@@ -29,7 +35,7 @@ fileprivate let uiTest = Target(
|
||||
dependencies: [Dependency(type: .target, reference: "MyApp")]
|
||||
)
|
||||
|
||||
fileprivate let targets = [app, framework, uiTest]
|
||||
fileprivate let targets = [app, framework, optionalFramework, uiTest]
|
||||
|
||||
class ProjectGeneratorTests: XCTestCase {
|
||||
|
||||
@@ -41,11 +47,9 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let options = SpecOptions(bundleIdPrefix: "com.test")
|
||||
let project = Project(basePath: "", name: "test", targets: [framework], options: options)
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
guard let target = pbxProj.objects.nativeTargets.first?.value,
|
||||
guard let target = pbxProj.nativeTargets.first,
|
||||
let buildConfigList = target.buildConfigurationList,
|
||||
let buildConfigs = pbxProj.objects.configurationLists.getReference(buildConfigList),
|
||||
let buildConfigReference = buildConfigs.buildConfigurations.first,
|
||||
let buildConfig = pbxProj.objects.buildConfigurations.getReference(buildConfigReference) else {
|
||||
let buildConfig = buildConfigList.buildConfigurations.first else {
|
||||
throw failure("Build Config not found")
|
||||
}
|
||||
try expect(buildConfig.buildSettings["PRODUCT_BUNDLE_IDENTIFIER"] as? String) == "com.test.MyFramework"
|
||||
@@ -55,15 +59,15 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let options = SpecOptions(settingPresets: .none)
|
||||
let project = Project(basePath: "", name: "test", targets: [framework], options: options)
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
let allSettings = pbxProj.objects.buildConfigurations.referenceValues.reduce([:]) { $0.merged($1.buildSettings) }.keys.sorted()
|
||||
try expect(allSettings) == ["SETTING_2"]
|
||||
let allSettings = pbxProj.buildConfigurations.reduce([:]) { $0.merged($1.buildSettings) }.keys.sorted()
|
||||
try expect(allSettings) == ["SDKROOT", "SETTING_2"]
|
||||
}
|
||||
|
||||
$0.it("generates development language") {
|
||||
let options = SpecOptions(developmentLanguage: "de")
|
||||
let project = Project(basePath: "", name: "test", options: options)
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
guard let pbxProject = pbxProj.objects.projects.first?.value else {
|
||||
guard let pbxProject = pbxProj.projects.first else {
|
||||
throw failure("Could't find PBXProject")
|
||||
}
|
||||
try expect(pbxProject.developmentRegion) == "de"
|
||||
@@ -92,8 +96,8 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let project = Project(basePath: "", name: "test", configs: [Config(name: "Aconfig"), Config(name: "Bconfig")], targets: [framework], options: options)
|
||||
let pbxProject = try project.generatePbxProj()
|
||||
|
||||
guard let projectConfigListReference = pbxProject.objects.projects.values.first?.buildConfigurationList,
|
||||
let defaultConfigurationName = pbxProject.objects.configurationLists[projectConfigListReference]?.defaultConfigurationName
|
||||
guard let projectConfigList = pbxProject.projects.first?.buildConfigurationList,
|
||||
let defaultConfigurationName = projectConfigList.defaultConfigurationName
|
||||
else {
|
||||
throw failure("Default configuration name not found")
|
||||
}
|
||||
@@ -109,7 +113,7 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
$0.it("generates config defaults") {
|
||||
let project = Project(basePath: "", name: "test")
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
let configs = pbxProj.objects.buildConfigurations.referenceValues
|
||||
let configs = pbxProj.buildConfigurations
|
||||
try expect(configs.count) == 2
|
||||
try expect(configs).contains(name: "Debug")
|
||||
try expect(configs).contains(name: "Release")
|
||||
@@ -122,7 +126,7 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
configs: [Config(name: "config1"), Config(name: "config2")]
|
||||
)
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
let configs = pbxProj.objects.buildConfigurations.referenceValues
|
||||
let configs = pbxProj.buildConfigurations
|
||||
try expect(configs.count) == 2
|
||||
try expect(configs).contains(name: "config1")
|
||||
try expect(configs).contains(name: "config2")
|
||||
@@ -135,7 +139,7 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
configs: [Config(name: "config")]
|
||||
)
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
guard let config = pbxProj.objects.buildConfigurations.first?.value else {
|
||||
guard let config = pbxProj.buildConfigurations.first else {
|
||||
throw failure("configuration not found")
|
||||
}
|
||||
try expect(config.buildSettings.isEmpty).to.beTrue()
|
||||
@@ -150,6 +154,7 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let targetDebugSettings = project.getTargetBuildSettings(target: target, config: config)
|
||||
|
||||
var buildSettings = BuildSettings()
|
||||
buildSettings += ["SDKROOT": "iphoneos"]
|
||||
buildSettings += SettingsPresetFile.base.getBuildSettings()
|
||||
buildSettings += SettingsPresetFile.config(.debug).getBuildSettings()
|
||||
|
||||
@@ -184,6 +189,23 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
try expect(buildSettings["SETTING1"] as? String) == "VALUE1"
|
||||
try expect(buildSettings["SETTING2"] as? String) == "VALUE2"
|
||||
}
|
||||
|
||||
$0.it("sets project SDKROOT if there is only a single platform") {
|
||||
var project = Project(
|
||||
basePath: "",
|
||||
name: "test",
|
||||
targets: [
|
||||
Target(name: "1", type: .application, platform: .iOS),
|
||||
Target(name: "2", type: .framework, platform: .iOS),
|
||||
]
|
||||
)
|
||||
var buildSettings = project.getProjectBuildSettings(config: project.configs.first!)
|
||||
try expect(buildSettings["SDKROOT"] as? String) == "iphoneos"
|
||||
|
||||
project.targets.append(Target(name: "3", type: .application, platform: .tvOS))
|
||||
buildSettings = project.getProjectBuildSettings(config: project.configs.first!)
|
||||
try expect(buildSettings["SDKROOT"]).beNil()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,8 +220,8 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
|
||||
$0.it("generates aggregate targets") {
|
||||
let pbxProject = try project.generatePbxProj()
|
||||
let nativeTargets = pbxProject.objects.nativeTargets.referenceValues
|
||||
let aggregateTargets = pbxProject.objects.aggregateTargets.referenceValues
|
||||
let nativeTargets = pbxProject.nativeTargets.sorted { $0.name < $1.name }
|
||||
let aggregateTargets = pbxProject.aggregateTargets.sorted { $0.name < $1.name }
|
||||
|
||||
try expect(nativeTargets.count) == 4
|
||||
try expect(aggregateTargets.count) == 2
|
||||
@@ -216,8 +238,7 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let target2 = nativeTargets.first { $0.name == "Other2" }
|
||||
try expect(target2?.dependencies.count) == 2
|
||||
|
||||
let targetDependencies = pbxProject.objects.targetDependencies.referenceValues
|
||||
try expect(targetDependencies.count) == 7
|
||||
try expect(pbxProject.targetDependencies.count) == 7
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -229,11 +250,12 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
|
||||
$0.it("generates targets") {
|
||||
let pbxProject = try project.generatePbxProj()
|
||||
let nativeTargets = pbxProject.objects.nativeTargets.referenceValues
|
||||
try expect(nativeTargets.count) == 3
|
||||
let nativeTargets = pbxProject.nativeTargets
|
||||
try expect(nativeTargets.count) == 4
|
||||
try expect(nativeTargets.contains { $0.name == app.name }).beTrue()
|
||||
try expect(nativeTargets.contains { $0.name == framework.name }).beTrue()
|
||||
try expect(nativeTargets.contains { $0.name == uiTest.name }).beTrue()
|
||||
try expect(nativeTargets.contains { $0.name == optionalFramework.name }).beTrue()
|
||||
}
|
||||
|
||||
$0.it("generates target attributes") {
|
||||
@@ -243,25 +265,25 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
|
||||
var testTargetWithAttributes = uiTest
|
||||
testTargetWithAttributes.settings.buildSettings["CODE_SIGN_STYLE"] = "Manual"
|
||||
let project = Project(basePath: "", name: "test", targets: [appTargetWithAttributes, framework, testTargetWithAttributes])
|
||||
let project = Project(basePath: "", name: "test", targets: [appTargetWithAttributes, framework, optionalFramework, testTargetWithAttributes])
|
||||
let pbxProject = try project.generatePbxProj()
|
||||
|
||||
guard let targetAttributes = pbxProject.objects.projects.referenceValues.first?.attributes["TargetAttributes"] as? [String: [String: Any]] else {
|
||||
guard let targetAttributes = pbxProject.projects.first?.targetAttributes else {
|
||||
throw failure("Couldn't find Project TargetAttributes")
|
||||
}
|
||||
|
||||
guard let appTarget = pbxProject.objects.targets(named: app.name).first else {
|
||||
guard let appTarget = pbxProject.targets(named: app.name).first else {
|
||||
throw failure("Couldn't find App Target")
|
||||
}
|
||||
|
||||
guard let uiTestTarget = pbxProject.objects.targets(named: uiTest.name).first else {
|
||||
guard let uiTestTarget = pbxProject.targets(named: uiTest.name).first else {
|
||||
throw failure("Couldn't find UITest Target")
|
||||
}
|
||||
|
||||
try expect(targetAttributes[uiTestTarget.reference]?["TestTargetID"] as? String) == appTarget.reference
|
||||
try expect(targetAttributes[uiTestTarget.reference]?["ProvisioningStyle"] as? String) == "Manual"
|
||||
try expect(targetAttributes[appTarget.reference]?["ProvisioningStyle"] as? String) == "Automatic"
|
||||
try expect(targetAttributes[appTarget.reference]?["DevelopmentTeam"] as? String) == "123"
|
||||
try expect((targetAttributes[uiTestTarget]?["TestTargetID"] as? PBXNativeTarget)?.name) == app.name
|
||||
try expect(targetAttributes[uiTestTarget]?["ProvisioningStyle"] as? String) == "Manual"
|
||||
try expect(targetAttributes[appTarget]?["ProvisioningStyle"] as? String) == "Automatic"
|
||||
try expect(targetAttributes[appTarget]?["DevelopmentTeam"] as? String) == "123"
|
||||
}
|
||||
|
||||
$0.it("generates platform version") {
|
||||
@@ -270,16 +292,14 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
|
||||
let pbxProject = try project.generatePbxProj()
|
||||
|
||||
guard let projectConfigListReference = pbxProject.objects.projects.values.first?.buildConfigurationList,
|
||||
let projectConfigReference = pbxProject.objects.configurationLists[projectConfigListReference]?.buildConfigurations.first,
|
||||
let projectConfig = pbxProject.objects.buildConfigurations[projectConfigReference]
|
||||
guard let projectConfigList = pbxProject.projects.first?.buildConfigurationList,
|
||||
let projectConfig = projectConfigList.buildConfigurations.first
|
||||
else {
|
||||
throw failure("Couldn't find Project config")
|
||||
}
|
||||
|
||||
guard let targetConfigListReference = pbxProject.objects.nativeTargets.referenceValues.first?.buildConfigurationList,
|
||||
let targetConfigReference = pbxProject.objects.configurationLists[targetConfigListReference]?.buildConfigurations.first,
|
||||
let targetConfig = pbxProject.objects.buildConfigurations[targetConfigReference]
|
||||
guard let targetConfigList = pbxProject.nativeTargets.first?.buildConfigurationList,
|
||||
let targetConfig = targetConfigList.buildConfigurations.first
|
||||
else {
|
||||
throw failure("Couldn't find Target config")
|
||||
}
|
||||
@@ -296,14 +316,14 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
$0.it("generates dependencies") {
|
||||
let pbxProject = try project.generatePbxProj()
|
||||
|
||||
let nativeTargets = pbxProject.objects.nativeTargets.objectReferences
|
||||
let dependencies = pbxProject.objects.targetDependencies.objectReferences
|
||||
let nativeTargets = pbxProject.nativeTargets
|
||||
let dependencies = pbxProject.targetDependencies.sorted { $0.target?.name ?? "" < $1.target?.name ?? "" }
|
||||
try expect(dependencies.count) == 2
|
||||
let appTarget = nativeTargets.first { $0.object.name == app.name }
|
||||
let frameworkTarget = nativeTargets.first { $0.object.name == framework.name }
|
||||
let appTarget = nativeTargets.first { $0.name == app.name }
|
||||
let frameworkTarget = nativeTargets.first { $0.name == framework.name }
|
||||
|
||||
try expect(dependencies).contains { $0.object.target == appTarget?.reference }
|
||||
try expect(dependencies).contains { $0.object.target == frameworkTarget?.reference }
|
||||
try expect(dependencies).contains { $0.target == appTarget }
|
||||
try expect(dependencies).contains { $0.target == frameworkTarget }
|
||||
}
|
||||
|
||||
$0.it("generates targets with correct transitive embeds") {
|
||||
@@ -543,20 +563,21 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let pbxProject = try project.generatePbxProj()
|
||||
|
||||
for target in targets {
|
||||
guard let nativeTarget = pbxProject.objects.nativeTargets.referenceValues.first(where: { $0.name == target.name }) else {
|
||||
guard let nativeTarget = pbxProject.nativeTargets.first(where: { $0.name == target.name }) else {
|
||||
throw failure("PBXNativeTarget for \(target) not found")
|
||||
}
|
||||
let buildPhases = nativeTarget.buildPhases
|
||||
let resourcesPhases = pbxProject.objects.resourcesBuildPhases.objectReferences.filter { buildPhases.contains($0.reference) }
|
||||
let frameworkPhases = pbxProject.objects.frameworksBuildPhases.objectReferences.filter { buildPhases.contains($0.reference) }
|
||||
let copyFilesPhases = pbxProject.objects.copyFilesBuildPhases.objectReferences.filter { buildPhases.contains($0.reference) }
|
||||
let resourcesPhases = pbxProject.resourcesBuildPhases.filter { buildPhases.contains($0) }
|
||||
let frameworkPhases = pbxProject.frameworksBuildPhases.filter { buildPhases.contains($0) }
|
||||
let copyFilesPhases = pbxProject.copyFilesBuildPhases.filter { buildPhases.contains($0) }
|
||||
|
||||
// ensure only the right resources are copies, no more, no less
|
||||
let expectedResourceFiles = expectedResourceFiles[target.name]!
|
||||
try expect(resourcesPhases.count) == (expectedResourceFiles.isEmpty ? 0 : 1)
|
||||
if !expectedResourceFiles.isEmpty {
|
||||
let resourceFiles = resourcesPhases[0].object.files
|
||||
.compactMap { pbxProject.objects.buildFiles[$0]?.fileRef.flatMap { pbxProject.objects.fileReferences[$0]?.nameOrPath } }
|
||||
let resourceFiles = resourcesPhases[0].files
|
||||
.compactMap { $0.file }
|
||||
.map { $0.nameOrPath }
|
||||
try expect(Set(resourceFiles)) == expectedResourceFiles
|
||||
}
|
||||
|
||||
@@ -564,8 +585,8 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let expectedLinkedFiles = expectedLinkedFiles[target.name]!
|
||||
try expect(frameworkPhases.count) == (expectedLinkedFiles.isEmpty ? 0 : 1)
|
||||
if !expectedLinkedFiles.isEmpty {
|
||||
let linkFrameworks = frameworkPhases[0].object.files
|
||||
.compactMap { pbxProject.objects.buildFiles[$0]?.fileRef.flatMap { pbxProject.objects.fileReferences[$0]?.nameOrPath } }
|
||||
let linkFrameworks = frameworkPhases[0].files
|
||||
.compactMap { $0.file?.nameOrPath }
|
||||
try expect(Set(linkFrameworks)) == expectedLinkedFiles
|
||||
}
|
||||
|
||||
@@ -573,8 +594,8 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let expectedEmbeddedFrameworks = expectedEmbeddedFrameworks[target.name]!
|
||||
try expect(copyFilesPhases.count) == (expectedEmbeddedFrameworks.isEmpty ? 0 : 1)
|
||||
if !expectedEmbeddedFrameworks.isEmpty {
|
||||
let copyFiles = copyFilesPhases[0].object.files
|
||||
.compactMap { pbxProject.objects.buildFiles[$0]?.fileRef.flatMap { pbxProject.objects.fileReferences[$0]?.nameOrPath } }
|
||||
let copyFiles = copyFilesPhases[0].files
|
||||
.compactMap { $0.file?.nameOrPath }
|
||||
try expect(Set(copyFiles)) == expectedEmbeddedFrameworks
|
||||
}
|
||||
}
|
||||
@@ -641,11 +662,9 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
|
||||
func buildSettings(for target: Target) throws -> BuildSettings {
|
||||
guard let nativeTarget = pbxProj.objects.targets(named: target.name).first?.object,
|
||||
guard let nativeTarget = pbxProj.targets(named: target.name).first,
|
||||
let buildConfigList = nativeTarget.buildConfigurationList,
|
||||
let buildConfigs = pbxProj.objects.configurationLists.getReference(buildConfigList),
|
||||
let buildConfigReference = buildConfigs.buildConfigurations.first,
|
||||
let buildConfig = pbxProj.objects.buildConfigurations.getReference(buildConfigReference) else {
|
||||
let buildConfig = buildConfigList.buildConfigurations.first else {
|
||||
throw failure("XCBuildConfiguration not found for Target \(target.name.quoted)")
|
||||
}
|
||||
|
||||
@@ -699,16 +718,15 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
let pbxProject = try project.generatePbxProj()
|
||||
|
||||
func scriptBuildPhases(target: Target) throws -> [PBXShellScriptBuildPhase] {
|
||||
guard let nativeTarget = pbxProject.objects.nativeTargets.referenceValues.first(where: { $0.name == target.name }) else {
|
||||
guard let nativeTarget = pbxProject.nativeTargets.first(where: { $0.name == target.name }) else {
|
||||
throw failure("PBXNativeTarget for \(target) not found")
|
||||
}
|
||||
let buildPhases = nativeTarget.buildPhases
|
||||
let scriptPhases = pbxProject.objects.shellScriptBuildPhases.objectReferences.filter({ buildPhases.contains($0.reference) }).map { $0.object }
|
||||
let scriptPhases = buildPhases.compactMap { $0 as? PBXShellScriptBuildPhase }
|
||||
return scriptPhases
|
||||
}
|
||||
|
||||
let expectedScriptPhase = PBXShellScriptBuildPhase(
|
||||
files: [],
|
||||
name: "Copy Swift Objective-C Interface Header",
|
||||
inputPaths: ["$(DERIVED_SOURCES_DIR)/$(SWIFT_OBJC_INTERFACE_HEADER_NAME)"],
|
||||
outputPaths: ["$(BUILT_PRODUCTS_DIR)/include/$(PRODUCT_MODULE_NAME)/$(SWIFT_OBJC_INTERFACE_HEADER_NAME)"],
|
||||
@@ -728,25 +746,20 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
scriptSpec.targets[0].postBuildScripts = [BuildScript(script: .script("script3"))]
|
||||
let pbxProject = try scriptSpec.generatePbxProj()
|
||||
|
||||
guard let nativeTarget = pbxProject.objects.nativeTargets.referenceValues
|
||||
guard let nativeTarget = pbxProject.nativeTargets
|
||||
.first(where: { $0.buildPhases.count >= 3 }) else {
|
||||
throw failure("Target with build phases not found")
|
||||
}
|
||||
let buildPhases = nativeTarget.buildPhases
|
||||
|
||||
let scripts = pbxProject.objects.shellScriptBuildPhases.objectReferences
|
||||
let script1 = scripts[0]
|
||||
let script2 = scripts[1]
|
||||
let script3 = scripts[2]
|
||||
let scripts = pbxProject.shellScriptBuildPhases
|
||||
try expect(scripts.count) == 3
|
||||
try expect(buildPhases.contains(script1.reference)) == true
|
||||
try expect(buildPhases.contains(script2.reference)) == true
|
||||
try expect(buildPhases.contains(script3.reference)) == true
|
||||
|
||||
let scriptTexts = Set<String>(["script1", "script2", "script3"])
|
||||
try expect(scriptTexts.contains(script1.object.shellScript!)) == true
|
||||
try expect(scriptTexts.contains(script2.object.shellScript!)) == true
|
||||
try expect(scriptTexts.contains(script3.object.shellScript!)) == true
|
||||
let script1 = scripts.first { $0.shellScript == "script1" }!
|
||||
let script2 = scripts.first { $0.shellScript == "script2" }!
|
||||
let script3 = scripts.first { $0.shellScript == "script3" }!
|
||||
try expect(buildPhases.contains(script1)) == true
|
||||
try expect(buildPhases.contains(script2)) == true
|
||||
try expect(buildPhases.contains(script3)) == true
|
||||
}
|
||||
|
||||
$0.it("generates targets with cylical dependencies") {
|
||||
@@ -788,7 +801,7 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
]
|
||||
let pbxProject = try scriptSpec.generatePbxProj()
|
||||
|
||||
let buildRules = pbxProject.objects.buildRules.referenceValues
|
||||
let buildRules = pbxProject.buildRules
|
||||
try expect(buildRules.count) == 2
|
||||
let first = buildRules.first { $0.name == "My Rule" }!
|
||||
let second = buildRules.first { $0.name != "My Rule" }!
|
||||
@@ -810,178 +823,64 @@ class ProjectGeneratorTests: XCTestCase {
|
||||
try expect(second.outputFiles) == []
|
||||
try expect(second.outputFilesCompilerFlags) == []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testSchemes() {
|
||||
describe {
|
||||
|
||||
let buildTarget = Scheme.BuildTarget(target: app.name)
|
||||
$0.it("generates scheme") {
|
||||
let preAction = Scheme.ExecutionAction(name: "Script", script: "echo Starting", settingsTarget: app.name)
|
||||
let scheme = Scheme(
|
||||
name: "MyScheme",
|
||||
build: Scheme.Build(targets: [buildTarget], preActions: [preAction])
|
||||
$0.it("generates dependency build file settings") {
|
||||
let app = Target(
|
||||
name: "MyApp",
|
||||
type: .application,
|
||||
platform: .iOS,
|
||||
dependencies: [
|
||||
Dependency(type: .target, reference: "MyFramework"),
|
||||
Dependency(type: .target, reference: "MyOptionalFramework", weakLink: true),
|
||||
]
|
||||
)
|
||||
let project = Project(
|
||||
basePath: "",
|
||||
name: "test",
|
||||
targets: [app, framework],
|
||||
schemes: [scheme]
|
||||
)
|
||||
let xcodeProject = try project.generateXcodeProject()
|
||||
guard let target = xcodeProject.pbxproj.objects.nativeTargets.objectReferences
|
||||
.first(where: { $0.object.name == app.name }) else {
|
||||
throw failure("Target not found")
|
||||
}
|
||||
guard let xcscheme = xcodeProject.sharedData?.schemes.first else {
|
||||
throw failure("Scheme not found")
|
||||
}
|
||||
try expect(scheme.name) == "MyScheme"
|
||||
try expect(xcscheme.buildAction?.buildImplicitDependencies) == true
|
||||
try expect(xcscheme.buildAction?.parallelizeBuild) == true
|
||||
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"
|
||||
try expect(xcscheme.buildAction?.preActions.first?.environmentBuildable?.blueprintName) == "MyApp"
|
||||
guard let buildActionEntry = xcscheme.buildAction?.buildActionEntries.first else {
|
||||
throw failure("Build Action entry not found")
|
||||
}
|
||||
try expect(buildActionEntry.buildFor) == BuildType.all
|
||||
|
||||
let buildableReferences: [XCScheme.BuildableReference] = [
|
||||
buildActionEntry.buildableReference,
|
||||
xcscheme.launchAction?.buildableProductRunnable?.buildableReference,
|
||||
xcscheme.profileAction?.buildableProductRunnable?.buildableReference,
|
||||
xcscheme.testAction?.macroExpansion,
|
||||
].compactMap { $0 }
|
||||
let project = Project(basePath: "", name: "test", targets: [app, framework, optionalFramework, uiTest])
|
||||
let pbxProject = try project.generatePbxProj()
|
||||
|
||||
for buildableReference in buildableReferences {
|
||||
try expect(buildableReference.blueprintIdentifier) == target.reference
|
||||
try expect(buildableReference.blueprintName) == target.object.name
|
||||
try expect(buildableReference.buildableName) == "\(target.object.name).\(target.object.productType!.fileExtension!)"
|
||||
guard let nativeTarget = pbxProject.nativeTargets.first(where: { $0.name == app.name }) else {
|
||||
throw failure("PBXNativeTarget for \(app.name) not found")
|
||||
}
|
||||
let frameworkPhases = nativeTarget.buildPhases.compactMap { $0 as? PBXFrameworksBuildPhase }
|
||||
|
||||
try expect(xcscheme.launchAction?.buildConfiguration) == "Debug"
|
||||
try expect(xcscheme.testAction?.buildConfiguration) == "Debug"
|
||||
try expect(xcscheme.profileAction?.buildConfiguration) == "Release"
|
||||
try expect(xcscheme.analyzeAction?.buildConfiguration) == "Debug"
|
||||
try expect(xcscheme.archiveAction?.buildConfiguration) == "Release"
|
||||
let frameworkBuildFiles = frameworkPhases[0].files
|
||||
let buildFileSettings = frameworkBuildFiles.map { $0.settings }
|
||||
|
||||
try expect(frameworkBuildFiles.count) == 2
|
||||
try expect(buildFileSettings.compactMap({ $0 }).count) == 1
|
||||
try expect(buildFileSettings.compactMap({ $0?["ATTRIBUTES"] }).count) == 1
|
||||
try expect(buildFileSettings.compactMap({ $0?["ATTRIBUTES"] as? [String] }).first) == ["Weak"]
|
||||
}
|
||||
|
||||
$0.it("sets environment variables for a scheme") {
|
||||
let runVariables: [XCScheme.EnvironmentVariable] = [
|
||||
XCScheme.EnvironmentVariable(variable: "RUN_ENV", value: "ENABLED", enabled: true),
|
||||
XCScheme.EnvironmentVariable(variable: "OTHER_RUN_ENV", value: "DISABLED", enabled: false),
|
||||
]
|
||||
$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 scheme = Scheme(
|
||||
name: "EnvironmentVariablesScheme",
|
||||
build: Scheme.Build(targets: [buildTarget]),
|
||||
run: Scheme.Run(config: "Debug", environmentVariables: runVariables),
|
||||
test: Scheme.Test(config: "Debug"),
|
||||
profile: Scheme.Profile(config: "Debug")
|
||||
)
|
||||
let project = Project(
|
||||
basePath: "",
|
||||
name: "test",
|
||||
targets: [app, framework],
|
||||
schemes: [scheme]
|
||||
)
|
||||
let xcodeProject = try project.generateXcodeProject()
|
||||
|
||||
guard let xcscheme = xcodeProject.sharedData?.schemes.first else {
|
||||
throw failure("Scheme not found")
|
||||
guard let targetConfig = pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first else {
|
||||
throw failure("Couldn't find Target config")
|
||||
}
|
||||
|
||||
try expect(
|
||||
xcodeProject.pbxproj.objects.nativeTargets.objectReferences
|
||||
.contains(where: { $0.object.name == app.name })
|
||||
).beTrue()
|
||||
try expect(xcscheme.launchAction?.environmentVariables) == runVariables
|
||||
try expect(xcscheme.testAction?.environmentVariables).to.beNil()
|
||||
try expect(xcscheme.profileAction?.environmentVariables).to.beNil()
|
||||
}
|
||||
try expect(targetConfig.buildSettings["INFOPLIST_FILE"] as? String) == plist.path
|
||||
|
||||
$0.it("generates target schemes from config variant") {
|
||||
let configVariants = ["Test", "Production"]
|
||||
var target = app
|
||||
target.scheme = TargetScheme(configVariants: configVariants)
|
||||
let configs: [Config] = [
|
||||
Config(name: "Test Debug", type: .debug),
|
||||
Config(name: "Production Debug", type: .debug),
|
||||
Config(name: "Test Release", type: .release),
|
||||
Config(name: "Production Release", type: .release),
|
||||
]
|
||||
let infoPlistFile = tempPath + plist.path
|
||||
let data: Data = try infoPlistFile.read()
|
||||
let infoPlist = try PropertyListSerialization.propertyList(from: data, options: [], format: nil) as! [String: Any]
|
||||
var expectedInfoPlist: [String: Any] = [:]
|
||||
expectedInfoPlist["CFBundleIdentifier"] = "$(PRODUCT_BUNDLE_IDENTIFIER)"
|
||||
expectedInfoPlist["CFBundleInfoDictionaryVersion"] = "6.0"
|
||||
expectedInfoPlist["CFBundleExecutable"] = "$(EXECUTABLE_NAME)"
|
||||
expectedInfoPlist["CFBundleName"] = "$(PRODUCT_NAME)"
|
||||
expectedInfoPlist["CFBundleDevelopmentRegion"] = "$(DEVELOPMENT_LANGUAGE)"
|
||||
expectedInfoPlist["CFBundleShortVersionString"] = "1.0"
|
||||
expectedInfoPlist["CFBundleVersion"] = "1"
|
||||
expectedInfoPlist["CFBundlePackageType"] = "APPL"
|
||||
expectedInfoPlist["UISupportedInterfaceOrientations"] = ["UIInterfaceOrientationPortrait", "UIInterfaceOrientationLandscapeLeft"]
|
||||
|
||||
let project = Project(basePath: "", name: "test", configs: configs, targets: [target, framework])
|
||||
let xcodeProject = try project.generateXcodeProject()
|
||||
|
||||
try expect(xcodeProject.sharedData?.schemes.count) == 2
|
||||
|
||||
guard let nativeTarget = xcodeProject.pbxproj.objects.nativeTargets.objectReferences
|
||||
.first(where: { $0.object.name == app.name }) else {
|
||||
throw failure("Target not found")
|
||||
}
|
||||
guard let xcscheme = xcodeProject.sharedData?.schemes
|
||||
.first(where: { $0.name == "\(target.name) Test" }) else {
|
||||
throw failure("Scheme not found")
|
||||
}
|
||||
guard let buildActionEntry = xcscheme.buildAction?.buildActionEntries.first else {
|
||||
throw failure("Build Action entry not found")
|
||||
}
|
||||
try expect(buildActionEntry.buildableReference.blueprintIdentifier) == nativeTarget.reference
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
$0.it("generates environment variables for target schemes") {
|
||||
let variables: [XCScheme.EnvironmentVariable] = [XCScheme.EnvironmentVariable(variable: "env", value: "var", enabled: false)]
|
||||
var target = app
|
||||
target.scheme = TargetScheme(environmentVariables: variables)
|
||||
|
||||
let project = Project(basePath: "", name: "test", targets: [target, framework])
|
||||
let xcodeProject = try project.generateXcodeProject()
|
||||
|
||||
try expect(xcodeProject.sharedData?.schemes.count) == 1
|
||||
|
||||
guard let xcscheme = xcodeProject.sharedData?.schemes.first else {
|
||||
throw failure("Scheme not found")
|
||||
}
|
||||
|
||||
try expect(xcscheme.launchAction?.environmentVariables) == variables
|
||||
try expect(xcscheme.testAction?.environmentVariables) == variables
|
||||
try expect(xcscheme.profileAction?.environmentVariables) == variables
|
||||
}
|
||||
|
||||
$0.it("generates pre and post actions for target schemes") {
|
||||
var target = app
|
||||
target.scheme = TargetScheme(
|
||||
preActions: [.init(name: "Run", script: "do")],
|
||||
postActions: [.init(name: "Run2", script: "post", settingsTarget: "MyApp")]
|
||||
)
|
||||
|
||||
let project = Project(basePath: "", name: "test", targets: [target, framework])
|
||||
let xcodeProject = try project.generateXcodeProject()
|
||||
|
||||
try expect(xcodeProject.sharedData?.schemes.count) == 1
|
||||
|
||||
guard let xcscheme = xcodeProject.sharedData?.schemes.first else {
|
||||
throw failure("Scheme not found")
|
||||
}
|
||||
|
||||
try expect(xcscheme.launchAction?.preActions.count) == 1
|
||||
try expect(xcscheme.launchAction?.preActions.first?.title) == "Run"
|
||||
try expect(xcscheme.launchAction?.preActions.first?.scriptText) == "do"
|
||||
|
||||
try expect(xcscheme.testAction?.postActions.count) == 1
|
||||
try expect(xcscheme.testAction?.postActions.first?.title) == "Run2"
|
||||
try expect(xcscheme.testAction?.postActions.first?.scriptText) == "post"
|
||||
try expect(xcscheme.testAction?.postActions.first?.environmentBuildable?.blueprintName) == "MyApp"
|
||||
try expect(NSDictionary(dictionary: expectedInfoPlist).isEqual(to: infoPlist)).beTrue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import XCTest
|
||||
|
||||
class ProjectSpecTests: XCTestCase {
|
||||
@@ -176,6 +176,20 @@ class ProjectSpecTests: XCTestCase {
|
||||
try expectValidationError(project, .invalidTargetSchemeConfigVariant(target: "target1", configVariant: "invalidVariant", configType: .debug))
|
||||
}
|
||||
|
||||
$0.it("fails with invalid sdk dependency") {
|
||||
var project = baseProject
|
||||
project.targets = [
|
||||
Target(
|
||||
name: "target1",
|
||||
type: .application,
|
||||
platform: .iOS,
|
||||
dependencies: [Dependency(type: .sdk, reference: "invalidDependency")]
|
||||
),
|
||||
]
|
||||
|
||||
try expectValidationError(project, .invalidSDKDependency(target: "target1", dependency: "invalidDependency"))
|
||||
}
|
||||
|
||||
$0.it("fails with invalid scheme") {
|
||||
var project = baseProject
|
||||
project.schemes = [Scheme(
|
||||
@@ -207,6 +221,14 @@ class ProjectSpecTests: XCTestCase {
|
||||
try expectValidationError(project, .missingDefaultConfig(configName: "foo"))
|
||||
}
|
||||
|
||||
$0.it("validates config settings format") {
|
||||
var project = baseProject
|
||||
project.configs = Config.defaultConfigs
|
||||
project.settings.buildSettings = ["Debug": ["SETTING": "VALUE"], "Release": ["SETTING": "VALUE"]]
|
||||
|
||||
try expectValidationError(project, .invalidPerConfigSettings)
|
||||
}
|
||||
|
||||
$0.it("allows custom scheme for aggregated target") {
|
||||
var project = baseProject
|
||||
let buildScript = BuildScript(script: .path(#file), name: "buildScript1")
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import XcodeGenKit
|
||||
import xcodeproj
|
||||
import XCTest
|
||||
import Yams
|
||||
|
||||
fileprivate let app = Target(
|
||||
name: "MyApp",
|
||||
type: .application,
|
||||
platform: .iOS,
|
||||
dependencies: [Dependency(type: .target, reference: "MyFramework")]
|
||||
)
|
||||
|
||||
fileprivate let framework = Target(
|
||||
name: "MyFramework",
|
||||
type: .framework,
|
||||
platform: .iOS
|
||||
)
|
||||
|
||||
fileprivate let optionalFramework = Target(
|
||||
name: "MyOptionalFramework",
|
||||
type: .framework,
|
||||
platform: .iOS
|
||||
)
|
||||
|
||||
fileprivate let uiTest = Target(
|
||||
name: "MyAppUITests",
|
||||
type: .uiTestBundle,
|
||||
platform: .iOS,
|
||||
dependencies: [Dependency(type: .target, reference: "MyApp")]
|
||||
)
|
||||
|
||||
class SchemeGeneratorTests: XCTestCase {
|
||||
|
||||
func testSchemes() {
|
||||
describe {
|
||||
|
||||
let buildTarget = Scheme.BuildTarget(target: app.name)
|
||||
$0.it("generates scheme") {
|
||||
let preAction = Scheme.ExecutionAction(name: "Script", script: "echo Starting", settingsTarget: app.name)
|
||||
let scheme = Scheme(
|
||||
name: "MyScheme",
|
||||
build: Scheme.Build(targets: [buildTarget], preActions: [preAction])
|
||||
)
|
||||
let project = Project(
|
||||
basePath: "",
|
||||
name: "test",
|
||||
targets: [app, framework],
|
||||
schemes: [scheme]
|
||||
)
|
||||
let xcodeProject = try project.generateXcodeProject()
|
||||
guard let target = xcodeProject.pbxproj.nativeTargets
|
||||
.first(where: { $0.name == app.name }) else {
|
||||
throw failure("Target not found")
|
||||
}
|
||||
guard let xcscheme = xcodeProject.sharedData?.schemes.first else {
|
||||
throw failure("Scheme not found")
|
||||
}
|
||||
try expect(scheme.name) == "MyScheme"
|
||||
try expect(xcscheme.buildAction?.buildImplicitDependencies) == true
|
||||
try expect(xcscheme.buildAction?.parallelizeBuild) == true
|
||||
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"
|
||||
try expect(xcscheme.buildAction?.preActions.first?.environmentBuildable?.blueprintName) == "MyApp"
|
||||
guard let buildActionEntry = xcscheme.buildAction?.buildActionEntries.first else {
|
||||
throw failure("Build Action entry not found")
|
||||
}
|
||||
try expect(buildActionEntry.buildFor) == BuildType.all
|
||||
|
||||
let buildableReferences: [XCScheme.BuildableReference] = [
|
||||
buildActionEntry.buildableReference,
|
||||
xcscheme.launchAction?.buildableProductRunnable?.buildableReference,
|
||||
xcscheme.profileAction?.buildableProductRunnable?.buildableReference,
|
||||
xcscheme.testAction?.macroExpansion,
|
||||
].compactMap { $0 }
|
||||
|
||||
for buildableReference in buildableReferences {
|
||||
// FIXME: try expect(buildableReference.blueprintIdentifier) == target.reference
|
||||
try expect(buildableReference.blueprintName) == target.name
|
||||
try expect(buildableReference.buildableName) == "\(target.name).\(target.productType!.fileExtension!)"
|
||||
}
|
||||
|
||||
try expect(xcscheme.launchAction?.buildConfiguration) == "Debug"
|
||||
try expect(xcscheme.testAction?.buildConfiguration) == "Debug"
|
||||
try expect(xcscheme.profileAction?.buildConfiguration) == "Release"
|
||||
try expect(xcscheme.analyzeAction?.buildConfiguration) == "Debug"
|
||||
try expect(xcscheme.archiveAction?.buildConfiguration) == "Release"
|
||||
}
|
||||
|
||||
$0.it("sets environment variables for a scheme") {
|
||||
let runVariables: [XCScheme.EnvironmentVariable] = [
|
||||
XCScheme.EnvironmentVariable(variable: "RUN_ENV", value: "ENABLED", enabled: true),
|
||||
XCScheme.EnvironmentVariable(variable: "OTHER_RUN_ENV", value: "DISABLED", enabled: false),
|
||||
]
|
||||
|
||||
let scheme = Scheme(
|
||||
name: "EnvironmentVariablesScheme",
|
||||
build: Scheme.Build(targets: [buildTarget]),
|
||||
run: Scheme.Run(config: "Debug", environmentVariables: runVariables),
|
||||
test: Scheme.Test(config: "Debug"),
|
||||
profile: Scheme.Profile(config: "Debug")
|
||||
)
|
||||
let project = Project(
|
||||
basePath: "",
|
||||
name: "test",
|
||||
targets: [app, framework],
|
||||
schemes: [scheme]
|
||||
)
|
||||
let xcodeProject = try project.generateXcodeProject()
|
||||
|
||||
guard let xcscheme = xcodeProject.sharedData?.schemes.first else {
|
||||
throw failure("Scheme not found")
|
||||
}
|
||||
|
||||
try expect(
|
||||
xcodeProject.pbxproj.nativeTargets
|
||||
.contains(where: { $0.name == app.name })
|
||||
).beTrue()
|
||||
try expect(xcscheme.launchAction?.environmentVariables) == runVariables
|
||||
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"]
|
||||
var target = app
|
||||
target.scheme = TargetScheme(configVariants: configVariants)
|
||||
let configs: [Config] = [
|
||||
Config(name: "Test Debug", type: .debug),
|
||||
Config(name: "Production Debug", type: .debug),
|
||||
Config(name: "Test Release", type: .release),
|
||||
Config(name: "Production Release", type: .release),
|
||||
]
|
||||
|
||||
let project = Project(basePath: "", name: "test", configs: configs, targets: [target, framework])
|
||||
let xcodeProject = try project.generateXcodeProject()
|
||||
|
||||
try expect(xcodeProject.sharedData?.schemes.count) == 2
|
||||
|
||||
guard let xcscheme = xcodeProject.sharedData?.schemes
|
||||
.first(where: { $0.name == "\(target.name) Test" }) else {
|
||||
throw failure("Scheme not found")
|
||||
}
|
||||
guard let buildActionEntry = xcscheme.buildAction?.buildActionEntries.first else {
|
||||
throw failure("Build Action entry not found")
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
$0.it("generates environment variables for target schemes") {
|
||||
let variables: [XCScheme.EnvironmentVariable] = [XCScheme.EnvironmentVariable(variable: "env", value: "var", enabled: false)]
|
||||
var target = app
|
||||
target.scheme = TargetScheme(environmentVariables: variables)
|
||||
|
||||
let project = Project(basePath: "", name: "test", targets: [target, framework])
|
||||
let xcodeProject = try project.generateXcodeProject()
|
||||
|
||||
try expect(xcodeProject.sharedData?.schemes.count) == 1
|
||||
|
||||
guard let xcscheme = xcodeProject.sharedData?.schemes.first else {
|
||||
throw failure("Scheme not found")
|
||||
}
|
||||
|
||||
try expect(xcscheme.launchAction?.environmentVariables) == variables
|
||||
try expect(xcscheme.testAction?.environmentVariables) == variables
|
||||
try expect(xcscheme.profileAction?.environmentVariables) == variables
|
||||
}
|
||||
|
||||
$0.it("generates pre and post actions for target schemes") {
|
||||
var target = app
|
||||
target.scheme = TargetScheme(
|
||||
preActions: [.init(name: "Run", script: "do")],
|
||||
postActions: [.init(name: "Run2", script: "post", settingsTarget: "MyApp")]
|
||||
)
|
||||
|
||||
let project = Project(basePath: "", name: "test", targets: [target, framework])
|
||||
let xcodeProject = try project.generateXcodeProject()
|
||||
|
||||
try expect(xcodeProject.sharedData?.schemes.count) == 1
|
||||
|
||||
guard let xcscheme = xcodeProject.sharedData?.schemes.first else {
|
||||
throw failure("Scheme not found")
|
||||
}
|
||||
|
||||
try expect(xcscheme.launchAction?.preActions.count) == 1
|
||||
try expect(xcscheme.launchAction?.preActions.first?.title) == "Run"
|
||||
try expect(xcscheme.launchAction?.preActions.first?.scriptText) == "do"
|
||||
|
||||
try expect(xcscheme.testAction?.postActions.count) == 1
|
||||
try expect(xcscheme.testAction?.postActions.first?.title) == "Run2"
|
||||
try expect(xcscheme.testAction?.postActions.first?.scriptText) == "post"
|
||||
try expect(xcscheme.testAction?.postActions.first?.environmentBuildable?.blueprintName) == "MyApp"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import XCTest
|
||||
import Yams
|
||||
|
||||
@@ -85,14 +85,16 @@ class SourceGeneratorTests: XCTestCase {
|
||||
let project = Project(basePath: directoryPath, name: "Test", targets: [target])
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
try pbxProj.expectFile(paths: ["Sources", "Bar.swift"], buildPhase: .sources)
|
||||
let buildPhase = pbxProj.objects.copyFilesBuildPhases.referenceValues.first
|
||||
let buildPhase = pbxProj.copyFilesBuildPhases.first
|
||||
try expect(buildPhase?.dstSubfolderSpec) == .frameworks
|
||||
let fileReference = pbxProj.getFileReference(
|
||||
paths: ["Sources", "Foo.framework"],
|
||||
names: ["Sources", "Foo.framework"]
|
||||
)?.reference ?? ""
|
||||
let buildFile = pbxProj.objects.buildFiles.objectReferences
|
||||
.first(where: { $0.object.fileRef == fileReference })?.reference ?? ""
|
||||
)
|
||||
guard let buildFile = pbxProj.buildFiles
|
||||
.first(where: { $0.file == fileReference }) else {
|
||||
throw failure("Cant find build file")
|
||||
}
|
||||
try expect(buildPhase?.files.count) == 1
|
||||
try expect(buildPhase?.files.contains(buildFile)) == true
|
||||
}
|
||||
@@ -112,16 +114,58 @@ class SourceGeneratorTests: XCTestCase {
|
||||
let project = Project(basePath: directoryPath, name: "Test", targets: [target])
|
||||
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
guard let fileReference = pbxProj.objects.fileReferences.first(where: { $0.value.nameOrPath == "model2.xcdatamodel" }) else {
|
||||
guard let fileReference = pbxProj.fileReferences.first(where: { $0.nameOrPath == "model2.xcdatamodel" }) else {
|
||||
throw failure("Couldn't find model file reference")
|
||||
}
|
||||
guard let versionGroup = pbxProj.objects.versionGroups.values.first else {
|
||||
guard let versionGroup = pbxProj.versionGroups.first else {
|
||||
throw failure("Couldn't find version group")
|
||||
}
|
||||
try expect(versionGroup.currentVersion) == fileReference.key
|
||||
try expect(versionGroup.currentVersion) == fileReference
|
||||
try expect(versionGroup.children.count) == 3
|
||||
try expect(versionGroup.path) == "model.xcdatamodeld"
|
||||
try expect(fileReference.value.path) == "model2.xcdatamodel"
|
||||
try expect(fileReference.path) == "model2.xcdatamodel"
|
||||
}
|
||||
|
||||
$0.it("generates variant groups") {
|
||||
let directories = """
|
||||
Sources:
|
||||
Base.lproj:
|
||||
- LocalizedStoryboard.storyboard
|
||||
en.lproj:
|
||||
- LocalizedStoryboard.strings
|
||||
"""
|
||||
try createDirectories(directories)
|
||||
|
||||
let target = Target(name: "Test", type: .application, platform: .iOS, sources: ["Sources"])
|
||||
let project = Project(basePath: directoryPath, name: "Test", targets: [target])
|
||||
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
|
||||
func getFileReferences(_ path: String) -> [PBXFileReference] {
|
||||
return pbxProj.fileReferences.filter { $0.path == path }
|
||||
}
|
||||
|
||||
func getVariableGroups(_ name: String?) -> [PBXVariantGroup] {
|
||||
return pbxProj.variantGroups.filter { $0.name == name }
|
||||
}
|
||||
|
||||
let resourceName = "LocalizedStoryboard.storyboard"
|
||||
let baseResource = "Base.lproj/LocalizedStoryboard.storyboard"
|
||||
let localizedResource = "en.lproj/LocalizedStoryboard.strings"
|
||||
|
||||
guard let variableGroup = getVariableGroups(resourceName).first else { throw failure("Couldn't find the variable group") }
|
||||
|
||||
do {
|
||||
let refs = getFileReferences(baseResource)
|
||||
try expect(refs.count) == 1
|
||||
try expect(variableGroup.children.filter { $0 == refs.first }.count) == 1
|
||||
}
|
||||
|
||||
do {
|
||||
let refs = getFileReferences(localizedResource)
|
||||
try expect(refs.count) == 1
|
||||
try expect(variableGroup.children.filter { $0 == refs.first }.count) == 1
|
||||
}
|
||||
}
|
||||
|
||||
$0.it("handles duplicate names") {
|
||||
@@ -458,9 +502,7 @@ class SourceGeneratorTests: XCTestCase {
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
try pbxProj.expectFile(paths: ["Sources/A", "a.swift"], names: ["A", "a.swift"], buildPhase: .sources)
|
||||
|
||||
let sourcesBuildPhase = pbxProj.objects.buildPhases
|
||||
.first(where: { $0.1.buildPhase == BuildPhase.sources })!
|
||||
.value
|
||||
let sourcesBuildPhase = pbxProj.buildPhases.first(where: { $0.buildPhase == BuildPhase.sources })!
|
||||
|
||||
try expect(sourcesBuildPhase.files.count) == 1
|
||||
}
|
||||
@@ -480,7 +522,7 @@ class SourceGeneratorTests: XCTestCase {
|
||||
let project = Project(basePath: directoryPath, name: "Test", targets: [target])
|
||||
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
let groups = try pbxProj.getMainGroup().children.compactMap { pbxProj.objects.getFileElement(reference: $0)?.nameOrPath }
|
||||
let groups = try pbxProj.getMainGroup().children.map { $0.nameOrPath }
|
||||
try expect(groups) == ["A", "P", "S", "Frameworks", "Products"]
|
||||
}
|
||||
|
||||
@@ -503,8 +545,9 @@ class SourceGeneratorTests: XCTestCase {
|
||||
let project = Project(basePath: directoryPath, name: "Test", targets: [target])
|
||||
|
||||
let pbxProj = try project.generatePbxProj()
|
||||
let group = pbxProj.objects.group(named: "Sources", inGroup: try pbxProj.getMainGroup())!.object
|
||||
let names = group.children.compactMap { pbxProj.objects.getFileElement(reference: $0)?.nameOrPath }
|
||||
let mainGroup = try pbxProj.getMainGroup()
|
||||
let group = mainGroup.children.compactMap { $0 as? PBXGroup }.first { $0.nameOrPath == "Sources" }!
|
||||
let names = group.children.compactMap { $0.nameOrPath }
|
||||
try expect(names) == [
|
||||
"1file.a",
|
||||
"10file.a",
|
||||
@@ -532,10 +575,10 @@ extension PBXProj {
|
||||
}
|
||||
|
||||
if let buildPhase = buildPhase {
|
||||
let buildFile = objects.buildFiles.objectReferences
|
||||
.first(where: { $0.object.fileRef == fileReference.reference })
|
||||
let buildFile = buildFiles
|
||||
.first(where: { $0.file === fileReference })
|
||||
let actualBuildPhase = buildFile
|
||||
.flatMap { buildFile in objects.buildPhases.referenceValues.first { $0.files.contains(buildFile.reference) } }?.buildPhase
|
||||
.flatMap { buildFile in buildPhases.first { $0.files.contains(buildFile) } }?.buildPhase
|
||||
|
||||
var error: String?
|
||||
if let buildPhase = buildPhase.buildPhase {
|
||||
@@ -563,24 +606,20 @@ extension PBXProj {
|
||||
}
|
||||
}
|
||||
|
||||
func getFileReference(paths: [String], names: [String], file: String = #file, line: Int = #line) -> ObjectReference<PBXFileReference>? {
|
||||
guard let project = objects.projects.first?.value else { return nil }
|
||||
guard let mainGroup = objects.groups.getReference(project.mainGroup) else { return nil }
|
||||
func getFileReference(paths: [String], names: [String], file: String = #file, line: Int = #line) -> PBXFileReference? {
|
||||
guard let mainGroup = projects.first?.mainGroup else { return nil }
|
||||
|
||||
return getFileReference(group: mainGroup, paths: paths, names: names)
|
||||
}
|
||||
|
||||
func getMainGroup(function: String = #function, file: String = #file, line: Int = #line) throws -> PBXGroup {
|
||||
guard let project = objects.projects.first?.value else {
|
||||
throw failure("Couldn't find project", file: file, line: line)
|
||||
}
|
||||
guard let mainGroup = objects.groups.getReference(project.mainGroup) else {
|
||||
guard let mainGroup = projects.first?.mainGroup else {
|
||||
throw failure("Couldn't find main group", file: file, line: line)
|
||||
}
|
||||
return mainGroup
|
||||
}
|
||||
|
||||
private func getFileReference(group: PBXGroup, paths: [String], names: [String]) -> ObjectReference<PBXFileReference>? {
|
||||
private func getFileReference(group: PBXGroup, paths: [String], names: [String]) -> PBXFileReference? {
|
||||
|
||||
guard !paths.isEmpty else { return nil }
|
||||
let path = paths.first!
|
||||
@@ -588,16 +627,10 @@ extension PBXProj {
|
||||
let restOfPath = Array(paths.dropFirst())
|
||||
let restOfName = Array(names.dropFirst())
|
||||
if restOfPath.isEmpty {
|
||||
let fileReferences: [ObjectReference<PBXFileReference>] = group.children.compactMap { reference in
|
||||
if let fileReference = self.objects.fileReferences.getReference(reference) {
|
||||
return ObjectReference(reference: reference, object: fileReference)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fileReferences.first { $0.object.path == path && $0.object.nameOrPath == name }
|
||||
let fileReferences: [PBXFileReference] = group.children.compactMap { $0 as? PBXFileReference }
|
||||
return fileReferences.first { $0.path == path && $0.nameOrPath == name }
|
||||
} else {
|
||||
let groups = group.children.compactMap { self.objects.groups.getReference($0) }
|
||||
let groups = group.children.compactMap { $0 as? PBXGroup }
|
||||
guard let group = groups.first(where: { $0.path == path && $0.nameOrPath == name }) else { return nil }
|
||||
return getFileReference(group: group, paths: restOfPath, names: restOfName)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import XcodeGenKit
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import XCTest
|
||||
|
||||
class SpecLoadingTests: XCTestCase {
|
||||
@@ -146,13 +146,47 @@ class SpecLoadingTests: XCTestCase {
|
||||
targetDictionary["dependencies"] = [
|
||||
["target": "name", "embed": false],
|
||||
["carthage": "name"],
|
||||
["framework": "path"],
|
||||
["framework": "path", "weak": true],
|
||||
["sdk": "Contacts.framework"],
|
||||
]
|
||||
let target = try Target(name: "test", jsonDictionary: targetDictionary)
|
||||
try expect(target.dependencies.count) == 3
|
||||
try expect(target.dependencies.count) == 4
|
||||
try expect(target.dependencies[0]) == Dependency(type: .target, reference: "name", embed: false)
|
||||
try expect(target.dependencies[1]) == Dependency(type: .carthage, reference: "name")
|
||||
try expect(target.dependencies[2]) == Dependency(type: .framework, reference: "path")
|
||||
try expect(target.dependencies[2]) == Dependency(type: .framework, reference: "path", weakLink: true)
|
||||
try expect(target.dependencies[3]) == Dependency(type: .sdk, reference: "Contacts.framework")
|
||||
}
|
||||
|
||||
$0.it("parses info plist") {
|
||||
var targetDictionary = validTarget
|
||||
targetDictionary["info"] = [
|
||||
"path": "Info.plist",
|
||||
"properties": [
|
||||
"CFBundleName": "MyAppName",
|
||||
"UIBackgroundModes": ["fetch"],
|
||||
],
|
||||
]
|
||||
|
||||
let target = try Target(name: "", jsonDictionary: targetDictionary)
|
||||
try expect(target.info) == Plist(path: "Info.plist", attributes: [
|
||||
"CFBundleName": "MyAppName",
|
||||
"UIBackgroundModes": ["fetch"],
|
||||
])
|
||||
}
|
||||
|
||||
$0.it("parses entitlement plist") {
|
||||
var targetDictionary = validTarget
|
||||
targetDictionary["entitlements"] = [
|
||||
"path": "app.entitlements",
|
||||
"properties": [
|
||||
"com.apple.security.application-groups": "com.group",
|
||||
],
|
||||
]
|
||||
|
||||
let target = try Target(name: "", jsonDictionary: targetDictionary)
|
||||
try expect(target.entitlements) == Plist(path: "app.entitlements", attributes: [
|
||||
"com.apple.security.application-groups": "com.group",
|
||||
])
|
||||
}
|
||||
|
||||
$0.it("parses cross platform targets") {
|
||||
@@ -221,7 +255,7 @@ class SpecLoadingTests: XCTestCase {
|
||||
$0.it("parses target schemes") {
|
||||
var targetDictionary = validTarget
|
||||
targetDictionary["scheme"] = [
|
||||
"testTargets": ["t1", "t2"],
|
||||
"testTargets": ["t1", ["name": "t2"]],
|
||||
"configVariants": ["dev", "app-store"],
|
||||
"commandLineArguments": [
|
||||
"ENV1": true,
|
||||
@@ -280,6 +314,18 @@ class SpecLoadingTests: XCTestCase {
|
||||
],
|
||||
],
|
||||
],
|
||||
"test": [
|
||||
"config": "debug",
|
||||
"targets": [
|
||||
"Target1",
|
||||
[
|
||||
"name": "Target2",
|
||||
"parallelizable": true,
|
||||
"randomExecutionOrder": true,
|
||||
],
|
||||
],
|
||||
"gatherCoverageData": true,
|
||||
],
|
||||
]
|
||||
let scheme = try Scheme(name: "Scheme", jsonDictionary: schemeDictionary)
|
||||
let expectedTargets: [Scheme.BuildTarget] = [
|
||||
@@ -298,6 +344,20 @@ class SpecLoadingTests: XCTestCase {
|
||||
|
||||
try expect(scheme.build.parallelizeBuild) == false
|
||||
try expect(scheme.build.buildImplicitDependencies) == false
|
||||
|
||||
let expectedTest = Scheme.Test(
|
||||
config: "debug",
|
||||
gatherCoverageData: true,
|
||||
targets: [
|
||||
"Target1",
|
||||
Scheme.Test.TestTarget(
|
||||
name: "Target2",
|
||||
randomExecutionOrder: true,
|
||||
parallelizable: true
|
||||
),
|
||||
]
|
||||
)
|
||||
try expect(scheme.test) == expectedTest
|
||||
}
|
||||
|
||||
$0.it("parses schemes variables") {
|
||||
|
||||
@@ -2,7 +2,7 @@ import Foundation
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import Spectre
|
||||
import xcproj
|
||||
import xcodeproj
|
||||
import XCTest
|
||||
|
||||
let fixturePath = Path(#file).parent().parent() + "Fixtures"
|
||||
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
cd Tests/Fixtures/TestProject
|
||||
./build.sh
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [[ `git status --porcelain Tests/Fixtures/TestProject` ]]; then
|
||||
echo ""
|
||||
echo "⚠️ Generated TestProject has changed."
|
||||
echo "⚠️ If this is a valid change please run the tests and commit the updated TestProject."
|
||||
echo ""
|
||||
git --no-pager diff --color=always Tests/Fixtures/TestProject
|
||||
exit 1
|
||||
else
|
||||
echo "✅ Generated TestProject has not changed."
|
||||
fi
|
||||
Reference in New Issue
Block a user