puppet-debugger 0.19.0 → 1.0.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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/.gitlab-ci.yml +10 -27
  3. data/.rubocop.yml +64 -232
  4. data/.rubocop_todo.yml +89 -147
  5. data/CHANGELOG.md +12 -1
  6. data/Gemfile +7 -5
  7. data/README.md +4 -5
  8. data/Rakefile +11 -12
  9. data/bin/pdb +1 -1
  10. data/lib/awesome_print/ext/awesome_puppet.rb +10 -8
  11. data/lib/plugins/puppet-debugger/input_responders/benchmark.rb +5 -4
  12. data/lib/plugins/puppet-debugger/input_responders/classes.rb +4 -1
  13. data/lib/plugins/puppet-debugger/input_responders/classification.rb +4 -2
  14. data/lib/plugins/puppet-debugger/input_responders/commands.rb +18 -18
  15. data/lib/plugins/puppet-debugger/input_responders/datatypes.rb +11 -5
  16. data/lib/plugins/puppet-debugger/input_responders/environment.rb +4 -2
  17. data/lib/plugins/puppet-debugger/input_responders/exit.rb +4 -2
  18. data/lib/plugins/puppet-debugger/input_responders/facterdb_filter.rb +4 -2
  19. data/lib/plugins/puppet-debugger/input_responders/facts.rb +4 -2
  20. data/lib/plugins/puppet-debugger/input_responders/functions.rb +34 -32
  21. data/lib/plugins/puppet-debugger/input_responders/help.rb +4 -2
  22. data/lib/plugins/puppet-debugger/input_responders/krt.rb +4 -2
  23. data/lib/plugins/puppet-debugger/input_responders/play.rb +22 -24
  24. data/lib/plugins/puppet-debugger/input_responders/reset.rb +5 -3
  25. data/lib/plugins/puppet-debugger/input_responders/resources.rb +5 -2
  26. data/lib/plugins/puppet-debugger/input_responders/set.rb +34 -32
  27. data/lib/plugins/puppet-debugger/input_responders/stacktrace.rb +23 -0
  28. data/lib/plugins/puppet-debugger/input_responders/types.rb +6 -2
  29. data/lib/plugins/puppet-debugger/input_responders/vars.rb +6 -5
  30. data/lib/plugins/puppet-debugger/input_responders/whereami.rb +5 -3
  31. data/lib/puppet-debugger/cli.rb +118 -91
  32. data/lib/puppet-debugger/code/code_file.rb +13 -14
  33. data/lib/puppet-debugger/code/code_range.rb +5 -3
  34. data/lib/puppet-debugger/code/loc.rb +1 -1
  35. data/lib/puppet-debugger/debugger_code.rb +2 -0
  36. data/lib/puppet-debugger/hooks.rb +15 -16
  37. data/lib/puppet-debugger/input_responder_plugin.rb +54 -52
  38. data/lib/puppet-debugger/monkey_patches.rb +4 -1
  39. data/lib/puppet-debugger/plugin_test_helper.rb +9 -8
  40. data/lib/puppet-debugger/support.rb +27 -17
  41. data/lib/puppet-debugger/support/environment.rb +4 -4
  42. data/lib/puppet-debugger/support/errors.rb +25 -27
  43. data/lib/puppet-debugger/support/facts.rb +5 -5
  44. data/lib/puppet-debugger/support/node.rb +4 -5
  45. data/lib/puppet-debugger/support/scope.rb +19 -17
  46. data/lib/puppet-debugger/trollop.rb +38 -31
  47. data/lib/puppet-debugger/version.rb +1 -1
  48. data/lib/puppet/application/debugger.rb +141 -135
  49. data/output.json +1 -0
  50. data/puppet-debugger.gemspec +17 -16
  51. data/spec/awesome_print/ext/awesome_puppet_spec.rb +30 -30
  52. data/spec/fixtures/sample_start_debugger.pp +3 -2
  53. data/spec/hooks_spec.rb +33 -35
  54. data/spec/input_responder_plugin_spec.rb +7 -6
  55. data/spec/input_responders/benchmark_spec.rb +3 -1
  56. data/spec/input_responders/classes_spec.rb +12 -10
  57. data/spec/input_responders/classification_spec.rb +4 -2
  58. data/spec/input_responders/commands_spec.rb +2 -0
  59. data/spec/input_responders/datatypes_spec.rb +4 -3
  60. data/spec/input_responders/environment_spec.rb +2 -0
  61. data/spec/input_responders/exit_spec.rb +9 -11
  62. data/spec/input_responders/facterdb_filter_spec.rb +2 -0
  63. data/spec/input_responders/facts_spec.rb +2 -0
  64. data/spec/input_responders/functions_spec.rb +30 -28
  65. data/spec/input_responders/help_spec.rb +4 -2
  66. data/spec/input_responders/krt_spec.rb +3 -1
  67. data/spec/input_responders/play_spec.rb +10 -20
  68. data/spec/input_responders/reset_spec.rb +2 -0
  69. data/spec/input_responders/resources_spec.rb +3 -1
  70. data/spec/input_responders/set_spec.rb +3 -1
  71. data/spec/input_responders/stacktrace_spec.rb +15 -0
  72. data/spec/input_responders/types_spec.rb +2 -0
  73. data/spec/input_responders/vars_spec.rb +4 -4
  74. data/spec/input_responders/whereami_spec.rb +2 -0
  75. data/spec/pdb_spec.rb +0 -9
  76. data/spec/puppet/application/debugger_spec.rb +18 -19
  77. data/spec/puppet_debugger_spec.rb +81 -84
  78. data/spec/remote_node_spec.rb +1 -5
  79. data/spec/spec_helper.rb +22 -18
  80. data/spec/support_spec.rb +3 -5
  81. data/test_matrix.rb +1 -1
  82. metadata +48 -31
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puppet-debugger/input_responder_plugin'
2
4
  module PuppetDebugger
