appsendr 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Manifest CHANGED
@@ -1,6 +1,7 @@
1
1
  Manifest
2
2
  README.rdoc
3
3
  Rakefile
4
+ appsendr.gemspec
4
5
  bin/appsendr
5
6
  lib/appsendr.rb
6
7
  lib/appsendr/binary_plist.rb
@@ -12,9 +13,12 @@ lib/appsendr/commands/base.rb
12
13
  lib/appsendr/commands/build.rb
13
14
  lib/appsendr/commands/collaborators.rb
14
15
  lib/appsendr/commands/deploy.rb
16
+ lib/appsendr/commands/groups.rb
15
17
  lib/appsendr/commands/help.rb
18
+ lib/appsendr/commands/portal.rb
16
19
  lib/appsendr/commands/testers.rb
17
20
  lib/appsendr/commands/version.rb
18
21
  lib/appsendr/constants.rb
19
22
  lib/appsendr/helpers.rb
23
+ lib/appsendr/progressbar.rb
20
24
  terms
data/Rakefile CHANGED
@@ -7,10 +7,10 @@ Echoe.new('appsendr', AppSendr::VERSION) do |p|
7
7
  p.description = "A gem that will build and distribute an iphone/ipad app to the web for remote install"
8
8
  p.url = "http://www.appsendr.com/gem"
9
9
  p.author = "AppSendr"
10
- p.email = "nolanbrown@gmail.com"
10
+ p.email = "nolan@appsendr.com"
11
11
  p.ignore_pattern = ["tmp/*", "script/*"]
12
12
  p.development_dependencies = []
13
- p.runtime_dependencies = ["rest-client >=1.4.0", "rubyzip", "json_pure >=1.2.0", "aws-s3"]
13
+ p.runtime_dependencies = ["rest-client >=1.4.0", "rubyzip", "json_pure >=1.2.0"]
14
14
  p.has_rdoc = true
15
15
 
16
16
  end
data/appsendr.gemspec CHANGED
@@ -2,17 +2,17 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{appsendr}
5
- s.version = "0.0.3"
5
+ s.version = "0.0.5"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["AppSendr"]
9
- s.date = %q{2010-12-27}
9
+ s.date = %q{2011-01-23}
10
10
  s.default_executable = %q{appsendr}
11
11
  s.description = %q{A gem that will build and distribute an iphone/ipad app to the web for remote install}
12
- s.email = %q{nolanbrown@gmail.com}
12
+ s.email = %q{nolan@appsendr.com}
13
13
  s.executables = ["appsendr"]
