summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorChris Price <chris@puppetlabs.com>2012-07-28 21:59:54 -0700
committerChris Price <chris@puppetlabs.com>2012-07-28 21:59:54 -0700
commit9c76b6af1200c71e7ae72e0e2f349919a3081738 (patch)
treee3dc5ca1824f1fcf74c08e78d649eed394408a78 /lib
parent91273a5a2b0c88e7129908406fd0933a0d88ef11 (diff)
downloadpuppet-inifile-9c76b6af1200c71e7ae72e0e2f349919a3081738.tar.gz
puppet-inifile-9c76b6af1200c71e7ae72e0e2f349919a3081738.tar.bz2
First (basic) working version of ini_setting provider
Diffstat (limited to 'lib')
-rw-r--r--lib/puppet/provider/ini_setting/ruby.rb19
-rw-r--r--lib/puppet/type/ini_setting.rb26
-rw-r--r--lib/puppet/util/external_iterator.rb24
-rw-r--r--lib/puppet/util/ini_file.rb132
-rw-r--r--lib/puppet/util/ini_file/section.rb34
5 files changed, 235 insertions, 0 deletions
diff --git a/lib/puppet/provider/ini_setting/ruby.rb b/lib/puppet/provider/ini_setting/ruby.rb
index e69de29..e44a107 100644
--- a/lib/puppet/provider/ini_setting/ruby.rb
+++ b/lib/puppet/provider/ini_setting/ruby.rb
@@ -0,0 +1,19 @@
+require 'puppet/util/ini_file'
+
+Puppet::Type.type(:ini_setting).provide(:ruby) do
+ def exists?
+ ini_file.get_value(resource[:section], resource[:setting]) == resource[:value]
+ end
+
+ def create
+ ini_file.set_value(resource[:section], resource[:setting], resource[:value])
+ ini_file.save
+ @ini_file = nil
+ end
+
+
+ private
+ def ini_file
+ @ini_file ||= Puppet::Util::IniFile.new(resource[:path])
+ end
+end
diff --git a/lib/puppet/type/ini_setting.rb b/lib/puppet/type/ini_setting.rb
index fb7f6e2..9af47c1 100644
--- a/lib/puppet/type/ini_setting.rb
+++ b/lib/puppet/type/ini_setting.rb
@@ -4,4 +4,30 @@ Puppet::Type.newtype(:ini_setting) do
defaultvalues
defaultto :present
end
+
+ newparam(:name, :namevar => true) do
+ desc 'An arbitrary name used as the identity of the resource.'
+ end
+
+ newparam(:section) do
+ desc 'The name of the section in the ini file in which the setting should be defined.'
+ end
+
+ newparam(:setting) do
+ desc 'The name of the setting to be defined.'
+ end
+
+ newparam(:value) do
+ desc 'The value of the setting to be defined.'
+ end
+
+ newparam(:path) do
+ desc 'The ini file Puppet will ensure contains the specified setting.'
+ validate do |value|
+ unless (Puppet.features.posix? and value =~ /^\//) or (Puppet.features.microsoft_windows? and (value =~ /^.:\// or value =~ /^\/\/[^\/]+\/[^\/]+/))
+ raise(Puppet::Error, "File paths must be fully qualified, not '#{value}'")
+ end
+ end
+ end
+
end \ No newline at end of file
diff --git a/lib/puppet/util/external_iterator.rb b/lib/puppet/util/external_iterator.rb
new file mode 100644
index 0000000..67b3375
--- /dev/null
+++ b/lib/puppet/util/external_iterator.rb
@@ -0,0 +1,24 @@
+module Puppet
+module Util
+ class ExternalIterator
+ def initialize(coll)
+ @coll = coll
+ @cur_index = 0
+ end
+
+ def next
+ @cur_index = @cur_index + 1
+ item_at(@cur_index)
+ end
+
+ def peek
+ item_at(@cur_index + 1)
+ end
+
+ private
+ def item_at(index)
+ [@coll[index], index]
+ end
+ end
+end
+end
diff --git a/lib/puppet/util/ini_file.rb b/lib/puppet/util/ini_file.rb
new file mode 100644
index 0000000..75d8a9f
--- /dev/null
+++ b/lib/puppet/util/ini_file.rb
@@ -0,0 +1,132 @@
+require 'puppet/util/external_iterator'
+require 'puppet/util/ini_file/section'
+
+module Puppet
+module Util
+ class IniFile
+
+ SECTION_REGEX = /^\s*\[([\w\d\.]+)\]\s*$/
+ SETTING_REGEX = /^\s*([\w\d\.]+)\s*=\s*([\w\d\.]+)\s*$/
+
+ def initialize(path)
+ @path = path
+ @section_names = []
+ @sections_hash = {}
+
+ parse_file
+ end
+
+ def section_names
+ @section_names
+ end
+
+ def get_value(section_name, setting)
+ if (@sections_hash.has_key?(section_name))
+ @sections_hash[section_name].get_value(setting)
+ end
+ end
+
+ def set_value(section_name, setting, value)
+ unless (@sections_hash.has_key?(section_name))
+ add_section(Section.new(section_name, nil, nil, nil))
+ end
+
+ section = @sections_hash[section_name]
+ if (section.has_existing_setting?(setting))
+ update_line(section, setting, value)
+ section.update_existing_setting(setting, value)
+ else
+ section.set_additional_setting(setting, value)
+ end
+ end
+
+ def save
+ File.open(@path, 'w') do |fh|
+ first_section = @sections_hash[@section_names[0]]
+ (0..first_section.start_line - 1).each do |line_num|
+ fh.puts(lines[line_num])
+ end
+
+ @section_names.each do |name|
+ section = @sections_hash[name]
+
+ if (section.start_line.nil?)
+ fh.puts("\n[#{section.name}]")
+ else
+ (section.start_line..section.end_line).each do |line_num|
+ fh.puts(lines[line_num])
+ end
+ end
+
+ section.additional_settings.each_pair do |key, value|
+ fh.puts("#{key} = #{value}")
+ end
+ end
+ end
+ end
+
+
+ private
+ def add_section(section)
+ @sections_hash[section.name] = section
+ @section_names << section.name
+ end
+
+ def parse_file
+ line_iter = create_line_iter
+ line, line_num = line_iter.next
+ while line
+ if (match = SECTION_REGEX.match(line))
+ section = read_section(match[1], line_num, line_iter)
+ add_section(section)
+ end
+ line, line_num = line_iter.next
+ end
+ end
+
+ def read_section(name, start_line, line_iter)
+ settings = {}
+ while true
+ line, line_num = line_iter.peek
+ if (line.nil? or match = SECTION_REGEX.match(line))
+ return Section.new(name, start_line, line_num - 1, settings)
+ elsif (match = SETTING_REGEX.match(line))
+ settings[match[1]] = match[2]
+ end
+
+ line_iter.next
+ end
+ end
+
+ 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} = #{value}"
+ end
+ end
+ end
+ end
+
+ def create_line_iter
+ ExternalIterator.new(lines)
+ end
+
+ def lines
+ @lines ||= IniFile.readlines(@path)
+ end
+
+ # This is mostly here because it makes testing easier--we don't have
+ # to try to stub any methods on File.
+ def self.readlines(path)
+ # If this type is ever used with very large files, we should
+ # write this in a different way, using a temp
+ # file; for now assuming that this type is only used on
+ # small-ish config files that can fit into memory without
+ # too much trouble.
+ File.readlines(path)
+ end
+
+ end
+end
+end \ No newline at end of file
diff --git a/lib/puppet/util/ini_file/section.rb b/lib/puppet/util/ini_file/section.rb
new file mode 100644
index 0000000..39f2959
--- /dev/null
+++ b/lib/puppet/util/ini_file/section.rb
@@ -0,0 +1,34 @@
+module Puppet
+module Util
+class IniFile
+ class Section
+ def initialize(name, start_line, end_line, settings)
+ @name = name
+ @start_line = start_line
+ @end_line = end_line
+ @existing_settings = settings.nil? ? {} : settings
+ @additional_settings = {}
+ end
+
+ attr_reader :name, :start_line, :end_line, :additional_settings
+
+ def get_value(setting_name)
+ @existing_settings[setting_name] || @additional_settings[setting_name]
+ end
+
+ def has_existing_setting?(setting_name)
+ @existing_settings.has_key?(setting_name)
+ end
+
+ def update_existing_setting(setting_name, value)
+ @existing_settings[setting_name] = value
+ end
+
+ def set_additional_setting(setting_name, value)
+ @additional_settings[setting_name] = value
+ end
+
+ end
+end
+end
+end \ No newline at end of file