td 0.10.4 → 0.10.5
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 +11 -0
- data/lib/td/command/aggr.rb +202 -0
- data/lib/td/command/common.rb +32 -6
- data/lib/td/command/help.rb +11 -3
- data/lib/td/command/import.rb +8 -0
- data/lib/td/command/job.rb +22 -34
- data/lib/td/command/list.rb +163 -106
- data/lib/td/command/query.rb +5 -1
- data/lib/td/command/result.rb +111 -0
- data/lib/td/command/runner.rb +20 -4
- data/lib/td/command/sched.rb +9 -5
- data/lib/td/command/status.rb +89 -0
- data/lib/td/command/table.rb +21 -2
- data/lib/td/version.rb +1 -1
- metadata +16 -13
data/ChangeLog
CHANGED
@@ -1,4 +1,15 @@
|
|
1
1
|
|
2
|
+
== 2011-12-04 version 0.10.5
|
3
|
+
|
4
|
+
* Added new feature: result
|
5
|
+
* Added new feature: status
|
6
|
+
* Refined usage message
|
7
|
+
* Fixed argument length check
|
8
|
+
* help subcommand shows commandline examples
|
9
|
+
* table:tail subcommand reduced default max row number
|
10
|
+
* job:list subcommand supports --running and --error options
|
11
|
+
|
12
|
+
|
2
13
|
== 2011-11-11 version 0.10.4
|
3
14
|
|
4
15
|
* Updated dependency: td-logger-0.3.7
|
@@ -0,0 +1,202 @@
|
|
1
|
+
|
2
|
+
module TreasureData
|
3
|
+
module Command
|
4
|
+
|
5
|
+
def aggr_list(op)
|
6
|
+
op.cmd_parse
|
7
|
+
|
8
|
+
client = get_client
|
9
|
+
|
10
|
+
ass = client.aggregation_schemas
|
11
|
+
|
12
|
+
rows = []
|
13
|
+
ass.each {|as|
|
14
|
+
rows << {:Name=>as.name, :Relation=>as.relation_key}
|
15
|
+
}
|
16
|
+
|
17
|
+
puts cmd_render_table(rows, :fields => [:Name, :Relation])
|
18
|
+
|
19
|
+
if rows.empty?
|
20
|
+
$stderr.puts "There are no aggregation schemas."
|
21
|
+
$stderr.puts "Use '#{$prog} aggr:create <name>' to create a aggregation schema."
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def aggr_show(op)
|
26
|
+
name = op.cmd_parse
|
27
|
+
|
28
|
+
client = get_client
|
29
|
+
|
30
|
+
begin
|
31
|
+
as = client.aggregation_schema(name)
|
32
|
+
rescue
|
33
|
+
cmd_debug_error $!
|
34
|
+
$stderr.puts "Aggregation '#{name}' does not exist."
|
35
|
+
exit 1
|
36
|
+
end
|
37
|
+
|
38
|
+
log_rows = []
|
39
|
+
as.logs.each {|las|
|
40
|
+
log_rows << {
|
41
|
+
:Table=>las.table.identifier,
|
42
|
+
:Name=>las.name,
|
43
|
+
:o1_key=>las.okeys[0].to_s,
|
44
|
+
:o2_key=>las.okeys[1].to_s,
|
45
|
+
:o3_key=>las.okeys[2].to_s,
|
46
|
+
:value_key=>las.value_key.to_s,
|
47
|
+
:count_key=>las.count_key.to_s,
|
48
|
+
:Comment=>las.comment.to_s
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
attr_rows = []
|
53
|
+
as.attributes.each {|aas|
|
54
|
+
params = aas.parameters.to_a.map {|k,v| "#{k}=#{v}" }.join(' ')
|
55
|
+
attr_rows << {
|
56
|
+
:Table=>aas.table.identifier,
|
57
|
+
:Name=>aas.name,
|
58
|
+
:Method=>aas.method_name,
|
59
|
+
:Parameters=>params,
|
60
|
+
:Comment=>aas.comment.to_s,
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
puts "Log entries:"
|
65
|
+
puts cmd_render_table(log_rows, :fields => [:Table, :Name, :o1_key, :o2_key, :o3_key, :value_key, :count_key, :Comment], :max_width=>400)
|
66
|
+
|
67
|
+
puts ''
|
68
|
+
|
69
|
+
puts "Attribute entries:"
|
70
|
+
puts cmd_render_table(attr_rows, :fields => [:Table, :Name, :Method, :Parameters, :Comment], :max_width=>400)
|
71
|
+
end
|
72
|
+
|
73
|
+
def aggr_create(op)
|
74
|
+
name, relation_key = op.cmd_parse
|
75
|
+
|
76
|
+
client = get_client
|
77
|
+
|
78
|
+
begin
|
79
|
+
client.create_aggregation_schema(name, relation_key)
|
80
|
+
rescue AlreadyExistsError
|
81
|
+
cmd_debug_error $!
|
82
|
+
$stderr.puts "Aggregation '#{name}' already exists."
|
83
|
+
exit 1
|
84
|
+
end
|
85
|
+
|
86
|
+
$stderr.puts "Aggregation schema '#{name}' is created."
|
87
|
+
end
|
88
|
+
|
89
|
+
def aggr_delete(op)
|
90
|
+
name = op.cmd_parse
|
91
|
+
|
92
|
+
client = get_client
|
93
|
+
|
94
|
+
client.delete_aggregation_schema(name)
|
95
|
+
|
96
|
+
$stderr.puts "Aggregation schema '#{name}' is deleted."
|
97
|
+
end
|
98
|
+
|
99
|
+
def aggr_add_log(op)
|
100
|
+
comment = nil
|
101
|
+
value_key = nil
|
102
|
+
count_key = nil
|
103
|
+
|
104
|
+
op.on('-m', '--comment COMMENT', 'comment of this entry') {|s|
|
105
|
+
comment = s
|
106
|
+
}
|
107
|
+
op.on('-v', '--value KEY_NAME', 'key name of value field') {|s|
|
108
|
+
value_key = s
|
109
|
+
}
|
110
|
+
op.on('-c', '--count KEY_NAME', 'key name of count field') {|s|
|
111
|
+
count_key = s
|
112
|
+
}
|
113
|
+
|
114
|
+
name, db_name, table_name, entry_name, o1_key, o2_key, o3_key = op.cmd_parse
|
115
|
+
|
116
|
+
okeys = [o1_key, o2_key, o3_key].compact
|
117
|
+
|
118
|
+
client = get_client
|
119
|
+
|
120
|
+
get_table(client, db_name, table_name)
|
121
|
+
|
122
|
+
begin
|
123
|
+
client.create_aggregation_log_entry(name, entry_name, comment, db_name, table_name, okeys, value_key, count_key)
|
124
|
+
rescue NotFoundError
|
125
|
+
cmd_debug_error $!
|
126
|
+
$stderr.puts "Aggregation schema '#{name}' does not exist."
|
127
|
+
$stderr.puts "Use '#{$prog} aggr:create #{name}' to create the aggregation schema."
|
128
|
+
exit 1
|
129
|
+
rescue AlreadyExistsError
|
130
|
+
$stderr.puts "Aggregation log entry '#{entry_name}' already exists."
|
131
|
+
exit 1
|
132
|
+
end
|
133
|
+
|
134
|
+
$stderr.puts "Aggregation log entry '#{entry_name}' is created."
|
135
|
+
end
|
136
|
+
|
137
|
+
def aggr_add_attr(op)
|
138
|
+
comment = nil
|
139
|
+
|
140
|
+
op.on('-m', '--comment COMMENT', 'comment of this entry') {|s|
|
141
|
+
comment = s
|
142
|
+
}
|
143
|
+
|
144
|
+
name, db_name, table_name, entry_name, method_name, *parameters = op.cmd_parse
|
145
|
+
|
146
|
+
params = {}
|
147
|
+
parameters.each {|pa|
|
148
|
+
k, v = pa.split('=')
|
149
|
+
params[k] = v
|
150
|
+
}
|
151
|
+
|
152
|
+
client = get_client
|
153
|
+
|
154
|
+
get_table(client, db_name, table_name)
|
155
|
+
|
156
|
+
begin
|
157
|
+
client.create_aggregation_attr_entry(name, entry_name, comment, db_name, table_name, method_name, params)
|
158
|
+
rescue NotFoundError
|
159
|
+
cmd_debug_error $!
|
160
|
+
$stderr.puts "Aggregation schema '#{name}' does not exist."
|
161
|
+
$stderr.puts "Use '#{$prog} aggr:create #{name}' to create the aggregation schema."
|
162
|
+
exit 1
|
163
|
+
rescue AlreadyExistsError
|
164
|
+
$stderr.puts "Aggregation attribute entry '#{entry_name}' already exists."
|
165
|
+
exit 1
|
166
|
+
end
|
167
|
+
|
168
|
+
$stderr.puts "Aggregation attribute entry '#{entry_name}' is created."
|
169
|
+
end
|
170
|
+
|
171
|
+
def aggr_del_log(op)
|
172
|
+
name, entry_name = op.cmd_parse
|
173
|
+
|
174
|
+
client = get_client
|
175
|
+
|
176
|
+
begin
|
177
|
+
client.delete_aggregation_log_entry(name, entry_name)
|
178
|
+
rescue NotFoundError
|
179
|
+
$stderr.puts "Aggregation log entry '#{entry_name}' does not exist."
|
180
|
+
exit 1
|
181
|
+
end
|
182
|
+
|
183
|
+
$stderr.puts "Aggregation log entry '#{entry_name}' is deleted."
|
184
|
+
end
|
185
|
+
|
186
|
+
def aggr_del_attr(op)
|
187
|
+
name, entry_name = op.cmd_parse
|
188
|
+
|
189
|
+
client = get_client
|
190
|
+
|
191
|
+
begin
|
192
|
+
client.delete_aggregation_attr_entry(name, entry_name)
|
193
|
+
rescue NotFoundError
|
194
|
+
$stderr.puts "Aggregation log entry '#{entry_name}' does not exist."
|
195
|
+
exit 1
|
196
|
+
end
|
197
|
+
|
198
|
+
$stderr.puts "Aggregation log entry '#{entry_name}' is deleted."
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
end
|
data/lib/td/command/common.rb
CHANGED
@@ -11,8 +11,8 @@ autoload :Job, 'td/client'
|
|
11
11
|
module Command
|
12
12
|
|
13
13
|
private
|
14
|
-
def
|
15
|
-
|
14
|
+
def initialize
|
15
|
+
@render_indent = ''
|
16
16
|
end
|
17
17
|
|
18
18
|
def get_client
|
@@ -28,10 +28,10 @@ module Command
|
|
28
28
|
Hirb::Helpers::Table.render(rows, *opts)
|
29
29
|
end
|
30
30
|
|
31
|
-
def cmd_render_tree(nodes, *opts)
|
32
|
-
|
33
|
-
|
34
|
-
end
|
31
|
+
#def cmd_render_tree(nodes, *opts)
|
32
|
+
# require 'hirb'
|
33
|
+
# Hirb::Helpers::Tree.render(nodes, *opts)
|
34
|
+
#end
|
35
35
|
|
36
36
|
def cmd_debug_error(ex)
|
37
37
|
if $verbose
|
@@ -43,6 +43,32 @@ module Command
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
def cmd_format_elapsed(start, finish)
|
47
|
+
if start
|
48
|
+
if !finish
|
49
|
+
finish = Time.now.utc
|
50
|
+
end
|
51
|
+
e = finish.to_i - start.to_i
|
52
|
+
elapsed = ''
|
53
|
+
if e >= 3600
|
54
|
+
elapsed << "#{e/3600}h "
|
55
|
+
e %= 3600
|
56
|
+
elapsed << "% 2dm " % (e/60)
|
57
|
+
e %= 60
|
58
|
+
elapsed << "% 2dsec" % e
|
59
|
+
elsif e >= 60
|
60
|
+
elapsed << "% 2dm " % (e/60)
|
61
|
+
e %= 60
|
62
|
+
elapsed << "% 2dsec" % e
|
63
|
+
else
|
64
|
+
elapsed << "% 2dsec" % e
|
65
|
+
end
|
66
|
+
else
|
67
|
+
elapsed = ''
|
68
|
+
end
|
69
|
+
elapsed = "% 10s" % elapsed # right aligned
|
70
|
+
end
|
71
|
+
|
46
72
|
def get_database(client, db_name)
|
47
73
|
begin
|
48
74
|
return client.database(db_name)
|
data/lib/td/command/help.rb
CHANGED
@@ -5,14 +5,22 @@ module Command
|
|
5
5
|
def help(op)
|
6
6
|
cmd = op.cmd_parse
|
7
7
|
|
8
|
-
|
9
|
-
unless
|
8
|
+
usage = List.cmd_usage(cmd)
|
9
|
+
unless usage
|
10
10
|
$stderr.puts "'#{cmd}' is not a td command. Run '#{$prog}' to show the list."
|
11
11
|
List.show_guess(cmd)
|
12
12
|
exit 1
|
13
13
|
end
|
14
14
|
|
15
|
-
puts
|
15
|
+
puts usage
|
16
|
+
end
|
17
|
+
|
18
|
+
def help_all(op)
|
19
|
+
cmd = op.cmd_parse
|
20
|
+
|
21
|
+
TreasureData::Command::List.show_help(op.summary_indent)
|
22
|
+
puts ""
|
23
|
+
puts "Type '#{$prog} help COMMAND' for more information on a specific command."
|
16
24
|
end
|
17
25
|
|
18
26
|
end
|
data/lib/td/command/import.rb
CHANGED
@@ -222,6 +222,10 @@ module Command
|
|
222
222
|
begin
|
223
223
|
record = JSON.parse(line)
|
224
224
|
|
225
|
+
unless record.is_a?(Hash)
|
226
|
+
raise "record must be a Hash"
|
227
|
+
end
|
228
|
+
|
225
229
|
time = record[@time_key]
|
226
230
|
unless time
|
227
231
|
raise "record doesn't have '#{@time_key}' column"
|
@@ -255,6 +259,10 @@ module Command
|
|
255
259
|
MessagePack::Unpacker.new(file).each {|record|
|
256
260
|
i += 1
|
257
261
|
begin
|
262
|
+
unless record.is_a?(Hash)
|
263
|
+
raise "record must be a Hash"
|
264
|
+
end
|
265
|
+
|
258
266
|
time = record[@time_key]
|
259
267
|
unless time
|
260
268
|
raise "record doesn't have '#{@time_key}' column"
|
data/lib/td/command/job.rb
CHANGED
@@ -5,6 +5,8 @@ module Command
|
|
5
5
|
def job_list(op)
|
6
6
|
page = 0
|
7
7
|
skip = 0
|
8
|
+
running = false
|
9
|
+
error = false
|
8
10
|
|
9
11
|
op.on('-p', '--page PAGE', 'skip N pages', Integer) {|i|
|
10
12
|
page = i
|
@@ -12,6 +14,12 @@ module Command
|
|
12
14
|
op.on('-s', '--skip N', 'skip N jobs', Integer) {|i|
|
13
15
|
skip = i
|
14
16
|
}
|
17
|
+
op.on('-R', '--running', 'show only running jobs', TrueClass) {|b|
|
18
|
+
running = b
|
19
|
+
}
|
20
|
+
op.on('-E', '--error', 'show only error jobs', TrueClass) {|b|
|
21
|
+
error = b
|
22
|
+
}
|
15
23
|
|
16
24
|
max = op.cmd_parse
|
17
25
|
|
@@ -26,36 +34,14 @@ module Command
|
|
26
34
|
|
27
35
|
rows = []
|
28
36
|
jobs.each {|job|
|
37
|
+
next if running && !job.running?
|
38
|
+
next if error && !job.error?
|
29
39
|
start = job.start_at
|
30
|
-
|
31
|
-
|
32
|
-
if !finish
|
33
|
-
finish = Time.now.utc
|
34
|
-
end
|
35
|
-
e = finish.to_i - start.to_i
|
36
|
-
elapsed = ''
|
37
|
-
if e >= 3600
|
38
|
-
elapsed << "#{e/3600}h "
|
39
|
-
e %= 3600
|
40
|
-
elapsed << "% 2dm " % (e/60)
|
41
|
-
e %= 60
|
42
|
-
elapsed << "% 2dsec" % e
|
43
|
-
elsif e >= 60
|
44
|
-
elapsed << "% 2dm " % (e/60)
|
45
|
-
e %= 60
|
46
|
-
elapsed << "% 2dsec" % e
|
47
|
-
else
|
48
|
-
elapsed << "% 2dsec" % e
|
49
|
-
end
|
50
|
-
else
|
51
|
-
elapsed = ''
|
52
|
-
end
|
53
|
-
elapsed = "% 10s" % elapsed # right aligned
|
54
|
-
|
55
|
-
rows << {:JobID => job.job_id, :Status => job.status, :Query => job.query.to_s, :Start => (start ? start.localtime : ''), :Elapsed => elapsed}
|
40
|
+
elapsed = cmd_format_elapsed(start, job.end_at)
|
41
|
+
rows << {:JobID => job.job_id, :Status => job.status, :Query => job.query.to_s, :Start => (start ? start.localtime : ''), :Elapsed => elapsed, :Result => job.rset_name}
|
56
42
|
}
|
57
43
|
|
58
|
-
puts cmd_render_table(rows, :fields => [:JobID, :Status, :Start, :Elapsed, :Query])
|
44
|
+
puts cmd_render_table(rows, :fields => [:JobID, :Status, :Start, :Elapsed, :Result, :Query])
|
59
45
|
end
|
60
46
|
|
61
47
|
def job_show(op)
|
@@ -86,21 +72,22 @@ module Command
|
|
86
72
|
|
87
73
|
job = client.job(job_id)
|
88
74
|
|
89
|
-
puts "JobID
|
90
|
-
puts "URL
|
91
|
-
puts "Status
|
92
|
-
puts "Query
|
75
|
+
puts "JobID : #{job.job_id}"
|
76
|
+
puts "URL : #{job.url}"
|
77
|
+
puts "Status : #{job.status}"
|
78
|
+
puts "Query : #{job.query}"
|
79
|
+
puts "Result table : #{job.rset_name}"
|
93
80
|
|
94
81
|
if wait && !job.finished?
|
95
82
|
wait_job(job)
|
96
83
|
if job.success?
|
97
|
-
puts "Result
|
84
|
+
puts "Result :"
|
98
85
|
show_result(job, output, format)
|
99
86
|
end
|
100
87
|
|
101
88
|
else
|
102
89
|
if job.success?
|
103
|
-
puts "Result
|
90
|
+
puts "Result :"
|
104
91
|
show_result(job, output, format)
|
105
92
|
end
|
106
93
|
|
@@ -231,7 +218,8 @@ module Command
|
|
231
218
|
# TODO limit number of rows to show
|
232
219
|
rows << row.map {|v|
|
233
220
|
if v.is_a?(String)
|
234
|
-
|
221
|
+
# TODO encoding check
|
222
|
+
v.to_s.force_encoding('ASCII-8BIT')
|
235
223
|
else
|
236
224
|
v.to_json
|
237
225
|
end
|
data/lib/td/command/list.rb
CHANGED
@@ -3,69 +3,36 @@ module TreasureData
|
|
3
3
|
module Command
|
4
4
|
module List
|
5
5
|
|
6
|
-
class
|
7
|
-
def initialize(name,
|
6
|
+
class CommandParser < OptionParser
|
7
|
+
def initialize(name, req_args, opt_args, varlen, argv)
|
8
8
|
super()
|
9
|
-
|
10
|
-
@
|
11
|
-
@
|
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
|
-
|
9
|
+
@req_args = req_args
|
10
|
+
@opt_args = opt_args
|
11
|
+
@varlen = varlen
|
12
|
+
@argv = argv
|
29
13
|
@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
|
-
@argv = nil
|
14
|
+
@message = ''
|
44
15
|
end
|
45
16
|
|
46
|
-
attr_accessor :message
|
17
|
+
attr_accessor :message
|
47
18
|
|
48
|
-
def
|
49
|
-
@
|
19
|
+
def on(*argv)
|
20
|
+
@has_options = true
|
21
|
+
super
|
50
22
|
end
|
51
23
|
|
52
24
|
def banner
|
53
|
-
s =
|
25
|
+
s = @message.dup
|
54
26
|
if @has_options
|
55
27
|
s << "\n"
|
56
28
|
s << "options:\n"
|
57
29
|
end
|
58
|
-
s << "\n"
|
59
30
|
s
|
60
31
|
end
|
61
32
|
|
62
|
-
def usage
|
63
|
-
"%-40s # %s" % [@usage_args, @description]
|
64
|
-
end
|
65
|
-
|
66
33
|
def cmd_parse(argv=@argv||ARGV)
|
67
34
|
parse!(argv)
|
68
|
-
if argv.length < @req_args.length || (!@varlen && argv.length > @
|
35
|
+
if argv.length < @req_args.length || (!@varlen && argv.length > (@req_args.length+@opt_args.length))
|
69
36
|
cmd_usage nil
|
70
37
|
end
|
71
38
|
if argv.length <= 1
|
@@ -78,40 +45,92 @@ module List
|
|
78
45
|
end
|
79
46
|
|
80
47
|
def cmd_usage(msg=nil)
|
81
|
-
puts self.
|
82
|
-
if msg
|
83
|
-
puts ""
|
84
|
-
puts "error: #{msg}"
|
85
|
-
end
|
48
|
+
puts self.to_s
|
49
|
+
puts "error: #{msg}" if msg
|
86
50
|
exit 1
|
87
51
|
end
|
52
|
+
end
|
88
53
|
|
89
|
-
|
90
|
-
|
54
|
+
class CommandOption
|
55
|
+
def initialize(name, args, description, examples)
|
56
|
+
@name = name
|
57
|
+
@args = args
|
58
|
+
@description = description.to_s
|
59
|
+
@examples = examples
|
60
|
+
@override_message = nil
|
91
61
|
end
|
92
62
|
|
93
|
-
|
94
|
-
|
95
|
-
|
63
|
+
attr_reader :name, :args, :description, :examples
|
64
|
+
attr_accessor :override_message
|
65
|
+
|
66
|
+
def compile!
|
67
|
+
return if @usage_args
|
68
|
+
|
69
|
+
args = @args.dup
|
70
|
+
if args.last.to_s =~ /_$/
|
71
|
+
@varlen = true
|
72
|
+
args.push args.pop.to_s[0..-2]+'...'
|
73
|
+
elsif args.last.to_s =~ /_\?$/
|
74
|
+
@varlen = true
|
75
|
+
args.push args.pop.to_s[0..-3]+'...?'
|
76
|
+
end
|
77
|
+
|
78
|
+
@req_args, @opt_args = args.partition {|a| a.to_s !~ /\?$/ }
|
79
|
+
@opt_args = @opt_args.map {|a| a.to_s[0..-2].to_sym }
|
80
|
+
|
81
|
+
@usage_args = "#{@name}"
|
82
|
+
@req_args.each {|a| @usage_args << " <#{a}>" }
|
83
|
+
@opt_args.each {|a| @usage_args << " [#{a}]" }
|
96
84
|
end
|
97
85
|
|
98
|
-
def
|
99
|
-
|
100
|
-
|
101
|
-
|
86
|
+
def create_optparse(argv)
|
87
|
+
compile!
|
88
|
+
op = CommandParser.new(@name, @req_args, @opt_args, @varlen, argv)
|
89
|
+
|
90
|
+
message = "usage:\n"
|
91
|
+
message << " $ #{File.basename($0)} #{@usage_args}\n"
|
92
|
+
unless @examples.empty?
|
93
|
+
message << "\n"
|
94
|
+
message << "example:\n"
|
95
|
+
@examples.each {|l|
|
96
|
+
message << " $ #{File.basename($0)} #{l}\n"
|
97
|
+
}
|
98
|
+
end
|
99
|
+
message << "\n"
|
100
|
+
message << "description:\n"
|
101
|
+
@description.split("\n").each {|l|
|
102
|
+
message << " #{l}\n"
|
103
|
+
}
|
104
|
+
|
105
|
+
op.message = message
|
106
|
+
op.summary_indent = " "
|
107
|
+
|
108
|
+
if msg = @override_message
|
109
|
+
(class<<op;self;end).module_eval do
|
110
|
+
define_method(:to_s) { msg }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
op
|
115
|
+
end
|
116
|
+
|
117
|
+
def usage
|
118
|
+
compile!
|
119
|
+
"%-40s # %s" % [@usage_args, @description]
|
102
120
|
end
|
103
121
|
|
104
|
-
|
105
|
-
|
122
|
+
def group
|
123
|
+
@name.split(':', 2).first
|
124
|
+
end
|
106
125
|
end
|
107
126
|
|
108
127
|
LIST = []
|
109
128
|
COMMAND = {}
|
110
129
|
GUESS = {}
|
111
|
-
HELP_EXCLUDE = [
|
130
|
+
HELP_EXCLUDE = [/^help/, /^account/, /^aggr/]
|
112
131
|
|
113
|
-
def self.add_list(name, args, description)
|
114
|
-
LIST << COMMAND[name] = CommandOption.new(name, args, description)
|
132
|
+
def self.add_list(name, args, description, *examples)
|
133
|
+
LIST << COMMAND[name] = CommandOption.new(name, args, description, examples)
|
115
134
|
end
|
116
135
|
|
117
136
|
def self.add_alias(new_cmd, old_cmd)
|
@@ -122,15 +141,22 @@ module List
|
|
122
141
|
GUESS[wrong] = correct
|
123
142
|
end
|
124
143
|
|
144
|
+
def self.cmd_usage(name)
|
145
|
+
if c = COMMAND[name]
|
146
|
+
c.create_optparse([]).cmd_usage
|
147
|
+
end
|
148
|
+
nil
|
149
|
+
end
|
150
|
+
|
125
151
|
def self.get_method(name)
|
126
|
-
if
|
127
|
-
name =
|
128
|
-
group, action =
|
152
|
+
if c = COMMAND[name]
|
153
|
+
name = c.name
|
154
|
+
group, action = c.group
|
129
155
|
require 'td/command/common'
|
130
156
|
require "td/command/#{group}"
|
131
|
-
cmd = name.gsub(
|
157
|
+
cmd = name.gsub(/[\:\-]/, '_')
|
132
158
|
m = Object.new.extend(Command).method(cmd)
|
133
|
-
return Proc.new {|args| m.call(
|
159
|
+
return Proc.new {|args| m.call(c.create_optparse(args)) }
|
134
160
|
end
|
135
161
|
nil
|
136
162
|
end
|
@@ -147,74 +173,96 @@ module List
|
|
147
173
|
|
148
174
|
def self.show_help(indent=' ')
|
149
175
|
before_group = nil
|
150
|
-
LIST.each {|
|
151
|
-
next if HELP_EXCLUDE.
|
152
|
-
if before_group !=
|
153
|
-
before_group =
|
176
|
+
LIST.each {|c|
|
177
|
+
next if HELP_EXCLUDE.any? {|pattern| pattern =~ c.name }
|
178
|
+
if before_group != c.group
|
179
|
+
before_group = c.group
|
154
180
|
puts ""
|
155
181
|
end
|
156
|
-
puts "#{indent}#{
|
182
|
+
puts "#{indent}#{c.usage}"
|
157
183
|
}
|
158
184
|
end
|
159
185
|
|
160
186
|
def self.get_group(group)
|
161
|
-
LIST.map {|
|
162
|
-
|
187
|
+
LIST.map {|c|
|
188
|
+
c.group == group
|
163
189
|
}
|
164
190
|
end
|
165
191
|
|
166
192
|
def self.finishup
|
167
193
|
groups = {}
|
168
|
-
LIST.each {|
|
169
|
-
(groups[
|
194
|
+
LIST.each {|c|
|
195
|
+
(groups[c.group] ||= []) << c
|
170
196
|
}
|
171
197
|
groups.each_pair {|group,ops|
|
172
|
-
if ops.size > 1 &&
|
198
|
+
if ops.size > 1 && c = COMMAND[group]
|
199
|
+
c = c.dup
|
200
|
+
|
173
201
|
msg = %[Additional commands, type "#{File.basename($0)} help COMMAND" for more details:\n\n]
|
174
|
-
ops.each {|
|
175
|
-
msg << %[ #{
|
202
|
+
ops.each {|c|
|
203
|
+
msg << %[ #{c.usage}\n]
|
176
204
|
}
|
177
205
|
msg << %[\n]
|
178
|
-
|
179
|
-
|
206
|
+
c.override_message = msg
|
207
|
+
|
208
|
+
COMMAND[group] = c
|
180
209
|
end
|
181
210
|
}
|
182
211
|
end
|
183
212
|
|
184
|
-
add_list 'db:list', %w[], 'Show list of tables in a database'
|
185
|
-
add_list 'db:show', %w[db], 'Describe a information of a database'
|
186
|
-
add_list 'db:create', %w[db], 'Create a database'
|
187
|
-
add_list 'db:delete', %w[db], 'Delete a database'
|
213
|
+
add_list 'db:list', %w[], 'Show list of tables in a database', 'db:list', 'dbs'
|
214
|
+
add_list 'db:show', %w[db], 'Describe a information of a database', 'db example_db'
|
215
|
+
add_list 'db:create', %w[db], 'Create a database', 'db:create example_db'
|
216
|
+
add_list 'db:delete', %w[db], 'Delete a database', 'db:delete example_db'
|
217
|
+
|
218
|
+
add_list 'table:list', %w[db?], 'Show list of tables', 'table:list', 'table:list example_db', 'tables'
|
219
|
+
add_list 'table:show', %w[db table], 'Describe a information of a table', 'table example_db table1'
|
220
|
+
add_list 'table:create', %w[db table], 'Create a table', 'table:create example_db table1'
|
221
|
+
add_list 'table:delete', %w[db table], 'Delete a table', 'table:delete example_db table1'
|
222
|
+
add_list 'table:import', %w[db table files_], 'Parse and import files to a table', 'table:import example_db table1 --apache access.log', 'table:import example_db table1 --json -t time - < test.json'
|
223
|
+
add_list 'table:tail', %w[db table], 'Get recently imported logs', 'table:tail example_db table1', 'table:tail example_db table1 -t "2011-01-02 03:04:05" -n 30'
|
224
|
+
|
225
|
+
add_list 'result:info', %w[], 'Show information of the MySQL server', 'result:info'
|
226
|
+
add_list 'result:list', %w[], 'Show list of result tables', 'result:list', 'results'
|
227
|
+
add_list 'result:create', %w[name], 'Create a result table', 'result:create rset1'
|
228
|
+
add_list 'result:delete', %w[name], 'Delete a result table', 'result:delete rset1'
|
229
|
+
add_list 'result:connect', %w[sql?], 'Connect to the server using mysql command', 'result:connect'
|
230
|
+
#add_list 'result:get', %w[name], 'Download dump of the result table'
|
188
231
|
|
189
|
-
add_list '
|
190
|
-
add_list 'table:show', %w[db table], 'Describe a information of a table'
|
191
|
-
add_list 'table:create', %w[db table], 'Create a table'
|
192
|
-
add_list 'table:delete', %w[db table], 'Delete a table'
|
193
|
-
add_list 'table:import', %w[db table files_], 'Parse and import files to a table'
|
194
|
-
add_list 'table:tail', %w[db table], 'Get recently imported logs'
|
232
|
+
add_list 'status', %w[], 'Show schedules, jobs, tables and results', 'status', 's'
|
195
233
|
|
196
|
-
add_list 'schema:show', %w[db table], 'Show schema of a table'
|
197
|
-
add_list 'schema:set', %w[db table columns_?], 'Set new schema on a table'
|
198
|
-
add_list 'schema:add', %w[db table columns_], 'Add new columns to a table'
|
199
|
-
add_list 'schema:remove', %w[db table columns_], 'Remove columns from a table'
|
234
|
+
add_list 'schema:show', %w[db table], 'Show schema of a table', 'schema example_db table1'
|
235
|
+
add_list 'schema:set', %w[db table columns_?], 'Set new schema on a table', 'schema:set example_db table1 user:string size:int'
|
236
|
+
add_list 'schema:add', %w[db table columns_], 'Add new columns to a table', 'schema:add example_db table1 user:string size:int'
|
237
|
+
add_list 'schema:remove', %w[db table columns_], 'Remove columns from a table', 'schema:remove example_db table1 user size'
|
200
238
|
|
201
|
-
add_list 'sched:list', %w[], 'Show list of schedules'
|
202
|
-
add_list 'sched:create', %w[name cron sql], 'Create a schedule'
|
203
|
-
add_list 'sched:delete', %w[name], 'Delete a schedule'
|
204
|
-
add_list 'sched:history', %w[name max?], 'Show history of scheduled queries'
|
239
|
+
add_list 'sched:list', %w[], 'Show list of schedules', 'sched:list', 'scheds'
|
240
|
+
add_list 'sched:create', %w[name cron sql], 'Create a schedule', 'sched:create sched1 "0 * * * *" -d example_db "select count(*) from table1" -r rset1'
|
241
|
+
add_list 'sched:delete', %w[name], 'Delete a schedule', 'sched:delete sched1'
|
242
|
+
add_list 'sched:history', %w[name max?], 'Show history of scheduled queries', 'sched sched1 --page 1'
|
205
243
|
|
206
|
-
add_list 'query', %w[sql], 'Issue a query'
|
244
|
+
add_list 'query', %w[sql], 'Issue a query', 'query -d example_db -w -r rset1 "select count(*) from table1"'
|
207
245
|
|
208
|
-
add_list 'job:show', %w[job_id], 'Show status and result of a job'
|
209
|
-
add_list 'job:list', %w[max?], 'Show list of jobs'
|
210
|
-
add_list 'job:kill', %w[job_id], 'Kill or cancel a job'
|
246
|
+
add_list 'job:show', %w[job_id], 'Show status and result of a job', 'job 1461'
|
247
|
+
add_list 'job:list', %w[max?], 'Show list of jobs', 'jobs', 'jobs --page 1'
|
248
|
+
add_list 'job:kill', %w[job_id], 'Kill or cancel a job', 'job:kill 1461'
|
211
249
|
|
212
250
|
add_list 'account', %w[user_name?], 'Setup a Treasure Data account'
|
213
251
|
add_list 'apikey:show', %w[], 'Show Treasure Data API key'
|
214
252
|
add_list 'apikey:set', %w[apikey], 'Set Treasure Data API key'
|
215
253
|
|
254
|
+
add_list 'aggr:list', %w[], 'Show list of aggregation schemas'
|
255
|
+
add_list 'aggr:show', %w[name], 'Describe a aggregation schema'
|
256
|
+
add_list 'aggr:create', %w[name relation_key], 'Create a aggregation schema'
|
257
|
+
add_list 'aggr:delete', %w[name], 'Delete a aggregation schema'
|
258
|
+
add_list 'aggr:add-log', %w[name db table entry_name o1_key? o2_key? o3_key?], 'Add a log aggregation entry'
|
259
|
+
add_list 'aggr:add-attr', %w[name db table entry_name method_name parameters_?], 'Add an attribute aggregation entry'
|
260
|
+
add_list 'aggr:del-log', %w[name entry_name], 'Delete a log aggregation entry'
|
261
|
+
add_list 'aggr:del-attr', %w[name entry_name], 'Delete an attribute aggregation entry'
|
262
|
+
|
216
263
|
add_list 'server:status', %w[], 'Show status of the Treasure Data server'
|
217
264
|
|
265
|
+
add_list 'help:all', %w[], 'Show usage of all commands'
|
218
266
|
add_list 'help', %w[command], 'Show usage of a command'
|
219
267
|
|
220
268
|
# aliases
|
@@ -231,6 +279,9 @@ module List
|
|
231
279
|
add_alias 'table', 'table:show'
|
232
280
|
add_alias 'tables', 'table:list'
|
233
281
|
|
282
|
+
add_alias 'result', 'help' # dummy
|
283
|
+
add_alias 'results', 'result:list'
|
284
|
+
|
234
285
|
add_alias 'schema', 'schema:show'
|
235
286
|
|
236
287
|
add_alias 'schedule:list', 'sched:list'
|
@@ -247,7 +298,13 @@ module List
|
|
247
298
|
add_alias 'jobs', 'job:list'
|
248
299
|
add_alias 'kill', 'job:kill'
|
249
300
|
|
301
|
+
add_alias 'aggr', 'aggr:show'
|
302
|
+
add_alias 'aggrs', 'aggr:list'
|
303
|
+
|
250
304
|
add_alias 'apikey', 'apikey:show'
|
305
|
+
add_alias 'server', 'server:status'
|
306
|
+
|
307
|
+
add_alias 's', 'status'
|
251
308
|
|
252
309
|
# backward compatibility
|
253
310
|
add_alias 'show-databases', 'db:list'
|
data/lib/td/command/query.rb
CHANGED
@@ -7,6 +7,7 @@ module Command
|
|
7
7
|
wait = false
|
8
8
|
output = nil
|
9
9
|
format = 'tsv'
|
10
|
+
result = nil
|
10
11
|
|
11
12
|
op.on('-d', '--database DB_NAME', 'use the database (required)') {|s|
|
12
13
|
db_name = s
|
@@ -14,6 +15,9 @@ module Command
|
|
14
15
|
op.on('-w', '--wait', 'wait for finishing the job', TrueClass) {|b|
|
15
16
|
wait = b
|
16
17
|
}
|
18
|
+
op.on('-r', '--result RESULT_TABLE', 'write result to the result table (use result:create command)') {|s|
|
19
|
+
result = s
|
20
|
+
}
|
17
21
|
op.on('-o', '--output PATH', 'write result to the file') {|s|
|
18
22
|
output = s
|
19
23
|
}
|
@@ -36,7 +40,7 @@ module Command
|
|
36
40
|
# local existance check
|
37
41
|
get_database(client, db_name)
|
38
42
|
|
39
|
-
job = client.query(db_name, sql)
|
43
|
+
job = client.query(db_name, sql, result)
|
40
44
|
|
41
45
|
$stderr.puts "Job #{job.job_id} is queued."
|
42
46
|
$stderr.puts "Use '#{$prog} job:show #{job.job_id}' to show the status."
|
@@ -0,0 +1,111 @@
|
|
1
|
+
|
2
|
+
module TreasureData
|
3
|
+
module Command
|
4
|
+
|
5
|
+
def result_info(op)
|
6
|
+
op.cmd_parse
|
7
|
+
|
8
|
+
client = get_client
|
9
|
+
|
10
|
+
info = client.result_set_info
|
11
|
+
|
12
|
+
puts "Type : #{info.type}"
|
13
|
+
puts "Host : #{info.host}"
|
14
|
+
puts "Port : #{info.port}"
|
15
|
+
puts "User : #{info.user}"
|
16
|
+
puts "Password : #{info.password}"
|
17
|
+
puts "Database : #{info.database}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def result_list(op)
|
21
|
+
op.cmd_parse
|
22
|
+
|
23
|
+
client = get_client
|
24
|
+
|
25
|
+
rsets = client.result_sets
|
26
|
+
|
27
|
+
rows = []
|
28
|
+
rsets.each {|rset|
|
29
|
+
rows << {:Name => rset.name}
|
30
|
+
}
|
31
|
+
rows = rows.sort_by {|map|
|
32
|
+
map[:Name]
|
33
|
+
}
|
34
|
+
|
35
|
+
puts cmd_render_table(rows, :fields => [:Name])
|
36
|
+
|
37
|
+
if rsets.empty?
|
38
|
+
$stderr.puts "There are result tables."
|
39
|
+
$stderr.puts "Use '#{$prog} result:create <name>' to create a result table."
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def result_create(op)
|
44
|
+
name = op.cmd_parse
|
45
|
+
|
46
|
+
API.validate_database_name(name)
|
47
|
+
|
48
|
+
client = get_client
|
49
|
+
|
50
|
+
begin
|
51
|
+
client.create_result_set(name)
|
52
|
+
rescue AlreadyExistsError
|
53
|
+
$stderr.puts "Result table '#{name}' already exists."
|
54
|
+
exit 1
|
55
|
+
end
|
56
|
+
|
57
|
+
$stderr.puts "Result table '#{name}' is created."
|
58
|
+
end
|
59
|
+
|
60
|
+
def result_delete(op)
|
61
|
+
name = op.cmd_parse
|
62
|
+
|
63
|
+
client = get_client
|
64
|
+
|
65
|
+
begin
|
66
|
+
client.delete_result_set(name)
|
67
|
+
rescue NotFoundError
|
68
|
+
$stderr.puts "Result table '#{name}' does not exist."
|
69
|
+
exit 1
|
70
|
+
end
|
71
|
+
|
72
|
+
$stderr.puts "Result table '#{name}' is deleted."
|
73
|
+
end
|
74
|
+
|
75
|
+
def result_connect(op)
|
76
|
+
mysql = 'mysql'
|
77
|
+
|
78
|
+
op.on('-e', '--execute MYSQL', 'mysql command') {|s|
|
79
|
+
mysql = s
|
80
|
+
}
|
81
|
+
|
82
|
+
sql = op.cmd_parse
|
83
|
+
|
84
|
+
client = get_client
|
85
|
+
|
86
|
+
info = client.result_set_info
|
87
|
+
|
88
|
+
cmd = [mysql, '-h', info.host, '-P', info.port.to_s, '-u', info.user, "--password=#{info.password}", info.database]
|
89
|
+
|
90
|
+
cmd_start = Time.now
|
91
|
+
|
92
|
+
if sql
|
93
|
+
IO.popen(cmd, "w") {|io|
|
94
|
+
io.write sql
|
95
|
+
io.close
|
96
|
+
}
|
97
|
+
else
|
98
|
+
STDERR.puts "> #{cmd.join(' ')}"
|
99
|
+
system(*cmd)
|
100
|
+
end
|
101
|
+
|
102
|
+
cmd_alive = Time.now - cmd_start
|
103
|
+
if $?.to_i != 0 && cmd_alive < 1.0
|
104
|
+
STDERR.puts "Command died within 1 second with exit code #{$?.to_i}."
|
105
|
+
STDERR.puts "Please confirm mysql command is installed."
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
data/lib/td/command/runner.rb
CHANGED
@@ -33,10 +33,26 @@ EOF
|
|
33
33
|
require 'td/command/list'
|
34
34
|
puts op.to_s
|
35
35
|
puts ""
|
36
|
-
puts
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
puts <<EOF
|
37
|
+
Basic commands:
|
38
|
+
|
39
|
+
db # create/delete/list databases
|
40
|
+
table # create/delete/list/import/tail tables
|
41
|
+
query # issue a query
|
42
|
+
job # show/kill/list jobs
|
43
|
+
result # create/delete/list/connect/get MySQL result set
|
44
|
+
|
45
|
+
Additional commands:
|
46
|
+
|
47
|
+
sched # create/delete/list schedules that run a query periodically
|
48
|
+
schema # create/delete/modify schemas of tables
|
49
|
+
status # show scheds, jobs, tables and results
|
50
|
+
apikey # show/set API key
|
51
|
+
server # show status of the Treasure Data server
|
52
|
+
help # show help messages
|
53
|
+
|
54
|
+
Type 'td help COMMAND' for more information on a specific command.
|
55
|
+
EOF
|
40
56
|
if errmsg
|
41
57
|
puts "error: #{errmsg}"
|
42
58
|
exit 1
|
data/lib/td/command/sched.rb
CHANGED
@@ -11,21 +11,25 @@ module Command
|
|
11
11
|
|
12
12
|
rows = []
|
13
13
|
scheds.each {|sched|
|
14
|
-
rows << {:Name => sched.name, :Cron => sched.cron, :Query => sched.query}
|
14
|
+
rows << {:Name => sched.name, :Cron => sched.cron, :Result => sched.rset_name, :Query => sched.query}
|
15
15
|
}
|
16
16
|
rows = rows.sort_by {|map|
|
17
17
|
map[:Name]
|
18
18
|
}
|
19
19
|
|
20
|
-
puts cmd_render_table(rows, :fields => [:Name, :Cron, :Query])
|
20
|
+
puts cmd_render_table(rows, :fields => [:Name, :Cron, :Result, :Query])
|
21
21
|
end
|
22
22
|
|
23
23
|
def sched_create(op)
|
24
24
|
db_name = nil
|
25
|
+
result = nil
|
25
26
|
|
26
27
|
op.on('-d', '--database DB_NAME', 'use the database (required)') {|s|
|
27
28
|
db_name = s
|
28
29
|
}
|
30
|
+
op.on('-r', '--result RESULT_TABLE', 'write result to the result table (use result:create command)') {|s|
|
31
|
+
result = s
|
32
|
+
}
|
29
33
|
|
30
34
|
name, cron, sql = op.cmd_parse
|
31
35
|
|
@@ -40,7 +44,7 @@ module Command
|
|
40
44
|
get_database(client, db_name)
|
41
45
|
|
42
46
|
begin
|
43
|
-
first_time = client.create_schedule(name, :cron=>cron, :query=>sql, :database=>db_name)
|
47
|
+
first_time = client.create_schedule(name, :cron=>cron, :query=>sql, :database=>db_name, :result=>result)
|
44
48
|
rescue AlreadyExistsError
|
45
49
|
cmd_debug_error $!
|
46
50
|
$stderr.puts "Schedule '#{name}' already exists."
|
@@ -99,10 +103,10 @@ module Command
|
|
99
103
|
|
100
104
|
rows = []
|
101
105
|
history.each {|j|
|
102
|
-
rows << {:Time => j.scheduled_at.localtime, :JobID => j.job_id, :Status => j.status}
|
106
|
+
rows << {:Time => j.scheduled_at.localtime, :JobID => j.job_id, :Status => j.status, :Result=>j.rset_name}
|
103
107
|
}
|
104
108
|
|
105
|
-
puts cmd_render_table(rows, :fields => [:JobID, :Time, :Status])
|
109
|
+
puts cmd_render_table(rows, :fields => [:JobID, :Time, :Status, :Result])
|
106
110
|
end
|
107
111
|
|
108
112
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
|
2
|
+
module TreasureData
|
3
|
+
module Command
|
4
|
+
|
5
|
+
def status(op)
|
6
|
+
op.cmd_parse
|
7
|
+
|
8
|
+
client = get_client
|
9
|
+
|
10
|
+
# +----------------+
|
11
|
+
# | scheds |
|
12
|
+
# +----------------+
|
13
|
+
# +----------------+
|
14
|
+
# | jobs |
|
15
|
+
# +----------------+
|
16
|
+
# +------+ +-------+
|
17
|
+
# |tables| |results|
|
18
|
+
# +------+ +-------+
|
19
|
+
|
20
|
+
scheds = []
|
21
|
+
jobs = []
|
22
|
+
tables = []
|
23
|
+
results = []
|
24
|
+
|
25
|
+
s = client.schedules
|
26
|
+
s.each {|sched|
|
27
|
+
scheds << {:Name => sched.name, :Cron => sched.cron, :Result => sched.rset_name, :Query => sched.query}
|
28
|
+
}
|
29
|
+
scheds = scheds.sort_by {|map|
|
30
|
+
map[:Name]
|
31
|
+
}
|
32
|
+
x1, y1 = status_render(0, 0, "[Schedules]", scheds, :fields => [:Name, :Cron, :Result, :Query])
|
33
|
+
|
34
|
+
j = client.jobs(0, 4)
|
35
|
+
j.each {|job|
|
36
|
+
start = job.start_at
|
37
|
+
elapsed = cmd_format_elapsed(start, job.end_at)
|
38
|
+
jobs << {:JobID => job.job_id, :Status => job.status, :Query => job.query.to_s, :Start => (start ? start.localtime : ''), :Elapsed => elapsed, :Result => job.rset_name}
|
39
|
+
}
|
40
|
+
x2, y2 = status_render(0, 0, "[Jobs]", jobs, :fields => [:JobID, :Status, :Start, :Elapsed, :Result, :Query])
|
41
|
+
|
42
|
+
dbs = client.databases
|
43
|
+
dbs.map {|db|
|
44
|
+
db.tables.each {|table|
|
45
|
+
tables << {:Database => db.name, :Table => table.name, :Count => table.count.to_s}
|
46
|
+
}
|
47
|
+
}
|
48
|
+
x3, y3 = status_render(0, 0, "[Tables]", tables, :fields => [:Database, :Table, :Count])
|
49
|
+
|
50
|
+
r = client.result_sets
|
51
|
+
r.each {|rset|
|
52
|
+
results << {:Name => rset.name}
|
53
|
+
}
|
54
|
+
results = results.sort_by {|map|
|
55
|
+
map[:Name]
|
56
|
+
}
|
57
|
+
x4, y4 = status_render(x3+2, y3, "[Results]", results, :fields => [:Name])
|
58
|
+
|
59
|
+
(y3-y4-1).times do
|
60
|
+
print "\eD"
|
61
|
+
end
|
62
|
+
print "\eE"
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
def status_render(movex, movey, msg, *args)
|
67
|
+
lines = cmd_render_table(*args).split("\n")
|
68
|
+
lines.pop # remove 'N rows in set' line
|
69
|
+
lines.unshift(msg)
|
70
|
+
#lines.unshift("")
|
71
|
+
|
72
|
+
print "\e[#{movey}A" if movey > 0
|
73
|
+
|
74
|
+
max_width = 0
|
75
|
+
height = 0
|
76
|
+
lines.each {|line|
|
77
|
+
print "\e[#{movex}C" if movex > 0
|
78
|
+
puts line
|
79
|
+
width = line.length
|
80
|
+
max_width = width if max_width < width
|
81
|
+
height += 1
|
82
|
+
}
|
83
|
+
|
84
|
+
return movex+max_width, height
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
data/lib/td/command/table.rb
CHANGED
@@ -103,15 +103,34 @@ module Command
|
|
103
103
|
|
104
104
|
def table_tail(op)
|
105
105
|
to = nil
|
106
|
-
count =
|
106
|
+
count = nil
|
107
107
|
|
108
108
|
op.on('-t', '--to TIME', 'end time of logs to get') {|s|
|
109
|
-
|
109
|
+
if s.to_i.to_s == s
|
110
|
+
to = s
|
111
|
+
else
|
112
|
+
to = Time.parse(s).to_i
|
113
|
+
end
|
110
114
|
}
|
111
115
|
op.on('-n', '--count N', 'number of logs to get', Integer) {|i|
|
112
116
|
count = i
|
113
117
|
}
|
114
118
|
|
119
|
+
if count == nil
|
120
|
+
# smart count calculation
|
121
|
+
begin
|
122
|
+
require "curses"
|
123
|
+
if Curses.stdscr.maxy - 1 <= 40
|
124
|
+
count = 5
|
125
|
+
else
|
126
|
+
count = 10
|
127
|
+
end
|
128
|
+
Curses.close_screen
|
129
|
+
rescue
|
130
|
+
count = 5
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
115
134
|
db_name, table_name = op.cmd_parse
|
116
135
|
|
117
136
|
client = get_client
|
data/lib/td/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: td
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.
|
4
|
+
version: 0.10.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-12-04 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: msgpack
|
16
|
-
requirement: &
|
16
|
+
requirement: &70131804842780 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 0.4.4
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70131804842780
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: json
|
27
|
-
requirement: &
|
27
|
+
requirement: &70131804842240 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 1.4.3
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70131804842240
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: hirb
|
38
|
-
requirement: &
|
38
|
+
requirement: &70131804841700 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,21 +43,21 @@ dependencies:
|
|
43
43
|
version: 0.4.5
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70131804841700
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: td-client
|
49
|
-
requirement: &
|
49
|
+
requirement: &70131804841140 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0.8.
|
54
|
+
version: 0.8.5
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70131804841140
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: td-logger
|
60
|
-
requirement: &
|
60
|
+
requirement: &70131804840600 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,7 +65,7 @@ dependencies:
|
|
65
65
|
version: 0.3.7
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70131804840600
|
69
69
|
description:
|
70
70
|
email:
|
71
71
|
executables:
|
@@ -77,6 +77,7 @@ extra_rdoc_files:
|
|
77
77
|
files:
|
78
78
|
- lib/td.rb
|
79
79
|
- lib/td/command/account.rb
|
80
|
+
- lib/td/command/aggr.rb
|
80
81
|
- lib/td/command/apikey.rb
|
81
82
|
- lib/td/command/common.rb
|
82
83
|
- lib/td/command/db.rb
|
@@ -85,10 +86,12 @@ files:
|
|
85
86
|
- lib/td/command/job.rb
|
86
87
|
- lib/td/command/list.rb
|
87
88
|
- lib/td/command/query.rb
|
89
|
+
- lib/td/command/result.rb
|
88
90
|
- lib/td/command/runner.rb
|
89
91
|
- lib/td/command/sched.rb
|
90
92
|
- lib/td/command/schema.rb
|
91
93
|
- lib/td/command/server.rb
|
94
|
+
- lib/td/command/status.rb
|
92
95
|
- lib/td/command/table.rb
|
93
96
|
- lib/td/config.rb
|
94
97
|
- lib/td/version.rb
|