sdbcli 1.0.1 → 1.1.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/README +20 -0
- data/bin/sdbcli +177 -6
- data/lib/sdbcli/sdb-client.rb +4 -0
- data/lib/sdbcli/sdb-driver.rb +8 -0
- data/lib/sdbcli/sdb-runner.rb +10 -0
- metadata +2 -2
data/README
CHANGED
@@ -19,6 +19,11 @@ https://bitbucket.org/winebarrel/sdbcli
|
|
19
19
|
-e, --eval=COMMAND
|
20
20
|
-f, --format=YAML_OR_JSON
|
21
21
|
-c, --consistent
|
22
|
+
-t, --timeout=SECOND
|
23
|
+
--import=DOMAIN,FILE
|
24
|
+
--import-replace=DOMAIN,FILE
|
25
|
+
--export=DOMAIN,FILE
|
26
|
+
--export-retry=NUM
|
22
27
|
shell> export AWS_ACCESS_KEY_ID='...'
|
23
28
|
shell> export AWS_SECRET_ACCESS_KEY='...'
|
24
29
|
shell> export SDB_ENDPOINT='sdb.ap-northeast-1.amazonaws.com' # or SDB_REGION=ap-northeast-1
|
@@ -81,6 +86,7 @@ https://bitbucket.org/winebarrel/sdbcli
|
|
81
86
|
.quit | .exit exits sdbcli
|
82
87
|
.format (yaml|json)? displays a format or changes it
|
83
88
|
.consistent (true|false)? displays ConsistentRead parameter or changes it
|
89
|
+
.timeout SECOND displays a timeout second or changes it
|
84
90
|
.version displays a version
|
85
91
|
|
86
92
|
ap-northeast-1> select * from test;
|
@@ -113,3 +119,17 @@ see http://docs.amazonwebservices.com/AmazonSimpleDB/latest/DeveloperGuide/Quoti
|
|
113
119
|
---
|
114
120
|
- [itemname1, {attr1: val1, attr2: val2}]
|
115
121
|
- [itemname2, {attr1: val1, attr2: val2}]
|
122
|
+
|
123
|
+
== Import/Export
|
124
|
+
|
125
|
+
shell> sdbcli -f json --export=employees,employees.json
|
126
|
+
// 2500 rows was outputted...
|
127
|
+
// 5000 rows was outputted...
|
128
|
+
// 7500 rows was outputted...
|
129
|
+
...
|
130
|
+
shell> sdbcli -f json --import=employees,employees.json
|
131
|
+
// 2500 rows was inputted...
|
132
|
+
// 5000 rows was inputted...
|
133
|
+
// 7500 rows was inputted...
|
134
|
+
|
135
|
+
If '-' is specified as a file name, the input/output of data will become a standard input/output.
|
data/bin/sdbcli
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
|
3
3
|
|
4
|
-
Version = '1.0
|
4
|
+
Version = '1.1.0'
|
5
5
|
HISTORY_FILE = File.join((ENV['HOME'] || ENV['USERPROFILE'] || '.'), '.sdbcli_history')
|
6
6
|
HISTSIZE = 500
|
7
|
+
SELECT_LIMIT = 2500
|
7
8
|
|
8
9
|
require 'rubygems'
|
9
10
|
require 'sdbcli'
|
@@ -21,6 +22,10 @@ sdb_endpoint = ENV['SDB_ENDPOINT'] || ENV['SDB_REGION'] || 'sdb.amazonaws.c
|
|
21
22
|
command = nil
|
22
23
|
$format = :yaml
|
23
24
|
$consistent = false
|
25
|
+
import = nil
|
26
|
+
export = nil
|
27
|
+
export_retry = 3
|
28
|
+
timeout = 60
|
24
29
|
|
25
30
|
ARGV.options do |opt|
|
26
31
|
opt.on('-k', '--access-key=ACCESS_KEY') {|v| access_key_id = v }
|
@@ -29,6 +34,11 @@ ARGV.options do |opt|
|
|
29
34
|
opt.on('-e', '--eval=COMMAND') {|v| command = v }
|
30
35
|
opt.on('-f', '--format=YAML_OR_JSON', [:yaml, :json]) {|v| $format = v }
|
31
36
|
opt.on('-c', '--consistent') { $consistent = true }
|
37
|
+
opt.on('-t', '--timeout=SECOND', Integer) {|v| timeout = v.to_i }
|
38
|
+
opt.on('' , '--import=DOMAIN,FILE') {|v| import = v.split(/\s*,\s*/, 2) + [false] }
|
39
|
+
opt.on('' , '--import-replace=DOMAIN,FILE') {|v| import = v.split(/\s*,\s*/, 2) + [true] }
|
40
|
+
opt.on('' , '--export=DOMAIN,FILE') {|v| export = v.split(/\s*,\s*/, 2) }
|
41
|
+
opt.on('' , '--export-retry=NUM', Integer) {|v| export_retry = v.to_i }
|
32
42
|
opt.parse!
|
33
43
|
|
34
44
|
unless access_key_id and secret_access_key and sdb_endpoint
|
@@ -38,17 +48,19 @@ ARGV.options do |opt|
|
|
38
48
|
end
|
39
49
|
|
40
50
|
$runner = SimpleDB::Runner.new(access_key_id, secret_access_key, sdb_endpoint)
|
51
|
+
$runner.timeout = timeout
|
41
52
|
|
42
|
-
def output_error(msg)
|
53
|
+
def output_error(msg, strip = false)
|
43
54
|
case $format
|
44
55
|
when :yaml
|
45
|
-
msg = "# #{msg}
|
56
|
+
msg = "# #{msg}"
|
46
57
|
when :json
|
47
|
-
msg = "// #{msg}
|
58
|
+
msg = "// #{msg}"
|
48
59
|
else
|
49
|
-
msg = "# #{msg}
|
60
|
+
msg = "# #{msg}"
|
50
61
|
end
|
51
62
|
|
63
|
+
msg << "\n\n" unless strip
|
52
64
|
$stderr.puts msg
|
53
65
|
end
|
54
66
|
|
@@ -105,7 +117,17 @@ def execute(src, show_rows = false)
|
|
105
117
|
when :yaml
|
106
118
|
str = YAML.dump(out)
|
107
119
|
when :json
|
108
|
-
|
120
|
+
if out.kind_of?(Array) and inline
|
121
|
+
str = "[\n"
|
122
|
+
out.each_with_index do |item, i|
|
123
|
+
str << " #{item.to_json}"
|
124
|
+
str << ',' if i < (out.length - 1)
|
125
|
+
str << "\n"
|
126
|
+
end
|
127
|
+
str << "]"
|
128
|
+
else
|
129
|
+
str = JSON.pretty_generate(out)
|
130
|
+
end
|
109
131
|
else
|
110
132
|
output_error('Unknown format')
|
111
133
|
end
|
@@ -139,6 +161,145 @@ def execute(src, show_rows = false)
|
|
139
161
|
buf
|
140
162
|
end
|
141
163
|
|
164
|
+
# export mode
|
165
|
+
if export
|
166
|
+
export_domain, export_file = export
|
167
|
+
|
168
|
+
begin
|
169
|
+
export_file = (export_file == '-') ? $stdout : open(export_file, 'wb')
|
170
|
+
|
171
|
+
case $format
|
172
|
+
when :yaml
|
173
|
+
export_file.puts '---'
|
174
|
+
when :json
|
175
|
+
export_file.puts '['
|
176
|
+
else
|
177
|
+
raise 'must not happen'
|
178
|
+
end
|
179
|
+
|
180
|
+
query = "SELECT * FROM #{export_domain} "
|
181
|
+
query_expr = "WHERE itemName() IS NOT NULL ORDER BY itemName() LIMIT #{SELECT_LIMIT}"
|
182
|
+
rownum = 0
|
183
|
+
|
184
|
+
loop do
|
185
|
+
items = nil
|
186
|
+
|
187
|
+
export_retry.times do |i|
|
188
|
+
begin
|
189
|
+
items = $runner.execute(query + query_expr, true, $consistent)
|
190
|
+
break
|
191
|
+
rescue Timeout::Error => e
|
192
|
+
raise e if i >= (export_retry - 1)
|
193
|
+
end
|
194
|
+
|
195
|
+
output_error("Retry...", true)
|
196
|
+
end
|
197
|
+
|
198
|
+
break if items.empty?
|
199
|
+
rownum += items.length
|
200
|
+
|
201
|
+
case $format
|
202
|
+
when :yaml
|
203
|
+
export_file.puts YAML.dump(items).sub(/\A---\s*/, '').strip
|
204
|
+
when :json
|
205
|
+
export_file.print "," if rownum > SELECT_LIMIT
|
206
|
+
items.each_with_index do |item, i|
|
207
|
+
row = item.to_json
|
208
|
+
row << ',' if i < (items.length - 1)
|
209
|
+
export_file.puts row
|
210
|
+
end
|
211
|
+
else
|
212
|
+
raise 'must not happen'
|
213
|
+
end
|
214
|
+
|
215
|
+
tail_item_name = "'" + items.last[0].gsub(/'/, "''") + "'"
|
216
|
+
query_expr = "WHERE itemName() > #{tail_item_name} ORDER BY itemName() LIMIT #{SELECT_LIMIT}"
|
217
|
+
|
218
|
+
output_error("#{rownum} #{rownum > 1 ? 'rows' : 'row'} was outputted...", true)
|
219
|
+
end
|
220
|
+
|
221
|
+
output_error("#{rownum} #{rownum > 1 ? 'rows' : 'row'} was processed", true)
|
222
|
+
rescue => e
|
223
|
+
output_error e.message.strip
|
224
|
+
exit 1
|
225
|
+
end
|
226
|
+
|
227
|
+
case $format
|
228
|
+
when :yaml
|
229
|
+
when :json
|
230
|
+
export_file.puts ']'
|
231
|
+
else
|
232
|
+
raise 'must not happen'
|
233
|
+
end
|
234
|
+
|
235
|
+
begin
|
236
|
+
if export_file.kind_of?(IO) and export_file != $stdout and not export_file.closed?
|
237
|
+
export_file.close
|
238
|
+
end
|
239
|
+
rescue => e
|
240
|
+
output_error e.message.strip
|
241
|
+
exit 1
|
242
|
+
end
|
243
|
+
|
244
|
+
exit 0
|
245
|
+
end
|
246
|
+
|
247
|
+
# import mode
|
248
|
+
if import
|
249
|
+
import_domain, import_file, import_as_replace = import
|
250
|
+
|
251
|
+
unless import_file == '-' or File.exist?(import_file)
|
252
|
+
output_error("No such file: #{import_file}")
|
253
|
+
exit 1
|
254
|
+
end
|
255
|
+
|
256
|
+
begin
|
257
|
+
items = case $format
|
258
|
+
when :yaml
|
259
|
+
if import_file == '-'
|
260
|
+
YAML.load($stdin)
|
261
|
+
else
|
262
|
+
YAML.load_file(import_file)
|
263
|
+
end
|
264
|
+
when :json
|
265
|
+
if import_file == '-'
|
266
|
+
JSON.load($stdin)
|
267
|
+
else
|
268
|
+
open(import_file) {|f| JSON.load(f) }
|
269
|
+
end
|
270
|
+
else
|
271
|
+
raise 'must not happen'
|
272
|
+
end
|
273
|
+
|
274
|
+
unless items.kind_of?(Array)
|
275
|
+
output_error('Route object is not Array')
|
276
|
+
exit 1
|
277
|
+
end
|
278
|
+
|
279
|
+
rownum = 0
|
280
|
+
|
281
|
+
until (chunk = items.slice!(0, SELECT_LIMIT)).empty?
|
282
|
+
rownum += chunk.length
|
283
|
+
|
284
|
+
if import_as_replace
|
285
|
+
$runner.driver.update(import_domain, chunk)
|
286
|
+
else
|
287
|
+
$runner.driver.insert(import_domain, chunk)
|
288
|
+
end
|
289
|
+
|
290
|
+
output_error("#{rownum} #{rownum > 1 ? 'rows' : 'row'} was inputted...", true)
|
291
|
+
end
|
292
|
+
|
293
|
+
output_error("#{rownum} #{rownum > 1 ? 'rows' : 'row'} was processed", true)
|
294
|
+
|
295
|
+
exit 0
|
296
|
+
rescue => e
|
297
|
+
output_error e.message.strip
|
298
|
+
exit 1
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
# eval mode
|
142
303
|
if not $stdin.tty? or command
|
143
304
|
src = command || $stdin.read.strip
|
144
305
|
|
@@ -202,6 +363,7 @@ USE region_or_endpoint
|
|
202
363
|
.quit | .exit exits sdbcli
|
203
364
|
.format (yaml|json)? displays a format or changes it
|
204
365
|
.consistent (true|false)? displays ConsistentRead parameter or changes it
|
366
|
+
.timeout SECOND displays a timeout second or changes it
|
205
367
|
.version displays a version
|
206
368
|
|
207
369
|
EOS
|
@@ -268,6 +430,15 @@ while buf = Readline.readline(prompt, true)
|
|
268
430
|
else
|
269
431
|
output_error('Invalid argument')
|
270
432
|
end
|
433
|
+
elsif r =~ 'timeout'
|
434
|
+
case (arg || '').strip
|
435
|
+
when ''
|
436
|
+
puts $runner.timeout
|
437
|
+
when /\d+/
|
438
|
+
$runner.timeout = arg.to_i
|
439
|
+
else
|
440
|
+
output_error('Invalid argument')
|
441
|
+
end
|
271
442
|
elsif r =~ 'version'
|
272
443
|
puts "sdbcli #{Version}"
|
273
444
|
else
|
data/lib/sdbcli/sdb-client.rb
CHANGED
@@ -13,11 +13,13 @@ module SimpleDB
|
|
13
13
|
SIGNATURE_ALGORITHM = :SHA256
|
14
14
|
|
15
15
|
attr_accessor :endpoint
|
16
|
+
attr_accessor :timeout
|
16
17
|
|
17
18
|
def initialize(accessKeyId, secretAccessKey, endpoint = 'sdb.amazonaws.com')
|
18
19
|
@accessKeyId = accessKeyId
|
19
20
|
@secretAccessKey = secretAccessKey
|
20
21
|
@endpoint = endpoint
|
22
|
+
@timeout = 60
|
21
23
|
end
|
22
24
|
|
23
25
|
# domain action
|
@@ -92,6 +94,8 @@ module SimpleDB
|
|
92
94
|
https = Net::HTTP.new(@endpoint, 443)
|
93
95
|
https.use_ssl = true
|
94
96
|
https.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
97
|
+
https.open_timeout = @timeout
|
98
|
+
https.read_timeout = @timeout
|
95
99
|
|
96
100
|
doc = https.start do |w|
|
97
101
|
req = Net::HTTP::Post.new('/',
|
data/lib/sdbcli/sdb-driver.rb
CHANGED
data/lib/sdbcli/sdb-runner.rb
CHANGED
@@ -16,6 +16,8 @@ module SimpleDB
|
|
16
16
|
}
|
17
17
|
|
18
18
|
class Runner
|
19
|
+
attr_reader :driver
|
20
|
+
|
19
21
|
def initialize(accessKeyId, secretAccessKey, endpoint = 'sdb.amazonaws.com')
|
20
22
|
endpoint = region_to_endpoint(endpoint)
|
21
23
|
@driver = Driver.new(accessKeyId, secretAccessKey, endpoint)
|
@@ -30,6 +32,14 @@ module SimpleDB
|
|
30
32
|
@driver.endpoint = v
|
31
33
|
end
|
32
34
|
|
35
|
+
def timeout
|
36
|
+
@driver.timeout
|
37
|
+
end
|
38
|
+
|
39
|
+
def timeout=(v)
|
40
|
+
@driver.timeout = v
|
41
|
+
end
|
42
|
+
|
33
43
|
def region
|
34
44
|
REGIONS[endpoint]
|
35
45
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sdbcli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
12
|
+
date: 2013-02-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|