turbot 0.1.36 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +15 -0
  5. data/.yardopts +3 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +22 -0
  8. data/README.md +44 -25
  9. data/Rakefile +16 -0
  10. data/appveyor.yml +35 -0
  11. data/bin/turbot +2 -16
  12. data/data/schema.json +134 -0
  13. data/{templates → data/templates}/LICENSE.txt +0 -0
  14. data/{templates → data/templates}/manifest.json +0 -0
  15. data/{templates → data/templates}/python/scraper.py +0 -0
  16. data/{templates → data/templates}/ruby/scraper.rb +0 -0
  17. data/dist/deb.rake +32 -0
  18. data/dist/gem.rake +16 -0
  19. data/dist/manifest.rake +9 -0
  20. data/dist/pkg.rake +60 -0
  21. data/dist/resources/deb/control +10 -0
  22. data/dist/resources/deb/postinst +45 -0
  23. data/dist/resources/deb/turbot +25 -0
  24. data/dist/resources/deb/turbot-release-key.txt +30 -0
  25. data/dist/resources/pkg/Distribution.erb +15 -0
  26. data/dist/resources/pkg/PackageInfo.erb +6 -0
  27. data/dist/resources/pkg/postinstall +45 -0
  28. data/dist/resources/pkg/turbot +24 -0
  29. data/dist/resources/tgz/turbot +24 -0
  30. data/dist/rpm.rake +35 -0
  31. data/dist/tgz.rake +26 -0
  32. data/dist/zip.rake +40 -0
  33. data/lib/turbot.rb +18 -15
  34. data/lib/turbot/cli.rb +10 -27
  35. data/lib/turbot/command.rb +59 -212
  36. data/lib/turbot/command/auth.rb +72 -34
  37. data/lib/turbot/command/base.rb +22 -61
  38. data/lib/turbot/command/bots.rb +251 -300
  39. data/lib/turbot/command/help.rb +57 -110
  40. data/lib/turbot/command/version.rb +6 -10
  41. data/lib/turbot/handlers/base_handler.rb +21 -0
  42. data/lib/turbot/handlers/dump_handler.rb +10 -0
  43. data/lib/turbot/handlers/preview_handler.rb +30 -0
  44. data/lib/turbot/handlers/validation_handler.rb +17 -0
  45. data/lib/turbot/helpers.rb +14 -482
  46. data/lib/turbot/helpers/api_helper.rb +41 -0
  47. data/lib/turbot/helpers/netrc_helper.rb +66 -0
  48. data/lib/turbot/helpers/shell_helper.rb +36 -0
  49. data/lib/turbot/version.rb +1 -1
  50. data/spec/fixtures/bad_permissions +0 -0
  51. data/spec/fixtures/empty +0 -0
  52. data/spec/fixtures/netrc +6 -0
  53. data/spec/spec_helper.rb +17 -219
  54. data/spec/support/bot_helper.rb +102 -0
  55. data/spec/support/command_helper.rb +20 -0
  56. data/spec/support/custom_matchers.rb +5 -0
  57. data/spec/support/fixture_helper.rb +9 -0
  58. data/spec/support/netrc_helper.rb +21 -0
  59. data/spec/turbot/command/auth_spec.rb +202 -20
  60. data/spec/turbot/command/base_spec.rb +22 -58
  61. data/spec/turbot/command/bots_spec.rb +580 -89
  62. data/spec/turbot/command/help_spec.rb +32 -75
  63. data/spec/turbot/command/version_spec.rb +11 -10
  64. data/spec/turbot/command_spec.rb +55 -87
  65. data/spec/turbot/helpers_spec.rb +28 -44
  66. data/turbot.gemspec +31 -0
  67. metadata +88 -178
  68. data/data/cacert.pem +0 -3988
  69. data/lib/turbot/auth.rb +0 -315
  70. data/lib/turbot/client.rb +0 -757
  71. data/lib/turbot/client/cisaurus.rb +0 -25
  72. data/lib/turbot/client/pgbackups.rb +0 -113
  73. data/lib/turbot/client/rendezvous.rb +0 -111
  74. data/lib/turbot/client/ssl_endpoint.rb +0 -25
  75. data/lib/turbot/client/turbot_postgresql.rb +0 -148
  76. data/lib/turbot/command/ssl.rb +0 -43
  77. data/lib/turbot/deprecated.rb +0 -5
  78. data/lib/turbot/deprecated/help.rb +0 -38
  79. data/lib/turbot/distribution.rb +0 -9
  80. data/lib/turbot/errors.rb +0 -28
  81. data/lib/turbot/excon.rb +0 -11
  82. data/lib/turbot/helpers/log_displayer.rb +0 -70
  83. data/lib/turbot/helpers/pg_dump_restore.rb +0 -115
  84. data/lib/turbot/helpers/turbot_postgresql.rb +0 -213
  85. data/lib/turbot/plugin.rb +0 -165
  86. data/lib/turbot/updater.rb +0 -171
  87. data/lib/vendor/turbot/okjson.rb +0 -598
  88. data/spec/helper/legacy_help.rb +0 -16
  89. data/spec/helper/pg_dump_restore_spec.rb +0 -67
  90. data/spec/spec.opts +0 -1
  91. data/spec/support/display_message_matcher.rb +0 -49
  92. data/spec/support/dummy_api.rb +0 -120
  93. data/spec/support/openssl_mock_helper.rb +0 -8
  94. data/spec/support/organizations_mock_helper.rb +0 -11
  95. data/spec/turbot/auth_spec.rb +0 -214
  96. data/spec/turbot/client/pgbackups_spec.rb +0 -43
  97. data/spec/turbot/client/rendezvous_spec.rb +0 -62
  98. data/spec/turbot/client/ssl_endpoint_spec.rb +0 -48
  99. data/spec/turbot/client/turbot_postgresql_spec.rb +0 -71
  100. data/spec/turbot/client_spec.rb +0 -548
  101. data/spec/turbot/helpers/turbot_postgresql_spec.rb +0 -181
  102. data/spec/turbot/plugin_spec.rb +0 -172
  103. data/spec/turbot/updater_spec.rb +0 -44
