Class: PuppetRepl::Cli

Inherits:
Object
  • Object
show all
Includes:
Support
Defined in:
lib/puppet-repl/cli.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Support

#default_manifests_dir, #default_modules_paths, #default_site_manifest, #do_initialize, #initialize_from_scope, #known_resource_types, #modules_paths, #parse_error, #parser, #puppet_lib_dir, #puppet_repl_lib_dir

Methods included from Support::Play

#convert_to_text, #play_back, #play_back_string, #play_back_url

Methods included from Support::InputResponders

#classes, #classification, #environment, #facts, #functions, #handle_set, #help, #krt, #play, #reset, #resources, #set_log_level, #static_responder_list, #vars

Methods included from Support::Node

#convert_remote_node, #create_node, #get_remote_node, #node, #remote_node_name, #remote_node_name=, #set_node, #set_node_from_name, #set_remote_node_name

Methods included from Support::Functions

#function_files, #function_map, #lib_dirs, #load_lib_dirs, #mod_finder, #resolve_paths

Methods included from Support::Scope

#create_scope, #scope, #scope_vars, #set_scope

Methods included from Support::Facts

#default_facts, #facterdb_filter, #server_facts, #set_facts

Methods included from Support::Environment

#create_environment, #default_puppet_env_name, #environment_loaders, #puppet_env_name, #puppet_environment, #set_environment

Methods included from Support::Compilier

#compiler, #create_compiler, #set_compiler

Constructor Details

#initialize(options = {}) ⇒ Cli

Returns a new instance of Cli.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/puppet-repl/cli.rb', line 12

