sdbport 0.3.0 → 0.4.0
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/CHANGELOG +6 -0
- data/README.md +11 -2
- data/lib/sdbport/aws/simpledb.rb +11 -0
- data/lib/sdbport/cli/export.rb +7 -1
- data/lib/sdbport/domain.rb +4 -0
- data/lib/sdbport/domain/export.rb +24 -2
- data/lib/sdbport/version.rb +1 -1
- data/spec/aws/simpledb_spec.rb +23 -0
- data/spec/cli/destroy_spec.rb +32 -0
- data/spec/cli/export_spec.rb +49 -0
- data/spec/cli/import_spec.rb +34 -0
- data/spec/cli/purge_spec.rb +32 -0
- data/spec/domain/export_spec.rb +18 -0
- data/spec/domain_spec.rb +10 -1
- metadata +18 -10
data/CHANGELOG
CHANGED
data/README.md
CHANGED
@@ -6,7 +6,9 @@ Sdbport exports & imports data from AWS SimpleDB domains. It can be used as a cl
|
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
9
|
+
```
|
9
10
|
gem install sdbport
|
11
|
+
```
|
10
12
|
|
11
13
|
## Getting Started
|
12
14
|
|
@@ -20,13 +22,20 @@ export AWS_SECRET_ACCESS_KEY=your_aws_secret
|
|
20
22
|
Export SimpleDB domain from us-west-1:
|
21
23
|
|
22
24
|
```
|
23
|
-
sdbport export -
|
25
|
+
sdbport export -k $AWS_ACCESS_KEY_ID -s $AWS_SECRET_ACCESS_KEY -r us-west-1 -n data -o /tmp/test-domain-dump
|
26
|
+
```
|
27
|
+
|
28
|
+
To export larger SimpleDB domains, add -w. This writes each chunk to file as it is received rather than storing in memory:
|
29
|
+
|
30
|
+
```
|
31
|
+
sdbport export -k $AWS_ACCESS_KEY_ID -s $AWS_SECRET_ACCESS_KEY -r us-west-1 -n data -o /tmp/test-domain-dump -w
|
24
32
|
```
|
25
33
|
|
26
34
|
Import into domain in us-east-1
|
27
35
|
|
28
36
|
```
|
29
|
-
sdbport import -
|
37
|
+
sdbport import -k $AWS_ACCESS_KEY_ID -s $AWS_SECRET_ACCESS_KEY -r us-west-1 -n data -i /tmp/test-domain-dump
|
38
|
+
```
|
30
39
|
|
31
40
|
## Exporting and importing from multiple accounts.
|
32
41
|
|
data/lib/sdbport/aws/simpledb.rb
CHANGED
@@ -35,6 +35,17 @@ module Sdbport
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
+
def select_and_store_chunk_of_tokens(query, options = {})
|
39
|
+
options.merge! 'NextToken' => @token_for_next_chunk
|
40
|
+
chunk = sdb.select(query, options).body
|
41
|
+
@token_for_next_chunk = chunk['NextToken']
|
42
|
+
return chunk['Items']
|
43
|
+
end
|
44
|
+
|
45
|
+
def more_chunks?
|
46
|
+
@token_for_next_chunk != nil
|
47
|
+
end
|
48
|
+
|
38
49
|
def count(domain)
|
39
50
|
body = sdb.select("SELECT count(*) FROM `#{domain}`").body
|
40
51
|
body['Items']['Domain']['Count'].first.to_i
|
data/lib/sdbport/cli/export.rb
CHANGED
@@ -19,7 +19,12 @@ module Sdbport
|
|
19
19
|
:access_key => access_key,
|
20
20
|
:secret_key => secret_key,
|
21
21
|
:logger => logger
|
22
|
-
|
22
|
+
|
23
|
+
if opts[:write_as_you_go]
|
24
|
+
exit 1 unless domain.export_sequential_write opts[:output]
|
25
|
+
else
|
26
|
+
exit 1 unless domain.export opts[:output]
|
27
|
+
end
|
23
28
|
end
|
24
29
|
|
25
30
|
def read_options
|
@@ -44,6 +49,7 @@ EOS
|
|
44
49
|
opt :access_key, "AWS Access Key ID", :type => :string,
|
45
50
|
:short => 'k'
|
46
51
|
opt :secret_key, "AWS Secret Access Key", :type => :string
|
52
|
+
opt :write_as_you_go, "Write chunks to disk as they are received from Simple DB"
|
47
53
|
end
|
48
54
|
end
|
49
55
|
end
|
data/lib/sdbport/domain.rb
CHANGED
@@ -13,8 +13,7 @@ module Sdbport
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def export(output)
|
16
|
-
|
17
|
-
file = File.open(output, 'w')
|
16
|
+
file = setup_file output
|
18
17
|
export_domain.each do |item|
|
19
18
|
file.write convert_to_string item
|
20
19
|
file.write "\n"
|
@@ -22,8 +21,27 @@ module Sdbport
|
|
22
21
|
return true if file.close.nil?
|
23
22
|
end
|
24
23
|
|
24
|
+
def export_sequential_write(output)
|
25
|
+
file = setup_file output
|
26
|
+
@logger.info "Writing to disk as records received."
|
27
|
+
|
28
|
+
while true
|
29
|
+
export_domain_with_sequential_write.each do |item|
|
30
|
+
file.write convert_to_string item
|
31
|
+
file.write "\n"
|
32
|
+
end
|
33
|
+
break unless sdb.more_chunks?
|
34
|
+
end
|
35
|
+
return true if file.close.nil?
|
36
|
+
end
|
37
|
+
|
25
38
|
private
|
26
39
|
|
40
|
+
def setup_file(output)
|
41
|
+
@logger.info "Export #{@name} in #{@region} to #{output}"
|
42
|
+
File.open(output, 'w')
|
43
|
+
end
|
44
|
+
|
27
45
|
def sdb
|
28
46
|
@sdb ||= AWS::SimpleDB.new :access_key => @access_key,
|
29
47
|
:secret_key => @secret_key,
|
@@ -34,6 +52,10 @@ module Sdbport
|
|
34
52
|
sdb.select_and_follow_tokens "select * from `#{@name}`"
|
35
53
|
end
|
36
54
|
|
55
|
+
def export_domain_with_sequential_write
|
56
|
+
sdb.select_and_store_chunk_of_tokens "select * from `#{@name}`"
|
57
|
+
end
|
58
|
+
|
37
59
|
def convert_to_string(item)
|
38
60
|
item.to_json
|
39
61
|
end
|
data/lib/sdbport/version.rb
CHANGED
data/spec/aws/simpledb_spec.rb
CHANGED
@@ -49,6 +49,29 @@ describe Sdbport do
|
|
49
49
|
'id3' => 'val3' }
|
50
50
|
end
|
51
51
|
|
52
|
+
it "should perform select query given and store next token" do
|
53
|
+
body_stub0 = stub 'body0', :body => { 'Items' =>
|
54
|
+
{ 'id1' => 'val1' },
|
55
|
+
'NextToken' => '1'
|
56
|
+
}
|
57
|
+
body_stub1 = stub 'body1', :body => { 'Items' =>
|
58
|
+
{ 'id2' => 'val2' },
|
59
|
+
'NextToken' => nil
|
60
|
+
}
|
61
|
+
@fog_mock.should_receive(:select).
|
62
|
+
with('select * from name', 'NextToken' => nil).
|
63
|
+
and_return body_stub0
|
64
|
+
@sdb.select_and_store_chunk_of_tokens('select * from name').
|
65
|
+
should == { 'id1' => 'val1' }
|
66
|
+
@sdb.more_chunks?.should be_true
|
67
|
+
@fog_mock.should_receive(:select).
|
68
|
+
with('select * from name', 'NextToken' => '1').
|
69
|
+
and_return body_stub1
|
70
|
+
@sdb.select_and_store_chunk_of_tokens('select * from name').
|
71
|
+
should == { 'id2' => 'val2' }
|
72
|
+
@sdb.more_chunks?.should be_false
|
73
|
+
end
|
74
|
+
|
52
75
|
it "should create a new domain when it does not exist" do
|
53
76
|
@fog_mock.stub :list_domains => @body_stub
|
54
77
|
@body_stub.stub :body => { 'Domains' => [] }
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sdbport::CLI::Destroy do
|
4
|
+
before do
|
5
|
+
@domain_mock = mock "domain"
|
6
|
+
@logger_stub = stub "logger"
|
7
|
+
@options = { :name => 'daname',
|
8
|
+
:region => 'us-west-1',
|
9
|
+
:secret_key => 'private',
|
10
|
+
:access_key => 'abc',
|
11
|
+
:level => 'debug' }
|
12
|
+
|
13
|
+
Sdbport::SdbportLogger.should_receive(:new).
|
14
|
+
with(:log_level => 'debug').
|
15
|
+
and_return @logger_stub
|
16
|
+
@destroy = Sdbport::CLI::Destroy.new
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should perform destroy the domain" do
|
20
|
+
Trollop.stub :options => @options
|
21
|
+
Sdbport::Domain.should_receive(:new).
|
22
|
+
with(:name => 'daname',
|
23
|
+
:region => 'us-west-1',
|
24
|
+
:secret_key => 'private',
|
25
|
+
:access_key => 'abc',
|
26
|
+
:logger => @logger_stub).
|
27
|
+
and_return @domain_mock
|
28
|
+
@domain_mock.should_receive(:destroy).and_return true
|
29
|
+
@destroy.destroy
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sdbport::CLI::Export do
|
4
|
+
before do
|
5
|
+
@domain_mock = mock "domain"
|
6
|
+
@logger_stub = stub "logger"
|
7
|
+
@options = { :name => 'daname',
|
8
|
+
:region => 'us-west-1',
|
9
|
+
:secret_key => 'private',
|
10
|
+
:access_key => 'abc',
|
11
|
+
:level => 'debug',
|
12
|
+
:output => '/test/file' }
|
13
|
+
|
14
|
+
Sdbport::SdbportLogger.should_receive(:new).
|
15
|
+
with(:log_level => 'debug').
|
16
|
+
and_return @logger_stub
|
17
|
+
@export = Sdbport::CLI::Export.new
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should perform a in memeory write" do
|
21
|
+
Trollop.stub :options => @options
|
22
|
+
Sdbport::Domain.should_receive(:new).
|
23
|
+
with(:name => 'daname',
|
24
|
+
:region => 'us-west-1',
|
25
|
+
:secret_key => 'private',
|
26
|
+
:access_key => 'abc',
|
27
|
+
:logger => @logger_stub).
|
28
|
+
and_return @domain_mock
|
29
|
+
@domain_mock.should_receive(:export).with('/test/file').
|
30
|
+
and_return true
|
31
|
+
@export.export
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should perform a sequential write" do
|
35
|
+
@options.merge! :write_as_you_go => true
|
36
|
+
Trollop.stub :options => @options
|
37
|
+
Sdbport::Domain.should_receive(:new).
|
38
|
+
with(:name => 'daname',
|
39
|
+
:region => 'us-west-1',
|
40
|
+
:secret_key => 'private',
|
41
|
+
:access_key => 'abc',
|
42
|
+
:logger => @logger_stub).
|
43
|
+
and_return @domain_mock
|
44
|
+
@domain_mock.should_receive(:export_sequential_write).
|
45
|
+
with('/test/file').
|
46
|
+
and_return true
|
47
|
+
@export.export
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sdbport::CLI::Import do
|
4
|
+
before do
|
5
|
+
@domain_mock = mock "domain"
|
6
|
+
@logger_stub = stub "logger"
|
7
|
+
@options = { :name => 'daname',
|
8
|
+
:region => 'us-west-1',
|
9
|
+
:secret_key => 'private',
|
10
|
+
:access_key => 'abc',
|
11
|
+
:level => 'debug',
|
12
|
+
:input => '/test/file' }
|
13
|
+
|
14
|
+
Sdbport::SdbportLogger.should_receive(:new).
|
15
|
+
with(:log_level => 'debug').
|
16
|
+
and_return @logger_stub
|
17
|
+
@import = Sdbport::CLI::Import.new
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should perform an import from file" do
|
21
|
+
Trollop.stub :options => @options
|
22
|
+
Sdbport::Domain.should_receive(:new).
|
23
|
+
with(:name => 'daname',
|
24
|
+
:region => 'us-west-1',
|
25
|
+
:secret_key => 'private',
|
26
|
+
:access_key => 'abc',
|
27
|
+
:logger => @logger_stub).
|
28
|
+
and_return @domain_mock
|
29
|
+
@domain_mock.should_receive(:import).with('/test/file').
|
30
|
+
and_return true
|
31
|
+
@import.import
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sdbport::CLI::Purge do
|
4
|
+
before do
|
5
|
+
@domain_mock = mock "domain"
|
6
|
+
@logger_stub = stub "logger"
|
7
|
+
@options = { :name => 'daname',
|
8
|
+
:region => 'us-west-1',
|
9
|
+
:secret_key => 'private',
|
10
|
+
:access_key => 'abc',
|
11
|
+
:level => 'debug' }
|
12
|
+
|
13
|
+
Sdbport::SdbportLogger.should_receive(:new).
|
14
|
+
with(:log_level => 'debug').
|
15
|
+
and_return @logger_stub
|
16
|
+
@purge = Sdbport::CLI::Purge.new
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should perform a purge on the domain" do
|
20
|
+
Trollop.stub :options => @options
|
21
|
+
Sdbport::Domain.should_receive(:new).
|
22
|
+
with(:name => 'daname',
|
23
|
+
:region => 'us-west-1',
|
24
|
+
:secret_key => 'private',
|
25
|
+
:access_key => 'abc',
|
26
|
+
:logger => @logger_stub).
|
27
|
+
and_return @domain_mock
|
28
|
+
@domain_mock.should_receive(:purge).and_return true
|
29
|
+
@purge.purge
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/spec/domain/export_spec.rb
CHANGED
@@ -30,4 +30,22 @@ describe Sdbport do
|
|
30
30
|
@export.export('/tmp/file').should be_true
|
31
31
|
end
|
32
32
|
|
33
|
+
it "should export the given domain sequentially to disk" do
|
34
|
+
File.should_receive(:open).with('/tmp/file', 'w').
|
35
|
+
and_return @file_mock
|
36
|
+
data = { 'item1' =>
|
37
|
+
{ 'attribute' => [ 'value' ] },
|
38
|
+
'item2' =>
|
39
|
+
{ 'attribute' => [ 'different' ] }
|
40
|
+
}
|
41
|
+
@sdb_mock.should_receive(:select_and_store_chunk_of_tokens).
|
42
|
+
with('select * from `name`').
|
43
|
+
and_return data
|
44
|
+
@file_mock.should_receive(:write).with("[\"item1\",{\"attribute\":[\"value\"]}]")
|
45
|
+
@file_mock.should_receive(:write).with("[\"item2\",{\"attribute\":[\"different\"]}]")
|
46
|
+
@sdb_mock.should_receive(:more_chunks?).and_return false
|
47
|
+
@file_mock.should_receive(:write).with("\n").exactly(2).times
|
48
|
+
@file_mock.should_receive(:close).and_return nil
|
49
|
+
@export.export_sequential_write('/tmp/file').should be_true
|
50
|
+
end
|
33
51
|
end
|
data/spec/domain_spec.rb
CHANGED
@@ -15,7 +15,7 @@ describe Sdbport do
|
|
15
15
|
@domain.import('/tmp/file').should be_true
|
16
16
|
end
|
17
17
|
|
18
|
-
it "should call
|
18
|
+
it "should call export from the given output" do
|
19
19
|
Sdbport::Domain::Export.should_receive(:new).
|
20
20
|
with(:args1 => 'val1').
|
21
21
|
and_return @mock
|
@@ -24,6 +24,15 @@ describe Sdbport do
|
|
24
24
|
@domain.export('/tmp/file').should be_true
|
25
25
|
end
|
26
26
|
|
27
|
+
it "should call export_sequential_write with the given output" do
|
28
|
+
Sdbport::Domain::Export.should_receive(:new).
|
29
|
+
with(:args1 => 'val1').
|
30
|
+
and_return @mock
|
31
|
+
@mock.should_receive(:export_sequential_write).with('/tmp/file').
|
32
|
+
and_return true
|
33
|
+
@domain.export_sequential_write('/tmp/file').should be_true
|
34
|
+
end
|
35
|
+
|
27
36
|
it "should call domain_purge" do
|
28
37
|
Sdbport::Domain::Purge.stub :new => @mock
|
29
38
|
@mock.should_receive(:purge).and_return true
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sdbport
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70336407307380 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70336407307380
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: fog
|
27
|
-
requirement: &
|
27
|
+
requirement: &70336407306100 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70336407306100
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: trollop
|
38
|
-
requirement: &
|
38
|
+
requirement: &70336407304460 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70336407304460
|
47
47
|
description: Import and export AWS SimpleDB domains.
|
48
48
|
email:
|
49
49
|
- brett@weav.net
|
@@ -79,6 +79,10 @@ files:
|
|
79
79
|
- lib/sdbport/version.rb
|
80
80
|
- sdbport.gemspec
|
81
81
|
- spec/aws/simpledb_spec.rb
|
82
|
+
- spec/cli/destroy_spec.rb
|
83
|
+
- spec/cli/export_spec.rb
|
84
|
+
- spec/cli/import_spec.rb
|
85
|
+
- spec/cli/purge_spec.rb
|
82
86
|
- spec/cli_spec.rb
|
83
87
|
- spec/config_spec.rb
|
84
88
|
- spec/domain/destroy_spec.rb
|
@@ -102,7 +106,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
102
106
|
version: '0'
|
103
107
|
segments:
|
104
108
|
- 0
|
105
|
-
hash:
|
109
|
+
hash: 3976557266021725498
|
106
110
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
111
|
none: false
|
108
112
|
requirements:
|
@@ -111,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
115
|
version: '0'
|
112
116
|
segments:
|
113
117
|
- 0
|
114
|
-
hash:
|
118
|
+
hash: 3976557266021725498
|
115
119
|
requirements: []
|
116
120
|
rubyforge_project:
|
117
121
|
rubygems_version: 1.8.16
|
@@ -120,6 +124,10 @@ specification_version: 3
|
|
120
124
|
summary: Import and export AWS SimpleDB domains.
|
121
125
|
test_files:
|
122
126
|
- spec/aws/simpledb_spec.rb
|
127
|
+
- spec/cli/destroy_spec.rb
|
128
|
+
- spec/cli/export_spec.rb
|
129
|
+
- spec/cli/import_spec.rb
|
130
|
+
- spec/cli/purge_spec.rb
|
123
131
|
- spec/cli_spec.rb
|
124
132
|
- spec/config_spec.rb
|
125
133
|
- spec/domain/destroy_spec.rb
|