@@ -1,176 +1,123 @@
1
- require "turbot/command/base"
2
- require "turbot/deprecated/help"
3
-
4
- # list commands and display help
1
+ #List commands and display help
5
2
  #
6
3
  class Turbot::Command::Help < Turbot::Command::Base
7
-
8
- PRIMARY_NAMESPACES = %w( auth bots ps run addons config releases domains logs sharing )
9
-
10
- include Turbot::Deprecated::Help
4
+ PRIMARY_NAMESPACES = Set.new(%w(auth bots))
11
5
 
12
6
  # help [COMMAND]
13
7
  #
14
- # list available commands or display help for a specific command
8
+ #List available commands or display help for a specific command.
15
9
  #
16
10
  #Examples:
17
11
  #
18
- # $ turbot help
19
- # Usage: turbot COMMAND [--bot APP] [command-specific-options]
12
+ # $ turbot help
13
+ # Usage: turbot COMMAND [--bot APP] [command-specific-options]
20
14
  #
21
- # Primary help topics, type "turbot help TOPIC" for more details:
15
+ # Primary help topics, type "turbot help TOPIC" for more details:
22
16
  #
23
- # addons # manage addon resources
24
- # bots # manage bots (create, destroy)
25
- # ...
17
+ # auth # Login or logout from Turbot
18
+ # bots # Manage bots (generate skeleton, validate data, submit code)
26
19
  #
27
- # Additional topics:
20
+ # Additional topics:
28
21
  #
29
- # account # manage turbot account options
30
- # accounts # manage multiple turbot accounts
31
- # ...
22
+ # help # List commands and display help
23
+ # version # Display version
32
24
  #
33
- # $ turbot help bots:create
34
- # Usage: turbot bots:create [NAME]
25
+ # $ turbot help auth:whoam
26
+ # Usage: turbot auth:whoami
35
27
  #
36
- # create a new bot
28
+ # Display your Turbot email address.
37
29
  #
38
- # --addons ADDONS # a comma-delimited list of addons to install
39
- # -b, --buildpack BUILDPACK # a buildpack url to use for this bot
40
- # -r, --remote REMOTE # the git remote to create, default "turbot"
41
- # -s, --stack STACK # the stack on which to create the bot
30
+ # Example:
31
+ #
32
+ # $ turbot auth:whoami
33
+ # email@example.com
42
34
  #
43
35
  def index
44
- if command = args.shift
36
+ command = args.shift
37
+ if command
45
38
  help_for_command(command)
46
39
  else
47
40
  help_for_root
48
41
  end
49
42
  end
50
-
51
- alias_command "-h", "help"
52
- alias_command "--help", "help"
43
+ alias_command '-h', 'help'
44
+ alias_command '--help', 'help'
53
45
 
