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