puppet-lint 2.3.6 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +238 -87
- data/README.md +18 -0
- data/lib/puppet-lint.rb +1 -1
- data/lib/puppet-lint/data.rb +26 -11
- data/lib/puppet-lint/lexer.rb +97 -200
- data/lib/puppet-lint/lexer/string_slurper.rb +173 -0
- data/lib/puppet-lint/lexer/token.rb +8 -0
- data/lib/puppet-lint/optparser.rb +4 -5
- data/lib/puppet-lint/plugins/check_classes/parameter_order.rb +12 -1
- data/lib/puppet-lint/plugins/check_conditionals/case_without_default.rb +15 -1
- data/lib/puppet-lint/plugins/check_documentation/documentation.rb +4 -0
- data/lib/puppet-lint/plugins/check_resources/ensure_first_param.rb +5 -2
- data/lib/puppet-lint/plugins/check_strings/quoted_booleans.rb +1 -0
- data/lib/puppet-lint/plugins/check_strings/variables_not_enclosed.rb +71 -0
- data/lib/puppet-lint/plugins/check_whitespace/arrow_alignment.rb +1 -1
- data/lib/puppet-lint/tasks/puppet-lint.rb +14 -0
- data/lib/puppet-lint/tasks/release_test.rb +3 -1
- data/lib/puppet-lint/version.rb +1 -1
- data/spec/fixtures/test/manifests/two_warnings.pp +5 -0
- data/spec/puppet-lint/bin_spec.rb +47 -6
- data/spec/puppet-lint/data_spec.rb +12 -0
- data/spec/puppet-lint/lexer/string_slurper_spec.rb +473 -0
- data/spec/puppet-lint/lexer_spec.rb +1153 -590
- data/spec/puppet-lint/plugins/check_classes/parameter_order_spec.rb +18 -0
- data/spec/puppet-lint/plugins/check_classes/variable_scope_spec.rb +15 -1
- data/spec/puppet-lint/plugins/check_conditionals/case_without_default_spec.rb +39 -0
- data/spec/puppet-lint/plugins/check_documentation/documentation_spec.rb +18 -0
- data/spec/puppet-lint/plugins/check_resources/ensure_first_param_spec.rb +16 -0
- data/spec/puppet-lint/plugins/check_strings/double_quoted_strings_spec.rb +5 -5
- data/spec/puppet-lint/plugins/check_strings/only_variable_string_spec.rb +6 -6
- data/spec/puppet-lint/plugins/check_strings/variables_not_enclosed_spec.rb +32 -0
- data/spec/puppet-lint/plugins/check_variables/variable_is_lowercase_spec.rb +28 -0
- data/spec/spec_helper.rb +7 -5
- metadata +14 -17
- data/.gitignore +0 -12
- data/.rspec +0 -2
- data/.rubocop.yml +0 -74
- data/.rubocop_todo.yml +0 -89
- data/.travis.yml +0 -24
- data/Gemfile +0 -40
- data/Rakefile +0 -42
- data/appveyor.yml +0 -33
- data/puppet-lint.gemspec +0 -19
data/README.md
CHANGED
@@ -120,6 +120,18 @@ Or to specify a whitelist of allowed checks, include a line like:
|
|
120
120
|
--only-checks=trailing_whitespace,hard_tabs,duplicate_params,double_quoted_strings,unquoted_file_mode,only_variable_string,variables_not_enclosed,single_quote_string_with_variables,variable_contains_dash,ensure_not_symlink_target,unquoted_resource_title,relative_classname_inclusion,file_mode,resource_reference_without_title_capital,leading_zero,arrow_alignment,variable_is_lowercase,ensure_first_param,resource_reference_without_whitespace,file_ensure,trailing_comma,leading_zero
|
121
121
|
```
|
122
122
|
|
123
|
+
Please note that there is an important difference between reading options from the command line and reading options from a configuration file: In the former case the shell interprets one level of quotes. That does not happen in the latter case. So, it would make sense to quote some configuration values on the command line, like so:
|
124
|
+
|
125
|
+
```
|
126
|
+
$ puppet-lint --ignore-paths 'modules/stdlib/*' modules/
|
127
|
+
```
|
128
|
+
|
129
|
+
When reading from a configuration file those quotes would be passed on to the option parser -- probably not giving the expected result. Instead the line should read
|
130
|
+
|
131
|
+
```
|
132
|
+
--ignore-paths=modules/stdlib/*
|
133
|
+
```
|
134
|
+
|
123
135
|
## Testing with Puppet Lint as a Rake task
|
124
136
|
|
125
137
|
To test your entire Puppet manifest directory, add `require 'puppet-lint/tasks/puppet-lint'` to your Rakefile and then run:
|
@@ -195,6 +207,12 @@ You can also disable checks when running Puppet Lint through the supplied Rake t
|
|
195
207
|
PuppetLint.configuration.pattern = "modules"
|
196
208
|
```
|
197
209
|
|
210
|
+
## Testing with Puppet Lint as a GitHub Action
|
211
|
+
|
212
|
+
There is a GitHub Actions action available to get linter feedback in workflows:
|
213
|
+
|
214
|
+
* [puppet-lint-action](https://github.com/marketplace/actions/puppet-lint-action)
|
215
|
+
|
198
216
|
## Options
|
199
217
|
|
200
218
|
See `puppet-lint --help` for a full list of command line options and checks.
|
data/lib/puppet-lint.rb
CHANGED
@@ -100,9 +100,9 @@ class PuppetLint
|
|
100
100
|
# Returns a format String to be used with String#%.
|
101
101
|
def log_format
|
102
102
|
if configuration.log_format.nil? || configuration.log_format.empty?
|
103
|
-
## recreate previous old log format as far as thats possible.
|
104
103
|
format = '%{KIND}: %{message} on line %{line}'
|
105
104
|
format.prepend('%{path} - ') if configuration.with_filename
|
105
|
+
format.concat(' (check: %{check})')
|
106
106
|
configuration.log_format = format
|
107
107
|
end
|
108
108
|
|
data/lib/puppet-lint/data.rb
CHANGED
@@ -171,21 +171,21 @@ class PuppetLint::Data
|
|
171
171
|
tokens.select { |t| t.type == :COLON }.each do |colon_token|
|
172
172
|
next unless colon_token.next_code_token && colon_token.next_code_token.type != :LBRACE
|
173
173
|
|
174
|
-
|
175
|
-
|
174
|
+
rel_start_idx = tokens[marker..-1].index(colon_token)
|
175
|
+
break if rel_start_idx.nil?
|
176
|
+
start_idx = rel_start_idx + marker
|
176
177
|
end_token = colon_token.next_token_of([:SEMIC, :RBRACE])
|
177
|
-
|
178
|
-
|
179
|
-
|
178
|
+
rel_end_idx = tokens[start_idx..-1].index(end_token)
|
179
|
+
raise PuppetLint::SyntaxError, colon_token if rel_end_idx.nil?
|
180
|
+
marker = rel_end_idx + start_idx
|
180
181
|
|
181
182
|
result << {
|
182
183
|
:start => start_idx + 1,
|
183
|
-
:end =>
|
184
|
-
:tokens => tokens[start_idx..
|
184
|
+
:end => marker,
|
185
|
+
:tokens => tokens[start_idx..marker],
|
185
186
|
:type => find_resource_type_token(start_idx),
|
186
|
-
:param_tokens => find_resource_param_tokens(tokens[start_idx..
|
187
|
+
:param_tokens => find_resource_param_tokens(tokens[start_idx..marker]),
|
187
188
|
}
|
188
|
-
marker = end_idx
|
189
189
|
end
|
190
190
|
result
|
191
191
|
end
|
@@ -201,6 +201,9 @@ class PuppetLint::Data
|
|
201
201
|
lbrace_idx = tokens[0..index].rindex do |token|
|
202
202
|
token.type == :LBRACE && token.prev_code_token.type != :QMARK
|
203
203
|
end
|
204
|
+
|
205
|
+
raise PuppetLint::SyntaxError, tokens[index] if lbrace_idx.nil?
|
206
|
+
|
204
207
|
tokens[lbrace_idx].prev_code_token
|
205
208
|
end
|
206
209
|
|
@@ -212,9 +215,21 @@ class PuppetLint::Data
|
|
212
215
|
#
|
213
216
|
# Returns an Array of Token objects.
|
214
217
|
def find_resource_param_tokens(resource_tokens)
|
215
|
-
|
216
|
-
|
218
|
+
param_tokens = []
|
219
|
+
|
220
|
+
iter_token = resource_tokens.first.prev_token
|
221
|
+
|
222
|
+
until iter_token.nil?
|
223
|
+
iter_token = iter_token.next_token_of(:NAME)
|
224
|
+
|
225
|
+
break unless resource_tokens.include?(iter_token)
|
226
|
+
|
227
|
+
if iter_token && iter_token.next_code_token.type == :FARROW
|
228
|
+
param_tokens << iter_token
|
229
|
+
end
|
217
230
|
end
|
231
|
+
|
232
|
+
param_tokens
|
218
233
|
end
|
219
234
|
|
220
235
|
# Internal: Calculate the positions of all class definitions within the
|
data/lib/puppet-lint/lexer.rb
CHANGED
@@ -2,8 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'pp'
|
4
4
|
require 'strscan'
|
5
|
-
require 'puppet-lint/lexer/token'
|
6
5
|
require 'set'
|
6
|
+
require 'puppet-lint/lexer/token'
|
7
|
+
require 'puppet-lint/lexer/string_slurper'
|
7
8
|
|
8
9
|
class PuppetLint
|
9
10
|
# Internal: A generic error thrown by the lexer when it encounters something
|
@@ -28,11 +29,15 @@ class PuppetLint
|
|
28
29
|
@column = column
|
29
30
|
@reason = reason
|
30
31
|
end
|
32
|
+
|
33
|
+
def to_s
|
34
|
+
"PuppetLint::LexerError: Line:#{line_no} Column: #{column} Reason: #{reason}"
|
35
|
+
end
|
31
36
|
end
|
32
37
|
|
33
38
|
# Internal: The puppet-lint lexer. Converts your manifest into its tokenised
|
34
39
|
# form.
|
35
|
-
class Lexer
|
40
|
+
class Lexer
|
36
41
|
def initialize
|
37
42
|
@line_no = 1
|
38
43
|
@column = 1
|
@@ -99,18 +104,32 @@ class PuppetLint
|
|
99
104
|
:IF => true,
|
100
105
|
:ELSIF => true,
|
101
106
|
:LPAREN => true,
|
107
|
+
:EQUALS => true,
|
102
108
|
}.freeze
|
103
109
|
|
110
|
+
# Internal: some commonly used regular expressions
|
111
|
+
# \t == tab
|
112
|
+
# \v == vertical tab
|
113
|
+
# \f == form feed
|
114
|
+
# \p{Zs} == ASCII + Unicode non-linebreaking whitespace
|
115
|
+
WHITESPACE_RE = RUBY_VERSION == '1.8.7' ? %r{[\t\v\f ]} : %r{[\t\v\f\p{Zs}]}
|
116
|
+
|
117
|
+
LINE_END_RE = %r{(?:\r\n|\r|\n)}
|
118
|
+
|
119
|
+
NAME_RE = %r{\A((?:(?:::)?[_a-z0-9][-\w]*)(?:::[a-z0-9][-\w]*)*)}
|
120
|
+
|
104
121
|
# Internal: An Array of Arrays containing tokens that can be described by
|
105
122
|
# a single regular expression. Each sub-Array contains 2 elements, the
|
106
123
|
# name of the token as a Symbol and a regular expression describing the
|
107
124
|
# value of the token.
|
108
|
-
NAME_RE = %r{\A(((::)?[_a-z0-9][-\w]*)(::[a-z0-9][-\w]*)*)}
|
109
125
|
KNOWN_TOKENS = [
|
110
|
-
[:
|
126
|
+
[:WHITESPACE, %r{\A(#{WHITESPACE_RE}+)}],
|
127
|
+
# FIXME: Future breaking change, the following :TYPE tokens conflict with
|
128
|
+
# the :TYPE keyword token.
|
129
|
+
[:TYPE, %r{\A(Integer|Float|Boolean|Regexp|String|Array|Hash|Resource|Class|Collection|Scalar|Numeric|CatalogEntry|Data|Tuple|Struct|Optional|NotUndef|Variant|Enum|Pattern|Any|Callable|Type|Runtime|Undef|Default|Sensitive)\b}], # rubocop:disable Metrics/LineLength
|
111
130
|
[:CLASSREF, %r{\A(((::){0,1}[A-Z][-\w]*)+)}],
|
112
131
|
[:NUMBER, %r{\A\b((?:0[xX][0-9A-Fa-f]+|0?\d+(?:\.\d+)?(?:[eE]-?\d+)?))\b}],
|
113
|
-
[:FUNCTION_NAME, %r{#{NAME_RE}
|
132
|
+
[:FUNCTION_NAME, %r{#{NAME_RE}(?=\()}],
|
114
133
|
[:NAME, NAME_RE],
|
115
134
|
[:LBRACK, %r{\A(\[)}],
|
116
135
|
[:RBRACK, %r{\A(\])}],
|
@@ -166,14 +185,6 @@ class PuppetLint
|
|
166
185
|
:INDENT => true,
|
167
186
|
}.freeze
|
168
187
|
|
169
|
-
# \t == tab
|
170
|
-
# \v == vertical tab
|
171
|
-
# \f == form feed
|
172
|
-
# \p{Zs} == ASCII + Unicode non-linebreaking whitespace
|
173
|
-
WHITESPACE_RE = RUBY_VERSION == '1.8.7' ? %r{[\t\v\f ]} : %r{[\t\v\f\p{Zs}]}
|
174
|
-
|
175
|
-
LINE_END_RE = %r{(?:\r\n|\r|\n)}
|
176
|
-
|
177
188
|
# Internal: Access the internal token storage.
|
178
189
|
#
|
179
190
|
# Returns an Array of PuppetLint::Lexer::Toxen objects.
|
@@ -200,13 +211,12 @@ class PuppetLint
|
|
200
211
|
value = chunk[regex, 1]
|
201
212
|
next if value.nil?
|
202
213
|
|
203
|
-
|
214
|
+
i += value.size
|
204
215
|
tokens << if type == :NAME && KEYWORDS.include?(value)
|
205
216
|
new_token(value.upcase.to_sym, value)
|
206
217
|
else
|
207
218
|
new_token(type, value)
|
208
219
|
end
|
209
|
-
i += length
|
210
220
|
found = true
|
211
221
|
break
|
212
222
|
end
|
@@ -215,7 +225,12 @@ class PuppetLint
|
|
215
225
|
|
216
226
|
if var_name = chunk[%r{\A\$((::)?(\w+(-\w+)*::)*\w+(-\w+)*(\[.+?\])*)}, 1]
|
217
227
|
length = var_name.size + 1
|
218
|
-
|
228
|
+
opts = if chunk.start_with?('$')
|
229
|
+
{ :raw => "$#{var_name}" }
|
230
|
+
else
|
231
|
+
{}
|
232
|
+
end
|
233
|
+
tokens << new_token(:VARIABLE, var_name, opts)
|
219
234
|
|
220
235
|
elsif chunk =~ %r{\A'.*?'}m
|
221
236
|
str_content = StringScanner.new(code[i + 1..-1]).scan_until(%r{(\A|[^\\])(\\\\)*'}m)
|
@@ -223,12 +238,16 @@ class PuppetLint
|
|
223
238
|
tokens << new_token(:SSTRING, str_content[0..-2])
|
224
239
|
|
225
240
|
elsif chunk.start_with?('"')
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
241
|
+
slurper = PuppetLint::Lexer::StringSlurper.new(code[i + 1..-1])
|
242
|
+
begin
|
243
|
+
string_segments = slurper.parse
|
244
|
+
process_string_segments(string_segments)
|
245
|
+
length = slurper.consumed_chars + 1
|
246
|
+
rescue PuppetLint::Lexer::StringSlurper::UnterminatedStringError
|
247
|
+
raise PuppetLint::LexerError.new(@line_no, @column, 'unterminated string')
|
248
|
+
end
|
230
249
|
|
231
|
-
elsif heredoc_name = chunk[%r{\A@\(("?.+?"?(:.+?)
|
250
|
+
elsif heredoc_name = chunk[%r{\A@\(("?.+?"?(:.+?)?#{WHITESPACE_RE}*(/.*?)?)\)}, 1]
|
232
251
|
heredoc_queue << heredoc_name
|
233
252
|
tokens << new_token(:HEREDOC_OPEN, heredoc_name)
|
234
253
|
length = heredoc_name.size + 3
|
@@ -251,7 +270,7 @@ class PuppetLint
|
|
251
270
|
mlcomment.gsub!(%r{^ *\*}, '')
|
252
271
|
tokens << new_token(:MLCOMMENT, mlcomment, :raw => mlcomment_raw)
|
253
272
|
|
254
|
-
elsif chunk.match(%r{\A/.*?/}) && possible_regex?
|
273
|
+
elsif chunk.match(%r{\A/.*?/}m) && possible_regex?
|
255
274
|
str_content = StringScanner.new(code[i + 1..-1]).scan_until(%r{(\A|[^\\])(\\\\)*/}m)
|
256
275
|
length = str_content.size + 1
|
257
276
|
tokens << new_token(:REGEX, str_content[0..-2])
|
@@ -267,27 +286,22 @@ class PuppetLint
|
|
267
286
|
length += indent.size
|
268
287
|
else
|
269
288
|
heredoc_tag = heredoc_queue.shift
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
length +=
|
289
|
+
slurper = PuppetLint::Lexer::StringSlurper.new(code[i + length..-1])
|
290
|
+
heredoc_segments = slurper.parse_heredoc(heredoc_tag)
|
291
|
+
process_heredoc_segments(heredoc_segments)
|
292
|
+
length += slurper.consumed_chars
|
274
293
|
end
|
275
294
|
|
276
|
-
elsif whitespace = chunk[%r{\A(#{WHITESPACE_RE}+)}, 1]
|
277
|
-
length = whitespace.size
|
278
|
-
tokens << new_token(:WHITESPACE, whitespace)
|
279
|
-
|
280
295
|
elsif eol = chunk[%r{\A(#{LINE_END_RE})}, 1]
|
281
296
|
length = eol.size
|
282
297
|
tokens << new_token(:NEWLINE, eol)
|
283
298
|
|
284
299
|
unless heredoc_queue.empty?
|
285
300
|
heredoc_tag = heredoc_queue.shift
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
length += str_contents.size
|
301
|
+
slurper = PuppetLint::Lexer::StringSlurper.new(code[i + length..-1])
|
302
|
+
heredoc_segments = slurper.parse_heredoc(heredoc_tag)
|
303
|
+
process_heredoc_segments(heredoc_segments)
|
304
|
+
length += slurper.consumed_chars
|
291
305
|
end
|
292
306
|
|
293
307
|
elsif chunk.start_with?('/')
|
@@ -308,22 +322,6 @@ class PuppetLint
|
|
308
322
|
tokens
|
309
323
|
end
|
310
324
|
|
311
|
-
def slurp_string(string)
|
312
|
-
dq_str_regexp = %r{(\$\{|(\A|[^\\])(\\\\)*")}m
|
313
|
-
scanner = StringScanner.new(string)
|
314
|
-
contents = scanner.scan_until(dq_str_regexp)
|
315
|
-
|
316
|
-
if scanner.matched.nil?
|
317
|
-
raise LexerError.new(@line_no, @column, 'Double quoted string missing closing quote')
|
318
|
-
end
|
319
|
-
|
320
|
-
until scanner.matched.end_with?('"')
|
321
|
-
contents += scanner.scan_until(%r{\}}m)
|
322
|
-
contents += scanner.scan_until(dq_str_regexp)
|
323
|
-
end
|
324
|
-
contents
|
325
|
-
end
|
326
|
-
|
327
325
|
# Internal: Given the tokens already processed, determine if the next token
|
328
326
|
# could be a regular expression.
|
329
327
|
#
|
@@ -403,167 +401,66 @@ class PuppetLint
|
|
403
401
|
token
|
404
402
|
end
|
405
403
|
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
#
|
413
|
-
# Returns an Array consisting of two Strings, the String up to the first
|
414
|
-
# terminator and the terminator that was found.
|
415
|
-
def get_string_segment(string, terminators)
|
416
|
-
str = string.scan_until(%r{([^\\]|^|[^\\])([\\]{2})*[#{terminators}]+})
|
417
|
-
begin
|
418
|
-
[str[0..-2], str[-1, 1]]
|
419
|
-
rescue
|
420
|
-
[nil, nil]
|
404
|
+
def process_string_segments(segments)
|
405
|
+
return if segments.empty?
|
406
|
+
|
407
|
+
if segments.length == 1
|
408
|
+
tokens << new_token(:STRING, segments[0][1])
|
409
|
+
return
|
421
410
|
end
|
422
|
-
end
|
423
411
|
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
if terminator == '"'
|
437
|
-
if first
|
438
|
-
tokens << new_token(:STRING, value, :line => line, :column => column)
|
439
|
-
first = false
|
440
|
-
else
|
441
|
-
token_column = column + (ss.pos - value.size)
|
442
|
-
tokens << new_token(:DQPOST, value, :line => line, :column => token_column)
|
443
|
-
line += value.scan(LINE_END_RE).size
|
444
|
-
@column = column + ss.pos + 1
|
445
|
-
@line_no = line
|
412
|
+
pre_segment = segments.delete_at(0)
|
413
|
+
post_segment = segments.delete_at(-1)
|
414
|
+
|
415
|
+
tokens << new_token(:DQPRE, pre_segment[1])
|
416
|
+
segments.each do |segment|
|
417
|
+
case segment[0]
|
418
|
+
when :INTERP
|
419
|
+
lexer = PuppetLint::Lexer.new
|
420
|
+
lexer.tokenise(segment[1])
|
421
|
+
lexer.tokens.each_with_index do |t, i|
|
422
|
+
type = i.zero? && t.interpolated_variable? ? :VARIABLE : t.type
|
423
|
+
tokens << new_token(type, t.value, :raw => t.raw)
|
446
424
|
end
|
425
|
+
when :UNENC_VAR
|
426
|
+
tokens << new_token(:UNENC_VARIABLE, segment[1].gsub(%r{\A\$}, ''))
|
447
427
|
else
|
448
|
-
|
449
|
-
tokens << new_token(:DQPRE, value, :line => line, :column => column)
|
450
|
-
first = false
|
451
|
-
else
|
452
|
-
token_column = column + (ss.pos - value.size)
|
453
|
-
tokens << new_token(:DQMID, value, :line => line, :column => token_column)
|
454
|
-
line += value.scan(LINE_END_RE).size
|
455
|
-
end
|
456
|
-
if ss.scan(%r{\{}).nil?
|
457
|
-
var_name = ss.scan(%r{(::)?(\w+(-\w+)*::)*\w+(-\w+)*})
|
458
|
-
if var_name.nil?
|
459
|
-
token_column = column + ss.pos - 1
|
460
|
-
tokens << new_token(:DQMID, '$', :line => line, :column => token_column)
|
461
|
-
else
|
462
|
-
token_column = column + (ss.pos - var_name.size)
|
463
|
-
tokens << new_token(:UNENC_VARIABLE, var_name, :line => line, :column => token_column)
|
464
|
-
end
|
465
|
-
else
|
466
|
-
line += value.scan(LINE_END_RE).size
|
467
|
-
contents = ss.scan_until(%r{\}})[0..-2]
|
468
|
-
raw = contents.dup
|
469
|
-
if contents.match(%r{\A(::)?([\w-]+::)*[\w-]+(\[.+?\])*}) && !contents.match(%r{\A\w+\(})
|
470
|
-
contents = "$#{contents}"
|
471
|
-
end
|
472
|
-
lexer = PuppetLint::Lexer.new
|
473
|
-
lexer.tokenise(contents)
|
474
|
-
lexer.tokens.each do |token|
|
475
|
-
tok_col = column + token.column + (ss.pos - contents.size - 1)
|
476
|
-
tok_line = token.line + line - 1
|
477
|
-
tokens << new_token(token.type, token.value, :line => tok_line, :column => tok_col)
|
478
|
-
end
|
479
|
-
if lexer.tokens.length == 1 && lexer.tokens[0].type == :VARIABLE
|
480
|
-
tokens.last.raw = raw
|
481
|
-
end
|
482
|
-
end
|
428
|
+
tokens << new_token(:DQMID, segment[1])
|
483
429
|
end
|
484
|
-
value, terminator = get_string_segment(ss, '"$')
|
485
430
|
end
|
431
|
+
tokens << new_token(:DQPOST, post_segment[1])
|
486
432
|
end
|
487
433
|
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
434
|
+
def process_heredoc_segments(segments)
|
435
|
+
return if segments.empty?
|
436
|
+
|
437
|
+
end_tag = segments.delete_at(-1)
|
438
|
+
|
439
|
+
if segments.length == 1
|
440
|
+
tokens << new_token(:HEREDOC, segments[0][1], :raw => "#{segments[0][1]}#{end_tag[1]}")
|
441
|
+
return
|
442
|
+
end
|
443
|
+
|
444
|
+
pre_segment = segments.delete_at(0)
|
445
|
+
post_segment = segments.delete_at(-1)
|
446
|
+
|
447
|
+
tokens << new_token(:HEREDOC_PRE, pre_segment[1])
|
448
|
+
segments.each do |segment|
|
449
|
+
case segment[0]
|
450
|
+
when :INTERP
|
451
|
+
lexer = PuppetLint::Lexer.new
|
452
|
+
lexer.tokenise(segment[1])
|
453
|
+
lexer.tokens.each_with_index do |t, i|
|
454
|
+
type = i.zero? && t.interpolated_variable? ? :VARIABLE : t.type
|
455
|
+
tokens << new_token(type, t.value, :raw => t.raw)
|
507
456
|
end
|
457
|
+
when :UNENC_VAR
|
458
|
+
tokens << new_token(:UNENC_VARIABLE, segment[1].gsub(%r{\A\$}, ''))
|
508
459
|
else
|
509
|
-
|
510
|
-
tokens << new_token(:HEREDOC_PRE, value)
|
511
|
-
first = false
|
512
|
-
else
|
513
|
-
tokens << new_token(:HEREDOC_MID, value)
|
514
|
-
end
|
515
|
-
if ss.scan(%r{\{}).nil?
|
516
|
-
var_name = ss.scan(%r{(::)?(\w+(-\w+)*::)*\w+(-\w+)*})
|
517
|
-
tokens << if var_name.nil?
|
518
|
-
new_token(:HEREDOC_MID, '$')
|
519
|
-
else
|
520
|
-
new_token(:UNENC_VARIABLE, var_name)
|
521
|
-
end
|
522
|
-
else
|
523
|
-
contents = ss.scan_until(%r{\}})[0..-2]
|
524
|
-
raw = contents.dup
|
525
|
-
if contents.match(%r{\A(::)?([\w-]+::)*[\w-]|(\[.+?\])*}) && !contents.match(%r{\A\w+\(})
|
526
|
-
contents = "$#{contents}" unless contents.start_with?('$')
|
527
|
-
end
|
528
|
-
|
529
|
-
lexer = PuppetLint::Lexer.new
|
530
|
-
lexer.tokenise(contents)
|
531
|
-
lexer.tokens.each do |token|
|
532
|
-
tokens << new_token(token.type, token.value)
|
533
|
-
end
|
534
|
-
if lexer.tokens.length == 1 && lexer.tokens[0].type == :VARIABLE
|
535
|
-
tokens.last.raw = raw
|
536
|
-
end
|
537
|
-
end
|
460
|
+
tokens << new_token(:HEREDOC_MID, segment[1])
|
538
461
|
end
|
539
|
-
value, terminator = get_heredoc_segment(ss, eos_text, interpolate)
|
540
|
-
end
|
541
|
-
end
|
542
|
-
|
543
|
-
# Internal: Splits a heredoc String into segments if it is to be
|
544
|
-
# interpolated.
|
545
|
-
#
|
546
|
-
# string - The String heredoc.
|
547
|
-
# eos_text - The String endtext for the heredoc.
|
548
|
-
# interpolate - A Boolean that specifies whether this heredoc can contain
|
549
|
-
# interpolated values (defaults to True).
|
550
|
-
#
|
551
|
-
# Returns an Array consisting of two Strings, the String up to the first
|
552
|
-
# terminator and the terminator that was found.
|
553
|
-
def get_heredoc_segment(string, eos_text, interpolate = true)
|
554
|
-
regexp = if interpolate
|
555
|
-
%r{(([^\\]|^|[^\\])([\\]{2})*[$]+|\|?\s*-?#{Regexp.escape(eos_text)})}
|
556
|
-
else
|
557
|
-
%r{\|?\s*-?#{Regexp.escape(eos_text)}}
|
558
|
-
end
|
559
|
-
|
560
|
-
str = string.scan_until(regexp)
|
561
|
-
begin
|
562
|
-
str =~ %r{\A(.*?)([$]+|\|?\s*-?#{Regexp.escape(eos_text)})\Z}m
|
563
|
-
[Regexp.last_match(1), Regexp.last_match(2)]
|
564
|
-
rescue
|
565
|
-
[nil, nil]
|
566
462
|
end
|
463
|
+
tokens << new_token(:HEREDOC_POST, post_segment[1], :raw => "#{post_segment[1]}#{end_tag[1]}")
|
567
464
|
end
|
568
465
|
end
|
569
466
|
end
|