Respect indentation / spacing for existing sections and settings

This commit adds some cosmetic functionality.  The main two
improvements are:

* We'll now pay attention to indentation within existing
  sections, and when we write new settings or update
  existing ones, we'll match the existing indentation.

* When modifying existing settings, the regex now captures
  a greater portion of the original line and preserves it.
  Basically, the original whitespacing in the line should
  remain intact and only the value should be modified.
This commit is contained in:
Chris Price 2012-10-20 00:08:06 -07:00
parent a5eebcfca0
commit c2c26de9b1
3 changed files with 214 additions and 13 deletions

View file

@ -6,7 +6,7 @@ module Util
class IniFile
SECTION_REGEX = /^\s*\[([\w\d\.\\\/\-\:]+)\]\s*$/
SETTING_REGEX = /^\s*([\w\d\.\\\/\-]+)\s*=\s*([\S\s]*\S)\s*$/
SETTING_REGEX = /^(\s*)([\w\d\.\\\/\-]+)(\s*=\s*)([\S\s]*\S)\s*$/
def initialize(path, key_val_separator = ' = ')
@path = path
@ -30,7 +30,7 @@ module Util
def set_value(section_name, setting, value)
unless (@sections_hash.has_key?(section_name))
add_section(Section.new(section_name, nil, nil, nil))
add_section(Section.new(section_name, nil, nil, nil, nil))
end
section = @sections_hash[section_name]
@ -77,7 +77,7 @@ module Util
end
section.additional_settings.each_pair do |key, value|
fh.puts("#{key}#{@key_val_separator}#{value}")
fh.puts("#{' ' * (section.indentation || 0)}#{key}#{@key_val_separator}#{value}")
end
end
end
@ -111,12 +111,15 @@ module Util
def read_section(name, start_line, line_iter)
settings = {}
end_line_num = nil
min_indentation = nil
while true
line, line_num = line_iter.peek
if (line_num.nil? or match = SECTION_REGEX.match(line))
return Section.new(name, start_line, end_line_num, settings)
return Section.new(name, start_line, end_line_num, settings, min_indentation)
elsif (match = SETTING_REGEX.match(line))
settings[match[1]] = match[2]
settings[match[2]] = match[4]
indentation = match[1].length
min_indentation = [indentation, min_indentation || indentation].min
end
end_line_num = line_num
line_iter.next
@ -126,8 +129,8 @@ module Util
def update_line(section, setting, value)
(section.start_line..section.end_line).each do |line_num|
if (match = SETTING_REGEX.match(lines[line_num]))
if (match[1] == setting)
lines[line_num] = "#{setting}#{@key_val_separator}#{value}"
if (match[2] == setting)
lines[line_num] = "#{match[1]}#{match[2]}#{match[3]}#{value}"
end
end
end
@ -136,7 +139,7 @@ module Util
def remove_line(section, setting)
(section.start_line..section.end_line).each do |line_num|
if (match = SETTING_REGEX.match(lines[line_num]))
if (match[1] == setting)
if (match[2] == setting)
lines.delete_at(line_num)
end
end

View file

@ -2,15 +2,16 @@ module Puppet
module Util
class IniFile
class Section
def initialize(name, start_line, end_line, settings)
def initialize(name, start_line, end_line, settings, indentation)
@name = name
@start_line = start_line
@end_line = end_line
@existing_settings = settings.nil? ? {} : settings
@additional_settings = {}
@indentation = indentation
end
attr_reader :name, :start_line, :end_line, :additional_settings
attr_reader :name, :start_line, :end_line, :additional_settings, :indentation
def get_value(setting_name)
@existing_settings[setting_name] || @additional_settings[setting_name]

View file

