itunes_store_transporter 0.0.1
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/README.rdoc +127 -0
- data/bin/itms +243 -0
- data/lib/itunes/store/transporter.rb +236 -0
- data/lib/itunes/store/transporter/command.rb +103 -0
- data/lib/itunes/store/transporter/command/lookup.rb +55 -0
- data/lib/itunes/store/transporter/command/option.rb +21 -0
- data/lib/itunes/store/transporter/command/providers.rb +35 -0
- data/lib/itunes/store/transporter/command/schema.rb +28 -0
- data/lib/itunes/store/transporter/command/status.rb +34 -0
- data/lib/itunes/store/transporter/command/upload.rb +27 -0
- data/lib/itunes/store/transporter/command/verify.rb +37 -0
- data/lib/itunes/store/transporter/command/version.rb +30 -0
- data/lib/itunes/store/transporter/errors.rb +67 -0
- data/lib/itunes/store/transporter/output_parser.rb +83 -0
- data/lib/itunes/store/transporter/shell.rb +94 -0
- data/lib/itunes/store/transporter/version.rb +7 -0
- data/spec/command_spec.rb +511 -0
- data/spec/errors_spec.rb +52 -0
- data/spec/output_parser_spec.rb +71 -0
- data/spec/shell_spec.rb +52 -0
- data/spec/spec_helper.rb +75 -0
- data/spec/transporter_spec.rb +106 -0
- metadata +123 -0
data/README.rdoc
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
= iTunes::Store::Transporter
|
2
|
+
|
3
|
+
Upload and manage your assets in the iTunes Store using the iTunes Store's Transporter (+iTMSTransporter+).
|
4
|
+
|
5
|
+
=== Overview
|
6
|
+
|
7
|
+
require "itunes/store/transporter"
|
8
|
+
|
9
|
+
itms = iTunes::Store::Transporter.new(:username => "CouchCaster",
|
10
|
+
:shortname => "bigtimer",
|
11
|
+
:password => "w3c@llYoU!")
|
12
|
+
|
13
|
+
itms.upload("/path/to/yourpackage.itmsp")
|
14
|
+
metadata = itms.lookup(:apple_id => "yourpackage")
|
15
|
+
|
16
|
+
begin
|
17
|
+
itms.verify("/path/to/package2.itmsp", :verify_asssets => false)
|
18
|
+
rescue iTunes::Store::Transporter::ExecutionError => e
|
19
|
+
puts "Exited with #{e.exitstatus}"
|
20
|
+
|
21
|
+
e.errors.each do |error|
|
22
|
+
puts "#{error.message} - #{error.code}"
|
23
|
+
puts "Basically, you have some faulty metadata" if error.missing_data?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
=== Description
|
28
|
+
|
29
|
+
iTunes::Store::Transporter is a wrapper around Apple's +iTMSTransporter+ program. It currently
|
30
|
+
supports the following operations:
|
31
|
+
|
32
|
+
* Upload packages
|
33
|
+
* Validate packages
|
34
|
+
* Retrieve status information
|
35
|
+
* Lookup package metadata
|
36
|
+
* List providers
|
37
|
+
* Retrieve iTunes metadata schemas
|
38
|
+
|
39
|
+
It also includes +itms+, an executable that's sorta like using +iTMSTransporter+ directly, except
|
40
|
+
that it can send email notifications and allows one to set global/per-command defaults via <code>$HOME/.itms</code>.
|
41
|
+
|
42
|
+
=== Requirements
|
43
|
+
|
44
|
+
* Optout v0.0.2 (<code>gem install optout</code>)
|
45
|
+
* iTunes Store Transporter (http://www.apple.com/itunes/sellcontent)
|
46
|
+
|
47
|
+
=== Running on Windows
|
48
|
+
|
49
|
+
On Windows +iTMSTransporter+ is called via the +iTMSTransporter.CMD+ batch file. This file does not handle the
|
50
|
+
+iTMSTransporter+'s exit status correctly, causing <code>iTunes::Store::Transporter</code> to report everything as a success.
|
51
|
+
|
52
|
+
This can be fixed by modifying +iTMSTransporter.CMD+ (note that the following does not mimic the batch file exactly):
|
53
|
+
|
54
|
+
...
|
55
|
+
|
56
|
+
call iTMSTransporter\iTMSTransporter %*
|
57
|
+
|
58
|
+
REM Add this line:
|
59
|
+
set exited=%errorlevel%
|
60
|
+
|
61
|
+
cd %olddir%
|
62
|
+
|
63
|
+
REM Add this line too:
|
64
|
+
exit /b %exited%
|
65
|
+
|
66
|
+
=== Using itms
|
67
|
+
|
68
|
+
<code>itms COMMAND [OPTIONS]</code>
|
69
|
+
|
70
|
+
* +COMMAND+ - The command (<code>iTunes::Store::Transporter</code> method) to run
|
71
|
+
* +OPTIONS+ - These are equivalent to the given +COMMAND+'s options except they must be given in long option format. For example <code>:apple_id => "X123"</code> would be <code>--apple-id=X123</code>.
|
72
|
+
|
73
|
+
==== Config file
|
74
|
+
|
75
|
+
Default options and email notifications can be placed in a YAML file at <code>$HOME/.itms</code>.
|
76
|
+
|
77
|
+
# Global command defaults
|
78
|
+
path: /usr/bin
|
79
|
+
username: sshaw
|
80
|
+
password: Pa55W0rd!
|
81
|
+
|
82
|
+
# Global email defaults
|
83
|
+
email:
|
84
|
+
to: everyone@example.com
|
85
|
+
from: no-reply@example.com
|
86
|
+
host: smtp.example.com
|
87
|
+
|
88
|
+
# Verify command
|
89
|
+
verify:
|
90
|
+
shortname: lUzer
|
91
|
+
|
92
|
+
# Upload command
|
93
|
+
upload:
|
94
|
+
shortname: enc0d3rz
|
95
|
+
transport: Aspera
|
96
|
+
rate: 750_000
|
97
|
+
# Email notifications for the upload command
|
98
|
+
email:
|
99
|
+
success:
|
100
|
+
cc: assets@example.com
|
101
|
+
subject: iTunes Upload <%= @apple_id %>
|
102
|
+
message: |
|
103
|
+
<% @username > uploaded it using <%= @transport %>
|
104
|
+
|
105
|
+
Bye!
|
106
|
+
failure:
|
107
|
+
to: support@example.com
|
108
|
+
subject: Upload Failed!
|
109
|
+
message: |
|
110
|
+
Here's the problem:
|
111
|
+
|
112
|
+
<%= @error %>
|
113
|
+
|
114
|
+
Fix it!
|
115
|
+
|
116
|
+
=== More Info
|
117
|
+
|
118
|
+
* Source Code: http://github.com/sshaw/itunes_store_transporter
|
119
|
+
* Bugs: http://github.com/sshaw/itunes_store_transporter/issues
|
120
|
+
|
121
|
+
=== Author
|
122
|
+
|
123
|
+
Skye Shaw [sshaw AT lucas.cis.temple.edu]
|
124
|
+
|
125
|
+
=== License
|
126
|
+
|
127
|
+
Released under the MIT License: http://www.opensource.org/licenses/MIT
|
data/bin/itms
ADDED
@@ -0,0 +1,243 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "erb"
|
4
|
+
require "yaml"
|
5
|
+
require "net/smtp"
|
6
|
+
require "itunes/store/transporter"
|
7
|
+
|
8
|
+
# Command line interface to the ITunes::Store::Transporter library.
|
9
|
+
# Using this is sorta like using iTMSTransporter except it can send email notifications and allows
|
10
|
+
# one to set global/per-command defaults via $HOME/.itms
|
11
|
+
|
12
|
+
module Command
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def execute(name, options, argv)
|
16
|
+
name = name.capitalize
|
17
|
+
# Avoid Ruby 1.8/1.9 String/Symbol/const_defined? differences
|
18
|
+
unless constants.include?(name) || constants.include?(name.to_sym)
|
19
|
+
raise ArgumentError, "unknown command '#{name}'"
|
20
|
+
end
|
21
|
+
|
22
|
+
command = const_get(name).new(options)
|
23
|
+
command.execute(argv)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Base
|
28
|
+
def initialize(options)
|
29
|
+
@itms = ITunes::Store::Transporter.new(options)
|
30
|
+
@options = options
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Providers < Base
|
35
|
+
def initialize(options)
|
36
|
+
# Let iTMSTransporter print the providers
|
37
|
+
options[:print_stdout] = true
|
38
|
+
super
|
39
|
+
end
|
40
|
+
|
41
|
+
def execute(args = [])
|
42
|
+
@itms.providers
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Lookup < Base
|
47
|
+
def execute(args = [])
|
48
|
+
filename = "#{@options[:apple_id] || @options[:vendor_id]}.xml"
|
49
|
+
metadata = @itms.lookup
|
50
|
+
File.open(filename, "w") { |f| f.write(metadata) }
|
51
|
+
puts "Metadata saved to #{filename}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class Schema < Base
|
56
|
+
def execute(args = [])
|
57
|
+
filename = "#{@options[:version]}-#{@options[:type]}.rng"
|
58
|
+
schema = @itms.schema
|
59
|
+
File.open(filename, "w") { |f| f.write(schema) }
|
60
|
+
puts "Schema saved to #{filename}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Status < Base
|
65
|
+
def initialize(options)
|
66
|
+
# Let iTMSTransporter print the status
|
67
|
+
options[:print_stdout] = true
|
68
|
+
super
|
69
|
+
end
|
70
|
+
|
71
|
+
def execute(args = [])
|
72
|
+
@itms.status(args.shift)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class Upload < Base
|
77
|
+
def initialize(options)
|
78
|
+
# These can take a while so we let the user know what's going on
|
79
|
+
options[:print_stderr] = true unless options.include?(:print_stderr)
|
80
|
+
super
|
81
|
+
end
|
82
|
+
|
83
|
+
def execute(args = [])
|
84
|
+
@itms.upload(args.shift)
|
85
|
+
puts "Upload complete"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class Verify < Base
|
90
|
+
def execute(args = [])
|
91
|
+
@itms.verify(args.shift)
|
92
|
+
puts "Package is valid"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class Version < Base
|
97
|
+
def execute(args = [])
|
98
|
+
puts @itms.version
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class Email
|
104
|
+
Binding = Class.new do
|
105
|
+
def initialize(options = {})
|
106
|
+
options.each do |k, v|
|
107
|
+
name = k.to_s.gsub(/[^\w]+/, "_")
|
108
|
+
instance_variable_set("@#{name}", v)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def initialize(config = {})
|
114
|
+
unless config["to"]
|
115
|
+
raise "No email recipeints provided, you must specify at least one"
|
116
|
+
end
|
117
|
+
|
118
|
+
@config = config
|
119
|
+
end
|
120
|
+
|
121
|
+
def send(params = {})
|
122
|
+
to = @config["to"].to_s.split /,/
|
123
|
+
host = @config["host"] || "localhost"
|
124
|
+
from = @config["from"] || "#{ENV["USER"]}@#{host}"
|
125
|
+
params = params.merge(@config)
|
126
|
+
message = ::ERB.new(build_template).def_class(Binding).new(params).result
|
127
|
+
|
128
|
+
# TODO: auth
|
129
|
+
smtp = ::Net::SMTP.start(host, @config["port"]) do |mail|
|
130
|
+
mail.send_message message, from, to
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
protected
|
135
|
+
def build_template
|
136
|
+
%w[to from subject cc bcc].inject("") do |t, key|
|
137
|
+
t << "#{key}: #{@config[key]}\n" if @config[key]
|
138
|
+
t
|
139
|
+
end + "\n#{@config["message"]}"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
COMMANDS = ITunes::Store::Transporter.instance_methods(false).map(&:to_s)
|
144
|
+
RC_FILE_NAME = ".itms"
|
145
|
+
|
146
|
+
def home
|
147
|
+
ENV["HOME"] || ENV["USERPROFILE"]
|
148
|
+
end
|
149
|
+
|
150
|
+
# Should probably create a class for the options
|
151
|
+
def load_config(command)
|
152
|
+
config = {}
|
153
|
+
return config unless home
|
154
|
+
|
155
|
+
path = File.join(home, RC_FILE_NAME)
|
156
|
+
return config unless File.file?(path)
|
157
|
+
|
158
|
+
config = YAML.load_file(path)
|
159
|
+
|
160
|
+
# Get the global defaults. select() returns an aray on Ruby < 1.9
|
161
|
+
defaults = config.select { |k,v| !v.is_a?(Hash) }
|
162
|
+
defaults = Hash[defaults] unless defaults.is_a?(Hash)
|
163
|
+
|
164
|
+
config[command] = defaults.merge(config[command] || {})
|
165
|
+
|
166
|
+
# Normalize the email config
|
167
|
+
email = Hash.new { |h, k| h[k] = {} }
|
168
|
+
|
169
|
+
%w[success failure].each do |type|
|
170
|
+
email[type] = (config[command]["email"] ||= {})[type]
|
171
|
+
next unless email[type]
|
172
|
+
|
173
|
+
# Merge the global email options & the command's "global" options with the success/failure options
|
174
|
+
settings = (config["email"].to_a + config[command]["email"].to_a).reject { |k, v| k == "success" or k == "failure" }
|
175
|
+
settings.each do |k, v|
|
176
|
+
email[type][k] = email[type][k] ? "#{email[type][k]}, #{v}" : v
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# ITunes::Store::Transporter uses Symbols for options
|
181
|
+
config[command] = config[command].inject({}) do |cfg, (k,v)|
|
182
|
+
cfg[k.to_sym] = v unless k.empty? # Avoid intern empty string errors in 1.8
|
183
|
+
cfg
|
184
|
+
end
|
185
|
+
|
186
|
+
config[command][:email] = email
|
187
|
+
config[command]
|
188
|
+
end
|
189
|
+
|
190
|
+
def print_errors(e)
|
191
|
+
$stderr.puts "#{e.errors.length} error(s)"
|
192
|
+
$stderr.puts "-" * 25
|
193
|
+
# TODO: group by type
|
194
|
+
e.errors.each_with_index do |msg, i|
|
195
|
+
$stderr.puts "#{i+1}. #{msg}"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def send_email(config, options)
|
200
|
+
return unless config
|
201
|
+
mail = Email.new(config)
|
202
|
+
mail.send(options)
|
203
|
+
end
|
204
|
+
|
205
|
+
command = ARGV.shift
|
206
|
+
abort("usage: itms command [options]") unless command
|
207
|
+
abort("invalid command '#{command}', valid commands are: #{COMMANDS.sort.join(', ')}") unless COMMANDS.include?(command)
|
208
|
+
|
209
|
+
options = load_config(command)
|
210
|
+
|
211
|
+
while ARGV.any?
|
212
|
+
opt = ARGV.first.dup
|
213
|
+
break unless opt.sub!(/\A--(?=\w)/, "")
|
214
|
+
|
215
|
+
key, val = opt.split(/=/, 2)
|
216
|
+
key.gsub!(/-/, "_")
|
217
|
+
# TODO: false, --no-xxxx
|
218
|
+
val = true unless val
|
219
|
+
val = val.to_i if val =~ /\A\d+\z/
|
220
|
+
options[key.to_sym] = val
|
221
|
+
ARGV.shift
|
222
|
+
end
|
223
|
+
|
224
|
+
# Keys for this are strings
|
225
|
+
email_options = options.delete(:email) || {}
|
226
|
+
command_options = options.dup
|
227
|
+
options[:argv] = ARGV.dup
|
228
|
+
options[:command] = command
|
229
|
+
|
230
|
+
begin
|
231
|
+
puts "Running command '#{command}'"
|
232
|
+
Command.execute(command, command_options, ARGV)
|
233
|
+
send_email(email_options["success"], options)
|
234
|
+
rescue ITunes::Store::Transporter::ExecutionError => e
|
235
|
+
print_errors(e)
|
236
|
+
options[:error] = e
|
237
|
+
send_email(email_options["failure"], options)
|
238
|
+
exit 1
|
239
|
+
rescue ITunes::Store::Transporter::TransporterError => e
|
240
|
+
$stderr.puts e
|
241
|
+
exit 2
|
242
|
+
end
|
243
|
+
|
@@ -0,0 +1,236 @@
|
|
1
|
+
require "itunes/store/transporter/command"
|
2
|
+
require "itunes/store/transporter/command/lookup"
|
3
|
+
require "itunes/store/transporter/command/providers"
|
4
|
+
require "itunes/store/transporter/command/schema"
|
5
|
+
require "itunes/store/transporter/command/status"
|
6
|
+
require "itunes/store/transporter/command/upload"
|
7
|
+
require "itunes/store/transporter/command/verify"
|
8
|
+
require "itunes/store/transporter/command/version"
|
9
|
+
|
10
|
+
module ITunes
|
11
|
+
module Store
|
12
|
+
##
|
13
|
+
# Upload and manage your assets in the iTunes Store using the iTunes Store's Transporter (+iTMSTransporter+).
|
14
|
+
|
15
|
+
class Transporter
|
16
|
+
|
17
|
+
##
|
18
|
+
# === Arguments
|
19
|
+
#
|
20
|
+
# [options (Hash)] Transporter options
|
21
|
+
#
|
22
|
+
# === Options
|
23
|
+
#
|
24
|
+
# Options given here will be used as defaults for all subsequent method calls. Thus you can set method specific options here but, if you call a method that does not accept one of these options, an OptionError will be raised.
|
25
|
+
#
|
26
|
+
# See specific methods for a list of options.
|
27
|
+
#
|
28
|
+
# [:username (String)] Your username
|
29
|
+
# [:password (String)] Your password
|
30
|
+
# [:shortname (String)] Your shortname. Optional, not every iTunes account has one
|
31
|
+
# [:path (String)] The path to the +iTMSTransporter+. Optional.
|
32
|
+
# [:print_stdout (Boolean)] Print +iTMSTransporter+'s stdout to your stdout. Defaults to +false+.
|
33
|
+
# [:print_stderr (Boolean)] Print +iTMSTransporter+'s stderr to your stderr. Defaults to +false+.
|
34
|
+
#
|
35
|
+
|
36
|
+
def initialize(options = nil)
|
37
|
+
@defaults = create_options(options)
|
38
|
+
@config = {
|
39
|
+
:path => @defaults.delete(:path),
|
40
|
+
:print_stdout => @defaults.delete(:print_stdout),
|
41
|
+
:print_stderr => @defaults.delete(:print_stderr),
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# :method: lookup
|
47
|
+
# :call-seq:
|
48
|
+
# lookup(options = {})
|
49
|
+
#
|
50
|
+
# Retrieve the metadata for a previously delivered package.
|
51
|
+
#
|
52
|
+
# === Arguments
|
53
|
+
#
|
54
|
+
# [options (Hash)] Transporter options
|
55
|
+
#
|
56
|
+
# ==== Options
|
57
|
+
#
|
58
|
+
# You must use either the +:apple_id+ or +:vendor_id+ option to identify the package
|
59
|
+
#
|
60
|
+
# === Errors
|
61
|
+
#
|
62
|
+
# TransporterError, OptionError, ExecutionError
|
63
|
+
#
|
64
|
+
# === Returns
|
65
|
+
#
|
66
|
+
# [String] The metadata
|
67
|
+
|
68
|
+
##
|
69
|
+
# :method: providers
|
70
|
+
# :call-seq:
|
71
|
+
# providers(options = {})
|
72
|
+
#
|
73
|
+
# List of Providers for whom your account is authorzed to deliver for.
|
74
|
+
#
|
75
|
+
# === Arguments
|
76
|
+
#
|
77
|
+
# [options (Hash)] Transporter options
|
78
|
+
#
|
79
|
+
# === Errors
|
80
|
+
#
|
81
|
+
# TransporterError, OptionError, ExecutionError
|
82
|
+
#
|
83
|
+
# === Returns
|
84
|
+
#
|
85
|
+
# [Array] Each element is a +Hash+ with two keys: +:shortname+ and +:longname+ representing the given provider's long and short names
|
86
|
+
|
87
|
+
##
|
88
|
+
# :method: schema
|
89
|
+
# :call-seq:
|
90
|
+
# schema(options = {})
|
91
|
+
#
|
92
|
+
# Download a RelaxNG schema file for a particular metadata specification.
|
93
|
+
#
|
94
|
+
# === Arguments
|
95
|
+
#
|
96
|
+
# [options (Hash)] Transporter options
|
97
|
+
#
|
98
|
+
# === Options
|
99
|
+
#
|
100
|
+
# [:type (String)] transitional or strict
|
101
|
+
# [:version (String)] The schema version you'd like to download. This is typically in the form of +schemaVERSION+. E.g., +film4.8+
|
102
|
+
#
|
103
|
+
# === Errors
|
104
|
+
#
|
105
|
+
# TransporterError, OptionError, ExecutionError
|
106
|
+
#
|
107
|
+
# === Returns
|
108
|
+
#
|
109
|
+
# [String] The schema
|
110
|
+
|
111
|
+
##
|
112
|
+
# :method: status
|
113
|
+
# :call-seq:
|
114
|
+
# status(options = {})
|
115
|
+
#
|
116
|
+
# Retrieve the status of a previously uploaded package.
|
117
|
+
#
|
118
|
+
# === Arguments
|
119
|
+
#
|
120
|
+
# [options (Hash)] Transporter options
|
121
|
+
#
|
122
|
+
# === Options
|
123
|
+
#
|
124
|
+
# [:vendor_id (String)] ID of the package you want status info on
|
125
|
+
#
|
126
|
+
# === Errors
|
127
|
+
#
|
128
|
+
# TransporterError, OptionError, ExecutionError
|
129
|
+
#
|
130
|
+
# === Returns
|
131
|
+
#
|
132
|
+
# [Hash] Descibes various facets of the package's status.
|
133
|
+
|
134
|
+
##
|
135
|
+
# :method: upload
|
136
|
+
# :call-seq:
|
137
|
+
# upload(package, options = {})
|
138
|
+
#
|
139
|
+
# Upload a package to the iTunes Store.
|
140
|
+
#
|
141
|
+
# === Arguments
|
142
|
+
#
|
143
|
+
# [package (String)] The path to the package directory to upload. Package names must end in +.itmsp+.
|
144
|
+
# [options (Hash)] Transporter options
|
145
|
+
#
|
146
|
+
# === Options
|
147
|
+
#
|
148
|
+
# [:transport (String)] The method/protocol used to upload your package. Optional. Can be one of: <code>"Aspera"</code>, <code>"Signiant"</code>, or <code>"DEV"</code>. By default +iTMSTransporter+ automatically selects the transport.
|
149
|
+
# [:rate (Integer)] Target bitrate in Kbps. Optional, only used with +Aspera+ and +Signiant+
|
150
|
+
# [:success (String)] A directory to move the package to if the upload succeeds
|
151
|
+
# [:failure (String)] A directory to move the package to if the upload fails
|
152
|
+
# [:delete (Boolean)] Delete the package if the upload succeeds. Defaults to +false+.
|
153
|
+
# [:log_history (String)] Write an +iTMSTransporter+ log to this directory. Off by default.
|
154
|
+
#
|
155
|
+
# === Errors
|
156
|
+
#
|
157
|
+
# TransporterError, OptionError, ExecutionError
|
158
|
+
#
|
159
|
+
# === Returns
|
160
|
+
#
|
161
|
+
# +true+ if the upload was successful.
|
162
|
+
|
163
|
+
##
|
164
|
+
# :method: verify
|
165
|
+
# :call-seq:
|
166
|
+
# verify(package, options = {})
|
167
|
+
#
|
168
|
+
# Validate the contents of a package's metadata and assets.
|
169
|
+
#
|
170
|
+
# If verification fails an ExecutionError containing the errors will be raised.
|
171
|
+
# Each error message is an instance of TransporterMessage.
|
172
|
+
#
|
173
|
+
# === Arguments
|
174
|
+
#
|
175
|
+
# [package (String)] The path to the package directory to verify. Package names must end in +.itmsp+.
|
176
|
+
# [options (Hash)] Verify options
|
177
|
+
#
|
178
|
+
# === Options
|
179
|
+
#
|
180
|
+
# [:verify_assets (Boolean)] If false the assets will not be verified. Defaults to +true+.
|
181
|
+
#
|
182
|
+
# === Errors
|
183
|
+
#
|
184
|
+
# TransporterError, OptionError, ExecutionError
|
185
|
+
#
|
186
|
+
# === Returns
|
187
|
+
#
|
188
|
+
# +true+ if the package was verified.
|
189
|
+
|
190
|
+
##
|
191
|
+
# :method: version
|
192
|
+
# :call-seq:
|
193
|
+
# version
|
194
|
+
#
|
195
|
+
# Return the underlying +iTMSTransporter+ version.
|
196
|
+
#
|
197
|
+
# === Returns
|
198
|
+
#
|
199
|
+
# [String] The version number
|
200
|
+
|
201
|
+
%w|upload verify|.each do |command|
|
202
|
+
define_method(command) do |package, *options|
|
203
|
+
cmd_options = create_options(options.first)
|
204
|
+
cmd_options[:package] = package
|
205
|
+
run_command(command, cmd_options)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
%w|lookup providers schema status version|.each do |command|
|
210
|
+
define_method(command) { |*options| run_command(command, options.shift) }
|
211
|
+
end
|
212
|
+
|
213
|
+
private
|
214
|
+
def run_command(name, options)
|
215
|
+
Command.const_get(name.capitalize).new(@config, @defaults).run(create_options(options))
|
216
|
+
end
|
217
|
+
|
218
|
+
def create_options(options)
|
219
|
+
options ||= {}
|
220
|
+
raise ArgumentError, "options must be a Hash" unless Hash === options
|
221
|
+
options.dup
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
unless ENV["ITUNES_STORE_TRANSPORTER_NO_SYNTAX_SUGAR"].to_i > 0
|
228
|
+
def iTunes
|
229
|
+
ITunes
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
|
235
|
+
|
236
|
+
|