puppet-lint 2.1.1 → 2.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +61 -19
- data/Gemfile +9 -5
- data/appveyor.yml +32 -0
- data/lib/puppet-lint/checkplugin.rb +2 -2
- data/lib/puppet-lint/checks.rb +21 -0
- data/lib/puppet-lint/data.rb +26 -30
- data/lib/puppet-lint/lexer.rb +179 -44
- data/lib/puppet-lint/lexer/token.rb +87 -2
- data/lib/puppet-lint/plugins/check_classes.rb +60 -8
- data/lib/puppet-lint/plugins/check_nodes.rb +10 -0
- data/lib/puppet-lint/plugins/check_resources.rb +13 -34
- data/lib/puppet-lint/plugins/check_strings.rb +1 -1
- data/lib/puppet-lint/plugins/check_whitespace.rb +37 -42
- data/lib/puppet-lint/version.rb +1 -1
- data/spec/fixtures/test/manifests/unterminated_control_comment.pp +5 -0
- data/spec/puppet-lint/bin_spec.rb +9 -1
- data/spec/puppet-lint/lexer_spec.rb +418 -17
- data/spec/puppet-lint/plugins/check_classes/arrow_on_right_operand_line_spec.rb +46 -0
- data/spec/puppet-lint/plugins/check_classes/variable_scope_spec.rb +73 -0
- data/spec/puppet-lint/plugins/check_nodes/unquoted_node_name_spec.rb +12 -0
- data/spec/puppet-lint/plugins/check_resources/ensure_first_param_spec.rb +40 -0
- data/spec/puppet-lint/plugins/check_resources/file_mode_spec.rb +84 -0
- data/spec/puppet-lint/plugins/check_resources/unquoted_file_mode_spec.rb +84 -0
- data/spec/puppet-lint/plugins/check_strings/double_quoted_strings_spec.rb +1 -0
- data/spec/puppet-lint/plugins/check_whitespace/arrow_alignment_spec.rb +181 -0
- data/spec/spec_helper.rb +3 -2
- metadata +8 -3
@@ -77,8 +77,13 @@ class PuppetLint
|
|
77
77
|
when :DQPOST
|
78
78
|
"#{@value}\""
|
79
79
|
when :VARIABLE
|
80
|
-
|
81
|
-
|
80
|
+
enclose_token_types = Set[:DQPRE, :DQMID, :HEREDOC_PRE, :HEREDOC_MID].freeze
|
81
|
+
if !@prev_code_token.nil? && enclose_token_types.include?(@prev_code_token.type)
|
82
|
+
if @raw.nil?
|
83
|
+
"${#{@value}}"
|
84
|
+
else
|
85
|
+
"${#{@raw}}"
|
86
|
+
end
|
82
87
|
else
|
83
88
|
"$#{@value}"
|
84
89
|
end
|
@@ -92,10 +97,90 @@ class PuppetLint
|
|
92
97
|
"/#{@value}/"
|
93
98
|
when :MLCOMMENT
|
94
99
|
@raw
|
100
|
+
when :HEREDOC_OPEN
|
101
|
+
"@(#{@value})"
|
102
|
+
when :HEREDOC
|
103
|
+
@raw
|
104
|
+
when :HEREDOC_POST
|
105
|
+
@raw
|
95
106
|
else
|
96
107
|
@value
|
97
108
|
end
|
98
109
|
end
|
110
|
+
|
111
|
+
# Public: Search from this token to find the next token of a given type.
|
112
|
+
#
|
113
|
+
# type - A Symbol type of the token to find, or an Array of Symbols.
|
114
|
+
# opts - An optional Hash
|
115
|
+
# :value - A token value to search for in addition to type
|
116
|
+
# :skip_blocks - A Boolean to specify whether { } blocks should be
|
117
|
+
# skipped over (defaults to true).
|
118
|
+
#
|
119
|
+
# Returns a PuppetLint::Lexer::Token object if a matching token could be
|
120
|
+
# found, otherwise nil.
|
121
|
+
def next_token_of(type, opts = {})
|
122
|
+
find_token_of(:next, type, opts)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Public: Search from this token to find the previous token of a given type.
|
126
|
+
#
|
127
|
+
# type - A Symbol type of the token to find, or an Array of Symbols.
|
128
|
+
# opts - An optional Hash
|
129
|
+
# :value - A token value to search for in addition to type
|
130
|
+
# :skip_blocks - A Boolean to specify whether { } blocks should be
|
131
|
+
# skipped over (defaults to true).
|
132
|
+
#
|
133
|
+
# Returns a PuppetLint::Lexer::Token object if a matching token could be
|
134
|
+
# found, otherwise nil.
|
135
|
+
def prev_token_of(type, opts = {})
|
136
|
+
find_token_of(:prev, type, opts)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Internal: Search from this token to find the next token of a given type
|
140
|
+
# in a given direction.
|
141
|
+
#
|
142
|
+
# direction - A Symbol direction to search (:next or :prev).
|
143
|
+
# type - A Symbol type of the token to find, or an Array of Symbols.
|
144
|
+
# opts - An optional Hash
|
145
|
+
# :value - A token value to search for in addition to type
|
146
|
+
# :skip_blocks - A Boolean to specify whether { } blocks should be
|
147
|
+
# skipped over (defaults to true).
|
148
|
+
#
|
149
|
+
# Returns a PuppetLint::Lexer::Token object if a matching token could be
|
150
|
+
# found, otherwise nil.
|
151
|
+
def find_token_of(direction, type, opts = {})
|
152
|
+
return nil unless [:next, :prev].include?(direction)
|
153
|
+
|
154
|
+
opts[:skip_blocks] ||= true
|
155
|
+
to_find = Array[*type]
|
156
|
+
|
157
|
+
token_iter = self.send("#{direction}_token".to_sym)
|
158
|
+
while !token_iter.nil?
|
159
|
+
if to_find.include? token_iter.type
|
160
|
+
if opts[:value]
|
161
|
+
return token_iter if token_iter.value == opts[:value]
|
162
|
+
else
|
163
|
+
return token_iter
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
opening_token = direction == :next ? "L" : "R"
|
168
|
+
closing_token = direction == :next ? "R" : "L"
|
169
|
+
|
170
|
+
if opts[:skip_blocks]
|
171
|
+
case token_iter.type
|
172
|
+
when "#{opening_token}BRACE".to_sym
|
173
|
+
token_iter = token_iter.send("#{direction}_token_of".to_sym, ["#{closing_token}BRACE".to_sym, opts])
|
174
|
+
when "#{opening_token}BRACK".to_sym
|
175
|
+
token_iter = token_iter.send("#{direction}_token_of".to_sym, ["#{closing_token}BRACK".to_sym, opts])
|
176
|
+
when "#{opening_token}PAREN".to_sym
|
177
|
+
token_iter = token_iter.send("#{direction}_token_of".to_sym, ["#{closing_token}PAREN".to_sym, opts])
|
178
|
+
end
|
179
|
+
end
|
180
|
+
token_iter = token_iter.send("#{direction}_token".to_sym)
|
181
|
+
end
|
182
|
+
nil
|
183
|
+
end
|
99
184
|
end
|
100
185
|
end
|
101
186
|
end
|
@@ -14,6 +14,44 @@ PuppetLint.new_check(:right_to_left_relationship) do
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
+
# Public: Test the manifest tokens for chaining arrow that is
|
18
|
+
# on the line of the left operand when the right operand is on another line.
|
19
|
+
#
|
20
|
+
# https://docs.puppet.com/guides/style_guide.html#chaining-arrow-syntax
|
21
|
+
PuppetLint.new_check(:arrow_on_right_operand_line) do
|
22
|
+
def check
|
23
|
+
tokens.select { |r| Set[:IN_EDGE, :IN_EDGE_SUB].include?(r.type) }.each do |token|
|
24
|
+
if token.next_code_token.line != token.line
|
25
|
+
notify :warning, {
|
26
|
+
:message => 'arrow should be on the right operand\'s line',
|
27
|
+
:line => token.line,
|
28
|
+
:column => token.column,
|
29
|
+
:token => token,
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def fix(problem)
|
36
|
+
token = problem[:token]
|
37
|
+
tokens.delete(token)
|
38
|
+
# remove any excessive whitespace on the line
|
39
|
+
temp_token = token.prev_code_token
|
40
|
+
while (temp_token = temp_token.next_token)
|
41
|
+
tokens.delete(temp_token) if whitespace?(temp_token)
|
42
|
+
break if temp_token.type == :NEWLINE
|
43
|
+
end
|
44
|
+
|
45
|
+
index = tokens.index(token.next_code_token)
|
46
|
+
tokens.insert(index, token)
|
47
|
+
tokens.insert(index + 1, PuppetLint::Lexer::Token.new(:WHITESPACE, ' ', 0, 0))
|
48
|
+
end
|
49
|
+
|
50
|
+
def whitespace?(token)
|
51
|
+
Set[:INDENT, :WHITESPACE].include?(token.type)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
17
55
|
# Public: Test the manifest tokens for any classes or defined types that are
|
18
56
|
# not in an appropriately named file for the autoloader to detect and record
|
19
57
|
# an error of each instance found.
|
@@ -295,7 +333,7 @@ PuppetLint.new_check(:variable_scope) do
|
|
295
333
|
|
296
334
|
future_parser_scopes = {}
|
297
335
|
in_pipe = false
|
298
|
-
|
336
|
+
block_params_stack = []
|
299
337
|
|
300
338
|
object_tokens.each do |token|
|
301
339
|
case token.type
|
@@ -303,18 +341,28 @@ PuppetLint.new_check(:variable_scope) do
|
|
303
341
|
if token.prev_code_token.type == :VARIABLE
|
304
342
|
variables_in_scope << token.prev_code_token.value
|
305
343
|
elsif token.prev_code_token.type == :RBRACK
|
306
|
-
temp_token = token
|
344
|
+
temp_token = token
|
307
345
|
|
308
|
-
|
309
|
-
|
346
|
+
brack_depth = 0
|
347
|
+
while temp_token = temp_token.prev_code_token
|
348
|
+
case temp_token.type
|
349
|
+
when :VARIABLE
|
310
350
|
variables_in_scope << temp_token.value
|
351
|
+
when :RBRACK
|
352
|
+
brack_depth += 1
|
353
|
+
when :LBRACK
|
354
|
+
brack_depth -= 1
|
355
|
+
break if brack_depth == 0
|
356
|
+
when :COMMA
|
357
|
+
# ignore
|
358
|
+
else # unexpected
|
359
|
+
break
|
311
360
|
end
|
312
|
-
temp_token = temp_token.prev_code_token
|
313
361
|
end
|
314
362
|
end
|
315
363
|
when :VARIABLE
|
316
364
|
if in_pipe
|
317
|
-
|
365
|
+
block_params_stack[-1] << token.value
|
318
366
|
else
|
319
367
|
referenced_variables << token
|
320
368
|
end
|
@@ -322,7 +370,7 @@ PuppetLint.new_check(:variable_scope) do
|
|
322
370
|
in_pipe = !in_pipe
|
323
371
|
|
324
372
|
if in_pipe
|
325
|
-
|
373
|
+
block_params_stack << []
|
326
374
|
else
|
327
375
|
start_idx = tokens.find_index(token)
|
328
376
|
end_token = nil
|
@@ -341,7 +389,11 @@ PuppetLint.new_check(:variable_scope) do
|
|
341
389
|
end
|
342
390
|
end
|
343
391
|
|
344
|
-
|
392
|
+
params = block_params_stack.pop
|
393
|
+
(token.line..end_token.line).each do |line|
|
394
|
+
future_parser_scopes[line] ||= []
|
395
|
+
future_parser_scopes[line].concat(params)
|
396
|
+
end
|
345
397
|
end
|
346
398
|
end
|
347
399
|
end
|
@@ -8,6 +8,16 @@ PuppetLint.new_check(:unquoted_node_name) do
|
|
8
8
|
node_tokens.each do |node|
|
9
9
|
node_token_idx = tokens.index(node)
|
10
10
|
node_lbrace_tok = tokens[node_token_idx..-1].find { |token| token.type == :LBRACE }
|
11
|
+
if node_lbrace_tok.nil?
|
12
|
+
notify :error, {
|
13
|
+
:check => :syntax,
|
14
|
+
:message => 'Syntax error (try running `puppet parser validate <file>`)',
|
15
|
+
:line => node.line,
|
16
|
+
:column => node.column,
|
17
|
+
}
|
18
|
+
next
|
19
|
+
end
|
20
|
+
|
11
21
|
node_lbrace_idx = tokens.index(node_lbrace_tok)
|
12
22
|
|
13
23
|
tokens[node_token_idx..node_lbrace_idx].select { |token|
|
@@ -47,43 +47,22 @@ PuppetLint.new_check(:ensure_first_param) do
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
50
|
+
|
50
51
|
def fix(problem)
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
ensure_param_name_token = nil
|
57
|
-
ensure_param_name_idx = nil
|
58
|
-
ensure_param_comma_token = nil
|
59
|
-
ensure_param_comma_idx = nil
|
60
|
-
tokens[(problem[:resource][:start])..(problem[:resource][:end])].each_with_index do |token, token_idx|
|
61
|
-
if first_param_name_token.nil?
|
62
|
-
if token.type == :NAME
|
63
|
-
first_param_name_token = token
|
64
|
-
first_param_name_idx = problem[:resource][:start] + token_idx
|
65
|
-
end
|
66
|
-
elsif first_param_comma_token.nil?
|
67
|
-
if token.type == :COMMA
|
68
|
-
first_param_comma_token = token
|
69
|
-
first_param_comma_idx = problem[:resource][:start] + token_idx
|
70
|
-
end
|
71
|
-
elsif ensure_param_name_token.nil?
|
72
|
-
if token.type == :NAME and token.value == 'ensure'
|
73
|
-
ensure_param_name_token = token
|
74
|
-
ensure_param_name_idx = problem[:resource][:start] + token_idx
|
75
|
-
end
|
76
|
-
elsif ensure_param_comma_token.nil?
|
77
|
-
if token.type == :COMMA or token.type == :SEMIC
|
78
|
-
ensure_param_comma_token = token
|
79
|
-
ensure_param_comma_idx = problem[:resource][:start] + token_idx
|
80
|
-
break
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
52
|
+
first_param_name_token = tokens[problem[:resource][:start]].next_token_of(:NAME)
|
53
|
+
first_param_comma_token = first_param_name_token.next_token_of(:COMMA)
|
54
|
+
ensure_param_name_token = first_param_comma_token.next_token_of(:NAME, :value => 'ensure')
|
55
|
+
ensure_param_comma_token = ensure_param_name_token.next_token_of([:COMMA, :SEMIC])
|
56
|
+
|
84
57
|
if first_param_name_token.nil? or first_param_comma_token.nil? or ensure_param_name_token.nil? or ensure_param_comma_token.nil?
|
85
58
|
raise PuppetLint::NoFix
|
86
59
|
end
|
60
|
+
|
61
|
+
first_param_name_idx = tokens.index(first_param_name_token)
|
62
|
+
first_param_comma_idx = tokens.index(first_param_comma_token)
|
63
|
+
ensure_param_name_idx = tokens.index(ensure_param_name_token)
|
64
|
+
ensure_param_comma_idx = tokens.index(ensure_param_comma_token)
|
65
|
+
|
87
66
|
# Flip params
|
88
67
|
prev_token = first_param_name_token.prev_token
|
89
68
|
first_param_name_token.prev_token = ensure_param_name_token.prev_token
|
@@ -191,7 +170,7 @@ end
|
|
191
170
|
PuppetLint.new_check(:file_mode) do
|
192
171
|
MSG = 'mode should be represented as a 4 digit octal value or symbolic mode'
|
193
172
|
SYM_RE = "([ugoa]*[-=+][-=+rstwxXugo]*)(,[ugoa]*[-=+][-=+rstwxXugo]*)*"
|
194
|
-
IGNORE_TYPES = Set[:VARIABLE, :UNDEF]
|
173
|
+
IGNORE_TYPES = Set[:VARIABLE, :UNDEF, :FUNCTION_NAME]
|
195
174
|
MODE_RE = Regexp.new(/\A([0-7]{4}|#{SYM_RE})\Z/)
|
196
175
|
|
197
176
|
def check
|
@@ -10,7 +10,7 @@ PuppetLint.new_check(:double_quoted_strings) do
|
|
10
10
|
}.map { |token|
|
11
11
|
[token, token.value.gsub(' '*token.column, "\n")]
|
12
12
|
}.select { |token, sane_value|
|
13
|
-
sane_value[/(\\\$|\\"|\\'|'|\r|\t|\\t|\n|\\n)/].nil?
|
13
|
+
sane_value[/(\\\$|\\"|\\'|'|\r|\t|\\t|\n|\\n|\\\\)/].nil?
|
14
14
|
}.each do |token, sane_value|
|
15
15
|
notify :warning, {
|
16
16
|
:message => 'double quoted string containing no variables',
|
@@ -125,8 +125,8 @@ PuppetLint.new_check(:arrow_alignment) do
|
|
125
125
|
|
126
126
|
def check
|
127
127
|
resource_indexes.each do |res_idx|
|
128
|
-
|
129
|
-
|
128
|
+
arrow_column = [0]
|
129
|
+
level_idx = 0
|
130
130
|
level_tokens = []
|
131
131
|
param_column = [nil]
|
132
132
|
resource_tokens = res_idx[:tokens]
|
@@ -139,11 +139,11 @@ PuppetLint.new_check(:arrow_alignment) do
|
|
139
139
|
last_arrow = resource_tokens.rindex { |r| r.type == :FARROW }
|
140
140
|
next if first_arrow.nil?
|
141
141
|
next if last_arrow.nil?
|
142
|
-
next
|
142
|
+
next if resource_tokens[first_arrow].line == resource_tokens[last_arrow].line
|
143
143
|
|
144
144
|
resource_tokens.each_with_index do |token, idx|
|
145
145
|
if token.type == :FARROW
|
146
|
-
(level_tokens[
|
146
|
+
(level_tokens[level_idx] ||= []) << token
|
147
147
|
param_token = token.prev_code_token
|
148
148
|
|
149
149
|
if param_token.type == :DQPOST
|
@@ -158,63 +158,52 @@ PuppetLint.new_check(:arrow_alignment) do
|
|
158
158
|
param_length = param_token.to_manifest.length
|
159
159
|
end
|
160
160
|
|
161
|
-
if param_column[
|
161
|
+
if param_column[level_idx].nil?
|
162
162
|
if param_token.type == :DQPOST
|
163
|
-
param_column[
|
163
|
+
param_column[level_idx] = iter_token.column
|
164
164
|
else
|
165
|
-
param_column[
|
165
|
+
param_column[level_idx] = param_token.column
|
166
166
|
end
|
167
167
|
end
|
168
168
|
|
169
|
-
|
169
|
+
this_arrow_column = param_column[level_idx] + param_length + 1
|
170
170
|
|
171
|
-
if
|
172
|
-
|
171
|
+
if arrow_column[level_idx] < this_arrow_column
|
172
|
+
arrow_column[level_idx] = this_arrow_column
|
173
173
|
end
|
174
174
|
|
175
175
|
elsif token.type == :LBRACE
|
176
|
-
|
177
|
-
|
178
|
-
level_tokens[
|
176
|
+
level_idx += 1
|
177
|
+
arrow_column << 0
|
178
|
+
level_tokens[level_idx] ||= []
|
179
179
|
param_column << nil
|
180
180
|
elsif token.type == :RBRACE || token.type == :SEMIC
|
181
|
-
level_tokens[
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
:
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
181
|
+
if level_tokens[level_idx].map(&:line).uniq.length > 1
|
182
|
+
level_tokens[level_idx].each do |arrow_tok|
|
183
|
+
unless arrow_tok.column == arrow_column[level_idx] || level_tokens[level_idx].size == 1
|
184
|
+
arrows_on_line = level_tokens[level_idx].select { |t| t.line == arrow_tok.line }
|
185
|
+
notify :warning, {
|
186
|
+
:message => "indentation of => is not properly aligned (expected in column #{arrow_column[level_idx]}, but found it in column #{arrow_tok.column})",
|
187
|
+
:line => arrow_tok.line,
|
188
|
+
:column => arrow_tok.column,
|
189
|
+
:token => arrow_tok,
|
190
|
+
:arrow_column => arrow_column[level_idx],
|
191
|
+
:newline => !(arrows_on_line.index(arrow_tok) == 0),
|
192
|
+
:newline_indent => param_column[level_idx] - 1,
|
193
|
+
}
|
194
|
+
end
|
193
195
|
end
|
194
196
|
end
|
195
|
-
|
196
|
-
level_tokens[
|
197
|
-
|
197
|
+
arrow_column[level_idx] = 0
|
198
|
+
level_tokens[level_idx].clear
|
199
|
+
param_column[level_idx] = nil
|
200
|
+
level_idx -= 1
|
198
201
|
end
|
199
202
|
end
|
200
203
|
end
|
201
204
|
end
|
202
205
|
|
203
206
|
def fix(problem)
|
204
|
-
param_token = problem[:token].prev_code_token
|
205
|
-
if param_token.type == :DQPOST
|
206
|
-
param_length = 0
|
207
|
-
iter_token = param_token
|
208
|
-
while iter_token.type != :DQPRE do
|
209
|
-
param_length += iter_token.to_manifest.length
|
210
|
-
iter_token = iter_token.prev_token
|
211
|
-
end
|
212
|
-
param_length += iter_token.to_manifest.length
|
213
|
-
else
|
214
|
-
param_length = param_token.to_manifest.length
|
215
|
-
end
|
216
|
-
new_ws_len = (problem[:indent_depth] - (problem[:newline_indent] + param_length + 1))
|
217
|
-
new_ws = ' ' * new_ws_len
|
218
207
|
if problem[:newline]
|
219
208
|
index = tokens.index(problem[:token].prev_code_token.prev_token)
|
220
209
|
|
@@ -226,6 +215,12 @@ PuppetLint.new_check(:arrow_alignment) do
|
|
226
215
|
problem[:token].prev_code_token.prev_token.value = ' ' * problem[:newline_indent]
|
227
216
|
end
|
228
217
|
|
218
|
+
end_param_idx = tokens.index(problem[:token].prev_code_token)
|
219
|
+
start_param_idx = tokens.index(problem[:token].prev_token_of([:INDENT, :NEWLINE])) + 1
|
220
|
+
param_length = tokens[start_param_idx..end_param_idx].map { |r| r.to_manifest.length }.inject(0) { |sum,x| sum + x }
|
221
|
+
new_ws_len = (problem[:arrow_column] - (problem[:newline_indent] + param_length + 1))
|
222
|
+
new_ws = ' ' * new_ws_len
|
223
|
+
|
229
224
|
if problem[:token].prev_token.type == :WHITESPACE
|
230
225
|
problem[:token].prev_token.value = new_ws
|
231
226
|
else
|
data/lib/puppet-lint/version.rb
CHANGED