puppet-lint 0.1.13 → 0.2.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,49 +1,80 @@
1
1
  class PuppetLint::Plugins::CheckClasses < PuppetLint::CheckPlugin
2
- if Puppet::PUPPETVERSION !~ /^0\.2/
3
- check 'right_to_left_relationship' do
4
- tokens.select { |r| r.first == :OUT_EDGE }.each do |token|
5
- notify :warning, :message => "right-to-left (<-) relationship", :linenumber => token.last[:line]
6
- end
2
+ # Public: Test the manifest tokens for any right-to-left (<-) chaining
3
+ # operators and record a warning for each instance found.
4
+ #
5
+ # Returns nothing.
6
+ check 'right_to_left_relationship' do
7
+ tokens.select { |r| r.type == :OUT_EDGE }.each do |token|
8
+ notify :warning, {
9
+ :message => 'right-to-left (<-) relationship',
10
+ :linenumber => token.line,
11
+ :column => token.column,
12
+ }
7
13
  end
8
14
  end
9
15
 
16
+ # Public: Test the manifest tokens for any classes or defined types that are
17
+ # not in an appropriately named file for the autoloader to detect and record
18
+ # an error of each instance found.
19
+ #
20
+ # Returns nothing.
10
21
  check 'autoloader_layout' do
11
- unless fullpath == ""
22
+ unless fullpath == ''
12
23
  (class_indexes + defined_type_indexes).each do |class_idx|
13
- title_token = tokens[class_idx[:start]+1]
14
- split_title = title_token.last[:value].split('::')
24
+ class_tokens = tokens[class_idx[:start]..class_idx[:end]]
25
+ title_token = class_tokens[class_tokens.index { |r| r.type == :NAME }]
26
+ split_title = title_token.value.split('::')
27
+ mod = split_title.first
15
28
  if split_title.length > 1
16
- expected_path = "#{split_title.first}/manifests/#{split_title[1..-1].join('/')}.pp"
29
+ expected_path = "#{mod}/manifests/#{split_title[1..-1].join('/')}.pp"
17
30
  else
18
- expected_path = "#{title_token.last[:value]}/manifests/init.pp"
31
+ expected_path = "#{title_token.value}/manifests/init.pp"
19
32
  end
20
33
 
21
34
  unless fullpath.end_with? expected_path
22
- notify :error, :message => "#{title_token.last[:value]} not in autoload module layout", :linenumber => title_token.last[:line]
35
+ notify :error, {
36
+ :message => "#{title_token.value} not in autoload module layout",
37
+ :linenumber => title_token.line,
38
+ :column => title_token.column,
39
+ }
23
40
  end
24
41
  end
25
42
  end
26
43
  end
27
44
 
45
+ # Public: Test the manifest tokens for any parameterised classes or defined
46
+ # types that take parameters and record a warning if there are any optional
47
+ # parameters listed before required parameters.
48
+ #
49
+ # Returns nothing.
28
50
  check 'parameter_order' do
29
51
  (class_indexes + defined_type_indexes).each do |class_idx|
30
52
  token_idx = class_idx[:start]
31
- header_end_idx = tokens[token_idx..-1].index { |r| r.first == :LBRACE }
32
- lparen_idx = tokens[token_idx..(header_end_idx + token_idx)].index { |r| r.first == :LPAREN }
33
- rparen_idx = tokens[token_idx..(header_end_idx + token_idx)].rindex { |r| r.first == :RPAREN }
53
+ header_end_idx = tokens[token_idx..-1].index { |r| r.type == :LBRACE }
54
+ header_tokens = tokens[token_idx..header_end_idx].reject { |r|
55
+ formatting_tokens.include?(r.type)
56
+ }
57
+ lparen_idx = header_tokens.index { |r| r.type == :LPAREN }
58
+ rparen_idx = header_tokens.rindex { |r| r.type == :RPAREN }
34
59
 
35
60
  unless lparen_idx.nil? or rparen_idx.nil?
36
- param_tokens = tokens[lparen_idx..rparen_idx]
61
+ param_tokens = header_tokens[lparen_idx..rparen_idx]
37
62
  param_tokens.each_index do |param_tokens_idx|
38
63
  this_token = param_tokens[param_tokens_idx]
39
64
  next_token = param_tokens[param_tokens_idx+1]
