turbot 0.1.36 → 0.2.3

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.
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