├── LICENSE.md ├── README.md ├── bootstrap ├── cibuild ├── schemes.awk └── xctool.awk /LICENSE.md: -------------------------------------------------------------------------------- 1 | **Copyright (c) 2013 Justin Spahr-Summers** 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # objc-build-scripts 2 | 3 | This project is a collection of scripts created with two goals: 4 | 5 | 1. To standardize how Objective-C projects are bootstrapped after cloning 6 | 1. To easily build Objective-C projects on continuous integration servers 7 | 8 | ## Scripts 9 | 10 | Right now, there are two important scripts: [`bootstrap`](#bootstrap) and 11 | [`cibuild`](#cibuild). Both are Bash scripts, to maximize compatibility and 12 | eliminate pesky system configuration issues (like setting up a working Ruby 13 | environment). 14 | 15 | The structure of the scripts on disk is meant to follow that of a typical Ruby 16 | project: 17 | 18 | ``` 19 | script/ 20 | bootstrap 21 | cibuild 22 | ``` 23 | 24 | ### bootstrap 25 | 26 | This script is responsible for bootstrapping (initializing) your project after 27 | it's been checked out. Here, you should install or clone any dependencies that 28 | are required for a working build and development environment. 29 | 30 | By default, the script will verify that [xctool][] is installed, then initialize 31 | and update submodules recursively. If any submodules contain `script/bootstrap`, 32 | that will be run as well. 33 | 34 | To check that other tools are installed, you can set the `REQUIRED_TOOLS` 35 | environment variable before running `script/bootstrap`, or edit it within the 36 | script directly. Note that no installation is performed automatically, though 37 | this can always be added within your specific project. 38 | 39 | ### cibuild 40 | 41 | This script is responsible for building the project, as you would want it built 42 | for continuous integration. This is preferable to putting the logic on the CI 43 | server itself, since it ensures that any changes are versioned along with the 44 | source. 45 | 46 | By default, the script will run [`bootstrap`](#bootstrap), look for any Xcode 47 | workspace or project in the working directory, then build all targets/schemes 48 | (as found by `xcodebuild -list`) using [xctool][]. 49 | 50 | You can also specify the schemes to build by passing them into the script: 51 | 52 | ```sh 53 | script/cibuild ReactiveCocoa-Mac ReactiveCocoa-iOS 54 | ``` 55 | 56 | As with the `bootstrap` script, there are several environment variables that can 57 | be used to customize behavior. They can be set on the command line before 58 | invoking the script, or the defaults changed within the script directly. 59 | 60 | ## Getting Started 61 | 62 | To add the scripts to your project, read the contents of this repository into 63 | a `script` folder: 64 | 65 | ``` 66 | $ git remote add objc-build-scripts https://github.com/jspahrsummers/objc-build-scripts.git 67 | $ git fetch objc-build-scripts 68 | $ git read-tree --prefix=script/ -u objc-build-scripts/master 69 | ``` 70 | 71 | Then commit the changes, to incorporate the scripts into your own repository's 72 | history. You can also freely tweak the scripts for your specific project's 73 | needs. 74 | 75 | To merge in upstream changes later: 76 | 77 | ``` 78 | $ git fetch -p objc-build-scripts 79 | $ git merge --ff --squash -Xsubtree=script objc-build-scripts/master 80 | ``` 81 | 82 | [xctool]: https://github.com/facebook/xctool 83 | -------------------------------------------------------------------------------- /bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export SCRIPT_DIR=$(dirname "$0") 4 | 5 | ## 6 | ## Bootstrap Process 7 | ## 8 | 9 | main () 10 | { 11 | local submodules=$(git submodule status) 12 | local result=$? 13 | 14 | if [ "$result" -ne "0" ] 15 | then 16 | exit $result 17 | fi 18 | 19 | if [ -n "$submodules" ] 20 | then 21 | echo "*** Updating submodules..." 22 | update_submodules 23 | fi 24 | } 25 | 26 | bootstrap_submodule () 27 | { 28 | local bootstrap="script/bootstrap" 29 | 30 | if [ -e "$bootstrap" ] 31 | then 32 | echo "*** Bootstrapping $name..." 33 | "$bootstrap" >/dev/null 34 | else 35 | update_submodules 36 | fi 37 | } 38 | 39 | update_submodules () 40 | { 41 | git submodule sync --quiet && git submodule update --init && git submodule foreach --quiet bootstrap_submodule 42 | } 43 | 44 | export -f bootstrap_submodule 45 | export -f update_submodules 46 | 47 | main 48 | -------------------------------------------------------------------------------- /cibuild: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export SCRIPT_DIR=$(dirname "$0") 4 | 5 | ## 6 | ## Configuration Variables 7 | ## 8 | 9 | SCHEMES="$@" 10 | 11 | config () 12 | { 13 | # The workspace to build. 14 | # 15 | # If not set and no workspace is found, the -workspace flag will not be passed 16 | # to `xctool`. 17 | # 18 | # Only one of `XCWORKSPACE` and `XCODEPROJ` needs to be set. The former will 19 | # take precedence. 20 | : ${XCWORKSPACE=$(find_pattern "*.xcworkspace")} 21 | 22 | # The project to build. 23 | # 24 | # If not set and no project is found, the -project flag will not be passed 25 | # to `xctool`. 26 | # 27 | # Only one of `XCWORKSPACE` and `XCODEPROJ` needs to be set. The former will 28 | # take precedence. 29 | : ${XCODEPROJ=$(find_pattern "*.xcodeproj")} 30 | 31 | # A bootstrap script to run before building. 32 | # 33 | # If this file does not exist, it is not considered an error. 34 | : ${BOOTSTRAP="$SCRIPT_DIR/bootstrap"} 35 | 36 | # Extra options to pass to xctool. 37 | : ${XCTOOL_OPTIONS="RUN_CLANG_STATIC_ANALYZER=NO"} 38 | 39 | # A whitespace-separated list of default schemes to build. 40 | # 41 | # Individual names can be quoted to avoid word splitting. 42 | : ${SCHEMES:=$(xcodebuild -list -project "$XCODEPROJ" 2>/dev/null | awk -f "$SCRIPT_DIR/schemes.awk")} 43 | 44 | # A whitespace-separated list of executables that must be present and locatable. 45 | : ${REQUIRED_TOOLS="xctool"} 46 | 47 | export XCWORKSPACE 48 | export XCODEPROJ 49 | export BOOTSTRAP 50 | export XCTOOL_OPTIONS 51 | export SCHEMES 52 | export REQUIRED_TOOLS 53 | } 54 | 55 | ## 56 | ## Build Process 57 | ## 58 | 59 | main () 60 | { 61 | config 62 | 63 | if [ -n "$REQUIRED_TOOLS" ] 64 | then 65 | echo "*** Checking dependencies..." 66 | check_deps 67 | fi 68 | 69 | if [ -f "$BOOTSTRAP" ] 70 | then 71 | echo "*** Bootstrapping..." 72 | "$BOOTSTRAP" || exit $? 73 | fi 74 | 75 | echo "*** The following schemes will be built:" 76 | echo "$SCHEMES" | xargs -n 1 echo " " 77 | echo 78 | 79 | echo "$SCHEMES" | xargs -n 1 | ( 80 | local status=0 81 | 82 | while read scheme 83 | do 84 | build_scheme "$scheme" || status=1 85 | done 86 | 87 | exit $status 88 | ) 89 | } 90 | 91 | check_deps () 92 | { 93 | for tool in $REQUIRED_TOOLS 94 | do 95 | which -s "$tool" 96 | if [ "$?" -ne "0" ] 97 | then 98 | echo "*** Error: $tool not found. Please install it and cibuild again." 99 | exit 1 100 | fi 101 | done 102 | } 103 | 104 | find_pattern () 105 | { 106 | ls -d $1 2>/dev/null | head -n 1 107 | } 108 | 109 | run_xctool () 110 | { 111 | if [ -n "$XCWORKSPACE" ] 112 | then 113 | xctool -workspace "$XCWORKSPACE" $XCTOOL_OPTIONS "$@" 2>&1 114 | elif [ -n "$XCODEPROJ" ] 115 | then 116 | xctool -project "$XCODEPROJ" $XCTOOL_OPTIONS "$@" 2>&1 117 | else 118 | echo "*** No workspace or project file found." 119 | exit 1 120 | fi 121 | } 122 | 123 | parse_build () 124 | { 125 | awk -f "$SCRIPT_DIR/xctool.awk" 2>&1 >/dev/null 126 | } 127 | 128 | build_scheme () 129 | { 130 | local scheme=$1 131 | 132 | echo "*** Building and testing $scheme..." 133 | echo 134 | 135 | local sdkflag= 136 | local action=test 137 | 138 | # Determine whether we can run unit tests for this target. 139 | run_xctool -scheme "$scheme" run-tests | parse_build 140 | 141 | local awkstatus=$? 142 | 143 | if [ "$awkstatus" -eq "1" ] 144 | then 145 | # SDK not found, try for iphonesimulator. 146 | sdkflag="-sdk iphonesimulator" 147 | 148 | # Determine whether the unit tests will run with iphonesimulator 149 | run_xctool $sdkflag -scheme "$scheme" run-tests | parse_build 150 | 151 | awkstatus=$? 152 | 153 | if [ "$awkstatus" -ne "0" ] 154 | then 155 | # Unit tests will not run on iphonesimulator. 156 | sdkflag="" 157 | fi 158 | fi 159 | 160 | if [ "$awkstatus" -ne "0" ] 161 | then 162 | # Unit tests aren't supported. 163 | action=build 164 | fi 165 | 166 | run_xctool $sdkflag -scheme "$scheme" $action 167 | } 168 | 169 | export -f build_scheme 170 | export -f run_xctool 171 | export -f parse_build 172 | 173 | main 174 | -------------------------------------------------------------------------------- /schemes.awk: -------------------------------------------------------------------------------- 1 | BEGIN { 2 | FS = "\n"; 3 | } 4 | 5 | /Schemes:/ { 6 | while (getline && $0 != "") { 7 | sub(/^ +/, ""); 8 | print "'" $0 "'"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /xctool.awk: -------------------------------------------------------------------------------- 1 | # Exit statuses: 2 | # 3 | # 0 - No errors found. 4 | # 1 - Wrong SDK. Retry with SDK `iphonesimulator`. 5 | # 2 - Missing target. 6 | 7 | BEGIN { 8 | status = 0; 9 | } 10 | 11 | { 12 | print; 13 | } 14 | 15 | /Testing with the '(.+)' SDK is not yet supported/ { 16 | status = 1; 17 | } 18 | 19 | /does not contain a target named/ { 20 | status = 2; 21 | } 22 | 23 | END { 24 | exit status; 25 | } 26 | --------------------------------------------------------------------------------