cupertino 0.3.3 → 0.4.0

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/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cupertino (0.3.3)
4
+ cupertino (0.4.0)
5
5
  commander (~> 4.1.2)
6
6
  mechanize (~> 2.5.1)
7
7
  netrc (~> 0.7.2)
data/README.md CHANGED
@@ -51,6 +51,12 @@ $ ios profiles:list
51
51
  +----------------------------------+--------------+---------+
52
52
  ```
53
53
 
54
+ ```sh
55
+ $ ios profiles:manage:devices
56
+ ```
57
+
58
+ _Opens an editor with a list of devices, each of which can be commented or uncommented to turn them off or on for that provisioning profile._
59
+
54
60
  ### App IDs
55
61
 
56
62
  ```sh
@@ -92,12 +98,12 @@ _Crossed out commands are not yet implemented_
92
98
  - ~~`devices:remove`~~
93
99
 
94
100
  - `profiles:list`
101
+ - `profiles:manage:devices`
95
102
  - ~~`profiles:add`~~
96
103
  - ~~`profiles:edit`~~
97
104
 
98
105
  - `certificates:list [development|distribution]`
99
- - ~~`certificates:add [development|distribution]`~~
100
- - ~~`certificates:download CERTIFICATE_NAME`~~
106
+ - `certificates:download CERTIFICATE_NAME`
101
107
  - ~~`certificates:revoke CERTIFICATE_NAME`~~
102
108
 
103
109
  - `app_ids:list`
data/bin/ios CHANGED
@@ -5,8 +5,6 @@ require 'terminal-table'
5
5
  require 'term/ansicolor'
6
6
  require 'netrc'
7
7
 
8
- $:.push File.expand_path("../../lib", __FILE__)
9
-
10
8
  require 'cupertino'
11
9
 
12
10
  HighLine.track_eof = false # Fix for built-in Ruby
@@ -10,13 +10,17 @@ module Cupertino
10
10
  super
11
11
  self.user_agent_alias = 'Mac Safari'
12
12
 
13
- @username, @password = Netrc.read[::Cupertino::HOSTNAME]
13
+ @username, @password = Netrc.read[Cupertino::HOSTNAME]
14
14
  end
15
15
 
16
16
  def get(uri, parameters = [], referer = nil, headers = {})
17
+ uri = ::File.join("https://#{Cupertino::HOSTNAME}", uri) unless /^https?/ === uri
18
+
17
19
  3.times do
18
20
  super(uri, parameters, referer, headers)
19
21
 
22
+ return page unless page.respond_to?(:title)
23
+
20
24
  case page.title
21
25
  when %r{Sign in with your Apple ID}
22
26
  login! and redo
@@ -46,6 +50,7 @@ module Cupertino
46
50
  page.parser.xpath('//div[@class="nt_multi"]/table/tbody/tr').each do |row|
47
51
  certificate = Certificate.new
48
52
  certificate.name = row.at_xpath('td[@class="name"]//p/text()').to_s.strip rescue nil
53
+ certificate.type = type
49
54
  certificate.provisioning_profiles = row.at_xpath('td[@class="profiles"]/text()').to_s.strip.split(/\n+/) rescue []
50
55
  certificate.expiration_date = row.at_xpath('td[@class="date"]/text()').to_s.strip rescue nil
51
56
  certificate.status = row.at_xpath('td[@class="status"]/text()').to_s.strip rescue nil
@@ -54,6 +59,25 @@ module Cupertino
54
59
  certificates
55
60
  end
56
61
 
62
+ def download_certificate(certificate)
63
+ list_certificates(certificate.type)
64
+
65
+ page.parser.xpath('//div[@class="nt_multi"]/table/tbody/tr').each do |row|
66
+ name = row.at_xpath('td[@class="name"]//p/text()').to_s.strip rescue nil
67
+
68
+ if name == certificate.name
69
+ download_url = row.at_xpath('td[@class="last"]/a')['href'].to_s.strip rescue nil
70
+
71
+ self.pluggable_parser.default = Mechanize::Download
72
+ download = get(download_url)
73
+ download.save
74
+ return download.filename
75
+ end
76
+ end
77
+
78
+ return nil
79
+ end
80
+
57
81
  def list_devices
