td 0.8.0 → 0.9.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/ChangeLog +6 -0
- data/README.rdoc +19 -2
- data/bin/td +2 -1
- data/lib/td/command/common.rb +21 -64
- data/lib/td/command/{database.rb → db.rb} +42 -31
- data/lib/td/command/help.rb +19 -0
- data/lib/td/command/import.rb +5 -7
- data/lib/td/command/job.rb +235 -0
- data/lib/td/command/list.rb +214 -85
- data/lib/td/command/query.rb +4 -234
- data/lib/td/command/schema.rb +96 -0
- data/lib/td/command/server.rb +1 -3
- data/lib/td/command/table.rb +17 -95
- data/lib/td/command/td.rb +1 -1
- data/lib/td/version.rb +1 -1
- metadata +24 -6
- data/lib/td/command/account.rb +0 -84
data/lib/td/command/list.rb
CHANGED
@@ -3,79 +3,128 @@ module TreasureData
|
|
3
3
|
module Command
|
4
4
|
module List
|
5
5
|
|
6
|
+
class CommandOption < OptionParser
|
7
|
+
def initialize(name, args, description)
|
8
|
+
super()
|
9
|
+
|
10
|
+
@name = name
|
11
|
+
@description = description.to_s
|
12
|
+
|
13
|
+
if args.last.to_s =~ /_$/
|
14
|
+
@varlen = true
|
15
|
+
args.push args.pop.to_s[0..-2]+'...'
|
16
|
+
elsif args.last.to_s =~ /_\?$/
|
17
|
+
@varlen = true
|
18
|
+
args.push args.pop.to_s[0..-3]+'...?'
|
19
|
+
end
|
20
|
+
|
21
|
+
@req_args, opt_args = args.partition {|a| a.to_s !~ /\?$/ }
|
22
|
+
@opt_args = opt_args.map {|a| a.to_s[0..-2].to_sym }
|
23
|
+
@args = @req_args + @opt_args
|
24
|
+
|
25
|
+
@usage_args = "#{@name}"
|
26
|
+
@req_args.each {|a| @usage_args << " <#{a}>" }
|
27
|
+
@opt_args.each {|a| @usage_args << " [#{a}]" }
|
28
|
+
|
29
|
+
@has_options = false
|
30
|
+
|
31
|
+
self.summary_indent = " "
|
32
|
+
|
33
|
+
banner = "usage:\n"
|
34
|
+
banner << " $ #{File.basename($0)} #{@usage_args}\n"
|
35
|
+
banner << "\n"
|
36
|
+
banner << "description:\n"
|
37
|
+
@description.split("\n").each {|l|
|
38
|
+
banner << " #{l}\n"
|
39
|
+
}
|
40
|
+
self.banner = banner
|
41
|
+
|
42
|
+
@message = nil
|
43
|
+
end
|
44
|
+
|
45
|
+
attr_accessor :message
|
46
|
+
|
47
|
+
def message
|
48
|
+
@message || banner
|
49
|
+
end
|
50
|
+
|
51
|
+
def banner
|
52
|
+
s = super.dup
|
53
|
+
if @has_options
|
54
|
+
s << "\n"
|
55
|
+
s << "options:\n"
|
56
|
+
end
|
57
|
+
s << "\n"
|
58
|
+
s
|
59
|
+
end
|
60
|
+
|
61
|
+
def usage
|
62
|
+
"%-40s # %s" % [@usage_args, @description]
|
63
|
+
end
|
64
|
+
|
65
|
+
def cmd_parse(argv=ARGV)
|
66
|
+
parse!(argv)
|
67
|
+
if argv.length < @req_args.length || (!@varlen && argv.length > @args.length)
|
68
|
+
cmd_usage nil
|
69
|
+
end
|
70
|
+
if argv.length <= 1
|
71
|
+
return argv[0]
|
72
|
+
else
|
73
|
+
return argv
|
74
|
+
end
|
75
|
+
rescue
|
76
|
+
cmd_usage $!
|
77
|
+
end
|
78
|
+
|
79
|
+
def cmd_usage(msg=nil)
|
80
|
+
puts self.message
|
81
|
+
if msg
|
82
|
+
puts ""
|
83
|
+
puts "error: #{msg}"
|
84
|
+
end
|
85
|
+
exit 1
|
86
|
+
end
|
87
|
+
|
88
|
+
def group
|
89
|
+
name.split(':', 2).first
|
90
|
+
end
|
91
|
+
|
92
|
+
def on(*args)
|
93
|
+
@has_options = true
|
94
|
+
super
|
95
|
+
end
|
96
|
+
|
97
|
+
attr_reader :name
|
98
|
+
attr_reader :description
|
99
|
+
end
|
100
|
+
|
6
101
|
LIST = []
|
7
|
-
|
102
|
+
COMMAND = {}
|
8
103
|
GUESS = {}
|
104
|
+
HELP_EXCLUDE = ['help', 'account']
|
9
105
|
|
10
|
-
def self.add_list(
|
11
|
-
LIST << [
|
106
|
+
def self.add_list(name, args, description)
|
107
|
+
LIST << COMMAND[name] = CommandOption.new(name, args, description)
|
12
108
|
end
|
13
109
|
|
14
110
|
def self.add_alias(new_cmd, old_cmd)
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.get_description(command)
|
19
|
-
LIST.each {|cmd,file,description|
|
20
|
-
if cmd == command
|
21
|
-
return description
|
22
|
-
end
|
23
|
-
}
|
24
|
-
nil
|
111
|
+
COMMAND[new_cmd] = COMMAND[old_cmd]
|
25
112
|
end
|
26
113
|
|
27
114
|
def self.add_guess(wrong, correct)
|
28
115
|
GUESS[wrong] = correct
|
29
116
|
end
|
30
117
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
add_list 'database', 'drop-database', 'Delete a database'
|
42
|
-
add_list 'table', 'drop-table', 'Delete a table'
|
43
|
-
add_list 'query', 'query', 'Start a query'
|
44
|
-
add_list 'query', 'job', 'Show status and result of a job'
|
45
|
-
add_list 'query', 'show-jobs', 'Show list of jobs'
|
46
|
-
add_list 'import', 'import', 'Import files to a table'
|
47
|
-
add_list 'list', 'version', 'Show version'
|
48
|
-
|
49
|
-
add_alias 'show-dbs', 'show-databases'
|
50
|
-
add_alias 'databases', 'show-databases'
|
51
|
-
add_alias 'dbs', 'show-databases'
|
52
|
-
add_alias 'create-db', 'create-databases'
|
53
|
-
add_alias 'drop-db', 'create-databases'
|
54
|
-
add_alias 'tables', 'show-tables'
|
55
|
-
add_alias 'table', 'describe-table'
|
56
|
-
add_alias 'show-table', 'describe-table'
|
57
|
-
add_alias 'delete-database', 'drop-database'
|
58
|
-
add_alias 'delete-table', 'drop-table'
|
59
|
-
add_alias 'jobs', 'show-jobs'
|
60
|
-
add_alias 'update-schema', 'set-schema'
|
61
|
-
|
62
|
-
add_guess 'create-table', 'create-log-table'
|
63
|
-
add_guess 'drop-log-table', 'drop-table'
|
64
|
-
#add_guess 'drop-item-table', 'drop-table'
|
65
|
-
add_guess 'delete-log-table', 'drop-table'
|
66
|
-
#add_guess 'delete-item-table', 'drop-table'
|
67
|
-
add_guess 'show-job', 'job'
|
68
|
-
|
69
|
-
def self.get_method(command)
|
70
|
-
command = ALIASES[command] || command
|
71
|
-
LIST.each {|cmd,file,description|
|
72
|
-
if cmd == command
|
73
|
-
require 'td/command/common'
|
74
|
-
require "td/command/#{file}"
|
75
|
-
name = command.gsub('-','_')
|
76
|
-
return Object.new.extend(Command).method(name)
|
77
|
-
end
|
78
|
-
}
|
118
|
+
def self.get_method(name)
|
119
|
+
if op = COMMAND[name]
|
120
|
+
name = op.name
|
121
|
+
group, action = op.group
|
122
|
+
require 'td/command/common'
|
123
|
+
require "td/command/#{group}"
|
124
|
+
cmd = name.gsub(':', '_')
|
125
|
+
m = Object.new.extend(Command).method(cmd)
|
126
|
+
return Proc.new { m.call(op) }
|
127
|
+
end
|
79
128
|
nil
|
80
129
|
end
|
81
130
|
|
@@ -85,37 +134,117 @@ module List
|
|
85
134
|
end
|
86
135
|
end
|
87
136
|
|
88
|
-
def self.
|
89
|
-
|
90
|
-
if cmd != 'help'
|
91
|
-
"#{indent}%-18s %s" % [cmd, description.split("\n").first]
|
92
|
-
end
|
93
|
-
}.join("\n")
|
137
|
+
def self.get_option(name)
|
138
|
+
COMMAND[name]
|
94
139
|
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def help
|
98
|
-
op = cmd_opt 'help', :command
|
99
|
-
cmd = op.cmd_parse
|
100
140
|
|
101
|
-
|
102
|
-
|
141
|
+
def self.show_help(indent=' ')
|
142
|
+
before_group = nil
|
143
|
+
LIST.each {|op|
|
144
|
+
next if HELP_EXCLUDE.include?(op.name)
|
145
|
+
if before_group != op.group
|
146
|
+
before_group = op.group
|
147
|
+
puts ""
|
148
|
+
end
|
149
|
+
puts "#{indent}#{op.usage}"
|
150
|
+
}
|
151
|
+
end
|
103
152
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
exit 1
|
153
|
+
def self.get_group(group)
|
154
|
+
LIST.map {|op|
|
155
|
+
op.group == group
|
156
|
+
}
|
109
157
|
end
|
110
158
|
|
111
|
-
|
112
|
-
|
159
|
+
def self.finishup
|
160
|
+
groups = {}
|
161
|
+
LIST.each {|op|
|
162
|
+
(groups[op.group] ||= []) << op
|
163
|
+
}
|
164
|
+
groups.each_pair {|group,ops|
|
165
|
+
if ops.size > 1 && xop = COMMAND[group].dup
|
166
|
+
msg = %[Additional commands, type "#{File.basename($0)} help COMMAND" for more details:\n\n]
|
167
|
+
ops.each {|op|
|
168
|
+
msg << %[ #{op.usage}\n]
|
169
|
+
}
|
170
|
+
msg << %[\n]
|
171
|
+
xop.message = msg
|
172
|
+
COMMAND[group] = xop
|
173
|
+
end
|
174
|
+
}
|
175
|
+
end
|
113
176
|
|
114
|
-
|
115
|
-
|
116
|
-
|
177
|
+
add_list 'db:list', %w[], 'Show list of tables in a database'
|
178
|
+
add_list 'db:show', %w[db], 'Describe a information of a database'
|
179
|
+
add_list 'db:create', %w[db], 'Create a database'
|
180
|
+
add_list 'db:delete', %w[db], 'Delete a database'
|
181
|
+
|
182
|
+
add_list 'table:list', %w[db?], 'Show list of tables'
|
183
|
+
add_list 'table:show', %w[db table], 'Describe a information of a table'
|
184
|
+
add_list 'table:create', %w[db table], 'Create a table'
|
185
|
+
add_list 'table:delete', %w[db table], 'Delete a table'
|
186
|
+
add_list 'table:import', %w[db table files_], 'Parse and import files to a table'
|
187
|
+
|
188
|
+
add_list 'schema:show', %w[db table], 'Show schema of a table'
|
189
|
+
add_list 'schema:set', %w[db table columns_?], 'Set new schema on a table'
|
190
|
+
add_list 'schema:add', %w[db table columns_], 'Add new columns to a table'
|
191
|
+
add_list 'schema:remove', %w[db table columns_], 'Remove columns from a table'
|
192
|
+
|
193
|
+
add_list 'query', %w[sql], 'Issue a query'
|
194
|
+
|
195
|
+
add_list 'job:show', %w[job_id], 'Show status and result of a job'
|
196
|
+
add_list 'job:list', %w[max?], 'Show list of jobs'
|
197
|
+
#add_list 'job:kill', %w[job_id], 'Kill a job'
|
198
|
+
|
199
|
+
add_list 'account', %w[], 'Setup a Treasure Data account'
|
200
|
+
|
201
|
+
add_list 'server:status', %w[], 'Show status of the Treasure Data server'
|
202
|
+
|
203
|
+
add_list 'help', %w[command], 'Show usage of a command'
|
204
|
+
|
205
|
+
# aliases
|
206
|
+
add_alias 'db', 'db:show'
|
207
|
+
add_alias 'dbs', 'db:list'
|
208
|
+
|
209
|
+
add_alias 'database:show', 'db:show'
|
210
|
+
add_alias 'database:list', 'db:list'
|
211
|
+
add_alias 'database:create', 'db:create'
|
212
|
+
add_alias 'database:delete', 'db:delete'
|
213
|
+
add_alias 'database', 'db:show'
|
214
|
+
add_alias 'databases', 'db:list'
|
215
|
+
|
216
|
+
add_alias 'table', 'table:show'
|
217
|
+
add_alias 'tables', 'table:list'
|
218
|
+
|
219
|
+
add_alias 'schema', 'schema:show'
|
220
|
+
|
221
|
+
add_alias 'job', 'job:show'
|
222
|
+
add_alias 'jobs', 'job:list'
|
223
|
+
|
224
|
+
# backward compatibility
|
225
|
+
add_alias 'show-databases', 'db:list'
|
226
|
+
add_alias 'show-dbs', 'db:list'
|
227
|
+
add_alias 'create-database', 'db:create'
|
228
|
+
add_alias 'create-db', 'db:create'
|
229
|
+
add_alias 'drop-database', 'db:delete'
|
230
|
+
add_alias 'drop-db', 'db:delete'
|
231
|
+
add_alias 'delete-database', 'db:delete'
|
232
|
+
add_alias 'delete-db', 'db:delete'
|
233
|
+
add_alias 'show-tables', 'table:list'
|
234
|
+
add_alias 'show-table', 'table:show'
|
235
|
+
add_alias 'create-log-table', 'table:create'
|
236
|
+
add_alias 'create-table', 'table:create'
|
237
|
+
add_alias 'drop-log-table', 'table:delete'
|
238
|
+
add_alias 'drop-table', 'table:delete'
|
239
|
+
add_alias 'delete-log-table', 'table:delete'
|
240
|
+
add_alias 'delete-table', 'table:delete'
|
241
|
+
add_guess 'show-job', 'job:show'
|
242
|
+
add_guess 'show-jobs', 'job:list'
|
243
|
+
add_guess 'server-status', 'server:status'
|
244
|
+
add_alias 'import', 'table:import'
|
245
|
+
|
246
|
+
finishup
|
117
247
|
end
|
118
|
-
|
119
248
|
end
|
120
249
|
end
|
121
250
|
|
data/lib/td/command/query.rb
CHANGED
@@ -2,11 +2,7 @@
|
|
2
2
|
module TreasureData
|
3
3
|
module Command
|
4
4
|
|
5
|
-
def query
|
6
|
-
op = cmd_opt 'query', :sql
|
7
|
-
|
8
|
-
op.banner << "\noptions:\n"
|
9
|
-
|
5
|
+
def query(op)
|
10
6
|
db_name = nil
|
11
7
|
wait = false
|
12
8
|
output = nil
|
@@ -37,12 +33,12 @@ module Command
|
|
37
33
|
exit 1
|
38
34
|
end
|
39
35
|
|
40
|
-
|
36
|
+
get_database(client, db_name)
|
41
37
|
|
42
38
|
job = client.query(db_name, sql)
|
43
39
|
|
44
40
|
$stderr.puts "Job #{job.job_id} is started."
|
45
|
-
$stderr.puts "Use '#{$prog} job #{job.job_id}' to show the status."
|
41
|
+
$stderr.puts "Use '#{$prog} job:show #{job.job_id}' to show the status."
|
46
42
|
$stderr.puts "See #{job.url} to see the progress."
|
47
43
|
|
48
44
|
if wait && !job.finished?
|
@@ -55,233 +51,7 @@ module Command
|
|
55
51
|
end
|
56
52
|
end
|
57
53
|
|
58
|
-
|
59
|
-
op = cmd_opt 'show-jobs', :max?
|
60
|
-
|
61
|
-
op.banner << "\noptions:\n"
|
62
|
-
|
63
|
-
page = 0
|
64
|
-
skip = 0
|
65
|
-
|
66
|
-
op.on('-p', '--page PAGE', 'skip N pages', Integer) {|i|
|
67
|
-
page = i
|
68
|
-
}
|
69
|
-
op.on('-s', '--skip N', 'skip N jobs', Integer) {|i|
|
70
|
-
skip = i
|
71
|
-
}
|
72
|
-
|
73
|
-
max = op.cmd_parse
|
74
|
-
|
75
|
-
max = (max || 20).to_i
|
76
|
-
|
77
|
-
client = get_client
|
78
|
-
|
79
|
-
if page
|
80
|
-
skip += max * page
|
81
|
-
end
|
82
|
-
jobs = client.jobs(skip, skip+max-1)
|
83
|
-
|
84
|
-
rows = []
|
85
|
-
jobs.each {|job|
|
86
|
-
start = job.start_at
|
87
|
-
finish = job.end_at
|
88
|
-
if start
|
89
|
-
if !finish
|
90
|
-
finish = Time.now.utc
|
91
|
-
end
|
92
|
-
e = finish.to_i - start.to_i
|
93
|
-
elapsed = ''
|
94
|
-
if e >= 3600
|
95
|
-
elapsed << "#{e/3600}h "
|
96
|
-
e %= 3600
|
97
|
-
elapsed << "% 2dm " % (e/60)
|
98
|
-
e %= 60
|
99
|
-
elapsed << "% 2dsec" % e
|
100
|
-
elsif e >= 60
|
101
|
-
elapsed << "% 2dm " % (e/60)
|
102
|
-
e %= 60
|
103
|
-
elapsed << "% 2dsec" % e
|
104
|
-
else
|
105
|
-
elapsed << "% 2dsec" % e
|
106
|
-
end
|
107
|
-
else
|
108
|
-
elapsed = ''
|
109
|
-
end
|
110
|
-
elapsed = "% 10s" % elapsed # right aligned
|
111
|
-
|
112
|
-
rows << {:JobID => job.job_id, :Status => job.status, :Query => job.query.to_s, :Start => start, :Elapsed => elapsed}
|
113
|
-
}
|
114
|
-
|
115
|
-
puts cmd_render_table(rows, :fields => [:JobID, :Status, :Start, :Elapsed, :Query])
|
116
|
-
end
|
117
|
-
|
118
|
-
def job
|
119
|
-
op = cmd_opt 'job', :job_id
|
120
|
-
|
121
|
-
op.banner << "\noptions:\n"
|
122
|
-
|
123
|
-
verbose = nil
|
124
|
-
wait = false
|
125
|
-
output = nil
|
126
|
-
format = 'tsv'
|
127
|
-
|
128
|
-
op.on('-v', '--verbose', 'show logs', TrueClass) {|b|
|
129
|
-
verbose = b
|
130
|
-
}
|
131
|
-
op.on('-w', '--wait', 'wait for finishing the job', TrueClass) {|b|
|
132
|
-
wait = b
|
133
|
-
}
|
134
|
-
op.on('-o', '--output PATH', 'write result to the file') {|s|
|
135
|
-
output = s
|
136
|
-
}
|
137
|
-
op.on('-f', '--format FORMAT', 'format of the result to write to the file (tsv, csv, json or msgpack)') {|s|
|
138
|
-
unless ['tsv', 'csv', 'json', 'msgpack'].include?(s)
|
139
|
-
raise "Unknown format #{s.dump}. Supported format: tsv, csv, json, msgpack"
|
140
|
-
end
|
141
|
-
format = s
|
142
|
-
}
|
143
|
-
|
144
|
-
job_id = op.cmd_parse
|
145
|
-
|
146
|
-
client = get_client
|
147
|
-
|
148
|
-
job = client.job(job_id)
|
149
|
-
|
150
|
-
puts "JobID : #{job.job_id}"
|
151
|
-
puts "URL : #{job.url}"
|
152
|
-
puts "Status : #{job.status}"
|
153
|
-
puts "Query : #{job.query}"
|
154
|
-
|
155
|
-
if wait && !job.finished?
|
156
|
-
wait_job(job)
|
157
|
-
if job.success?
|
158
|
-
puts "Result :"
|
159
|
-
show_result(job, output, format)
|
160
|
-
end
|
161
|
-
|
162
|
-
else
|
163
|
-
if job.success?
|
164
|
-
puts "Result :"
|
165
|
-
show_result(job, output, format)
|
166
|
-
end
|
167
|
-
|
168
|
-
if verbose
|
169
|
-
puts ""
|
170
|
-
puts "cmdout:"
|
171
|
-
job.debug['cmdout'].to_s.split("\n").each {|line|
|
172
|
-
puts " "+line
|
173
|
-
}
|
174
|
-
puts ""
|
175
|
-
puts "stderr:"
|
176
|
-
job.debug['stderr'].to_s.split("\n").each {|line|
|
177
|
-
puts " "+line
|
178
|
-
}
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
$stderr.puts "Use '-v' option to show detailed messages." unless verbose
|
183
|
-
end
|
184
|
-
|
185
|
-
private
|
186
|
-
def wait_job(job)
|
187
|
-
$stderr.puts "running..."
|
188
|
-
|
189
|
-
cmdout_lines = 0
|
190
|
-
stderr_lines = 0
|
191
|
-
|
192
|
-
until job.finished?
|
193
|
-
sleep 2
|
194
|
-
|
195
|
-
job.update_status!
|
196
|
-
|
197
|
-
cmdout = job.debug['cmdout'].to_s.split("\n")[cmdout_lines..-1] || []
|
198
|
-
stderr = job.debug['stderr'].to_s.split("\n")[stderr_lines..-1] || []
|
199
|
-
(cmdout + stderr).each {|line|
|
200
|
-
puts " "+line
|
201
|
-
}
|
202
|
-
cmdout_lines += cmdout.size
|
203
|
-
stderr_lines += stderr.size
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
def show_result(job, output, format)
|
208
|
-
if output
|
209
|
-
write_result(job, output, format)
|
210
|
-
puts "written to #{output} in #{format} format"
|
211
|
-
else
|
212
|
-
render_result(job)
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
def write_result(job, output, format)
|
217
|
-
case format
|
218
|
-
when 'json'
|
219
|
-
require 'json'
|
220
|
-
first = true
|
221
|
-
File.open(output, "w") {|f|
|
222
|
-
f.write "["
|
223
|
-
job.result_each {|row|
|
224
|
-
if first
|
225
|
-
first = false
|
226
|
-
else
|
227
|
-
f.write ","
|
228
|
-
end
|
229
|
-
f.write row.to_json
|
230
|
-
}
|
231
|
-
f.write "]"
|
232
|
-
}
|
233
|
-
|
234
|
-
when 'msgpack'
|
235
|
-
File.open(output, "w") {|f|
|
236
|
-
f.write job.result_format('msgpack')
|
237
|
-
}
|
238
|
-
|
239
|
-
when 'csv'
|
240
|
-
require 'json'
|
241
|
-
require 'csv'
|
242
|
-
CSV.open(output, "w") {|writer|
|
243
|
-
job.result_each {|row|
|
244
|
-
writer << row.map {|col| col.is_a?(String) ? col.to_s : col.to_json }
|
245
|
-
}
|
246
|
-
}
|
247
|
-
|
248
|
-
when 'tsv'
|
249
|
-
require 'json'
|
250
|
-
File.open(output, "w") {|f|
|
251
|
-
job.result_each {|row|
|
252
|
-
first = true
|
253
|
-
row.each {|col|
|
254
|
-
if first
|
255
|
-
first = false
|
256
|
-
else
|
257
|
-
f.write "\t"
|
258
|
-
end
|
259
|
-
f.write col.is_a?(String) ? col.to_s : col.to_json
|
260
|
-
}
|
261
|
-
f.write "\n"
|
262
|
-
}
|
263
|
-
}
|
264
|
-
|
265
|
-
else
|
266
|
-
raise "Unknown format #{format.inspect}"
|
267
|
-
end
|
268
|
-
end
|
269
|
-
|
270
|
-
def render_result(job)
|
271
|
-
require 'json'
|
272
|
-
rows = []
|
273
|
-
job.result_each {|row|
|
274
|
-
# TODO limit number of rows to show
|
275
|
-
rows << row.map {|v|
|
276
|
-
if v.is_a?(String)
|
277
|
-
v.to_s
|
278
|
-
else
|
279
|
-
v.to_json
|
280
|
-
end
|
281
|
-
}
|
282
|
-
}
|
283
|
-
puts cmd_render_table(rows, :max_width=>10000)
|
284
|
-
end
|
54
|
+
require 'td/command/job' # wait_job
|
285
55
|
end
|
286
56
|
end
|
287
57
|
|