puppet-lint 0.4.0.pre1 → 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 (70) hide show
  1. data/.travis.yml +3 -4
  2. data/Gemfile +2 -5
  3. data/README.md +2 -149
  4. data/Rakefile +0 -5
  5. data/lib/puppet-lint.rb +74 -20
  6. data/lib/puppet-lint/bin.rb +20 -85
  7. data/lib/puppet-lint/checkplugin.rb +158 -12
  8. data/lib/puppet-lint/checks.rb +39 -222
  9. data/lib/puppet-lint/configuration.rb +12 -31
  10. data/lib/puppet-lint/data.rb +329 -0
  11. data/lib/puppet-lint/lexer.rb +37 -30
  12. data/lib/puppet-lint/lexer/token.rb +14 -16
  13. data/lib/puppet-lint/monkeypatches/string_prepend.rb +6 -0
  14. data/lib/puppet-lint/optparser.rb +105 -0
  15. data/lib/puppet-lint/plugins.rb +28 -9
  16. data/lib/puppet-lint/plugins/check_classes.rb +162 -238
  17. data/lib/puppet-lint/plugins/check_comments.rb +40 -25
  18. data/lib/puppet-lint/plugins/check_conditionals.rb +16 -20
  19. data/lib/puppet-lint/plugins/check_documentation.rb +14 -20
  20. data/lib/puppet-lint/plugins/check_nodes.rb +23 -0
  21. data/lib/puppet-lint/plugins/check_resources.rb +127 -141
  22. data/lib/puppet-lint/plugins/check_strings.rb +133 -107
  23. data/lib/puppet-lint/plugins/check_variables.rb +11 -11
  24. data/lib/puppet-lint/plugins/check_whitespace.rb +86 -92
  25. data/lib/puppet-lint/tasks/puppet-lint.rb +17 -1
  26. data/lib/puppet-lint/version.rb +1 -1
  27. data/puppet-lint.gemspec +4 -2
  28. data/spec/fixtures/test/manifests/ignore.pp +1 -0
  29. data/spec/fixtures/test/manifests/ignore_reason.pp +1 -0
  30. data/spec/puppet-lint/bin_spec.rb +104 -84
  31. data/spec/puppet-lint/configuration_spec.rb +19 -19
  32. data/spec/puppet-lint/ignore_overrides_spec.rb +97 -0
  33. data/spec/puppet-lint/lexer/token_spec.rb +9 -9
  34. data/spec/puppet-lint/lexer_spec.rb +352 -325
  35. data/spec/puppet-lint/plugins/check_classes/autoloader_layout_spec.rb +77 -23
  36. data/spec/puppet-lint/plugins/check_classes/class_inherits_from_params_class_spec.rb +14 -12
  37. data/spec/puppet-lint/plugins/check_classes/inherits_across_namespaces_spec.rb +18 -14
  38. data/spec/puppet-lint/plugins/check_classes/names_containing_dash_spec.rb +30 -30
  39. data/spec/puppet-lint/plugins/check_classes/nested_classes_or_defines_spec.rb +31 -26
  40. data/spec/puppet-lint/plugins/check_classes/parameter_order_spec.rb +34 -28
  41. data/spec/puppet-lint/plugins/check_classes/right_to_left_relationship_spec.rb +14 -12
  42. data/spec/puppet-lint/plugins/check_classes/variable_scope_spec.rb +74 -30
  43. data/spec/puppet-lint/plugins/check_comments/slash_comments_spec.rb +27 -20
  44. data/spec/puppet-lint/plugins/check_comments/star_comments_spec.rb +78 -13
  45. data/spec/puppet-lint/plugins/check_conditionals/case_without_default_spec.rb +17 -12
  46. data/spec/puppet-lint/plugins/check_conditionals/selector_inside_resource_spec.rb +13 -10
  47. data/spec/puppet-lint/plugins/check_documentation/documentation_spec.rb +21 -16
  48. data/spec/puppet-lint/plugins/check_nodes/unquoted_node_name_spec.rb +69 -0
  49. data/spec/puppet-lint/plugins/check_resources/duplicate_params_spec.rb +42 -38
  50. data/spec/puppet-lint/plugins/check_resources/ensure_first_param_spec.rb +22 -10
  51. data/spec/puppet-lint/plugins/check_resources/ensure_not_symlink_target_spec.rb +81 -18
  52. data/spec/puppet-lint/plugins/check_resources/file_mode_spec.rb +69 -112
  53. data/spec/puppet-lint/plugins/check_resources/unquoted_file_mode_spec.rb +27 -20
  54. data/spec/puppet-lint/plugins/check_resources/unquoted_resource_title_spec.rb +177 -171
  55. data/spec/puppet-lint/plugins/check_strings/double_quoted_strings_spec.rb +165 -88
  56. data/spec/puppet-lint/plugins/check_strings/only_variable_string_spec.rb +97 -22
  57. data/spec/puppet-lint/plugins/check_strings/puppet_url_without_modules_spec.rb +25 -0
  58. data/spec/puppet-lint/plugins/check_strings/quoted_booleans_spec.rb +97 -111
  59. data/spec/puppet-lint/plugins/check_strings/single_quote_string_with_variables_spec.rb +10 -9
  60. data/spec/puppet-lint/plugins/check_strings/variables_not_enclosed_spec.rb +53 -53
  61. data/spec/puppet-lint/plugins/check_variables/variable_contains_dash_spec.rb +26 -14
  62. data/spec/puppet-lint/plugins/check_whitespace/2sp_soft_tabs_spec.rb +10 -9
  63. data/spec/puppet-lint/plugins/check_whitespace/80chars_spec.rb +31 -15
  64. data/spec/puppet-lint/plugins/check_whitespace/arrow_alignment_spec.rb +340 -322
  65. data/spec/puppet-lint/plugins/check_whitespace/hard_tabs_spec.rb +30 -23
  66. data/spec/puppet-lint/plugins/check_whitespace/trailing_whitespace_spec.rb +42 -41
  67. data/spec/puppet-lint_spec.rb +3 -3
  68. data/spec/spec_helper.rb +109 -116
  69. metadata +109 -50
  70. data/spec/puppet-lint/plugins/check_classes/class_parameter_defaults_spec.rb +0 -60
