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 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