3
5
  module InputResponders
4
6
  class Help < InputResponderPlugin
5
- COMMAND_WORDS = %w(help)
7
+ COMMAND_WORDS = %w[help].freeze
6
8
  SUMMARY = 'Show the help screen with version information.'
7
9
  COMMAND_GROUP = :help
8
10
 
9
- def run(args = [])
11
+ def run(_args = [])
10
12
  PuppetDebugger::Cli.print_repl_desc
11
13
  end
12
14
  end
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puppet-debugger/input_responder_plugin'
2
4
  module PuppetDebugger
3
5
  module InputResponders
4
6
  class Krt < InputResponderPlugin
5
- COMMAND_WORDS = %w(krt)
7
+ COMMAND_WORDS = %w[krt].freeze
6
8
  SUMMARY = 'List all the known resource types.'
7
9
  COMMAND_GROUP = :scope
8
10
 
9
- def run(args = [])
11
+ def run(_args = [])
10
12
  debugger.known_resource_types.ai(sort_keys: true, indent: -1)
11
13
  end
12
14
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puppet-debugger/input_responder_plugin'
2
4
  module PuppetDebugger
3
5
  module InputResponders
4
6
  class Play < InputResponderPlugin
5
- COMMAND_WORDS = %w(play)
7
+ COMMAND_WORDS = %w[play].freeze
6
8
  SUMMARY = 'Playback a file or URL as input.'
7
9
  COMMAND_GROUP = :editing
8
10
 
@@ -20,7 +22,7 @@ module PuppetDebugger
20
22
  elsif File.exist? config[:play]
21
23
  play_back_string(File.read(config[:play]))
22
24
  else config[:play]
23
- debugger.out_buffer.puts "puppet-debugger can't play #{config[:play]}'"
25
+ debugger.out_buffer.puts "puppet-debugger can't play #{config[:play]}'"
24
26
  end
25
27
  end
26
28
  end
@@ -29,29 +31,29 @@ module PuppetDebugger
29
31
  require 'uri'
30
32
  url_data = URI(url)
31
33
  case url_data.host
32
- when /^gist\.github*/
33
- url = url += '.txt' unless url_data.path =~ /raw/
34
- url
35
- when /^github.com/
36
- url.gsub('blob', 'raw') if url_data.path =~ /blob/
37
- when /^gist.github.com/
38
- url = url += '.txt' unless url_data.path =~ /raw/
34
+ when /^gist\.github*/
35
+ url = url += '.txt' unless url_data.path =~ /raw/
36
+ url
37
+ when /^github.com/
38
+ url.gsub('blob', 'raw') if url_data.path =~ /blob/
39
+ when /^gist.github.com/
40
+ url = url += '.txt' unless url_data.path =~ /raw/
41
+ url
42
+ when /^gitlab.com/
43
+ if url_data.path =~ /snippets/
44
+ url += '/raw' unless url_data.path =~ /raw/
39
45
  url
