nimbu 0.4 → 0.5.1
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.
- data/lib/nimbu.rb +3 -19
- data/lib/nimbu/auth.rb +106 -95
- data/lib/nimbu/cli.rb +20 -3
- data/lib/nimbu/command.rb +138 -68
- data/lib/nimbu/command/auth.rb +21 -3
- data/lib/nimbu/command/base.rb +38 -75
- data/lib/nimbu/command/browse.rb +63 -0
- data/lib/nimbu/command/help.rb +1 -1
- data/lib/nimbu/command/helpers.rb +6 -4
- data/lib/nimbu/command/init.rb +5 -6
- data/lib/nimbu/command/server.rb +119 -55
- data/lib/nimbu/command/sites.rb +32 -0
- data/lib/nimbu/command/themes.rb +29 -52
- data/lib/nimbu/helpers.rb +268 -89
- data/lib/nimbu/server/base.rb +56 -41
- data/lib/nimbu/ssh.rb +54 -0
- data/lib/nimbu/version.rb +1 -1
- metadata +128 -42
- data/lib/nimbu/client.rb +0 -289
- data/lib/nimbu/client/rendezvous.rb +0 -76
- data/lib/nimbu/server/views/index.haml +0 -1
@@ -0,0 +1,32 @@
|
|
1
|
+
require "nimbu/command/base"
|
2
|
+
|
3
|
+
# interacting with your sites (list, create)
|
4
|
+
#
|
5
|
+
class Nimbu::Command::Sites < Nimbu::Command::Base
|
6
|
+
# index
|
7
|
+
#
|
8
|
+
# list sites you can edit
|
9
|
+
#
|
10
|
+
def index
|
11
|
+
sites = nimbu.sites.list
|
12
|
+
if sites.respond_to?(:any?) && sites.any?
|
13
|
+
display "\nYou have access to following sites:\n"
|
14
|
+
sites.each do |site|
|
15
|
+
display " - #{site.name.white.bold} => http://#{site.domain}"
|
16
|
+
end
|
17
|
+
else
|
18
|
+
display "You don't have access to any Nimbu sites."
|
19
|
+
display ""
|
20
|
+
display "Visit http://nimbu.io, start your 30-day trial and discover our amazing platform!"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# index
|
25
|
+
#
|
26
|
+
# list sites you can edit
|
27
|
+
#
|
28
|
+
def list
|
29
|
+
return index
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
data/lib/nimbu/command/themes.rb
CHANGED
@@ -9,17 +9,17 @@ class Nimbu::Command::Themes < Nimbu::Command::Base
|
|
9
9
|
# list available commands or display help for a specific command
|
10
10
|
#
|
11
11
|
def index
|
12
|
-
themes =
|
12
|
+
themes = nimbu.themes(:subdomain => Nimbu::Auth.site).list
|
13
13
|
if themes.any?
|
14
|
-
|
14
|
+
display "\nYou have following themes for this website:"
|
15
15
|
themes.each do |theme|
|
16
|
-
puts " - #{theme
|
16
|
+
puts " - #{theme.name.bold} (#{theme.short})"
|
17
17
|
end
|
18
18
|
else
|
19
19
|
puts "Hm. You seem to have no themes. Is that normal?"
|
20
20
|
end
|
21
21
|
puts ""
|
22
|
-
puts "Currently this directory is configured for '#{Nimbu::Auth.theme}'"
|
22
|
+
puts "Currently this directory is configured for '#{Nimbu::Auth.theme.red.bold}'"
|
23
23
|
end
|
24
24
|
|
25
25
|
# list
|
@@ -33,57 +33,34 @@ class Nimbu::Command::Themes < Nimbu::Command::Base
|
|
33
33
|
else
|
34
34
|
theme = Nimbu::Auth.theme
|
35
35
|
end
|
36
|
-
display "
|
37
|
-
contents =
|
38
|
-
contents["layouts"].
|
39
|
-
display "
|
40
|
-
|
41
|
-
|
42
|
-
display " - templates/#{t["name"]}"
|
43
|
-
end unless contents["templates"].nil?
|
44
|
-
contents["snippets"].each do |s|
|
45
|
-
display " - snippets/#{s["name"]}"
|
46
|
-
end unless contents["templates"].nil?
|
47
|
-
contents["assets"].each do |a|
|
48
|
-
display " - #{a["folder"]}/#{a["name"]}"
|
49
|
-
end unless contents["assets"].nil?
|
50
|
-
end
|
51
|
-
|
52
|
-
# download
|
53
|
-
#
|
54
|
-
# download all layouts, templates and assets
|
55
|
-
#
|
56
|
-
def download
|
57
|
-
input = args.shift.downcase rescue nil
|
58
|
-
if !input.to_s.strip.empty?
|
59
|
-
theme = input.to_s.strip
|
60
|
-
else
|
61
|
-
theme = Nimbu::Auth.theme
|
62
|
-
end
|
63
|
-
display "Downloading layouts, templates and assets for '#{theme}':"
|
64
|
-
contents = json_decode(nimbu.show_theme_contents(theme))
|
65
|
-
contents["layouts"].each do |asset|
|
66
|
-
print " - layouts/#{asset["name"]}"
|
67
|
-
data = json_decode(nimbu.fetch_theme_layout(theme,asset["id"]))
|
68
|
-
filename = File.join(Dir.pwd,"layouts",asset["name"])
|
69
|
-
FileUtils.mkdir_p(File.dirname(filename))
|
70
|
-
File.open(filename, 'w') do |file|
|
71
|
-
file.puts(data["code"])
|
36
|
+
display "\nShowing layouts, templates, snippets and assets for '#{theme.red.bold}':"
|
37
|
+
contents = nimbu.themes(:subdomain => Nimbu::Auth.site).get(theme)
|
38
|
+
if contents["layouts"].any?
|
39
|
+
display "\nLayouts:".bold
|
40
|
+
contents["layouts"].each do |l|
|
41
|
+
display " - layouts/#{l["name"]}"
|
72
42
|
end
|
43
|
+
end
|
73
44
|
|
74
|
-
|
45
|
+
if contents["templates"].any?
|
46
|
+
display "\nTemplates:".bold
|
47
|
+
contents["templates"].each do |t|
|
48
|
+
display " - templates/#{t["name"]}"
|
49
|
+
end
|
75
50
|
end
|
76
51
|
|
77
|
-
contents["
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
FileUtils.mkdir_p(File.dirname(filename))
|
82
|
-
File.open(filename, 'w') do |file|
|
83
|
-
file.puts(data["code"])
|
52
|
+
if contents["snippets"].any?
|
53
|
+
display "\nSnippets:".bold
|
54
|
+
contents["snippets"].each do |s|
|
55
|
+
display " - snippets/#{s["name"]}"
|
84
56
|
end
|
57
|
+
end
|
85
58
|
|
86
|
-
|
59
|
+
if contents["assets"].any?
|
60
|
+
display "\nAssets:".bold
|
61
|
+
contents["assets"].each do |a|
|
62
|
+
display " - #{a["folder"]}/#{a["name"]}"
|
63
|
+
end
|
87
64
|
end
|
88
65
|
end
|
89
66
|
|
@@ -103,7 +80,7 @@ class Nimbu::Command::Themes < Nimbu::Command::Base
|
|
103
80
|
# end
|
104
81
|
theme = Nimbu::Auth.theme
|
105
82
|
display "Pushing layouts, templates and assets for '#{theme}' to the server:"
|
106
|
-
|
83
|
+
|
107
84
|
layouts_glob = Dir.glob("#{Dir.pwd}/layouts/**/*.liquid")
|
108
85
|
layouts_files = layouts_glob.map {|dir| dir.gsub("#{Dir.pwd}/layouts/","")}
|
109
86
|
templates_glob = Dir.glob("#{Dir.pwd}/templates/**/*.liquid")
|
@@ -119,7 +96,7 @@ class Nimbu::Command::Themes < Nimbu::Command::Base
|
|
119
96
|
print " - layouts/#{layout}"
|
120
97
|
nimbu.upload_layout(theme, layout, IO.read(file))
|
121
98
|
print " (ok)\n"
|
122
|
-
end
|
99
|
+
end
|
123
100
|
|
124
101
|
print "\nTemplates:\n"
|
125
102
|
templates_files.each do |template|
|
@@ -181,7 +158,7 @@ class Nimbu::Command::Themes < Nimbu::Command::Base
|
|
181
158
|
end
|
182
159
|
end
|
183
160
|
|
184
|
-
private
|
161
|
+
private
|
185
162
|
|
186
163
|
def anyFileWithWord?(glob,word)
|
187
164
|
found = false
|
data/lib/nimbu/helpers.rb
CHANGED
@@ -2,6 +2,9 @@ require "vendor/nimbu/okjson"
|
|
2
2
|
|
3
3
|
module Nimbu
|
4
4
|
module Helpers
|
5
|
+
|
6
|
+
extend self
|
7
|
+
|
5
8
|
def home_directory
|
6
9
|
running_on_windows? ? ENV['USERPROFILE'].gsub("\\","/") : ENV['HOME']
|
7
10
|
end
|
@@ -19,7 +22,7 @@ module Nimbu
|
|
19
22
|
puts(msg)
|
20
23
|
else
|
21
24
|
print(msg)
|
22
|
-
|
25
|
+
$stdout.flush
|
23
26
|
end
|
24
27
|
end
|
25
28
|
|
@@ -27,50 +30,40 @@ module Nimbu
|
|
27
30
|
display("\r\e[0K#{line}", line_break)
|
28
31
|
end
|
29
32
|
|
30
|
-
def deprecate(
|
31
|
-
display "
|
32
|
-
display
|
33
|
-
end
|
34
|
-
|
35
|
-
def error(msg)
|
36
|
-
STDERR.puts(format_with_bang(msg))
|
37
|
-
exit 1
|
33
|
+
def deprecate(message)
|
34
|
+
display "WARNING: #{message}"
|
38
35
|
end
|
39
36
|
|
40
37
|
def confirm_billing
|
41
38
|
display
|
42
39
|
display "This action will cause your account to be billed at the end of the month"
|
43
|
-
display "For more information, see
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
return true
|
40
|
+
display "For more information, see https://devcenter.Nimbu.com/articles/usage-and-billing"
|
41
|
+
if confirm
|
42
|
+
Nimbu::Auth.client.confirm_billing
|
43
|
+
true
|
48
44
|
end
|
49
45
|
end
|
50
46
|
|
51
|
-
def confirm(message="Are you sure you wish to continue? (y/n)
|
47
|
+
def confirm(message="Are you sure you wish to continue? (y/n)")
|
52
48
|
display("#{message} ", false)
|
53
|
-
ask.downcase
|
49
|
+
['y', 'yes'].include?(ask.downcase)
|
54
50
|
end
|
55
51
|
|
56
52
|
def confirm_command(app_to_confirm = app, message=nil)
|
57
|
-
|
58
|
-
|
59
|
-
if respond_to?(:extract_option) && confirmed_app = extract_option('--confirm', false)
|
53
|
+
if confirmed_app = Nimbu::Command.current_options[:confirm]
|
60
54
|
unless confirmed_app == app_to_confirm
|
61
55
|
raise(Nimbu::Command::CommandFailed, "Confirmed app #{confirmed_app} did not match the selected app #{app_to_confirm}.")
|
62
56
|
end
|
63
57
|
return true
|
64
58
|
else
|
65
59
|
display
|
66
|
-
message ||= "WARNING:
|
60
|
+
message ||= "WARNING: Destructive Action\nThis command will affect the app: #{app_to_confirm}"
|
67
61
|
message << "\nTo proceed, type \"#{app_to_confirm}\" or re-run this command with --confirm #{app_to_confirm}"
|
68
62
|
output_with_bang(message)
|
69
63
|
display
|
70
64
|
display "> ", false
|
71
65
|
if ask.downcase != app_to_confirm
|
72
|
-
|
73
|
-
false
|
66
|
+
error("Confirmation did not match #{app_to_confirm}. Aborted.")
|
74
67
|
else
|
75
68
|
true
|
76
69
|
end
|
@@ -78,12 +71,12 @@ module Nimbu
|
|
78
71
|
end
|
79
72
|
|
80
73
|
def format_date(date)
|
81
|
-
date = Time.parse(date) if date.is_a?(String)
|
82
|
-
date.strftime("%Y-%m-%d %H:%M %Z")
|
74
|
+
date = Time.parse(date).utc if date.is_a?(String)
|
75
|
+
date.strftime("%Y-%m-%d %H:%M %Z").gsub('GMT', 'UTC')
|
83
76
|
end
|
84
77
|
|
85
78
|
def ask
|
86
|
-
|
79
|
+
$stdin.gets.to_s.strip
|
87
80
|
end
|
88
81
|
|
89
82
|
def shell(cmd)
|
@@ -117,14 +110,22 @@ module Nimbu
|
|
117
110
|
%x{ git #{flattened_args} 2>&1 }.strip
|
118
111
|
end
|
119
112
|
|
120
|
-
def time_ago(
|
121
|
-
if
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
113
|
+
def time_ago(since)
|
114
|
+
if since.is_a?(String)
|
115
|
+
since = Time.parse(since)
|
116
|
+
end
|
117
|
+
|
118
|
+
elapsed = Time.now - since
|
119
|
+
|
120
|
+
message = since.strftime("%Y/%m/%d %H:%M:%S")
|
121
|
+
if elapsed <= 60
|
122
|
+
message << " (~ #{elapsed.floor}s ago)"
|
123
|
+
elsif elapsed <= (60 * 60)
|
124
|
+
message << " (~ #{(elapsed / 60).floor}m ago)"
|
125
|
+
elsif elapsed <= (60 * 60 * 25)
|
126
|
+
message << " (~ #{(elapsed / 60 / 60).floor}h ago)"
|
127
127
|
end
|
128
|
+
message
|
128
129
|
end
|
129
130
|
|
130
131
|
def truncate(text, length)
|
@@ -152,7 +153,6 @@ module Nimbu
|
|
152
153
|
end
|
153
154
|
|
154
155
|
def create_git_remote(remote, url)
|
155
|
-
return unless has_git?
|
156
156
|
return if git('remote').split("\n").include?(remote)
|
157
157
|
return unless File.exists?(".git")
|
158
158
|
git "remote add #{remote} #{url}"
|
@@ -169,30 +169,33 @@ module Nimbu
|
|
169
169
|
header = headers[index]
|
170
170
|
lengths << longest([header].concat(objects.map { |o| o[column].to_s }))
|
171
171
|
end
|
172
|
+
lines = lengths.map {|length| "-" * length}
|
173
|
+
lengths[-1] = 0 # remove padding from last column
|
172
174
|
display_row headers, lengths
|
173
|
-
display_row
|
175
|
+
display_row lines, lengths
|
174
176
|
objects.each do |row|
|
175
177
|
display_row columns.map { |column| row[column] }, lengths
|
176
178
|
end
|
177
179
|
end
|
178
180
|
|
179
181
|
def display_row(row, lengths)
|
182
|
+
row_data = []
|
180
183
|
row.zip(lengths).each do |column, length|
|
181
|
-
format = column.is_a?(Fixnum) ? "%#{length}s
|
182
|
-
|
184
|
+
format = column.is_a?(Fixnum) ? "%#{length}s" : "%-#{length}s"
|
185
|
+
row_data << format % column
|
183
186
|
end
|
184
|
-
display
|
187
|
+
display(row_data.join(" "))
|
185
188
|
end
|
186
189
|
|
187
190
|
def json_encode(object)
|
188
191
|
Nimbu::OkJson.encode(object)
|
189
|
-
rescue Nimbu::OkJson::
|
192
|
+
rescue Nimbu::OkJson::Error
|
190
193
|
nil
|
191
194
|
end
|
192
195
|
|
193
196
|
def json_decode(json)
|
194
197
|
Nimbu::OkJson.decode(json)
|
195
|
-
rescue Nimbu::OkJson::
|
198
|
+
rescue Nimbu::OkJson::Error
|
196
199
|
nil
|
197
200
|
end
|
198
201
|
|
@@ -207,7 +210,7 @@ module Nimbu
|
|
207
210
|
end
|
208
211
|
|
209
212
|
def with_tty(&block)
|
210
|
-
return unless $stdin.
|
213
|
+
return unless $stdin.isatty
|
211
214
|
begin
|
212
215
|
yield
|
213
216
|
rescue
|
@@ -216,7 +219,7 @@ module Nimbu
|
|
216
219
|
end
|
217
220
|
|
218
221
|
def get_terminal_environment
|
219
|
-
{ "TERM" => ENV["TERM"], "COLUMNS" => `tput cols
|
222
|
+
{ "TERM" => ENV["TERM"], "COLUMNS" => `tput cols`.strip, "LINES" => `tput lines`.strip }
|
220
223
|
rescue
|
221
224
|
{ "TERM" => ENV["TERM"] }
|
222
225
|
end
|
@@ -227,30 +230,24 @@ module Nimbu
|
|
227
230
|
|
228
231
|
## DISPLAY HELPERS
|
229
232
|
|
230
|
-
def action(message)
|
231
|
-
|
232
|
-
Nimbu::Helpers.
|
233
|
-
yield
|
234
|
-
Nimbu::Helpers.
|
235
|
-
display "done", false
|
236
|
-
|
233
|
+
def action(message, options={})
|
234
|
+
display("#{message}... ", false)
|
235
|
+
Nimbu::Helpers.error_with_failure = true
|
236
|
+
ret = yield
|
237
|
+
Nimbu::Helpers.error_with_failure = false
|
238
|
+
display((options[:success] || "done"), false)
|
239
|
+
if @status
|
240
|
+
display(", #{@status}", false)
|
241
|
+
@status = nil
|
242
|
+
end
|
237
243
|
display
|
244
|
+
ret
|
238
245
|
end
|
239
246
|
|
240
247
|
def status(message)
|
241
248
|
@status = message
|
242
249
|
end
|
243
250
|
|
244
|
-
def output(message="", new_line=true)
|
245
|
-
return if message.to_s.strip == ""
|
246
|
-
display(" " + message.split("\n").join("\n "), new_line)
|
247
|
-
end
|
248
|
-
|
249
|
-
def output_with_arrow(message="", new_line=true)
|
250
|
-
return if message.to_s.strip == ""
|
251
|
-
display("----> " + message.split("\n").join("\n "), new_line)
|
252
|
-
end
|
253
|
-
|
254
251
|
def format_with_bang(message)
|
255
252
|
return '' if message.to_s.strip == ""
|
256
253
|
" ! " + message.split("\n").join("\n ! ")
|
@@ -261,10 +258,21 @@ module Nimbu
|
|
261
258
|
display(format_with_bang(message), new_line)
|
262
259
|
end
|
263
260
|
|
264
|
-
def
|
265
|
-
|
266
|
-
|
267
|
-
|
261
|
+
def error(message)
|
262
|
+
if Nimbu::Helpers.error_with_failure
|
263
|
+
display("failed")
|
264
|
+
Nimbu::Helpers.error_with_failure = false
|
265
|
+
end
|
266
|
+
$stderr.puts(format_with_bang(message))
|
267
|
+
exit(1)
|
268
|
+
end
|
269
|
+
|
270
|
+
def self.error_with_failure
|
271
|
+
@@error_with_failure ||= false
|
272
|
+
end
|
273
|
+
|
274
|
+
def self.error_with_failure=(new_error_with_failure)
|
275
|
+
@@error_with_failure = new_error_with_failure
|
268
276
|
end
|
269
277
|
|
270
278
|
def self.included_into
|
@@ -283,31 +291,6 @@ module Nimbu
|
|
283
291
|
extended_into << base
|
284
292
|
end
|
285
293
|
|
286
|
-
def self.enable_error_capture
|
287
|
-
included_into.each do |base|
|
288
|
-
base.send(:alias_method, :error_without_failure, :error)
|
289
|
-
base.send(:alias_method, :error, :error_with_failure)
|
290
|
-
end
|
291
|
-
extended_into.each do |base|
|
292
|
-
class << base
|
293
|
-
alias_method :error_without_failure, :error
|
294
|
-
alias_method :error, :error_with_failure
|
295
|
-
end
|
296
|
-
end
|
297
|
-
end
|
298
|
-
|
299
|
-
def self.disable_error_capture
|
300
|
-
included_into.each do |base|
|
301
|
-
base.send(:alias_method, :error, :error_without_failure)
|
302
|
-
end
|
303
|
-
extended_into.each do |base|
|
304
|
-
class << base
|
305
|
-
alias_method :error, :error_without_failure
|
306
|
-
end
|
307
|
-
end
|
308
|
-
end
|
309
|
-
|
310
|
-
|
311
294
|
def display_header(message="", new_line=true)
|
312
295
|
return if message.to_s.strip == ""
|
313
296
|
display("=== " + message.to_s.split("\n").join("\n=== "), new_line)
|
@@ -341,7 +324,128 @@ module Nimbu
|
|
341
324
|
|
342
325
|
def hprint(string='')
|
343
326
|
Kernel.print(string)
|
344
|
-
|
327
|
+
$stdout.flush
|
328
|
+
end
|
329
|
+
|
330
|
+
def spinner(ticks)
|
331
|
+
%w(/ - \\ |)[ticks % 4]
|
332
|
+
end
|
333
|
+
|
334
|
+
def launchy(message, url)
|
335
|
+
action(message) do
|
336
|
+
require("launchy")
|
337
|
+
launchy = Launchy.open(url)
|
338
|
+
if launchy.respond_to?(:join)
|
339
|
+
launchy.join
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
# produces a printf formatter line for an array of items
|
345
|
+
# if an individual line item is an array, it will create columns
|
346
|
+
# that are lined-up
|
347
|
+
#
|
348
|
+
# line_formatter(["foo", "barbaz"]) # => "%-6s"
|
349
|
+
# line_formatter(["foo", "barbaz"], ["bar", "qux"]) # => "%-3s %-6s"
|
350
|
+
#
|
351
|
+
def line_formatter(array)
|
352
|
+
if array.any? {|item| item.is_a?(Array)}
|
353
|
+
cols = []
|
354
|
+
array.each do |item|
|
355
|
+
if item.is_a?(Array)
|
356
|
+
item.each_with_index { |val,idx| cols[idx] = [cols[idx]||0, (val || '').length].max }
|
357
|
+
end
|
358
|
+
end
|
359
|
+
cols.map { |col| "%-#{col}s" }.join(" ")
|
360
|
+
else
|
361
|
+
"%s"
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
def styled_array(array, options={})
|
366
|
+
fmt = line_formatter(array)
|
367
|
+
array = array.sort unless options[:sort] == false
|
368
|
+
array.each do |element|
|
369
|
+
display((fmt % element).rstrip)
|
370
|
+
end
|
371
|
+
display
|
372
|
+
end
|
373
|
+
|
374
|
+
def format_error(error, message='Nimbu client internal error.')
|
375
|
+
formatted_error = []
|
376
|
+
formatted_error << " ! #{message}"
|
377
|
+
formatted_error << ' ! Search for help at: https://help.Nimbu.com'
|
378
|
+
formatted_error << ' ! Or report a bug at: https://github.com/Nimbu/Nimbu/issues/new'
|
379
|
+
formatted_error << ''
|
380
|
+
formatted_error << " Error: #{error.message} (#{error.class})"
|
381
|
+
formatted_error << " Backtrace: #{error.backtrace.first}"
|
382
|
+
error.backtrace[1..-1].each do |line|
|
383
|
+
formatted_error << " #{line}"
|
384
|
+
end
|
385
|
+
if error.backtrace.length > 1
|
386
|
+
formatted_error << ''
|
387
|
+
end
|
388
|
+
command = ARGV.map do |arg|
|
389
|
+
if arg.include?(' ')
|
390
|
+
arg = %{"#{arg}"}
|
391
|
+
else
|
392
|
+
arg
|
393
|
+
end
|
394
|
+
end.join(' ')
|
395
|
+
formatted_error << " Command: Nimbu #{command}"
|
396
|
+
require 'Nimbu/auth'
|
397
|
+
unless Nimbu::Auth.host == Nimbu::Auth.default_host
|
398
|
+
formatted_error << " Host: #{Nimbu::Auth.host}"
|
399
|
+
end
|
400
|
+
if http_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
|
401
|
+
formatted_error << " HTTP Proxy: #{http_proxy}"
|
402
|
+
end
|
403
|
+
if https_proxy = ENV['https_proxy'] || ENV['HTTPS_PROXY']
|
404
|
+
formatted_error << " HTTPS Proxy: #{https_proxy}"
|
405
|
+
end
|
406
|
+
formatted_error << " Version: #{Nimbu.user_agent}"
|
407
|
+
formatted_error << "\n"
|
408
|
+
formatted_error.join("\n")
|
409
|
+
end
|
410
|
+
|
411
|
+
def styled_error(error, message='Nimbu client internal error.')
|
412
|
+
if Nimbu::Helpers.error_with_failure
|
413
|
+
display("failed")
|
414
|
+
Nimbu::Helpers.error_with_failure = false
|
415
|
+
end
|
416
|
+
$stderr.puts(format_error(error, message))
|
417
|
+
end
|
418
|
+
|
419
|
+
def styled_header(header)
|
420
|
+
display("=== #{header}")
|
421
|
+
end
|
422
|
+
|
423
|
+
def styled_hash(hash, keys=nil)
|
424
|
+
max_key_length = hash.keys.map {|key| key.to_s.length}.max + 2
|
425
|
+
keys ||= hash.keys.sort {|x,y| x.to_s <=> y.to_s}
|
426
|
+
keys.each do |key|
|
427
|
+
case value = hash[key]
|
428
|
+
when Array
|
429
|
+
if value.empty?
|
430
|
+
next
|
431
|
+
else
|
432
|
+
elements = value.sort {|x,y| x.to_s <=> y.to_s}
|
433
|
+
display("#{key}: ".ljust(max_key_length), false)
|
434
|
+
display(elements[0])
|
435
|
+
elements[1..-1].each do |element|
|
436
|
+
display("#{' ' * max_key_length}#{element}")
|
437
|
+
end
|
438
|
+
if elements.length > 1
|
439
|
+
display
|
440
|
+
end
|
441
|
+
end
|
442
|
+
when nil
|
443
|
+
next
|
444
|
+
else
|
445
|
+
display("#{key}: ".ljust(max_key_length), false)
|
446
|
+
display(value)
|
447
|
+
end
|
448
|
+
end
|
345
449
|
end
|
346
450
|
|
347
451
|
def string_distance(first, last)
|
@@ -378,5 +482,80 @@ module Nimbu
|
|
378
482
|
distances[first.length][last.length]
|
379
483
|
end
|
380
484
|
|
485
|
+
def suggestion(actual, possibilities)
|
486
|
+
distances = Hash.new {|hash,key| hash[key] = []}
|
487
|
+
|
488
|
+
possibilities.each do |suggestion|
|
489
|
+
distances[string_distance(actual, suggestion)] << suggestion
|
490
|
+
end
|
491
|
+
|
492
|
+
minimum_distance = distances.keys.min
|
493
|
+
if minimum_distance < 4
|
494
|
+
suggestions = distances[minimum_distance].sort
|
495
|
+
if suggestions.length == 1
|
496
|
+
"Perhaps you meant `#{suggestions.first}`."
|
497
|
+
else
|
498
|
+
"Perhaps you meant #{suggestions[0...-1].map {|suggestion| "`#{suggestion}`"}.join(', ')} or `#{suggestions.last}`."
|
499
|
+
end
|
500
|
+
else
|
501
|
+
nil
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
505
|
+
module System
|
506
|
+
# Cross-platform web browser command; respects the value set in $BROWSER.
|
507
|
+
#
|
508
|
+
# Returns an array, e.g.: ['open']
|
509
|
+
def browser_launcher
|
510
|
+
browser = ENV['BROWSER'] || (
|
511
|
+
osx? ? 'open' : windows? ? %w[cmd /c start] :
|
512
|
+
%w[xdg-open cygstart x-www-browser firefox opera mozilla netscape].find { |comm| which comm }
|
513
|
+
)
|
514
|
+
|
515
|
+
abort "Please set $BROWSER to a web launcher to use this command." unless browser
|
516
|
+
Array(browser)
|
517
|
+
end
|
518
|
+
|
519
|
+
def osx?
|
520
|
+
require 'rbconfig'
|
521
|
+
RbConfig::CONFIG['host_os'].to_s.include?('darwin')
|
522
|
+
end
|
523
|
+
|
524
|
+
def windows?
|
525
|
+
require 'rbconfig'
|
526
|
+
RbConfig::CONFIG['host_os'] =~ /msdos|mswin|djgpp|mingw|windows/
|
527
|
+
end
|
528
|
+
|
529
|
+
# Cross-platform way of finding an executable in the $PATH.
|
530
|
+
#
|
531
|
+
# which('ruby') #=> /usr/bin/ruby
|
532
|
+
def which(cmd)
|
533
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
534
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
535
|
+
exts.each { |ext|
|
536
|
+
exe = "#{path}/#{cmd}#{ext}"
|
537
|
+
return exe if File.executable? exe
|
538
|
+
}
|
539
|
+
end
|
540
|
+
return nil
|
541
|
+
end
|
542
|
+
|
543
|
+
# Checks whether a command exists on this system in the $PATH.
|
544
|
+
#
|
545
|
+
# name - The String name of the command to check for.
|
546
|
+
#
|
547
|
+
# Returns a Boolean.
|
548
|
+
def command?(name)
|
549
|
+
!which(name).nil?
|
550
|
+
end
|
551
|
+
|
552
|
+
def tmp_dir
|
553
|
+
ENV['TMPDIR'] || ENV['TEMP'] || '/tmp'
|
554
|
+
end
|
555
|
+
end
|
556
|
+
|
557
|
+
include System
|
558
|
+
extend System
|
559
|
+
|
381
560
|
end
|
382
|
-
end
|
561
|
+
end
|