@@ -1,35 +1,37 @@
1
1
  class PuppetLint
2
2
  class Lexer
3
+ # Public: Stores a fragment of the manifest and the information about its
4
+ # location in the manifest.
3
5
  class Token
4
- # Internal: Returns the Symbol type of the Token.
6
+ # Public: Returns the Symbol type of the Token.
5
7
  attr_accessor :type
6
8
 
7
- # Internal: Returns the String value of the Token.
9
+ # Public: Returns the String value of the Token.
8
10
  attr_accessor :value
9
11
 
10
- # Internal: Returns the Integer line number of the manifest text where
12
+ # Public: Returns the Integer line number of the manifest text where
11
13
  # the Token can be found.
12
14
  attr_reader :line
13
15
 
14
- # Internal: Returns the Integer column number of the line of the manifest
16
+ # Public: Returns the Integer column number of the line of the manifest
15
17
  # text where the Token can be found.
16
18
  attr_reader :column
17
19
 
18
- # Internal: Gets/sets the next token in the manifest.
20
+ # Public: Gets/sets the next token in the manifest.
19
21
  attr_accessor :next_token
20
22
 
21
- # Internal: Gets/sets the previous token in the manifest.
23
+ # Public: Gets/sets the previous token in the manifest.
22
24
  attr_accessor :prev_token
23
25
 
24
- # Internal: Gets/sets the next code token (skips whitespace, comments,
26
+ # Public: Gets/sets the next code token (skips whitespace, comments,
25
27
  # etc) in the manifest.
26
28
  attr_accessor :next_code_token
27
29
 
28
- # Internal: Gets/sets the previous code tokne (skips whitespace,
30
+ # Public: Gets/sets the previous code tokne (skips whitespace,
29
31
  # comments, etc) in the manifest.
30
32
  attr_accessor :prev_code_token
31
33
 
32
- # Internal: Initialise a new Token object.
34
+ # Public: Initialise a new Token object.
33
35
  #
34
36
  # type - An upper case Symbol describing the type of Token.
35
37
  # value - The String value of the Token.
@@ -50,7 +52,7 @@ class PuppetLint
50
52
  @prev_code_token = nil
51
53
  end
52
54
 
53
- # Internal: Produce a human friendly description of the Token when
55
+ # Public: Produce a human friendly description of the Token when
54
56
  # inspected.
55
57
  #
56
58
  # Returns a String describing the Token.
@@ -58,7 +60,7 @@ class PuppetLint
58
60
  "<Token #{@type.inspect} (#{@value}) @#{@line}:#{@column}>"
59
61
  end
60
62
 
61
- # Internal: Produce a Puppet DSL representation of a Token.
63
+ # Public: Produce a Puppet DSL representation of a Token.
62
64
  #
63
65
  # Returns a Puppet DSL String.
64
66
  def to_manifest
@@ -82,11 +84,7 @@ class PuppetLint
82
84
  when :NEWLINE
83
85
  "\n"
84
86
  when :COMMENT