40
- when /^gitlab.com/
41
- if url_data.path =~ /snippets/
42
- url += '/raw' unless url_data.path =~ /raw/
43
- url
44
- else
45
- url.gsub('blob', 'raw')
46
- end
47
46
  else
48
- url
47
+ url.gsub('blob', 'raw')
48
+ end
49
+ else
50
+ url
49
51
  end
50
52
  end
51
53
 
52
54
  # opens the url and reads the data
53
55
  def fetch_url_data(url)
54
- open(url).read
56
+ URI.open(url).read # open(url).read
55
57
  end
56
58
 
57
59
  def play_back_url(url)
@@ -72,12 +74,8 @@ module PuppetDebugger
72
74
  begin
73
75
  full_buffer += buf
74
76
  # unless this is puppet code, otherwise skip repl keywords
75
- if PuppetDebugger::InputResponders::Commands.command_list_regex.match(buf)
76
- debugger.out_buffer.write('>> ')
77
- else
78
- debugger.parser.parse_string(full_buffer)
79
- debugger.out_buffer.write('>> ')
80
- end
77
+ debugger.parser.parse_string(full_buffer) unless PuppetDebugger::InputResponders::Commands.command_list_regex.match(buf)
78
+ debugger.out_buffer.write('>> ')
81
79
  rescue Puppet::ParseErrorWithIssue => e
82
80
  if debugger.multiline_input?(e)
83
81
  full_buffer += "\n"
@@ -1,19 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puppet-debugger/input_responder_plugin'
2
4
  module PuppetDebugger
3
5
  module InputResponders
4
6
  class Reset < InputResponderPlugin
5
- COMMAND_WORDS = %w(reset)
7
+ COMMAND_WORDS = %w[reset].freeze
6
8
  SUMMARY = 'Reset the debugger to a clean state.'
7
9
  COMMAND_GROUP = :context
8
10
 
9
- def run(args = [])
11
+ def run(_args = [])
10
12
  debugger.set_scope(nil)
11
13
  debugger.set_remote_node_name(nil)
12
14
  debugger.set_node(nil)
13
15
  debugger.set_facts(nil)
14
16
  debugger.set_environment(nil)
15
17
  debugger.set_compiler(nil)
16
- #debugger.handle_input(":set loglevel #{debugger.log_level}")
18
+ # debugger.handle_input(":set loglevel #{debugger.log_level}")
17
19
  nil
18
20
  end
19
21
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puppet-debugger/input_responder_plugin'
2
4
  module PuppetDebugger
3
5
  module InputResponders
4
6
  class Resources < InputResponderPlugin
5
- COMMAND_WORDS = %w(resources)
7
+ COMMAND_WORDS = %w[resources].freeze
6
8
  SUMMARY = 'List all the resources current in the catalog.'
7
9
  COMMAND_GROUP = :scope
8
10
 
@@ -13,11 +15,12 @@ module PuppetDebugger
13
15
  res.to_s.gsub(/\[/, "['").gsub(/\]/, "']") # ensure the title has quotes
14
16
  end
15
17
  output = "Resources not shown in any specific order\n".warning
16
- output += modified.ai
18
+ output + modified.ai
17
19
  end
18
20
 
19
21
  def find_resources(resources, filter = [])
20
22
  return resources if filter.nil? || filter.empty?
23
+
21
24
  filter_string = filter.join(' ').downcase
22
25
  resources.find_all do |resource|
23
26
  resource.name.to_s.downcase.include?(filter_string) || resource.type.to_s.downcase.include?(filter_string)
@@ -1,28 +1,30 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puppet-debugger/input_responder_plugin'
2
4
  module PuppetDebugger
3
5
  module InputResponders
4
6
  class Set < InputResponderPlugin
5
- COMMAND_WORDS = %w(set :set)
7
+ COMMAND_WORDS = %w[set :set].freeze
6
8
  SUMMARY = 'Set the a puppet debugger config'
7
9
  COMMAND_GROUP = :scope
8
- KEYWORDS = %w(node loglevel)
9
- LOGLEVELS = %w(debug info)
10
+ KEYWORDS = %w[node loglevel].freeze
11
+ LOGLEVELS = %w[debug info].freeze
10
12
 
11
13
  def self.command_completion(buffer_words)
12
14
  next_word = buffer_words.shift
13
15
  case next_word