40
65
  prev_token = param_tokens[param_tokens_idx-1]
41
- if this_token.first == :VARIABLE
66
+ if this_token.type == :VARIABLE
42
67
  unless next_token.nil?
43
- if next_token.first == :COMMA or next_token.first == :RPAREN
44
- unless param_tokens[0..param_tokens_idx].rindex { |r| r.first == :EQUALS }.nil?
45
- unless prev_token.nil? or prev_token.first == :EQUALS
46
- notify :warning, :message => "optional parameter listed before required parameter", :linenumber => this_token.last[:line]
68
+ if next_token.type == :COMMA or next_token.type == :RPAREN
69
+ prev_tokens = param_tokens[0..param_tokens_idx]
70
+ unless prev_tokens.rindex { |r| r.type == :EQUALS }.nil?
71
+ unless prev_token.nil? or prev_token.type == :EQUALS
72
+ msg = 'optional parameter listed before required parameter'
73
+ notify :warning, {
74
+ :message => msg,
75
+ :linenumber => this_token.line,
76
+ :column => this_token.column,
77
+ }
47
78
  end
48
79
  end
49
80
  end
@@ -54,57 +85,107 @@ class PuppetLint::Plugins::CheckClasses < PuppetLint::CheckPlugin
54
85
  end
55
86
  end
56
87
 
88
+ # Public: Test the manifest tokens for any classes that inherit across
89
+ # namespaces and record a warning for each instance found.
90
+ #
91
+ # Returns nothing.
57
92
  check 'inherits_across_namespaces' do
58
93
  class_indexes.each do |class_idx|
59
- token_idx = class_idx[:start]
60
- if tokens[token_idx+2].first == :INHERITS
61
- class_name = tokens[token_idx+1].last[:value]
62
- inherited_class = tokens[token_idx+3].last[:value]
94
+ class_tokens = tokens[class_idx[:start]..class_idx[:end]].reject { |r|
95
+ formatting_tokens.include?(r.type)
96
+ }
97
+
98
+ if class_tokens[2].type == :INHERITS
99
+ class_name = class_tokens[1].value
100
+ inherited_class = class_tokens[3].value
63
101
 
64
102
  unless class_name =~ /^#{inherited_class}::/
65
- notify :warning, :message => "class inherits across namespaces", :linenumber => tokens[token_idx].last[:line]
103
+ notify :warning, {
104
+ :message => "class inherits across namespaces",
105
+ :linenumber => class_tokens[3].line,
106
+ :column => class_tokens[3].column,
107
+ }
66
108
  end
67
109
  end
68
110
  end
69
111
  end
70
112
 
113
+ # Public: Test the manifest tokens for any classes or defined types that are
114
+ # defined inside another class.
115
+ #
116
+ # Returns nothing.
71
117
  check 'nested_classes_or_defines' do
72
118
  class_indexes.each do |class_idx|
73
- class_tokens = tokens[class_idx[:start]..class_idx[:end]]
74
- class_tokens[1..-1].each_index do |token_idx|
75
- token = class_tokens[1..-1][token_idx]
76
- next_token = class_tokens[1..-1][token_idx + 1]
77
-
78
- if token.first == :CLASS
79
- if next_token.first != :LBRACE
80
- notify :warning, :message => "class defined inside a class", :linenumber => token.last[:line]
119
+ # Skip the first token so that we don't pick up the first :CLASS
120
+ class_tokens = tokens[class_idx[:start]+1..class_idx[:end]].reject { |r|
121
+ formatting_tokens.include?(r.type)
122
+ }
123
+
124
+ class_tokens.each_index do |token_idx|
125
+ token = class_tokens[token_idx]
126
+ next_token = class_tokens[token_idx + 1]
127
+
128
+ if token.type == :CLASS
129
+ if next_token.type != :LBRACE
130
+ notify :warning, {
131
+ :message => "class defined inside a class",
132
+ :linenumber => token.line,
133
+ :column => token.column,
134
+ }
81
135
  end
82
136
  end
83
137
 
84
- if token.first == :DEFINE
85
- notify :warning, :message => "define defined inside a class", :linenumber => token.last[:line]
138
+ if token.type == :DEFINE
139
+ notify :warning, {
140
+ :message => "define defined inside a class",
141
+ :linenumber => token.line,
142
+ :column => token.column,
143
+ }
86
144
  end
