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/spec/errors_spec.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe ITunes::Store::Transporter::TransporterMessage do
|
4
|
+
subject { ITunes::Store::Transporter::TransporterMessage.new("some message", 1) }
|
5
|
+
its(:code) { should == 1 }
|
6
|
+
its(:message) { should == "some message" }
|
7
|
+
|
8
|
+
describe "#to_s" do
|
9
|
+
it "includes the code and message" do
|
10
|
+
subject.to_s.should == "some message (1)"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "error predicate methods" do
|
15
|
+
method_codes = {
|
16
|
+
:bad_data? => [3000, 3999],
|
17
|
+
:invalid_data? => [4000, 4999],
|
18
|
+
:missing_data? => [5000, 5999],
|
19
|
+
:unsupported_feature? => [6000, 6999],
|
20
|
+
:schema_error? => [8000, 8999],
|
21
|
+
:asset_error? => [9000, 9999]
|
22
|
+
}
|
23
|
+
|
24
|
+
method_codes.each do |method, codes|
|
25
|
+
[codes.first, codes.last].each do |code|
|
26
|
+
|
27
|
+
context "code #{code}" do
|
28
|
+
subject { described_class.new("", code) }
|
29
|
+
its(method) { should be_true }
|
30
|
+
its(:validation_error?) { should be_true }
|
31
|
+
|
32
|
+
(method_codes.keys - [method]).each do |other|
|
33
|
+
its(other) { should be_false }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe ITunes::Store::Transporter::ExecutionError do
|
42
|
+
subject { described_class.new(messages, 1) }
|
43
|
+
let(:messages) { 2.times.inject([]) { |err, i| err << ITunes::Store::Transporter::TransporterMessage.new("message #{i}", i) } }
|
44
|
+
its(:exitstatus) { should == 1 }
|
45
|
+
its(:errors) { should == messages }
|
46
|
+
|
47
|
+
describe "#to_s" do
|
48
|
+
it "includes each messages and its code" do
|
49
|
+
subject.to_s.should == "message 0 (0), message 1 (1)"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe ITunes::Store::Transporter::OutputParser do
|
4
|
+
describe "parsing errors" do
|
5
|
+
# TODO: test various error message/code formats handled by the parser
|
6
|
+
|
7
|
+
context "without an error code" do
|
8
|
+
before(:all) { @parser = described_class.new(fixture("errors_and_warnings.no_error_number")) }
|
9
|
+
|
10
|
+
subject { @parser }
|
11
|
+
its(:warnings) { should be_empty }
|
12
|
+
its(:errors) { should have(2).items }
|
13
|
+
|
14
|
+
describe "the first error" do
|
15
|
+
subject { @parser.errors.first }
|
16
|
+
its(:code) { should be_nil }
|
17
|
+
its(:message) { should == "An error occurred while doing fun stuff" }
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "the second error" do
|
21
|
+
subject { @parser.errors.last }
|
22
|
+
its(:code) { should be_nil }
|
23
|
+
its(:message) { should == "An exception has occurred: network timeout" }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "with an error code" do
|
28
|
+
before(:all) { @parser = described_class.new(fixture("errors_and_warnings.with_error_number")) }
|
29
|
+
|
30
|
+
subject { @parser }
|
31
|
+
its(:warnings) { should be_empty }
|
32
|
+
its(:errors) { should have(2).items }
|
33
|
+
|
34
|
+
|
35
|
+
describe "the first error" do
|
36
|
+
subject { @parser.errors.first }
|
37
|
+
its(:code) { should == 4000 }
|
38
|
+
its(:message) { should == "This is error 4000" }
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "the second error" do
|
42
|
+
subject { @parser.errors.last }
|
43
|
+
its(:code) { should == 5000 }
|
44
|
+
its(:message) { should == "This is error 5000" }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "with duplicate messages" do
|
49
|
+
before(:all) { @parser = described_class.new(fixture("errors_and_warnings.duplicate_errors")) }
|
50
|
+
|
51
|
+
it "does not include duplicates" do
|
52
|
+
errors = @parser.errors.map { |e| e.message }
|
53
|
+
errors.should == ["Error 1", "Error 2", "Error 3"]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "parsing warnings" do
|
59
|
+
before(:all) { @parser = described_class.new(fixture("errors_and_warnings.single_warning")) }
|
60
|
+
|
61
|
+
subject { @parser }
|
62
|
+
its(:errors) { should be_empty }
|
63
|
+
its(:warnings) { should have(1).item }
|
64
|
+
|
65
|
+
describe "the warning" do
|
66
|
+
subject { @parser.warnings.first }
|
67
|
+
its(:code) { should == 4010 }
|
68
|
+
its(:message) { should == "You've been warned!" }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/spec/shell_spec.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "rbconfig"
|
3
|
+
|
4
|
+
describe ITunes::Store::Transporter::Shell do
|
5
|
+
it "yields stdout and stderr as they become available" do
|
6
|
+
ruby = File.join(RbConfig::CONFIG["bindir"], RbConfig::CONFIG["ruby_install_name"])
|
7
|
+
temp = Tempfile.new ""
|
8
|
+
# sleep else poll() (select) can favor the 1st FD in the read array, causing the
|
9
|
+
# test to fail on some platforms
|
10
|
+
temp.write(<<-CODE)
|
11
|
+
$stdout.puts "OUT 1"
|
12
|
+
$stdout.flush
|
13
|
+
sleep 1
|
14
|
+
$stderr.puts "ERR 1"
|
15
|
+
$stderr.flush
|
16
|
+
sleep 1
|
17
|
+
$stdout.puts "OUT 2"
|
18
|
+
$stdout.flush
|
19
|
+
sleep 1
|
20
|
+
$stderr.puts "ERR 2"
|
21
|
+
CODE
|
22
|
+
|
23
|
+
temp.flush
|
24
|
+
|
25
|
+
output = []
|
26
|
+
expect = [ [ :stdout, "OUT 1" ],
|
27
|
+
[ :stderr, "ERR 1" ],
|
28
|
+
[ :stdout, "OUT 2" ],
|
29
|
+
[ :stderr, "ERR 2" ] ]
|
30
|
+
|
31
|
+
described_class.new(ruby).exec([temp.path]) do |line, stream|
|
32
|
+
output << [ stream, line.chomp! ]
|
33
|
+
end
|
34
|
+
|
35
|
+
output.should == expect
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when on Windows" do
|
39
|
+
before(:all) { ENV["PROGRAMFILES"] = "C:\\" }
|
40
|
+
it "selects the Windows executable" do
|
41
|
+
described_class.stub(:windows? => true)
|
42
|
+
described_class.new.path.should match /#{described_class::WINDOWS_EXE}\Z/
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "when on anything but Windows" do
|
47
|
+
it "selects the right executable" do
|
48
|
+
described_class.stub(:windows? => false)
|
49
|
+
described_class.new.path.should match /#{described_class::EXE_NAME}\Z/
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require "rspec"
|
2
|
+
require "yaml"
|
3
|
+
require "tempfile"
|
4
|
+
require "fileutils"
|
5
|
+
require "itunes/store/transporter"
|
6
|
+
|
7
|
+
module SpecHelper
|
8
|
+
def create_options(options = {})
|
9
|
+
{ :username => "uzer",
|
10
|
+
:password => "_Gcod3" }.merge(options)
|
11
|
+
end
|
12
|
+
|
13
|
+
# TODO: options for package contents?
|
14
|
+
def create_package(options = {})
|
15
|
+
Dir.mktmpdir ["",".itmsp"]
|
16
|
+
end
|
17
|
+
|
18
|
+
def expect_shell_args(*expected)
|
19
|
+
ITunes::Store::Transporter::Shell.any_instance.stub(:exec) { |*arg| arg.first.should include(*expected) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def fixture(path)
|
23
|
+
Fixture.for(path)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Set up output streams and exit code
|
27
|
+
def mock_output(options = {})
|
28
|
+
outputs = []
|
29
|
+
exitcode = options[:exit] || 0
|
30
|
+
|
31
|
+
# Load a fixture for the given stream
|
32
|
+
[:stderr, :stdout].each do |fd|
|
33
|
+
fixture = options[fd]
|
34
|
+
next unless fixture
|
35
|
+
lines = Array === fixture ? fixture : Fixture.for(fixture)
|
36
|
+
outputs << [ lines, fd ]
|
37
|
+
end
|
38
|
+
|
39
|
+
ITunes::Store::Transporter::Shell.any_instance.stub(:exec) do |*options|
|
40
|
+
block = options.pop
|
41
|
+
outputs.each do |lines, fd|
|
42
|
+
lines.each { |line| block.call(line, fd) }
|
43
|
+
end
|
44
|
+
exitcode
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module Fixture
|
49
|
+
class << self
|
50
|
+
def for(path)
|
51
|
+
type, name = path.split ".", 2
|
52
|
+
raise "Unknown fixture '#{path}'" unless fixtures[type].include?(name)
|
53
|
+
fixtures[type][name].split("\n")
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def fixtures
|
58
|
+
@fixtures ||= load_fixtures
|
59
|
+
end
|
60
|
+
|
61
|
+
def load_fixtures
|
62
|
+
init = Hash.new { |h, k| h[k] = {} }
|
63
|
+
Dir[File.join(File.expand_path(File.dirname(__FILE__)), "fixtures", "*.yml")].inject(init) do |fixtures, path|
|
64
|
+
name = File.basename(path, ".yml")
|
65
|
+
fixtures[name] = YAML.load_file(path)
|
66
|
+
fixtures
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
RSpec.configure do |config|
|
74
|
+
config.include(SpecHelper)
|
75
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "itunes/store/transporter"
|
3
|
+
|
4
|
+
shared_examples_for "a transporter method" do
|
5
|
+
it "uses the default options" do
|
6
|
+
defaults = create_options
|
7
|
+
config = {
|
8
|
+
:path => "/",
|
9
|
+
:print_stderr => true,
|
10
|
+
:print_stdout => true
|
11
|
+
}
|
12
|
+
|
13
|
+
s = stub(command)
|
14
|
+
s.should_receive(:run)
|
15
|
+
|
16
|
+
klass = ITunes::Store::Transporter::Command.const_get(command)
|
17
|
+
klass.should_receive(:new).with(config, defaults).and_return(s)
|
18
|
+
|
19
|
+
described_class.new(config.merge(defaults)).send(method, options)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
shared_examples_for "a transporter method without a package argument" do
|
24
|
+
it_behaves_like "a transporter method"
|
25
|
+
|
26
|
+
it "executes the underlying command" do
|
27
|
+
ITunes::Store::Transporter::Command.const_get(command).any_instance.should_receive(:run).with(options)
|
28
|
+
subject.send(method, options)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
shared_examples_for "a transporter method with a package argument" do
|
33
|
+
it_behaves_like "a transporter method"
|
34
|
+
|
35
|
+
it "executes the underlying command" do
|
36
|
+
ITunes::Store::Transporter::Command.const_get(command).any_instance.should_receive(:run).with(:package => "package.itmsp")
|
37
|
+
subject.send(method, "package.itmsp")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
describe ITunes::Store::Transporter do
|
43
|
+
let(:options) { {} }
|
44
|
+
|
45
|
+
describe "#new" do
|
46
|
+
context "when the options are not a Hash or nil" do
|
47
|
+
it "raises an ArgumentError" do
|
48
|
+
lambda { described_class.new(123) }.should raise_exception(ArgumentError, /must be/)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#lookup" do
|
54
|
+
let(:method) { :lookup }
|
55
|
+
let(:command) { "Lookup" }
|
56
|
+
|
57
|
+
it_behaves_like "a transporter method without a package argument"
|
58
|
+
|
59
|
+
it "executes the underlying command" do
|
60
|
+
ITunes::Store::Transporter::Command::Lookup.any_instance.should_receive(:run)
|
61
|
+
subject.lookup
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#providers" do
|
66
|
+
let(:method) { :providers }
|
67
|
+
let(:command) { "Providers" }
|
68
|
+
|
69
|
+
it_behaves_like "a transporter method without a package argument"
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#schema" do
|
73
|
+
let(:method) { :schema }
|
74
|
+
let(:command) { "Schema" }
|
75
|
+
|
76
|
+
it_behaves_like "a transporter method without a package argument"
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#status" do
|
80
|
+
let(:method) { :status }
|
81
|
+
let(:command) { "Status" }
|
82
|
+
|
83
|
+
it_behaves_like "a transporter method without a package argument"
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#upload" do
|
87
|
+
let(:method) { :upload }
|
88
|
+
let(:command) { "Upload" }
|
89
|
+
|
90
|
+
it_behaves_like "a transporter method with a package argument"
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "#verify" do
|
94
|
+
let(:method) { :verify }
|
95
|
+
let(:command) { "Verify" }
|
96
|
+
|
97
|
+
it_behaves_like "a transporter method with a package argument"
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "#version" do
|
101
|
+
let(:method) { :version }
|
102
|
+
let(:command) { "Version" }
|
103
|
+
|
104
|
+
it_behaves_like "a transporter method without a package argument"
|
105
|
+
end
|
106
|
+
end
|
metadata
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: itunes_store_transporter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Skye Shaw
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-10 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: childprocess
|
16
|
+
requirement: &70193863731280 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.3.2
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70193863731280
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: optout
|
27
|
+
requirement: &70193863730780 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.0.2
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70193863730780
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rake
|
38
|
+
requirement: &70193863730320 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.9.2
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70193863730320
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: &70193863729860 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.8.0
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70193863729860
|
58
|
+
description: ! " iTunes::Store::Transporter is a wrapper around Apple's iTMSTransporter
|
59
|
+
program. It allows you to upload packages to the \n Apple Store, validate them,
|
60
|
+
retrieve status information, lookup metadata, and more!\n"
|
61
|
+
email: sshaw@lucas.cis.temple.edu
|
62
|
+
executables:
|
63
|
+
- itms
|
64
|
+
extensions: []
|
65
|
+
extra_rdoc_files:
|
66
|
+
- README.rdoc
|
67
|
+
files:
|
68
|
+
- lib/itunes/store/transporter/command/lookup.rb
|
69
|
+
- lib/itunes/store/transporter/command/option.rb
|
70
|
+
- lib/itunes/store/transporter/command/providers.rb
|
71
|
+
- lib/itunes/store/transporter/command/schema.rb
|
72
|
+
- lib/itunes/store/transporter/command/status.rb
|
73
|
+
- lib/itunes/store/transporter/command/upload.rb
|
74
|
+
- lib/itunes/store/transporter/command/verify.rb
|
75
|
+
- lib/itunes/store/transporter/command/version.rb
|
76
|
+
- lib/itunes/store/transporter/command.rb
|
77
|
+
- lib/itunes/store/transporter/errors.rb
|
78
|
+
- lib/itunes/store/transporter/output_parser.rb
|
79
|
+
- lib/itunes/store/transporter/shell.rb
|
80
|
+
- lib/itunes/store/transporter/version.rb
|
81
|
+
- lib/itunes/store/transporter.rb
|
82
|
+
- README.rdoc
|
83
|
+
- spec/command_spec.rb
|
84
|
+
- spec/errors_spec.rb
|
85
|
+
- spec/output_parser_spec.rb
|
86
|
+
- spec/shell_spec.rb
|
87
|
+
- spec/spec_helper.rb
|
88
|
+
- spec/transporter_spec.rb
|
89
|
+
- bin/itms
|
90
|
+
homepage: http://github.com/sshaw/itunes_store_transporter
|
91
|
+
licenses:
|
92
|
+
- MIT
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ! '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
requirements: []
|
110
|
+
rubyforge_project:
|
111
|
+
rubygems_version: 1.8.10
|
112
|
+
signing_key:
|
113
|
+
specification_version: 3
|
114
|
+
summary: Upload and manage your assets in the iTunes Store using the iTunes Store's
|
115
|
+
Transporter (iTMSTransporter).
|
116
|
+
test_files:
|
117
|
+
- spec/command_spec.rb
|
118
|
+
- spec/errors_spec.rb
|
119
|
+
- spec/output_parser_spec.rb
|
120
|
+
- spec/shell_spec.rb
|
121
|
+
- spec/spec_helper.rb
|
122
|
+
- spec/transporter_spec.rb
|
123
|
+
has_rdoc:
|