85
- if @value.start_with?('#') || @value.empty?
86
- "##{@value}"
87
- else
88
- "# #{@value}"
89
- end
87
+ "##{@value}"
90
88
  when :REGEX
91
89
  "/#{@value}/"
92
90
  else
@@ -1,5 +1,11 @@
1
1
  unless String.respond_to?('prepend')
2
+ # Internal: Monkey patching String.
2
3
  class String
4
+ # Internal: Prepends a String to self.
5
+ #
6
+ # lead - The String to prepend self with.
7
+ #
8
+ # Returns a String which is lead and self concatenated.
3
9
  def prepend(lead)
4
10
  self.replace "#{lead}#{self}"
5
11
  end
@@ -0,0 +1,105 @@
1
+ require 'optparse'
2
+
3
+ # Public: Contains the puppet-lint option parser so that it can be used easily
4
+ # in multiple places.
5
+ class PuppetLint::OptParser
6
+ HELP_TEXT = <<-EOF
7
+ puppet-lint
8
+
9
+ Basic Command Line Usage:
10
+ puppet-lint [OPTIONS] PATH
11
+
12
+ PATH The path to the Puppet manifest.
13
+
14
+ Option:
15
+ EOF
16
+
17
+ # Public: Initialise a new puppet-lint OptionParser.
18
+ #
19
+ # Returns an OptionParser object.
20
+ def self.build
21
+ OptionParser.new do |opts|
22
+ opts.banner = HELP_TEXT
23
+
24
+ opts.on('--version', 'Display the current version.') do
25
+ PuppetLint.configuration.display_version = true
26
+ end
27
+
28
+ opts.on('-c', '--config FILE', 'Load puppet-lint options from file.') do |file|
29
+ opts.load(file)
30
+ end
31
+
32
+ opts.on('--with-context', 'Show where in the manifest the problem is.') do
33
+ PuppetLint.configuration.with_context = true
34
+ end
35
+
36
+ opts.on('--with-filename', 'Display the filename before the warning.') do
37
+ PuppetLint.configuration.with_filename = true
38
+ end
39
+
40
+ opts.on('--fail-on-warnings', 'Return a non-zero exit status for warnings') do
41
+ PuppetLint.configuration.fail_on_warnings = true
42
+ end
43
+
44
+ opts.on('--error-level LEVEL', [:all, :warning, :error],
45
+ 'The level of error to return (warning, error or all).') do |el|
46
+ PuppetLint.configuration.error_level = el
47
+ end
48
+
49
+ opts.on('--show-ignored', 'Show problems that have been ignored by control comments') do
50
+ PuppetLint.configuration.show_ignored = true
51
+ end
52
+
53
+ opts.on('--relative', 'Compare module layout relative to the module root') do
54
+ PuppetLint.configuration.relative = true
55
+ end
56
+
57
+ opts.on('-l', '--load FILE', 'Load a file containing custom puppet-lint checks.') do |f|
58
+ load f
59
+ end
60
+
61
+ opts.on('-f', '--fix', 'Attempt to automatically fix errors') do
62
+ PuppetLint.configuration.fix = true
63
+ end
64
+
65
+ opts.on('--log-format FORMAT',
66
+ 'Change the log format.', 'Overrides --with-filename.',
67
+ 'The following placeholders can be used:',
68
+ '%{filename} - Filename without path.',
69
+ '%{path} - Path as provided to puppet-lint.',
70
+ '%{fullpath} - Expanded path to the file.',
71
+ '%{line} - Line number.',
72
+ '%{column} - Column number.',
73
+ '%{kind} - The kind of message (warning, error).',
74
+ '%{KIND} - Uppercase version of %{kind}.',
75
+ '%{check} - The name of the check.',
76
+ '%{message} - The message.'
77
+ ) do |format|
78
+ if format.include?('%{linenumber}')
79
+ $stderr.puts "DEPRECATION: Please use %{line} instead of %{linenumber}"
80
+ end
81
+ PuppetLint.configuration.log_format = format
82
+ end
83
+
84
+ opts.separator ''
85
+ opts.separator ' Checks:'
86
+
87
+ opts.on('--only-checks CHECKS', 'A comma separated list of checks that should be run') do |checks|
88
+ enable_checks = checks.split(',').map(&:to_sym)
89
+ (PuppetLint.configuration.checks - enable_checks).each do |check|
90
+ PuppetLint.configuration.send("disable_#{check}")
91
+ end
92
+ end
93
+
94
+ PuppetLint.configuration.checks.each do |check|
95
+ opts.on("--no-#{check}-check", "Skip the #{check} check.") do
96
+ PuppetLint.configuration.send("disable_#{check}")
97
+ end
98
+ end
99
+
100
+ opts.load('/etc/puppet-lint.rc')
101
+ opts.load(File.expand_path('~/.puppet-lint.rc')) if ENV['HOME']
102
+ opts.load('.puppet-lint.rc')
103
+ end
104
+ end
105
+ end
@@ -1,8 +1,13 @@
1
1
  require 'pathname'
