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 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.1'
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}\n\n"
56
+ msg = "# #{msg}"
46
57
  when :json
47
- msg = "// #{msg}\n\n"
58
+ msg = "// #{msg}"
48
59
  else
49
- msg = "# #{msg}\n\n"
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
- str = JSON.pretty_generate(out)
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
@@ -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('/',
@@ -20,6 +20,14 @@ module SimpleDB
20
20
  @client.endpoint = v
21
21
  end
22
22
 
23
+ def timeout
24
+ @client.timeout
25
+ end
26
+
27
+ def timeout=(v)
28
+ @client.timeout = v
29
+ end
30
+
23
31
  # domain action
24
32
 
25
33
  def create_domain(domain_name)
@@ -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.1
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-02 00:00:00.000000000 Z
12
+ date: 2013-02-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri