td 0.11.12 → 0.11.13

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 36266b9c823ecc10de37fafc29ed07458a50a728
4
- data.tar.gz: 92ec61eb2983e7b284565252729aaedadf1483f9
3
+ metadata.gz: 844dda6ec2ea3ce703d94332d12f07da0c8130c1
4
+ data.tar.gz: 2fe722894996e437589d8841b06dcf0d8da0534d
5
5
  SHA512:
6
- metadata.gz: 545c05fd90e3577b175d732742182fca1bdd02dd9bf58666213006e89c0033e6ded3410cd610cc4f503b67db1f6e0f630d75249f33cd4f1ab56c326f0106b380
7
- data.tar.gz: 92ff25f768e6a82dceb87fddb41e395624a2de9b0e8bd64160b584f709cf28bfaaa7790f8cd5bfc3fe2de7169cf3d7305d99024eaafc2afec7a2735d51eb70ae
6
+ metadata.gz: 467d5b84f145cb1a2e11926b8332018eed6734fab410bbae0271873b4481ea1755c2aea6475e5835cef7981fb3f18605e7a5b8fbe983f9a608fbd2ca447ae12c
7
+ data.tar.gz: c1fae992cf68fc41304fe1b8326e8d1782ca29ad0b6b52828bb75553f66df0b4aa85ebf33888a0516e04929bbcdd1a406abb6cd25f68b77a043741e1c79ccb3b
data/ChangeLog CHANGED
@@ -1,3 +1,8 @@
1
+ == 2015-07-29 version 0.11.13
2
+
3
+ * allow retry when `td query -w` fail show result.
4
+ * `connector:issue` create database and table if use `--auto-create-table`
5
+
1
6
  == 2015-07-27 version 0.11.12
2
7
 
3
8
  * query command support msgpack.gz format save
@@ -247,6 +247,30 @@ EOS
247
247
  table
248
248
  end
249
249
 
250
+ def create_database_and_table_if_not_exist(client, db_name, table_name)
251
+ # Merge with db_create and table_create after refactoring
252
+ API.validate_database_name(db_name)
253
+ begin
254
+ client.database(db_name)
255
+ rescue NotFoundError
256
+ begin
257
+ client.create_database(db_name)
258
+ $stderr.puts "Database '#{db_name}' is created."
259
+ rescue AlreadyExistsError
260
+ # do nothing
261
+ end
262
+ rescue ForbiddenError
263
+ # do nothing
264
+ end
265
+
266
+ API.validate_table_name(table_name)
267
+ begin
268
+ client.create_log_table(db_name, table_name)
269
+ $stderr.puts "Table '#{db_name}.#{table_name}' is created."
270
+ rescue AlreadyExistsError
271
+ end
272
+ end
273
+
250
274
  def ask_password(max=3, &block)
251
275
  3.times do
252
276
  begin
@@ -109,13 +109,18 @@ module Command
109
109
 
110
110
  def connector_issue(op)
111
111
  database = table = nil
112
- time_column = nil
113
- wait = exclude = false
112
+ time_column = nil
113
+ wait = exclude = false
114
+ auto_create = false
115
+
114
116
  op.on('--database DB_NAME', "destination database") { |s| database = s }
115
117
  op.on('--table TABLE_NAME', "destination table") { |s| table = s }
116
118
  op.on('--time-column COLUMN_NAME', "data partitioning key") { |s| time_column = s } # unnecessary but for backward compatibility
117
119
  op.on('-w', '--wait', 'wait for finishing the job', TrueClass) { |b| wait = b }
118
120
  op.on('-x', '--exclude', 'do not automatically retrieve the job result', TrueClass) { |b| exclude = b }
121
+ op.on('--auto-create-table', "Create table and database if doesn't exist", TrueClass) { |b|
122
+ auto_create = b
123
+ }
119
124
 
120
125
  config_file = op.cmd_parse
121
126
 
@@ -126,6 +131,11 @@ module Command
126
131
  (config['out'] ||= {})['time_column'] = time_column if time_column # TODO will not work once embulk implements multi-job
127
132
 
128
133
  client = get_client()
134
+
135
+ if auto_create
136
+ create_database_and_table_if_not_exist(client, database, table)
137
+ end
138
+
129
139
  job_id = client.bulk_load_issue(database, table, config: config)
130
140
 
131
141
  $stdout.puts "Job #{job_id} is queued."
@@ -142,11 +142,10 @@ module Command
142
142
 
143
143
  if wait
144
144
  wait_job(job, true)
145
- $stdout.puts "Status : #{job.status}"
145
+ $stdout.puts "Status : #{job.status}"
146
146
  if job.success? && !exclude
147
- $stdout.puts "Result :"
148
147
  begin
149
- show_result(job, output, limit, format, render_opts)
148
+ show_result_with_retry(job, output, limit, format, render_opts)
150
149
  rescue TreasureData::NotFoundError => e
151
150
  end
152
151
  end
@@ -372,28 +372,30 @@ module Command
372
372
  time_key = 'time'
373
373
  auto_create = false
374
374
 
375
+ import_params = {}
376
+
375
377
  op.on('--format FORMAT', "file format (default: #{format})") {|s|
376
- format = s
378
+ import_params[:format] = s
377
379
  }
378
380
 
379
381
  op.on('--apache', "same as --format apache; apache common log format") {
380
- format = 'apache'
382
+ import_params[:format] = 'apache'
381
383
  }
382
384
 
383
385
  op.on('--syslog', "same as --format syslog; syslog") {
384
- format = 'syslog'
386
+ import_params[:format] = 'syslog'
385
387
  }
386
388
 
387
389
  op.on('--msgpack', "same as --format msgpack; msgpack stream format") {
388
- format = 'msgpack'
390
+ import_params[:format] = 'msgpack'
389
391
  }
390
392
 
391
393
  op.on('--json', "same as --format json; LF-separated json format") {
392
- format = 'json'
394
+ import_params[:format] = 'json'
393
395
  }
394
396
 
395
397
  op.on('-t', '--time-key COL_NAME', "time key name for json and msgpack format (e.g. 'created_at')") {|s|
396
- time_key = s
398
+ import_params[:time_key] = s
397
399
  }
398
400
 
399
401
  op.on('--auto-create-table', "Create table and database if doesn't exist", TrueClass) { |b|
@@ -401,63 +403,51 @@ module Command
401
403
  }
402
404
 
403
405
  db_name, table_name, *paths = op.cmd_parse
406
+ import_params[:db_name] = db_name
407
+ import_params[:table_name] = table_name
408
+ import_params[:paths] = paths
404
409
 
405
410
  client = get_client
406
411
 
407
412
  if auto_create
408
- # Merge with db_create and table_create after refactoring
409
- API.validate_database_name(db_name)
410
- begin
411
- client.database(db_name)
412
- rescue NotFoundError
413
- begin
414
- client.create_database(db_name)
415
- $stderr.puts "Database '#{db_name}' is created."
416
- rescue AlreadyExistsError
417
- # do nothing
418
- end
419
- rescue ForbiddenError
420
- # do nothing
421
- end
422
-
423
- API.validate_table_name(table_name)
424
- begin
425
- client.create_log_table(db_name, table_name)
426
- $stderr.puts "Table '#{db_name}.#{table_name}' is created."
427
- rescue AlreadyExistsError
428
- end
413
+ create_database_and_table_if_not_exist(client, db_name, table_name)
429
414
  end
430
415
 
431
- case format
416
+ do_table_import(client, import_params)
417
+ end
418
+
419
+ private
420
+ def do_table_import(client, import_params)
421
+ case import_params[:format]
432
422
  when 'json', 'msgpack'
433
423
  #unless time_key
434
424
  # $stderr.puts "-t, --time-key COL_NAME (e.g. '-t created_at') parameter is required for #{format} format"
435
425
  # exit 1
436
426
  #end
437
- if format == 'json'
427
+ if import_params[:format] == 'json'
438
428
  require 'json'
439
429
  require 'time'
440
- parser = JsonParser.new(time_key)
430
+ parser = JsonParser.new(import_params[:time_key])
441
431
  else