def initialize(options={})
  @log_level = 'notice'
  @out_buffer = options[:out_buffer] || $stdout
  @html_mode = options[:html_mode] || false
  @in_buffer = options[:in_buffer] || $stdin
  comp = Proc.new do |s|
    key_words.grep(/^#{Regexp.escape(s)}/)
  end
  Readline.completion_append_character = ""
  Readline.basic_word_break_characters = " "

  Readline.completion_proc = comp
  AwesomePrint.defaults = {
    :html => @html_mode,
    :sort_keys => true,
    :indent => 2
  }
  do_initialize
end

Instance Attribute Details

#html_modeObject

Returns the value of attribute html_mode.



10
11
12
# File 'lib/puppet-repl/cli.rb', line 10

def html_mode
  @html_mode
end

#in_bufferObject

Returns the value of attribute in_buffer.



10
11
12
# File 'lib/puppet-repl/cli.rb', line 10

def in_buffer
  @in_buffer
end

#log_levelObject

Returns the value of attribute log_level.



10
11
12
# File 'lib/puppet-repl/cli.rb', line 10

def log_level
  @log_level
end

#out_bufferObject

Returns the value of attribute out_buffer.



10
11
12
# File 'lib/puppet-repl/cli.rb', line 10

def out_buffer
  @out_buffer
end

#settingsObject

Returns the value of attribute settings.



10
11
12
# File 'lib/puppet-repl/cli.rb', line 10

def settings
  @settings
end

Class Method Details



143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/puppet-repl/cli.rb', line 143

def self.print_repl_desc
  output = "Ruby Version: \#{RUBY_VERSION}\nPuppet Version: \#{Puppet.version}\nPuppet Repl Version: \#{PuppetRepl::VERSION}\nCreated by: NWOps <[email protected]>\nType \"exit\", \"functions\", \"vars\", \"krt\", \"facts\", \"resources\", \"classes\",\n \"play\", \"classification\", \"reset\", or \"help\" for more information.\n\n  EOT\n  output\nend\n"

.start(options = {:scope => nil}) ⇒ Object

start reads from stdin or from a file if from stdin, the repl will process the input and exit if from a file, the repl will process the file and continue to prompt

Parameters:

  • puppet (Scope)

    scope object



195
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
# File 'lib/puppet-repl/cli.rb', line 195

def self.start(options={:scope => nil})
  opts = Trollop::options do
    opt :play, "Url or file to load from", :required => false, :type => String
    opt :run_once, "Evaluate and quit", :required => false, :default => false
    opt :node_name, "Remote Node to grab facts from", :required => false, :type => String
  end
  options = opts.merge(options)
  puts print_repl_desc
  repl_obj = new
  repl_obj.remote_node_name = opts[:node_name] if opts[:node_name]
  repl_obj.initialize_from_scope(options[:scope])
  if options[:play]
    repl_obj.play_back(opts)
  # when the user supplied a file name without using the args (stdin)
  elsif ARGF.filename != "-"
    path = File.expand_path(ARGF.filename)
    repl_obj.play_back(:play => path)
  # when the user supplied a file content using stdin, aka. cat,pipe,echo or redirection
  elsif ARGF.filename == "-" and (not STDIN.tty? and not STDIN.closed?)
    input = ARGF.read
    repl_obj.handle_input(input)
  end
  # helper code to make tests exit the loop
  unless options[:run_once]
    repl_obj.read_loop
  end
end

Instance Method Details

#expand_resource_type(types) ⇒ Object

ruturns a formatted array



69
70
71
72
73
74
75
76
77
78
# File 'lib/puppet-repl/cli.rb', line 69

def expand_resource_type(types)
  output = [types].flatten.map do |t|
    if t.class.to_s =~ /Puppet::Pops::Types/
      to_resource_declaration(t)
    else
      t
    end
  end
  output
end

#handle_input(input_text) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/puppet-repl/cli.rb', line 93

def handle_input(input_text)
  input_text.split("\n").each do |input|
    begin
      output = ''
      case input
      when /^play|^classification|^facts|^vars|^functions|^classes|^resources|^krt|^environment|^reset|^help/
        args = input.split(' ')
        command = args.shift.to_sym
        if self.respond_to?(command)
          output = self.send(command, args)
        end
        return out_buffer.puts output
      when /exit/
        exit 0
      when /^:set/
        output = handle_set(input)
      when '_'
        output = " => #{@last_item}"
      else
        result = puppet_eval(input)
        @last_item = result
        output = normalize_output(result)
        if output.nil?
          output = ""
        else
          output = output.ai
        end
      end
    rescue LoadError => e
      output = e.message.fatal
    rescue Errno::ETIMEDOUT => e
      output = e.message.fatal
    rescue ArgumentError => e
      output = e.message.fatal
    rescue Puppet::ResourceError => e
      output = e.message.fatal
    rescue Puppet::ParseErrorWithIssue => e
      output = e.message.fatal
    rescue PuppetRepl::Exception::FatalError => e
      output = e.message.fatal
      out_buffer.puts output
      exit 1
    rescue PuppetRepl::Exception::Error => e
      output = e.message.fatal
    end
    out_buffer.print " => "
    out_buffer.puts output
  end
end

#key_wordsObject

returns a cached list of key words



33
34
35
36
37
38
39
40
41
42
# File 'lib/puppet-repl/cli.rb', line 33

def key_words
  # because dollar signs don't work we can't display a $ sign in the keyword
  # list so its not explicitly clear what the keyword
  variables = scope.to_hash.keys
  # prepend a :: to topscope variables
  scoped_vars = variables.map { |k,v| scope.compiler.topscope.exist?(k) ? "$::#{k}" : "$#{k}" }
  # append a () to functions so we know they are functions
  funcs = function_map.keys.map { |k| "#{k.split('::').last}()"}
  (scoped_vars + funcs + static_responder_list).uniq.sort
end

#multiline_input?(e) ⇒ Boolean

tries to determine if the input is going to be a multiline input by reading the parser error message

Returns:

  • (Boolean)


158
159
160
161
162
163
164
165
# File 'lib/puppet-repl/cli.rb', line 158

def multiline_input?(e)
  case e.message
  when /Syntax error at end of file/i
    true
  else
    false
  end
end

#normalize_output(result) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/puppet-repl/cli.rb', line 80

def normalize_output(result)
  if result.instance_of?(Array)
    output = expand_resource_type(result)
    if output.count == 1
      return output.first
    end
    return output
  elsif result.class.to_s =~ /Puppet::Pops::Types/
    return to_resource_declaration(result)
  end
  result
end

#puppet_eval(input) ⇒ Object



44
45
46
# File 'lib/puppet-repl/cli.rb', line 44

def puppet_eval(input)
  parser.evaluate_string(scope, input)
end

#read_loopObject

reads input from stdin, since readline requires a tty we cannot read from other sources as readline requires a file object we parse the string after each input to determine if the input is a multiline_input entry. If it is multiline we run through the loop again and concatenate the input



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/puppet-repl/cli.rb', line 172

def read_loop
  line_number = 1
  full_buffer = ''
  while buf = Readline.readline("#{line_number}:>> ", true)
    begin
      line_number = line_number.next
      full_buffer += buf
      parser.parse_string(full_buffer)
    rescue Puppet::ParseErrorWithIssue => e
      if multiline_input?(e)
        out_buffer.print '  '
        next
      end
    end
    handle_input(full_buffer)
    full_buffer = ''
  end
end

#to_resource_declaration(type) ⇒ Object

looks up the type in the catalog by using the type and title and returns the resource in ral format



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/puppet-repl/cli.rb', line 50

def to_resource_declaration(type)
  if type.respond_to?(:type_name) and type.respond_to?(:title)
    title = type.title
    type_name = type.type_name
  else
    # not all types have a type_name and title so we
    # output to a string and parse the results
    type_result = /(\w+)\['?(\w+)'?\]/.match(type.to_s)
    title = type_result[2]
    type_name = type_result[1]
  end
  res = scope.catalog.resource(type_name, title)
  if res
    return res.to_ral
  end
  # don't return anything or returns nil if item is not in the catalog
end