87
145
  end
88
146
  end
89
147
  end
90
148
 
149
+ # Public: Test the manifest tokens for any variables that are referenced in
150
+ # the manifest. If the variables are not fully qualified or one of the
151
+ # variables automatically created in the scope, check that they have been
152
+ # defined in the local scope and record a warning for each variable that has
153
+ # not.
154
+ #
155
+ # Returns nothing.
91
156
  check 'variable_scope' do
157
+ variables_in_scope = [
158
+ 'name',
159
+ 'title',
160
+ 'module_name',
161
+ 'environment',
162
+ 'clientcert',
163
+ 'clientversion',
164
+ 'servername',
165
+ 'serverip',
166
+ 'serverversion',
167
+ 'caller_module_name',
168
+ ]
92
169
  (class_indexes + defined_type_indexes).each do |idx|
93
170
  object_tokens = tokens[idx[:start]..idx[:end]]
94
- variables_in_scope = ['name', 'title', 'module_name', 'environment', 'clientcert', 'clientversion', 'servername', 'serverip', 'serverversion', 'caller_module_name']
171
+ object_tokens.reject! { |r| formatting_tokens.include?(r.type) }
95
172
  referenced_variables = []
96
- header_end_idx = object_tokens.index { |r| r.first == :LBRACE }
97
- lparen_idx = object_tokens[0..header_end_idx].index { |r| r.first == :LPAREN }
98
- rparen_idx = object_tokens[0..header_end_idx].rindex { |r| r.first == :RPAREN }
173
+ header_end_idx = object_tokens.index { |r| r.type == :LBRACE }
174
+ lparen_idx = object_tokens[0..header_end_idx].index { |r|
175
+ r.type == :LPAREN
176
+ }
177
+ rparen_idx = object_tokens[0..header_end_idx].rindex { |r|
178
+ r.type == :RPAREN
179
+ }
99
180
 
100
181
  unless lparen_idx.nil? or rparen_idx.nil?
101
182
  param_tokens = object_tokens[lparen_idx..rparen_idx]
102
183
  param_tokens.each_index do |param_tokens_idx|
103
184
  this_token = param_tokens[param_tokens_idx]
104
185
  next_token = param_tokens[param_tokens_idx+1]
105
- if this_token.first == :VARIABLE
106
- if [:COMMA, :EQUALS, :RPAREN].include? next_token.first
107
- variables_in_scope << this_token.last[:value]
186
+ if this_token.type == :VARIABLE
187
+ if [:COMMA, :EQUALS, :RPAREN].include? next_token.type
188
+ variables_in_scope << this_token.value
108
189
  end
109
190
  end
110
191
  end
@@ -114,20 +195,25 @@ class PuppetLint::Plugins::CheckClasses < PuppetLint::CheckPlugin
114
195
  this_token = object_tokens[object_token_idx]
115
196
  next_token = object_tokens[object_token_idx + 1]
116
197
 
117
- if this_token.first == :VARIABLE
118
- if next_token.first == :EQUALS
119
- variables_in_scope << this_token.last[:value]
198
+ if this_token.type == :VARIABLE
199
+ if next_token.type == :EQUALS
200
+ variables_in_scope << this_token.value
120
201
  else
121
202
  referenced_variables << this_token
122
203
  end
123
204
  end
124
205
  end
125
206
 
207
+ msg = "top-scope variable being used without an explicit namespace"
126
208
  referenced_variables.each do |token|
127
- unless token.last[:value].include? '::'
128
- unless variables_in_scope.include? token.last[:value]
129
- unless token.last[:value] =~ /\d+/
130
- notify :warning, :message => "top-scope variable being used without an explicit namespace", :linenumber => token.last[:line]
209
+ unless token.value.include? '::'
210
+ unless variables_in_scope.include? token.value
211
+ unless token.value =~ /\d+/
212
+ notify :warning, {
213
+ :message => msg,
214
+ :linenumber => token.line,
215
+ :column => token.column,
216
+ }
131
217
  end
132
218
  end
133
219
  end
@@ -1,14 +1,24 @@
1
1
  class PuppetLint::Plugins::CheckConditionals < PuppetLint::CheckPlugin
2
+ # Public: Test the manifest tokens for any selectors embedded within resource
3
+ # declarations and record a warning for each instance found.
4
+ #
5
+ # Returns nothing.
2
6
  check 'selector_inside_resource' do