14
- s.extra_rdoc_files = ["README.rdoc", "bin/appsendr", "lib/appsendr.rb", "lib/appsendr/binary_plist.rb", "lib/appsendr/client.rb", "lib/appsendr/command.rb", "lib/appsendr/commands/app.rb", "lib/appsendr/commands/auth.rb", "lib/appsendr/commands/base.rb", "lib/appsendr/commands/build.rb", "lib/appsendr/commands/collaborators.rb", "lib/appsendr/commands/deploy.rb", "lib/appsendr/commands/help.rb", "lib/appsendr/commands/testers.rb", "lib/appsendr/commands/version.rb", "lib/appsendr/constants.rb", "lib/appsendr/helpers.rb"]
15
- s.files = ["Manifest", "README.rdoc", "Rakefile", "bin/appsendr", "lib/appsendr.rb", "lib/appsendr/binary_plist.rb", "lib/appsendr/client.rb", "lib/appsendr/command.rb", "lib/appsendr/commands/app.rb", "lib/appsendr/commands/auth.rb", "lib/appsendr/commands/base.rb", "lib/appsendr/commands/build.rb", "lib/appsendr/commands/collaborators.rb", "lib/appsendr/commands/deploy.rb", "lib/appsendr/commands/help.rb", "lib/appsendr/commands/testers.rb", "lib/appsendr/commands/version.rb", "lib/appsendr/constants.rb", "lib/appsendr/helpers.rb", "terms", "appsendr.gemspec"]
14
+ s.extra_rdoc_files = ["README.rdoc", "bin/appsendr", "lib/appsendr.rb", "lib/appsendr/binary_plist.rb", "lib/appsendr/client.rb", "lib/appsendr/command.rb", "lib/appsendr/commands/app.rb", "lib/appsendr/commands/auth.rb", "lib/appsendr/commands/base.rb", "lib/appsendr/commands/build.rb", "lib/appsendr/commands/collaborators.rb", "lib/appsendr/commands/deploy.rb", "lib/appsendr/commands/groups.rb", "lib/appsendr/commands/help.rb", "lib/appsendr/commands/portal.rb", "lib/appsendr/commands/testers.rb", "lib/appsendr/commands/version.rb", "lib/appsendr/constants.rb", "lib/appsendr/helpers.rb", "lib/appsendr/progressbar.rb"]
15
+ s.files = ["Manifest", "README.rdoc", "Rakefile", "bin/appsendr", "lib/appsendr.rb", "lib/appsendr/binary_plist.rb", "lib/appsendr/client.rb", "lib/appsendr/command.rb", "lib/appsendr/commands/app.rb", "lib/appsendr/commands/auth.rb", "lib/appsendr/commands/base.rb", "lib/appsendr/commands/build.rb", "lib/appsendr/commands/collaborators.rb", "lib/appsendr/commands/deploy.rb", "lib/appsendr/commands/groups.rb", "lib/appsendr/commands/help.rb", "lib/appsendr/commands/portal.rb", "lib/appsendr/commands/testers.rb", "lib/appsendr/commands/version.rb", "lib/appsendr/constants.rb", "lib/appsendr/helpers.rb", "lib/appsendr/progressbar.rb", "terms", "appsendr.gemspec"]
16
16
  s.homepage = %q{http://www.appsendr.com/gem}
17
17
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Appsendr", "--main", "README.rdoc"]
18
18
  s.require_paths = ["lib"]
@@ -28,17 +28,14 @@ Gem::Specification.new do |s|
28
28
  s.add_runtime_dependency(%q<rest-client>, [">= 1.4.0"])
29
29
  s.add_runtime_dependency(%q<rubyzip>, [">= 0"])
30
30
  s.add_runtime_dependency(%q<json_pure>, [">= 1.2.0"])
31
- s.add_runtime_dependency(%q<aws-s3>, [">= 0"])
32
31
  else
33
32
  s.add_dependency(%q<rest-client>, [">= 1.4.0"])
34
33
  s.add_dependency(%q<rubyzip>, [">= 0"])
35
34
  s.add_dependency(%q<json_pure>, [">= 1.2.0"])
36
- s.add_dependency(%q<aws-s3>, [">= 0"])
37
35
  end
38
36
  else
39
37
  s.add_dependency(%q<rest-client>, [">= 1.4.0"])
40
38
  s.add_dependency(%q<rubyzip>, [">= 0"])
41
39
  s.add_dependency(%q<json_pure>, [">= 1.2.0"])
42
- s.add_dependency(%q<aws-s3>, [">= 0"])
43
40
  end
44
41
  end
@@ -4,7 +4,7 @@ require 'uri'
4
4
  require 'time'
5
5
  require 'appsendr/constants'
6
6
  require 'json/pure' unless {}.respond_to?(:to_json)
7
- require 'aws/s3'
7
+
8
8
  # A Ruby class to call the AppSendr REST API.
9
9
  #
10
10
  # Example:
@@ -64,6 +64,17 @@ class AppSendr::Client
64
64
  post('/api/app/create.json', {:name=>name})
65
65
  end
66
66
 
67
+ def devices(app_id,plist=true)
68
+ format = "json"
69
+ format = "plist" if plist
70
+
71
+ if app_id
72
+ get("/api/tester/devices.#{format}", {:app_id=>app_id})
73
+ else
74
+ get("/api/tester/devices.#{format}")
75
+ end
76
+ end
77
+
67
78
  def add_tester(app_id,email,name,udid=nil)
68
79
  post('/api/tester/create.json',{:email=>email, :name=>name, :app_id=>app_id.to_s});
69
80
  end
@@ -88,6 +99,16 @@ class AppSendr::Client
88
99
  get('/api/app/groups/'+app_id.to_s+'.json')
89
100
  end
90
101
 
102
+
103
+ def add_group_tester(app_id,name, email)
104
+ post('/api/group/add_tester.json',{:name=>name,:app_id=>app_id.to_s, :email=>email});
105
+ end
106
+
107
+ def remove_group_tester(app_id, name, email)
108
+ post('/api/group/remove_tester.json',{:name=>name,:app_id=>app_id.to_s, :email=>email});
109
+ end
110
+
111
+
91
112
  ### add_collaborator
92
113
 
93
114
  def add_collaborator(app_id,emaill)
@@ -105,11 +126,11 @@ class AppSendr::Client
105
126
  def testers(app_id)
106
127
  get('/api/app/testers/'+app_id.to_s+'.json')
107
128
  end
108
- def notify(app_id)
109
- get('/api/app/notify/'+app_id.to_s+'.json')
129
+ def notify(app_id,group=nil)
130
+ post('/api/app/notify/'+app_id.to_s+'.json',{:group=>group})
110
131
  end
111
132
 
112
- def upload(app_id, ipa,provisioning,notify, notes, bundle_id, icon)
133
+ def upload(app_id, ipa,provisioning, notify, notes, bundle_id, icon, later=false)
113
134
  params = {
114
135
  :provisioning_profile => File.new(provisioning, 'rb'),
115
136
  :notes=>notes,
@@ -119,41 +140,82 @@ class AppSendr::Client
119
140
  :app_id => app_id.to_s
120
141
  # :ipa=>
121
142
  }
122
-
123
143
  if icon
124
144
  params[:icon] = File.new(icon,'rb')
125
145
  end
126
- if(is_file_to_large?(ipa))
127
- puts "IPA is too large to upload."
128
- else
129
- params[:ipa] = File.new(ipa, 'rb')
130
-
131
- post('/api/version/create/', {:version=>params})
132
- end
146
+
147
+ if later
148
+ params[:upload_later] = File.basename(ipa)
149
+
150
+ else
151
+ params[:ipa] = File.new(ipa, 'rb')
152
+
153
+ end
154
+
155
+ post('/api/version/create.json', {:version=>params})
133
156
  end
134
157
 
135
- protected
136
- def is_file_to_large?(file)
137
- in_mb = size_of_file(file).to_f
138
- if in_mb > 10
139
- return true
140
- else
141
- return false
142
- end
143
-
158
+ def initialize_multipart(app_id, version_id, ipa)
159
+ ipa_name = File.basename(ipa)
160
+
161
+ params = {}
162
+ params[:ipa_path] = upload_path(app_id,version_id,ipa_name)
163
+ params[:ipa_name] = ipa_name
164
+ params[:id] = version_id
165
+
166
+ post('/api/version/multipart_init.json', {:version=>params})
144
167
  end
168
+
169
+ def upload_part(app_id, version_id, ipa, upload_id, part_number, chunk)
170
+ ipa_name = File.basename(ipa)
171
+ ipa_size = File.size(ipa)
172
+
173
+ params = {}
174
+ params[:ipa_chunk] = File.new(chunk,'rb')
175
+ params[:ipa_size] = ipa_size
176
+ params[:ipa_path] = upload_path(app_id,version_id,ipa_name)
177
+ params[:upload_id] = upload_id
178
+ params[:part_number] = part_number
179
+ params[:id] = version_id
145
180
 
146
- def size_of_file(file)
147
- size = File.size(file)
148
- mb = 1024.0 * 1024.0
149
- in_mb = size / mb
150
-
181
+ retryable( :tries => 5 ) do
182
+ resp = post('/api/version/multipart_upload_part.json', {:version=>params})
183
+ return resp
184
+ end
151
185
  end
186
+
187
+ def finish_multipart(app_id, version_id, ipa, upload_id, parts)
188
+ ipa_name = File.basename(ipa)
189
+ ipa_size = File.size(ipa)
152
190
 
191
+ params = {}
192
+ params[:ipa_size] = ipa_size
193
+ params[:ipa_path] = upload_path(app_id,version_id,ipa_name)
194
+ params[:upload_id] = upload_id
195
+ params[:parts] = parts
196
+ params[:id] = version_id
153
197
 
154
- def upload_to_s3_directly
155
- @s3_url = "http://appsendr.s3.amazonaws.com/"
156
-
198
+ post('/api/version/multipart_finished.json', {:version=>params})
199
+
200
+
201
+ end
202
+
203
+ def abort_multipart(app_id, version_id, ipa, upload_id)
204
+ params = { :version=> {
205
+ :ipa_path=>upload_path(app_id,version_id,File.basename(ipa)),
206
+ :upload_id=>upload_id,
207
+ :id=>version_id
208
+ }
209
+ }
210
+ post('/api/version/abort_multipart.json',params)
211
+
212
+ end
213
+
214
+ protected
215
+
216
+
217
+ def upload_path(app_id,version_id,ipa_name)
218
+ "app/#{app_id}/#{version_id}/ipa/#{ipa_name}"
157
219
  end
158
220
 
159
221
  def api_params(params={})
@@ -161,6 +223,20 @@ class AppSendr::Client
161
223
 
162
224
  end
163
225
 
226
+ def retryable(options = {}, &block)
227
+ opts = { :tries => 1, :on => Exception }.merge(options)
228
+
229
+ retry_exception, retries = opts[:on], opts[:tries]
230
+
231
+ begin
232
+ return yield
233
+ rescue retry_exception
234
+ retry if (retries -= 1) > 0
235
+ end
236
+
237
+ yield
238
+ end
239
+
164
240
  def get(uri,params={})
165
241
  params[:api_key] ||= @api_key
166
242
  resp = RestClient.get @resource.url+uri, {:params=>params}
@@ -1,6 +1,7 @@
1
1
  require 'appsendr/helpers'
2
2
  require 'appsendr/binary_plist'
3
3
  require 'appsendr/commands/base'
4
+ require 'appsendr/progressbar'
4
5
 
5
6
  Dir["#{File.dirname(__FILE__)}/commands/*.rb"].each { |c| require c }
6
7
 
@@ -27,13 +28,23 @@ module AppSendr
27
28
  error "Authentication failure"
28
29
  end
29
30
  rescue RestClient::ResourceNotFound
30
- error "Resouce not found."
31
- rescue RestClient::RequestFailed
32
- error "Something went wrong with the server."
31
+ error "Record not found. Are you allowed to access this record?"
32
+ rescue RestClient::RequestFailed => e
33
+ begin
34
+ response = JSON.parse(e.http_body)
35
+ display "=== Errors"
36
+ response['message'].each{|err|
37
+ display err.join(" ")
38
+ }
39
+ rescue
40
+ error "Something went wrong with the server."
41
+ end
33
42
  rescue CommandFailed => e
34
43
  error e.message
35
44
  rescue Interrupt => e
36
45
  error "\n[canceled]"
46
+ rescue Exception => e
47
+ error e
37
48
  end
38
49
  end
39
50
 
@@ -7,7 +7,7 @@ module AppSendr::Command
7
7
  def list
8
8
  list = appsendr.list
9
9
  if list["message"].size > 0
10
- display "=== Your apps"
10
+ message "Your apps"
11
11
  i = 0
12
12
  display list["message"].map {|app, id|
13
13
  "#{i+=1}. #{app['name'].ljust(35)}"
@@ -23,15 +23,42 @@ module AppSendr::Command
23
23
  # password = extract_option('--password')
24
24
  # display password
25
25
  #
26
+ name = args.join(" ").strip
26
27
 
27
- if require_in_project_and_no_droppr(1,"an app name","a name to create an app on appsendr",true)
28
- name = args.join(" ").strip
29
- resp = appsendr.create(name)
30
- make_appsendr_dir if resp['message']
31
- @app = [resp['message']['id'],resp['message']['name']]
32
- write_app
33
- display "Your app has been created."
34
-
28
+ if require_project(1,"an app name","a name to create an app on appsendr",true)
29
+ if has_project_droppr?
30
+ list = appsendr.list
31
+ if list["message"].size > 0
32
+ list["message"].each{|app|
33
+ if app['name'] == name
34
+ remove_appsendr_dir
35
+ make_appsendr_dir
36
+
37
+ @app = [ app['id'], app['name']]
38
+ write_app
39
+ display "Your app has been linked."
40
+ return
41
+ end
42
+ }
43
+
44
+ resp = appsendr.create(name)
45
+ remove_appsendr_dir
46
+ make_appsendr_dir if resp['message']
47
+ @app = [resp['message']['id'],resp['message']['name']]
48
+ write_app
49
+ display "Your app has been created."
50
+
51
+ else
52
+ error "This app is linked to another account's app"
53
+ end
54
+ else
55
+ resp = appsendr.create(name)
56
+ make_appsendr_dir if resp['message']
57
+ @app = [resp['message']['id'],resp['message']['name']]
58
+ write_app
59
+ display "Your app has been created."
60
+ end
61
+
35
62
  end
36
63
  end
37
64
 
@@ -40,7 +67,7 @@ module AppSendr::Command
40
67
 
41
68
  resp = appsendr.current_version(get_app_id)
42
69
  if resp["message"].size > 0
43
- display "=== Your last install url is:"
70
+ message "Your last install url is:"
44
71
  url = resp["message"][0]['install_url']
45
72
  display url
46
73
  do_copy = option_exists?('--copy', false)
@@ -83,7 +110,7 @@ module AppSendr::Command
83
110
  lines = []
84
111
  list = appsendr.list
85
112
  if list["message"].size > 0
86
- display "=== Your apps"
113
+ message "Your apps"
87
114
  i = 0
88
115
  list["message"].each{|app|
89
116
  apps.push({"name"=>app['name'], "id"=>app['id']})
@@ -100,32 +127,13 @@ module AppSendr::Command
100
127
  display "You have no apps."
101
128
  end
102
129
  end
103
-
104
- def groups
105
- if in_project_dir?
106
-
107
- groups = appsendr.groups(get_app_id)
108
- if groups["message"].size > 0
109
- display "=== Your groups"
110
- i = 0
111
- display groups["message"].map {|app, id|
112
- "#{i+=1}. #{app['name'].ljust(35)}"
113
- }.join("\n")
114
- else
115
- display "You have no groups."
116
- end
117
- else
118
- error("You are not in a project directory")
119
- end
120
- end
121
-
122
-
130
+
123
131
  def versions
124
132
  if in_project_dir?
125
133
 
126
134
  groups = appsendr.versions(get_app_id)
127
135
  if groups["message"].size > 0
128
- display "=== Your versions"
136
+ message "Your versions"
129
137
  i = 0
130
138
  display groups["message"].map {|app, id|
131
139
  "#{i+=1}. #{app['notes']} #{app['install_url']}"
@@ -189,7 +197,12 @@ module AppSendr::Command
189
197
  # end
190
198
 
191
199
  protected
192
-
200
+ def remove_appsendr_dir
201
+ if in_project_dir?
202
+ FileUtils.rm_r(Dir.pwd+"/"+AppSendr::PROJECT_DIR)
203
+ end
204
+ end
205
+
193
206
  def make_appsendr_dir
194
207
  if in_project_dir?
195
208
  FileUtils.mkdir_p(Dir.pwd+"/"+AppSendr::PROJECT_DIR)
@@ -22,7 +22,9 @@ module AppSendr::Command
22
22
  end
23
23
 
24
24
  def host
25
- ENV['APPDROPPR_HOST'] || 'appsendr.com' ##'appsendr.heroku.com' #
25
+ ENV['APPDROPPR_HOST'] || 'appsendr.com'
26
+ #ENV['APPDROPPR_HOST'] || '0.0.0.0:3000'
27
+
26
28
  end
27
29
 
28
30
  def reauthorize
@@ -73,33 +75,15 @@ module AppSendr::Command
73
75
  def ask_for_credentials
74
76
  puts "Enter your AppSendr credentials."
75
77
 
76
- print "Username: "
78
+ print "Email: "
77
79
  user = ask
78
80
 
79
81
  print "Password: "
80
- password = running_on_windows? ? ask_for_password_on_windows : ask_for_password
82
+ password = ask_for_password
81
83
 
82
84
  [ user, password ]
83
85
  end
84
86
 
85
- def ask_for_password_on_windows
86
- require "Win32API"
87
- char = nil
88
- password = ''
89
-
90
- while char = Win32API.new("crtdll", "_getch", [ ], "L").Call do
91
- break if char == 10 || char == 13 # received carriage return or newline
92
- if char == 127 || char == 8 # backspace and delete
93
- password.slice!(-1, 1)
94
- else
95
- # windows might throw a -1 at us so make sure to handle RangeError
96
- (password << char.chr) rescue RangeError
97
- end
98
- end
99
- puts
100
- return password
101
- end
102
-
103
87
  def ask_for_password
104
88
  echo_off
105
89
  password = ask
@@ -51,6 +51,7 @@ module AppSendr::Command
51
51
  def option_exists?(options, default=true)
52
52
  values = options.is_a?(Array) ? options : [options]
53
53
  return false unless opt_index = args.select { |a| values.include? a }.first
54
+ args.delete(opt_index)
54
55
  return true
55
56
  end
56
57