foreman 0.85.0 → 0.87.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/data/export/systemd/master.target.erb +1 -1
  4. data/data/export/systemd/process.service.erb +6 -3
  5. data/lib/foreman/cli.rb +3 -3
  6. data/lib/foreman/export/systemd.rb +7 -13
  7. data/lib/foreman/vendor/thor/lib/thor/actions/create_file.rb +103 -0
  8. data/lib/foreman/vendor/thor/lib/thor/actions/create_link.rb +59 -0
  9. data/lib/foreman/vendor/thor/lib/thor/actions/directory.rb +118 -0
  10. data/lib/foreman/vendor/thor/lib/thor/actions/empty_directory.rb +135 -0
  11. data/lib/foreman/vendor/thor/lib/thor/actions/file_manipulation.rb +327 -0
  12. data/lib/foreman/vendor/thor/lib/thor/actions/inject_into_file.rb +103 -0
  13. data/lib/foreman/vendor/thor/lib/thor/actions.rb +318 -0
  14. data/lib/foreman/vendor/thor/lib/thor/base.rb +656 -0
  15. data/lib/foreman/vendor/thor/lib/thor/command.rb +133 -0
  16. data/lib/foreman/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +85 -0
  17. data/lib/foreman/vendor/thor/lib/thor/core_ext/io_binary_read.rb +12 -0
  18. data/lib/foreman/vendor/thor/lib/thor/core_ext/ordered_hash.rb +129 -0
  19. data/lib/foreman/vendor/thor/lib/thor/error.rb +32 -0
  20. data/lib/foreman/vendor/thor/lib/thor/group.rb +281 -0
  21. data/lib/foreman/vendor/thor/lib/thor/invocation.rb +177 -0
  22. data/lib/foreman/vendor/thor/lib/thor/line_editor/basic.rb +35 -0
  23. data/lib/foreman/vendor/thor/lib/thor/line_editor/readline.rb +88 -0
  24. data/lib/foreman/vendor/thor/lib/thor/line_editor.rb +17 -0
  25. data/lib/foreman/vendor/thor/lib/thor/parser/argument.rb +70 -0
  26. data/lib/foreman/vendor/thor/lib/thor/parser/arguments.rb +175 -0
  27. data/lib/foreman/vendor/thor/lib/thor/parser/option.rb +146 -0
  28. data/lib/foreman/vendor/thor/lib/thor/parser/options.rb +220 -0
  29. data/lib/foreman/vendor/thor/lib/thor/parser.rb +4 -0
  30. data/lib/foreman/vendor/thor/lib/thor/rake_compat.rb +71 -0
  31. data/lib/foreman/vendor/thor/lib/thor/runner.rb +322 -0
  32. data/lib/foreman/vendor/thor/lib/thor/shell/basic.rb +436 -0
  33. data/lib/foreman/vendor/thor/lib/thor/shell/color.rb +149 -0
  34. data/lib/foreman/vendor/thor/lib/thor/shell/html.rb +126 -0
  35. data/lib/foreman/vendor/thor/lib/thor/shell.rb +81 -0
  36. data/lib/foreman/vendor/thor/lib/thor/util.rb +268 -0
  37. data/lib/foreman/vendor/thor/lib/thor/version.rb +3 -0
  38. data/lib/foreman/vendor/thor/lib/thor.rb +492 -0
  39. data/lib/foreman/version.rb +1 -1
  40. data/man/foreman.1 +1 -1
  41. data/spec/foreman/export/systemd_spec.rb +88 -46
  42. data/spec/resources/export/systemd/{app-alpha@.service → app-alpha.1.service} +6 -3
  43. data/spec/resources/export/systemd/{app-bravo@.service → app-alpha.2.service} +6 -3
  44. data/spec/resources/export/systemd/app-bravo.1.service +18 -0
  45. data/spec/resources/export/systemd/app.target +1 -1
  46. data/spec/spec_helper.rb +1 -1
  47. metadata +39 -22
  48. data/data/export/systemd/process_master.target.erb +0 -2
