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
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
|