td 0.7.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.
@@ -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
+