appsendr 0.0.6 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,139 +0,0 @@
1
- module AppSendr::Command
2
- class Auth < Base
3
- attr_accessor :credentials
4
-
5
- def client
6
- @client ||= init_for_credentials
7
- end
8
-
9
- def init_for_credentials
10
- client = AppSendr::Client.new(api_key, host)
11
- #client.on_warning { |msg| self.display("\n#{msg}\n\n") }
12
- client
13
- end
14
-
15
- def auth_credentials(user,pass)
16
- AppSendr::Client.auth(user,pass,host)
17
- end
18
-
19
- # just a stub; will raise if not authenticated
20
- def check
21
- client.list
22
- end
23
-
24
- def host
25
- ENV['APPDROPPR_HOST'] || 'appsendr.com'
26
- #ENV['APPDROPPR_HOST'] || '0.0.0.0:3000'
27
-
28
- end
29
-
30
- def login
31
- user_pass = ask_for_credentials
32
- @credentials = auth_credentials(user_pass[0],user_pass[1])
33
- write_credentials
34
- end
35
-
36
- def api_key
37
- get_credentials
38
- @credentials[0]
39
- end
40
-
41
- # def user # :nodoc:
42
- # get_credentials
43
- # @credentials[0]
44
- # end
45
- #
46
- # def password # :nodoc:
47
- # get_credentials
48
- # @credentials[1]
49
- # end
50
-
51
- def get_credentials # :nodoc:
52
- return if @credentials
53
- unless @credentials = read_credentials
54
- user_pass = ask_for_credentials
55
- @credentials = auth_credentials(user_pass[0],user_pass[1])
56
-
57
- #@credentials = ask_for_credentials
58
- save_credentials
59
- end
60
- @credentials
61
- end
62
-
63
- def read_credentials
64
- File.exists?(credentials_file) and File.read(credentials_file).split("\n")
65
- end
66
-
67
- def echo_off
68
- system "stty -echo"
69
- end
70
-
71
- def echo_on
72
- system "stty echo"
73
- end
74
-
75
- def ask_for_credentials
76
- puts "Enter your AppSendr credentials."
77
-
78
- print "Email: "
79
- user = ask
80
-
81
- print "Password: "
82
- password = ask_for_password
83
-
84
- [ user, password ]
85
- end
86
-
87
- def ask_for_password
88
- echo_off
89
- password = ask
90
- puts
91
- echo_on
92
- return password
93
- end
94
-
95
- def save_credentials
96
- begin
97
- write_credentials
98
- #command = args.any? { |a| a == '--ignore-keys' } ? 'auth:check' : 'keys:add'
99
- command = 'auth:check'
100
- AppSendr::Command.run_internal(command, args)
101
- rescue RestClient::Unauthorized => e
102
- delete_credentials
103
- raise e unless retry_login?
104
-
105
- display "\nAuthentication failed"
106
- user_pass = ask_for_credentials
107
- @credentials = auth_credentials(user_pass[0],user_pass[1])
108
- @client = init_for_credentials
109
- retry
110
- rescue Exception => e
111
- delete_credentials
112
- raise e
113
- end
114
- end
115
-
116
- def retry_login?
117
- @login_attempts ||= 0
118
- @login_attempts += 1
119
- @login_attempts < 3
120
- end
121
-
122
- def write_credentials
123
- FileUtils.mkdir_p(File.dirname(credentials_file))
124
- File.open(credentials_file, 'w') do |f|
125
- f.puts self.credentials
126
- end
127
- set_credentials_permissions
128
- end
129
-
130
- def set_credentials_permissions
131
- FileUtils.chmod 0700, File.dirname(credentials_file)
132
- FileUtils.chmod 0600, credentials_file
133
- end
134
-
135
- def delete_credentials
136
- FileUtils.rm_f(credentials_file)
137
- end
138
- end
139
- end
@@ -1,78 +0,0 @@
1
- require 'fileutils'
2
-
3
- class String
4
- def cl_escape
5
- self.gsub('&','\\\\&').gsub(" ","\\ ")
6
- end
7
- end
8
-
9
-
10
- module AppSendr::Command
11
- class Base
12
- include AppSendr::Helpers
13
-
14
- attr_accessor :args
15
- attr_reader :autodetected_app
16
- def initialize(args, appsendr=nil)
17
- @args = args
18
- @appsendr = appsendr
19
- @autodetected_app = false
20
- end
21
-
22
- def confirm(message="Are you sure you wish to continue? (y/n)?")
23
- display("#{message} ", false)
24
- ask.downcase == 'y'
25
- end
26
-
27
- def format_date(date)
28
- date = Time.parse(date) if date.is_a?(String)
29
- date.strftime("%Y-%m-%d %H:%M %Z")
30
- end
31
-
32
- def ask
33
- gets.strip
34
- end
35
-
36
- def appsendr
37
- @appsendr ||= AppSendr::Command.run_internal('auth:client', args)
38
- end
39
-
40
- def extract_app(force=true)
41
- app = extract_option('--app', false)
42
- raise(CommandFailed, "You must specify an app name after --app") if app == false
43
- unless app
44
- app = extract_app_in_dir(Dir.pwd) ||
45
- raise(CommandFailed, "No app specified.\nRun this command from app folder or set it adding --app <app name>") if force
46
- @autodetected_app = true
47
- end
48
- app
49
- end
50
-
51
- def option_exists?(options, default=true)
52
- values = options.is_a?(Array) ? options : [options]
53
- return false unless opt_index = args.select { |a| values.include? a }.first
54
- args.delete(opt_index)
55
- return true
56
- end
57
-
58
-
59
- def extract_option(options, default=true)
60
- values = options.is_a?(Array) ? options : [options]
61
- return unless opt_index = args.select { |a| values.include? a }.first
62
- opt_position = args.index(opt_index) + 1
63
- if args.size > opt_position && opt_value = args[opt_position]
64
- if opt_value.include?('--')
65
- opt_value = nil
66
- else
67
- args.delete_at(opt_position)
68
- end
69
- end
70
- opt_value ||= default
71
- args.delete(opt_index)
72
- block_given? ? yield(opt_value) : opt_value
73
- end
74
-
75
- end
76
-
77
-
78
- end
@@ -1,320 +0,0 @@
1
- require 'zip/zip'
2
- require 'fileutils'
3
- require 'appsendr/progressbar'
4
-
5
- module AppSendr::Command
6
- class Build < Base
7
- attr_accessor :app_path, :app_dir, :app_name, :ipa_path, :provisioning_name, :provisioning_path, :configuration, :project_info
8
-
9
-
10
- def index
11
- notify = option_exists?('--notify', false)
12
- is_public = option_exists?('--public', false)
13
-
14
- if require_project(1,"build","your active configuration name")
15
- @configuration = load_configuration
16
- message "Building Xcode project with configuration #{@configuration}"
17
- compile(@configuration)
18
-
19
-
20
- @app_dir = path_to_app_dir
21
- @app_path = @app_dir+"/#{app_name}"
22
- if @app_name
23
- @notes = ask_for_notes
24
- message "Building IPA File"
25
-
26
- @ipa_path = build_ipa_with_app_at_path
27
- info = app_info
28
- bundle_identifier ||= info['CFBundleIdentifier']
29
- icon_path = icon_path(info)
30
- if is_file_to_large?(@ipa_path)
31
- upload_large_ipa(read_app_id,@ipa_path, profile_path,is_public,notify,@notes,bundle_identifier,icon_path)
32
- else
33
- message "Uploading IPA"
34
- appsendr.upload(read_app_id,@ipa_path, profile_path,is_public,notify,@notes,bundle_identifier,icon_path)
35
- message "App deployed"
36
- end
37
- FileUtils.rm_rf @ipa_path
38
- else
39
- error "No .app file was built for the configuration \"#{@configuration}\"."
40
- end
41
- end
42
- end
43
-
44
-
45
- def clean
46
- require_project_dir("clean")
47
- require_project_droppr
48
- config = args.join(" ").strip
49
- if !config.empty?
50
- config = "-configuration #{config} "
51
- end
52
- %x[xcodebuild #{config} clean]
53
- end
54
-
55
- private
56
-
57
- def compile(build_style, ossdk=nil, target=nil)
58
- iossdk = "iphoneos4.1"
59
- iossdk ||= ossdk
60
- sdk_str = "-sdk "+iossdk
61
-
62
- if target
63
- target_str = "-target "+target
64
- end
65
- xcode = "xcodebuild #{sdk_str} #{target_str}-configuration #{build_style} > /dev/null 2>&1"
66
- system(xcode)
67
- end
68
-
69
- def build_ipa_with_app_at_path
70
- payload_path = @app_dir+"/Payload"
71
- ipa_path = @app_dir+"/#{ipa_app_name(app_name).delete('^A-Za-z0-9\.\_\-')}"
72
-
73
-
74
- FileUtils.rm_rf payload_path
75
- Dir.mkdir(payload_path)
76
- `cp -r #{@app_path.cl_escape} #{payload_path.cl_escape+"/"+app_name.cl_escape}`
77
- build_ipa(payload_path.cl_escape,ipa_path.cl_escape)
78
-
79
- FileUtils.rm_rf payload_path
80
-
81
- return ipa_path
82
-
83
- end
84
-
85
- def build_ipa(payload_path,ipa_path)
86
- ditto_exec = "ditto -c -k --keepParent --sequesterRsrc #{payload_path} #{ipa_path}"
87
- system(ditto_exec)
88
- end
89
-
90
- def upload_large_ipa(app_id, ipa, provisioning ,is_public, notify, notes, bundle_id, icon)
91
- resp = appsendr.upload(app_id,ipa, provisioning,is_public,notify,notes,bundle_id,icon, true)
92
-
93
- @upload_id = nil
94
- @app_version_id = resp['message']['version']['id']
95
- if @app_version_id
96
- begin
97
- split_file(ipa)
98
- upload_as_multipart(app_id, @app_version_id, ipa, notify)
99
- rescue Exception => e
100
- clean_split_files(File.dirname(ipa))
101
- appsendr.abort_multipart(app_id, @app_version_id, ipa, @upload_id)
102
- raise e
103
- end
104
- end
105
-
106
- end
107
-
108
- def upload_as_multipart(app_id, version_id, ipa, notify)
109
-
110
- ipa_name = File.basename(ipa)
111
- ipa_dir = File.dirname(ipa)
112
-
113
- @split_files = organize_split_files(ipa_dir)
114
-
115
- resp = appsendr.initialize_multipart(app_id, version_id, ipa)
116
- @upload_id = resp['message']['upload_id']
117
- unless @upload_id
118
- clean_split_files(ipa_dir)
119
- raise "A error has occured with the upload"
120
- end
121
-
122
- parts = {}
123
- pbar = ProgressBar.new("Uploading IPA", @split_files.length * 2)
124
-
125
- @split_files.each_with_index{|file, i|
126
- pbar.inc
127
-
128
- resp = appsendr.upload_part(app_id, version_id, ipa, @upload_id, i+1, file)
129
- etag = resp['message']['etag']
130
- parts["#{i}"]={:part_num=>i+1, :e_tag=>etag}
131
-
132
- pbar.inc
133
-
134
- }
135
- pbar.finish
136
-
137
- appsendr.finish_multipart(app_id, version_id, ipa, @upload_id, parts, notify)
138
-
139
- clean_split_files(ipa_dir)
140
-
141
- end
142
-
143
- def clean_split_files(ipa_dir)
144
- if File.directory? "#{ipa_dir}/appsendr_splits"
145
- FileUtils.rm_r Dir.glob("#{ipa_dir}/appsendr_splits/*")
146
- FileUtils.rmdir "#{ipa_dir}/appsendr_splits"
147
- end
148
- end
149
-
150
- def organize_split_files(ipa_dir)
151
- dir_contents = Dir["#{ipa_dir}/appsendr_splits/AppSendrSplit*"]
152
- dir_contents.sort! { |a,b| a <=> b }
153
- unless dir_contents.length > 1
154
-
155
- clean_split_files(ipa_dir)
156
- raise "A error has occured with the upload"
157
-
158
- end
159
- return dir_contents
160
- end
161
-
162
- def split_file(file_path)
163
- return unless file_path
164
- file_dir = File.dirname(file_path)
165
-
166
- file_path = file_path.cl_escape
167
- clean_split_files(file_dir)
168
-
169
- file_dir << "/appsendr_splits"
170
-
171
- FileUtils.mkdir file_dir
172
-
173
- name = File.basename(file_path)
174
- `split -b 5mb #{file_path} AppSendrSplit`
175
-
176
- FileUtils.mv Dir.glob("AppSendrSplit*"), file_dir
177
- end
178
-
179
-
180
- #povisioning
181
-
182
- def profile_path
183
- return @provisioning_path if @provisioning_path
184
- @provisioning_path = provisioning_profiles_dir + "/#{profile_name}"
185
- @provisioning_path
186
- end
187
-
188
- def provisioning_profiles_dir
189
- File.expand_path("~/Library/MobileDevice/Provisioning\ Profiles/")
190
- end
191
-
192
-
193
- def profile_name
194
- return @provisioning_name if @provisioning_name
195
- error "Build is not valid for AdHoc distribution" unless valid_build?
196
-
197
- mem_buf = File.open(@app_path+"/embedded.mobileprovision","rb") {|io| io.read}
198
- name = mem_buf.scan(/UUID<\/key>[\s]+<string>(.*)<\/string>/).flatten.first
199
- @provisioning_name = name + ".mobileprovision"
200
- @provisioning_name
201
- end
202
-
203
-
204
- ## helpers
205
- def load_configuration
206
- @configuration = args.join(" ").strip
207
- error "That configuration does not exist.\nAvailable configurations:\n#{project_info[:configurations].join("\n")}" unless valid_configuration?
208
- @configuration
209
- end
210
-
211
- def valid_configuration?
212
- return false unless @configuration
213
- info = project_info
214
- info[:configurations].include?(@configuration)
215
- end
216
-
217
- def project_info
218
- return @project_info if @project_info
219
- result = %x[xcodebuild -list]
220
- project_info = result.split("\n")
221
- name = project_info.shift.scan(/\"(.*)\"/).flatten.first
222
- project_info.shift
223
- project_info.pop #remove last line
224
- project_info.pop #remove
225
- on_targets = true
226
- targets = []
227
- configs = []
228
- project_info.each{|ln|
229
- if ln.strip == "Build Configurations:"
230
- on_targets = false
231
- end
232
- if ln.strip != "Build Configurations:" and ln.strip != "Targets:" and ln.strip!=""
233
- ln = ln.gsub("(Active)","").strip
234
- on_targets ? targets.push(ln) : configs.push(ln)
235
- end
236
- }
237
-
238
- @project_info = {:name => name, :targets=>targets, :configurations=>configs}
239
- @project_info
240
- end
241
- def icon_path(info)
242
- icon_files = info['CFBundleIconFiles']
243
- icon_path = nil
244
- icon_file = nil
245
- if icon_files.nil? or icon_files.count == 0
246
- icon_file = info['CFBundleIconFile']
247
- else
248
- icon_file = icon_files.grep(/@2x/i)
249
- end
250
-
251
- if icon_file and !icon_file.empty?
252
- all_dir_contents = Dir["**/*"]
253
- all_dir_contents = all_dir_contents - all_dir_contents.grep(/^build/)
254
- icon = all_dir_contents.grep(%r{#{icon_file}}).flatten.first
255
- if icon
256
- icon_path = Dir.pwd+"/#{icon}"
257
- end
258
- elsif icon_files
259
-
260
- all_dir_contents = Dir["**/*"]
261
- all_dir_contents = all_dir_contents - all_dir_contents.grep(/^build/)
262
- icon = all_dir_contents.grep(%r{#{icon_files.first}}).flatten.first
263
- icon_dir = icon.sub(icon_files.first,"");
264
-
265
- icon_full_path = Dir.pwd+"/#{icon_dir}"
266
- biggest_icon_size = 0
267
- biggest_icon = ""
268
- for icon_file in icon_files
269
- size = File.size(icon_full_path+icon_file)
270
- if size > biggest_icon_size
271
- biggest_icon = icon_full_path+icon_file
272
- end
273
- end
274
- icon_path = biggest_icon
275
-
276
- end
277
- return icon_path
278
- end
279
-
280
-
281
- def valid_build?
282
- return unless @app_path
283
- File.exist?(@app_path+"/embedded.mobileprovision")
284
- end
285
-
286
- def app_info
287
- return unless @app_path
288
- mem_buf = File.open(@app_path+"/Info.plist","rb") {|io| io.read}
289
- plist = AppSendr::Plist::Binary.decode_binary_plist(mem_buf)
290
- plist
291
- end
292
-
293
- def path_to_app_dir
294
- Dir.pwd+"/build/#{@configuration}-iphoneos"
295
- end
296
-
297
- def app_name
298
- if @app_dir.nil?
299
- return unless @configuration
300
- @app_dir = path_to_app_dir
301
- end
302
- return @app_name if @app_name
303
- if File.directory? @app_dir
304
- @app_name = Dir.entries(@app_dir).grep(/.+\.app$/).first
305
- @app_name
306
- else
307
- error "#{@app_dir} does not exisit"
308
- end
309
- end
310
-
311
- def ipa_app_name(app_name)
312
- app_name.gsub(/\.app$/,".ipa")
313
- end
314
-
315
- def project_name
316
- return Dir.entries(Dir.pwd).grep(/.+\.xcodeproj/).first.sub("",".xcodeproj")
317
- end
318
-
319
- end
320
- end