Skip to content

add hash2ini function #620

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,103 @@ Determines if a hash has a certain key value.

Converts an array into a hash. For example, `hash(['a',1,'b',2,'c',3])` returns {'a'=>1,'b'=>2,'c'=>3}. *Type*: rvalue.

#### `hash2ini`

Converts a hash into an
[INI file format](https://en.wikipedia.org/wiki/INI_file). *Type*: rvalue.

It is used when you want to overwrite an entire file with a hash of settings. If
you want to manage bits and pieces of an INI file, you want
[puppetlabs/inifile](https://github.com/puppetlabs/puppetlabs-inifile).

##### Parameters

It accepts the following optional parameters passed to it in a hash as the second argument:

* `header`: String you want at the top of the file saying it is controlled by puppet. Default: '# THIS FILE IS CONTROLLED BY PUPPET'
* `section_prefix`: String that will appear before the section's name. Default: '['
* `section_suffix`: String that will appear after the section's name. Default: ']'
* `key_val_separator`: String to use between setting name and value (e.g., to determine whether the separator includes whitespace). Default: '='.
* `quote_char`: Character or string to quote the entire value of the setting. Default: '"'

For example:

~~~
$config = {
'main' => {
'logging' => 'INFO',
'limit' => 314,
'awesome' => true,
},
'dev' => {
'logging' => 'DEBUG',
'log_location' => '/var/log/dev.log',
}
}

file {'/etc/config.ini':
ensure => 'present',
content => hash2ini($config)
}
~~~

will produce a file at /etc/config.ini that looks like:

~~~
# THIS FILE IS CONTROLLED BY PUPPET

[main]
logging="INFO"
limit="314"
awesome="true"

[dev]
logging="DEBUG"
log_location="/var/log/dev.log"
~~~

Or you can specify custom settings:

~~~
settings = {
'header' => '; THIS FILE IS CONTROLLED BY PUPPET',
'key_val_separator' => ' = ',
'quote_char' => '',
}

$php_config = {
'PHP' => {
'engine' => 'On',
'realpath_cache_size' => '32k',
'zlib.output_compression' => 'On',
'expose_php' => 'Off',
},
'Date' => {
'date.timezone' => '"America/Detroit"',
}
}

file {'/etc/php.ini':
ensure => 'present',
content => hash2ini($php_config, $settings)
}
~~~

will produce a file at /etc/php.ini that looks like:

~~~
; THIS FILE IS CONTROLLED BY PUPPET

[PHP]
engine = On
realpath_cache_size = 32k
zlib.output_compression = On
expose_php = Off

[Date]
date.timezone = "America/Detroit"
~~~

#### `intersection`

Returns an array an intersection of two. For example, `intersection(["a","b","c"],["b","c","d"])` returns ["b","c"]. *Type*: rvalue.
Expand Down
47 changes: 47 additions & 0 deletions lib/puppet/parser/functions/hash2ini.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
module Puppet::Parser::Functions
newfunction(:hash2ini, :type => :rvalue, :doc => <<-EOS
This converts a puppet hash to an INI string.
EOS
) do |arguments|

if arguments.size < 1
raise(Puppet::ParseError, 'hash2ini(): requires at least one argument')
end
if arguments.size >= 3
raise(Puppet::ParseError, 'hash2ini(): too many arguments')
end
unless arguments[0].is_a?(Hash)
raise(Puppet::ParseError, 'hash2ini(): requires a hash as argument')
end

h = arguments[0]

settings = {
'header' => '# THIS FILE IS CONTROLLED BY PUPPET',
'section_prefix' => '[',
'section_suffix' => ']',
'key_val_separator' => '=',
'quote_char' => '"',
}

if arguments[1]
unless arguments[1].is_a?(Hash)
raise(Puppet::ParseError, 'hash2ini(): Requires a hash as argument')
end
settings.merge!(arguments[1])
end



ini = []
ini << settings['header'] << nil
h.keys.each do |section|
ini << "#{settings['section_prefix']}#{section}#{settings['section_suffix']}"
h[section].each do |k, v|
ini << "#{k}#{settings['key_val_separator']}#{settings['quote_char']}#{v}#{settings['quote_char']}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will behave strangely if v is not a string.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is true. I can document that a string is expected for the value, all merging of of arrays of values must be done beforehand. There's no real standard on arrays of values for ini files so I'd just leave it up to the programmer to do what is necessary rather than put the logic in hash2ini().

end
ini << nil
end
return ini.join("\n")
end
end
59 changes: 59 additions & 0 deletions spec/functions/hash2ini_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
require 'spec_helper'

describe 'hash2ini' do
it { is_expected.not_to eq(nil) }
it { is_expected.to run.with_params().and_raise_error(Puppet::ParseError, /requires at least one argument/) }
it { is_expected.to run.with_params({}, {}, {}).and_raise_error(Puppet::ParseError, /too many arguments/) }
it { is_expected.to run.with_params('some string').and_raise_error(Puppet::ParseError, /requires a hash as argument/) }

example_input = {
'main' => {
'logging' => 'INFO',
'limit' => 314,
'awesome' => true,
},
'dev' => {
'logging' => 'DEBUG',
'log_location' => '/var/log/dev.log',
}
}

context 'no custom settings' do
output=<<-EOS
# THIS FILE IS CONTROLLED BY PUPPET

[main]
logging="INFO"
limit="314"
awesome="true"

[dev]
logging="DEBUG"
log_location="/var/log/dev.log"
EOS
it { is_expected.to run.with_params(example_input).and_return(output) }
end

context 'custom settings' do
settings = {
'header' => '; THIS FILE IS CONTROLLED BY /dev/random',
'section_prefix' => '[[',
'section_suffix' => ']]',
'key_val_separator' => ': ',
'quote_char' => "",
}
output=<<-EOS
; THIS FILE IS CONTROLLED BY /dev/random

[[main]]
logging: INFO
limit: 314
awesome: true

[[dev]]
logging: DEBUG
log_location: /var/log/dev.log
EOS
it { is_expected.to run.with_params(example_input, settings).and_return(output) }
end
end