Skip to content

Commit 54ffdd8

Browse files
committed
(MODULES-5651) Do not append infinitely
https://tickets.puppetlabs.com/browse/MODULES-5003 gave rise to #788 and #794 which caused different behavior based on whether the line value was matched by the match regex or not. The change in behavior was both breaking and broken, though that was hard to tell because the behavior was ill-described in general. [bugfix] This commit resolves the breaking behavior by reverting the behavior of "replacing matches when a line matching `line` exists even when `multiple` is set to `true`". [feature] This commit adds a new parameter to make file_line replace all matches universally with the `line` value, even when the line exists elsewhere in the file. This feature only affects modifying multiple lines in a file when the `line` value already exists. [bugfix] This commit more strictly defines the various interactions of `ensure`, `match`, `append_on_no_match`, `replace`, `multiple`, and `replace_all_matches_not_matching_line`. It also more clearly documents and tests these interactions.
1 parent 2339ea8 commit 54ffdd8

File tree

4 files changed

+555
-270
lines changed

4 files changed

+555
-270
lines changed

README.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ Values: String.
219219

220220
##### `match`
221221

222-
Specifies a regular expression to compare against existing lines in the file; if a match is found, it is replaced rather than adding a new line. A regex comparison is performed against the line value, and if it does not match, an exception is raised.
222+
Specifies a regular expression to compare against existing lines in the file; if a match is found, it is replaced rather than adding a new line.
223223

224224
Values: String containing a regex.
225225

@@ -236,7 +236,7 @@ Default value: `false`.
236236

237237
##### `multiple`
238238

239-
Specifies whether `match` and `after` can change multiple lines. If set to `false`, an exception is raised if more than one line matches.
239+
Specifies whether `match` and `after` can change multiple lines. If set to `false`, allows file\_line to replace only one line and raises an error if more than one will be replaced. If set to `true`, allows file\_line to replace one or more lines.
240240

241241
Values: `true`, `false`.
242242

@@ -261,12 +261,20 @@ Value: String specifying an absolute path to the file.
261261

262262
##### `replace`
263263

264-
Specifies whether the resource overwrites an existing line that matches the `match` parameter. If set to `false` and a line is found matching the `match` parameter, the line is not placed in the file.
264+
Specifies whether the resource overwrites an existing line that matches the `match` parameter when `line` does not otherwise exist.
265+
266+
If set to `false` and a line is found matching the `match` parameter, the line is not placed in the file.
265267

266268
Boolean.
267269

268270
Default value: `true`.
269271

272+
##### `replace_all_matches_not_matching_line`
273+
274+
Replace all lines matched by `match` parameter, even if `line` already exists in the file.
275+
276+
Default value: `false`.
277+
270278
### Data types
271279

272280
#### `Stdlib::Absolutepath`

lib/puppet/provider/file_line/ruby.rb

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,50 @@ def exists?
1212
found = lines_count > 0
1313
else
1414
match_count = count_matches(new_match_regex)
15-
if resource[:append_on_no_match].to_s == 'false'
16-
found = true
17-
elsif resource[:replace].to_s == 'true'
18-
found = lines_count > 0 && lines_count == match_count
15+
if resource[:ensure] == :present
16+
if match_count == 0
17+
if lines_count == 0
18+
if resource[:append_on_no_match].to_s == 'false'
19+
found = true # lies, but gets the job done
20+
else
21+
found = false
22+
end
23+
else
24+
found = true
25+
end
26+
else
27+
if resource[:replace_all_matches_not_matching_line].to_s == 'true'
28+
found = false # maybe lies, but knows there's still work to do
29+
else
30+
if lines_count == 0
31+
if resource[:replace].to_s == 'false'
32+
found = true
33+
else
34+
found = false
35+
end
36+
else
37+
found = true
38+
end
39+
end
40+
end
1941
else
20-
found = match_count > 0
42+
if match_count == 0
43+
if lines_count == 0
44+
found = false
45+
else
46+
found = true
47+
end
48+
else
49+
if lines_count == 0
50+
if resource[:match_for_absence].to_s == 'true'
51+
found = true # found matches, not lines
52+
else
53+
found = false
54+
end
55+
else
56+
found = true
57+
end
58+
end
2159
end
2260
end
2361
found
@@ -68,7 +106,13 @@ def new_match_regex
68106
end
69107

70108
def count_matches(regex)
71-
lines.select{ |line| line.match(regex) }.size
109+
lines.select do |line|
110+
if resource[:replace_all_matches_not_matching_line].to_s == 'true'
111+
line.match(regex) unless line.chomp == resource[:line]
112+
else
113+
line.match(regex)
114+
end
115+
end.size
72116
end
73117

74118
def handle_create_with_match()
@@ -140,8 +184,9 @@ def handle_destroy_line
140184
end
141185

142186
def handle_append_line
187+
local_lines = lines
143188
File.open(resource[:path],'w') do |fh|
144-
lines.each do |line|
189+
local_lines.each do |line|
145190
fh.puts(line)
146191
end
147192
fh.puts(resource[:line])

lib/puppet/type/file_line.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,13 @@ def retrieve
151151
defaultto true
152152
end
153153

154+
newparam(:replace_all_matches_not_matching_line) do
155+
desc 'Configures the behavior of replacing all lines in a file which match the `match` parameter regular expression, regardless of whether the specified line is already present in the file.'
156+
157+
newvalues(true, false)
158+
defaultto false
159+
end
160+
154161
newparam(:encoding) do
155162
desc 'For files that are not UTF-8 encoded, specify encoding such as iso-8859-1'
156163
defaultto 'UTF-8'
@@ -168,6 +175,12 @@ def retrieve
168175
end
169176

170177
validate do
178+
if self[:replace_all_matches_not_matching_line].to_s == 'true' and self[:multiple].to_s == 'false'
179+
raise(Puppet::Error, "multiple must be true when replace_all_matches_not_matching_line is true")
180+
end
181+
if self[:replace_all_matches_not_matching_line].to_s == 'true' and self[:replace].to_s == 'false'
182+
raise(Puppet::Error, "replace must be true when replace_all_matches_not_matching_line is true")
183+
end
171184
unless self[:line]
172185
unless (self[:ensure].to_s == 'absent') and (self[:match_for_absence].to_s == 'true') and self[:match]
173186
raise(Puppet::Error, "line is a required attribute")

0 commit comments

Comments
 (0)