sdbcli 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|