58
82
  get("https://developer.apple.com/ios/manage/devices/index.action")
59
83
 
@@ -65,7 +89,6 @@ module Cupertino
65
89
  devices << device
66
90
  end
67
91
 
68
-
69
92
  if message = page.parser.at_xpath('//p[@class="devicesannounce"]/strong/text()').to_s.strip rescue nil
70
93
  number_of_devices_available = message.scan(/\d{1,3}/).first.to_i
71
94
  number_of_devices_available.times do
@@ -114,7 +137,8 @@ module Cupertino
114
137
  profiles = []
115
138
  page.parser.xpath('//fieldset[@id="fs-0"]/table/tbody/tr').each do |row|
116
139
  profile = ProvisioningProfile.new
117
- profile.name = row.at_xpath('td[@class="profile"]/text()').to_s.strip rescue nil
140
+ profile.name = row.at_xpath('td[@class="profile"]//text()').to_s.strip rescue nil
141
+ profile.type = type
118
142
  profile.app_id = row.at_xpath('td[@class="appid"]/text()').to_s.strip rescue nil
119
143
  profile.status = row.at_xpath('td[@class="statusXcode"]/text()').to_s.strip rescue nil
120
144
  profiles << profile
@@ -122,6 +146,63 @@ module Cupertino
122
146
  profiles
123
147
  end
124
148
 
149
+ def manage_devices_for_profile(profile)
150
+ raise ArgumentError unless block_given?
151
+
152
+ list_profiles(profile.type)
153
+
154
+ modify_url = nil
155
+ page.parser.xpath('//fieldset[@id="fs-0"]/table/tbody/tr').each do |row|
156
+ break if modify_url
157
+
158
+ name = row.at_xpath('td[@class="profile"]//text()').to_s.strip rescue nil
159
+
160
+ if name == profile.name
161
+ row.css('td.action a').each do |a|
162
+ if /edit\.action/ === a['href']
163
+ modify_url = a['href']
164
+ end
165
+ end
166
+ end
167
+ end
168
+
169
+ if modify_url
170
+ get(modify_url)
171
+
172
+ on, off = [], []
173
+ page.parser.css('.checkboxlist.last td').each do |td|
174
+ checkbox = td.at_xpath('input[@type="checkbox"]')
175
+
176
+ device = Device.new
177
+ device.name = td.at_xpath('label/text()').to_s.strip rescue nil
178
+ device.udid = checkbox['value'].to_s.strip rescue nil
179
+
180
+ if checkbox['checked']
181
+ on << device
182
+ else
183
+ off << device
184
+ end
185
+ end
186
+
187
+ devices = yield on, off
188
+
189
+ form = page.form_with(:name => 'save')
190
+ form.checkboxes_with(:name => "selectedDevices").each do |checkbox|
191
+ checkbox.check
192
+ if devices.detect{|device| device.udid == checkbox['value']}
193
+ checkbox.check
194
+ else
195
+ checkbox.uncheck
196
+ end
197
+ end
198
+
199
+ button = form.button_with(:name => 'submit')
200
+ form.click_button(button)
201
+ end
202
+
203
+ return nil
204
+ end
205
+
125
206
  def list_app_ids
126
207
  get("https://developer.apple.com/ios/manage/bundles/index.action")
127
208
 
@@ -159,8 +240,8 @@ module Cupertino
159
240
  team_option = team_list.option_with(:text => self.team)
160
241
  team_option.select
161
242
 
162
- btn = form.button_with(:name => 'action:saveTeamSelection!save')
163
- form.click_button(btn)
243
+ button = form.button_with(:name => 'action:saveTeamSelection!save')
244
+ form.click_button(button)
164
245
  end
165
246
  end
166
247
  end
@@ -29,3 +29,23 @@ command :'certificates:list' do |c|
29
29
  end
30
30
 
31
31
  alias_command :certificates, :'certificates:list'
