itunes_store_transporter 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|