Class: Chef::Knife::UI

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/chef/knife/core/ui.rb

Overview

==Chef::Knife::UI The User Interaction class used by knife.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(stdout, stderr, stdin, config) ⇒ UI


46
47
48
49
# File 'lib/chef/knife/core/ui.rb', line 46

def initialize(stdout, stderr, stdin, config)
  @stdout, @stderr, @stdin, @config = stdout, stderr, stdin, config
  @presenter = Chef::Knife::Core::GenericPresenter.new(self, config)
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config


38
39
40
# File 'lib/chef/knife/core/ui.rb', line 38

def config
  @config
end

#presenterObject (readonly)

Returns the value of attribute presenter


40
41
42
# File 'lib/chef/knife/core/ui.rb', line 40

def presenter
  @presenter
end

#stderrObject (readonly)

Returns the value of attribute stderr


36
37
38
# File 'lib/chef/knife/core/ui.rb', line 36

def stderr
  @stderr
end

#stdinObject (readonly)

Returns the value of attribute stdin


37
38
39
# File 'lib/chef/knife/core/ui.rb', line 37

def stdin
  @stdin
end

#stdoutObject (readonly)

Returns the value of attribute stdout


35
36
37
# File 'lib/chef/knife/core/ui.rb', line 35

def stdout
  @stdout
end

Instance Method Details

#ask(*args, &block) ⇒ Object


115
116
117
# File 'lib/chef/knife/core/ui.rb', line 115

def ask(*args, &block)
  highline.ask(*args, &block)
end

#ask_question(question, opts = {}) ⇒ Object


136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/chef/knife/core/ui.rb', line 136

def ask_question(question, opts = {})
  question += "[#{opts[:default]}] " if opts[:default]

  if opts[:default] && config[:defaults]
    opts[:default]
  else
    stdout.print question
    a = stdin.readline.strip

    if opts[:default]
      a.empty? ? opts[:default] : a
    else
      a
    end
  end
end

#color(string, *colors) ⇒ Object


100
101
102
103
104
105
106
# File 'lib/chef/knife/core/ui.rb', line 100

def color(string, *colors)
  if color?
    highline.color(string, *colors)
  else
    string
  end
end

#color?Boolean

Should colored output be used? For output to a terminal, this is determined by the value of config[:color]. When output is not to a terminal, colored output is never used


111
112
113
# File 'lib/chef/knife/core/ui.rb', line 111

def color?
  Chef::Config[:color] && stdout.tty?
end

#confirm(question, append_instructions = true, default_choice = nil) ⇒ Object

Not the ideal signature for a function but we need to stick with this for now until we get a chance to break our API in Chef 12.

question => Question to print before asking for confirmation append_instructions => Should print '? (Y/N)' as instructions default_choice => Set to true for 'Y', and false for 'N' as default answer


268
269
270
271
272
273
# File 'lib/chef/knife/core/ui.rb', line 268

def confirm(question, append_instructions = true, default_choice = nil)
  unless confirm_without_exit(question, append_instructions, default_choice)
    exit 3
  end
  true
end

#confirm_without_exit(question, append_instructions = true, default_choice = nil) ⇒ Object

See confirm method for argument information


230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/chef/knife/core/ui.rb', line 230

def confirm_without_exit(question, append_instructions = true, default_choice = nil)
  return true if config[:yes]

  stdout.print question
  stdout.print confirmation_instructions(default_choice) if append_instructions

  answer = stdin.readline
  answer.chomp!

  case answer
  when "Y", "y"
    true
  when "N", "n"
    msg("You said no, so I'm done here.")
    false
  when ""
    unless default_choice.nil?
      default_choice
    else
      msg("I have no idea what to do with '#{answer}'")
      msg("Just say Y or N, please.")
      confirm_without_exit(question, append_instructions, default_choice)
    end
  else
    msg("I have no idea what to do with '#{answer}'")
    msg("Just say Y or N, please.")
    confirm_without_exit(question, append_instructions, default_choice)
  end
end

#confirmation_instructions(default_choice) ⇒ Object


218
219
220
221
222
223
224
225
226
227
# File 'lib/chef/knife/core/ui.rb', line 218

def confirmation_instructions(default_choice)
  case default_choice
  when true
    "? (Y/n) "
  when false
    "? (y/N) "
  else
    "? (Y/N) "
  end
end

#edit_data(data, parse_output = true, object_class: nil) ⇒ Object


168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/chef/knife/core/ui.rb', line 168

