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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d618e442c08c4d3e79853fc370348c9ee8e8970
|
4
|
+
data.tar.gz: 82099093c21a374e137a39bd0323443e16015e95
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 179cd2b6f7ada144261bf630064a4ca26a212d3693fba9244a9a4fbd2b8c75ec78f6935f50175845bf2d743e53671f19c683e9e5ccb14b950e7d6e9e86c269d4
|
7
|
+
data.tar.gz: 8d5f9a973d53c47e8ce6a7caac88c4aa8ab7637e95221e95676b7adf40b8cc8c2ed9b615d09f19857aeadbc36d7629d86518ba644fbaf08845050ae2c2018201
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,65 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## [2.2.0](https://github.com/rodjek/puppet-lint/tree/2.2.0) (2017-03-29)
|
4
|
+
[Full Changelog](https://github.com/rodjek/puppet-lint/compare/2.1.1...2.2.0)
|
5
|
+
|
6
|
+
**Closed issues:**
|
7
|
+
|
8
|
+
- Missed bad file modes in file with multiple resource bodies [\#663](https://github.com/rodjek/puppet-lint/issues/663)
|
9
|
+
- Provide helper methods to search for specific tokens [\#660](https://github.com/rodjek/puppet-lint/issues/660)
|
10
|
+
- ensure\_first\_param fix can create invalid syntax [\#659](https://github.com/rodjek/puppet-lint/issues/659)
|
11
|
+
- puppet-lint dies with inline\_template syntax [\#656](https://github.com/rodjek/puppet-lint/issues/656)
|
12
|
+
- Variable use like "${$a}" isn't reported as an error and is changed with no message when run with --fix [\#655](https://github.com/rodjek/puppet-lint/issues/655)
|
13
|
+
- Linter gets confused with arrays of hashes [\#654](https://github.com/rodjek/puppet-lint/issues/654)
|
14
|
+
- 2.1.1 git tag [\#652](https://github.com/rodjek/puppet-lint/issues/652)
|
15
|
+
- heredoc throws unhandled exception [\#649](https://github.com/rodjek/puppet-lint/issues/649)
|
16
|
+
- Quoted boolean triggers on the command 'true' [\#646](https://github.com/rodjek/puppet-lint/issues/646)
|
17
|
+
- Match function breaks puppet-lint [\#645](https://github.com/rodjek/puppet-lint/issues/645)
|
18
|
+
- top-scope variable being used without an explicit namespace in a string with a lookup [\#635](https://github.com/rodjek/puppet-lint/issues/635)
|
19
|
+
- unquoted file mode & mode should be represented as a 4 digit when file mode is done by a lookup [\#634](https://github.com/rodjek/puppet-lint/issues/634)
|
20
|
+
- Namevars detected as optional parameters [\#633](https://github.com/rodjek/puppet-lint/issues/633)
|
21
|
+
- 'Duplicate Parameter' warning on dynamic class parameter [\#627](https://github.com/rodjek/puppet-lint/issues/627)
|
22
|
+
- double\_quoted\_strings-check issue with escaped character in the string [\#625](https://github.com/rodjek/puppet-lint/issues/625)
|
23
|
+
- unable to disable 140chars check with control comments "block" [\#622](https://github.com/rodjek/puppet-lint/issues/622)
|
24
|
+
- arrow\_alignment should only check the alignment of the first arrow on each line [\#609](https://github.com/rodjek/puppet-lint/issues/609)
|
25
|
+
- unquoted\_node\_name crash when curly braces missing [\#582](https://github.com/rodjek/puppet-lint/issues/582)
|
26
|
+
- Heredoc triggers exception in arrow\_alignment check [\#578](https://github.com/rodjek/puppet-lint/issues/578)
|
27
|
+
- Each + With = Fake positive top-scope variable detection [\#576](https://github.com/rodjek/puppet-lint/issues/576)
|
28
|
+
- Top-scope variable warning on inline lambda [\#549](https://github.com/rodjek/puppet-lint/issues/549)
|
29
|
+
- Top-scope variable warning on nested each loops [\#548](https://github.com/rodjek/puppet-lint/issues/548)
|
30
|
+
- Puppet-lint crash with new puppet 4 syntax [\#516](https://github.com/rodjek/puppet-lint/issues/516)
|
31
|
+
- `arrow\_alignment --fix` doesn't indent keys when introducing line breaks; erroneously reports success [\#506](https://github.com/rodjek/puppet-lint/issues/506)
|
32
|
+
- Top-scope warning when looping though an array of hashes [\#464](https://github.com/rodjek/puppet-lint/issues/464)
|
33
|
+
- Array of hashes one-liner throws a "Indentation of =\> is not properly aligned" [\#446](https://github.com/rodjek/puppet-lint/issues/446)
|
34
|
+
- heredoc escape gives syntax error [\#430](https://github.com/rodjek/puppet-lint/issues/430)
|
35
|
+
- NoMethodError when multiple heredocs are used [\#395](https://github.com/rodjek/puppet-lint/issues/395)
|
36
|
+
|
37
|
+
**Merged pull requests:**
|
38
|
+
|
39
|
+
- Ignore selectors when finding resource type [\#678](https://github.com/rodjek/puppet-lint/pull/678) ([rodjek](https://github.com/rodjek))
|
40
|
+
- Fix for arrow\_alignment bugs in \#506 [\#677](https://github.com/rodjek/puppet-lint/pull/677) ([rodjek](https://github.com/rodjek))
|
41
|
+
- Support double quoted strings inside interpolated values in double quoted strings [\#676](https://github.com/rodjek/puppet-lint/pull/676) ([rodjek](https://github.com/rodjek))
|
42
|
+
- Don't silently remove unnecessary $ from enclosed variables [\#674](https://github.com/rodjek/puppet-lint/pull/674) ([rodjek](https://github.com/rodjek))
|
43
|
+
- Fix ensure\_first\_param fix method to retrieve the full value of the ensure parameter [\#673](https://github.com/rodjek/puppet-lint/pull/673) ([rodjek](https://github.com/rodjek))
|
44
|
+
- Check that arrow is on the line of right operand [\#672](https://github.com/rodjek/puppet-lint/pull/672) ([Darhazer](https://github.com/Darhazer))
|
45
|
+
- Restrict appveyor testing to Ruby versions that appveyor supports [\#670](https://github.com/rodjek/puppet-lint/pull/670) ([james-stocks](https://github.com/james-stocks))
|
46
|
+
- Clear expected parameter column after processing each block when checking arrow alignment [\#669](https://github.com/rodjek/puppet-lint/pull/669) ([rodjek](https://github.com/rodjek))
|
47
|
+
- Allow regexps to used as function arguments [\#665](https://github.com/rodjek/puppet-lint/pull/665) ([rodjek](https://github.com/rodjek))
|
48
|
+
- Catch unhandled exception and provide debug info for issue [\#664](https://github.com/rodjek/puppet-lint/pull/664) ([rodjek](https://github.com/rodjek))
|
49
|
+
- Fix showing of a failure [\#662](https://github.com/rodjek/puppet-lint/pull/662) ([Darhazer](https://github.com/Darhazer))
|
50
|
+
- \(SDK-115\) Enable appveyor testing [\#653](https://github.com/rodjek/puppet-lint/pull/653) ([james-stocks](https://github.com/james-stocks))
|
51
|
+
- Heredoc support [\#650](https://github.com/rodjek/puppet-lint/pull/650) ([rodjek](https://github.com/rodjek))
|
52
|
+
- Warn when control comment blocks are not properly terminated [\#648](https://github.com/rodjek/puppet-lint/pull/648) ([rodjek](https://github.com/rodjek))
|
53
|
+
- Prevent incomplete node blocks from crashing puppet-lint [\#642](https://github.com/rodjek/puppet-lint/pull/642) ([rodjek](https://github.com/rodjek))
|
54
|
+
- Update the tokeniser to differentiate between unquoted strings and function names [\#640](https://github.com/rodjek/puppet-lint/pull/640) ([rodjek](https://github.com/rodjek))
|
55
|
+
- Check for escaped backslashes too [\#639](https://github.com/rodjek/puppet-lint/pull/639) ([binford2k](https://github.com/binford2k))
|
56
|
+
- Correctly handle function calls inside string interpolation [\#638](https://github.com/rodjek/puppet-lint/pull/638) ([hanazuki](https://github.com/hanazuki))
|
57
|
+
- Correctly handle nested lambdas [\#637](https://github.com/rodjek/puppet-lint/pull/637) ([hanazuki](https://github.com/hanazuki))
|
58
|
+
- Support for nested multiple-variable assignments [\#636](https://github.com/rodjek/puppet-lint/pull/636) ([hanazuki](https://github.com/hanazuki))
|
59
|
+
- Add LoadError to fix broken tests [\#631](https://github.com/rodjek/puppet-lint/pull/631) ([davidmogar](https://github.com/davidmogar))
|
60
|
+
- Deal with ruby 1.8.7 gem issues [\#630](https://github.com/rodjek/puppet-lint/pull/630) ([mterzo](https://github.com/mterzo))
|
61
|
+
- Plugin review; disable unnecessary plugins [\#567](https://github.com/rodjek/puppet-lint/pull/567) ([rnelson0](https://github.com/rnelson0))
|
62
|
+
|
3
63
|
## [2.1.1](https://github.com/rodjek/puppet-lint/tree/2.1.1) (2017-02-13)
|
4
64
|
[Full Changelog](https://github.com/rodjek/puppet-lint/compare/2.1.0...2.1.1)
|
5
65
|
|
@@ -15,6 +75,7 @@
|
|
15
75
|
|
16
76
|
**Merged pull requests:**
|
17
77
|
|
78
|
+
- puppet-lint 2.1.1 release [\#628](https://github.com/rodjek/puppet-lint/pull/628) ([rnelson0](https://github.com/rnelson0))
|
18
79
|
- Correctly handle strings-with-variables as hash keys in arrow\_alignment check [\#621](https://github.com/rodjek/puppet-lint/pull/621) ([rodjek](https://github.com/rodjek))
|
19
80
|
- Support array of variables on left side of an assign operation [\#617](https://github.com/rodjek/puppet-lint/pull/617) ([rodjek](https://github.com/rodjek))
|
20
81
|
- Test against Ruby 2.4.0 [\#616](https://github.com/rodjek/puppet-lint/pull/616) ([rodjek](https://github.com/rodjek))
|
@@ -181,25 +242,6 @@
|
|
181
242
|
## [2.0.0](https://github.com/rodjek/puppet-lint/tree/2.0.0) (2016-06-22)
|
182
243
|
[Full Changelog](https://github.com/rodjek/puppet-lint/compare/1.1.0...2.0.0)
|
183
244
|
|
184
|
-
puppet-lint 2.0.0 is a breaking change. Specifically, the renaming of the line length test was changed from `80chars` to `140chars`. You may need to adjust your configuration and lint checks. For example:
|
185
|
-
```ruby
|
186
|
-
# Line length test is 80 chars in puppet-lint 1.1.0
|
187
|
-
PuppetLint.configuration.send('disable_80chars')
|
188
|
-
# Line length test is 140 chars in puppet-lint 2.x
|
189
|
-
PuppetLint.configuration.send('disable_140chars')
|
190
|
-
```
|
191
|
-
|
192
|
-
You may also need to adjust your Gemfile if you are pointing directly at git:
|
193
|
-
```ruby
|
194
|
-
# old
|
195
|
-
gem 'puppet-lint', :require => false, :git => 'https://github.com/rodjek/puppet-lint.git'
|
196
|
-
|
197
|
-
# new
|
198
|
-
gem 'puppet-lint', '~> 2.0'
|
199
|
-
```
|
200
|
-
|
201
|
-
If the additional gems you use for checks are pinned to 1.x, you should pin puppet-lint to `'~> 1.0'` or `'>= 1.0', '< 3.0'` until updated check gems are released.
|
202
|
-
|
203
245
|
**Closed issues:**
|
204
246
|
|
205
247
|
- Current package [\#471](https://github.com/rodjek/puppet-lint/issues/471)
|
data/Gemfile
CHANGED
@@ -4,7 +4,6 @@ gemspec
|
|
4
4
|
|
5
5
|
group :test do
|
6
6
|
gem 'rake', '~> 10.0'
|
7
|
-
gem 'rspec', '~> 3.0'
|
8
7
|
gem 'rspec-its', '~> 1.0'
|
9
8
|
gem 'rspec-collection_matchers', '~> 1.0'
|
10
9
|
|
@@ -15,10 +14,13 @@ group :test do
|
|
15
14
|
gem 'json_pure', '= 1.8.3'
|
16
15
|
# addressable 2.4.0 requires ruby 1.9.0. Lock to 2.3.8.
|
17
16
|
gem 'addressable', '= 2.3.8'
|
17
|
+
gem 'diff-lcs', '< 1.3'
|
18
|
+
gem 'rspec', '<= 3.4'
|
18
19
|
else
|
20
|
+
gem 'rspec', '~> 3.0'
|
19
21
|
gem 'json'
|
20
22
|
end
|
21
|
-
|
23
|
+
|
22
24
|
if RUBY_VERSION > '1.8'
|
23
25
|
# requires ruby 1.9+, on 1.8 we'll fall back to the old regex parsing
|
24
26
|
gem 'rspec-json_expectations', '~> 1.4'
|
@@ -27,7 +29,9 @@ end
|
|
27
29
|
|
28
30
|
group :development do
|
29
31
|
# For Changelog generation
|
30
|
-
|
31
|
-
|
32
|
-
|
32
|
+
if RUBY_VERSION > '1.9'
|
33
|
+
gem 'github_changelog_generator', :require => false if RUBY_VERSION >= '2.2.2'
|
34
|
+
gem 'github_changelog_generator', '~> 1.13.0', :require => false if RUBY_VERSION < '2.2.2'
|
35
|
+
gem 'rack', '~> 1.0', :require => false if RUBY_VERSION < '2.2.2'
|
36
|
+
end
|
33
37
|
end
|
data/appveyor.yml
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
build: off
|
2
|
+
|
3
|
+
branches:
|
4
|
+
only:
|
5
|
+
- master
|
6
|
+
|
7
|
+
# ruby versions under test
|
8
|
+
environment:
|
9
|
+
matrix:
|
10
|
+
- RUBY_VERSION: 193
|
11
|
+
- RUBY_VERSION: 200
|
12
|
+
- RUBY_VERSION: 21
|
13
|
+
- RUBY_VERSION: 22
|
14
|
+
- RUBY_VERSION: 23-x64
|
15
|
+
|
16
|
+
install:
|
17
|
+
- SET PATH=C:\Ruby%RUBY_VERSION%\bin;%PATH%
|
18
|
+
- SET LOG_SPEC_ORDER=true
|
19
|
+
- bundle install --jobs 4 --retry 2 --without development
|
20
|
+
|
21
|
+
before_test:
|
22
|
+
- type Gemfile.lock
|
23
|
+
- ruby -v
|
24
|
+
- gem -v
|
25
|
+
- bundle -v
|
26
|
+
|
27
|
+
test_script:
|
28
|
+
- bundle exec rake test
|
29
|
+
|
30
|
+
notifications:
|
31
|
+
email:
|
32
|
+
- tim@bombasticmonkey.com
|
@@ -21,7 +21,7 @@ class PuppetLint::CheckPlugin
|
|
21
21
|
check
|
22
22
|
|
23
23
|
@problems.each do |problem|
|
24
|
-
if PuppetLint::Data.ignore_overrides[problem[:check]].has_key?(problem[:line])
|
24
|
+
if problem[:check] != :syntax && PuppetLint::Data.ignore_overrides[problem[:check]].has_key?(problem[:line])
|
25
25
|
problem[:kind] = :ignored
|
26
26
|
problem[:reason] = PuppetLint::Data.ignore_overrides[problem[:check]][problem[:line]]
|
27
27
|
next
|
@@ -35,7 +35,7 @@ class PuppetLint::CheckPlugin
|
|
35
35
|
#
|
36
36
|
# Returns an Array of problem Hashes.
|
37
37
|
def fix_problems
|
38
|
-
@problems.reject { |problem| problem[:kind] == :ignored }.each do |problem|
|
38
|
+
@problems.reject { |problem| problem[:kind] == :ignored || problem[:check] == :syntax }.each do |problem|
|
39
39
|
if self.respond_to?(:fix)
|
40
40
|
begin
|
41
41
|
fix(problem)
|
data/lib/puppet-lint/checks.rb
CHANGED
@@ -65,6 +65,27 @@ class PuppetLint::Checks
|
|
65
65
|
end
|
66
66
|
|
67
67
|
@problems
|
68
|
+
rescue => e
|
69
|
+
puts <<-END
|
70
|
+
Whoops! It looks like puppet-lint has encountered an error that it doesn't
|
71
|
+
know how to handle. Please open an issue at https://github.com/rodjek/puppet-lint
|
72
|
+
and paste the following output into the issue description.
|
73
|
+
---
|
74
|
+
puppet-lint version: #{PuppetLint::VERSION}
|
75
|
+
ruby version: #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}
|
76
|
+
platform: #{RUBY_PLATFORM}
|
77
|
+
file path: #{fileinfo}
|
78
|
+
file contents:
|
79
|
+
```
|
80
|
+
#{File.read(fileinfo) if File.readable?(fileinfo)}
|
81
|
+
```
|
82
|
+
error:
|
83
|
+
```
|
84
|
+
#{e.class}: #{e.message}
|
85
|
+
#{e.backtrace.join("\n")}
|
86
|
+
```
|
87
|
+
END
|
88
|
+
exit 1
|
68
89
|
end
|
69
90
|
|
70
91
|
# Internal: Get a list of checks that have not been disabled.
|
data/lib/puppet-lint/data.rb
CHANGED
@@ -105,38 +105,28 @@ class PuppetLint::Data
|
|
105
105
|
# :end - An Integer position in the `tokens` Array pointing to the last
|
106
106
|
# Token of a resource declaration.
|
107
107
|
def resource_indexes
|
108
|
-
@resource_indexes ||=
|
108
|
+
@resource_indexes ||= begin
|
109
|
+
marker = 0
|
109
110
|
result = []
|
110
|
-
tokens.
|
111
|
-
if
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
:end => real_idx,
|
126
|
-
:tokens => tokens[(token_idx + 1)..real_idx],
|
127
|
-
:type => find_resource_type_token(token_idx),
|
128
|
-
:param_tokens => find_resource_param_tokens(tokens[(token_idx + 1)..real_idx]),
|
129
|
-
}
|
130
|
-
break
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
111
|
+
tokens.select { |t| t.type == :COLON }.each do |colon_token|
|
112
|
+
if colon_token.next_code_token && colon_token.next_code_token != :LBRACE
|
113
|
+
start_idx = tokens.index(colon_token)
|
114
|
+
next if start_idx < marker
|
115
|
+
end_token = colon_token.next_token_of([:SEMIC, :RBRACE])
|
116
|
+
end_idx = tokens.index(end_token)
|
117
|
+
|
118
|
+
result << {
|
119
|
+
:start => start_idx + 1,
|
120
|
+
:end => end_idx,
|
121
|
+
:tokens => tokens[start_idx..end_idx],
|
122
|
+
:type => find_resource_type_token(start_idx),
|
123
|
+
:param_tokens => find_resource_param_tokens(tokens[start_idx..end_idx]),
|
124
|
+
}
|
125
|
+
marker = end_idx
|
136
126
|
end
|
137
127
|
end
|
138
128
|
result
|
139
|
-
end
|
129
|
+
end
|
140
130
|
end
|
141
131
|
|
142
132
|
# Internal: Find the Token representing the type of a resource definition.
|
@@ -146,7 +136,10 @@ class PuppetLint::Data
|
|
146
136
|
#
|
147
137
|
# Returns a Token object.
|
148
138
|
def find_resource_type_token(index)
|
149
|
-
tokens[
|
139
|
+
lbrace_idx = tokens[0..index].rindex { |token|
|
140
|
+
token.type == :LBRACE && token.prev_code_token.type != :QMARK
|
141
|
+
}
|
142
|
+
tokens[lbrace_idx].prev_code_token
|
150
143
|
end
|
151
144
|
|
152
145
|
# Internal: Find all the Token objects representing the parameter names in
|
@@ -497,7 +490,6 @@ class PuppetLint::Data
|
|
497
490
|
|
498
491
|
if command == 'ignore'
|
499
492
|
check = split_control[2].to_sym
|
500
|
-
|
501
493
|
if token.prev_token && !Set[:NEWLINE, :INDENT].include?(token.prev_token.type)
|
502
494
|
# control comment at the end of the line, override applies to
|
503
495
|
# a single line only
|
@@ -524,6 +516,10 @@ class PuppetLint::Data
|
|
524
516
|
end
|
525
517
|
stack << stack_add unless stack_add.empty?
|
526
518
|
end
|
519
|
+
|
520
|
+
stack.each do |control|
|
521
|
+
puts "WARNING: lint:ignore:#{control[0][2]} comment on line #{control[0][0]} with no closing lint:endignore comment"
|
522
|
+
end
|
527
523
|
end
|
528
524
|
end
|
529
525
|
end
|
data/lib/puppet-lint/lexer.rb
CHANGED
@@ -29,6 +29,7 @@ class PuppetLint
|
|
29
29
|
def initialize
|
30
30
|
@line_no = 1
|
31
31
|
@column = 1
|
32
|
+
@@heredoc_queue ||= []
|
32
33
|
end
|
33
34
|
|
34
35
|
# Internal: A Hash whose keys are Strings representing reserved keywords in
|
@@ -83,17 +84,20 @@ class PuppetLint
|
|
83
84
|
:LBRACK => true,
|
84
85
|
:IF => true,
|
85
86
|
:ELSIF => true,
|
87
|
+
:LPAREN => true,
|
86
88
|
}
|
87
89
|
|
88
90
|
# Internal: An Array of Arrays containing tokens that can be described by
|
89
91
|
# a single regular expression. Each sub-Array contains 2 elements, the
|
90
92
|
# name of the token as a Symbol and a regular expression describing the
|
91
93
|
# value of the token.
|
94
|
+
NAME_RE = /\A(((::)?[_a-z0-9][-\w]*)(::[a-z0-9][-\w]*)*)/
|
92
95
|
KNOWN_TOKENS = [
|
93
96
|
[:TYPE, /\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)\b/],
|
94
97
|
[:CLASSREF, /\A(((::){0,1}[A-Z][-\w]*)+)/],
|
95
98
|
[:NUMBER, /\A\b((?:0[xX][0-9A-Fa-f]+|0?\d+(?:\.\d+)?(?:[eE]-?\d+)?))\b/],
|
96
|
-
[:
|
99
|
+
[:FUNCTION_NAME, /#{NAME_RE}\(/],
|
100
|
+
[:NAME, NAME_RE],
|
97
101
|
[:LBRACK, /\A(\[)/],
|
98
102
|
[:RBRACK, /\A(\])/],
|
99
103
|
[:LBRACE, /\A(\{)/],
|
@@ -128,7 +132,6 @@ class PuppetLint
|
|
128
132
|
[:COMMA, /\A(,)/],
|
129
133
|
[:DOT, /\A(\.)/],
|
130
134
|
[:COLON, /\A(:)/],
|
131
|
-
[:AT, /\A(@)/],
|
132
135
|
[:SEMIC, /\A(;)/],
|
133
136
|
[:QMARK, /\A(\?)/],
|
134
137
|
[:BACKSLASH, /\A(\\)/],
|
@@ -176,12 +179,12 @@ class PuppetLint
|
|
176
179
|
length = value.size
|
177
180
|
if type == :NAME
|
178
181
|
if KEYWORDS.include? value
|
179
|
-
tokens << new_token(value.upcase.to_sym, value
|
182
|
+
tokens << new_token(value.upcase.to_sym, value)
|
180
183
|
else
|
181
|
-
tokens << new_token(type, value
|
184
|
+
tokens << new_token(type, value)
|
182
185
|
end
|
183
186
|
else
|
184
|
-
tokens << new_token(type, value
|
187
|
+
tokens << new_token(type, value)
|
185
188
|
end
|
186
189
|
i += length
|
187
190
|
found = true
|
@@ -192,28 +195,33 @@ class PuppetLint
|
|
192
195
|
unless found
|
193
196
|
if var_name = chunk[/\A\$((::)?(\w+(-\w+)*::)*\w+(-\w+)*(\[.+?\])*)/, 1]
|
194
197
|
length = var_name.size + 1
|
195
|
-
tokens << new_token(:VARIABLE, var_name
|
198
|
+
tokens << new_token(:VARIABLE, var_name)
|
196
199
|
|
197
200
|
elsif chunk.match(/\A'(.*?)'/m)
|
198
201
|
str_content = StringScanner.new(code[i+1..-1]).scan_until(/(\A|[^\\])(\\\\)*'/m)
|
199
202
|
length = str_content.size + 1
|
200
|
-
tokens << new_token(:SSTRING, str_content[0..-2]
|
203
|
+
tokens << new_token(:SSTRING, str_content[0..-2])
|
201
204
|
|
202
205
|
elsif chunk.match(/\A"/)
|
203
|
-
str_contents =
|
206
|
+
str_contents = slurp_string(code[i+1..-1])
|
204
207
|
_ = code[0..i].split("\n")
|
205
208
|
interpolate_string(str_contents, _.count, _.last.length)
|
206
209
|
length = str_contents.size + 1
|
207
210
|
|
211
|
+
elsif heredoc_name = chunk[/\A@\(("?.+?"?(:.+?)?(\/.*?)?)\)/, 1]
|
212
|
+
@@heredoc_queue << heredoc_name
|
213
|
+
tokens << new_token(:HEREDOC_OPEN, heredoc_name)
|
214
|
+
length = heredoc_name.size + 3
|
215
|
+
|
208
216
|
elsif comment = chunk[/\A(#.*)/, 1]
|
209
217
|
length = comment.size
|
210
218
|
comment.sub!(/#/, '')
|
211
|
-
tokens << new_token(:COMMENT, comment
|
219
|
+
tokens << new_token(:COMMENT, comment)
|
212
220
|
|
213
221
|
elsif slash_comment = chunk[/\A(\/\/.*)/, 1]
|
214
222
|
length = slash_comment.size
|
215
223
|
slash_comment.sub!(/\/\//, '')
|
216
|
-
tokens << new_token(:SLASH_COMMENT, slash_comment
|
224
|
+
tokens << new_token(:SLASH_COMMENT, slash_comment)
|
217
225
|
|
218
226
|
elsif mlcomment = chunk[/\A(\/\*.*?\*\/)/m, 1]
|
219
227
|
length = mlcomment.size
|
@@ -221,32 +229,54 @@ class PuppetLint
|
|
221
229
|
mlcomment.sub!(/\A\/\* ?/, '')
|
222
230
|
mlcomment.sub!(/ ?\*\/\Z/, '')
|
223
231
|
mlcomment.gsub!(/^ *\*/, '')
|
224
|
-
tokens << new_token(:MLCOMMENT, mlcomment,
|
225
|
-
tokens.last.raw = mlcomment_raw
|
232
|
+
tokens << new_token(:MLCOMMENT, mlcomment, :raw => mlcomment_raw)
|
226
233
|
|
227
234
|
elsif chunk.match(/\A\/.*?\//) && possible_regex?
|
228
235
|
str_content = StringScanner.new(code[i+1..-1]).scan_until(/(\A|[^\\])(\\\\)*\//m)
|
229
236
|
length = str_content.size + 1
|
230
|
-
tokens << new_token(:REGEX, str_content[0..-2]
|
237
|
+
tokens << new_token(:REGEX, str_content[0..-2])
|
231
238
|
|
232
239
|
elsif eolindent = chunk[/\A((\r\n|\r|\n)[ \t]+)/m, 1]
|
233
240
|
eol = eolindent[/\A([\r\n]+)/m, 1]
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
241
|
+
tokens << new_token(:NEWLINE, eol)
|
242
|
+
length = eol.size
|
243
|
+
|
244
|
+
if @@heredoc_queue.empty?
|
245
|
+
indent = eolindent[/\A[\r\n]+([ \t]+)/m, 1]
|
246
|
+
tokens << new_token(:INDENT, indent)
|
247
|
+
length += indent.size
|
248
|
+
else
|
249
|
+
heredoc_tag = @@heredoc_queue.shift
|
250
|
+
heredoc_name = heredoc_tag[/\A"?(.+?)"?(:.+?)?(\/.*)?\Z/, 1]
|
251
|
+
str_contents = StringScanner.new(code[i+length..-1]).scan_until(/\|?\s*-?\s*#{heredoc_name}/)
|
252
|
+
interpolate_heredoc(str_contents, heredoc_tag)
|
253
|
+
length += str_contents.size
|
254
|
+
end
|
238
255
|
|
239
256
|
elsif whitespace = chunk[/\A([ \t]+)/, 1]
|
240
257
|
length = whitespace.size
|
241
|
-
tokens << new_token(:WHITESPACE, whitespace
|
258
|
+
tokens << new_token(:WHITESPACE, whitespace)
|
242
259
|
|
243
260
|
elsif eol = chunk[/\A(\r\n|\r|\n)/, 1]
|
244
261
|
length = eol.size
|
245
|
-
tokens << new_token(:NEWLINE, eol
|
262
|
+
tokens << new_token(:NEWLINE, eol)
|
263
|
+
|
264
|
+
unless @@heredoc_queue.empty?
|
265
|
+
heredoc_tag = @@heredoc_queue.shift
|
266
|
+
heredoc_name = heredoc_tag[/\A"?(.+?)"?(:.+?)?(\/.*)?\Z/, 1]
|
267
|
+
str_contents = StringScanner.new(code[i+length..-1]).scan_until(/\|?\s*-?\s*#{heredoc_name}/)
|
268
|
+
_ = code[0..i+length].split("\n")
|
269
|
+
interpolate_heredoc(str_contents, heredoc_tag)
|
270
|
+
length += str_contents.size
|
271
|
+
end
|
246
272
|
|
247
273
|
elsif chunk.match(/\A\//)
|
248
274
|
length = 1
|
249
|
-
tokens << new_token(:DIV, '/'
|
275
|
+
tokens << new_token(:DIV, '/')
|
276
|
+
|
277
|
+
elsif chunk.match(/\A@/)
|
278
|
+
length = 1
|
279
|
+
tokens << new_token(:AT, '@')
|
250
280
|
|
251
281
|
else
|
252
282
|
raise PuppetLint::LexerError.new(@line_no, @column)
|
@@ -259,6 +289,18 @@ class PuppetLint
|
|
259
289
|
tokens
|
260
290
|
end
|
261
291
|
|
292
|
+
|
293
|
+
def slurp_string(string)
|
294
|
+
dq_str_regexp = /(\$\{|(\A|[^\\])(\\\\)*")/m
|
295
|
+
scanner = StringScanner.new(string)
|
296
|
+
contents = scanner.scan_until(dq_str_regexp)
|
297
|
+
until scanner.matched.end_with?('"')
|
298
|
+
contents += scanner.scan_until(/\}/m)
|
299
|
+
contents += scanner.scan_until(dq_str_regexp)
|
300
|
+
end
|
301
|
+
contents
|
302
|
+
end
|
303
|
+
|
262
304
|
# Internal: Given the tokens already processed, determine if the next token
|
263
305
|
# could be a regular expression.
|
264
306
|
#
|
@@ -282,14 +324,19 @@ class PuppetLint
|
|
282
324
|
#
|
283
325
|
# type - The Symbol token type.
|
284
326
|
# value - The token value.
|
285
|
-
# length - The Integer length of the token's value.
|
286
327
|
# opts - A Hash of additional values required to determine line number and
|
287
328
|
# column:
|
288
329
|
# :line - The Integer line number if calculated externally.
|
289
330
|
# :column - The Integer column number if calculated externally.
|
331
|
+
# :raw - The String raw value of the token (if necessary).
|
290
332
|
#
|
291
333
|
# Returns the instantiated PuppetLint::Lexer::Token object.
|
292
|
-
def new_token(type, value,
|
334
|
+
def new_token(type, value, *args)
|
335
|
+
# This bit of magic is used instead of an "opts = {}" argument so that we
|
336
|
+
# can safely deprecate the old "length" parameter that might still be
|
337
|
+
# passed by 3rd party plugins that haven't updated yet.
|
338
|
+
opts = args.last.is_a?(Hash) ? args.last : {}
|
339
|
+
|
293
340
|
column = opts[:column] || @column
|
294
341
|
line_no = opts[:line] || @line_no
|
295
342
|
|
@@ -308,25 +355,24 @@ class PuppetLint
|
|
308
355
|
end
|
309
356
|
end
|
310
357
|
|
311
|
-
|
312
|
-
|
313
|
-
# If creating a :VARIABLE token inside a double quoted string, add 3 to
|
314
|
-
# the column state in order to account for the ${} characters when
|
315
|
-
# rendering out to manifest.
|
316
|
-
if token.type == :VARIABLE
|
317
|
-
if !token.prev_code_token.nil? && [:DQPRE, :DQMID].include?(token.prev_code_token.type)
|
318
|
-
@column += 3
|
319
|
-
end
|
358
|
+
if opts[:raw]
|
359
|
+
token.raw = opts[:raw]
|
320
360
|
end
|
321
361
|
|
322
362
|
if type == :NEWLINE
|
323
363
|
@line_no += 1
|
324
364
|
@column = 1
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
365
|
+
else
|
366
|
+
lines = token.to_manifest.split(/(?:\r\n|\r|\n)/, -1)
|
367
|
+
@line_no += lines.length - 1
|
368
|
+
if lines.length > 1
|
369
|
+
# if the token renders to multiple lines, set the column state to the
|
370
|
+
# length of the last line plus 1 (because column numbers are
|
371
|
+
# 1 indexed)
|
372
|
+
@column = lines.last.size + 1
|
373
|
+
else
|
374
|
+
@column += (lines.last || "").size
|
375
|
+
end
|
330
376
|
end
|
331
377
|
|
332
378
|
token
|
@@ -364,34 +410,37 @@ class PuppetLint
|
|
364
410
|
until value.nil?
|
365
411
|
if terminator == "\""
|
366
412
|
if first
|
367
|
-
tokens << new_token(:STRING, value,
|
413
|
+
tokens << new_token(:STRING, value, :line => line, :column => column)
|
368
414
|
first = false
|
369
415
|
else
|
370
416
|
line += value.scan(/(\r\n|\r|\n)/).size
|
371
417
|
token_column = column + (ss.pos - value.size)
|
372
|
-
tokens << new_token(:DQPOST, value,
|
418
|
+
tokens << new_token(:DQPOST, value, :line => line, :column => token_column)
|
419
|
+
@column = token_column + 1
|
420
|
+
@line_no = line
|
373
421
|
end
|
374
422
|
else
|
375
423
|
if first
|
376
|
-
tokens << new_token(:DQPRE, value,
|
424
|
+
tokens << new_token(:DQPRE, value, :line => line, :column => column)
|
377
425
|
first = false
|
378
426
|
else
|
379
427
|
line += value.scan(/(\r\n|\r|\n)/).size
|
380
428
|
token_column = column + (ss.pos - value.size)
|
381
|
-
tokens << new_token(:DQMID, value,
|
429
|
+
tokens << new_token(:DQMID, value, :line => line, :column => token_column)
|
382
430
|
end
|
383
431
|
if ss.scan(/\{/).nil?
|
384
432
|
var_name = ss.scan(/(::)?(\w+(-\w+)*::)*\w+(-\w+)*/)
|
385
433
|
if var_name.nil?
|
386
434
|
token_column = column + ss.pos - 1
|
387
|
-
tokens << new_token(:DQMID, "$",
|
435
|
+
tokens << new_token(:DQMID, "$", :line => line, :column => token_column)
|
388
436
|
else
|
389
437
|
token_column = column + (ss.pos - var_name.size)
|
390
|
-
tokens << new_token(:UNENC_VARIABLE, var_name,
|
438
|
+
tokens << new_token(:UNENC_VARIABLE, var_name, :line => line, :column => token_column)
|
391
439
|
end
|
392
440
|
else
|
393
441
|
contents = ss.scan_until(/\}/)[0..-2]
|
394
|
-
|
442
|
+
raw = contents.dup
|
443
|
+
if contents.match(/\A(::)?([\w-]+::)*[\w-]+(\[.+?\])*/) && !contents.match(/\A\w+\(/)
|
395
444
|
contents = "$#{contents}"
|
396
445
|
end
|
397
446
|
lexer = PuppetLint::Lexer.new
|
@@ -399,12 +448,98 @@ class PuppetLint
|
|
399
448
|
lexer.tokens.each do |token|
|
400
449
|
tok_col = column + token.column + (ss.pos - contents.size - 1)
|
401
450
|
tok_line = token.line + line - 1
|
402
|
-
tokens << new_token(token.type, token.value,
|
451
|
+
tokens << new_token(token.type, token.value, :line => tok_line, :column => tok_col)
|
452
|
+
end
|
453
|
+
if lexer.tokens.length == 1 && lexer.tokens[0].type == :VARIABLE
|
454
|
+
tokens.last.raw = raw
|
403
455
|
end
|
404
456
|
end
|
405
457
|
end
|
406
458
|
value, terminator = get_string_segment(ss, '"$')
|
407
459
|
end
|
408
460
|
end
|
461
|
+
|
462
|
+
# Internal: Tokenise the contents of a heredoc.
|
463
|
+
#
|
464
|
+
# string - The String to be tokenised.
|
465
|
+
# name - The String name/endtext of the heredoc.
|
466
|
+
#
|
467
|
+
# Returns nothing.
|
468
|
+
def interpolate_heredoc(string, name)
|
469
|
+
ss = StringScanner.new(string)
|
470
|
+
eos_text = name[/\A"?(.+?)"?(:.+?)?(\/.*)?\Z/, 1]
|
471
|
+
first = true
|
472
|
+
interpolate = name.start_with?('"')
|
473
|
+
value, terminator = get_heredoc_segment(ss, eos_text, interpolate)
|
474
|
+
until value.nil?
|
475
|
+
if terminator =~ /\A\|?\s*-?\s*#{Regexp.escape(eos_text)}/
|
476
|
+
if first
|
477
|
+
tokens << new_token(:HEREDOC, value, :raw => "#{value}#{terminator}")
|
478
|
+
first = false
|
479
|
+
else
|
480
|
+
tokens << new_token(:HEREDOC_POST, value, :raw => "#{value}#{terminator}")
|
481
|
+
end
|
482
|
+
else
|
483
|
+
if first
|
484
|
+
tokens << new_token(:HEREDOC_PRE, value)
|
485
|
+
first = false
|
486
|
+
else
|
487
|
+
tokens << new_token(:HEREDOC_MID, value)
|
488
|
+
end
|
489
|
+
if ss.scan(/\{/).nil?
|
490
|
+
var_name = ss.scan(/(::)?(\w+(-\w+)*::)*\w+(-\w+)*/)
|
491
|
+
if var_name.nil?
|
492
|
+
tokens << new_token(:HEREDOC_MID, "$")
|
493
|
+
else
|
494
|
+
tokens << new_token(:UNENC_VARIABLE, var_name)
|
495
|
+
end
|
496
|
+
else
|
497
|
+
contents = ss.scan_until(/\}/)[0..-2]
|
498
|
+
raw = contents.dup
|
499
|
+
if contents.match(/\A(::)?([\w-]+::)*[\w-]|(\[.+?\])*/) && !contents.match(/\A\w+\(/)
|
500
|
+
contents = "$#{contents}" unless contents.start_with?("$")
|
501
|
+
end
|
502
|
+
|
503
|
+
lexer = PuppetLint::Lexer.new
|
504
|
+
lexer.tokenise(contents)
|
505
|
+
lexer.tokens.each do |token|
|
506
|
+
tokens << new_token(token.type, token.value)
|
507
|
+
end
|
508
|
+
if lexer.tokens.length == 1 && lexer.tokens[0].type == :VARIABLE
|
509
|
+
tokens.last.raw = raw
|
510
|
+
end
|
511
|
+
end
|
512
|
+
end
|
513
|
+
value, terminator = get_heredoc_segment(ss, eos_text, interpolate)
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
# Internal: Splits a heredoc String into segments if it is to be
|
518
|
+
# interpolated.
|
519
|
+
#
|
520
|
+
# string - The String heredoc.
|
521
|
+
# eos_text - The String endtext for the heredoc.
|
522
|
+
# interpolate - A Boolean that specifies whether this heredoc can contain
|
523
|
+
# interpolated values (defaults to True).
|
524
|
+
#
|
525
|
+
# Returns an Array consisting of two Strings, the String up to the first
|
526
|
+
# terminator and the terminator that was found.
|
527
|
+
def get_heredoc_segment(string, eos_text, interpolate=true)
|
528
|
+
if interpolate
|
529
|
+
regexp = /(([^\\]|^|[^\\])([\\]{2})*[$]+|\|?\s*-?#{Regexp.escape(eos_text)})/
|
530
|
+
else
|
531
|
+
regexp = /\|?\s*-?#{Regexp.escape(eos_text)}/
|
532
|
+
end
|
533
|
+
|
534
|
+
str = string.scan_until(regexp)
|
535
|
+
begin
|
536
|
+
str =~ /\A(.*?)([$]+|\|?\s*-?#{Regexp.escape(eos_text)})\Z/m
|
537
|
+
value = $1
|
538
|
+
terminator = $2
|
539
|
+
[value, terminator]
|
540
|
+
rescue
|
541
|
+
[nil, nil]
|
542
|
+
end
|
543
|
+
end
|
409
544
|
end
|
410
545
|
end
|