2
2
 
3
3
  class PuppetLint
4
+ # Public: Various methods that implement puppet-lint's plugin system
5
+ #
6
+ # Examples
7
+ #
8
+ # PuppetLint::Plugins.load_spec_helper
4
9
  class Plugins
5
- # Public: Find any gems containing puppet-lint plugins and load them.
10
+ # Internal: Find any gems containing puppet-lint plugins and load them.
6
11
  #
7
12
  # Returns nothing.
8
13
  def self.load_from_gems
@@ -14,6 +19,14 @@ class PuppetLint
14
19
  end
15
20
  end
16
21
  end
22
+
23
+ # Public: Load the puppet-lint spec_helper.rb
24
+ #
25
+ # Returns nothings.
26
+ def self.load_spec_helper
27
+ gemspec = gemspecs.select { |spec| spec.name == 'puppet-lint' }.first
28
+ load Pathname.new(gemspec.full_gem_path) + 'spec/spec_helper.rb'
29
+ end
17
30
  private
18
31
  # Internal: Check if RubyGems is loaded and available.
19
32
  #
@@ -22,19 +35,24 @@ class PuppetLint
22
35
  defined? ::Gem
23
36
  end
24
37
 
38
+ # Internal: Retrieve a list of avaliable gemspecs.
39
+ #
40
+ # Returns an Array of Gem::Specification objects.
41
+ def self.gemspecs
42
+ @gemspecs ||= if Gem::Specification.respond_to?(:latest_specs)
43
+ Gem::Specification.latest_specs
44
+ else
45
+ Gem.searcher.init_gemspecs
46
+ end
47
+ end
48
+
25
49
  # Internal: Retrieve a list of available gem paths from RubyGems.
26
50
  #
27
51
  # Returns an Array of Pathname objects.
28
52
  def self.gem_directories
29
53
  if has_rubygems?
30
- if Gem::Specification.respond_to? :latest_specs
31
- Gem::Specification.latest_specs.map do |spec|
32
- Pathname.new(spec.full_gem_path) + 'lib'
33
- end
34
- else
35
- Gem.searcher.init_gemspecs.map do |spec|
36
- Pathname.new(spec.full_gem_path) + 'lib'
37
- end
54
+ gemspecs.reject { |spec| spec.name == 'puppet-lint' }.map do |spec|
55
+ Pathname.new(spec.full_gem_path) + 'lib'
38
56
  end
39
57
  else
40
58
  []
@@ -51,5 +69,6 @@ require 'puppet-lint/plugins/check_strings'
51
69
  require 'puppet-lint/plugins/check_variables'
52
70
  require 'puppet-lint/plugins/check_whitespace'
53
71
  require 'puppet-lint/plugins/check_resources'
72
+ require 'puppet-lint/plugins/check_nodes'
54
73
 
55
74
  PuppetLint::Plugins.load_from_gems
@@ -1,200 +1,115 @@
1
- class PuppetLint::Plugins::CheckClasses < PuppetLint::CheckPlugin
2
- # Public: Test the manifest tokens for any right-to-left (<-) chaining
3
- # operators and record a warning for each instance found.
4
- #
5
- # Returns nothing.
6
- check 'right_to_left_relationship' do
1
+ # Public: Test the manifest tokens for any right-to-left (<-) chaining
2
+ # operators and record a warning for each instance found.
3
+ PuppetLint.new_check(:right_to_left_relationship) do
4
+ def check
7
5
  tokens.select { |r| r.type == :OUT_EDGE }.each do |token|
8
6
  notify :warning, {
9
- :message => 'right-to-left (<-) relationship',
10
- :linenumber => token.line,
11
- :column => token.column,
7
+ :message => 'right-to-left (<-) relationship',
8
+ :line => token.line,
9
+ :column => token.column,
12
10
  }
13
11
  end
14
12
  end
13
+ end
15
14
 
16
- # Public: Test the manifest tokens for any classes or defined types that are
17
- # not in an appropriately named file for the autoloader to detect and record
18
- # an error of each instance found.
19
- #
20
- # Returns nothing.
21
- check 'autoloader_layout' do
22
- unless fullpath == ''
15
+ # Public: Test the manifest tokens for any classes or defined types that are
16
+ # not in an appropriately named file for the autoloader to detect and record
17
+ # an error of each instance found.
18
+ PuppetLint.new_check(:autoloader_layout) do
19
+ def check
20
+ unless fullpath.nil? || fullpath == ''
23
21
  (class_indexes + defined_type_indexes).each do |class_idx|