3
7
  resource_indexes.each do |resource|
4
- resource_tokens = tokens[resource[:start]..resource[:end]]
8
+ resource_tokens = tokens[resource[:start]..resource[:end]].reject { |r|
9
+ formatting_tokens.include? r.type
10
+ }
5
11
 
6
12
  resource_tokens.each_index do |resource_token_idx|
7
- if resource_tokens[resource_token_idx].first == :FARROW
8
- if resource_tokens[resource_token_idx + 1].first == :VARIABLE
13
+ if resource_tokens[resource_token_idx].type == :FARROW
14
+ if resource_tokens[resource_token_idx + 1].type == :VARIABLE
9
15
  unless resource_tokens[resource_token_idx + 2].nil?
10
- if resource_tokens[resource_token_idx + 2].first == :QMARK
11
- notify :warning, :message => "selector inside resource block", :linenumber => resource_tokens[resource_token_idx].last[:line]
16
+ if resource_tokens[resource_token_idx + 2].type == :QMARK
17
+ notify :warning, {
18
+ :message => 'selector inside resource block',
19
+ :linenumber => resource_tokens[resource_token_idx].line,
20
+ :column => resource_tokens[resource_token_idx].column,
21
+ }
12
22
  end
13
23
  end
14
24
  end
@@ -17,26 +27,23 @@ class PuppetLint::Plugins::CheckConditionals < PuppetLint::CheckPlugin
17
27
  end
18
28
  end
19
29
 
30
+ # Public: Test the manifest tokens for any case statements that do not
31
+ # contain a "default" case and record a warning for each instance found.
32
+ #
33
+ # Returns nothing.
20
34
  check 'case_without_default' do
21
35
  case_indexes = []
22
36
 
23
37
  tokens.each_index do |token_idx|
24
- if tokens[token_idx].first == :COLON
25
- # gather a list of start and end indexes for resource attribute blocks
26
- if tokens[token_idx+1].first != :LBRACE
27
- resource_indexes << {:start => token_idx+1, :end => tokens[token_idx+1..-1].index { |r| [:SEMIC, :RBRACE].include? r.first }+token_idx}
28
- end
29
- end
30
-
31
- if tokens[token_idx].first == :CASE
32
- lbrace_count = 0
33
- tokens[token_idx+1..-1].each_index do |case_token_idx|
34
- idx = case_token_idx + token_idx
35
- if tokens[idx].first == :LBRACE
36
- lbrace_count += 1
37
- elsif tokens[idx].first == :RBRACE
38
- lbrace_count -= 1
39
- if lbrace_count == 0
38
+ if tokens[token_idx].type == :CASE
39
+ depth = 0
40
+ tokens[(token_idx + 1)..-1].each_index do |case_token_idx|
41
+ idx = case_token_idx + token_idx + 1
42
+ if tokens[idx].type == :LBRACE
43
+ depth += 1
44
+ elsif tokens[idx].type == :RBRACE
45
+ depth -= 1
46
+ if depth == 0
40
47
  case_indexes << {:start => token_idx, :end => idx}
41
48
  break
42
49
  end
@@ -48,8 +55,12 @@ class PuppetLint::Plugins::CheckConditionals < PuppetLint::CheckPlugin
48
55
  case_indexes.each do |kase|
49
56
  case_tokens = tokens[kase[:start]..kase[:end]]
50
57
 
51
- unless case_tokens.index { |r| r.first == :DEFAULT }
52
- notify :warning, :message => "case statement without a default case", :linenumber => case_tokens.first.last[:line]
58
+ unless case_tokens.index { |r| r.type == :DEFAULT }
59
+ notify :warning, {
60
+ :message => 'case statement without a default case',
61
+ :linenumber => case_tokens.first.line,
62
+ :column => case_tokens.first.column,
63
+ }
53
64
  end
54
65
  end
55
66
  end
@@ -1,39 +1,79 @@
1
- # Resources
2
- # http://docs.puppetlabs.com/guides/style_guide.html#resources
3
-
4
1
  class PuppetLint::Plugins::CheckResources < PuppetLint::CheckPlugin
2
+ # Public: Check the manifest tokens for any resource titles / namevars that
3
+ # are not quoted and record a warning for each instance found.
4
+ #
5
+ # Return nothing.
5
6
  check 'unquoted_resource_title' do