14
- when 'loglevel'
15
- if buffer_words.count > 0
16
- LOGLEVELS.grep(/^#{Regexp.escape(buffer_words.first)}/)
17
- else
18
- LOGLEVELS
19
- end
20
- when 'debug', 'info','node'
21
- []
22
- when nil
23
- %w(node loglevel)
16
+ when 'loglevel'
17
+ if buffer_words.count.positive?
18
+ LOGLEVELS.grep(/^#{Regexp.escape(buffer_words.first)}/)
24
19
  else
25
- KEYWORDS.grep(/^#{Regexp.escape(next_word)}/)
20
+ LOGLEVELS
21
+ end
22
+ when 'debug', 'info', 'node'
23
+ []
24
+ when nil
25
+ %w[node loglevel]
26
+ else
27
+ KEYWORDS.grep(/^#{Regexp.escape(next_word)}/)
26
28
  end
27
29
  end
28
30
 
@@ -37,24 +39,24 @@ module PuppetDebugger
37
39
  # args = input.split(' ')
38
40
  # args.shift # throw away the set
39
41
  case input.shift
40
- when /node/
41
- if name = input.shift
42
- output = "Resetting to use node #{name}"
43
- debugger.set_scope(nil)
44
- debugger.set_node(nil)
45
- debugger.set_facts(nil)
46
- debugger.set_environment(nil)
47
- debugger.set_compiler(nil)
48
- set_log_level(debugger.log_level)
49
- debugger.set_remote_node_name(name)
50
- else
51
- debugger.out_buffer.puts 'Must supply a valid node name'
52
- end
53
- when /loglevel/
54
- if level = input.shift
55
- set_log_level(level)
56
- output = "loglevel #{Puppet::Util::Log.level} is set"
57
- end
42
+ when /node/
43
+ if name = input.shift
44
+ output = "Resetting to use node #{name}"
45
+ debugger.set_scope(nil)
46
+ debugger.set_node(nil)
47
+ debugger.set_facts(nil)
48
+ debugger.set_environment(nil)
49
+ debugger.set_compiler(nil)
50
+ set_log_level(debugger.log_level)
51
+ debugger.set_remote_node_name(name)
52
+ else
53
+ debugger.out_buffer.puts 'Must supply a valid node name'
54
+ end
55
+ when /loglevel/
56
+ if level = input.shift
57
+ set_log_level(level)
58
+ output = "loglevel #{Puppet::Util::Log.level} is set"
59
+ end
58
60
  end
59
61
  output
60
62
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'puppet-debugger/input_responder_plugin'
4
+ module PuppetDebugger
5
+ module InputResponders
6
+ class Stacktrace < InputResponderPlugin
7
+ COMMAND_WORDS = %w[stacktrace].freeze
8
+ SUMMARY = 'Show the stacktrace for how we got here'
9
+ COMMAND_GROUP = :tools
10
+
11
+ # @return [Array]- returns a array of pp files that are involved in the stacktrace
12
+ def run(_args = [])
13
+ s = stacktrace
14
+ s.empty? ? 'stacktrace not available'.warning : s.ai
15
+ end
16
+
17
+ # @return [Array] - an array of files
18
+ def stacktrace
19
+ Puppet::Pops::PuppetStack.stacktrace.find_all { |line| !line.include?('unknown') }
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,14 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puppet-debugger/input_responder_plugin'
2
4
  module PuppetDebugger
3
5
  module InputResponders
4
6
  class Types < InputResponderPlugin
5
- COMMAND_WORDS = %w(types)
7
+ COMMAND_WORDS = %w[types].freeze
6
8
  SUMMARY = 'List all the types available in the environment.'
7
9
  COMMAND_GROUP = :environment
8
10
 
9
11
  # @return - returns a list of types available to the environment
10
12
  # if a error occurs we we run the types function again
11
- def run(args = [])
13
+ def run(_args = [])
12
14
  types
13
15
  end
14
16
 
@@ -19,6 +21,7 @@ module PuppetDebugger
19
21
  Puppet::Type.loadall
20
22
  Puppet::Type.eachtype do |t|
21
23
  next if t.name == :component
24
+
22
25
  loaded_types << t.name.to_s
23
26
  end
24
27
  loaded_types.ai
@@ -27,6 +30,7 @@ module PuppetDebugger
27
30
  Puppet.info(e.message)
28
31
  # prevent more than two calls and recursive loop
29
32
  return if caller_locations(1, 10).find_all { |f| f.label == 'types' }.count > 2
33
+
30
34
  types
31
35
  end
32
36
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puppet-debugger/input_responder_plugin'
2
4
  module PuppetDebugger
3
5
  module InputResponders
4
6
  class Vars < InputResponderPlugin
5
- COMMAND_WORDS = %w(vars ls)
7
+ COMMAND_WORDS = %w[vars ls].freeze
6
8
  SUMMARY = 'List all the variables in the current scopes.'
7
9
  COMMAND_GROUP = :scope
8
10
 
@@ -16,11 +18,11 @@ module PuppetDebugger
16
18
  variables = debugger.scope.to_hash.delete_if { |key, _value| debugger.node.facts.values.key?(key) }
17
19
  variables['facts'] = 'removed by the puppet-debugger' if variables.key?('facts')
18
20
  output = 'Facts were removed for easier viewing'.ai + "\n"
19
- output += variables.ai(sort_keys: true, indent: -1)
21
+ output + variables.ai(sort_keys: true, indent: -1)
20
22
  end
21
23
 
22
24
  def resource_parameters(resources, filter = [])
23
- find_resources(resources, filter).each_with_object({}) do | resource, acc|
25
+ find_resources(resources, filter).each_with_object({}) do |resource, acc|
24
26
  name = "#{resource.type}[#{resource.name}]"
25
27
  acc[name] = parameters_to_h(resource)
26
28
  acc
@@ -28,7 +30,7 @@ module PuppetDebugger
28
30
  end
29
31
 
30
32
  def parameters_to_h(resource)
31
- resource.parameters.each_with_object({}) do | param, params |
33
+ resource.parameters.each_with_object({}) do |param, params|
32
34
  name = param.first.to_s
33
35
  params[name] = param.last.respond_to?(:value) ? param.last.value : param.last
34
36
  params
@@ -41,7 +43,6 @@ module PuppetDebugger
41
43
  resource.name.to_s.downcase.include?(filter_string) || resource.type.to_s.downcase.include?(filter_string)
42
44
  end
43
45
  end
44
-
45
46
  end
46
47
  end
47
48
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puppet-debugger/input_responder_plugin'
2
4
  module PuppetDebugger
3
5
  module InputResponders
4
6
  class Whereami < InputResponderPlugin
5
- COMMAND_WORDS = %w(whereami)
7
+ COMMAND_WORDS = %w[whereami].freeze
6
8
  SUMMARY = 'Show code surrounding the current context.'
7
9
  COMMAND_GROUP = :context
8
10
 
@@ -21,8 +23,8 @@ module PuppetDebugger
21
23
  else
22
24
  code = DebuggerCode.from_file(file, :puppet)
23
25
  end
24
- return code.with_marker(line_num).around(line_num, num_lines)
25
- .with_line_numbers.with_indentation(5).with_file_reference.to_s
26
+ code.with_marker(line_num).around(line_num, num_lines)
27
+ .with_line_numbers.with_indentation(5).with_file_reference.to_s
26
28
  end
27
29
  end
28
30
 
@@ -1,31 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "puppet"
4
- require "readline"
5
- require "json"
6
- require "puppet-debugger/support"
7
- require "pluginator"
8
- require "puppet-debugger/hooks"
9
- require "forwardable"
10
- require "plugins/puppet-debugger/input_responders/functions"
11
- require "plugins/puppet-debugger/input_responders/datatypes"
12
-
3
+ require 'puppet'
4
+ require 'readline'
5
+ require 'json'
6
+ require 'puppet-debugger/support'
7
+ require 'pluginator'
8
+ require 'puppet-debugger/hooks'
9
+ require 'forwardable'
10
+ require 'plugins/puppet-debugger/input_responders/functions'
11
+ require 'plugins/puppet-debugger/input_responders/datatypes'
12
+ require 'tty-pager'
13
13
  module PuppetDebugger
14
14
  class Cli
15
15
  include PuppetDebugger::Support
16
16
  extend Forwardable
17
17
  attr_accessor :settings, :log_level, :in_buffer, :out_buffer, :html_mode, :extra_prompt, :bench
18
- attr_reader :source_file, :source_line_num, :hooks
18
+ attr_reader :source_file, :source_line_num, :hooks, :options
19
19
  def_delegators :hooks, :exec_hook, :add_hook, :delete_hook
20
-
20
+ OUT_SYMBOL = ' => '
21
21
  def initialize(options = {})
22
22
  do_initialize if Puppet[:codedir].nil?
23
23
  Puppet.settings[:name] = :debugger
24
+ @options = options
24
25
  Puppet[:static_catalogs] = false unless Puppet.settings[:static_catalogs].nil?
25
26
  set_remote_node_name(options[:node_name])
26
27
  initialize_from_scope(options[:scope])
27
28
  set_catalog(options[:catalog])
28
- @log_level = "notice"
29
+ @log_level = 'notice'
29
30
  @out_buffer = options[:out_buffer] || $stdout
30
31
  @html_mode = options[:html_mode] || false
31
32
  @source_file = options[:source_file] || nil
@@ -33,13 +34,13 @@ module PuppetDebugger
33
34
  @in_buffer = options[:in_buffer] || $stdin
34
35
  Readline.input = @in_buffer
35
36
  Readline.output = @out_buffer
36
- Readline.completion_append_character = ""
37
- Readline.basic_word_break_characters = " "
37
+ Readline.completion_append_character = ''
38
+ Readline.basic_word_break_characters = ' '
38
39
  Readline.completion_proc = command_completion
39
40
  AwesomePrint.defaults = {
40
41
  html: @html_mode,
41
42
  sort_keys: true,
42
- indent: 2,
43
+ indent: 2
43
44
  }
44
45
  end
45
46
 
@@ -50,11 +51,12 @@ module PuppetDebugger
50
51
  proc do |input|
51
52
  words = Readline.line_buffer.split(Readline.basic_word_break_characters)
52
53
  next key_words.grep(/^#{Regexp.escape(input)}/) if words.empty?
54
+
53
55
  first_word = words.shift
54
56
  plugins = PuppetDebugger::InputResponders::Commands.plugins.find_all do |p|
55
57
  p::COMMAND_WORDS.find { |word| word.start_with?(first_word) }
56
58
  end
57
- if plugins.count == 1 and /\A#{first_word}\s/.match(Readline.line_buffer)
59
+ if (plugins.count == 1) && /\A#{first_word}\s/.match(Readline.line_buffer)
58
60
  plugins.first.command_completion(words)
59
61
  else
60
62
  key_words.grep(/^#{Regexp.escape(input)}/)
@@ -76,7 +78,8 @@ module PuppetDebugger
76
78
  PuppetDebugger::InputResponders::Functions.instance.debugger = self
77
79
  funcs = PuppetDebugger::InputResponders::Functions.instance.func_list
78
80
  PuppetDebugger::InputResponders::Datatypes.instance.debugger = self
79
- (scoped_vars + funcs + static_responder_list + PuppetDebugger::InputResponders::Datatypes.instance.all_data_types).uniq.sort
81
+ (scoped_vars + funcs + static_responder_list +
82
+ PuppetDebugger::InputResponders::Datatypes.instance.all_data_types).uniq.sort
80
83
  end
81
84
 
82
85
  # looks up the type in the catalog by using the type and title
@@ -116,87 +119,107 @@ module PuppetDebugger
116
119
  # if the only output is a resource then return it
117
120
  # otherwise it is multiple items or an actually array
118
121
  return output.first if output.count == 1
122
+
119
123
  return output
120
124
  end
121
125
  result
122
126
  end
123
127
 
124
128
  def responder_list
125
- plugins = Pluginator.find(PuppetDebugger)
129
+ Pluginator.find(PuppetDebugger)
130
+ end
131
+
132
+ # @return [TTY::Pager] the pager object, disable if CI or testing is present
133
+ def pager
134
+ @pager ||= TTY::Pager.new(output: out_buffer, enabled: pager_enabled?)
135
+ end
136
+
137
+ def pager_enabled?
138
+ ENV['CI'].nil?
139
+ end
140
+
141
+ # @param output [String] - the content to output
142
+ # @summary outputs the output to the output buffer
143
+ # uses the pager if the screen height is less than the height of the
144
+ # output content
145
+ # Disabled if CI or testing is being done
146
+ def handle_output(output)
147
+ return if output.nil?
148
+ if pager_enabled? && output.lines.count >= TTY::Screen.height
149
+ output << "\n"
150
+ pager.page(output)
151
+ else
152
+ out_buffer.puts(output) unless output.empty?
153
+ end
126
154
  end
127
155
 
128
156
  # this method handles all input and expects a string of text.
129
- #
157
+ # @param input [String] - the input content to parse or run
130
158
  def handle_input(input)
131
159
  raise ArgumentError unless input.instance_of?(String)
132
- begin
133
- output = ""
134
- case input.strip
135
- when PuppetDebugger::InputResponders::Commands.command_list_regex
136
- args = input.split(" ")
137
- command = args.shift
138
- plugin = PuppetDebugger::InputResponders::Commands.plugin_from_command(command)
139
- output = plugin.execute(args, self)
140
- return out_buffer.puts output
141
- when "_"
142
- output = " => #{@last_item}"
143
- else
144
- result = puppet_eval(input)
145
- @last_item = result
146
- output = normalize_output(result)
147
- output = output.nil? ? "" : output.ai
160
+
161
+ output =
162
+ begin
163
+ case input.strip
164
+ when PuppetDebugger::InputResponders::Commands.command_list_regex
165
+ args = input.split(' ')
166
+ command = args.shift
167
+ plugin = PuppetDebugger::InputResponders::Commands.plugin_from_command(command)
168
+ plugin.execute(args, self) || ''
169
+ when '_'
170
+ " => #{@last_item}"
171
+ else
172
+ result = puppet_eval(input)
173
+ @last_item = result
174
+ o = normalize_output(result)
175
+ o.nil? ? '' : o.ai
176
+ end
177
+ rescue PuppetDebugger::Exception::InvalidCommand => e
178
+ e.message.fatal
179
+ rescue LoadError => e
180
+ e.message.fatal
181
+ rescue Errno::ETIMEDOUT => e
182
+ e.message.fatal
183
+ rescue ArgumentError => e
184
+ e.message.fatal
185
+ rescue Puppet::ResourceError => e
186
+ e.message.fatal
187
+ rescue Puppet::Error => e
188
+ e.message.fatal
189
+ rescue Puppet::ParseErrorWithIssue => e
190
+ e.message.fatal
191
+ rescue PuppetDebugger::Exception::FatalError => e
192
+ handle_output(e.message.fatal)
193
+ exit 1 # this can sometimes causes tests to fail
194
+ rescue PuppetDebugger::Exception::Error => e
195
+ e.message.fatal
196
+ rescue ::RuntimeError => e
197
+ handle_output(e.message.fatal)
198
+ exit 1
148
199
  end
149
- rescue PuppetDebugger::Exception::InvalidCommand => e
150
- output = e.message.fatal
151
- rescue LoadError => e
152
- output = e.message.fatal
153
- rescue Errno::ETIMEDOUT => e
154
- output = e.message.fatal
155
- rescue ArgumentError => e
156
- output = e.message.fatal
157
- rescue Puppet::ResourceError => e
158
- output = e.message.fatal
159
- rescue Puppet::Error => e
160
- output = e.message.fatal
161
- rescue Puppet::ParseErrorWithIssue => e
162
- output = e.message.fatal
163
- rescue PuppetDebugger::Exception::FatalError => e
164
- output = e.message.fatal
165
- out_buffer.puts output
166
- exit 1 # this can sometimes causes tests to fail
167
- rescue PuppetDebugger::Exception::Error => e
168
- output = e.message.fatal
169
- rescue ::RuntimeError => e
170
- output = e.message.fatal
171
- out_buffer.puts output
172
- exit 1
173
- end
174
- unless output.empty?
175
- out_buffer.print " => "
176
- out_buffer.puts output unless output.empty?
177
- exec_hook :after_output, out_buffer, self, self
178
- end
200
+ output = OUT_SYMBOL + output unless output.empty?
201
+ handle_output(output)
202
+ exec_hook :after_output, out_buffer, self, self
179
203
  end
180
204
 
181
205
  def self.print_repl_desc
182
- output = <<-EOT
183
- Ruby Version: #{RUBY_VERSION}
184
- Puppet Version: #{Puppet.version}
185
- Puppet Debugger Version: #{PuppetDebugger::VERSION}
186
- Created by: NWOps <corey@nwops.io>
187
- Type "commands" for a list of debugger commands
188
- or "help" to show the help screen.
206
+ <<~OUT
207
+ Ruby Version: #{RUBY_VERSION}
208
+ Puppet Version: #{Puppet.version}
209
+ Puppet Debugger Version: #{PuppetDebugger::VERSION}
210
+ Created by: NWOps <corey@nwops.io>
211
+ Type "commands" for a list of debugger commands
212
+ or "help" to show the help screen.
189
213
 
190
214
 
191
- EOT
192
- output
215
+ OUT
193
216
  end
194
217
 
195
218
  # tries to determine if the input is going to be a multiline input
196
219
  # by reading the parser error message
197
220
  # @return [Boolean] - return true if this is a multiline input, false otherwise
198
- def multiline_input?(e)
199
- case e.message
221
+ def multiline_input?(data)
222
+ case data.message
200
223
  when /Syntax error at end of/i
201
224
  true
202
225
  else
@@ -211,7 +234,7 @@ or "help" to show the help screen.
211
234
  # input
212
235
  def read_loop
213
236
  line_number = 1
214
- full_buffer = ""
237
+ full_buffer = ''
215
238
  while buf = Readline.readline("#{line_number}:#{extra_prompt}>> ", true)
216
239
  begin
217
240
  full_buffer += buf
@@ -222,14 +245,14 @@ or "help" to show the help screen.
222
245
  parser.parse_string(full_buffer)
223
246
  rescue Puppet::ParseErrorWithIssue => e
224
247
  if multiline_input?(e)
225
- out_buffer.print " "
248
+ out_buffer.print ' '
226
249
  full_buffer += "\n"
227
250
  next
228
251
  end
229
252
  end
230
253
  end
231
254
  handle_input(full_buffer)
232
- full_buffer = ""
255
+ full_buffer = ''
233
256
  end
234
257
  end
235
258
  end
@@ -251,7 +274,7 @@ or "help" to show the help screen.
251
274
  repl_obj.out_buffer.puts print_repl_desc unless options[:quiet]
252
275
  repl_obj.handle_input(options[:content]) if options[:content]
253
276
  # TODO: make the output optional so we can have different output destinations
254
- repl_obj.handle_input("whereami") if options[:source_file] && options[:source_line]
277
+ repl_obj.handle_input('whereami') if options[:source_file] && options[:source_line]
255
278
  repl_obj.handle_input("play #{options[:play]}") if options[:play]
256
279
  repl_obj.read_loop unless options[:run_once]
257
280
  end
@@ -262,11 +285,15 @@ or "help" to show the help screen.
262
285
  # @param [Hash] puppet scope object
263
286
  def self.start(options = { scope: nil })
264
287
  opts = Trollop.options do
265
- opt :play, "Url or file to load from", required: false, type: String
266
- opt :run_once, "Evaluate and quit", required: false, default: false
267
- opt :node_name, "Remote Node to grab facts from", required: false, type: String
268
- opt :catalog, "Import a catalog file to inspect", required: false, type: String
269
- opt :quiet, "Do not display banner", required: false, default: false
288
+ opt :play, 'Url or file to load from', required: false, type: String
289
+ opt :run_once, 'Evaluate and quit', required: false, default: false
290
+ opt :node_name, 'Remote Node to grab facts from', required: false, type: String
291
+ opt :catalog, 'Import a catalog file to inspect', required: false, type: String
292
+ opt :quiet, 'Do not display banner', required: false, default: false
293
+ end
294
+ if !STDIN.tty? && !STDIN.closed?
295
+ options[:run_once] = true
296
+ options[:quiet] = true
270
297
  end
271
298
  options = opts.merge(options)
272
299
  options[:play] = options[:play].path if options[:play].respond_to?(:path)
@@ -274,14 +301,14 @@ or "help" to show the help screen.
274
301
  repl_obj.out_buffer.puts print_repl_desc unless options[:quiet]
275
302
  if options[:play]
276
303
  repl_obj.handle_input("play #{options[:play]}")
277
- elsif ARGF.filename != "-"
278
- # when the user supplied a file name without using the args (stdin)
279
- path = File.expand_path(ARGF.filename)
280
- repl_obj.handle_input("play #{path}")
281
- elsif (ARGF.filename == "-") && (!STDIN.tty? && !STDIN.closed?)
304
+ elsif (ARGF.filename == '-') && (!STDIN.tty? && !STDIN.closed?)
282
305
  # when the user supplied a file content using stdin, aka. cat,pipe,echo or redirection
283
306
  input = ARGF.read
284
307
  repl_obj.handle_input(input)
308
+ elsif ARGF.filename != '-'
309
+ # when the user supplied a file name without using the args (stdin)
310
+ path = File.expand_path(ARGF.filename)
311
+ repl_obj.handle_input("play #{path}")
285
312
  end
286
313
  # helper code to make tests exit the loop
287
314
  repl_obj.read_loop unless options[:run_once]