def edit_data(data, parse_output = true, object_class: nil)
  output = Chef::JSONCompat.to_json_pretty(data)
  if !config[:disable_editing]
    Tempfile.open([ "knife-edit-", ".json" ]) do |tf|
      tf.sync = true
      tf.puts output
      tf.close
      raise "Please set EDITOR environment variable" unless system("#{config[:editor]} #{tf.path}")

      output = IO.read(tf.path)
    end
  end

  if parse_output
    if object_class.nil?
      raise ArgumentError, "Please pass in the object class to hydrate or use #edit_hash"
    else
      object_class.from_hash(Chef::JSONCompat.parse(output))
    end
  else
    output
  end
end

#edit_hash(hash) ⇒ Object

Hash -> Hash Works the same as edit_data but returns a hash rather than a JSON string/Fully inflated object


163
164
165
166
# File 'lib/chef/knife/core/ui.rb', line 163

def edit_hash(hash)
  raw = edit_data(hash, false)
  Chef::JSONCompat.parse(raw)
end

#edit_object(klass, name) ⇒ Object


192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/chef/knife/core/ui.rb', line 192

def edit_object(klass, name)
  object = klass.load(name)

  output = edit_data(object, object_class: klass)

  # Only make the save if the user changed the object.
  #
  # Output JSON for the original (object) and edited (output), then parse
  # them without reconstituting the objects into real classes
  # (create_additions=false). Then, compare the resulting simple objects,
  # which will be Array/Hash/String/etc.
  #
  # We wouldn't have to do these shenanigans if all the editable objects
  # implemented to_hash, or if to_json against a hash returned a string
  # with stable key order.
  object_parsed_again = Chef::JSONCompat.parse(Chef::JSONCompat.to_json(object))
  output_parsed_again = Chef::JSONCompat.parse(Chef::JSONCompat.to_json(output))
  if object_parsed_again != output_parsed_again
    output.save
    msg("Saved #{output}")
  else
    msg("Object unchanged, not saving")
  end
  output(format_for_display(object)) if config[:print_after]
end

#error(message) ⇒ Object

Print an error message


91
92
93
# File 'lib/chef/knife/core/ui.rb', line 91

def error(message)
  log("#{color('ERROR:', :red, :bold)} #{message}")
end

#fatal(message) ⇒ Object

Print a message describing a fatal error.


96
97
98
# File 'lib/chef/knife/core/ui.rb', line 96

def fatal(message)
  log("#{color('FATAL:', :red, :bold)} #{message}")
end

#highlineObject


58
59
60
61
62
63
# File 'lib/chef/knife/core/ui.rb', line 58

def highline
  @highline ||= begin
    require "highline"
    HighLine.new
  end
end

#interchange?Boolean

Determines if the output format is a data interchange format, i.e., JSON or YAML


132
133
134
# File 'lib/chef/knife/core/ui.rb', line 132

def interchange?
  @presenter.interchange?
end

#list(*args) ⇒ Object


119
120
121
# File 'lib/chef/knife/core/ui.rb', line 119

def list(*args)
  highline.list(*args)
end

#log(message) ⇒ Object Also known as: info, err

Prints a msg to stderr. Used for info, warn, error, and fatal.


75
76
77
78
79
80
# File 'lib/chef/knife/core/ui.rb', line 75

def log(message)
  stderr.puts message
rescue Errno::EPIPE => e
  raise e if @config[:verbosity] >= 2
  exit 0
end

#msg(message) ⇒ Object

Prints a message to stdout. Aliased as +info+ for compatibility with the logger API.


67
68
69
70
71
72
# File 'lib/chef/knife/core/ui.rb', line 67

def msg(message)
  stdout.puts message
rescue Errno::EPIPE => e
  raise e if @config[:verbosity] >= 2
  exit 0
end

#output(data) ⇒ Object

Formats +data+ using the configured presenter and outputs the result via +msg+. Formatting can be customized by configuring a different presenter. See +use_presenter+


126
127
128
# File 'lib/chef/knife/core/ui.rb', line 126

def output(data)
  msg @presenter.format(data)
end

#pretty_print(data) ⇒ Object


153
154
155
156
157
158
# File 'lib/chef/knife/core/ui.rb', line 153

def pretty_print(data)
  stdout.puts data
rescue Errno::EPIPE => e
  raise e if @config[:verbosity] >= 2
  exit 0
end

#use_presenter(presenter_class) ⇒ Object

Creates a new +presenter_class+ object and uses it to format structured data for display. By default, a Chef::Knife::Core::GenericPresenter object is used.


54
55
56
# File 'lib/chef/knife/core/ui.rb', line 54

def use_presenter(presenter_class)
  @presenter = presenter_class.new(self, config)
end

#warn(message) ⇒ Object

Print a warning message


86
87
88
# File 'lib/chef/knife/core/ui.rb', line 86

def warn(message)
  log("#{color('WARNING:', :yellow, :bold)} #{message}")
end