442
- parser = MessagePackParser.new(time_key)
432
+ parser = MessagePackParser.new(import_params[:time_key])
443
433
  end
444
434
 
445
435
  else # apache, syslog
446
- regexp, names, time_format = IMPORT_TEMPLATES[format]
436
+ regexp, names, time_format = IMPORT_TEMPLATES[import_params[:format]]
447
437
  if !regexp || !names || !time_format
448
- $stderr.puts "Unknown format '#{format}'"
438
+ $stderr.puts "Unknown format '#{import_params[:format]}'"
449
439
  exit 1
450
440
  end
451
441
  parser = TextParser.new(names, regexp, time_format)
452
442
  end
453
443
 
454
444
  begin
455
- db = client.database(db_name)
445
+ db = client.database(import_params[:db_name])
456
446
  rescue ForbiddenError => e
457
447
  $stdout.puts "Warning: database and table validation skipped - #{e.message}"
458
448
  else
459
449
  begin
460
- table = db.table(table_name)
450
+ table = db.table(import_params[:table_name])
461
451
  rescue ForbiddenError => e
462
452
  $stdout.puts "Warning: table validation skipped - #{e.message}"
463
453
  end
@@ -466,7 +456,7 @@ module Command
466
456
  require 'zlib'
467
457
 
468
458
  begin
