Suggest different variables to use if we want to tunnel both v4 and v6
[mirror/dsa-puppet.git] / 3rdparty / modules / stdlib / lib / puppet / provider / file_line / ruby.rb
1 Puppet::Type.type(:file_line).provide(:ruby) do
2   def exists?
3     found = false
4     lines_count = 0
5     lines.each do |line|
6       found = line.chomp == resource[:line]
7       if found
8         lines_count += 1
9       end
10     end
11     return found = lines_count > 0 if resource[:match].nil?
12
13     match_count = count_matches(new_match_regex)
14     found = if resource[:ensure] == :present
15               if match_count.zero?
16                 if lines_count.zero? && resource[:append_on_no_match].to_s == 'false'
17                   true # lies, but gets the job done
18                 elsif lines_count.zero? && resource[:append_on_no_match].to_s != 'false'
19                   false
20                 else
21                   true
22                 end
23               elsif resource[:replace_all_matches_not_matching_line].to_s == 'true'
24                 false # maybe lies, but knows there's still work to do
25               elsif lines_count.zero?
26                 resource[:replace].to_s == 'false'
27               else
28                 true
29               end
30             elsif match_count.zero?
31               if lines_count.zero?
32                 false
33               else
34                 true
35               end
36             elsif lines_count.zero?
37               resource[:match_for_absence].to_s == 'true'
38             else
39               true
40             end
41   end
42
43   def create
44     return if resource[:replace].to_s != 'true' && count_matches(new_match_regex) > 0
45     if resource[:match]
46       handle_create_with_match
47     elsif resource[:after]
48       handle_create_with_after
49     else
50       handle_append_line
51     end
52   end
53
54   def destroy
55     if resource[:match_for_absence].to_s == 'true' && resource[:match]
56       handle_destroy_with_match
57     else
58       handle_destroy_line
59     end
60   end
61
62   private
63
64   def lines
65     # If this type is ever used with very large files, we should
66     #  write this in a different way, using a temp
67     #  file; for now assuming that this type is only used on
68     #  small-ish config files that can fit into memory without
69     #  too much trouble.
70
71     @lines ||= File.readlines(resource[:path], :encoding => resource[:encoding])
72   rescue TypeError => _e
73     # Ruby 1.8 doesn't support open_args
74     @lines ||= File.readlines(resource[:path])
75   end
76
77   def new_after_regex
78     resource[:after] ? Regexp.new(resource[:after]) : nil
79   end
80
81   def new_match_regex
82     resource[:match] ? Regexp.new(resource[:match]) : nil
83   end
84
85   def count_matches(regex)
86     lines.select { |line|
87       if resource[:replace_all_matches_not_matching_line].to_s == 'true'
88         line.match(regex) unless line.chomp == resource[:line]
89       else
90         line.match(regex)
91       end
92     }.size
93   end
94
95   def handle_create_with_match
96     after_regex = new_after_regex
97     match_regex = new_match_regex
98     match_count = count_matches(new_match_regex)
99
100     if match_count > 1 && resource[:multiple].to_s != 'true'
101       raise Puppet::Error, "More than one line in file '#{resource[:path]}' matches pattern '#{resource[:match]}'"
102     end
103
104     File.open(resource[:path], 'w') do |fh|
105       lines.each do |line|
106         fh.puts(match_regex.match(line) ? resource[:line] : line)
107         next unless match_count.zero? && after_regex
108         if after_regex.match(line)
109           fh.puts(resource[:line])
110           match_count += 1 # Increment match_count to indicate that the new line has been inserted.
111         end
112       end
113
114       if match_count.zero?
115         fh.puts(resource[:line])
116       end
117     end
118   end
119
120   def handle_create_with_after
121     after_regex = new_after_regex
122     after_count = count_matches(after_regex)
123
124     if after_count > 1 && resource[:multiple].to_s != 'true'
125       raise Puppet::Error, "#{after_count} lines match pattern '#{resource[:after]}' in file '#{resource[:path]}'. One or no line must match the pattern."
126     end
127
128     File.open(resource[:path], 'w') do |fh|
129       lines.each do |line|
130         fh.puts(line)
131         if after_regex.match(line)
132           fh.puts(resource[:line])
133         end
134       end
135
136       if after_count.zero?
137         fh.puts(resource[:line])
138       end
139     end
140   end
141
142   def handle_destroy_with_match
143     match_regex = new_match_regex
144     match_count = count_matches(match_regex)
145     if match_count > 1 && resource[:multiple].to_s != 'true'
146       raise Puppet::Error, "More than one line in file '#{resource[:path]}' matches pattern '#{resource[:match]}'"
147     end
148
149     local_lines = lines
150     File.open(resource[:path], 'w') do |fh|
151       fh.write(local_lines.reject { |line| match_regex.match(line) }.join(''))
152     end
153   end
154
155   def handle_destroy_line
156     local_lines = lines
157     File.open(resource[:path], 'w') do |fh|
158       fh.write(local_lines.reject { |line| line.chomp == resource[:line] }.join(''))
159     end
160   end
161
162   def handle_append_line
163     local_lines = lines
164     File.open(resource[:path], 'w') do |fh|
165       local_lines.each do |line|
166         fh.puts(line)
167       end
168       fh.puts(resource[:line])
169     end
170   end
171 end