32
+
33
+ command :'certificates:download' do |c|
34
+ c.syntax = 'ios certificates:download [development|distribution]'
35
+ c.summary = 'Downloads the Certificates'
36
+ c.description = ''
37
+
38
+ c.action do |args, options|
39
+ type = args.first.downcase.to_sym rescue nil
40
+ certificates = try{agent.list_certificates(type ||= :development)}
41
+
42
+ say_warning "No #{type} certificates found." and abort if certificates.empty?
43
+
44
+ certificate = choose "Select a certificate to download:", *certificates
45
+ if filename = agent.download_certificate(certificate)
46
+ say_ok "Successfully downloaded: '#{filename}'"
47
+ else
48
+ say_error "Could not download certificate"
49
+ end
50
+ end
51
+ end
@@ -29,3 +29,41 @@ command :'profiles:list' do |c|
29
29
  end
30
30
 
31
31
  alias_command :profiles, :'profiles:list'
32
+
33
+ command :'profiles:manage:devices' do |c|
34
+ c.syntax = 'ios profiles:manage:devices'
35
+ c.summary = 'Manage active devices for a development provisioning profile'
36
+ c.description = ''
37
+
38
+ c.action do |args, options|
39
+ type = args.first.downcase.to_sym rescue nil
40
+ profiles = try{agent.list_profiles(:development)}
41
+
42
+ say_warning "No #{type} provisioning profiles found." and abort if profiles.empty?
43
+
44
+ profile = choose "Select a provisioning profile to manage:", *profiles
45
+
46
+ agent.manage_devices_for_profile(profile) do |on, off|
47
+ lines = ["# Comment / Uncomment Devices to Turn Off / On for Provisioning Profile"]
48
+ lines += on.collect{|device| "#{device}"}
49
+ lines += off.collect{|device| "# #{device}"}
50
+ result = ask_editor lines.join("\n")
51
+
52
+ devices = []
53
+ result.split(/\n+/).each do |line|
54
+ next if /^\#/ === line
55
+ components = line.split(/\s+/)
56
+ device = Device.new
57
+ device.udid = components.pop
58
+ device.name = components.join(" ")
59
+ devices << device
60
+ end
61
+
62
+ devices
63
+ end
64
+
65
+ say_ok "Successfully managed devices"
66
+ end
67
+ end
68
+
69
+ alias_command :'profiles:manage', :'profiles:manage:devices'
@@ -1,11 +1,9 @@
1
1
  include Cupertino::ProvisioningPortal
2
2
  include Cupertino::ProvisioningPortal::Helpers
3
3
 
4
- $:.push File.expand_path('../', __FILE__)
5
-
6
- require 'commands/certificates'
7
- require 'commands/devices'
8
- require 'commands/profiles'
9
- require 'commands/app_ids'
10
- require 'commands/login'
11
- require 'commands/logout'
4
+ require 'cupertino/provisioning_portal/commands/certificates'
5
+ require 'cupertino/provisioning_portal/commands/devices'
6
+ require 'cupertino/provisioning_portal/commands/profiles'
7
+ require 'cupertino/provisioning_portal/commands/app_ids'
8
+ require 'cupertino/provisioning_portal/commands/login'
9
+ require 'cupertino/provisioning_portal/commands/logout'
@@ -1,18 +1,35 @@
1
1
  require 'mechanize'
2
2
 
3
3
  module Cupertino
4
- module ProvisioningPortal
5
- class Device < Struct.new(:name, :udid); end
6
- class Certificate < Struct.new(:name, :provisioning_profiles, :expiration_date, :status); end
7
- class AppID < Struct.new(:bundle_seed_id, :description, :development_properties, :distribution_properties); end
8
- class ProvisioningProfile < Struct.new(:name, :app_id, :status); end
9
-
4
+ module ProvisioningPortal
5
+ class Device < Struct.new(:name, :udid)
6
+ def to_s
7
+ "#{self.name} #{self.udid}"
8
+ end
9
+ end
10
+
11
+ class Certificate < Struct.new(:name, :type, :provisioning_profiles, :expiration_date, :status)
12
+ def to_s
13
+ "#{self.name}"
14
+ end
15
+ end
16
+
17
+ class AppID < Struct.new(:bundle_seed_id, :description, :development_properties, :distribution_properties)
18
+ def to_s
19
+ "#{self.bundle_seed_id}"
20
+ end
21
+ end
22
+
23
+ class ProvisioningProfile < Struct.new(:name, :type, :app_id, :status)
24
+ def to_s
25
+ "#{self.name}"
26
+ end
27
+ end
28
+
10
29
  class UnsuccessfulAuthenticationError < RuntimeError; end