@ -123,7 +123,7 @@ master = true
[section2]
foo= foovalue2
baz = bazvalue2
baz=bazvalue2
url = http://192.168.1.1:8080
[section:sub]
subby=bar
@ -154,7 +154,7 @@ foo= foovalue2
baz=bazvalue
url = http://192.168.1.1:8080
[section:sub]
subby = foo
subby=foo
#another comment
; yet another comment
EOS
@ -329,7 +329,7 @@ foo = http://192.168.1.1:8080
provider.value=('yippee')
validate_file(<<-EOS
# This is a comment
foo = yippee
foo=yippee
[section2]
foo = http://192.168.1.1:8080
; yet another comment
@ -533,4 +533,201 @@ subby=bar
end
end
context "when dealing with indentation in sections" do
let(:orig_content) {
<<-EOS
# This is a comment
[section1]
; This is also a comment
foo=foovalue
bar = barvalue
master = true
[section2]
foo= foovalue2
baz=bazvalue
url = http://192.168.1.1:8080
[section:sub]
subby=bar
#another comment
fleezy = flam
; yet another comment
EOS
}
it "should add a missing setting at the correct indentation when the header is aligned" do
resource = Puppet::Type::Ini_setting.new(common_params.merge(
:section => 'section1', :setting => 'yahoo', :value => 'yippee'))
provider = described_class.new(resource)
provider.exists?.should be_nil
provider.create
validate_file(<<-EOS
# This is a comment
[section1]
; This is also a comment
foo=foovalue
bar = barvalue
master = true
yahoo = yippee
[section2]
foo= foovalue2
baz=bazvalue
url = http://192.168.1.1:8080
[section:sub]
subby=bar
#another comment
fleezy = flam
; yet another comment
EOS
)
end
it "should update an existing setting at the correct indentation when the header is aligned" do
resource = Puppet::Type::Ini_setting.new(
common_params.merge(:section => 'section1', :setting => 'bar', :value => 'barvalue2'))
provider = described_class.new(resource)
provider.exists?.should be_true
provider.create
validate_file(<<-EOS
# This is a comment
[section1]
; This is also a comment
foo=foovalue
bar = barvalue2
master = true
[section2]
foo= foovalue2
baz=bazvalue
url = http://192.168.1.1:8080
[section:sub]
subby=bar
#another comment
fleezy = flam
; yet another comment
EOS
)
end
it "should add a missing setting at the correct indentation when the header is not aligned" do
resource = Puppet::Type::Ini_setting.new(common_params.merge(
:section => 'section2', :setting => 'yahoo', :value => 'yippee'))
provider = described_class.new(resource)
provider.exists?.should be_nil
provider.create
validate_file(<<-EOS
# This is a comment
[section1]
; This is also a comment
foo=foovalue
bar = barvalue
master = true
[section2]
foo= foovalue2
baz=bazvalue
url = http://192.168.1.1:8080
yahoo = yippee
[section:sub]
subby=bar
#another comment
fleezy = flam
; yet another comment
EOS
)
end
it "should update an existing setting at the correct indentation when the header is not aligned" do
resource = Puppet::Type::Ini_setting.new(
common_params.merge(:section => 'section2', :setting => 'baz', :value => 'bazvalue2'))
provider = described_class.new(resource)
provider.exists?.should be_true
provider.create
validate_file(<<-EOS
# This is a comment
[section1]
; This is also a comment
foo=foovalue
bar = barvalue
master = true
[section2]
foo= foovalue2
baz=bazvalue2
url = http://192.168.1.1:8080
[section:sub]
subby=bar
#another comment
fleezy = flam
; yet another comment
EOS
)
end
it "should add a missing setting at the min indentation when the section is not aligned" do
resource = Puppet::Type::Ini_setting.new(
common_params.merge(:section => 'section:sub', :setting => 'yahoo', :value => 'yippee'))
provider = described_class.new(resource)
provider.exists?.should be_nil
provider.create
validate_file(<<-EOS
# This is a comment
[section1]
; This is also a comment
foo=foovalue
bar = barvalue
master = true
[section2]
foo= foovalue2
baz=bazvalue
url = http://192.168.1.1:8080
[section:sub]
subby=bar
#another comment
fleezy = flam
; yet another comment
yahoo = yippee
EOS
)
end
it "should update an existing setting at the previous indentation when the section is not aligned" do
resource = Puppet::Type::Ini_setting.new(
common_params.merge(:section => 'section:sub', :setting => 'fleezy', :value => 'flam2'))
provider = described_class.new(resource)
provider.exists?.should be_true
provider.create
validate_file(<<-EOS
# This is a comment
[section1]
; This is also a comment
foo=foovalue
bar = barvalue
master = true
[section2]
foo= foovalue2
baz=bazvalue
url = http://192.168.1.1:8080
[section:sub]
subby=bar
#another comment
fleezy = flam2
; yet another comment
EOS
)
end
end
end