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 +4 -4
- data/ChangeLog +5 -0
- data/lib/td/command/common.rb +24 -0
- data/lib/td/command/connector.rb +12 -2
- data/lib/td/command/query.rb +2 -3
- data/lib/td/command/table.rb +28 -39
- data/lib/td/version.rb +1 -1
- data/spec/td/command/connector_spec.rb +53 -7
- data/spec/td/command/table_spec.rb +38 -0
- data/spec/td/common_spec.rb +102 -0
- data/td.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 844dda6ec2ea3ce703d94332d12f07da0c8130c1
|
4
|
+
data.tar.gz: 2fe722894996e437589d8841b06dcf0d8da0534d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 467d5b84f145cb1a2e11926b8332018eed6734fab410bbae0271873b4481ea1755c2aea6475e5835cef7981fb3f18605e7a5b8fbe983f9a608fbd2ca447ae12c
|
7
|
+
data.tar.gz: c1fae992cf68fc41304fe1b8326e8d1782ca29ad0b6b52828bb75553f66df0b4aa85ebf33888a0516e04929bbcdd1a406abb6cd25f68b77a043741e1c79ccb3b
|
data/ChangeLog
CHANGED
data/lib/td/command/common.rb
CHANGED
@@ -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
|
data/lib/td/command/connector.rb
CHANGED
@@ -109,13 +109,18 @@ module Command
|
|
109
109
|
|
110
110
|
def connector_issue(op)
|
111
111
|
database = table = nil
|
112
|
-
time_column
|
113
|
-
wait = exclude
|
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."
|
data/lib/td/command/query.rb
CHANGED
@@ -142,11 +142,10 @@ module Command
|
|
142
142
|
|
143
143
|
if wait
|
144
144
|
wait_job(job, true)
|
145
|
-
$stdout.puts "Status
|
145
|
+
$stdout.puts "Status : #{job.status}"
|
146
146
|
if job.success? && !exclude
|
147
|
-
$stdout.puts "Result :"
|
148
147
|
begin
|
149
|
-
|
148
|
+
show_result_with_retry(job, output, limit, format, render_opts)
|
150
149
|
rescue TreasureData::NotFoundError => e
|
151
150
|
end
|
152
151
|
end
|
data/lib/td/command/table.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
|
data/lib/td/version.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
78
|
-
|
79
|
-
|
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
|
-
|
83
|
-
|
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
|
data/spec/td/common_spec.rb
CHANGED
@@ -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.
|
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.
|
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-
|
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.
|
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.
|
112
|
+
version: 0.8.73
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: td-logger
|
115
115
|
requirement: !ruby/object:Gem::Requirement
|