11
30
  end
12
31
  end
13
32
 
14
- $:.push File.expand_path('../', __FILE__)
15
-
16
- require 'provisioning_portal/helpers'
17
- require 'provisioning_portal/agent'
18
- require 'provisioning_portal/commands'
33
+ require 'cupertino/provisioning_portal/helpers'
34
+ require 'cupertino/provisioning_portal/agent'
35
+ require 'cupertino/provisioning_portal/commands'
data/lib/cupertino.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Cupertino
2
- VERSION = '0.3.3'
2
+ VERSION = '0.4.0'
3
3
  HOSTNAME = "developer.apple.com"
4
4
  end
metadata CHANGED
@@ -1,143 +1,100 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: cupertino
3
- version: !ruby/object:Gem::Version
4
- hash: 21
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 3
9
- - 3
10
- version: 0.3.3
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Mattt Thompson
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2012-07-10 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- prerelease: false
22
- type: :development
23
- requirement: &id001 !ruby/object:Gem::Requirement
12
+ date: 2012-07-15 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &70144971248520 !ruby/object:Gem::Requirement
24
17
  none: false
25
- requirements:
18
+ requirements:
26
19
  - - ~>
27
- - !ruby/object:Gem::Version
28
- hash: 5
29
- segments:
30
- - 0
31
- - 6
32
- - 1
20
+ - !ruby/object:Gem::Version
33
21
  version: 0.6.1
34
- name: rspec
35
- version_requirements: *id001
36
- - !ruby/object:Gem::Dependency
37
- prerelease: false
38
22
  type: :development
39
- requirement: &id002 !ruby/object:Gem::Requirement
23
+ prerelease: false
24
+ version_requirements: *70144971248520
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &70144972093640 !ruby/object:Gem::Requirement
40
28
  none: false
41
- requirements:
29
+ requirements:
42
30
  - - ~>
43
- - !ruby/object:Gem::Version
44
- hash: 63
45
- segments:
46
- - 0
47
- - 9
48
- - 2
31
+ - !ruby/object:Gem::Version
49
32
  version: 0.9.2
50
- name: rake
51
- version_requirements: *id002
52
- - !ruby/object:Gem::Dependency
33
+ type: :development
53
34
  prerelease: false
54
- type: :runtime
55
- requirement: &id003 !ruby/object:Gem::Requirement
35
+ version_requirements: *70144972093640
36
+ - !ruby/object:Gem::Dependency
37
+ name: commander
38
+ requirement: &70144974129360 !ruby/object:Gem::Requirement
56
39
  none: false
57
- requirements:
40
+ requirements:
58
41
  - - ~>
59
- - !ruby/object:Gem::Version
60
- hash: 63
61
- segments:
62
- - 4
63
- - 1
64
- - 2
42
+ - !ruby/object:Gem::Version
65
43
  version: 4.1.2
66
- name: commander
67
- version_requirements: *id003
68
- - !ruby/object:Gem::Dependency
69
- prerelease: false
70
44
  type: :runtime
71
- requirement: &id004 !ruby/object:Gem::Requirement
45
+ prerelease: false
46
+ version_requirements: *70144974129360
47
+ - !ruby/object:Gem::Dependency
48
+ name: terminal-table
49
+ requirement: &70144974134820 !ruby/object:Gem::Requirement
72
50
  none: false
73
- requirements:
51
+ requirements:
74
52
  - - ~>
75
- - !ruby/object:Gem::Version
76
- hash: 13
77
- segments:
78
- - 1
79
- - 4
80
- - 5
53
+ - !ruby/object:Gem::Version
81
54
  version: 1.4.5
82
- name: terminal-table
83
- version_requirements: *id004
84
- - !ruby/object:Gem::Dependency
85
- prerelease: false
86
55
  type: :runtime
