puppet-lint 0.4.0.pre1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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