24
- class_tokens = tokens[class_idx[:start]..class_idx[:end]]
25
- title_token = class_tokens[class_tokens.index { |r| r.type == :NAME }]
22
+ title_token = class_idx[:name_token]
26
23
  split_title = title_token.value.split('::')
27
24
  mod = split_title.first
28
25
  if split_title.length > 1
29
- expected_path = "#{mod}/manifests/#{split_title[1..-1].join('/')}.pp"
26
+ expected_path = "/#{mod}/manifests/#{split_title[1..-1].join('/')}.pp"
30
27
  else
31
- expected_path = "#{title_token.value}/manifests/init.pp"
28
+ expected_path = "/#{title_token.value}/manifests/init.pp"
29
+ end
30
+
31
+ if PuppetLint.configuration.relative
32
+ expected_path = expected_path.gsub(/^\//,'').split('/')[1..-1].join('/')
32
33
  end
33
34
 
34
35
  unless fullpath.end_with? expected_path
35
36
  notify :error, {
36
- :message => "#{title_token.value} not in autoload module layout",
37
- :linenumber => title_token.line,
38
- :column => title_token.column,
37
+ :message => "#{title_token.value} not in autoload module layout",
38
+ :line => title_token.line,
39
+ :column => title_token.column,
39
40
  }
40
41
  end
41
42
  end
42
43
  end
43
44
  end
45
+ end
44
46
 
45
- # Public: Check the manifest tokens for any classes or defined types that
46
- # have a dash in their name and record a warning for each instance found.
47
- #
48
- # Returns nothing.
49
- check 'names_containing_dash' do
47
+ # Public: Check the manifest tokens for any classes or defined types that
48
+ # have a dash in their name and record a warning for each instance found.
49
+ PuppetLint.new_check(:names_containing_dash) do
50
+ def check
50
51
  (class_indexes + defined_type_indexes).each do |class_idx|
51
- class_tokens = tokens[class_idx[:start]..class_idx[:end]]
52
- title_token = class_tokens[class_tokens.index { |r| r.type == :NAME }]
53
-
54
- if title_token.value.include? '-'
55
- if class_tokens.first.type == :CLASS
52
+ if class_idx[:name_token].value.include? '-'
53
+ if class_idx[:type] == :CLASS
56
54
  obj_type = 'class'
57
55
  else
58
56
  obj_type = 'defined type'
59
57
  end
60
58
 
61
59
  notify :warning, {
62
- :message => "#{obj_type} name containing a dash",
63
- :linenumber => title_token.line,
64
- :column => title_token.column,
60
+ :message => "#{obj_type} name containing a dash",
61
+ :line => class_idx[:name_token].line,
62
+ :column => class_idx[:name_token].column,
65
63
  }
66
64
  end
67
65
  end
68
66
  end
67
+ end
69
68
 
70
- check 'class_inherits_from_params_class' do
69
+ # Public: Check the manifest tokens for any classes that inherit a params
70
+ # subclass and record a warning for each instance found.
71
+ PuppetLint.new_check(:class_inherits_from_params_class) do
72
+ def check
71
73
  class_indexes.each do |class_idx|
72
- class_tokens = tokens[class_idx[:start]..class_idx[:end]]
73
- inherits_idx = class_tokens.index { |r| r.type == :INHERITS }
74
- unless inherits_idx.nil?
75
- inherited_class_token = class_tokens[inherits_idx].next_code_token
76
- if inherited_class_token.value.end_with? '::params'
74
+ unless class_idx[:inherited_token].nil?
75
+ if class_idx[:inherited_token].value.end_with? '::params'
77
76
  notify :warning, {
78
- :message => 'class inheriting from params class',
79
- :linenumber => inherited_class_token.line,
80
- :column => inherited_class_token.column,
77
+ :message => 'class inheriting from params class',
78
+ :line => class_idx[:inherited_token].line,
79
+ :column => class_idx[:inherited_token].column,
81
80
  }
82
81
  end
83
82
  end
84
83
  end
85
84
  end
85
+ end
86
86
 
87
- check 'class_parameter_defaults' do
88
- class_indexes.each do |class_idx|
89
- token_idx = class_idx[:start]
90
- depth = 0
91
- lparen_idx = nil
92
- rparen_idx = nil
93
- class_name_token = tokens[class_idx[:start]].next_code_token
94
-
95
- if class_name_token.next_code_token.type == :LPAREN
96
- tokens[token_idx..-1].each_index do |t|
97
- idx = token_idx + t
98
- if tokens[idx].type == :LPAREN
99
- depth += 1
100
- lparen_idx = idx if depth == 1
101
- elsif tokens[idx].type == :RPAREN
102
- depth -= 1
103
- if depth == 0
104
- rparen_idx = idx
105
- break
106
- end
107
- end
108
- end
109
- end
110
-
111
- unless lparen_idx.nil? or rparen_idx.nil?
112
- param_tokens = tokens[lparen_idx+1..rparen_idx-1].reject { |r|
113
- formatting_tokens.include? r.type
114
- }
115
-
116
- paren_stack = []
117
- param_tokens.each_index do |param_tokens_idx|
118
- this_token = param_tokens[param_tokens_idx]
119
- next_token = this_token.next_code_token
120
- prev_token = this_token.prev_code_token
121
-
122
- if this_token.type == :LPAREN
123
- paren_stack.push(true)
124
- elsif this_token.type == :RPAREN
125
- paren_stack.pop
126
- end
127
- next unless paren_stack.empty?
128
-
129
- if this_token.type == :VARIABLE
130
- if !next_token.nil? && next_token.type != :EQUALS
131
- if !prev_token.nil? && prev_token.type != :EQUALS
132
- notify :warning, {
133
- :message => 'parameterised class parameter without a default value',
134
- :linenumber => this_token.line,
135
- :column => this_token.column,
136
- }
137
- end
138
- end
139
- end
140
- end
141
- end
142
- end
143
- end
144
-
145
- # Public: Test the manifest tokens for any parameterised classes or defined
146
- # types that take parameters and record a warning if there are any optional
147
- # parameters listed before required parameters.
148
- #
149
- # Returns nothing.
150
- check 'parameter_order' do
87
+ # Public: Test the manifest tokens for any parameterised classes or defined
88
+ # types that take parameters and record a warning if there are any optional
89
+ # parameters listed before required parameters.
90
+ PuppetLint.new_check(:parameter_order) do
91
+ def check
151
92
  defined_type_indexes.each do |class_idx|
152
- token_idx = class_idx[:start]
153
- depth = 0
154
- lparen_idx = nil
155
- rparen_idx = nil
156
- tokens[token_idx..-1].each_index do |t|
157
- idx = token_idx + t
158
- if tokens[idx].type == :LPAREN
159
- depth += 1
160
- lparen_idx = idx if depth == 1
161
- elsif tokens[idx].type == :RPAREN
162
- depth -= 1
163
- if depth == 0
164
- rparen_idx = idx
165
- break
166
- end
167
- end
168
- end
169
-
170
- unless lparen_idx.nil? or rparen_idx.nil?
171
- param_tokens = tokens[lparen_idx+1..rparen_idx-1].reject { |r|
172
- formatting_tokens.include? r.type
173
- }
174
-
93
+ unless class_idx[:param_tokens].nil?
175
94
  paren_stack = []
176
- param_tokens.each_index do |param_tokens_idx|
177
- this_token = param_tokens[param_tokens_idx]
178
- next_token = param_tokens[param_tokens_idx+1]
179
- prev_token = param_tokens[param_tokens_idx-1]
180
-
181
- if this_token.type == :LPAREN
95
+ class_idx[:param_tokens].each_with_index do |token, i|
96
+ if token.type == :LPAREN
182
97
  paren_stack.push(true)
183
- elsif this_token.type == :RPAREN
98
+ elsif token.type == :RPAREN
184
99
  paren_stack.pop
185
100
  end
186
101
  next unless paren_stack.empty?
187
102
 
188
- if this_token.type == :VARIABLE
189
- if next_token.nil? || next_token.type == :COMMA
190
- prev_tokens = param_tokens[0..param_tokens_idx]
103
+ if token.type == :VARIABLE
104
+ if token.next_code_token.nil? || [:COMMA, :RPAREN].include?(token.next_code_token.type)
105
+ prev_tokens = class_idx[:param_tokens][0..i]
191
106
  unless prev_tokens.rindex { |r| r.type == :EQUALS }.nil?
192
- unless prev_token.nil? or prev_token.type == :EQUALS
107
+ unless token.prev_code_token.nil? or token.prev_code_token.type == :EQUALS
193
108
  msg = 'optional parameter listed before required parameter'
194
109
  notify :warning, {
195
- :message => msg,
196
- :linenumber => this_token.line,
197
- :column => this_token.column,
110
+ :message => msg,
111
+ :line => token.line,
112
+ :column => token.column,
198
113
  }
199
114
  end
200
115
  end
@@ -204,140 +119,149 @@ class PuppetLint::Plugins::CheckClasses < PuppetLint::CheckPlugin
204
119
  end
205
120
  end
206
121
  end
122
+ end
207
123
 
208
- # Public: Test the manifest tokens for any classes that inherit across
209
- # namespaces and record a warning for each instance found.
210
- #
211
- # Returns nothing.
212
- check 'inherits_across_namespaces' do
124
+ # Public: Test the manifest tokens for any classes that inherit across
125
+ # namespaces and record a warning for each instance found.
126
+ PuppetLint.new_check(:inherits_across_namespaces) do
127
+ def check
213
128
  class_indexes.each do |class_idx|
214
- class_token = tokens[class_idx[:start]]
215
- class_name_token = class_token.next_code_token
216
- inherits_token = class_name_token.next_code_token
217
- next if inherits_token.nil?
218
-
219
- if inherits_token.type == :INHERITS
220
- inherited_class_token = inherits_token.next_code_token
221
- inherited_module_name = inherited_class_token.value.split('::').reject { |r| r.empty? }.first
222
- class_module_name = class_name_token.value.split('::').reject { |r| r.empty? }.first
129
+ unless class_idx[:inherited_token].nil?
130
+ inherited_module_name = class_idx[:inherited_token].value.split('::').reject { |r| r.empty? }.first
131
+ class_module_name = class_idx[:name_token].value.split('::').reject { |r| r.empty? }.first
223
132
 
224
133
  unless class_module_name == inherited_module_name
225
134
  notify :warning, {
226
- :message => "class inherits across module namespaces",
227
- :linenumber => inherited_class_token.line,
228
- :column => inherited_class_token.column,
135
+ :message => "class inherits across module namespaces",
136
+ :line => class_idx[:inherited_token].line,
137
+ :column => class_idx[:inherited_token].column,
229
138
  }
230
139
  end
231
140
  end
232
141
  end
233
142
  end
143
+ end
144
+
145
+ # Public: Test the manifest tokens for any classes or defined types that are
146
+ # defined inside another class.
147
+ PuppetLint.new_check(:nested_classes_or_defines) do
148
+ TOKENS = Set[:CLASS, :DEFINE]
234
149
 
235
- # Public: Test the manifest tokens for any classes or defined types that are
236
- # defined inside another class.
237
- #
238
- # Returns nothing.
239
- check 'nested_classes_or_defines' do
150
+ def check
240
151
  class_indexes.each do |class_idx|
241
152
  # Skip the first token so that we don't pick up the first :CLASS
242
- class_tokens = tokens[class_idx[:start]+1..class_idx[:end]]
153
+ class_tokens = class_idx[:tokens][1..-1]
243
154
 
244
155
  class_tokens.each do |token|
245
- if token.type == :CLASS
156
+ if TOKENS.include?(token.type)
246
157
  if token.next_code_token.type != :LBRACE
158
+ type = token.type == :CLASS ? 'class' : 'defined type'
159
+
247
160
  notify :warning, {
248
- :message => "class defined inside a class",
249
- :linenumber => token.line,
250
- :column => token.column,
161
+ :message => "#{type} defined inside a class",
162
+ :line => token.line,
163
+ :column => token.column,
251
164
  }
252
165
  end
253
166
  end
254
-
255
- if token.type == :DEFINE
256
- notify :warning, {
257
- :message => "define defined inside a class",
258
- :linenumber => token.line,
259
- :column => token.column,
260
- }
261
- end
262
167
  end
263
168
  end
264
169
  end
170
+ end
171
+
172
+ # Public: Test the manifest tokens for any variables that are referenced in
173
+ # the manifest. If the variables are not fully qualified or one of the
174
+ # variables automatically created in the scope, check that they have been
175
+ # defined in the local scope and record a warning for each variable that has
176
+ # not.
177
+ PuppetLint.new_check(:variable_scope) do
178
+ DEFAULT_SCOPE_VARS = Set[
179
+ 'name',
180
+ 'title',
181
+ 'module_name',
182
+ 'environment',
183
+ 'clientcert',
184
+ 'clientversion',
185
+ 'servername',
186
+ 'serverip',
187
+ 'serverversion',
188
+ 'caller_module_name',
189
+ ]
190
+ POST_VAR_TOKENS = Set[:COMMA, :EQUALS, :RPAREN]
191
+
192
+ def check
193
+ variables_in_scope = DEFAULT_SCOPE_VARS.clone
265
194
 
266
- # Public: Test the manifest tokens for any variables that are referenced in
267
- # the manifest. If the variables are not fully qualified or one of the
268
- # variables automatically created in the scope, check that they have been
269
- # defined in the local scope and record a warning for each variable that has
270
- # not.
271
- #
272
- # Returns nothing.
273
- check 'variable_scope' do
274
- variables_in_scope = [
275
- 'name',
276
- 'title',
277
- 'module_name',
278
- 'environment',
279
- 'clientcert',
280
- 'clientversion',
281
- 'servername',
282
- 'serverip',
283
- 'serverversion',
284
- 'caller_module_name',
285
- ]
286
195
  (class_indexes + defined_type_indexes).each do |idx|
287
- object_tokens = tokens[idx[:start]..idx[:end]]
288
- object_tokens.reject! { |r| formatting_tokens.include?(r.type) }
289
- depth = 0
290
- lparen_idx = nil
291
- rparen_idx = nil
292
- object_tokens.each_index do |t|
293
- if object_tokens[t].type == :LPAREN
294
- depth += 1
295
- lparen_idx = t if depth == 1
296
- elsif object_tokens[t].type == :RPAREN
297
- depth -= 1
298
- if depth == 0
299
- rparen_idx = t
300
- break
301
- end
302
- end
303
- end
304
- referenced_variables = []
196
+ referenced_variables = Set[]
197
+ object_tokens = idx[:tokens]
305
198
 
306
- unless lparen_idx.nil? or rparen_idx.nil?
307
- param_tokens = object_tokens[lparen_idx..rparen_idx]
308
- param_tokens.each_index do |param_tokens_idx|
309
- this_token = param_tokens[param_tokens_idx]
310
- next_token = param_tokens[param_tokens_idx+1]
311
- if this_token.type == :VARIABLE
312
- if {:COMMA => true, :EQUALS => true, :RPAREN => true}.include? next_token.type
313
- variables_in_scope << this_token.value
199
+ unless idx[:param_tokens].nil?
200
+ idx[:param_tokens].each do |token|
201
+ if token.type == :VARIABLE
202
+ if POST_VAR_TOKENS.include? token.next_code_token.type
203
+ variables_in_scope << token.value
314
204
  end
315
205
  end
316
206
  end
317
207
  end
318
208
 
319
- object_tokens.each_index do |object_token_idx|
320
- this_token = object_tokens[object_token_idx]
321
- next_token = object_tokens[object_token_idx + 1]
209
+ future_parser_scopes = {}
210
+ in_pipe = false
211
+ temp_scope_vars = []
212
+
213
+ object_tokens.each do |token|
214
+ if token.type == :VARIABLE
215
+ if in_pipe
216
+ temp_scope_vars << token.value
217
+ else
218
+ if token.next_code_token.type == :EQUALS
219
+ variables_in_scope << token.value
220
+ else
221
+ referenced_variables << token
222
+ end
223
+ end
224
+ elsif token.type == :PIPE
225
+ in_pipe = !in_pipe
322
226
 
323
- if this_token.type == :VARIABLE
324
- if next_token.type == :EQUALS
325
- variables_in_scope << this_token.value
227
+ if in_pipe
228
+ temp_scope_vars = []
326
229
  else
327
- referenced_variables << this_token
230
+ start_idx = tokens.find_index(token)
231
+ end_token = nil
232
+ brace_depth = 0
233
+
234
+ tokens[start_idx..-1].each do |sub_token|
235
+ case sub_token.type
236
+ when :LBRACE
237
+ brace_depth += 1
238
+ when :RBRACE
239
+ brace_depth -= 1
240
+ if brace_depth == 0
241
+ end_token = sub_token
242
+ break
243
+ end
244
+ end
245
+ end
246
+
247
+ future_parser_scopes.merge!(Hash[(token.line..end_token.line).to_a.map { |i| [i, temp_scope_vars] }])
328
248
  end
329
249
  end
330
250
  end
331
251
 
332
252
  msg = "top-scope variable being used without an explicit namespace"
333
253
  referenced_variables.each do |token|
254
+ unless future_parser_scopes[token.line].nil?
255
+ next if future_parser_scopes[token.line].include?(token.value)
256
+ end
257
+
334
258
  unless token.value.include? '::'
335
259
  unless variables_in_scope.include? token.value
336
- unless token.value =~ /\d+/
260
+ unless token.value =~ /\A\d+\Z/
337
261
  notify :warning, {
338
- :message => msg,
339
- :linenumber => token.line,
340
- :column => token.column,
262
+ :message => msg,
263
+ :line => token.line,
264
+ :column => token.column,
341
265
  }
342
266
  end
343
267
  end