appsendr 0.0.3 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest +4 -0
- data/Rakefile +2 -2
- data/appsendr.gemspec +5 -8
- data/lib/appsendr/client.rb +105 -29
- data/lib/appsendr/command.rb +14 -3
- data/lib/appsendr/commands/app.rb +46 -33
- data/lib/appsendr/commands/auth.rb +5 -21
- data/lib/appsendr/commands/base.rb +1 -0
- data/lib/appsendr/commands/build.rb +139 -19
- data/lib/appsendr/commands/collaborators.rb +29 -1
- data/lib/appsendr/commands/deploy.rb +13 -2
- data/lib/appsendr/commands/groups.rb +63 -0
- data/lib/appsendr/commands/help.rb +10 -3
- data/lib/appsendr/commands/portal.rb +375 -0
- data/lib/appsendr/commands/testers.rb +14 -31
- data/lib/appsendr/constants.rb +1 -1
- data/lib/appsendr/helpers.rb +31 -7
- data/lib/appsendr/progressbar.rb +236 -0
- metadata +12 -20
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'zip/zip'
|
2
|
-
require '
|
2
|
+
require 'fileutils'
|
3
|
+
require 'appsendr/progressbar'
|
4
|
+
|
3
5
|
module AppSendr::Command
|
4
6
|
class Build < Base
|
5
7
|
attr_accessor :app_path, :app_dir, :app_name, :ipa_path, :provisioning_name, :provisioning_path, :configuration, :project_info
|
@@ -8,18 +10,30 @@ module AppSendr::Command
|
|
8
10
|
def index
|
9
11
|
if require_project(1,"build","your active configuration name")
|
10
12
|
@configuration = load_configuration
|
11
|
-
|
13
|
+
message "Building Xcode project with configuration #{@configuration}"
|
12
14
|
compile(@configuration)
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
appsendr.upload(read_app_id,@ipa_path, profile_path,nil,bundle_identifier,icon_path)
|
21
|
-
FileUtils.rm_rf @ipa_path
|
16
|
+
|
17
|
+
@app_dir = path_to_app_dir
|
18
|
+
@app_path = @app_dir+"/#{app_name}"
|
19
|
+
if @app_name
|
20
|
+
@notes = ask_for_notes
|
21
|
+
message "Building IPA File"
|
22
22
|
|
23
|
+
@ipa_path = build_ipa_with_app_at_path
|
24
|
+
info = app_info
|
25
|
+
bundle_identifier ||= info['CFBundleIdentifier']
|
26
|
+
icon_path = icon_path(info)
|
27
|
+
if is_file_to_large?(@ipa_path)
|
28
|
+
upload_large_ipa(read_app_id,@ipa_path, profile_path,notify,@notes,bundle_identifier,icon_path)
|
29
|
+
else
|
30
|
+
appsendr.upload(read_app_id,@ipa_path, profile_path,notify,@notes,bundle_identifier,icon_path)
|
31
|
+
message "App deployed"
|
32
|
+
end
|
33
|
+
FileUtils.rm_rf @ipa_path
|
34
|
+
else
|
35
|
+
error "No .app file was built for the configuration \"#{@configuration}\"."
|
36
|
+
end
|
23
37
|
end
|
24
38
|
end
|
25
39
|
|
@@ -50,7 +64,7 @@ module AppSendr::Command
|
|
50
64
|
|
51
65
|
def build_ipa_with_app_at_path
|
52
66
|
payload_path = @app_dir+"/Payload"
|
53
|
-
ipa_path = @app_dir+"/#{ipa_app_name(app_name)}"
|
67
|
+
ipa_path = @app_dir+"/#{ipa_app_name(app_name).delete('^A-Za-z0-9\.\_\-')}"
|
54
68
|
|
55
69
|
|
56
70
|
FileUtils.rm_rf payload_path
|
@@ -72,6 +86,94 @@ module AppSendr::Command
|
|
72
86
|
system(ditto_exec)
|
73
87
|
end
|
74
88
|
|
89
|
+
def upload_large_ipa(app_id, ipa, provisioning ,notify, notes, bundle_id, icon)
|
90
|
+
resp = appsendr.upload(app_id,ipa, provisioning,notify,notes,bundle_id,icon, true)
|
91
|
+
|
92
|
+
@upload_id = nil
|
93
|
+
@app_version_id = resp['message']['version']['id']
|
94
|
+
if @app_version_id
|
95
|
+
begin
|
96
|
+
split_file(ipa)
|
97
|
+
upload_as_multipart(app_id, @app_version_id, ipa)
|
98
|
+
rescue Exception => e
|
99
|
+
clean_split_files(File.dirname(ipa))
|
100
|
+
appsendr.abort_multipart(app_id, @app_version_id, ipa, @upload_id)
|
101
|
+
raise e
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
def upload_as_multipart(app_id, version_id, ipa)
|
108
|
+
|
109
|
+
ipa_name = File.basename(ipa)
|
110
|
+
ipa_dir = File.dirname(ipa)
|
111
|
+
|
112
|
+
@split_files = organize_split_files(ipa_dir)
|
113
|
+
|
114
|
+
resp = appsendr.initialize_multipart(app_id, version_id, ipa)
|
115
|
+
@upload_id = resp['message']['upload_id']
|
116
|
+
unless @upload_id
|
117
|
+
clean_split_files(ipa_dir)
|
118
|
+
raise "A error has occured with the upload"
|
119
|
+
end
|
120
|
+
|
121
|
+
parts = {}
|
122
|
+
pbar = ProgressBar.new("Uploading IPA", @split_files.length * 2)
|
123
|
+
|
124
|
+
@split_files.each_with_index{|file, i|
|
125
|
+
pbar.inc
|
126
|
+
|
127
|
+
resp = appsendr.upload_part(app_id, version_id, ipa, @upload_id, i+1, file)
|
128
|
+
etag = resp['message']['etag']
|
129
|
+
parts["#{i}"]={:part_num=>i+1, :e_tag=>etag}
|
130
|
+
|
131
|
+
pbar.inc
|
132
|
+
|
133
|
+
}
|
134
|
+
pbar.finish
|
135
|
+
|
136
|
+
appsendr.finish_multipart(app_id, version_id, ipa, @upload_id, parts)
|
137
|
+
|
138
|
+
clean_split_files(ipa_dir)
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
def clean_split_files(ipa_dir)
|
143
|
+
if File.directory? "#{ipa_dir}/appsendr_splits"
|
144
|
+
FileUtils.rm_r Dir.glob("#{ipa_dir}/appsendr_splits/*")
|
145
|
+
FileUtils.rmdir "#{ipa_dir}/appsendr_splits"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def organize_split_files(ipa_dir)
|
150
|
+
dir_contents = Dir["#{ipa_dir}/appsendr_splits/AppSendrSplit*"]
|
151
|
+
dir_contents.sort! { |a,b| a <=> b }
|
152
|
+
unless dir_contents.length > 1
|
153
|
+
|
154
|
+
clean_split_files(ipa_dir)
|
155
|
+
raise "A error has occured with the upload"
|
156
|
+
|
157
|
+
end
|
158
|
+
return dir_contents
|
159
|
+
end
|
160
|
+
|
161
|
+
def split_file(file_path)
|
162
|
+
return unless file_path
|
163
|
+
file_dir = File.dirname(file_path)
|
164
|
+
|
165
|
+
file_path = file_path.cl_escape
|
166
|
+
clean_split_files(file_dir)
|
167
|
+
|
168
|
+
file_dir << "/appsendr_splits"
|
169
|
+
|
170
|
+
FileUtils.mkdir file_dir
|
171
|
+
|
172
|
+
name = File.basename(file_path)
|
173
|
+
`split -b 5mb #{file_path} AppSendrSplit`
|
174
|
+
|
175
|
+
FileUtils.mv Dir.glob("AppSendrSplit*"), file_dir
|
176
|
+
end
|
75
177
|
|
76
178
|
|
77
179
|
#povisioning
|
@@ -142,20 +244,34 @@ module AppSendr::Command
|
|
142
244
|
if icon_files.nil? or icon_files.count == 0
|
143
245
|
icon_file = info['CFBundleIconFile']
|
144
246
|
else
|
145
|
-
|
146
|
-
if large_icon.nil?
|
147
|
-
large_icon = icon_files.first
|
148
|
-
end
|
149
|
-
icon_file = large_icon
|
247
|
+
icon_file = icon_files.grep(/@2x/i)
|
150
248
|
end
|
249
|
+
|
151
250
|
if icon_file and !icon_file.empty?
|
152
251
|
all_dir_contents = Dir["**/*"]
|
153
252
|
all_dir_contents = all_dir_contents - all_dir_contents.grep(/^build/)
|
154
|
-
|
155
253
|
icon = all_dir_contents.grep(%r{#{icon_file}}).flatten.first
|
156
254
|
if icon
|
157
255
|
icon_path = Dir.pwd+"/#{icon}"
|
158
256
|
end
|
257
|
+
elsif icon_files
|
258
|
+
|
259
|
+
all_dir_contents = Dir["**/*"]
|
260
|
+
all_dir_contents = all_dir_contents - all_dir_contents.grep(/^build/)
|
261
|
+
icon = all_dir_contents.grep(%r{#{icon_files.first}}).flatten.first
|
262
|
+
icon_dir = icon.sub(icon_files.first,"");
|
263
|
+
|
264
|
+
icon_full_path = Dir.pwd+"/#{icon_dir}"
|
265
|
+
biggest_icon_size = 0
|
266
|
+
biggest_icon = ""
|
267
|
+
for icon_file in icon_files
|
268
|
+
size = File.size(icon_full_path+icon_file)
|
269
|
+
if size > biggest_icon_size
|
270
|
+
biggest_icon = icon_full_path+icon_file
|
271
|
+
end
|
272
|
+
end
|
273
|
+
icon_path = biggest_icon
|
274
|
+
|
159
275
|
end
|
160
276
|
return icon_path
|
161
277
|
end
|
@@ -183,8 +299,12 @@ module AppSendr::Command
|
|
183
299
|
@app_dir = path_to_app_dir
|
184
300
|
end
|
185
301
|
return @app_name if @app_name
|
186
|
-
|
187
|
-
|
302
|
+
if File.directory? @app_dir
|
303
|
+
@app_name = Dir.entries(@app_dir).grep(/.+\.app$/).first
|
304
|
+
@app_name
|
305
|
+
else
|
306
|
+
error "#{@app_dir} does not exisit"
|
307
|
+
end
|
188
308
|
end
|
189
309
|
|
190
310
|
def ipa_app_name(app_name)
|
@@ -10,7 +10,7 @@ module AppSendr::Command
|
|
10
10
|
|
11
11
|
testers = appsendr.collaborators(read_app_id)
|
12
12
|
if testers["message"].size > 0
|
13
|
-
|
13
|
+
message "Your collaborators"
|
14
14
|
i = 0
|
15
15
|
display testers["message"].map {|app, id|
|
16
16
|
"#{i+=1}. #{app['name']} - #{app['email']}"
|
@@ -20,5 +20,33 @@ module AppSendr::Command
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
23
|
+
|
24
|
+
|
25
|
+
def add
|
26
|
+
|
27
|
+
if require_project(2,"add collaborators","an email", true)
|
28
|
+
email = args.shift.strip
|
29
|
+
|
30
|
+
begin
|
31
|
+
response = appsendr.add_collaborator(read_app_id,email)
|
32
|
+
rescue RestClient::RequestFailed => e
|
33
|
+
message "Errors"
|
34
|
+
response = JSON.parse(e.http_body)
|
35
|
+
response['message'].each{|err|
|
36
|
+
display err.join(" ")
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def remove
|
44
|
+
if require_project(1,"remove testers","an email")
|
45
|
+
entered_email = args.shift.strip
|
46
|
+
|
47
|
+
appsendr.remove_collaborator(read_app_id,entered_email)
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
23
51
|
end
|
24
52
|
end
|
@@ -11,20 +11,31 @@ module AppSendr::Command
|
|
11
11
|
# opts.parse!(args) rescue return false
|
12
12
|
#
|
13
13
|
#
|
14
|
+
notify = option_exists?('--notify', false)
|
14
15
|
|
15
16
|
@configuration = load_configuration
|
16
17
|
if require_project(1,"deploy","your active configuration name",true)
|
18
|
+
|
17
19
|
@app_dir = path_to_app_dir
|
18
20
|
@app_path = @app_dir+"/#{app_name}"
|
19
21
|
if @app_name
|
22
|
+
|
20
23
|
@notes = ask_for_notes
|
24
|
+
message "Deploying #{@app_name}"
|
25
|
+
|
26
|
+
message "Building IPA File"
|
21
27
|
|
22
28
|
@ipa_path = build_ipa_with_app_at_path
|
23
29
|
info = app_info
|
24
30
|
bundle_identifier ||= info['CFBundleIdentifier']
|
25
31
|
icon_path = icon_path(info)
|
26
|
-
|
27
|
-
|
32
|
+
if is_file_to_large?(@ipa_path)
|
33
|
+
upload_large_ipa(read_app_id,@ipa_path, profile_path,notify,@notes,bundle_identifier,icon_path)
|
34
|
+
else
|
35
|
+
appsendr.upload(read_app_id,@ipa_path, profile_path,notify,@notes,bundle_identifier,icon_path)
|
36
|
+
message "App deployed"
|
37
|
+
|
38
|
+
end
|
28
39
|
FileUtils.rm_rf @ipa_path
|
29
40
|
else
|
30
41
|
error "No .app file was built for the configuration \"#{@configuration}\". Compile your app or use the \"build\" command."
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module AppSendr::Command
|
2
|
+
class Groups < Base
|
3
|
+
def index #output testers
|
4
|
+
if in_project_dir?
|
5
|
+
|
6
|
+
groups = appsendr.groups(read_app_id)
|
7
|
+
if groups["message"].size > 0
|
8
|
+
message "Your groups"
|
9
|
+
i = 0
|
10
|
+
display groups["message"].map {|app, id|
|
11
|
+
"#{i+=1}. #{app['name'].ljust(35)}"
|
12
|
+
}.join("\n")
|
13
|
+
else
|
14
|
+
display "You have no groups."
|
15
|
+
end
|
16
|
+
else
|
17
|
+
error("You are not in a project directory")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def add
|
22
|
+
if in_project_dir?
|
23
|
+
name = args.join(" ").strip
|
24
|
+
appsendr.add_group(read_app_id,name)
|
25
|
+
message "Group added"
|
26
|
+
else
|
27
|
+
error("You are not in a project directory")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def remove
|
32
|
+
if in_project_dir?
|
33
|
+
name = args.join(" ").strip
|
34
|
+
appsendr.remove_group(read_app_id,name)
|
35
|
+
message "Removed group"
|
36
|
+
else
|
37
|
+
error("You are not in a project directory")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_tester #<group> #<email>
|
42
|
+
|
43
|
+
if in_project_dir?
|
44
|
+
email = args.shift.strip
|
45
|
+
name = args.join(" ").strip
|
46
|
+
appsendr.add_group_tester(read_app_id,name, email)
|
47
|
+
message "Added tester to group"
|
48
|
+
else
|
49
|
+
error("You are not in a project directory")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
def remove_tester #<group> #<email>
|
53
|
+
if in_project_dir?
|
54
|
+
email = args.shift.strip
|
55
|
+
name = args.join(" ").strip
|
56
|
+
appsendr.remove_group_tester(read_app_id,name, email)
|
57
|
+
message "Added tester to group"
|
58
|
+
else
|
59
|
+
error("You are not in a project directory")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -49,12 +49,19 @@ module AppSendr::Command
|
|
49
49
|
group.command 'testers:remove <email> ', 'remove a tester'
|
50
50
|
group.command 'testers:clear', 'remove all testers'
|
51
51
|
group.command 'testers:notify <group>', 'notify testers about the latest build. group is optional.'
|
52
|
-
group.
|
53
|
-
|
52
|
+
group.command 'testers:devices', 'devices of your testers'
|
53
|
+
|
54
|
+
# group.space
|
55
|
+
# group.command 'groups', 'list groups'
|
56
|
+
# group.command 'groups:add <name>', 'add group'
|
57
|
+
# group.command 'groups:remove <name>', 'remove group'
|
58
|
+
# group.command 'groups:add_tester <email> <group name>', 'add tester to group'
|
59
|
+
# group.command 'groups:remove_tester <email> <group name>', 'remove tester from group'
|
60
|
+
|
54
61
|
group.space
|
55
62
|
group.command 'collaborators', 'list collaborators'
|
56
63
|
group.command 'collaborators:add <email>', 'add collaborators'
|
57
|
-
group.command 'collaborators:remove <email>','
|
64
|
+
group.command 'collaborators:remove <email>','remove collaborators'
|
58
65
|
end
|
59
66
|
|
60
67
|
end
|