54
46
  private
55
47
 
56
- def commands_for_namespace(name)
57
- Turbot::Command.commands.values.select do |command|
58
- command[:namespace] == name && command[:command] != name
59
- end
60
- end
61
-
62
- def namespaces
63
- namespaces = Turbot::Command.namespaces
64
- namespaces.delete("bot")
65
- namespaces
66
- end
67
-
68
- def commands
69
- Turbot::Command.commands
70
- end
71
-
72
- def legacy_help_for_namespace(namespace)
73
- instance = Turbot::Command::Help.groups.map do |group|
74
- [ group.title, group.select { |c| c.first =~ /^#{namespace}/ }.length ]
75
- end.sort_by { |l| l.last }.last
76
- return nil unless instance
77
- return nil if instance.last.zero?
78
- instance.first
79
- end
80
-
81
- def legacy_help_for_command(command)
82
- Turbot::Command::Help.groups.each do |group|
83
- group.each do |cmd, description|
84
- return description if cmd.split(" ").first == command
85
- end
48
+ def help_for(items, name_key, description_key)
49
+ size = items.map { |namespace| namespace[name_key].size }.max
50
+ items.sort_by { |namespace| namespace[name_key] }.each do |namespace|
51
+ puts " %-#{size}s # %s" % [namespace[name_key], namespace[description_key]]
86
52
  end
87
- nil
88
53
  end
89
54
 
90
- def skip_namespace?(ns)
91
- return true if ns[:description] =~ /DEPRECATED:/
92
- return true if ns[:description] =~ /HIDDEN:/
93
- false
94
- end
55
+ ### Root
95
56
 
96
- def skip_command?(command)
97
- return true if command[:help] =~ /DEPRECATED:/
98
- return true if command[:help] =~ /^ HIDDEN:/
99
- false
57
+ def namespaces
58
+ Turbot::Command.namespaces
100
59
  end
101
60
 
102
61
  def primary_namespaces
103
- PRIMARY_NAMESPACES.map { |name| namespaces[name] }.compact
62
+ namespaces.select { |name,_| PRIMARY_NAMESPACES.include?(name) }.values
104
63
  end
105
64
 
106
65
  def additional_namespaces
107
- (namespaces.values - primary_namespaces)
66
+ namespaces.reject { |name,_| PRIMARY_NAMESPACES.include?(name) }.values
108
67
  end
109
68
 
110
69
  def summary_for_namespaces(namespaces)
111
- size = longest(namespaces.map { |n| n[:name] })
112
- namespaces.sort_by {|namespace| namespace[:name]}.each do |namespace|
113
- next if skip_namespace?(namespace)
114
- name = namespace[:name]
115
- namespace[:description] ||= legacy_help_for_namespace(name)
116
- puts " %-#{size}s # %s" % [ name, namespace[:description] ]
117
- end
70
+ help_for(namespaces, :name, :description)
118
71
  end
119
72
 
120
73
  def help_for_root
121
- puts "Usage: turbot COMMAND [--bot APP] [command-specific-options]"
74
+ puts 'Usage: turbot COMMAND [--bot APP] [command-specific-options]'
122
75
  puts
123
- puts "Primary help topics, type \"turbot help TOPIC\" for more details:"
76
+ puts 'Primary help topics, type "turbot help TOPIC" for more details:'
124
77
  puts
125
78
  summary_for_namespaces(primary_namespaces)
126
79
  puts
127
- puts "Additional topics:"
80
+ puts 'Additional topics:'
128
81
  puts
129
82
  summary_for_namespaces(additional_namespaces)
130
83
  puts
131
84
  end
132
85
 
133
- def help_for_namespace(name)
134
- namespace_commands = commands_for_namespace(name)
86
+ ### Command
87
+
88
+ def commands
89
+ Turbot::Command.commands
90
+ end
135
91
 
136
- unless namespace_commands.empty?
137
- size = longest(namespace_commands.map { |c| c[:banner] })
138
- namespace_commands.sort_by { |c| c[:banner].to_s }.each do |command|
139
- next if skip_command?(command)
140
- command[:summary] ||= legacy_help_for_command(command[:command])
141
- puts " %-#{size}s # %s" % [ command[:banner], command[:summary] ]
142
- end
92
+ def commands_for_namespace(name)
93
+ commands.values.select do |command|
94
+ command[:namespace] == name && command[:command] != name
143
95
  end
144
96
  end
145
97
 
98
+ def help_for_namespace(namespace_commands)
99
+ help_for(namespace_commands, :banner, :summary)
100
+ end
101
+
146
102
  def help_for_command(name)
147
- if command_alias = Turbot::Command.command_aliases[name]
148
- display("Alias: #{name} redirects to #{command_alias}")
103
+ command_alias = Turbot::Command.command_aliases[name]
104
+ if command_alias
105
+ puts "Alias: #{name} redirects to #{command_alias}"
149
106
  name = command_alias
150
107
  end
151
- if command = commands[name]
152
- puts "Usage: turbot #{command[:banner]}"
153
108
 
154
- if command[:help].strip.length > 0
155
- help = command[:help].split("\n").reject do |line|
156
- line =~ /HIDDEN/
157
- end
158
- puts help[1..-1].join("\n")
159
- else
160
- puts
161
- puts " " + legacy_help_for_command(name).to_s
162
- end
109
+ command = commands[name]
110
+ if command
111
+ puts "Usage: turbot #{command[:banner]}"
112
+ puts command[:help].split("\n").drop(1).join("\n")
163
113
  puts
164
114
  end
165
115
 
166
- namespace_commands = commands_for_namespace(name).reject do |command|
167
- command[:help] =~ /DEPRECATED/
168
- end
169
-
116
+ namespace_commands = commands_for_namespace(name)
170
117
  if !namespace_commands.empty?
171
- puts "Additional commands, type \"turbot help COMMAND\" for more details:"
118
+ puts 'Additional commands, type "turbot help COMMAND" for more details:'
172
119
  puts
173
- help_for_namespace(name)
120
+ help_for_namespace(namespace_commands)
174
121
  puts
175
122
  elsif command.nil?
176
123
  error "#{name} is not a turbot command. See `turbot help`."
@@ -1,23 +1,19 @@
1
- require "turbot/command/base"
2
- require "turbot/version"
3
-
4
- # display version
1
+ #Display version
5
2
  #
6
3
  class Turbot::Command::Version < Turbot::Command::Base
7
4
 
8
5
  # version
9
6
  #
10
- # show turbot client version
7
+ #Show the Turbot client's version.
11
8
  #
12
9
  #Example:
13
10
  #
14
- # $ turbot version
15
- # turbot-toolbelt/1.2.3 (x86_64-darwin11.2.0) ruby/1.9.3
11
+ # $ turbot version
12
+ # turbot-gem/0.1.36 (x86_64-darwin14) ruby/2.2.0
16
13
  #
17
14
  def index
18
15
  validate_arguments!
19
-
20
- display(Turbot.user_agent)
16
+ puts "#{Turbot::DEBUG_VERSION}"
21
17
  end
22
-
18
+ alias_command '--version', 'version'
23
19
  end
@@ -0,0 +1,21 @@
1
+ module Turbot
2
+ module Handlers
3
+ class BaseHandler < TurbotRunner::BaseHandler
4
+ # Implements `TurbotRunner::BaseHandler#handle_invalid_record`.
5
+ def handle_invalid_record(record, data_type, error_message)
6
+ puts
7
+ puts 'The following record is invalid:'
8
+ puts record.to_json
9
+ puts " * #{error_message}"
10
+ puts
11
+ end
12
+
13
+ # Implements `TurbotRunner::BaseHandler#handle_invalid_json`.
14
+ def handle_invalid_json(line)
15
+ puts
16
+ puts 'The following line was not valid JSON:'
17
+ puts line
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ module Turbot
2
+ module Handlers
3
+ class DumpHandler < BaseHandler
4
+ # Implements `TurbotRunner::BaseHandler#handle_valid_record`.
5
+ def handle_valid_record(record, data_type)
6
+ puts record.to_json
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,30 @@
1
+ module Turbot
2
+ module Handlers
3
+ class PreviewHandler < BaseHandler
4
+ attr_reader :count
5
+
6
+ def initialize(bot_name, api)
7
+ @bot_name = bot_name
8
+ @api = api
9
+ @count = 0
10
+ @batch = []
11
+ end
12
+
13
+ # Implements `TurbotRunner::BaseHandler#handle_valid_record`.
14
+ def handle_valid_record(record, data_type)
15
+ @count += 1
16
+ STDOUT.write('.')
17
+ @batch << record.merge(:data_type => data_type)
18
+ if @count % 20 == 0
19
+ submit_batch
20
+ end
21
+ end
22
+
23
+ def submit_batch
24
+ result = @api.create_draft_data(@bot_name, @batch.to_json)
25
+ @batch = []
26
+ result
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,17 @@
1
+ module Turbot
2
+ module Handlers
3
+ class ValidationHandler < BaseHandler
4
+ attr_reader :count
5
+
6
+ def initialize
7
+ @count = 0
8
+ end
9
+
10
+ # Implements `TurbotRunner::BaseHandler#handle_valid_record`.
11
+ def handle_valid_record(record, data_type)
12
+ @count += 1
13
+ STDOUT.write('.')
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,368 +1,27 @@
1
- require "vendor/turbot/okjson"
2
-
3
1
  module Turbot
4
2
  module Helpers
3
+ DEFAULT_HOST = 'http://turbot.opencorporates.com'
5
4
 
6
5
  extend self
7
6
 
8
- def home_directory
9
- running_on_windows? ? ENV['USERPROFILE'].gsub("\\","/") : ENV['HOME']
10
- end
11
-
12
- def running_on_windows?
13
- RUBY_PLATFORM =~ /mswin32|mingw32/
14
- end
15
-
16
- def running_on_a_mac?
17
- RUBY_PLATFORM =~ /-darwin\d/
18
- end
19
-
20
- def display(msg="", new_line=true)
21
- if new_line
22
- puts(msg)
23
- else
24
- print(msg)
25
- end
26
- $stdout.flush
27
- end
28
-
29
- def redisplay(line, line_break = false)
30
- display("\r\e[0K#{line}", line_break)
31
- end
32
-
33
- def deprecate(message)
34
- display "WARNING: #{message}"
35
- end
36
-
37
- def confirm(message="Are you sure you wish to continue? (y/n)")
38
- display("#{message} ", false)
39
- ['y', 'yes'].include?(ask.downcase)
40
- end
41
-
42
- def confirm_command(bot_to_confirm = bot, message=nil)
43
- if confirmed_bot = Turbot::Command.current_options[:confirm]
44
- unless confirmed_bot == bot_to_confirm
45
- raise(Turbot::Command::CommandFailed, "Confirmed bot #{confirmed_bot} did not match the selected bot #{bot_to_confirm}.")
46
- end
47
- return true
48
- else
49
- display
50
- message ||= "WARNING: Destructive Action\nThis command will affect the bot: #{bot_to_confirm}"
51
- message << "\nTo proceed, type \"#{bot_to_confirm}\" or re-run this command with --confirm #{bot_to_confirm}"
52
- output_with_bang(message)
53
- display
54
- display "> ", false
55
- if ask.downcase != bot_to_confirm
56
- error("Confirmation did not match #{bot_to_confirm}. Aborted.")
57
- else
58
- true
59
- end
60
- end
61
- end
62
-
63
- def format_date(date)
64
- date = Time.parse(date).utc if date.is_a?(String)
65
- date.strftime("%Y-%m-%d %H:%M %Z").gsub('GMT', 'UTC')
66
- end
67
-
68
- def ask
69
- $stdin.gets.to_s.strip
70
- end
71
-
72
- def shell(cmd)
73
- FileUtils.cd(Dir.pwd) {|d| return `#{cmd}`}
74
- end
75
-
76
- def run_command(command, args=[])
77
- Turbot::Command.run(command, args)
78
- end
79
-
80
- def retry_on_exception(*exceptions)
81
- retry_count = 0
82
- begin
83
- yield
84
- rescue *exceptions => ex
85
- raise ex if retry_count >= 3
86
- sleep 3
87
- retry_count += 1
88
- retry
89
- end
90
- end
91
-
92
- def has_git?
93
- %x{ git --version }
94
- $?.success?
95
- end
96
-
97
- def git(args)
98
- return "" unless has_git?
99
- flattened_args = [args].flatten.compact.join(" ")
100
- %x{ git #{flattened_args} 2>&1 }.strip
101
- end
102
-
103
- def time_ago(since)
104
- if since.is_a?(String)
105
- since = Time.parse(since)
106
- end
107
-
108
- elapsed = Time.now - since
109
-
110
- message = since.strftime("%Y/%m/%d %H:%M:%S")
111
- if elapsed <= 60
112
- message << " (~ #{elapsed.floor}s ago)"
113
- elsif elapsed <= (60 * 60)
114
- message << " (~ #{(elapsed / 60).floor}m ago)"
115
- elsif elapsed <= (60 * 60 * 25)
116
- message << " (~ #{(elapsed / 60 / 60).floor}h ago)"
117
- end
118
- message
119
- end
120
-
121
- def truncate(text, length)
122
- if text.size > length
123
- text[0, length - 2] + '..'
124
- else
125
- text
126
- end
127
- end
128
-
129
- @@kb = 1024
130
- @@mb = 1024 * @@kb
131
- @@gb = 1024 * @@mb
132
- def format_bytes(amount)
133
- amount = amount.to_i
134
- return '(empty)' if amount == 0
135
- return amount if amount < @@kb
136
- return "#{(amount / @@kb).round}k" if amount < @@mb
137
- return "#{(amount / @@mb).round}M" if amount < @@gb
138
- return "#{(amount / @@gb).round}G"
139
- end
140
-
141
- def quantify(string, num)
142
- "%d %s" % [ num, num.to_i == 1 ? string : "#{string}s" ]
143
- end
144
-
145
- def create_git_remote(remote, url)
146
- return if git('remote').split("\n").include?(remote)
147
- return unless File.exists?(".git")
148
- git "remote add #{remote} #{url}"
149
- display "Git remote #{remote} added"
150
- end
151
-
152
- def longest(items)
153
- items.map { |i| i.to_s.length }.sort.last
154
- end
155
-
156
- def display_table(objects, columns, headers)
157
- lengths = []
158
- columns.each_with_index do |column, index|
159
- header = headers[index]
160
- lengths << longest([header].concat(objects.map { |o| o[column].to_s }))
161
- end
162
- lines = lengths.map {|length| "-" * length}
163
- lengths[-1] = 0 # remove padding from last column
164
- display_row headers, lengths
165
- display_row lines, lengths
166
- objects.each do |row|
167
- display_row columns.map { |column| row[column] }, lengths
168
- end
169
- end
170
-
171
- def display_row(row, lengths)
172
- row_data = []
173
- row.zip(lengths).each do |column, length|
174
- format = column.is_a?(Fixnum) ? "%#{length}s" : "%-#{length}s"
175
- row_data << format % column
176
- end
177
- display(row_data.join(" "))
178
- end
179
-
180
- def json_encode(object)
181
- Turbot::OkJson.encode(object)
182
- rescue Turbot::OkJson::Error
183
- nil
184
- end
185
-
186
- def json_decode(json)
187
- Turbot::OkJson.decode(json)
188
- rescue Turbot::OkJson::Error
189
- nil
190
- end
191
-
192
- def set_buffer(enable)
193
- with_tty do
194
- if enable
195
- `stty icanon echo`
196
- else
197
- `stty -icanon -echo`
198
- end
199
- end
200
- end
201
-
202
- def with_tty(&block)
203
- return unless $stdin.isatty
204
- begin
205
- yield
206
- rescue
207
- # fails on windows
208
- end
209
- end
210
-
211
- def get_terminal_environment
212
- { "TERM" => ENV["TERM"], "COLUMNS" => `tput cols`.strip, "LINES" => `tput lines`.strip }
213
- rescue
214
- { "TERM" => ENV["TERM"] }
215
- end
216
-
217
- def fail(message)
218
- raise Turbot::Command::CommandFailed, message
219
- end
220
-
221
- ## DISPLAY HELPERS
222
-
223
- def action(message, options={})
224
- message = "#{message} in organzation #{org}" if options[:org]
225
- display("#{message}... ", false)
226
- Turbot::Helpers.error_with_failure = true
227
- ret = yield
228
- Turbot::Helpers.error_with_failure = false
229
- display((options[:success] || "done"), false)
230
- if @status
231
- display(", #{@status}", false)
232
- @status = nil
233
- end
234
- display
235
- ret
236
- end
237
-
238
- def status(message)
239
- @status = message
240
- end
241
-
242
- def format_with_bang(message)
243
- return '' if message.to_s.strip == ""
244
- " ! " + message.split("\n").join("\n ! ")
245
- end
246
-
247
- def output_with_bang(message="", new_line=true)
248
- return if message.to_s.strip == ""
249
- display(format_with_bang(message), new_line)
7
+ # Returns the base URL of the Turbot server.
8
+ #
9
+ # @return [String] the base URL of the Turbot server
10
+ def host
11
+ ENV['TURBOT_HOST'] || DEFAULT_HOST
250
12
  end
251
13
 
252
14
  def error(message)
253
- if Turbot::Helpers.error_with_failure
254
- display("failed")
255
- Turbot::Helpers.error_with_failure = false
256
- end
257
- $stderr.puts(format_with_bang(message))
15
+ prefix = ' ! '
16
+ $stderr.puts(prefix + message.split("\n").join("\n#{prefix}"))
258
17
  exit(1)
259
18
  end
260
19
 
261
- def self.error_with_failure
262
- @@error_with_failure ||= false
263
- end
264
-
265
- def self.error_with_failure=(new_error_with_failure)
266
- @@error_with_failure = new_error_with_failure
267
- end
268
-
269
- def self.included_into
270
- @@included_into ||= []
271
- end
272
-
273
- def self.extended_into
274
- @@extended_into ||= []
275
- end
276
-
277
- def self.included(base)
278
- included_into << base
279
- end
280
-
281
- def self.extended(base)
282
- extended_into << base
283
- end
284
-
285
- def display_header(message="", new_line=true)
286
- return if message.to_s.strip == ""
287
- display("=== " + message.to_s.split("\n").join("\n=== "), new_line)
288
- end
289
-
290
- def display_object(object)
291
- case object
292
- when Array
293
- # list of objects
294
- object.each do |item|
295
- display_object(item)
296
- end
297
- when Hash
298
- # if all values are arrays, it is a list with headers
299
- # otherwise it is a single header with pairs of data
300
- if object.values.all? {|value| value.is_a?(Array)}
301
- object.keys.sort_by {|key| key.to_s}.each do |key|
302
- display_header(key)
303
- display_object(object[key])
304
- hputs
305
- end
306
- end
307
- else
308
- hputs(object.to_s)
309
- end
310
- end
311
-
312
- def hputs(string='')
313
- Kernel.puts(string)
314
- end
315
-
316
- def hprint(string='')
317
- Kernel.print(string)
318
- $stdout.flush
319
- end
320
-
321
- def spinner(ticks)
322
- %w(/ - \\ |)[ticks % 4]
323
- end
324
-
325
- def launchy(message, url)
326
- action(message) do
327
- require("launchy")
328
- launchy = Launchy.open(url)
329
- if launchy.respond_to?(:join)
330
- launchy.join
331
- end
332
- end
333
- end
334
-
335
- # produces a printf formatter line for an array of items
336
- # if an individual line item is an array, it will create columns
337
- # that are lined-up
338
- #
339
- # line_formatter(["foo", "barbaz"]) # => "%-6s"
340
- # line_formatter(["foo", "barbaz"], ["bar", "qux"]) # => "%-3s %-6s"
341
- #
342
- def line_formatter(array)
343
- if array.any? {|item| item.is_a?(Array)}
344
- cols = []
345
- array.each do |item|
346
- if item.is_a?(Array)
347
- item.each_with_index { |val,idx| cols[idx] = [cols[idx]||0, (val || '').length].max }
348
- end
349
- end
350
- cols.map { |col| "%-#{col}s" }.join(" ")
351
- else
352
- "%s"
353
- end
354
- end
355
-
356
- def styled_array(array, options={})
357
- fmt = line_formatter(array)
358
- array = array.sort unless options[:sort] == false
359
- array.each do |element|
360
- display((fmt % element).rstrip)
361
- end
362
- display
20
+ def styled_error(error, message = 'Turbot client internal error.')
21
+ $stderr.puts(format_error(error, message))
363
22
  end
364
23
 
365
- def format_error(error, message='Turbot client internal error.')
24
+ def format_error(error, message = 'Turbot client internal error.')
366
25
  formatted_error = []
367
26
  formatted_error << " ! #{message}"
368
27
  formatted_error << ' ! Report a bug at: https://github.com/openc/turbot-client/issues/new'
@@ -383,139 +42,12 @@ module Turbot
383
42
  end
384
43
  end.join(' ')
385
44
  formatted_error << " Command: turbot #{command}"
386
- require 'turbot/auth'
387
- unless Turbot::Auth.host == Turbot::Auth.default_host
388
- formatted_error << " Host: #{Turbot::Auth.host}"
389
- end
390
- if http_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
391
- formatted_error << " HTTP Proxy: #{http_proxy}"
45
+ unless host == DEFAULT_HOST
46
+ formatted_error << " Host: #{host}"
392
47
  end
393
- if https_proxy = ENV['https_proxy'] || ENV['HTTPS_PROXY']
394
- formatted_error << " HTTPS Proxy: #{https_proxy}"
395
- end
396
- plugins = Turbot::Plugin.list.sort
397
- unless plugins.empty?
398
- formatted_error << " Plugins: #{plugins.first}"
399
- plugins[1..-1].each do |plugin|
400
- formatted_error << " #{plugin}"
401
- end
402
- if plugins.length > 1
403
- formatted_error << ''
404
- $stderr.puts
405
- end
406
- end
407
- formatted_error << " Version: #{Turbot.user_agent}"
48
+ formatted_error << " Version: #{Turbot::DEBUG_VERSION}"
408
49
  formatted_error << "\n"
409
50
  formatted_error.join("\n")
410
51
  end
411
-
412
- def styled_error(error, message='Turbot client internal error.')
413
- if Turbot::Helpers.error_with_failure
414
- display("failed")
415
- Turbot::Helpers.error_with_failure = false
416
- end
417
- $stderr.puts(format_error(error, message))
418
- end
419
-
420
- def styled_header(header)
421
- display("=== #{header}")
422
- end
423
-
424
- def styled_hash(hash, keys=nil)
425
- max_key_length = hash.keys.map {|key| key.to_s.length}.max + 2
426
- keys ||= hash.keys.sort {|x,y| x.to_s <=> y.to_s}
427
- keys.each do |key|
428
- case value = hash[key]
429
- when Array
430
- if value.empty?
431
- next
432
- else
433
- elements = value.sort {|x,y| x.to_s <=> y.to_s}
434
- display("#{key}: ".ljust(max_key_length), false)
435
- display(elements[0])
436
- elements[1..-1].each do |element|
437
- display("#{' ' * max_key_length}#{element}")
438
- end
439
- if elements.length > 1
440
- display
441
- end
442
- end
443
- when nil
444
- next
445
- else
446
- display("#{key}: ".ljust(max_key_length), false)
447
- display(value)
448
- end
449
- end
450
- end
451
-
452
- def string_distance(first, last)
453
- distances = [] # 0x0s
454
- 0.upto(first.length) do |index|
455
- distances << [index] + [0] * last.length
456
- end
457
- distances[0] = 0.upto(last.length).to_a
458
- 1.upto(last.length) do |last_index|
459
- 1.upto(first.length) do |first_index|
460
- first_char = first[first_index - 1, 1]
461
- last_char = last[last_index - 1, 1]
462
- if first_char == last_char
463
- distances[first_index][last_index] = distances[first_index - 1][last_index - 1] # noop
464
- else
465
- distances[first_index][last_index] = [
466
- distances[first_index - 1][last_index], # deletion
467
- distances[first_index][last_index - 1], # insertion
468
- distances[first_index - 1][last_index - 1] # substitution
469
- ].min + 1 # cost
470
- if first_index > 1 && last_index > 1
471
- first_previous_char = first[first_index - 2, 1]
472
- last_previous_char = last[last_index - 2, 1]
473
- if first_char == last_previous_char && first_previous_char == last_char
474
- distances[first_index][last_index] = [
475
- distances[first_index][last_index],
476
- distances[first_index - 2][last_index - 2] + 1 # transposition
477
- ].min
478
- end
479
- end
480
- end
481
- end
482
- end
483
- distances[first.length][last.length]
484
- end
485
-
486
- def suggestion(actual, possibilities)
487
- distances = Hash.new {|hash,key| hash[key] = []}
488
- possibilities.each do |suggestion|
489
- distances[string_distance(actual, suggestion)] << suggestion
490
- end
491
- minimum_distance = distances.keys.min
492
- if minimum_distance < 4
493
- suggestions = distances[minimum_distance].sort
494
- if suggestions.length == 1
495
- "Perhaps you meant `#{suggestions.first}`."
496
- else
497
- "Perhaps you meant #{suggestions[0...-1].map {|suggestion| "`#{suggestion}`"}.join(', ')} or `#{suggestions.last}`."
498
- end
499
- else
500
- nil
501
- end
502
- end
503
-
504
- def org_host
505
- ENV["TURBOT_ORG_HOST"] || default_org_host
506
- end
507
-
508
- def default_org_host
509
- "turbotmanager.com"
510
- end
511
-
512
- def org? email
513
- email =~ /^.*@#{org_host}$/
514
- end
515
-
516
- def bot_owner email
517
- org?(email) ? email.gsub(/^(.*)@#{org_host}$/,'\1') : email
518
- end
519
-
520
52
  end
521
53
  end