puppet-lint 0.3.2 → 0.4.0.pre1
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.
- data/.gitignore +2 -0
- data/Gemfile +0 -1
- data/README.md +3 -1
- data/Rakefile +0 -19
- data/lib/puppet-lint.rb +65 -74
- data/lib/puppet-lint/bin.rb +21 -0
- data/lib/puppet-lint/checkplugin.rb +22 -0
- data/lib/puppet-lint/{plugin.rb → checks.rb} +66 -31
- data/lib/puppet-lint/configuration.rb +105 -0
- data/lib/puppet-lint/lexer.rb +94 -31
- data/lib/puppet-lint/lexer/token.rb +38 -2
- data/lib/puppet-lint/monkeypatches.rb +2 -0
- data/lib/puppet-lint/monkeypatches/string_percent.rb +52 -0
- data/lib/puppet-lint/monkeypatches/string_prepend.rb +7 -0
- data/lib/puppet-lint/plugins.rb +42 -0
- data/lib/puppet-lint/plugins/check_comments.rb +8 -1
- data/lib/puppet-lint/plugins/check_resources.rb +25 -3
- data/lib/puppet-lint/plugins/check_strings.rb +53 -6
- data/lib/puppet-lint/plugins/check_whitespace.rb +69 -26
- data/lib/puppet-lint/version.rb +1 -1
- data/puppet-lint.gemspec +0 -1
- data/spec/puppet-lint/configuration_spec.rb +1 -0
- data/spec/puppet-lint/lexer_spec.rb +2 -2
- data/spec/puppet-lint/plugins/check_comments/slash_comments_spec.rb +22 -0
- data/spec/puppet-lint/plugins/check_resources/file_mode_spec.rb +119 -6
- data/spec/puppet-lint/plugins/check_resources/unquoted_file_mode_spec.rb +30 -3
- data/spec/puppet-lint/plugins/check_resources/unquoted_resource_title_spec.rb +103 -3
- data/spec/puppet-lint/plugins/check_strings/double_quoted_strings_spec.rb +39 -0
- data/spec/puppet-lint/plugins/check_strings/only_variable_string_spec.rb +23 -0
- data/spec/puppet-lint/plugins/check_strings/quoted_booleans_spec.rb +88 -0
- data/spec/puppet-lint/plugins/check_strings/variables_not_enclosed_spec.rb +44 -0
- data/spec/puppet-lint/plugins/check_whitespace/arrow_alignment_spec.rb +171 -6
- data/spec/puppet-lint/plugins/check_whitespace/hard_tabs_spec.rb +22 -0
- data/spec/puppet-lint/plugins/check_whitespace/trailing_whitespace_spec.rb +44 -0
- data/spec/puppet-lint_spec.rb +1 -1
- metadata +10 -22
@@ -1,19 +1,50 @@
|
|
1
1
|
class PuppetLint
|
2
2
|
class Configuration
|
3
|
+
# Internal: Add helper methods for a new check to the
|
4
|
+
# PuppetLint::Configuration object.
|
5
|
+
#
|
6
|
+
# check - The String name of the check.
|
7
|
+
#
|
8
|
+
# Returns nothing.
|
9
|
+
#
|
10
|
+
# Signature
|
11
|
+
#
|
12
|
+
# <check>_enabled?
|
13
|
+
# disable_<check>
|
14
|
+
# enable_<check>
|
3
15
|
def self.add_check(check)
|
16
|
+
# Public: Determine if the named check is enabled.
|
17
|
+
#
|
18
|
+
# Returns true if the check is enabled, otherwise return false.
|
4
19
|
define_method("#{check}_enabled?") do
|
5
20
|
settings["#{check}_disabled"] == true ? false : true
|
6
21
|
end
|
7
22
|
|
23
|
+
# Public: Disable the named check.
|
24
|
+
#
|
25
|
+
# Returns nothing.
|
8
26
|
define_method("disable_#{check}") do
|
9
27
|
settings["#{check}_disabled"] = true
|
10
28
|
end
|
11
29
|
|
30
|
+
# Public: Enable the named check.
|
31
|
+
#
|
32
|
+
# Returns nothing.
|
12
33
|
define_method("enable_#{check}") do
|
13
34
|
settings["#{check}_disabled"] = false
|
14
35
|
end
|
15
36
|
end
|
16
37
|
|
38
|
+
# Public: Catch situations where options are being set for the first time
|
39
|
+
# and create the necessary methods to get & set the option in the future.
|
40
|
+
#
|
41
|
+
# args[0] - The value to set the option to.
|
42
|
+
#
|
43
|
+
# Returns nothing.
|
44
|
+
#
|
45
|
+
# Signature
|
46
|
+
#
|
47
|
+
# <option>=(value)
|
17
48
|
def method_missing(method, *args, &block)
|
18
49
|
if method.to_s =~ /^(\w+)=$/
|
19
50
|
option = $1
|
@@ -24,37 +55,110 @@ class PuppetLint
|
|
24
55
|
end
|
25
56
|
end
|
26
57
|
|
58
|
+
# Internal: Add options to the PuppetLint::Configuration object from inside
|
59
|
+
# the class.
|
60
|
+
#
|
61
|
+
# option - The String name of the option.
|
62
|
+
#
|
63
|
+
# Returns nothing.
|
64
|
+
#
|
65
|
+
# Signature
|
66
|
+
#
|
67
|
+
# <option>
|
68
|
+
# <option>=(value)
|
27
69
|
def add_option(option)
|
28
70
|
self.class.add_option(option)
|
29
71
|
end
|
30
72
|
|
73
|
+
# Public: Add an option to the PuppetLint::Configuration object from
|
74
|
+
# outside the class.
|
75
|
+
#
|
76
|
+
# option - The String name of the option.
|
77
|
+
#
|
78
|
+
# Returns nothing.
|
79
|
+
#
|
80
|
+
# Signature
|
81
|
+
#
|
82
|
+
# <option>
|
83
|
+
# <option>=(value)
|
31
84
|
def self.add_option(option)
|
85
|
+
# Public: Set the value of the named option.
|
86
|
+
#
|
87
|
+
# value - The value to set the option to.
|
88
|
+
#
|
89
|
+
# Returns nothing.
|
32
90
|
define_method("#{option}=") do |value|
|
33
91
|
settings[option] = value
|
34
92
|
end
|
35
93
|
|
94
|
+
# Public: Get the value of the named option.
|
95
|
+
#
|
96
|
+
# Returns the value of the option.
|
36
97
|
define_method(option) do
|
37
98
|
settings[option]
|
38
99
|
end
|
39
100
|
end
|
40
101
|
|
102
|
+
# Internal: Register a new check.
|
103
|
+
#
|
104
|
+
# check - The String name of the check
|
105
|
+
# b - The Block containing the logic of the check
|
106
|
+
#
|
107
|
+
# Returns nothing.
|
41
108
|
def add_check(check, &b)
|
42
109
|
self.class.add_check(check)
|
43
110
|
check_method[check] = b
|
44
111
|
end
|
45
112
|
|
113
|
+
# Internal: Register a new check helper method.
|
114
|
+
#
|
115
|
+
# name - The String name of the method.
|
116
|
+
# b - The Block containing the logic of the helper.
|
117
|
+
#
|
118
|
+
# Returns nothing.
|
119
|
+
def add_helper(name, &b)
|
120
|
+
helper_method[name] = b
|
121
|
+
end
|
122
|
+
|
123
|
+
# Internal: Access the internal storage for settings.
|
124
|
+
#
|
125
|
+
# Returns a Hash containing all the settings.
|
46
126
|
def settings
|
47
127
|
@settings ||= {}
|
48
128
|
end
|
49
129
|
|
130
|
+
# Internal: Access the internal storage for check method blocks.
|
131
|
+
#
|
132
|
+
# Returns a Hash containing all the check blocks.
|
50
133
|
def check_method
|
51
134
|
@check_method ||= {}
|
52
135
|
end
|
53
136
|
|
137
|
+
# Public: Get a list of all the defined checks.
|
138
|
+
#
|
139
|
+
# Returns an Array of String check names.
|
54
140
|
def checks
|
55
141
|
check_method.keys
|
56
142
|
end
|
57
143
|
|
144
|
+
# Internal: Access the internal storage for helper method blocks.
|
145
|
+
#
|
146
|
+
# Returns a Hash containing all the helper blocks.
|
147
|
+
def helper_method
|
148
|
+
@helper_method ||= {}
|
149
|
+
end
|
150
|
+
|
151
|
+
# Public: Get a list of all the helper methods.
|
152
|
+
#
|
153
|
+
# Returns an Array of String method names.
|
154
|
+
def helpers
|
155
|
+
helper_method.keys
|
156
|
+
end
|
157
|
+
|
158
|
+
# Public: Clear the PuppetLint::Configuration storage and set some sane
|
159
|
+
# default values.
|
160
|
+
#
|
161
|
+
# Returns nothing.
|
58
162
|
def defaults
|
59
163
|
settings.clear
|
60
164
|
self.with_filename = false
|
@@ -62,6 +166,7 @@ class PuppetLint
|
|
62
166
|
self.error_level = :all
|
63
167
|
self.log_format = ''
|
64
168
|
self.with_context = false
|
169
|
+
self.fix = false
|
65
170
|
end
|
66
171
|
end
|
67
172
|
end
|
data/lib/puppet-lint/lexer.rb
CHANGED
@@ -5,7 +5,17 @@ require 'set'
|
|
5
5
|
|
6
6
|
class PuppetLint
|
7
7
|
class LexerError < StandardError
|
8
|
-
|
8
|
+
# Internal: Get the Integer line number of the location of the error.
|
9
|
+
attr_reader :line_no
|
10
|
+
|
11
|
+
# Internal: Get the Integer column number of the location of the error.
|
12
|
+
attr_reader :column
|
13
|
+
|
14
|
+
# Internal: Initialise a new PuppetLint::LexerError object.
|
15
|
+
#
|
16
|
+
# code - The String manifest code being tokenised.
|
17
|
+
# offset - The Integer position in the code string that the tokeniser was
|
18
|
+
# at when it encountered the error.
|
9
19
|
def initialize(code, offset)
|
10
20
|
chunk = code[0..offset]
|
11
21
|
@line_no = chunk.count("\n") + 1
|
@@ -19,35 +29,43 @@ class PuppetLint
|
|
19
29
|
end
|
20
30
|
|
21
31
|
class Lexer
|
32
|
+
# Internal: A Hash whose keys are Strings representing reserved keywords in
|
33
|
+
# the Puppet DSL.
|
22
34
|
KEYWORDS = {
|
23
|
-
'class'
|
24
|
-
'case'
|
25
|
-
'default'
|
26
|
-
'define'
|
27
|
-
'import'
|
28
|
-
'if'
|
29
|
-
'else'
|
30
|
-
'elsif'
|
35
|
+
'class' => true,
|
36
|
+
'case' => true,
|
37
|
+
'default' => true,
|
38
|
+
'define' => true,
|
39
|
+
'import' => true,
|
40
|
+
'if' => true,
|
41
|
+
'else' => true,
|
42
|
+
'elsif' => true,
|
31
43
|
'inherits' => true,
|
32
|
-
'node'
|
33
|
-
'and'
|
34
|
-
'or'
|
35
|
-
'undef'
|
36
|
-
'true'
|
37
|
-
'false'
|
38
|
-
'in'
|
39
|
-
'unless'
|
44
|
+
'node' => true,
|
45
|
+
'and' => true,
|
46
|
+
'or' => true,
|
47
|
+
'undef' => true,
|
48
|
+
'true' => true,
|
49
|
+
'false' => true,
|
50
|
+
'in' => true,
|
51
|
+
'unless' => true,
|
40
52
|
}
|
41
53
|
|
54
|
+
# Internal: A Hash whose keys are Symbols representing token types which
|
55
|
+
# a regular expression can follow.
|
42
56
|
REGEX_PREV_TOKENS = {
|
43
|
-
:NODE
|
44
|
-
:LBRACE
|
45
|
-
:RBRACE
|
46
|
-
:MATCH
|
57
|
+
:NODE => true,
|
58
|
+
:LBRACE => true,
|
59
|
+
:RBRACE => true,
|
60
|
+
:MATCH => true,
|
47
61
|
:NOMATCH => true,
|
48
|
-
:COMMA
|
62
|
+
:COMMA => true,
|
49
63
|
}
|
50
64
|
|
65
|
+
# Internal: An Array of Arrays containing tokens that can be described by
|
66
|
+
# a single regular expression. Each sub-Array contains 2 elements, the
|
67
|
+
# name of the token as a Symbol and a regular expression describing the
|
68
|
+
# value of the token.
|
51
69
|
KNOWN_TOKENS = [
|
52
70
|
[:CLASSREF, /\A(((::){0,1}[A-Z][-\w]*)+)/],
|
53
71
|
[:NUMBER, /\A\b((?:0[xX][0-9A-Fa-f]+|0?\d+(?:\.\d+)?(?:[eE]-?\d+)?))\b/],
|
@@ -93,19 +111,32 @@ class PuppetLint
|
|
93
111
|
[:TIMES, /\A(\*)/],
|
94
112
|
]
|
95
113
|
|
114
|
+
# Internal: A Hash whose keys are Symbols representing token types which
|
115
|
+
# are considered to be formatting tokens (i.e. tokens that don't contain
|
116
|
+
# code).
|
96
117
|
FORMATTING_TOKENS = {
|
97
|
-
:WHITESPACE
|
98
|
-
:NEWLINE
|
99
|
-
:COMMENT
|
100
|
-
:MLCOMMENT
|
118
|
+
:WHITESPACE => true,
|
119
|
+
:NEWLINE => true,
|
120
|
+
:COMMENT => true,
|
121
|
+
:MLCOMMENT => true,
|
101
122
|
:SLASH_COMMENT => true,
|
102
|
-
:INDENT
|
123
|
+
:INDENT => true,
|
103
124
|
}
|
104
125
|
|
126
|
+
# Internal: Access the internal token storage.
|
127
|
+
#
|
128
|
+
# Returns an Array of PuppetLint::Lexer::Toxen objects.
|
105
129
|
def tokens
|
106
130
|
@tokens ||= []
|
107
131
|
end
|
108
132
|
|
133
|
+
# Internal: Convert a Puppet manifest into tokens.
|
134
|
+
#
|
135
|
+
# code - The Puppet manifest to be tokenised as a String.
|
136
|
+
#
|
137
|
+
# Returns an Array of PuppetLint::Lexer::Token objects.
|
138
|
+
# Raises PuppetLint::LexerError if it encounters unexpected characters
|
139
|
+
# (usually the result of syntax errors).
|
109
140
|
def tokenise(code)
|
110
141
|
code.chomp!
|
111
142
|
|
@@ -165,8 +196,7 @@ class PuppetLint
|
|
165
196
|
mlcomment_size = mlcomment.size
|
166
197
|
mlcomment.sub!(/\A\/\* ?/, '')
|
167
198
|
mlcomment.sub!(/ ?\*\/\Z/, '')
|
168
|
-
mlcomment.gsub!(
|
169
|
-
mlcomment.gsub!(/\n/, ' ')
|
199
|
+
mlcomment.gsub!(/ *\* ?/, '')
|
170
200
|
mlcomment.strip!
|
171
201
|
tokens << new_token(:MLCOMMENT, mlcomment, :chunk => code[0..i])
|
172
202
|
i += mlcomment_size
|
@@ -176,7 +206,7 @@ class PuppetLint
|
|
176
206
|
tokens << new_token(:REGEX, str_content[0..-2], :chunk => code[0..i])
|
177
207
|
i += str_content.size + 1
|
178
208
|
|
179
|
-
elsif indent = chunk[/\A\n([ \t]+)/m, 1]
|
209
|
+
elsif indent = chunk[/\A\r?\n([ \t]+)/m, 1]
|
180
210
|
tokens << new_token(:NEWLINE, '\n', :chunk => code[0..i])
|
181
211
|
tokens << new_token(:INDENT, indent, :chunk => code[0..i+1])
|
182
212
|
i += indent.size + 1
|
@@ -185,7 +215,7 @@ class PuppetLint
|
|
185
215
|
tokens << new_token(:WHITESPACE, whitespace, :chunk => code[0..i])
|
186
216
|
i += whitespace.size
|
187
217
|
|
188
|
-
elsif chunk.match(/\A\n/)
|
218
|
+
elsif chunk.match(/\A\r?\n/)
|
189
219
|
tokens << new_token(:NEWLINE, '\n', :chunk => code[0..i])
|
190
220
|
i += 1
|
191
221
|
|
@@ -202,6 +232,10 @@ class PuppetLint
|
|
202
232
|
tokens
|
203
233
|
end
|
204
234
|
|
235
|
+
# Internal: Given the tokens already processed, determine if the next token
|
236
|
+
# could be a regular expression.
|
237
|
+
#
|
238
|
+
# Returns true if the next token could be a regex, otherwise return false.
|
205
239
|
def possible_regex?
|
206
240
|
prev_token = tokens.reject { |r|
|
207
241
|
FORMATTING_TOKENS.include? r.type
|
@@ -216,6 +250,19 @@ class PuppetLint
|
|
216
250
|
end
|
217
251
|
end
|
218
252
|
|
253
|
+
# Internal: Create a new PuppetLint::Lexer::Token object, calculate its
|
254
|
+
# line number and column and then add it to the Linked List of tokens.
|
255
|
+
#
|
256
|
+
# type - The Symbol token type.
|
257
|
+
# value - The token value.
|
258
|
+
# opts - A Hash of additional values required to determine line number and
|
259
|
+
# column:
|
260
|
+
# :chunk - The String chunk of the manifest that has been tokenised so
|
261
|
+
# far.
|
262
|
+
# :line - The Integer line number if calculated externally.
|
263
|
+
# :column - The Integer column number if calculated externally.
|
264
|
+
#
|
265
|
+
# Returns the instantiated PuppetLint::Lexer::Token object.
|
219
266
|
def new_token(type, value, opts = {})
|
220
267
|
if opts[:chunk]
|
221
268
|
line_no = opts[:chunk].count("\n") + 1
|
@@ -248,6 +295,15 @@ class PuppetLint
|
|
248
295
|
token
|
249
296
|
end
|
250
297
|
|
298
|
+
# Internal: Split a string on multiple terminators, excluding escaped
|
299
|
+
# terminators.
|
300
|
+
#
|
301
|
+
# string - The String to be split.
|
302
|
+
# terminators - The String of terminators that the String should be split
|
303
|
+
# on.
|
304
|
+
#
|
305
|
+
# Returns an Array consisting of two Strings, the String up to the first
|
306
|
+
# terminator and the terminator that was found.
|
251
307
|
def get_string_segment(string, terminators)
|
252
308
|
str = string.scan_until(/([^\\]|^|[^\\])([\\]{2})*[#{terminators}]+/)
|
253
309
|
begin
|
@@ -257,6 +313,13 @@ class PuppetLint
|
|
257
313
|
end
|
258
314
|
end
|
259
315
|
|
316
|
+
# Internal: Tokenise the contents of a double quoted string.
|
317
|
+
#
|
318
|
+
# string - The String to be tokenised.
|
319
|
+
# line - The Integer line number of the start of the passed string.
|
320
|
+
# column - The Integer column number of the start of the passed string.
|
321
|
+
#
|
322
|
+
# Returns nothing.
|
260
323
|
def interpolate_string(string, line, column)
|
261
324
|
ss = StringScanner.new(string)
|
262
325
|
first = true
|
@@ -2,10 +2,10 @@ class PuppetLint
|
|
2
2
|
class Lexer
|
3
3
|
class Token
|
4
4
|
# Internal: Returns the Symbol type of the Token.
|
5
|
-
|
5
|
+
attr_accessor :type
|
6
6
|
|
7
7
|
# Internal: Returns the String value of the Token.
|
8
|
-
|
8
|
+
attr_accessor :value
|
9
9
|
|
10
10
|
# Internal: Returns the Integer line number of the manifest text where
|
11
11
|
# the Token can be found.
|
@@ -57,6 +57,42 @@ class PuppetLint
|
|
57
57
|
def inspect
|
58
58
|
"<Token #{@type.inspect} (#{@value}) @#{@line}:#{@column}>"
|
59
59
|
end
|
60
|
+
|
61
|
+
# Internal: Produce a Puppet DSL representation of a Token.
|
62
|
+
#
|
63
|
+
# Returns a Puppet DSL String.
|
64
|
+
def to_manifest
|
65
|
+
case @type
|
66
|
+
when :STRING
|
67
|
+
"\"#{@value}\""
|
68
|
+
when :SSTRING
|
69
|
+
"'#{@value}'"
|
70
|
+
when :DQPRE
|
71
|
+
"\"#{@value}"
|
72
|
+
when :DQPOST
|
73
|
+
"#{@value}\""
|
74
|
+
when :VARIABLE
|
75
|
+
if !@prev_code_token.nil? && [:DQPRE, :DQMID].include?(@prev_code_token.type)
|
76
|
+
"${#{@value}}"
|
77
|
+
else
|
78
|
+
"$#{@value}"
|
79
|
+
end
|
80
|
+
when :UNENC_VARIABLE
|
81
|
+
"$#{@value}"
|
82
|
+
when :NEWLINE
|
83
|
+
"\n"
|
84
|
+
when :COMMENT
|
85
|
+
if @value.start_with?('#') || @value.empty?
|
86
|
+
"##{@value}"
|
87
|
+
else
|
88
|
+
"# #{@value}"
|
89
|
+
end
|
90
|
+
when :REGEX
|
91
|
+
"/#{@value}/"
|
92
|
+
else
|
93
|
+
@value
|
94
|
+
end
|
95
|
+
end
|
60
96
|
end
|
61
97
|
end
|
62
98
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# If we are using an older ruby version, we back-port the basic functionality
|
2
|
+
# we need for formatting output: 'somestring' % <hash>
|
3
|
+
begin
|
4
|
+
if ('%{test}' % {:test => 'replaced'} == 'replaced')
|
5
|
+
# If this works, we are all good to go.
|
6
|
+
end
|
7
|
+
rescue
|
8
|
+
# If the test failed (threw a error), monkeypatch String.
|
9
|
+
# Most of this code came from http://www.ruby-forum.com/topic/144310 but was
|
10
|
+
# simplified for our use.
|
11
|
+
|
12
|
+
# Basic implementation of 'string' % { } like we need it. needs work.
|
13
|
+
class String
|
14
|
+
Percent = instance_method '%' unless defined? Percent
|
15
|
+
def % *a, &b
|
16
|
+
a.flatten!
|
17
|
+
|
18
|
+
string = case a.last
|
19
|
+
when Hash
|
20
|
+
expand a.pop
|
21
|
+
else
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
if a.empty?
|
26
|
+
string
|
27
|
+
else
|
28
|
+
Percent.bind(string).call(a, &b)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
def expand! vars = {}
|
33
|
+
loop do
|
34
|
+
changed = false
|
35
|
+
vars.each do |var, value|
|
36
|
+
var = var.to_s
|
37
|
+
var.gsub! %r/[^a-zA-Z0-9_]/, ''
|
38
|
+
[
|
39
|
+
%r/\%\{#{ var }\}/,
|
40
|
+
].each do |pat|
|
41
|
+
changed = gsub! pat, "#{ value }"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
break unless changed
|
45
|
+
end
|
46
|
+
self
|
47
|
+
end
|
48
|
+
def expand opts = {}
|
49
|
+
dup.expand! opts
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|