6
7
  title_tokens.each do |token|
7
- if token.first == :NAME
8
- notify :warning, :message => "unquoted resource title", :linenumber => token.last[:line]
8
+ if token.type == :NAME
9
+ notify :warning, {
10
+ :message => 'unquoted resource title',
11
+ :linenumber => token.line,
12
+ :column => token.column,
13
+ }
9
14
  end
10
15
  end
11
16
  end
12
17
 
18
+ # Public: Check the tokens of each resource instance for an ensure parameter
19
+ # and if found, check that it is the first parameter listed. If it is not
20
+ # the first parameter, record a warning.
21
+ #
22
+ # Returns nothing.
13
23
  check 'ensure_first_param' do
14
24
  resource_indexes.each do |resource|
15
- resource_tokens = tokens[resource[:start]..resource[:end]]
16
- ensure_attr_index = resource_tokens.index { |token| token.first == :NAME and token.last[:value] == 'ensure' }
25
+ resource_tokens = tokens[resource[:start]..resource[:end]].reject { |r|
26
+ formatting_tokens.include? r.type
27
+ }
28
+
29
+ ensure_attr_index = resource_tokens.index { |token|
30
+ token.type == :NAME and token.value == 'ensure'
31
+ }
32
+
17
33
  unless ensure_attr_index.nil?
18
34
  if ensure_attr_index > 1
19
- ensure_attr_line_no = resource_tokens[ensure_attr_index].last[:line]
20
- notify :warning, :message => "ensure found on line but it's not the first attribute", :linenumber => ensure_attr_line_no
35
+ ensure_token = resource_tokens[ensure_attr_index]
36
+ notify :warning, {
37
+ :message => "ensure found on line but it's not the first attribute",
38
+ :linenumber => ensure_token.line,
39
+ :column => ensure_token.column,
40
+ }
21
41
  end
22
42
  end
23
43
  end
24
44
  end
25
45
 
46
+ # Public: Check the tokens of each File resource instance for a mode
47
+ # parameter and if found, record a warning if the value of that parameter is
48
+ # not a quoted string.
49
+ #
50
+ # Returns nothing.
26
51
  check 'unquoted_file_mode' do
27
52
  resource_indexes.each do |resource|
28
- resource_tokens = tokens[resource[:start]..resource[:end]]
29
- resource_type_token = tokens[tokens[0..resource[:start]].rindex { |r| r.first == :LBRACE } - 1]
30
- if resource_type_token.last[:value] == "file"
53
+ resource_tokens = tokens[resource[:start]..resource[:end]].reject { |r|
54
+ formatting_tokens.include? r.type
55
+ }
56
+
57
+ stripped_tokens = tokens[0..resource[:start]].reject { |r|
58
+ formatting_tokens.include? r.type
59
+ }
60
+
61
+ res_type_idx = stripped_tokens.rindex { |r|
62
+ r.type == :LBRACE
63
+ } - 1
64
+
65
+ resource_type_token = stripped_tokens[res_type_idx]
66
+ if resource_type_token.value == "file"
31
67
  resource_tokens.each_index do |resource_token_idx|
32
68
  attr_token = resource_tokens[resource_token_idx]
33
- if attr_token.first == :NAME and attr_token.last[:value] == 'mode'
69
+ if attr_token.type == :NAME and attr_token.value == 'mode'
34
70
  value_token = resource_tokens[resource_token_idx + 2]
35
- if value_token.first == :NAME
36
- notify :warning, :message => "unquoted file mode", :linenumber => value_token.last[:line]
71
+ if value_token.type == :NAME
72
+ notify :warning, {
73
+ :message => 'unquoted file mode',
74
+ :linenumber => value_token.line,
75
+ :column => value_token.column,
76
+ }
37
77
  end
38
78
  end
39
79
  end
@@ -41,35 +81,81 @@ class PuppetLint::Plugins::CheckResources < PuppetLint::CheckPlugin
41
81
  end
42
82
  end
43
83
 
84
+ # Public: Check the tokens of each File resource instance for a mode
85
+ # parameter and if found, record a warning if the value of that parameter is
86
+ # not a 4 digit octal value (0755) or a symbolic mode ('o=rwx,g+r').
87
+ #
88
+ # Returns nothing.
44
89
  check 'file_mode' do