@@ -0,0 +1,436 @@
1
+ require "tempfile"
2
+ require "io/console" if RUBY_VERSION > "1.9.2"
3
+
4
+ class Foreman::Thor
5
+ module Shell
6
+ class Basic
7
+ attr_accessor :base
8
+ attr_reader :padding
9
+
10
+ # Initialize base, mute and padding to nil.
11
+ #
12
+ def initialize #:nodoc:
13
+ @base = nil
14
+ @mute = false
15
+ @padding = 0
16
+ @always_force = false
17
+ end
18
+
19
+ # Mute everything that's inside given block
20
+ #
21
+ def mute
22
+ @mute = true
23
+ yield
24
+ ensure
25
+ @mute = false
26
+ end
27
+
28
+ # Check if base is muted
29
+ #
30
+ def mute?
31
+ @mute
32
+ end
33
+
34
+ # Sets the output padding, not allowing less than zero values.
35
+ #
36
+ def padding=(value)
37
+ @padding = [0, value].max
38
+ end
39
+
40
+ # Sets the output padding while executing a block and resets it.
41
+ #
42
+ def indent(count = 1)
43
+ orig_padding = padding
44
+ self.padding = padding + count
45
+ yield
46
+ self.padding = orig_padding
47
+ end
48
+
49
+ # Asks something to the user and receives a response.
50
+ #
51
+ # If asked to limit the correct responses, you can pass in an
52
+ # array of acceptable answers. If one of those is not supplied,
53
+ # they will be shown a message stating that one of those answers
54
+ # must be given and re-asked the question.
55
+ #
56
+ # If asking for sensitive information, the :echo option can be set
57
+ # to false to mask user input from $stdin.
58
+ #
59
+ # If the required input is a path, then set the path option to
60
+ # true. This will enable tab completion for file paths relative
61
+ # to the current working directory on systems that support
62
+ # Readline.
63
+ #
64
+ # ==== Example
65
+ # ask("What is your name?")
66
+ #
67
+ # ask("What is your favorite Neopolitan flavor?", :limited_to => ["strawberry", "chocolate", "vanilla"])
68
+ #
69
+ # ask("What is your password?", :echo => false)
70
+ #
71
+ # ask("Where should the file be saved?", :path => true)
72
+ #
73
+ def ask(statement, *args)
74
+ options = args.last.is_a?(Hash) ? args.pop : {}
75
+ color = args.first
76
+
77
+ if options[:limited_to]
78
+ ask_filtered(statement, color, options)
79
+ else
80
+ ask_simply(statement, color, options)
81
+ end
82
+ end
83
+
84
+ # Say (print) something to the user. If the sentence ends with a whitespace
85
+ # or tab character, a new line is not appended (print + flush). Otherwise
86
+ # are passed straight to puts (behavior got from Highline).
87
+ #
88
+ # ==== Example
89
+ # say("I know you knew that.")
90
+ #
91
+ def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
92
+ buffer = prepare_message(message, *color)
93
+ buffer << "\n" if force_new_line && !message.to_s.end_with?("\n")
94
+
95
+ stdout.print(buffer)
96
+ stdout.flush
97
+ end
98
+
99
+ # Say a status with the given color and appends the message. Since this
100
+ # method is used frequently by actions, it allows nil or false to be given
101
+ # in log_status, avoiding the message from being shown. If a Symbol is
102
+ # given in log_status, it's used as the color.
103
+ #
104
+ def say_status(status, message, log_status = true)
105
+ return if quiet? || log_status == false
106
+ spaces = " " * (padding + 1)
107
+ color = log_status.is_a?(Symbol) ? log_status : :green
108
+
109
+ status = status.to_s.rjust(12)
110
+ status = set_color status, color, true if color
111
+
112
+ buffer = "#{status}#{spaces}#{message}"
113
+ buffer << "\n" unless buffer.end_with?("\n")
114
+
115
+ stdout.print(buffer)
116
+ stdout.flush
117
+ end
118
+
119
+ # Make a question the to user and returns true if the user replies "y" or
120
+ # "yes".
121
+ #
122
+ def yes?(statement, color = nil)
123
+ !!(ask(statement, color, :add_to_history => false) =~ is?(:yes))
124
+ end
125
+
126
+ # Make a question the to user and returns true if the user replies "n" or
127
+ # "no".
128
+ #
129
+ def no?(statement, color = nil)
130
+ !!(ask(statement, color, :add_to_history => false) =~ is?(:no))
131
+ end
132
+
133
+ # Prints values in columns
134
+ #
135
+ # ==== Parameters
136
+ # Array[String, String, ...]
137
+ #
138
+ def print_in_columns(array)
139
+ return if array.empty?
140
+ colwidth = (array.map { |el| el.to_s.size }.max || 0) + 2
141
+ array.each_with_index do |value, index|
142
+ # Don't output trailing spaces when printing the last column
143
+ if ((((index + 1) % (terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length
144
+ stdout.puts value
145
+ else
146
+ stdout.printf("%-#{colwidth}s", value)
147
+ end
148
+ end
149
+ end
150
+
151
+ # Prints a table.
152
+ #
153
+ # ==== Parameters
154
+ # Array[Array[String, String, ...]]
155
+ #
156
+ # ==== Options
157
+ # indent<Integer>:: Indent the first column by indent value.
158
+ # colwidth<Integer>:: Force the first column to colwidth spaces wide.
159
+ #
160
+ def print_table(array, options = {}) # rubocop:disable MethodLength
161
+ return if array.empty?
162
+
163
+ formats = []
164
+ indent = options[:indent].to_i
165
+ colwidth = options[:colwidth]
166
+ options[:truncate] = terminal_width if options[:truncate] == true
167
+
168
+ formats << "%-#{colwidth + 2}s" if colwidth
169
+ start = colwidth ? 1 : 0
170
+
171
+ colcount = array.max { |a, b| a.size <=> b.size }.size
172
+
173
+ maximas = []
174
+
175
+ start.upto(colcount - 1) do |index|
176
+ maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max
177
+ maximas << maxima
178
+ formats << if index == colcount - 1
179
+ # Don't output 2 trailing spaces when printing the last column
180
+ "%-s"
181
+ else
182
+ "%-#{maxima + 2}s"
183
+ end
184
+ end
185
+
186
+ formats[0] = formats[0].insert(0, " " * indent)
187
+ formats << "%s"
188
+
189
+ array.each do |row|
190
+ sentence = ""
191
+
192
+ row.each_with_index do |column, index|
193
+ maxima = maximas[index]
194
+
195
+ f = if column.is_a?(Numeric)
196
+ if index == row.size - 1
197
+ # Don't output 2 trailing spaces when printing the last column
198
+ "%#{maxima}s"
199
+ else
200
+ "%#{maxima}s "
201
+ end
202
+ else
203
+ formats[index]
204
+ end
205
+ sentence << f % column.to_s
206
+ end
207
+
208
+ sentence = truncate(sentence, options[:truncate]) if options[:truncate]
209
+ stdout.puts sentence
210
+ end
211
+ end
212
+
213
+ # Prints a long string, word-wrapping the text to the current width of the
214
+ # terminal display. Ideal for printing heredocs.
215
+ #
216
+ # ==== Parameters
217
+ # String
218
+ #
219
+ # ==== Options
220
+ # indent<Integer>:: Indent each line of the printed paragraph by indent value.
221
+ #
222
+ def print_wrapped(message, options = {})
223
+ indent = options[:indent] || 0
224
+ width = terminal_width - indent
225
+ paras = message.split("\n\n")
226
+
227
+ paras.map! do |unwrapped|
228
+ unwrapped.strip.tr("\n", " ").squeeze(" ").gsub(/.{1,#{width}}(?:\s|\Z)/) { ($& + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n") }
229
+ end
230
+
231
+ paras.each do |para|
232
+ para.split("\n").each do |line|
233
+ stdout.puts line.insert(0, " " * indent)
234
+ end
235
+ stdout.puts unless para == paras.last
236
+ end
237
+ end
238
+
239
+ # Deals with file collision and returns true if the file should be
240
+ # overwritten and false otherwise. If a block is given, it uses the block
241
+ # response as the content for the diff.
242
+ #
243
+ # ==== Parameters
244
+ # destination<String>:: the destination file to solve conflicts
245
+ # block<Proc>:: an optional block that returns the value to be used in diff
246
+ #
247
+ def file_collision(destination)
248
+ return true if @always_force
249
+ options = block_given? ? "[Ynaqdh]" : "[Ynaqh]"
250
+
251
+ loop do
252
+ answer = ask(
253
+ %[Overwrite #{destination}? (enter "h" for help) #{options}],
254
+ :add_to_history => false
255
+ )
256
+
257
+ case answer
258
+ when is?(:yes), is?(:force), ""
259
+ return true
260
+ when is?(:no), is?(:skip)
261
+ return false
262
+ when is?(:always)
263
+ return @always_force = true
264
+ when is?(:quit)
265
+ say "Aborting..."
266
+ raise SystemExit
267
+ when is?(:diff)
268
+ show_diff(destination, yield) if block_given?
269
+ say "Retrying..."
270
+ else
271
+ say file_collision_help
272
+ end
273
+ end
274
+ end
275
+
276
+ # This code was copied from Rake, available under MIT-LICENSE
277
+ # Copyright (c) 2003, 2004 Jim Weirich
278
+ def terminal_width
279
+ result = if ENV["THOR_COLUMNS"]
280
+ ENV["THOR_COLUMNS"].to_i
281
+ else
282
+ unix? ? dynamic_width : 80
283
+ end
284
+ result < 10 ? 80 : result
285
+ rescue
286
+ 80
287
+ end
288
+
289
+ # Called if something goes wrong during the execution. This is used by Foreman::Thor
290
+ # internally and should not be used inside your scripts. If something went
291
+ # wrong, you can always raise an exception. If you raise a Foreman::Thor::Error, it
292
+ # will be rescued and wrapped in the method below.
293
+ #
294
+ def error(statement)
295
+ stderr.puts statement
296
+ end
297
+
298
+ # Apply color to the given string with optional bold. Disabled in the
299
+ # Foreman::Thor::Shell::Basic class.
300
+ #
301
+ def set_color(string, *) #:nodoc:
302
+ string
303
+ end
304
+
305
+ protected
306
+
307
+ def prepare_message(message, *color)
308
+ spaces = " " * padding
309
+ spaces + set_color(message.to_s, *color)
310
+ end
311
+
312
+ def can_display_colors?
313
+ false
314
+ end
315
+
316
+ def lookup_color(color)
317
+ return color unless color.is_a?(Symbol)
318
+ self.class.const_get(color.to_s.upcase)
319
+ end
320
+
321
+ def stdout
322
+ $stdout
323
+ end
324
+
325
+ def stderr
326
+ $stderr
327
+ end
328
+
329
+ def is?(value) #:nodoc:
330
+ value = value.to_s
331
+
332
+ if value.size == 1
333
+ /\A#{value}\z/i
334
+ else
335
+ /\A(#{value}|#{value[0, 1]})\z/i
336
+ end
337
+ end
338
+
339
+ def file_collision_help #:nodoc:
340
+ <<-HELP
341
+ Y - yes, overwrite
342
+ n - no, do not overwrite
343
+ a - all, overwrite this and all others
344
+ q - quit, abort
345
+ d - diff, show the differences between the old and the new
346
+ h - help, show this help
347
+ HELP
348
+ end
349
+
350
+ def show_diff(destination, content) #:nodoc:
351
+ diff_cmd = ENV["THOR_DIFF"] || ENV["RAILS_DIFF"] || "diff -u"
352
+
353
+ Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp|
354
+ temp.write content
355
+ temp.rewind
356
+ system %(#{diff_cmd} "#{destination}" "#{temp.path}")
357
+ end
358
+ end
359
+
360
+ def quiet? #:nodoc:
361
+ mute? || (base && base.options[:quiet])
362
+ end
363
+
364
+ # Calculate the dynamic width of the terminal
365
+ def dynamic_width
366
+ @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
367
+ end
368
+
369
+ def dynamic_width_stty
370
+ `stty size 2>/dev/null`.split[1].to_i
371
+ end
372
+
373
+ def dynamic_width_tput
374
+ `tput cols 2>/dev/null`.to_i
375
+ end
376
+
377
+ def unix?
378
+ RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
379
+ end
380
+
381
+ def truncate(string, width)
382
+ as_unicode do
383
+ chars = string.chars.to_a
384
+ if chars.length <= width
385
+ chars.join
386
+ else
387
+ chars[0, width - 3].join + "..."
388
+ end
389
+ end
390
+ end
391
+
392
+ if "".respond_to?(:encode)
393
+ def as_unicode
394
+ yield
395
+ end
396
+ else
397
+ def as_unicode
398
+ old = $KCODE
399
+ $KCODE = "U"
400
+ yield
401
+ ensure
402
+ $KCODE = old
403
+ end
404
+ end
405
+
406
+ def ask_simply(statement, color, options)
407
+ default = options[:default]
408
+ message = [statement, ("(#{default})" if default), nil].uniq.join(" ")
409
+ message = prepare_message(message, *color)
410
+ result = Foreman::Thor::LineEditor.readline(message, options)
411
+
412
+ return unless result
413
+
414
+ result.strip!
415
+
416
+ if default && result == ""
417
+ default
418
+ else
419
+ result
420
+ end
421
+ end
422
+
423
+ def ask_filtered(statement, color, options)
424
+ answer_set = options[:limited_to]
425
+ correct_answer = nil
426
+ until correct_answer
427
+ answers = answer_set.join(", ")
428
+ answer = ask_simply("#{statement} [#{answers}]", color, options)
429
+ correct_answer = answer_set.include?(answer) ? answer : nil
430
+ say("Your response must be one of: [#{answers}]. Please try again.") unless correct_answer
431
+ end
432
+ correct_answer
433
+ end
434
+ end
435
+ end
436
+ end
@@ -0,0 +1,149 @@
1
+ require "foreman/vendor/thor/lib/thor/shell/basic"
2
+
3
+ class Foreman::Thor
4
+ module Shell
5
+ # Inherit from Foreman::Thor::Shell::Basic and add set_color behavior. Check
6
+ # Foreman::Thor::Shell::Basic to see all available methods.
7
+ #
8
+ class Color < Basic
9
+ # Embed in a String to clear all previous ANSI sequences.
10
+ CLEAR = "\e[0m"
11
+ # The start of an ANSI bold sequence.
12
+ BOLD = "\e[1m"
13
+
14
+ # Set the terminal's foreground ANSI color to black.
15
+ BLACK = "\e[30m"
16
+ # Set the terminal's foreground ANSI color to red.
17
+ RED = "\e[31m"
18
+ # Set the terminal's foreground ANSI color to green.
19
+ GREEN = "\e[32m"
20
+ # Set the terminal's foreground ANSI color to yellow.
21
+ YELLOW = "\e[33m"
22
+ # Set the terminal's foreground ANSI color to blue.
23
+ BLUE = "\e[34m"
24
+ # Set the terminal's foreground ANSI color to magenta.
25
+ MAGENTA = "\e[35m"
26
+ # Set the terminal's foreground ANSI color to cyan.
27
+ CYAN = "\e[36m"
28
+ # Set the terminal's foreground ANSI color to white.
29
+ WHITE = "\e[37m"
30
+
31
+ # Set the terminal's background ANSI color to black.
32
+ ON_BLACK = "\e[40m"
33
+ # Set the terminal's background ANSI color to red.
34
+ ON_RED = "\e[41m"
35
+ # Set the terminal's background ANSI color to green.
36
+ ON_GREEN = "\e[42m"
37
+ # Set the terminal's background ANSI color to yellow.
38
+ ON_YELLOW = "\e[43m"
39
+ # Set the terminal's background ANSI color to blue.
40
+ ON_BLUE = "\e[44m"
41
+ # Set the terminal's background ANSI color to magenta.
42
+ ON_MAGENTA = "\e[45m"
43
+ # Set the terminal's background ANSI color to cyan.
44
+ ON_CYAN = "\e[46m"
45
+ # Set the terminal's background ANSI color to white.
46
+ ON_WHITE = "\e[47m"
47
+
48
+ # Set color by using a string or one of the defined constants. If a third
49
+ # option is set to true, it also adds bold to the string. This is based
50
+ # on Highline implementation and it automatically appends CLEAR to the end
51
+ # of the returned String.
52
+ #
53
+ # Pass foreground, background and bold options to this method as
54
+ # symbols.
55
+ #
56
+ # Example:
57
+ #
58
+ # set_color "Hi!", :red, :on_white, :bold
59
+ #
60
+ # The available colors are:
61
+ #
62
+ # :bold
63
+ # :black
64
+ # :red
65
+ # :green
66
+ # :yellow
67
+ # :blue
68
+ # :magenta
69
+ # :cyan
70
+ # :white
71
+ # :on_black
72
+ # :on_red
73
+ # :on_green
74
+ # :on_yellow
75
+ # :on_blue
76
+ # :on_magenta
77
+ # :on_cyan
78
+ # :on_white
79
+ def set_color(string, *colors)
80
+ if colors.compact.empty? || !can_display_colors?
81
+ string
82
+ elsif colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) }
83
+ ansi_colors = colors.map { |color| lookup_color(color) }
84
+ "#{ansi_colors.join}#{string}#{CLEAR}"
85
+ else
86
+ # The old API was `set_color(color, bold=boolean)`. We
87
+ # continue to support the old API because you should never
88
+ # break old APIs unnecessarily :P
89
+ foreground, bold = colors
90
+ foreground = self.class.const_get(foreground.to_s.upcase) if foreground.is_a?(Symbol)
91
+
92
+ bold = bold ? BOLD : ""
93
+ "#{bold}#{foreground}#{string}#{CLEAR}"
94
+ end
95
+ end
96
+
97
+ protected
98
+
99
+ def can_display_colors?
100
+ stdout.tty?
101
+ end
102
+
103
+ # Overwrite show_diff to show diff with colors if Diff::LCS is
104
+ # available.
105
+ #
106
+ def show_diff(destination, content) #:nodoc:
107
+ if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil?
108
+ actual = File.binread(destination).to_s.split("\n")
109
+ content = content.to_s.split("\n")
110
+
111
+ Diff::LCS.sdiff(actual, content).each do |diff|
112
+ output_diff_line(diff)
113
+ end
114
+ else
115
+ super
116
+ end
117
+ end
118
+
119
+ def output_diff_line(diff) #:nodoc:
120
+ case diff.action
121
+ when "-"
122
+ say "- #{diff.old_element.chomp}", :red, true
123
+ when "+"
124
+ say "+ #{diff.new_element.chomp}", :green, true
125
+ when "!"
126
+ say "- #{diff.old_element.chomp}", :red, true
127
+ say "+ #{diff.new_element.chomp}", :green, true
128
+ else
129
+ say " #{diff.old_element.chomp}", nil, true
130
+ end
131
+ end
132
+
133
+ # Check if Diff::LCS is loaded. If it is, use it to create pretty output
134
+ # for diff.
135
+ #
136
+ def diff_lcs_loaded? #:nodoc:
137
+ return true if defined?(Diff::LCS)
138
+ return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
139
+
140
+ @diff_lcs_loaded = begin
141
+ require "diff/lcs"
142
+ true
143
+ rescue LoadError
144
+ false
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,126 @@
1
+ require "foreman/vendor/thor/lib/thor/shell/basic"
2
+
3
+ class Foreman::Thor
4
+ module Shell
5
+ # Inherit from Foreman::Thor::Shell::Basic and add set_color behavior. Check
6
+ # Foreman::Thor::Shell::Basic to see all available methods.
7
+ #
8
+ class HTML < Basic
9
+ # The start of an HTML bold sequence.
10
+ BOLD = "font-weight: bold"
11
+
12
+ # Set the terminal's foreground HTML color to black.
13
+ BLACK = "color: black"
14
+ # Set the terminal's foreground HTML color to red.
15
+ RED = "color: red"
16
+ # Set the terminal's foreground HTML color to green.
17
+ GREEN = "color: green"
18
+ # Set the terminal's foreground HTML color to yellow.
19
+ YELLOW = "color: yellow"
20
+ # Set the terminal's foreground HTML color to blue.
21
+ BLUE = "color: blue"
22
+ # Set the terminal's foreground HTML color to magenta.
23
+ MAGENTA = "color: magenta"
24
+ # Set the terminal's foreground HTML color to cyan.
25
+ CYAN = "color: cyan"
26
+ # Set the terminal's foreground HTML color to white.
27
+ WHITE = "color: white"
28
+
29
+ # Set the terminal's background HTML color to black.
30
+ ON_BLACK = "background-color: black"
31
+ # Set the terminal's background HTML color to red.
32
+ ON_RED = "background-color: red"
33
+ # Set the terminal's background HTML color to green.
34
+ ON_GREEN = "background-color: green"
35
+ # Set the terminal's background HTML color to yellow.
36
+ ON_YELLOW = "background-color: yellow"
37
+ # Set the terminal's background HTML color to blue.
38
+ ON_BLUE = "background-color: blue"
39
+ # Set the terminal's background HTML color to magenta.
40
+ ON_MAGENTA = "background-color: magenta"
41
+ # Set the terminal's background HTML color to cyan.
42
+ ON_CYAN = "background-color: cyan"
43
+ # Set the terminal's background HTML color to white.
44
+ ON_WHITE = "background-color: white"
45
+
46
+ # Set color by using a string or one of the defined constants. If a third
47
+ # option is set to true, it also adds bold to the string. This is based
48
+ # on Highline implementation and it automatically appends CLEAR to the end
49
+ # of the returned String.
50
+ #
51
+ def set_color(string, *colors)
52
+ if colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) }
53
+ html_colors = colors.map { |color| lookup_color(color) }
54
+ "<span style=\"#{html_colors.join('; ')};\">#{string}</span>"
55
+ else
56
+ color, bold = colors
57
+ html_color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol)
58
+ styles = [html_color]
59
+ styles << BOLD if bold
60
+ "<span style=\"#{styles.join('; ')};\">#{string}</span>"
61
+ end
62
+ end
63
+
64
+ # Ask something to the user and receives a response.
65
+ #
66
+ # ==== Example
67
+ # ask("What is your name?")
68
+ #
69
+ # TODO: Implement #ask for Foreman::Thor::Shell::HTML
70
+ def ask(statement, color = nil)
71
+ raise NotImplementedError, "Implement #ask for Foreman::Thor::Shell::HTML"
72
+ end
73
+
74
+ protected
75
+
76
+ def can_display_colors?
77
+ true
78
+ end
79
+
80
+ # Overwrite show_diff to show diff with colors if Diff::LCS is
81
+ # available.
82
+ #
83
+ def show_diff(destination, content) #:nodoc:
84
+ if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil?
85
+ actual = File.binread(destination).to_s.split("\n")
86
+ content = content.to_s.split("\n")
87
+
88
+ Diff::LCS.sdiff(actual, content).each do |diff|
89
+ output_diff_line(diff)
90
+ end
91
+ else
92
+ super
93
+ end
94
+ end
95
+
96
+ def output_diff_line(diff) #:nodoc:
97
+ case diff.action
98
+ when "-"
99
+ say "- #{diff.old_element.chomp}", :red, true
100
+ when "+"
101
+ say "+ #{diff.new_element.chomp}", :green, true
102
+ when "!"
103
+ say "- #{diff.old_element.chomp}", :red, true
104
+ say "+ #{diff.new_element.chomp}", :green, true
105
+ else
106
+ say " #{diff.old_element.chomp}", nil, true
107
+ end
108
+ end
109
+
110
+ # Check if Diff::LCS is loaded. If it is, use it to create pretty output
111
+ # for diff.
112
+ #
113
+ def diff_lcs_loaded? #:nodoc:
114
+ return true if defined?(Diff::LCS)
115
+ return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
116
+
117
+ @diff_lcs_loaded = begin
118
+ require "diff/lcs"
119
+ true
120
+ rescue LoadError
121
+ false
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end