Class: Bolt::Outputter::Human

Inherits:
Bolt::Outputter show all
Defined in:
lib/bolt/outputter/human.rb

Constant Summary collapse

COLORS =
{ red: "31",
green: "32",
yellow: "33" }.freeze

Instance Method Summary collapse

Methods inherited from Bolt::Outputter

for_format, #initialize, #print_message

Constructor Details

This class inherits a constructor from Bolt::Outputter

Instance Method Details

#colorize(color, string) ⇒ Object



14
15
16
17
18
19
20
# File 'lib/bolt/outputter/human.rb', line 14

def colorize(color, string)
  if @color && @stream.isatty
    "\033[#{COLORS[color]}m#{string}\033[0m"
  else
    string
  end
end

#fatal_error(err) ⇒ Object



253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/bolt/outputter/human.rb', line 253

def fatal_error(err)
  @stream.puts(colorize(:red, err.message))
  if err.is_a? Bolt::RunFailure
    @stream.puts ::JSON.pretty_generate(err.result_set)
  end

  if @trace && err.backtrace
    err.backtrace.each do |line|
      @stream.puts(colorize(:red, "\t#{line}"))
    end
  end
end

#indent(indent, string) ⇒ Object



22
23
24
25
# File 'lib/bolt/outputter/human.rb', line 22

def indent(indent, string)
  indent = ' ' * indent
  string.gsub(/^/, indent.to_s)
end


225
226
227
228
# File 'lib/bolt/outputter/human.rb', line 225

def print_apply_result(apply_result)
  apply_result.each { |result| print_result(result) }
  print_summary(apply_result)
end


31
32
33
34
35
36
37
38
# File 'lib/bolt/outputter/human.rb', line 31

def print_event(event)
  case event[:type]
  when :node_start
    print_start(event[:target])
  when :node_result
    print_result(event[:result])
  end
end


12
# File 'lib/bolt/outputter/human.rb', line 12

def print_head; end


196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/bolt/outputter/human.rb', line 196

def print_module_list(module_list)
  module_list.each do |path, modules|
    if (mod = modules.find { |m| m[:internal_module_group] })
      @stream.puts(mod[:internal_module_group])
    else
      @stream.puts(path)
    end

    if modules.empty?
      @stream.puts('(no modules installed)')
    else
      module_info = modules.map do |m|
        version = if m[:version].nil?
                    m[:internal_module_group].nil? ? '(no metadata)' : '(built-in)'
                  else
                    m[:version]
                  end

        [m[:name], version]
      end

      print_table(module_info)
    end

    @stream.write("\n")
  end
end


163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/bolt/outputter/human.rb', line 163

def print_plan_info(plan)
  # Building lots of strings...
  pretty_params = +""
  plan_info = +""
  usage = +"bolt plan run #{plan['name']}"

  plan['parameters']&.each do |name, p|
    pretty_params << "- #{name}: #{p['type']}\n"
    usage << (p.include?('default_value') ? " [#{name}=<value>]" : " #{name}=<value>")
  end

  plan_info << "\n#{plan['name']}"
  plan_info << "\n\n"
  plan_info << "USAGE:\n#{usage}\n\n"
  plan_info << "PARAMETERS:\n#{pretty_params}\n" if plan['parameters']
  plan_info << "MODULE:\n"

  path = plan['module']
  plan_info << if path.start_with?(Bolt::PAL::MODULES_PATH)
                 "built-in module"
               else
                 path
               end
  @stream.puts(plan_info)
end


231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/bolt/outputter/human.rb', line 231

def print_plan_result(plan_result)
  value = plan_result.value
  if value.nil?
    @stream.puts("Plan completed successfully with no result")
  elsif value.is_a? Bolt::ApplyFailure
    @stream.puts(colorize(:red, value.message))
  elsif value.is_a? Bolt::ResultSet
    value.each { |result| print_result(result) }
    print_summary(value)
  else
    @stream.puts(::JSON.pretty_generate(plan_result, quirks_mode: true))
  end
end


189
190
191
192
193
194
# File 'lib/bolt/outputter/human.rb', line 189

def print_plans(plans, modulepath)
  print_table(plans)
  print_message("\nMODULEPATH:\n#{modulepath.join(':')}\n"\
                  "\nUse `bolt plan show <plan-name>` to view "\
                  "details and parameters for a specific plan.")
end


245
246
247
248
249
250
251
# File 'lib/bolt/outputter/human.rb', line 245