469
- files = paths.map {|path|
459
+ files = import_params[:paths].map {|path|
470
460
  if path == '-'
471
461
  $stdin
472
462
  elsif path =~ /\.gz$/
@@ -484,14 +474,13 @@ module Command
484
474
  require 'tempfile'
485
475
  #require 'thread'
486
476
 
487
- files.zip(paths).each {|file, path|
488
- import_log_file(file, path, client, db_name, table_name, parser)
477
+ files.zip(import_params[:paths]).each {|file, path|
478
+ import_log_file(file, path, client, import_params[:db_name], import_params[:table_name], parser)
489
479
  }
490
480
 
491
481
  $stdout.puts "done."
492
482
  end
493
483
 
494
- private
495
484
  def import_log_file(file, path, client, db_name, table_name, parser)
496
485
  $stdout.puts "importing #{path}..."
497
486
 
@@ -1,3 +1,3 @@
1
1
  module TreasureData
2
- TOOLBELT_VERSION = '0.11.12'
2
+ TOOLBELT_VERSION = '0.11.13'
3
3
  end
@@ -58,29 +58,75 @@ module TreasureData::Command
58
58
  Class.new { include TreasureData::Command }.new
59
59
  end
60
60
 
61
+ let(:stderr_io) do
62
+ StringIO.new
63
+ end
64
+
61
65
  subject do
62
66
  backup = $stdout.dup
67
+ stderr_backup = $stderr.dup
63
68
  buf = StringIO.new
64
69
 
65
70
  begin
66
71
  $stdout = buf
72
+ $stderr = stderr_io
67
73
 
68
- op = List::CommandParser.new("connector:issue", ["config"], ['database', 'table'], nil, [File.join("spec", "td", "fixture", "bulk_load.yml"), '--database', 'database', '--table', 'table'], true)
69
- command.connector_issue(op)
74
+ command.connector_issue(option)
70
75
 
71
76
  buf.string
72
77
  ensure
73
78
  $stdout = backup
79
+ $stderr = stderr_backup
74
80
  end
75
81
  end
76
82
 
77
- before do
78
- client = double(:client, bulk_load_issue: 1234)
79
- command.stub(:get_client).and_return(client)
83
+ describe 'queueing job' do
84
+ let(:option) {
85
+ List::CommandParser.new("connector:issue", ["config"], ['database', 'table'], nil, [File.join("spec", "td", "fixture", "bulk_load.yml"), '--database', 'database', '--table', 'table'], true)
86
+ }
87
+
88
+ before do
89
+ client = double(:client, bulk_load_issue: 1234)
90
+ command.stub(:get_client).and_return(client)
91
+ command.stub(:create_database_and_table_if_not_exist)
92
+ end
93
+
94
+ it 'should include too_long_column_name without truncated' do
95
+ expect(subject).to include "Job 1234 is queued."
96
+ end
80
97
  end
81
98
 
82
- it 'should include too_long_column_name without truncated' do
83
- expect(subject).to include "Job 1234 is queued."
99
+ describe 'distination table' do
100
+ let(:client) { double(:client, bulk_load_issue: 1234) }
101
+
102
+ before do
103
+ command.stub(:get_client).and_return(client)
104
+ client.stub(:database)
105
+ end
106
+
107
+ context 'set auto crate table option' do
108
+ let(:option) {
109
+ List::CommandParser.new("connector:issue", ["config"], ['database', 'table'], nil, [File.join("spec", "td", "fixture", "bulk_load.yml"), '--database', 'database', '--table', 'table', '--auto-create-table'], true)
110
+ }
111
+
112
+ it 'call create_database_and_table_if_not_exist' do
113
+ command.should_receive(:create_database_and_table_if_not_exist)
114
+
115
+ subject
116
+ end
117
+ end
118
+
119
+ context 'not set auto crate table option' do
120
+ let(:option) {
121
+ List::CommandParser.new("connector:issue", ["config"], ['database', 'table'], nil, [File.join("spec", "td", "fixture", "bulk_load.yml"), '--database', 'database', '--table', 'table'], true)
122
+ }
123
+
124
+ it 'call create_database_and_table_if_not_exist' do
125
+ command.should_not_receive(:create_database_and_table_if_not_exist)
126
+
127
+ subject
128
+ end
129
+ end
84
130
  end
85
131
  end
86
132
  end
@@ -179,5 +179,43 @@ module TreasureData::Command
179
179
  end
180
180
  end
181
181
  end
182
+
183
+ describe '#table_import' do
184
+ let(:db_name) { 'database' }
185
+ let(:table_name) { 'table' }
186
+ let(:client) { double('client') }
187
+ let(:command) { Class.new { include TreasureData::Command }.new }
188
+
189
+ describe 'auto create table' do
190
+ before do
191
+ command.stub(:get_client) { client }
192
+ command.stub(:do_table_import)
193
+ end
194
+
195
+ context 'set --auto-create-table' do
196
+ let(:option) {
197
+ List::CommandParser.new('table:import', [], %w(db_name table_name path), false, [db_name, table_name, 'path', '--auto-create-table'], true)
198
+ }
199
+
200
+ it 'create table' do
201
+ command.should_receive(:create_database_and_table_if_not_exist).with(client, db_name, table_name)
202
+
203
+ command.table_import(option)
204
+ end
205
+ end
206
+
207
+ context 'not set --auto-create-table' do
208
+ let(:option) {
209
+ List::CommandParser.new('table:import', [], %w(db_name table_name path), false, [db_name, table_name, 'path'], true)
210
+ }
211
+
212
+ it 'not create table' do
213
+ command.should_not_receive(:create_database_and_table_if_not_exist)
214
+
215
+ command.table_import(option)
216
+ end
217
+ end
218
+ end
219
+ end
182
220
  end
183
221
  end
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
  require 'td/command/common'
3
+ require 'td/client/api_error'
3
4
 
4
5
  module TreasureData::Command
5
6
  describe 'humanize_bytesize' do
@@ -189,4 +190,105 @@ module TreasureData::Command
189
190
  end
190
191
  }
191
192
  end
193
+
194
+ describe '#create_database_and_table_if_not_exist' do
195
+ let(:command_class) { Class.new { include TreasureData::Command } }
196
+ let(:command) { command_class.new }
197
+ let(:client) { double(:client) }
198
+ let(:database_name) { 'database' }
199
+ let(:table_name) { 'table1' }
200
+
201
+ let(:stderr_io) { StringIO.new }
202
+
203
+ subject(:call_create_database_and_table_if_not_exist) {
204
+ stderr = $stderr.dup
205
+ begin
206
+ $stderr = stderr_io
207
+
208
+ command.__send__(:create_database_and_table_if_not_exist, client, database_name, table_name)
209
+ ensure
210
+ $stderr = stderr
211
+ end
212
+ }
213
+
214
+ describe 'create database' do
215
+ before do
216
+ client.stub(:create_log_table)
217
+ end
218
+
219
+ context 'client.database success' do
220
+ it 'not call client.create_database' do
221
+ client.should_receive(:database).with(database_name)
222
+ client.should_not_receive(:create_database)
223
+
224
+ call_create_database_and_table_if_not_exist
225
+ expect(stderr_io.string).not_to include "Database '#{database_name}'"
226
+ end
227
+ end
228
+
229
+ context 'client.database raise NotFoundError' do
230
+ before do
231
+ client.should_receive(:database).with(database_name).and_return { raise TreasureData::NotFoundError }
232
+ end
233
+
234
+ context 'craet_database success' do
235
+ it 'call client.create_database' do
236
+ client.should_receive(:create_database).with(database_name)
237
+
238
+ call_create_database_and_table_if_not_exist
239
+ expect(stderr_io.string).to include "Database '#{database_name}'"
240
+ end
241
+ end
242
+
243
+ context 'craet_database raise AlreadyExistsError' do
244
+ it 'resuce in method' do
245
+ client.should_receive(:create_database).with(database_name).and_return { raise TreasureData::AlreadyExistsError }
246
+
247
+ expect {
248
+ call_create_database_and_table_if_not_exist
249
+ }.not_to raise_error
250
+
251
+ expect(stderr_io.string).not_to include "Database '#{database_name}'"
252
+ end
253
+ end
254
+ end
255
+
256
+ context 'client.database raise ForbiddenError' do
257
+ it 'not call client.create_database' do
258
+ client.should_receive(:database).with(database_name).and_return { raise TreasureData::ForbiddenError }
259
+ client.should_not_receive(:create_database)
260
+
261
+ call_create_database_and_table_if_not_exist
262
+ expect(stderr_io.string).not_to include "Database '#{database_name}'"
263
+ end
264
+ end
265
+ end
266
+
267
+ describe 'create table' do
268
+ before do
269
+ client.stub(:database)
270
+ end
271
+
272
+ context 'create_log_table success' do
273
+ it 'show message' do
274
+ client.should_receive(:create_log_table).with(database_name, table_name)
275
+
276
+ call_create_database_and_table_if_not_exist
277
+ expect(stderr_io.string).to include "Table '#{database_name}.#{table_name}'"
278
+ end
279
+ end
280
+
281
+ context 'create_log_table raise AlreadyExistsError' do
282
+ it 'resuce in method' do
283
+ client.should_receive(:create_log_table).with(database_name, table_name).and_return { raise TreasureData::AlreadyExistsError }
284
+
285
+ expect {
286
+ call_create_database_and_table_if_not_exist
287
+ }.not_to raise_error
288
+
289
+ expect(stderr_io.string).not_to include "Table '#{database_name}.#{table_name}'"
290
+ end
291
+ end
292
+ end
293
+ end
192
294
  end
data/td.gemspec CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |gem|
21
21
  gem.add_dependency "yajl-ruby", "~> 1.1"
22
22
  gem.add_dependency "hirb", ">= 0.4.5"
23
23
  gem.add_dependency "parallel", "~> 0.6.1"
24
- gem.add_dependency "td-client", "~> 0.8.72"
24
+ gem.add_dependency "td-client", "~> 0.8.73"
25
25
  gem.add_dependency "td-logger", "~> 0.3.21"
26
26
  gem.add_dependency "rubyzip", "~> 1.1.7"
27
27
  gem.add_dependency "zip-zip", "~> 0.3"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: td
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.12
4
+ version: 0.11.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Treasure Data, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-27 00:00:00.000000000 Z
11
+ date: 2015-07-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -102,14 +102,14 @@ dependencies:
102
102
  requirements:
103
103
  - - ~>
104
104
  - !ruby/object:Gem::Version
105
- version: 0.8.72
105
+ version: 0.8.73
106
106
  type: :runtime
107
107
  prerelease: false
108
108
  version_requirements: !ruby/object:Gem::Requirement
109
109
  requirements:
110
110
  - - ~>
111
111
  - !ruby/object:Gem::Version
112
- version: 0.8.72
112
+ version: 0.8.73
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: td-logger
115
115
  requirement: !ruby/object:Gem::Requirement