cupertino 0.0.2
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 +3 -0
- data/Gemfile.lock +42 -0
- data/README.md +43 -0
- data/Rakefile +10 -0
- data/bin/ios +20 -0
- data/cupertino.gemspec +25 -0
- data/lib/cupertino/provisioning_portal/agent.rb +86 -0
- data/lib/cupertino/provisioning_portal/commands/devices.rb +39 -0
- data/lib/cupertino/provisioning_portal/commands.rb +6 -0
- data/lib/cupertino/provisioning_portal/helpers.rb +33 -0
- data/lib/cupertino/provisioning_portal.rb +16 -0
- data/lib/cupertino.rb +3 -0
- metadata +107 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
cupertino (0.0.2)
|
5
|
+
commander (~> 4.1.2)
|
6
|
+
mechanize (~> 2.5.1)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
commander (4.1.2)
|
12
|
+
highline (~> 1.6.11)
|
13
|
+
domain_name (0.5.3)
|
14
|
+
unf (~> 0.0.3)
|
15
|
+
highline (1.6.12)
|
16
|
+
mechanize (2.5.1)
|
17
|
+
domain_name (~> 0.5, >= 0.5.1)
|
18
|
+
mime-types (~> 1.17, >= 1.17.2)
|
19
|
+
net-http-digest_auth (~> 1.1, >= 1.1.1)
|
20
|
+
net-http-persistent (~> 2.5, >= 2.5.2)
|
21
|
+
nokogiri (~> 1.4)
|
22
|
+
ntlm-http (~> 0.1, >= 0.1.1)
|
23
|
+
webrobots (~> 0.0, >= 0.0.9)
|
24
|
+
mime-types (1.19)
|
25
|
+
net-http-digest_auth (1.2.1)
|
26
|
+
net-http-persistent (2.7)
|
27
|
+
nokogiri (1.5.5)
|
28
|
+
ntlm-http (0.1.1)
|
29
|
+
rake (0.9.2.2)
|
30
|
+
rspec (0.6.4)
|
31
|
+
unf (0.0.5)
|
32
|
+
unf_ext
|
33
|
+
unf_ext (0.0.5)
|
34
|
+
webrobots (0.0.13)
|
35
|
+
|
36
|
+
PLATFORMS
|
37
|
+
ruby
|
38
|
+
|
39
|
+
DEPENDENCIES
|
40
|
+
cupertino!
|
41
|
+
rake (~> 0.9.2)
|
42
|
+
rspec (~> 0.6.1)
|
data/README.md
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# Cupertino
|
2
|
+
**Mechanize the Apple Dev Center**
|
3
|
+
|
4
|
+
Automate administrative tasks that you would normally have to do through the Apple Dev Center websites. Life's too short to manage device identifiers by hand!
|
5
|
+
|
6
|
+
This project is starting with the iOS Provisioning Portal, and may later expand to include iTunes Connect and/or Mac Developer Certificate Utility.
|
7
|
+
|
8
|
+
## Usage
|
9
|
+
|
10
|
+
```sh
|
11
|
+
$ ios devices:list
|
12
|
+
|
13
|
+
Mattt Thompson's iPad abcdef0123456789...
|
14
|
+
Mattt Thompson's iPhone abcdef0123456789...
|
15
|
+
|
16
|
+
$ ios devices:add "iPad 1"=abc123
|
17
|
+
$ ios devices:add "iPad 2"=def456 "iPad 3"=ghi789 ...
|
18
|
+
|
19
|
+
$ ios devices:remove "iPad 1"
|
20
|
+
```
|
21
|
+
|
22
|
+
## Commands
|
23
|
+
|
24
|
+
- `devices:list`
|
25
|
+
|
26
|
+
### To Be Implemented
|
27
|
+
|
28
|
+
#### Devices
|
29
|
+
|
30
|
+
- `devices:add`
|
31
|
+
- `devices:remove`
|
32
|
+
|
33
|
+
#### Certificates
|
34
|
+
|
35
|
+
- `certificates:list [-e development|distribution]`
|
36
|
+
- `certificates:add [-e development|distribution]`
|
37
|
+
- `certificates:download CERTIFICATE_NAME`
|
38
|
+
- `certificates:revoke CERTIFICATE_NAME`
|
39
|
+
|
40
|
+
#### Application IDs
|
41
|
+
|
42
|
+
- `app_ids:list`
|
43
|
+
- `app_ids:new`
|
data/Rakefile
ADDED
data/bin/ios
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'commander/import'
|
4
|
+
|
5
|
+
$:.push File.expand_path("../../lib", __FILE__)
|
6
|
+
|
7
|
+
require 'cupertino'
|
8
|
+
|
9
|
+
HighLine.track_eof = false # Fix for built-in Ruby
|
10
|
+
|
11
|
+
program :version, Cupertino::VERSION
|
12
|
+
program :description, 'A command-line interface for the iOS Provisioning Portal'
|
13
|
+
|
14
|
+
program :help, 'Author', 'Mattt Thompson <m@mattt.me>'
|
15
|
+
program :help, 'Website', 'https://github.com/mattt'
|
16
|
+
program :help_formatter, :compact
|
17
|
+
|
18
|
+
default_command :help
|
19
|
+
|
20
|
+
require 'cupertino/provisioning_portal'
|
data/cupertino.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "cupertino"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "cupertino"
|
7
|
+
s.authors = ["Mattt Thompson"]
|
8
|
+
s.email = "m@mattt.me"
|
9
|
+
s.homepage = "http://mattt.me"
|
10
|
+
s.version = Cupertino::VERSION
|
11
|
+
s.platform = Gem::Platform::RUBY
|
12
|
+
s.summary = "Cupertino"
|
13
|
+
s.description = "Mechanize the Apple Developer Center"
|
14
|
+
|
15
|
+
s.add_development_dependency "rspec", "~> 0.6.1"
|
16
|
+
s.add_development_dependency "rake", "~> 0.9.2"
|
17
|
+
|
18
|
+
s.add_dependency "commander", "~> 4.1.2"
|
19
|
+
s.add_dependency "mechanize", "~> 2.5.1"
|
20
|
+
|
21
|
+
s.files = Dir["./**/*"].reject { |file| file =~ /\.\/(bin|log|pkg|script|spec|test|vendor)/ }
|
22
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
23
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
|
+
s.require_paths = ["lib"]
|
25
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'mechanize'
|
2
|
+
|
3
|
+
module Cupertino
|
4
|
+
module ProvisioningPortal
|
5
|
+
class Agent < ::Mechanize
|
6
|
+
attr_accessor :username, :password, :team
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
super
|
10
|
+
self.user_agent_alias = 'Mac Safari'
|
11
|
+
end
|
12
|
+
|
13
|
+
def get(uri, parameters = [], referer = nil, headers = {})
|
14
|
+
3.times do
|
15
|
+
super(uri, parameters, referer, headers)
|
16
|
+
|
17
|
+
case page.title
|
18
|
+
when %r{Sign in with your Apple ID}
|
19
|
+
login! and redo
|
20
|
+
when %r{Select Your Team}
|
21
|
+
select_team! and redo
|
22
|
+
else
|
23
|
+
return page
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def list_devices
|
29
|
+
get("https://developer.apple.com/ios/manage/devices/index.action")
|
30
|
+
|
31
|
+
devices = []
|
32
|
+
page.parser.xpath('//fieldset[@id="fs-0"]/table/tbody/tr').each do |row|
|
33
|
+
device = Device.new
|
34
|
+
device.name = row.at_xpath('td[@class="name"]/span/text()')
|
35
|
+
device.udid = row.at_xpath('td[@class="id"]/text()')
|
36
|
+
devices << device
|
37
|
+
end
|
38
|
+
devices
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_devices(*devices)
|
42
|
+
return if devices.empty?
|
43
|
+
|
44
|
+
get("https://developer.apple.com/ios/manage/devices/upload.action")
|
45
|
+
|
46
|
+
begin
|
47
|
+
file = Tempfile.new(['devices', '.txt'])
|
48
|
+
file.write("deviceIdentifier\tdeviceName")
|
49
|
+
devices.each do |device|
|
50
|
+
file.write("\n#{device.udid}\t#{device.name}")
|
51
|
+
end
|
52
|
+
file.rewind
|
53
|
+
|
54
|
+
if form = page.form_with(:name => 'saveupload')
|
55
|
+
upload = form.file_uploads.first
|
56
|
+
upload.file_name = file.path
|
57
|
+
form.submit
|
58
|
+
end
|
59
|
+
ensure
|
60
|
+
file.close!
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def login!
|
67
|
+
if form = page.form_with(:name => 'appleConnectForm')
|
68
|
+
form.theAccountName = self.username
|
69
|
+
form.theAccountPW = self.password
|
70
|
+
form.submit
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def select_team!
|
75
|
+
if form = page.form_with(:name => 'saveTeamSelection')
|
76
|
+
team_list = form.field_with(:name => 'memberDisplayId')
|
77
|
+
team_option = team_list.option_with(:text => self.team)
|
78
|
+
team_option.select
|
79
|
+
|
80
|
+
btn = form.button_with(:name => 'action:saveTeamSelection!save')
|
81
|
+
form.click_button(btn)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
command :'devices:list' do |c|
|
2
|
+
c.syntax = 'ios devices:list'
|
3
|
+
c.summary = 'Lists the Name and ID of Devices in the Provisioning Portal'
|
4
|
+
c.description = ''
|
5
|
+
|
6
|
+
c.action do |args, options|
|
7
|
+
devices = agent.list_devices
|
8
|
+
|
9
|
+
say_ok "Devices:"
|
10
|
+
devices.each do |device|
|
11
|
+
log device.name, device.udid
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
alias_command :devices, :'devices:list'
|
17
|
+
|
18
|
+
command :'devices:add' do |c|
|
19
|
+
c.syntax = 'ios devices:add DEVICE_NAME=DEVICE_ID [...]'
|
20
|
+
c.summary = 'Adds the a device to the Provisioning Portal'
|
21
|
+
c.description = ''
|
22
|
+
|
23
|
+
c.action do |args, options|
|
24
|
+
say_error "Missing arguments, expected DEVICE_NAME=DEVICE_ID" and abort if args.nil? or args.empty?
|
25
|
+
|
26
|
+
devices = []
|
27
|
+
args.each do |arg|
|
28
|
+
components = arg.strip.gsub(/\"/, '').split(/\=/)
|
29
|
+
device = Device.new
|
30
|
+
device.name = components.first
|
31
|
+
device.udid = components.last
|
32
|
+
devices << device
|
33
|
+
end
|
34
|
+
|
35
|
+
agent.add_devices(*devices)
|
36
|
+
|
37
|
+
say_ok "Added #{devices.length} #{devices.length == 1 ? 'device' : 'devices'}"
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Monkey Patch Commander::UI to alias password to avoid conflicts
|
2
|
+
module Commander::UI
|
3
|
+
alias :pw :password
|
4
|
+
end
|
5
|
+
|
6
|
+
module Cupertino
|
7
|
+
module ProvisioningPortal
|
8
|
+
module Helpers
|
9
|
+
def agent
|
10
|
+
unless @agent
|
11
|
+
@agent = Cupertino::ProvisioningPortal::Agent.new
|
12
|
+
|
13
|
+
@agent.instance_eval do
|
14
|
+
def username
|
15
|
+
@username ||= ask "Username:"
|
16
|
+
end
|
17
|
+
|
18
|
+
def password
|
19
|
+
@password ||= pw "Password:"
|
20
|
+
end
|
21
|
+
|
22
|
+
def team
|
23
|
+
teams = page.form_with(:name => 'saveTeamSelection').field_with(:name => 'memberDisplayId').options.collect(&:text)
|
24
|
+
@team ||= choose "Select a team:", *teams
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
@agent
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'mechanize'
|
2
|
+
|
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
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
$:.push File.expand_path('../', __FILE__)
|
13
|
+
|
14
|
+
require 'provisioning_portal/helpers'
|
15
|
+
require 'provisioning_portal/agent'
|
16
|
+
require 'provisioning_portal/commands'
|
data/lib/cupertino.rb
ADDED
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cupertino
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Mattt Thompson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-07-05 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &70106699402980 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.6.1
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70106699402980
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rake
|
27
|
+
requirement: &70106699401440 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.9.2
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70106699401440
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: commander
|
38
|
+
requirement: &70106699399220 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 4.1.2
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70106699399220
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: mechanize
|
49
|
+
requirement: &70106699395800 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.5.1
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70106699395800
|
58
|
+
description: Mechanize the Apple Developer Center
|
59
|
+
email: m@mattt.me
|
60
|
+
executables:
|
61
|
+
- ios
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- ./cupertino.gemspec
|
66
|
+
- ./Gemfile
|
67
|
+
- ./Gemfile.lock
|
68
|
+
- ./lib/cupertino/provisioning_portal/agent.rb
|
69
|
+
- ./lib/cupertino/provisioning_portal/commands/devices.rb
|
70
|
+
- ./lib/cupertino/provisioning_portal/commands.rb
|
71
|
+
- ./lib/cupertino/provisioning_portal/helpers.rb
|
72
|
+
- ./lib/cupertino/provisioning_portal.rb
|
73
|
+
- ./lib/cupertino.rb
|
74
|
+
- ./Rakefile
|
75
|
+
- ./README.md
|
76
|
+
- bin/ios
|
77
|
+
homepage: http://mattt.me
|
78
|
+
licenses: []
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ! '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
segments:
|
90
|
+
- 0
|
91
|
+
hash: 2027864098063448986
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ! '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
segments:
|
99
|
+
- 0
|
100
|
+
hash: 2027864098063448986
|
101
|
+
requirements: []
|
102
|
+
rubyforge_project:
|
103
|
+
rubygems_version: 1.8.15
|
104
|
+
signing_key:
|
105
|
+
specification_version: 3
|
106
|
+
summary: Cupertino
|
107
|
+
test_files: []
|