td 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,115 @@
1
+
2
+ module TD
3
+ module Command
4
+ module List
5
+
6
+ LIST = []
7
+ ALIASES = {}
8
+ GUESS = {}
9
+
10
+ def self.add_list(file, cmd, description)
11
+ LIST << [cmd, file, description]
12
+ end
13
+
14
+ def self.add_alias(new_cmd, old_cmd)
15
+ ALIASES[new_cmd] = old_cmd
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
25
+ end
26
+
27
+ def self.add_guess(wrong, correct)
28
+ GUESS[wrong] = correct
29
+ end
30
+
31
+ add_list 'list', 'help', 'Show usage of a command'
32
+ add_list 'account', 'account', 'Setup a Treasure Data account'
33
+ add_list 'server', 'server-status', 'Show status of the Treasure Data server'
34
+ add_list 'database', 'show-databases', 'Show list of databases'
35
+ add_list 'table', 'show-tables', 'Show list of tables'
36
+ add_list 'query', 'show-jobs', 'Show list of jobs'
37
+ add_list 'database', 'create-database', 'Create a database'
38
+ add_list 'table', 'create-log-table', 'Create a log table'
39
+ #add_list 'table', 'create-item-table', 'Create a item table'
40
+ add_list 'database', 'drop-database', 'Delete a database'
41
+ add_list 'table', 'drop-table', 'Delete a table'
42
+ add_list 'query', 'query', 'Start a query'
43
+ add_list 'query', 'job', 'Show status and result of a job'
44
+ add_list 'import', 'import', 'Import files to a table'
45
+ add_list 'list', 'version', 'Show version'
46
+
47
+ add_alias 'show-dbs', 'show-databases'
48
+ add_alias 'show-database', 'show-databases'
49
+ add_alias 'create-db', 'create-databases'
50
+ add_alias 'drop-db', 'create-databases'
51
+ add_alias 'show-table', 'show-tables'
52
+ add_alias 'delete-database', 'drop-database'
53
+ add_alias 'delete-table', 'drop-table'
54
+ add_alias 'jobs', 'show-jobs'
55
+
56
+ add_guess 'create-table', 'create-log-table'
57
+ add_guess 'drop-log-table', 'drop-table'
58
+ #add_guess 'drop-item-table', 'drop-table'
59
+ add_guess 'delete-log-table', 'drop-table'
60
+ #add_guess 'delete-item-table', 'drop-table'
61
+ add_guess 'show-job', 'job'
62
+
63
+ def self.get_method(command)
64
+ command = ALIASES[command] || command
65
+ LIST.each {|cmd,file,description|
66
+ if cmd == command
67
+ require 'td/command/common'
68
+ require "td/command/#{file}"
69
+ name = command.gsub('-','_')
70
+ return Object.new.extend(Command).method(name)
71
+ end
72
+ }
73
+ nil
74
+ end
75
+
76
+ def self.show_guess(wrong)
77
+ if correct = GUESS[wrong]
78
+ $stderr.puts "Did you mean this?: #{correct}"
79
+ end
80
+ end
81
+
82
+ def self.help(indent)
83
+ LIST.map {|cmd,file,description|
84
+ if cmd != 'help'
85
+ "#{indent}%-18s %s" % [cmd, description.split("\n").first]
86
+ end
87
+ }.join("\n")
88
+ end
89
+ end
90
+
91
+ def help
92
+ op = cmd_opt 'help', :command
93
+ cmd = op.cmd_parse
94
+
95
+ ARGV.clear
96
+ ARGV[0] = '--help'
97
+
98
+ method = List.get_method(cmd)
99
+ unless method
100
+ $stderr.puts "'#{cmd}' is not a td command. Run '#{$prog}' to show the list."
101
+ List.show_guess(cmd)
102
+ exit 1
103
+ end
104
+
105
+ method.call
106
+ end
107
+
108
+ def version
109
+ require 'td/version'
110
+ puts "td-#{TD::VERSION}"
111
+ end
112
+
113
+ end
114
+ end
115
+
@@ -0,0 +1,167 @@
1
+
2
+ module TD
3
+ module Command
4
+
5
+ def query
6
+ op = cmd_opt 'query', :sql
7
+
8
+ op.banner << "\noptions:\n"
9
+
10
+ db_name = nil
11
+ op.on('-d', '--database DB_NAME', 'use the database') {|s|
12
+ db_name = s
13
+ }
14
+
15
+ wait = false
16
+ op.on('-w', '--wait', 'wait for finishing the job', TrueClass) {|b|
17
+ wait = b
18
+ }
19
+
20
+ sql = op.cmd_parse
21
+
22
+ conf = cmd_config
23
+ api = cmd_api(conf)
24
+
25
+ if db_name
26
+ find_database(api, db_name)
27
+ end
28
+
29
+ job = api.query(sql, db_name)
30
+
31
+ $stderr.puts "Job #{job.job_id} is started."
32
+ $stderr.puts "Use '#{$prog} job #{job.job_id}' to show the status."
33
+ $stderr.puts "See #{job.url} to see the progress."
34
+
35
+ if wait && !job.finished?
36
+ wait_job(job)
37
+ puts "Status : #{job.status}"
38
+ puts "Result :"
39
+ puts cmd_render_table(job.result, :max_width=>10000)
40
+ end
41
+ end
42
+
43
+ def show_jobs
44
+ op = cmd_opt 'show-jobs', :max?, :from?
45
+ max, from = op.cmd_parse
46
+
47
+ max = (max || 20).to_i
48
+ from = (from || 0).to_i
49
+
50
+ conf = cmd_config
51
+ api = cmd_api(conf)
52
+
53
+ jobs = api.jobs(from, from+max-1)
54
+
55
+ rows = []
56
+ jobs.each {|job|
57
+ start = job.start_at
58
+ finish = job.end_at
59
+ if start
60
+ if !finish
61
+ finish = Time.now.utc
62
+ end
63
+ e = finish.to_i - start.to_i
64
+ elapsed = ''
65
+ if e >= 3600
66
+ elapsed << "#{e/3600}h "
67
+ e %= 3600
68
+ elapsed << "% 2dm " % (e/60)
69
+ e %= 60
70
+ elapsed << "% 2dsec" % e
71
+ elsif e >= 60
72
+ elapsed << "% 2dm " % (e/60)
73
+ e %= 60
74
+ elapsed << "% 2dsec" % e
75
+ else
76
+ elapsed << "% 2dsec" % e
77
+ end
78
+ else
79
+ elapsed = ''
80
+ end
81
+ elapsed = "% 10s" % elapsed # right aligned
82
+
83
+ rows << {:JobID => job.job_id, :Status => job.status, :Query => job.query.to_s, :Start => start, :Elapsed => elapsed}
84
+ }
85
+
86
+ puts cmd_render_table(rows, :fields => [:JobID, :Status, :Start, :Elapsed, :Query])
87
+ end
88
+
89
+ def job
90
+ op = cmd_opt 'job', :job_id
91
+
92
+ op.banner << "\noptions:\n"
93
+
94
+ verbose = nil
95
+ op.on('-v', '--verbose', 'show logs', TrueClass) {|b|
96
+ verbose = b
97
+ }
98
+
99
+ wait = false
100
+ op.on('-w', '--wait', 'wait for finishing the job', TrueClass) {|b|
101
+ wait = b
102
+ }
103
+
104
+ job_id = op.cmd_parse
105
+
106
+ conf = cmd_config
107
+ api = cmd_api(conf)
108
+
109
+ job = api.job(job_id)
110
+
111
+ puts "JobID : #{job.job_id}"
112
+ puts "URL : #{job.url}"
113
+ puts "Status : #{job.status}"
114
+ puts "Query : #{job.query}"
115
+
116
+ if wait && !job.finished?
117
+ wait_job(job)
118
+ puts "Result :"
119
+ puts cmd_render_table(job.result, :max_width=>10000)
120
+
121
+ else
122
+ if job.finished?
123
+ puts "Result :"
124
+ puts cmd_render_table(job.result, :max_width=>10000)
125
+ end
126
+
127
+ if verbose
128
+ puts ""
129
+ puts "cmdout:"
130
+ job.debug['cmdout'].to_s.split("\n").each {|line|
131
+ puts " "+line
132
+ }
133
+ puts ""
134
+ puts "stderr:"
135
+ job.debug['stderr'].to_s.split("\n").each {|line|
136
+ puts " "+line
137
+ }
138
+ end
139
+ end
140
+
141
+ $stderr.puts "Use '-v' option to show detailed messages." unless verbose
142
+ end
143
+
144
+ private
145
+ def wait_job(job)
146
+ $stderr.puts "running..."
147
+
148
+ cmdout_lines = 0
149
+ stderr_lines = 0
150
+
151
+ until job.finished?
152
+ sleep 2
153
+
154
+ job.update_status!
155
+
156
+ cmdout = job.debug['cmdout'].to_s.split("\n")[cmdout_lines..-1] || []
157
+ stderr = job.debug['stderr'].to_s.split("\n")[stderr_lines..-1] || []
158
+ (cmdout + stderr).each {|line|
159
+ puts " "+line
160
+ }
161
+ cmdout_lines += cmdout.size
162
+ stderr_lines += stderr.size
163
+ end
164
+ end
165
+ end
166
+ end
167
+
@@ -0,0 +1,15 @@
1
+
2
+ module TD
3
+ module Command
4
+
5
+ def server_status
6
+ op = cmd_opt 'server-status'
7
+ op.cmd_parse
8
+
9
+ require 'td/api'
10
+ puts API.server_status
11
+ end
12
+
13
+ end
14
+ end
15
+
@@ -0,0 +1,101 @@
1
+
2
+ module TD
3
+ module Command
4
+
5
+ def create_table_type(type, db_name, table_name)
6
+ conf = cmd_config
7
+ api = cmd_api(conf)
8
+
9
+ begin
10
+ api.create_table(db_name, table_name, type)
11
+ rescue NotFoundError
12
+ cmd_debug_error $!
13
+ $stderr.puts "Database '#{db_name}' does not exist."
14
+ $stderr.puts "Use '#{$prog} create-database #{db_name}' to create the database."
15
+ exit 1
16
+ rescue AlreadyExistsError
17
+ cmd_debug_error $!
18
+ $stderr.puts "Table '#{db_name}.#{table_name}' already exists."
19
+ exit 1
20
+ end
21
+
22
+ $stderr.puts "Table '#{db_name}.#{table_name}' is created."
23
+ end
24
+ private :create_table_type
25
+
26
+ def create_log_table
27
+ op = cmd_opt 'create-log-table', :db_name, :table_name
28
+ db_name, table_name = op.cmd_parse
29
+
30
+ create_table_type(:log, db_name, table_name)
31
+ end
32
+
33
+ def create_item_table
34
+ op = cmd_opt 'create-item-table', :db_name, :table_name
35
+ db_name, table_name = op.cmd_parse
36
+
37
+ create_table_type(:item, db_name, table_name)
38
+ end
39
+
40
+ def drop_table
41
+ op = cmd_opt 'drop-table', :db_name, :table_name
42
+ db_name, table_name = op.cmd_parse
43
+
44
+ conf = cmd_config
45
+ api = cmd_api(conf)
46
+
47
+ begin
48
+ api.delete_table(db_name, table_name)
49
+ rescue NotFoundError
50
+ cmd_debug_error $!
51
+ $stderr.puts "Table '#{db_name}.#{table_name}' does not exist."
52
+ $stderr.puts "Use '#{$prog} show-tables #{db_name}' to show list of the tables."
53
+ exit 1
54
+ end
55
+
56
+ $stderr.puts "Table '#{db_name}.#{table_name}' is deleted."
57
+ end
58
+
59
+ def show_tables
60
+ op = cmd_opt 'show-tables', :db_name?
61
+ db_name = op.cmd_parse
62
+
63
+ conf = cmd_config
64
+ api = cmd_api(conf)
65
+
66
+ if db_name
67
+ db = find_database(api, db_name)
68
+ dbs = [db]
69
+ else
70
+ dbs = api.databases
71
+ end
72
+
73
+ rows = []
74
+ dbs.each {|db|
75
+ db.tables.each {|table|
76
+ rows << {:Database => db.name, :Table => table.name, :Type => table.type.to_s, :Count => table.count.to_s}
77
+ }
78
+ }
79
+ rows = rows.sort_by {|map|
80
+ [map[:Database], map[:Type].size, map[:Table]]
81
+ }
82
+
83
+ puts cmd_render_table(rows, :fields => [:Database, :Table, :Type, :Count])
84
+
85
+ if rows.empty?
86
+ if db_name
87
+ $stderr.puts "Database '#{db_name}' has no tables."
88
+ $stderr.puts "Use '#{$prog} create-log-table #{db_name} <table_name>' to create a table."
89
+ elsif dbs.empty?
90
+ $stderr.puts "There are no databases."
91
+ $stderr.puts "Use '#{$prog} create-database <db_name>' to create a database."
92
+ else
93
+ $stderr.puts "There are no tables."
94
+ $stderr.puts "Use '#{$prog} create-log-table <db_name> <table_name>' to create a table."
95
+ end
96
+ end
97
+ end
98
+
99
+ end
100
+ end
101
+
@@ -0,0 +1,82 @@
1
+
2
+ require 'optparse'
3
+
4
+ $prog = File.basename($0)
5
+
6
+ op = OptionParser.new
7
+ op.banner = <<EOF
8
+ usage: #{$prog} [options] COMMAND [args]
9
+
10
+ options:
11
+ EOF
12
+
13
+ op.summary_indent = " "
14
+
15
+ (class<<self;self;end).module_eval do
16
+ define_method(:usage) do |errmsg|
17
+ require 'td/command/list'
18
+ puts op.to_s
19
+ puts ""
20
+ puts "commands:"
21
+ puts TD::Command::List.help(op.summary_indent)
22
+ puts ""
23
+ puts "Type 'td help COMMAND' for more information on a specific command."
24
+ if errmsg
25
+ puts "error: #{errmsg}"
26
+ exit 1
27
+ else
28
+ exit 0
29
+ end
30
+ end
31
+ end
32
+
33
+ config_path = File.join(ENV['HOME'], '.td', 'td.conf')
34
+ $verbose = false
35
+ #$debug = false
36
+
37
+ op.on('-c', '--config PATH', "path to config file (~/.td/td.conf)") {|s|
38
+ config_path = s
39
+ }
40
+
41
+ op.on('-v', '--verbose', "verbose mode", TrueClass) {|b|
42
+ $verbose = b
43
+ }
44
+
45
+ #op.on('-d', '--debug', "debug mode", TrueClass) {|b|
46
+ # $debug = b
47
+ #}
48
+
49
+ begin
50
+ op.order!(ARGV)
51
+ usage nil if ARGV.empty?
52
+ cmd = ARGV.shift
53
+ $TRD_CONFIG_PATH = config_path
54
+ rescue
55
+ usage $!.to_s
56
+ end
57
+
58
+ require 'td/command/list'
59
+
60
+ method = TD::Command::List.get_method(cmd)
61
+ unless method
62
+ $stderr.puts "'#{cmd}' is not a td command. Run '#{$prog}' to show the list."
63
+ TD::Command::List.show_guess(cmd)
64
+ exit 1
65
+ end
66
+
67
+ require 'td/error'
68
+
69
+ begin
70
+ method.call
71
+ rescue TD::ConfigError
72
+ $stderr.puts "TreasureData account is not configured yet."
73
+ $stderr.puts "Run '#{$prog} account' first."
74
+ rescue
75
+ $stderr.puts "error #{$!.class}: backtrace:"
76
+ $!.backtrace.each {|b|
77
+ $stderr.puts " #{b}"
78
+ }
79
+ puts ""
80
+ puts $!
81
+ end
82
+