90
+ msg = 'mode should be represented as a 4 digit octal value or symbolic mode'
91
+ sym_mode = /\A([ugoa]*[-=+][-=+rstwxXugo]*)(,[ugoa]*[-=+][-=+rstwxXugo]*)*\Z/
92
+
45
93
  resource_indexes.each do |resource|
46
- resource_tokens = tokens[resource[:start]..resource[:end]]
47
- resource_type_token = tokens[tokens[0..resource[:start]].rindex { |r| r.first == :LBRACE } - 1]
48
- if resource_type_token.last[:value] == "file"
94
+ resource_tokens = tokens[resource[:start]..resource[:end]].reject { |r|
95
+ formatting_tokens.include? r.type
96
+ }
97
+
98
+ stripped_tokens = tokens[0..resource[:start]].reject { |r|
99
+ formatting_tokens.include? r.type
100
+ }
101
+
102
+ res_type_idx = stripped_tokens.rindex { |r|
103
+ r.type == :LBRACE
104
+ } - 1
105
+
106
+ resource_type_token = stripped_tokens[res_type_idx]
107
+ if resource_type_token.value == "file"
49
108
  resource_tokens.each_index do |resource_token_idx|
50
109
  attr_token = resource_tokens[resource_token_idx]
51
- if attr_token.first == :NAME and attr_token.last[:value] == 'mode'
110
+ if attr_token.type == :NAME and attr_token.value == 'mode'
52
111
  value_token = resource_tokens[resource_token_idx + 2]
53
- if value_token.last[:value] !~ /\d{4}/ and value_token.first != :VARIABLE and value_token.last[:value] !~ /^([ugoa]*[-=+][-=+rstwxXugo]*)(,[ugoa]*[-=+][-=+rstwxXugo]*)*$/
54
- notify :warning, :message => "mode should be represented as a 4 digit octal value or symbolic file mode", :linenumber => value_token.last[:line]
55
- end
112
+
113
+ break if value_token.value =~ /\d{4}/
114
+ break if value_token.type == :VARIABLE
115
+ break if value_token.value =~ sym_mode
116
+
117
+ notify :warning, {
118
+ :message => msg,
119
+ :linenumber => value_token.line,
120
+ :column => value_token.column,
121
+ }
56
122
  end
57
123
  end
58
124
  end
59
125
  end
60
126
  end
61
127
 
128
+ # Public: Check the tokens of each File resource instance for an ensure
129
+ # parameter and record a warning if the value of that parameter looks like
130
+ # a symlink target (starts with a '/').
131
+ #
132
+ # Returns nothing.
62
133
  check 'ensure_not_symlink_target' do
63
134
  resource_indexes.each do |resource|
64
- resource_tokens = tokens[resource[:start]..resource[:end]]
65
- resource_type_token = tokens[tokens[0..resource[:start]].rindex { |r| r.first == :LBRACE } - 1]
66
- if resource_type_token.last[:value] == "file"
135
+ resource_tokens = tokens[resource[:start]..resource[:end]].reject { |r|
136
+ formatting_tokens.include? r.type
137
+ }
138
+
139
+ stripped_tokens = tokens[0..resource[:start]].reject { |r|
140
+ formatting_tokens.include? r.type
141
+ }
142
+
143
+ res_type_idx = stripped_tokens.rindex { |r|
144
+ r.type == :LBRACE
145
+ } - 1
146
+
147
+ resource_type_token = stripped_tokens[res_type_idx]
148
+ if resource_type_token.value == "file"
67
149
  resource_tokens.each_index do |resource_token_idx|
68
150
  attr_token = resource_tokens[resource_token_idx]
69
- if attr_token.first == :NAME and attr_token.last[:value] == 'ensure'
151
+ if attr_token.type == :NAME and attr_token.value == 'ensure'
70
152
  value_token = resource_tokens[resource_token_idx + 2]
71
- if value_token.last[:value].start_with? '/'
72
- notify :warning, :message => "symlink target specified in ensure attr", :linenumber => value_token.last[:line]
153
+ if value_token.value.start_with? '/'
154
+ notify :warning, {
155
+ :message => 'symlink target specified in ensure attr',
156
+ :linenumber => value_token.line,
157
+ :column => value_token.column,
158
+ }
73
159
  end
74
160
  end
75
161
  end