collins_shell 0.2.14

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 (39) hide show
  1. data/.pryrc +1 -0
  2. data/.rvmrc +1 -0
  3. data/Gemfile +18 -0
  4. data/Gemfile.lock +59 -0
  5. data/README.md +335 -0
  6. data/Rakefile +64 -0
  7. data/VERSION +1 -0
  8. data/bin/collins-shell +36 -0
  9. data/collins_shell.gemspec +95 -0
  10. data/lib/collins_shell.rb +3 -0
  11. data/lib/collins_shell/asset.rb +198 -0
  12. data/lib/collins_shell/cli.rb +185 -0
  13. data/lib/collins_shell/console.rb +129 -0
  14. data/lib/collins_shell/console/asset.rb +127 -0
  15. data/lib/collins_shell/console/cache.rb +17 -0
  16. data/lib/collins_shell/console/command_helpers.rb +131 -0
  17. data/lib/collins_shell/console/commands.rb +28 -0
  18. data/lib/collins_shell/console/commands/cat.rb +123 -0
  19. data/lib/collins_shell/console/commands/cd.rb +61 -0
  20. data/lib/collins_shell/console/commands/io.rb +26 -0
  21. data/lib/collins_shell/console/commands/iterators.rb +190 -0
  22. data/lib/collins_shell/console/commands/tail.rb +178 -0
  23. data/lib/collins_shell/console/commands/versions.rb +42 -0
  24. data/lib/collins_shell/console/filesystem.rb +121 -0
  25. data/lib/collins_shell/console/options_helpers.rb +8 -0
  26. data/lib/collins_shell/errors.rb +7 -0
  27. data/lib/collins_shell/ip_address.rb +144 -0
  28. data/lib/collins_shell/ipmi.rb +67 -0
  29. data/lib/collins_shell/monkeypatch.rb +60 -0
  30. data/lib/collins_shell/provision.rb +152 -0
  31. data/lib/collins_shell/state.rb +98 -0
  32. data/lib/collins_shell/tag.rb +41 -0
  33. data/lib/collins_shell/thor.rb +209 -0
  34. data/lib/collins_shell/util.rb +120 -0
  35. data/lib/collins_shell/util/asset_printer.rb +265 -0
  36. data/lib/collins_shell/util/asset_stache.rb +32 -0
  37. data/lib/collins_shell/util/log_printer.rb +187 -0
  38. data/lib/collins_shell/util/printer_util.rb +28 -0
  39. metadata +200 -0
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.14
data/bin/collins-shell ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if ENV.key?('COLLINS_DEBUG') && ENV['COLLINS_DEBUG'] then
4
+ HTTP_DEBUG = true
5
+ end
6
+
7
+ # Make sure we're running a valid version of ruby
8
+ if RUBY_VERSION !~ /^1\.9\./ then
9
+ puts("We require ruby 1.9.2")
10
+ exit(1)
11
+ end
12
+
13
+ if not ENV.key?('HOME') || ENV['HOME'].empty? then
14
+ puts("No HOME environment found. Exiting")
15
+ exit(2)
16
+ end
17
+
18
+ $:.unshift File.join File.dirname(__FILE__), *%w[.. lib]
19
+ # Allows us to use a dev version of collins-client if needed
20
+ $:.unshift File.join File.dirname(__FILE__), *%w[.. .. ruby collins-client lib]
21
+ %w[collins_shell collins_shell/cli].each {|f| require f}
22
+
23
+ begin
24
+ CollinsShell::Cli.start
25
+ rescue SystemExit => e
26
+ rescue CollinsShell::ConfigurationError => e
27
+ cli = CollinsShell::Cli.new
28
+ cli.say_status("fatal", "your environment is not setup correctly", :red)
29
+ cli.say_status("message", "#{e.message}")
30
+ exit(1)
31
+ rescue Exception => e
32
+ cli = CollinsShell::Cli.new
33
+ cli.print_error e
34
+ exit(2)
35
+ end
36
+ exit(0)
@@ -0,0 +1,95 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "collins_shell"
8
+ s.version = "0.2.14"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Blake Matheny"]
12
+ s.date = "2012-10-31"
13
+ s.description = "Provides basic CLI for interacting with Collins API"
14
+ s.email = "bmatheny@tumblr.com"
15
+ s.executables = ["collins-shell"]
16
+ s.extra_rdoc_files = [
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ ".pryrc",
21
+ ".rvmrc",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "README.md",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "bin/collins-shell",
28
+ "collins_shell.gemspec",
29
+ "lib/collins_shell.rb",
30
+ "lib/collins_shell/asset.rb",
31
+ "lib/collins_shell/cli.rb",
32
+ "lib/collins_shell/console.rb",
33
+ "lib/collins_shell/console/asset.rb",
34
+ "lib/collins_shell/console/cache.rb",
35
+ "lib/collins_shell/console/command_helpers.rb",
36
+ "lib/collins_shell/console/commands.rb",
37
+ "lib/collins_shell/console/commands/cat.rb",
38
+ "lib/collins_shell/console/commands/cd.rb",
39
+ "lib/collins_shell/console/commands/io.rb",
40
+ "lib/collins_shell/console/commands/iterators.rb",
41
+ "lib/collins_shell/console/commands/tail.rb",
42
+ "lib/collins_shell/console/commands/versions.rb",
43
+ "lib/collins_shell/console/filesystem.rb",
44
+ "lib/collins_shell/console/options_helpers.rb",
45
+ "lib/collins_shell/errors.rb",
46
+ "lib/collins_shell/ip_address.rb",
47
+ "lib/collins_shell/ipmi.rb",
48
+ "lib/collins_shell/monkeypatch.rb",
49
+ "lib/collins_shell/provision.rb",
50
+ "lib/collins_shell/state.rb",
51
+ "lib/collins_shell/tag.rb",
52
+ "lib/collins_shell/thor.rb",
53
+ "lib/collins_shell/util.rb",
54
+ "lib/collins_shell/util/asset_printer.rb",
55
+ "lib/collins_shell/util/asset_stache.rb",
56
+ "lib/collins_shell/util/log_printer.rb",
57
+ "lib/collins_shell/util/printer_util.rb"
58
+ ]
59
+ s.homepage = "https://github.com/tumblr/collins/tree/master/support/collins-shell"
60
+ s.licenses = ["APL 2.0"]
61
+ s.require_paths = ["lib"]
62
+ s.rubygems_version = "1.8.24"
63
+ s.summary = "Shell for Collins API"
64
+
65
+ if s.respond_to? :specification_version then
66
+ s.specification_version = 3
67
+
68
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
69
+ s.add_runtime_dependency(%q<collins_client>, ["~> 0.2.7"])
70
+ s.add_runtime_dependency(%q<highline>, ["~> 1.6.15"])
71
+ s.add_runtime_dependency(%q<mustache>, ["~> 0.99.4"])
72
+ s.add_runtime_dependency(%q<pry>, ["~> 0.9.9.6"])
73
+ s.add_runtime_dependency(%q<rubygems-update>, ["~> 1.8.24"])
74
+ s.add_runtime_dependency(%q<terminal-table>, ["~> 1.4.5"])
75
+ s.add_runtime_dependency(%q<thor>, ["~> 0.16.0"])
76
+ else
77
+ s.add_dependency(%q<collins_client>, ["~> 0.2.7"])
78
+ s.add_dependency(%q<highline>, ["~> 1.6.15"])
79
+ s.add_dependency(%q<mustache>, ["~> 0.99.4"])
80
+ s.add_dependency(%q<pry>, ["~> 0.9.9.6"])
81
+ s.add_dependency(%q<rubygems-update>, ["~> 1.8.24"])
82
+ s.add_dependency(%q<terminal-table>, ["~> 1.4.5"])
83
+ s.add_dependency(%q<thor>, ["~> 0.16.0"])
84
+ end
85
+ else
86
+ s.add_dependency(%q<collins_client>, ["~> 0.2.7"])
87
+ s.add_dependency(%q<highline>, ["~> 1.6.15"])
88
+ s.add_dependency(%q<mustache>, ["~> 0.99.4"])
89
+ s.add_dependency(%q<pry>, ["~> 0.9.9.6"])
90
+ s.add_dependency(%q<rubygems-update>, ["~> 1.8.24"])
91
+ s.add_dependency(%q<terminal-table>, ["~> 1.4.5"])
92
+ s.add_dependency(%q<thor>, ["~> 0.16.0"])
93
+ end
94
+ end
95
+
@@ -0,0 +1,3 @@
1
+ $:.unshift File.join File.dirname(__FILE__)
2
+ require 'collins_shell/errors'
3
+ require 'pp'
@@ -0,0 +1,198 @@
1
+ require 'collins_shell/thor'
2
+ require 'collins_shell/util'
3
+ require 'collins_shell/util/asset_printer'
4
+ require 'thor'
5
+ require 'thor/group'
6
+
7
+ module CollinsShell
8
+
9
+ class Asset < Thor
10
+ include ThorHelper
11
+ include CollinsShell::Util
12
+ namespace :asset
13
+ def self.banner task, namespace = true, subcommand = false
14
+ "#{basename} #{task.formatted_usage(self, true, subcommand).gsub(':',' ')}"
15
+ end
16
+
17
+ desc 'create', 'create an asset in collins'
18
+ use_collins_options
19
+ use_tag_option(true)
20
+ method_option :ipmi, :type => :boolean, :desc => 'Generate IPMI data'
21
+ method_option :status, :type => :string, :desc => 'Status of asset'
22
+ method_option :type, :type => :string, :desc => 'Asset type'
23
+ def create
24
+ call_collins get_collins_client, "create asset" do |client|
25
+ asset = client.create! options.tag, :generate_ipmi => options.ipmi, :status => options.status, :type => options.type
26
+ print_find_results asset, nil
27
+ end
28
+ end
29
+
30
+ desc 'delete', 'delete an asset in collins (must be cancelled)'
31
+ use_collins_options
32
+ use_tag_option(true)
33
+ method_option :reason, :required => true, :type => :string, :desc => 'Reason to delete asset'
34
+ def delete
35
+ call_collins get_collins_client, "delete asset" do |client|
36
+ if client.delete!(options.tag, :reason => options.reason) then
37
+ say_success "deleted asset #{options.tag}"
38
+ else
39
+ say_error "deleting asset #{options.tag}", :exit => true
40
+ end
41
+ end
42
+ end
43
+
44
+ desc 'find', 'find assets using the specified selector'
45
+ use_collins_options
46
+ use_selector_option(true)
47
+ method_option :confirm, :type => :boolean, :default => :true, :desc => 'Require exec confirmation. Defaults to true'
48
+ method_option :details, :type => :boolean, :desc => 'Output assets how you see them in get'
49
+ method_option :exec, :type => :string, :desc => 'Execute a command using the data from this asset. Use {{hostname}}, {{ipmi.password}}, etc for substitution'
50
+ method_option :header, :type => :boolean, :default => true, :desc => 'Display a tag header. Defaults to true'
51
+ method_option :logs, :type => :boolean, :default => false, :desc => 'Also display asset logs, only used with details (SLOW)'
52
+ method_option :size, :type => :numeric, :default => 50, :desc => 'Number of results to find. Defaults to 50'
53
+ method_option :tags, :type => :array, :desc => 'Tags to display of form: tag1 tag2 tag3. e.g. --tags=hostname tag backend_ip_address'
54
+ method_option :url, :type => :boolean, :default => true, :desc => 'Display a URL along with tags or the default listing'
55
+ def find
56
+ client = get_collins_client
57
+ tags = options.tags || [:stuff]
58
+ selector = get_selector options.selector, tags, options["size"], options.remote
59
+ assets = client.find selector
60
+ if options.details then
61
+ assets.each do |asset|
62
+ if not options.quiet then
63
+ logs = []
64
+ if options.logs and not options.exec? then
65
+ logs = client.logs(asset, :size => 5000, :SORT => "DESC").reverse
66
+ end
67
+ printer = CollinsShell::AssetPrinter.new asset, self, :separator => '*',
68
+ :logs => logs,
69
+ :detailed => !options.exec?
70
+ puts printer
71
+ end
72
+ asset_exec asset, options.exec, options.confirm
73
+ end
74
+ else
75
+ if not options.quiet then
76
+ print_find_results assets, options.tags, :header => options.header, :url => options.url
77
+ end
78
+ assets.each {|asset| asset_exec(asset, options.exec, options.confirm)}
79
+ end
80
+ end
81
+
82
+ desc 'find_similar TAG', 'get similar unallocated assets for a gven asset'
83
+ use_collins_options
84
+ method_option :size, :type => :numeric, :default => 50, :desc => 'number of results to find. Defaults to 50'
85
+ method_option :details, :type => :boolean, :desc => 'Output assets how you see them in get'
86
+ method_option :sort, :type => :string, :default => "DESC", :desc => 'sort direction, either ASC or DESC'
87
+ method_option :sort_type, :type => :string, :default => "distribution", :desc => 'sorting type'
88
+ method_option :only_unallocated, :type => :boolean, :default => true, :desc => 'only return unallocated assets, defaults to true'
89
+ def find_similar tag
90
+ call_collins get_collins_client, "similar asset" do |client|
91
+ as_asset = Collins::Asset.new(tag)
92
+ assets = client.find_similar as_asset, options["size"], options["sort"], options.sort_type, options.only_unallocated
93
+ if options.details then
94
+ assets.each do |asset|
95
+ printer = CollinsShell::AssetPrinter.new asset, self, :separator => '*'
96
+ puts printer
97
+ end
98
+ else
99
+ print_find_results assets, options.tags
100
+ end
101
+ end
102
+ end
103
+
104
+ desc 'get TAG', 'get an asset and display its attributes'
105
+ use_collins_options
106
+ method_option :confirm, :type => :boolean, :default => :true, :desc => 'Require exec confirmation. Defaults to true'
107
+ method_option :exec, :type => :string, :desc => 'Execute a command using the data from this asset. Use {{hostname}}, {{ipmi.password}}, etc for substitution'
108
+ method_option :logs, :type => :boolean, :default => false, :desc => 'Also display asset logs'
109
+ method_option :remote, :type => :string, :desc => 'Remote location to search. This is a tag in collins corresponding to the datacenter asset'
110
+ def get tag
111
+ asset = asset_get tag, options
112
+ if asset then
113
+ if not options.quiet then
114
+ logs = []
115
+ if options.logs and not options.exec? then
116
+ logs = call_collins(get_collins_client, "logs") do |client|
117
+ client.logs(asset, :size => 5000, :sort => "DESC").reverse
118
+ end
119
+ end
120
+ printer = CollinsShell::AssetPrinter.new asset, self, :logs => logs, :detailed => !options.exec?
121
+ puts printer
122
+ end
123
+ asset_exec asset, options.exec, options.confirm
124
+ else
125
+ say_error "No such asset #{tag}"
126
+ end
127
+ end
128
+
129
+ desc 'set_attribute KEY VALUE', 'set an attribute in collins'
130
+ use_collins_options
131
+ use_tag_option
132
+ use_selector_option
133
+ method_option :json, :type => :boolean, :default => false, :desc => 'Encode as JSON value. Only works for arrays and hashes.'
134
+ def set_attribute key, value
135
+ batch_selector_operation Hash[
136
+ :remote => options.remote,
137
+ :operation => "set_attribute",
138
+ :success_message => proc {|asset| "Set attribute on #{asset.tag}"},
139
+ :error_message => proc{|asset| "Setting attribute on #{asset.tag}"},
140
+ :confirmation_message => proc do |assets|
141
+ "You are about to set #{key}=#{value} on #{assets.length} hosts. ARE YOU SURE?"
142
+ end
143
+ ] do |client,asset|
144
+ if options.json then
145
+ value = JSON.dump(eval(value))
146
+ end
147
+ client.set_attribute!(asset, key, value)
148
+ end
149
+ end
150
+
151
+ desc 'delete_attribute KEY', 'delete an attribute in collins'
152
+ use_collins_options
153
+ use_tag_option
154
+ use_selector_option
155
+ def delete_attribute key
156
+ batch_selector_operation Hash[
157
+ :remote => options.remote,
158
+ :operation => "delete_attribute",
159
+ :success_message => proc {|asset| "Delete attribute on #{asset.tag}"},
160
+ :error_message => proc{|asset| "Delete attribute on #{asset.tag}"},
161
+ :confirmation_message => proc do |assets|
162
+ "You are about to delete #{key} on #{assets.length} hosts. ARE YOU SURE?"
163
+ end
164
+ ] do |client,asset|
165
+ client.delete_attribute!(asset, key)
166
+ end
167
+ end
168
+
169
+ desc 'set_status', 'set status, state, or both on an asset'
170
+ use_collins_options
171
+ use_tag_option
172
+ use_selector_option
173
+ method_option :reason, :type => :string, :required => true, :desc => 'Reason for changing status'
174
+ method_option :state, :type => :string, :required => false, :desc => 'Set state of asset as well'
175
+ method_option :status, :type => :string, :required => false, :desc => 'Set status of asset'
176
+ def set_status
177
+ status = options.status
178
+ state = options.state
179
+ reason = options.reason
180
+ if status.nil? && state.nil? then
181
+ raise ::Collins::ExpectationFailedError.new("set_status requires either a status or a state")
182
+ end
183
+ batch_selector_operation Hash[
184
+ :remote => options.remote,
185
+ :operation => "set_status",
186
+ :success_message => proc {|asset| "Set status to #{status} on #{asset.tag}"},
187
+ :error_message => proc{|asset| "Setting status on #{asset.tag}"},
188
+ :confirmation_message => proc do |assets|
189
+ "You are about to set status to #{status} on #{assets.length} hosts. ARE YOU SURE?"
190
+ end
191
+ ] do |client,asset|
192
+ client.set_status!(asset, :reason => reason, :status => status, :state => state)
193
+ end
194
+ end
195
+
196
+ end
197
+
198
+ end
@@ -0,0 +1,185 @@
1
+ require 'collins_shell/asset'
2
+ require 'collins_shell/console'
3
+ require 'collins_shell/ip_address'
4
+ require 'collins_shell/ipmi'
5
+ require 'collins_shell/provision'
6
+ require 'collins_shell/state'
7
+ require 'collins_shell/tag'
8
+ require 'collins_shell/thor'
9
+ require 'collins_shell/util'
10
+ require 'collins_shell/util/log_printer'
11
+ require 'thor'
12
+ require 'thor/group'
13
+
14
+ # Need these to support latest method
15
+ require 'rubygems'
16
+ require 'rubygems/spec_fetcher'
17
+
18
+ module CollinsShell
19
+
20
+ class Cli < Thor
21
+
22
+ include ThorHelper
23
+ include CollinsShell::Util
24
+
25
+ register(CollinsShell::Asset, 'asset', 'asset <command>', 'Asset related commands')
26
+ register(CollinsShell::Tag, 'tag', 'tag <command>', 'Tag related commands')
27
+ register(CollinsShell::IpAddress, 'ip_address', 'ip_address <command>', 'IP address related commands')
28
+ register(CollinsShell::Ipmi, 'ipmi', 'ipmi <command>', 'IPMI related commands')
29
+ register(CollinsShell::Provision, 'provision', 'provision <command>', 'Provisioning related commands')
30
+ register(CollinsShell::State, 'state', 'state <command>', 'State management related commands - use with care')
31
+
32
+ desc 'latest', 'check if there is a newer version of collins-shell'
33
+ def latest
34
+ puts(get_latest_version)
35
+ end
36
+
37
+ desc 'version', 'current version of collins-shell'
38
+ def version
39
+ puts("collins-shell #{get_version}")
40
+ end
41
+
42
+ desc 'power_status', 'check power status on an asset'
43
+ use_collins_options
44
+ use_tag_option
45
+ use_selector_option
46
+ def power_status
47
+ batch_selector_operation Hash[
48
+ :remote => options.remote,
49
+ :operation => "power_status",
50
+ :success_message => proc {|asset| "Got power status for #{asset.tag}"},
51
+ :error_message => proc{|asset| "Error getting power status for #{asset.tag}"},
52
+ :confirmation_message => proc do |assets|
53
+ "You are about to check the power status of #{assets.length} hosts. ARE YOU SURE?"
54
+ end
55
+ ] do |client,asset|
56
+ puts('*'*80)
57
+ begin
58
+ status = client.power_status(asset)
59
+ say_success "Power status of #{asset.tag}: #{status}"
60
+ rescue Exception => e
61
+ print_error e, "Unable to check power status of #{asset.tag}", false
62
+ end
63
+ end
64
+ end
65
+
66
+ desc 'power ACTION', 'perform power action (off, on, rebootSoft, rebootHard, etc) on an asset'
67
+ use_collins_options
68
+ use_tag_option(true)
69
+ method_option :reason, :type => :string, :required => true, :desc => 'Reason for reboot'
70
+ def power action
71
+ action = Collins::Power.normalize_action(action)
72
+ call_collins get_collins_client, "power" do |client|
73
+ client.log! options.tag, options.reason, 'ALERT'
74
+ if client.power!(options.tag, action) then
75
+ say_success "power #{action} on #{options.tag}"
76
+ else
77
+ say_error "power #{action} on #{options.tag}", :exit => true
78
+ end
79
+ end
80
+ end
81
+
82
+ desc 'log MESSAGE', 'log a message on an asset'
83
+ use_collins_options
84
+ use_tag_option
85
+ use_selector_option
86
+ method_option :severity, :type => :string, :desc => 'Log severity (EMERGENCY, WARN, etc)'
87
+ def log message
88
+ batch_selector_operation Hash[
89
+ :remote => options.remote,
90
+ :operation => "log",
91
+ :success_message => proc {|asset| "Logged to #{asset.tag}"},
92
+ :error_message => proc{|asset| "Log to #{asset.tag}"},
93
+ :confirmation_message => proc do |assets|
94
+ "You are about to log '#{message}' on #{assets.length} hosts. ARE YOU SURE?"
95
+ end
96
+ ] do |client,asset|
97
+ client.log!(asset, message, options.severity)
98
+ end
99
+ end
100
+
101
+ desc 'logs TAG', 'fetch logs for an asset specified by its tag. Use "all" for all logs'
102
+ use_collins_options
103
+ use_page_options(5000)
104
+ method_option :severity, :type => :array, :desc => 'Severities to include'
105
+ def logs tag
106
+ call_collins get_collins_client, "logs" do |client|
107
+ severity = []
108
+ if options.severity? then
109
+ severity = options.severity
110
+ end
111
+ params = Hash[
112
+ :filter => severity.join(';'),
113
+ :size => options[:size].to_i,
114
+ :sort => options[:sort]
115
+ ]
116
+ logs = client.logs tag, params.merge(:all_tag => 'all')
117
+ logs.reverse! if options[:sort].to_s.downcase == 'desc'
118
+ printer = CollinsShell::LogPrinter.new(tag, logs)
119
+ puts printer.render
120
+ end
121
+ end
122
+
123
+ desc 'console', 'drop into the interactive collins shell'
124
+ use_collins_options
125
+ def console
126
+ ensure_password
127
+ CollinsShell::Console.launch(options)
128
+ end
129
+
130
+ no_tasks do
131
+ def get_version
132
+ version_file = File.absolute_path(File.join(File.dirname(__FILE__), '..', '..', 'VERSION'))
133
+ if File.exists?(version_file) then
134
+ File.read(version_file)
135
+ else
136
+ "0.0.0"
137
+ end
138
+ end
139
+
140
+ def get_latest_version
141
+ begin
142
+ Gem.sources = ["http://repo.tumblr.net:9929"]
143
+ gem = Gem::SpecFetcher.new
144
+ shell = gem.fetch(Gem::Dependency.new('collins_shell')).flatten.first
145
+ rescue Exception => e
146
+ return "Could not retrieve latest gem info from #{Gem.sources.join(',')}"
147
+ end
148
+ if shell.nil? then
149
+ "Could not retrieve latest gem info from repo.tumblr.net"
150
+ else
151
+ my_version = Gem::Version.new(get_version)
152
+ if shell.version == my_version then
153
+ "You are running the most recent version of collins-shell: #{my_version.to_s}"
154
+ elsif shell.version > my_version then
155
+ "Time to upgrade! You are running collins-shell #{my_version.to_s}, latest is #{shell.version.to_s}"
156
+ else
157
+ "You are probably a developer. You are running version #{my_version.to_s}, latest published is #{shell.version.to_s}"
158
+ end
159
+ end
160
+ end
161
+
162
+ def print_error e, cmd = nil, separator = true
163
+ cmd = "unable to run command '#{$0} #{ARGV.join(' ')}'" unless cmd
164
+ say_status("fatal", cmd, :red)
165
+ say_status("exception", "#{e.message}", :red)
166
+ is_debug = ARGV.include?("--debug") || ARGV.include?("--trace")
167
+ if e.is_a?(Collins::RequestError) then
168
+ puts('*'*80) if separator
169
+ say_status("details", e.description(is_debug).strip.sub(e.message,""), :red)
170
+ end
171
+ if ARGV.include?("--debug") || ARGV.include?("--trace") then
172
+ say_status("DEBUG", "local backtrace is presented latest to earliest (reverse cronological)")
173
+ puts("#{e.class.to_s}")
174
+ e.backtrace.each do |line|
175
+ file, line, method = line.split(":", 3)
176
+ puts "\t\t#{method}(#{file}:#{line})"
177
+ end
178
+ end
179
+ end # print_error
180
+ end # no_tasks
181
+
182
+
183
+ end
184
+
185
+ end