krausefx-shenzhen 0.14.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e9dcf3992465f173b3273dd22c4bfd5d71b42dd7
4
+ data.tar.gz: c526db6c2bcc0fd7f45e9b2612d0a393f11670db
5
+ SHA512:
6
+ metadata.gz: ae852791af679b572b4e39726a661a4cbcbac2d8dab9bc0c460fe0b7903b4369e83690b63d7eeb4ec244657f9c82e7c998de3e29b0de867de2f2153a4f6fba3d
7
+ data.tar.gz: f02238a3d2be2e1e02bada918969fe3031a78a50b342e945c42c1db77b82c86df2bd4adc6303a46b1476ba9963239f71e274d8812cd77dd89a484bc0ffc7d0ea
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,68 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ krausefx-shenzhen (0.14.1)
5
+ aws-sdk (~> 1.0)
6
+ commander (~> 4.3)
7
+ dotenv (>= 0.7)
8
+ faraday (~> 0.8.9)
9
+ faraday_middleware (~> 0.9)
10
+ highline (>= 1.7.2)
11
+ json (~> 1.8)
12
+ net-sftp (~> 2.1.2)
13
+ plist (~> 3.1.0)
14
+ rubyzip (~> 1.1)
15
+ security (~> 0.1.3)
16
+ terminal-table (~> 1.4.5)
17
+
18
+ GEM
19
+ remote: https://rubygems.org/
20
+ specs:
21
+ aws-sdk (1.64.0)
22
+ aws-sdk-v1 (= 1.64.0)
23
+ aws-sdk-v1 (1.64.0)
24
+ json (~> 1.4)
25
+ nokogiri (>= 1.4.4)
26
+ commander (4.3.4)
27
+ highline (~> 1.7.2)
28
+ diff-lcs (1.2.5)
29
+ dotenv (2.0.1)
30
+ faraday (0.8.9)
31
+ multipart-post (~> 1.2.0)
32
+ faraday_middleware (0.9.1)
33
+ faraday (>= 0.7.4, < 0.10)
34
+ highline (1.7.2)
35
+ json (1.8.2)
36
+ mini_portile (0.6.2)
37
+ multipart-post (1.2.0)
38
+ net-sftp (2.1.2)
39
+ net-ssh (>= 2.6.5)
40
+ net-ssh (2.9.2)
41
+ nokogiri (1.6.6.2)
42
+ mini_portile (~> 0.6.0)
43
+ plist (3.1.0)
44
+ rake (10.4.2)
45
+ rspec (3.2.0)
46
+ rspec-core (~> 3.2.0)
47
+ rspec-expectations (~> 3.2.0)
48
+ rspec-mocks (~> 3.2.0)
49
+ rspec-core (3.2.3)
50
+ rspec-support (~> 3.2.0)
51
+ rspec-expectations (3.2.1)
52
+ diff-lcs (>= 1.2.0, < 2.0)
53
+ rspec-support (~> 3.2.0)
54
+ rspec-mocks (3.2.1)
55
+ diff-lcs (>= 1.2.0, < 2.0)
56
+ rspec-support (~> 3.2.0)
57
+ rspec-support (3.2.2)
58
+ rubyzip (1.1.7)
59
+ security (0.1.3)
60
+ terminal-table (1.4.5)
61
+
62
+ PLATFORMS
63
+ ruby
64
+
65
+ DEPENDENCIES
66
+ krausefx-shenzhen!
67
+ rake
68
+ rspec
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2012–2015 Mattt Thompson (http://mattt.me/)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all 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,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,198 @@
1
+ ![Shenzhen](https://raw.github.com/nomad/nomad.github.io/assets/shenzhen-banner.png)
2
+
3
+ Create `.ipa` files and distribute them from the command line, using any of the following methods:
4
+
5
+ - [iTunes Connect](https://itunesconnect.apple.com)
6
+ - [HockeyApp](http://www.hockeyapp.net)
7
+ - [Beta by Crashlytics](http://try.crashlytics.com/beta/)
8
+ - [RivieraBuild](http://rivierabuild.com)
9
+ - [TestFairy](https://www.testfairy.com/)
10
+ - [DeployGate](https://deploygate.com)
11
+ - [Fly It Remotely (FIR.im)](http://fir.im)
12
+ - [蒲公英 (PGYER)](http://www.pgyer.com)
13
+ - [Amazon S3](http://aws.amazon.com/s3/)
14
+ - FTP / SFTP
15
+
16
+ Less cumbersome than clicking around in Xcode, and less hassle than rolling your own build script, Shenzhen radically improves the process of getting new builds out to testers and enterprises.
17
+
18
+ > `shenzhen` is named for [深圳](http://en.wikipedia.org/wiki/Shenzhen), the Chinese city famous for being the center of manufacturing for a majority of consumer electronics, including iPhones and iPads.
19
+ > It's part of a series of world-class command-line utilities for iOS development, which includes [Cupertino](https://github.com/mattt/cupertino) (Apple Dev Center management), [Houston](https://github.com/mattt/houston) (Push Notifications), [Venice](https://github.com/mattt/venice) (In-App Purchase Receipt Verification), [Dubai](https://github.com/mattt/dubai) (Passbook pass generation), and [Nashville](https://github.com/nomad/nashville) (iTunes Store API).
20
+
21
+ ## Installation
22
+
23
+ ```
24
+ $ gem install shenzhen
25
+ ```
26
+
27
+ ### JSON Build Error
28
+
29
+ Users running Mac OS X Mavericks with Xcode 5.1 may encounter an error when attempting to install the `json` gem dependency. As per the [Xcode 5.1 Release Notes](https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Introduction/Introduction.html):
30
+
31
+ > The Apple LLVM compiler in Xcode 5.1 treats unrecognized command-line options as errors. This issue has been seen when building both Python native extensions and Ruby Gems, where some invalid compiler options are currently specified.
32
+
33
+ To work around this, install the `json` gem first with the following command:
34
+
35
+ ```
36
+ $ ARCHFLAGS=-Wno-error=unused-command-line-argument-hard-error-in-future gem install json
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ > For best results, set your environment localization to UTF-8, with `$ export LC_ALL="en_US.UTF-8"`. Otherwise, Shenzhen may return unexpectedly with the error "invalid byte sequence in US-ASCII".
42
+
43
+ Shenzhen adds the `ipa` command to your PATH:
44
+
45
+ ```
46
+ $ ipa
47
+
48
+ Build and distribute iOS apps (.ipa files)
49
+
50
+ Commands:
51
+ build Create a new .ipa file for your app
52
+ distribute:rivierabuild Distribute an .ipa file over [RivieraBuild](http://rivierabuild.com)
53
+ distribute:hockeyapp Distribute an .ipa file over HockeyApp
54
+ distribute:crashlytics Distribute an .ipa file over Crashlytics
55
+ distribute:deploygate Distribute an .ipa file over deploygate
56
+ distribute:firim Distribute an .ipa file over fir.im
57
+ distribute:itunesconnect Upload an .ipa file to iTunes Connect for review
58
+ distribute:pgyer Distribute an .ipa file over Pgyer
59
+ distribute:ftp Distribute an .ipa file over FTP
60
+ distribute:s3 Distribute an .ipa file over Amazon S3
61
+ distribute:testfairy Distribute an .ipa file over TestFairy
62
+ info Show mobile provisioning information about an .ipa file
63
+ help Display global or [command] help documentation.
64
+
65
+ Global Options:
66
+ -h, --help Display help documentation
67
+ -v, --version Display version information
68
+ -t, --trace Display backtrace when an error occurs
69
+ ```
70
+
71
+ ### Building & Distribution
72
+
73
+ ```
74
+ $ cd /path/to/iOS Project/
75
+ $ ipa build
76
+ $ ipa distribute
77
+ ```
78
+
79
+ #### RivieraBuild Distribution
80
+
81
+ ```
82
+ $ ipa distribute:rivierabuild -k API_TOKEN -a AVAILABILITY
83
+ ```
84
+
85
+ > Shenzhen will load credentials from the environment variable `RIVIERA_API_TOKEN` unless otherwise specified.
86
+ > To get the list of availability options, visit http://api.rivierabuild.com
87
+
88
+ #### HockeyApp Distribution
89
+
90
+ ```
91
+ $ ipa distribute:hockeyapp -a API_TOKEN
92
+ ```
93
+
94
+ > Shenzhen will load credentials from the environment variable `HOCKEYAPP_API_TOKEN` unless otherwise specified.
95
+
96
+ #### TestFairy Distribution
97
+
98
+ ```
99
+ $ ipa distribute:testfairy -a API_KEY
100
+ ```
101
+
102
+ > Shenzhen will load credentials from the environment variable `TESTFAIRY_API_KEY` unless otherwise specified.
103
+
104
+ #### Crashlytics Beta Distribution
105
+
106
+ ```
107
+ $ ipa distribute:crashlytics -c /path/to/Crashlytics.framework -a API_TOKEN -s BUILD_SECRET
108
+ ```
109
+
110
+ > Shenzhen will load credentials from the environment variables `CRASHLYTICS_API_TOKEN` & `CRASHLYTICS_BUILD_SECRET`, and attempt to run the submit executable `submit` in the path to Crashlytics.framework specified by `CRASHLYTICS_FRAMEWORK_PATH` unless otherwise specified.
111
+
112
+
113
+ #### DeployGate Distribution
114
+
115
+ ```
116
+ $ ipa distribute:deploygate -a API_TOKEN -u USER_NAME
117
+ ```
118
+
119
+ > Shenzhen will load credentials from the environment variable `DEPLOYGATE_API_TOKEN` and `DEPLOYGATE_USER_NAME` unless otherwise specified.
120
+
121
+ #### FTP Distribution
122
+
123
+ ```
124
+ $ ipa distribute:ftp --host HOST -u USER -p PASSWORD -P FTP_PATH
125
+ ```
126
+
127
+ #### SFTP Distribution
128
+
129
+ ```
130
+ $ ipa distribute:sftp --host HOST -u USER -p PASSWORD -P FTP_PATH
131
+ ```
132
+
133
+ #### Amazon S3 Distribution
134
+
135
+ ```
136
+ $ ipa distribute:s3 -a ACCESS_KEY_ID -s SECRET_ACCESS_KEY -b BUCKET
137
+ ```
138
+
139
+ > Shenzhen will load credentials from the environment variables `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and `AWS_REGION` unless otherwise specified.
140
+
141
+ #### FIR (Fly it Remotely)
142
+
143
+ ```
144
+ $ ipa distribute:fir -u USER_TOKEN -a APP_ID
145
+ ```
146
+
147
+ > Shenzhen will load credentials from the environment variables `FIR_USER_TOKEN`, `FIR_APP_ID` unless otherwise specified.
148
+
149
+ #### 蒲公英 (PGYER)
150
+
151
+ ```
152
+ $ ipa distribute:pgyer -u USER_KEY -a APP_KEY
153
+ ```
154
+
155
+ > Shenzhen will load credentials from the environment variables `PGYER_USER_KEY`, `PGYER_API_KEY` unless otherwise specified.
156
+
157
+
158
+ #### iTunes Connect Distribution
159
+
160
+ ```
161
+ $ ipa distribute:itunesconnect -a me@email.com -p myitunesconnectpassword -i appleid --upload
162
+ ```
163
+
164
+ > Shenzhen will load credentials from the environment variables `ITUNES_CONNECT_ACCOUNT` and `ITUNES_CONNECT_PASSWORD` unless otherwise specified. If only an account is provided, the keychain will be searched for a matching entry.
165
+ >
166
+ > The `-i` (or `--apple-id`) flag is "An automatically generated ID assigned to your app". It can be found via iTunes Connect by navigating to:
167
+ > * My Apps -> [App Name] -> More -> About This App -> Apple ID
168
+ >
169
+ > For a fully hands-free upload, in a CI environment for example, ensure your iTunes Connect credentials are stored in your keychain, and that the keychain item has the Validation app in its 'Always allow access' list. Running Shenzhen once with the `--save-keychain` flag, and clicking `Always Allow` on the prompt will set this up for you.
170
+
171
+ ### Displaying Embedded .mobileprovision Information
172
+
173
+ ```
174
+ $ ipa info /path/to/app.ipa
175
+
176
+ +-----------------------------+----------------------------------------------------------+
177
+ | ApplicationIdentifierPrefix | DJ73OPSO53 |
178
+ | CreationDate | 2014-03-26T02:53:00+00:00 |
179
+ | Entitlements | application-identifier: DJ73OPSO53.com.nomad.shenzhen |
180
+ | | aps-environment: production |
181
+ | | get-task-allow: false |
182
+ | | keychain-access-groups: ["DJ73OPSO53.*"] |
183
+ | CreationDate | 2017-03-26T02:53:00+00:00 |
184
+ | Name | Shenzhen |
185
+ | TeamIdentifier | S6ZYP4L6TY |
186
+ | TimeToLive | 172 |
187
+ | UUID | P7602NR3-4D34-441N-B6C9-R79395PN1OO3 |
188
+ | Version | 1 |
189
+ +-----------------------------+----------------------------------------------------------+
190
+ ```
191
+
192
+ ## Creator
193
+
194
+ Mattt Thompson ([@mattt](https://twitter.com/mattt))
195
+
196
+ ## License
197
+
198
+ Shenzhen is released under an MIT license. See LICENSE for more information.
@@ -0,0 +1,9 @@
1
+ require "bundler/setup"
2
+
3
+ gemspec = eval(File.read("shenzhen.gemspec"))
4
+
5
+ task :build => "#{gemspec.full_name}.gem"
6
+
7
+ file "#{gemspec.full_name}.gem" => gemspec.files + ["shenzhen.gemspec"] do
8
+ system "gem build shenzhen.gemspec"
9
+ end
@@ -0,0 +1,4 @@
1
+ require 'shenzhen/version'
2
+ require 'shenzhen/agvtool'
3
+ require 'shenzhen/xcodebuild'
4
+ require 'shenzhen/plistbuddy'
@@ -0,0 +1,17 @@
1
+ module Shenzhen::Agvtool
2
+ class << self
3
+ def what_version
4
+ output = `agvtool what-version -terse`
5
+ output.length > 0 ? output : nil
6
+ end
7
+
8
+ alias :vers :what_version
9
+
10
+ def what_marketing_version
11
+ output = `agvtool what-marketing-version -terse`
12
+ output.scan(/\=(.+)$/).flatten.first
13
+ end
14
+
15
+ alias :mvers :what_marketing_version
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ $:.push File.expand_path('../', __FILE__)
2
+
3
+ require 'plugins/rivierabuild'
4
+ require 'plugins/hockeyapp'
5
+ require 'plugins/testfairy'
6
+ require 'plugins/deploygate'
7
+ require 'plugins/itunesconnect'
8
+ require 'plugins/ftp'
9
+ require 'plugins/s3'
10
+ require 'plugins/crashlytics'
11
+ require 'plugins/fir'
12
+ require 'plugins/pgyer'
13
+
14
+ require 'commands/build'
15
+ require 'commands/distribute'
16
+ require 'commands/info'
@@ -0,0 +1,213 @@
1
+ require 'fileutils'
2
+
3
+ command :build do |c|
4
+ c.syntax = 'ipa build [options]'
5
+ c.summary = 'Create a new .ipa file for your app'
6
+ c.description = ''
7
+
8
+ c.option '-w', '--workspace WORKSPACE', 'Workspace (.xcworkspace) file to use to build app (automatically detected in current directory)'
9
+ c.option '-p', '--project PROJECT', 'Project (.xcodeproj) file to use to build app (automatically detected in current directory, overridden by --workspace option, if passed)'
10
+ c.option '-c', '--configuration CONFIGURATION', 'Configuration used to build'
11
+ c.option '-s', '--scheme SCHEME', 'Scheme used to build app'
12
+ c.option '--xcconfig XCCONFIG', 'use an extra XCCONFIG file to build the app'
13
+ c.option '--xcargs XCARGS', 'pass additional arguments to xcodebuild when building the app. Be sure to quote multiple args.'
14
+ c.option '--[no-]clean', 'Clean project before building'
15
+ c.option '--[no-]archive', 'Archive project after building'
16
+ c.option '-d', '--destination DESTINATION', 'Destination. Defaults to current directory'
17
+ c.option '-m', '--embed PROVISION', 'Sign .ipa file with .mobileprovision'
18
+ c.option '-i', '--identity IDENTITY', 'Identity to be used along with --embed'
19
+ c.option '--sdk SDK', 'use SDK as the name or path of the base SDK when building the project'
20
+ c.option '--ipa IPA', 'specify the name of the .ipa file to generate (including file extension)'
21
+
22
+ c.action do |args, options|
23
+ validate_xcode_version!
24
+
25
+ @workspace = options.workspace
26
+ @project = options.project unless @workspace
27
+
28
+ @xcodebuild_info = Shenzhen::XcodeBuild.info(:workspace => @workspace, :project => @project)
29
+
30
+ @scheme = options.scheme
31
+ @sdk = options.sdk || 'iphoneos'
32
+ @configuration = options.configuration
33
+ @xcconfig = options.xcconfig
34
+ @xcargs = options.xcargs
35
+ @destination = options.destination || Dir.pwd
36
+ @ipa_name_override = options.ipa
37
+ FileUtils.mkdir_p(@destination) unless File.directory?(@destination)
38
+
39
+ determine_workspace_or_project! unless @workspace || @project
40
+
41
+ if @project
42
+ determine_configuration! unless @configuration
43
+ say_error "Configuration #{@configuration} not found" and abort unless (@xcodebuild_info.build_configurations.include?(@configuration) rescue false)
44
+ end
45
+
46
+ determine_scheme! unless @scheme
47
+ say_error "Scheme #{@scheme} not found" and abort unless (@xcodebuild_info.schemes.include?(@scheme) rescue false)
48
+
49
+ @configuration = options.configuration
50
+
51
+ flags = []
52
+ flags << %{-sdk #{@sdk}}
53
+ flags << %{-workspace "#{@workspace}"} if @workspace
54
+ flags << %{-project "#{@project}"} if @project
55
+ flags << %{-scheme "#{@scheme}"} if @scheme
56
+ flags << %{-configuration "#{@configuration}"} if @configuration
57
+ flags << %{-xcconfig "#{@xcconfig}"} if @xcconfig
58
+ flags << @xcargs if @xcargs
59
+
60
+ @target, @xcodebuild_settings = Shenzhen::XcodeBuild.settings(*flags).detect{|target, settings| settings['WRAPPER_EXTENSION'] == "app"}
61
+ say_error "App settings could not be found." and abort unless @xcodebuild_settings
62
+
63
+ if !@configuration
64
+ @configuration = @xcodebuild_settings['CONFIGURATION']
65
+ flags << "-configuration '#{@configuration}'"
66
+ end
67
+
68
+ say_warning "Building \"#{@workspace || @project}\" with Scheme \"#{@scheme}\" and Configuration \"#{@configuration}\"\n" if $verbose
69
+
70
+ log "xcodebuild", (@workspace || @project)
71
+
72
+ xcode = `xcode-select --print-path`.strip
73
+
74
+ actions = []
75
+ actions << :clean unless options.clean == false
76
+ actions << :build
77
+ actions << :archive unless options.archive == false
78
+
79
+ ENV['CC'] = nil # Fix for RVM
80
+ command = %{xcodebuild #{flags.join(' ')} #{actions.join(' ')} #{'1> /dev/null' unless $verbose}}
81
+ puts command if $verbose
82
+ abort unless system command
83
+
84
+ @target, @xcodebuild_settings = Shenzhen::XcodeBuild.settings(*flags).detect{|target, settings| settings['WRAPPER_EXTENSION'] == "app"}
85
+ say_error "App settings could not be found." and abort unless @xcodebuild_settings
86
+
87
+ @app_path = File.join(@xcodebuild_settings['BUILT_PRODUCTS_DIR'], @xcodebuild_settings['WRAPPER_NAME'])
88
+ @dsym_path = @app_path + ".dSYM"
89
+ @dsym_filename = File.expand_path("#{@xcodebuild_settings['WRAPPER_NAME']}.dSYM", @destination)
90
+ @ipa_name = @ipa_name_override || @xcodebuild_settings['WRAPPER_NAME'].gsub(@xcodebuild_settings['WRAPPER_SUFFIX'], "") + ".ipa"
91
+ @ipa_path = File.expand_path(@ipa_name, @destination)
92
+
93
+ log "xcrun", "PackageApplication"
94
+ command = %{xcrun -sdk #{@sdk} PackageApplication -v "#{@app_path}" -o "#{@ipa_path}" --embed "#{options.embed || @dsym_path}" #{"-s \"#{options.identity}\"" if options.identity} #{'--verbose' if $verbose} #{'1> /dev/null' unless $verbose}}
95
+ puts command if $verbose
96
+ abort unless system command
97
+
98
+
99
+ # Determine whether this is a Swift project and, eventually, the list of libraries to copy from
100
+ # Xcode's toolchain directory since there's no "xcodebuild" target to do just that (it is done
101
+ # post-build when exporting an archived build from the "Organizer").
102
+ @ipa_swift_frameworks = Dir["#{@app_path}/Frameworks/libswift*"]
103
+
104
+ if not @ipa_swift_frameworks.empty?
105
+ Dir.mktmpdir do |tmpdir|
106
+ # Copy all necessary Swift libraries to a temporary "SwiftSupport" directory so that we can
107
+ # easily add it to the .ipa later.
108
+ swift_support = File.join(tmpdir, "SwiftSupport")
109
+
110
+ Dir.mkdir(swift_support)
111
+
112
+ @ipa_swift_frameworks.each do |path|
113
+ framework = File.basename(path)
114
+
115
+ FileUtils.copy_file("#{xcode}/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/#{@sdk}/#{framework}", File.join(swift_support, framework))
116
+ end
117
+
118
+ # Add "SwiftSupport" to the .ipa archive
119
+ Dir.chdir(tmpdir) do
120
+ abort unless system %{zip --recurse-paths "#{@ipa_path}" "SwiftSupport" #{'> /dev/null' unless $verbose}}
121
+ end
122
+ end
123
+ end
124
+
125
+ if is_watchkit?(@app_path)
126
+ log "Adding WatchKit support files", "#{xcode}/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/Library/Application Support/WatchKit/WK"
127
+ Dir.mktmpdir do |tmpdir|
128
+ # Make watchkit support directory
129
+ watchkit_support = File.join(tmpdir, "WatchKitSupport")
130
+ Dir.mkdir(watchkit_support)
131
+
132
+ # Copy WK from Xcode into WatchKitSupport
133
+ FileUtils.copy_file("#{xcode}/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/Library/Application Support/WatchKit/WK", File.join(watchkit_support, "WK"))
134
+
135
+ # Add "WatchKitSupport" to the .ipa archive
136
+ Dir.chdir(tmpdir) do
137
+ abort unless system %{zip --recurse-paths "#{@ipa_path}" "WatchKitSupport" #{'> /dev/null' unless $verbose}}
138
+ end
139
+ end
140
+ end
141
+
142
+ log "zip", @dsym_filename
143
+ abort unless system %{cp -r "#{@dsym_path}" "#{@destination}" && pushd "#{File.dirname(@dsym_filename)}" && zip -r "#{@dsym_filename}.zip" "#{File.basename(@dsym_filename)}" #{'> /dev/null' unless $verbose} && popd && rm -rf "#{@dsym_filename}"}
144
+
145
+ say_ok "Successfully built:"
146
+ say_ok @ipa_path
147
+ end
148
+
149
+ private
150
+
151
+ def is_watchkit?(path)
152
+ Dir["#{path}/**/*.plist"].each do |current|
153
+ # `2>&1` to hide the error if it's not there: http://stackoverflow.com/a/4783536/445598
154
+ watchkit_enabled = `/usr/libexec/PlistBuddy -c 'Print WKWatchKitApp' '#{current}' 2>&1`.strip
155
+ if watchkit_enabled == 'true'
156
+ return true
157
+ end
158
+ end
159
+ false
160
+ end
161
+
162
+ def validate_xcode_version!
163
+ version = Shenzhen::XcodeBuild.version
164
+ say_error "Shenzhen requires Xcode 4 (found #{version}). Please install or switch to the latest Xcode." and abort if version < "4.0.0"
165
+ end
166
+
167
+ def determine_workspace_or_project!
168
+ workspaces, projects = Dir["*.xcworkspace"], Dir["*.xcodeproj"]
169
+
170
+ if workspaces.empty?
171
+ if projects.empty?
172
+ say_error "No Xcode projects or workspaces found in current directory" and abort
173
+ else
174
+ if projects.length == 1
175
+ @project = projects.first
176
+ else
177
+ @project = choose "Select a project:", *projects
178
+ end
179
+ end
180
+ else
181
+ if workspaces.length == 1
182
+ @workspace = workspaces.first
183
+ else
184
+ @workspace = choose "Select a workspace:", *workspaces
185
+ end
186
+ end
187
+ end
188
+
189
+ def determine_scheme!
190
+ say_error "No schemes found in Xcode project or workspace" and abort unless @xcodebuild_info.schemes
191
+
192
+ if @xcodebuild_info.schemes.length == 1
193
+ @scheme = @xcodebuild_info.schemes.first
194
+ else
195
+ @scheme = choose "Select a scheme:", *@xcodebuild_info.schemes
196
+ end
197
+ end
198
+
199
+ def determine_configuration!
200
+ configurations = @xcodebuild_info.build_configurations rescue []
201
+ if configurations.nil? or configurations.empty? or configurations.include?("Debug")
202
+ @configuration = "Debug"
203
+ elsif configurations.length == 1
204
+ @configuration = configurations.first
205
+ end
206
+
207
+ if @configuration
208
+ say_warning "Configuration was not passed, defaulting to #{@configuration}"
209
+ else
210
+ @configuration = choose "Select a configuration:", *configurations
211
+ end
212
+ end
213
+ end