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.
@@ -0,0 +1,103 @@
1
+ require "optout"
2
+ require "itunes/store/transporter"
3
+ require "itunes/store/transporter/shell"
4
+ require "itunes/store/transporter/errors"
5
+ require "itunes/store/transporter/output_parser"
6
+ require "itunes/store/transporter/command/option"
7
+
8
+ module ITunes
9
+ module Store
10
+ class Transporter
11
+ module Command # :nodoc: all
12
+
13
+ class Base
14
+ include Option
15
+
16
+ def initialize(config, default_options = {})
17
+ @config = config
18
+ @shell = Shell.new(@config[:path])
19
+ @default_options = default_options
20
+ end
21
+
22
+ def run(options = {})
23
+ options = default_options.merge(options)
24
+ argv = create_transporter_options(options)
25
+ stdout_lines = []
26
+ stderr_lines = []
27
+
28
+ # TODO: hooks
29
+ exitcode = @shell.exec(argv) do |line, name|
30
+ if name == :stdout
31
+ stdout_lines << line
32
+ $stdout.puts line if config[:print_stdout]
33
+ else
34
+ stderr_lines << line
35
+ $stderr.puts line if config[:print_stderr]
36
+ end
37
+ end
38
+
39
+ if exitcode == 0
40
+ handle_success(stdout_lines, stderr_lines, options)
41
+ else
42
+ handle_error(stdout_lines, stderr_lines, options, exitcode)
43
+ end
44
+ end
45
+
46
+ protected
47
+ attr :config
48
+ attr :default_options
49
+
50
+ def options
51
+ @options ||= Optout.options do
52
+ # On Windows we must include this else the Transporter batch script will call `pause` after the Transporter exits
53
+ on :windows, "-WONoPause"
54
+ # Optout can't do this: [a, b, c] => -X a -X b -X c
55
+ on :jvm, "-X" #, :multiple => true
56
+ end
57
+ end
58
+
59
+ # TODO: conf[:warnings]
60
+ def handle_success(stdout_lines, stderr_lines, options)
61
+ stdout_lines.join
62
+ end
63
+
64
+ def handle_error(stdout_lines, stderr_lines, options, exitcode)
65
+ parser = Transporter::OutputParser.new(stderr_lines)
66
+ errors = parser.errors.any? ? parser.errors : [ TransporterMessage.new(stderr_lines.join) ]
67
+ raise ITunes::Store::Transporter::ExecutionError.new(errors, exitcode)
68
+ end
69
+
70
+ def create_transporter_options(optz)
71
+ optz[:windows] = "true" if Transporter::Shell.windows?
72
+ options.argv(optz)
73
+ rescue Optout::OptionError => e
74
+ raise ITunes::Store::Transporter::OptionError, e.message
75
+ end
76
+ end
77
+
78
+ class Mode < Base
79
+ def initialize(*config)
80
+ super
81
+ options.on :log, "-o", Optout::File
82
+ options.on :verbose, "-v", %w|informational critical detailed eXtreme| # Since log output is critical to determining what's going on we can't include "off"
83
+ options.on :username, "-u", :required => true
84
+ options.on :password, "-p", :required => true
85
+ options.on :summary, "-summaryFile", Optout::File
86
+ options.on :mode, "-m", /\w+/, :required => true
87
+ options.on *SHORTNAME
88
+ end
89
+
90
+ def create_transporter_options(optz)
91
+ optz[:mode] = mode
92
+ super
93
+ end
94
+
95
+ def mode
96
+ self.class.to_s.split("::")[-1].gsub(/([a-z])([A-Z])/, "\1_\2").downcase
97
+ end
98
+ end
99
+
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,55 @@
1
+ require "fileutils"
2
+ require "itunes/store/transporter/errors"
3
+ require "itunes/store/transporter/command"
4
+
5
+ module ITunes
6
+ module Store
7
+ class Transporter
8
+ module Command
9
+
10
+ ##
11
+ # Retrieve the metadata for a previously delivered package.
12
+ #
13
+ class Lookup < Mode
14
+ def initialize(*config)
15
+ super
16
+ # These 2 are mutually exclusive, and one is required.
17
+ # Optout has no way to denote this
18
+ options.on *VENDOR_ID
19
+ options.on *APPLE_ID
20
+ options.on *DESTINATION
21
+ end
22
+
23
+ def run(options = {})
24
+ options[:destination] = Dir.mktmpdir
25
+ super
26
+ ensure
27
+ FileUtils.rm_rf(options[:destination])
28
+ end
29
+
30
+ protected
31
+ def handle_success(stdout_lines, stderr_lines, options)
32
+ id = options[:apple_id] || options[:vendor_id]
33
+ path = File.join(options[:destination], "#{id}.itmsp", "metadata.xml")
34
+
35
+ if !File.exists?(path)
36
+ raise ITunes::Store::Transporter::TransporterError, "No metadata file exists at #{path}"
37
+ end
38
+
39
+ begin
40
+ metadata = File.read(path)
41
+ rescue StandardError => e
42
+ raise ITunes::Store::Transporter::TransporterError, "Failed to read metadata file #{path}: #{e}"
43
+ end
44
+
45
+ metadata
46
+ end
47
+
48
+ def mode
49
+ "lookupMetadata"
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,21 @@
1
+ require "optout"
2
+
3
+ module ITunes
4
+ module Store
5
+ class Transporter
6
+ module Command
7
+ module Option
8
+ # Common command options
9
+ VENDOR_ID = [ :vendor_id, "-vendor_id", /\w/ ]
10
+ APPLE_ID = [ :apple_id, "-apple_id", /\w/ ]
11
+ SHORTNAME = [ :shortname, "-s", /\w/ ]
12
+ TRANSPORT = [ :transport, "-t", %w|Aspera Signiant DAV| ]
13
+ SUCCESS = [ :success, "-success", Optout::Dir.exists ]
14
+ FAILURE = [ :failure, "-failure", Optout::Dir.exists ]
15
+ PACKAGE = [ :package, "-f", Optout::Dir.exists.named(/\.itmsp\z/), { :required => true } ]
16
+ DESTINATION = [ :destination, "-destination" ]
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,35 @@
1
+ require "itunes/store/transporter/command"
2
+
3
+ module ITunes
4
+ module Store
5
+ class Transporter
6
+ module Command
7
+
8
+ ##
9
+ # List of Providers for whom your account is authorzed to deliver for.
10
+ #
11
+ class Providers < Mode
12
+ protected
13
+ def mode
14
+ "provider"
15
+ end
16
+
17
+ def handle_success(stdout_lines, stderr_lines, options)
18
+ providers = []
19
+ stdout_lines.each do |line|
20
+ line.chomp!
21
+ if line =~ /\A\d+\s+(.+?)\s+(\w+)\Z/
22
+ provider = {}
23
+ provider[:longname] = $1
24
+ provider[:shortname] = $2
25
+ providers << provider
26
+ end
27
+ end
28
+
29
+ providers
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,28 @@
1
+ require "itunes/store/transporter/command"
2
+
3
+ module ITunes
4
+ module Store
5
+ class Transporter
6
+ module Command
7
+
8
+ ##
9
+ # Download a RelaxNG schema file for a particular metadata specification.
10
+ #
11
+
12
+ class Schema < Mode
13
+ def initialize(*config)
14
+ super
15
+ options.on *DESTINATION
16
+ options.on :type, "-schemaType", /\A(transitional|strict)\z/i, :required => true
17
+ options.on :version, "-schema", /\w+/i, :required => true
18
+ end
19
+
20
+ protected
21
+ def mode
22
+ "generateSchema"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,34 @@
1
+ require "itunes/store/transporter/command"
2
+
3
+ module ITunes
4
+ module Store
5
+ class Transporter
6
+ module Command # :nodoc:
7
+
8
+ ##
9
+ # Retrieve the status of a previously uploaded package
10
+ #
11
+ class Status < Mode
12
+ def initialize(*config)
13
+ super
14
+ options.on *VENDOR_ID
15
+ end
16
+
17
+ protected
18
+ def handle_success(stdout_lines, stderr_lines, options)
19
+ status = {}
20
+ stdout_lines.each do |line|
21
+ next unless line =~ /\A\s*\w/
22
+ key, value = line.split(/:\s+/, 2).map(&:strip)
23
+ key.gsub!(/\s+/, "_")
24
+ key.downcase!
25
+ status[key.to_sym] = value
26
+ end
27
+ status
28
+ end
29
+ end
30
+
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,27 @@
1
+ require "optout"
2
+ require "itunes/store/transporter/command"
3
+
4
+ module ITunes
5
+ module Store
6
+ class Transporter
7
+ module Command # :nodoc: all
8
+
9
+ ##
10
+ # Upload a package to the iTunes Store
11
+ #
12
+ class Upload < Mode
13
+ def initialize(*config)
14
+ super
15
+ options.on *PACKAGE
16
+ options.on *TRANSPORT
17
+ options.on *SUCCESS
18
+ options.on *FAILURE
19
+ options.on :delete, "-delete", Optout::Boolean
20
+ options.on :rate, "-k", Integer # Required if TRANSPORT is Aspera or Signiant
21
+ options.on :log_history, "-loghistory", Optout::Dir.exists
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,37 @@
1
+ require "optout"
2
+ require "itunes/store/transporter/errors"
3
+ require "itunes/store/transporter/command"
4
+ require "itunes/store/transporter/output_parser"
5
+
6
+ module ITunes
7
+ module Store
8
+ class Transporter
9
+ module Command # :nodoc:
10
+
11
+ ##
12
+ # Validate the contents of a package's metadata and assets.
13
+ #
14
+
15
+ class Verify < Mode
16
+ def initialize(*config)
17
+ super
18
+ options.on *PACKAGE
19
+ options.on :verify_assets, "-disableAssetVerification", Optout::Boolean # If false verify MD only no assets
20
+ end
21
+
22
+ protected
23
+ # Verify mode returns 0 if there are no packages to verify but will emit an error message about the lack of packages
24
+ def handle_success(stdout_lines, stderr_lines, options)
25
+ parser = Transporter::OutputParser.new(stderr_lines)
26
+ if parser.errors.any?
27
+ raise ITunes::Store::Transporter::ExecutionError.new(parser.errors, 0)
28
+ else
29
+ true
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+
@@ -0,0 +1,30 @@
1
+ require "itunes/store/transporter/command"
2
+
3
+ module ITunes
4
+ module Store
5
+ class Transporter
6
+ module Command # :nodoc: all
7
+
8
+ ##
9
+ # Return the +iTMSTransporter+ version.
10
+ #
11
+ class Version < Base
12
+ def initialize(*config)
13
+ super
14
+ options.on :version, "-version"
15
+ end
16
+
17
+ protected
18
+ def create_transporter_options(optz)
19
+ optz[:version] = true
20
+ super
21
+ end
22
+
23
+ def handle_success(stdout_lines, stderr_lines, options)
24
+ super =~ /version\s+(\d+(?:\.\d+)*)\b/i ? $1 : "Unknown"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,67 @@
1
+
2
+ module ITunes
3
+ module Store
4
+ class Transporter
5
+
6
+ class TransporterError < StandardError; end
7
+ class OptionError < TransporterError; end
8
+
9
+ class ExecutionError < TransporterError
10
+ attr :errors
11
+ attr :exitstatus
12
+
13
+ def initialize(errors, exitstatus = nil)
14
+ @errors = [ errors ].flatten
15
+ @exitstatus = exitstatus
16
+ super @errors.map { |e| e.to_s }.join ", "
17
+ end
18
+ end
19
+
20
+ class TransporterMessage
21
+ attr :code
22
+ attr :message
23
+
24
+ def initialize(message, code = nil)
25
+ @message = message
26
+ @code = code
27
+ end
28
+
29
+ # 1000...2000?
30
+
31
+ def bad_data?
32
+ (3000...4000).include?(code)
33
+ end
34
+
35
+ def invalid_data?
36
+ (4000...5000).include?(code)
37
+ end
38
+
39
+ def missing_data?
40
+ (5000...6000).include?(code)
41
+ end
42
+
43
+ def unsupported_feature?
44
+ (6000...7000).include?(code)
45
+ end
46
+
47
+ def schema_error?
48
+ (8000...9000).include?(code)
49
+ end
50
+
51
+ def asset_error?
52
+ (9000...10_000).include?(code)
53
+ end
54
+
55
+ def validation_error?
56
+ (3000...10_000).include?(code)
57
+ end
58
+
59
+ def to_s
60
+ s = message.dup
61
+ s << " (#{code})" if code
62
+ s
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end