def print_puppetfile_result(success, puppetfile, moduledir)
  if success
    @stream.puts("Successfully synced modules from #{puppetfile} to #{moduledir}")
  else
    @stream.puts(colorize(:red, "Failed to sync modules from #{puppetfile} to #{moduledir}"))
  end
end


44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/bolt/outputter/human.rb', line 44

def print_result(result)
  if result.success?
    @stream.puts(colorize(:green, "Finished on #{result.target.host}:"))
  else
    @stream.puts(colorize(:red, "Failed on #{result.target.host}:"))
  end

  if result.error_hash
    @stream.puts(colorize(:red, remove_trail(indent(2, result.error_hash['msg']))))
  end

  if result.message
    @stream.puts(remove_trail(indent(2, result.message)))
  end

  # There is more information to output
  if result.generic_value
    # Use special handling if the result looks like a command or script result
    if result.generic_value.keys == %w[stdout stderr exit_code]
      unless result['stdout'].strip.empty?
        @stream.puts(indent(2, "STDOUT:"))
        @stream.puts(indent(4, result['stdout']))
      end
      unless result['stderr'].strip.empty?
        @stream.puts(indent(2, "STDERR:"))
        @stream.puts(indent(4, result['stderr']))
      end
    else
      @stream.puts(indent(2, ::JSON.pretty_generate(result.generic_value)))
    end
  end
end


40
41
42
# File 'lib/bolt/outputter/human.rb', line 40

def print_start(target)
  @stream.puts(colorize(:green, "Started on #{target.host}..."))
end


77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/bolt/outputter/human.rb', line 77

def print_summary(results, elapsed_time = nil)
  ok_set = results.ok_set
  unless ok_set.empty?
    @stream.puts format('Successful on %<size>d node%<plural>s: %<names>s',
                        size: ok_set.size,
                        plural: ok_set.size == 1 ? '' : 's',
                        names: ok_set.names.join(','))
  end

  error_set = results.error_set
  unless error_set.empty?
    @stream.puts colorize(:red,
                          format('Failed on %<size>d node%<plural>s: %<names>s',
                                 size: error_set.size,
                                 plural: error_set.size == 1 ? '' : 's',
                                 names: error_set.names.join(',')))
  end

  total_msg = format('Ran on %<size>d node%<plural>s',
                     size: results.size,
                     plural: results.size == 1 ? '' : 's')
  total_msg += format(' in %<elapsed>.2f seconds', elapsed: elapsed_time) unless elapsed_time.nil?
  @stream.puts total_msg
end


102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/bolt/outputter/human.rb', line 102

def print_table(results)
  # lazy-load expensive gem code
  require 'terminal-table'

  @stream.puts Terminal::Table.new(
    rows: results,
    style: {
      border_x: '',
      border_y: '',
      border_i: '',
      padding_left: 0,
      padding_right: 3,
      border_top: false,
      border_bottom: false
    }
  )
end


128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/bolt/outputter/human.rb', line 128

def print_task_info(task)
  # Building lots of strings...
  pretty_params = +""
  task_info = +""
  usage = +"bolt task run --nodes <node-name> #{task['name']}"

  task['metadata']['parameters']&.each do |k, v|
    pretty_params << "- #{k}: #{v['type'] || 'Any'}\n"
    pretty_params << "    #{v['description']}\n" if v['description']
    usage << if v['type'].is_a?(Puppet::Pops::Types::POptionalType)
               " [#{k}=<value>]"
             else
               " #{k}=<value>"
             end
  end

  usage << " [--noop]" if task['metadata']['supports_noop']

  task_info << "\n#{task['name']}"
  task_info << " - #{task['metadata']['description']}" if task['metadata']['description']
  task_info << "\n\n"
  task_info << "USAGE:\n#{usage}\n\n"
  task_info << "PARAMETERS:\n#{pretty_params}\n" unless pretty_params.empty?
  task_info << "MODULE:\n"

  path = task['files'][0]['path'].chomp("/tasks/#{task['files'][0]['name']}")
  task_info << if path.start_with?(Bolt::PAL::MODULES_PATH)
                 "built-in module"
               else
                 path
               end
  @stream.puts(task_info)
end


120
121
122
123
124
125
# File 'lib/bolt/outputter/human.rb', line 120

def print_tasks(tasks, modulepath)
  print_table(tasks)
  print_message("\nMODULEPATH:\n#{modulepath.join(':')}\n"\
                  "\nUse `bolt task show <task-name>` to view "\
                  "details and parameters for a specific task.")
end

#remove_trail(string) ⇒ Object



27
28
29
# File 'lib/bolt/outputter/human.rb', line 27

def remove_trail(string)
  string.sub(/\s\z/, '')
end