87
- requirement: &id005 !ruby/object:Gem::Requirement
56
+ prerelease: false
57
+ version_requirements: *70144974134820
58
+ - !ruby/object:Gem::Dependency
59
+ name: term-ansicolor
60
+ requirement: &70144975372120 !ruby/object:Gem::Requirement
88
61
  none: false
89
- requirements:
62
+ requirements:
90
63
  - - ~>
91
- - !ruby/object:Gem::Version
92
- hash: 25
93
- segments:
94
- - 1
95
- - 0
96
- - 7
64
+ - !ruby/object:Gem::Version
97
65
  version: 1.0.7
98
- name: term-ansicolor
99
- version_requirements: *id005
100
- - !ruby/object:Gem::Dependency
101
- prerelease: false
102
66
  type: :runtime
103
- requirement: &id006 !ruby/object:Gem::Requirement
67
+ prerelease: false
68
+ version_requirements: *70144975372120
69
+ - !ruby/object:Gem::Dependency
70
+ name: mechanize
71
+ requirement: &70144976016960 !ruby/object:Gem::Requirement
104
72
  none: false
105
- requirements:
73
+ requirements:
106
74
  - - ~>
107
- - !ruby/object:Gem::Version
108
- hash: 25
109
- segments:
110
- - 2
111
- - 5
112
- - 1
75
+ - !ruby/object:Gem::Version
113
76
  version: 2.5.1
114
- name: mechanize
115
- version_requirements: *id006
116
- - !ruby/object:Gem::Dependency
117
- prerelease: false
118
77
  type: :runtime
119
- requirement: &id007 !ruby/object:Gem::Requirement
78
+ prerelease: false
79
+ version_requirements: *70144976016960
80
+ - !ruby/object:Gem::Dependency
81
+ name: netrc
82
+ requirement: &70144976088360 !ruby/object:Gem::Requirement
120
83
  none: false
121
- requirements:
84
+ requirements:
122
85
  - - ~>
123
- - !ruby/object:Gem::Version
124
- hash: 7
125
- segments:
126
- - 0
127
- - 7
128
- - 2
86
+ - !ruby/object:Gem::Version
129
87
  version: 0.7.2
130
- name: netrc
131
- version_requirements: *id007
88
+ type: :runtime
89
+ prerelease: false
90
+ version_requirements: *70144976088360
132
91
  description: A command-line interface for the iOS Provisioning Portal
133
92
  email: m@mattt.me
134
- executables:
93
+ executables:
135
94
  - ios
136
95
  extensions: []
137
-
138
96
  extra_rdoc_files: []
139
-
140
- files:
97
+ files:
141
98
  - ./cupertino.gemspec
142
99
  - ./Gemfile
143
100
  - ./Gemfile.lock
@@ -158,36 +115,32 @@ files:
158
115
  - bin/ios
159
116
  homepage: http://mattt.me
160
117
  licenses: []
161
-
162
118
  post_install_message:
163
119
  rdoc_options: []
164
-
165
- require_paths:
120
+ require_paths:
166
121
  - lib
167
- required_ruby_version: !ruby/object:Gem::Requirement
122
+ required_ruby_version: !ruby/object:Gem::Requirement
168
123
  none: false
169
- requirements:
170
- - - ">="
171
- - !ruby/object:Gem::Version
172
- hash: 3
173
- segments:
124
+ requirements:
125
+ - - ! '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ segments:
174
129
  - 0
175
- version: "0"
176
- required_rubygems_version: !ruby/object:Gem::Requirement
130
+ hash: 3169719571408403656
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
177
132
  none: false
178
- requirements:
179
- - - ">="
180
- - !ruby/object:Gem::Version
181
- hash: 3
182
- segments:
133
+ requirements:
134
+ - - ! '>='
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ segments:
183
138
  - 0
184
- version: "0"
139
+ hash: 3169719571408403656
185
140
  requirements: []
186
-
187
141
  rubyforge_project:
188
142
  rubygems_version: 1.8.15
189
143
  signing_key:
190
144
  specification_version: 3
191
145
  summary: Cupertino
192
146
  test_files: []
193
-