Class: Puppet::Util::PTomulik::Package::Ports::Options

Inherits:
Object
  • Object
show all
Extended by:
Execution
Includes:
Vash::Contained
Defined in:
lib/puppet/util/ptomulik/package/ports/options.rb

Overview

Maintain FreeBSD ports options (normally settable with ‘make config`).

This is just a hash with simple validation and few additional methods for loading, parsing and saving ports options to a file.

### Options as a validating hash

The hash accepts Strings or Symbols as keys. When entering the hash, keys are validated against a regexp accepting only well-formed identifiers (‘/^[a-zA-Z_]w*$/`). The values must be either `true`/`false` boolean values, `:on`/`:off` symbols or `’on’‘/`’off’‘ strings. If validation fails an exception is raised. The class uses [vash](github.com/ptomulik/puppet-vash) module to enforce validation and munging, and it is vash who defines the exceptions being raised.

Keys and values are internally munged, such that all input keys get converted to symbols and input values to booleans. For example:

require 'puppet/util/ptomulik/package/ports/options'
opts = Puppet::Util::PTomulik::Package::Ports::Options.new
opts['FOO'] = 'off'
puts opts.inspect

would print ‘:FOO=>false`.

### Loading and saving options

Options can be loaded from FreeBSD port options files or extracted from a string. They may be further converted to a string or saved to a file. The class provides following methods for that:

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Execution

execpipe, execute_command

Class Method Details

.load(files, params = {}) ⇒ Object

Read options from options files. Missing files from __files__ list are ignored by default.

Parameters:

  • files (String|Array)

    file name (or array of file names) to be scanned for ports options, the files get loaded in order specified in __files__ array; options found in later files overwrite the earlier options,

  • params (Hash) (defaults to: {})

    additional parameters to alter method behavior

Options Hash (params):

  • :all (Boolean)

    load options from all files listed in __files__ (don’t skip missing files), if a file is missing the method will fail with an exception instead of silently ignoring missing files,



143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/puppet/util/ptomulik/package/ports/options.rb', line 143

def self.load(files,params={})
  files = [files] unless files.is_a?(Array)
  # concatenate all files in order ...
  contents = []
  files.each do|file|
    next if (not File.exists?(file)) and not params[:all]
    msg = "Reading port options from '#{file}'"
    respond_to?(:debug) ? debug(msg) : Puppet.debug(msg)
    contents << File.read(file)
  end
  parse(contents.join("\n"))
end

.munge_option_name(name) ⇒ Symbol

Convert valid option names to symbols

Parameters:

  • name (String|Symbol)

    input name to be munged

Returns:

  • (Symbol)

    the ‘name` converted to Symbol



75
76
77
78
# File 'lib/puppet/util/ptomulik/package/ports/options.rb', line 75

def self.munge_option_name(name)
  # note, on 1.8 Symbol has no :intern method
  name.is_a?(String) ? name.intern : name
end

.munge_option_value(value) ⇒ Boolean

Convert valid option values (strings, symbols) to boolean values

Parameters:

  • value (String|Symbol|Boolean)

    input value to be munged,

Returns:

  • (Boolean)

    ‘true` if the `value` is `true`, `:on`, or `on`; otherwise `false`



86
87
88
89
90
91
# File 'lib/puppet/util/ptomulik/package/ports/options.rb', line 86

def self.munge_option_value(value)
  case value
  when 'on', :on, true; true
  else; false
  end
end

.option_name?(x) ⇒ Boolean

Is x valid as option name?

Parameters:

  • x

    an input value to be checked

Returns:

  • (Boolean)

    ‘true` if `x` is a valid option name, `false` if not.



56
57
58
59
# File 'lib/puppet/util/ptomulik/package/ports/options.rb', line 56

def self.option_name?(x)
  x = x.to_s if x.is_a?(Symbol)
  x.is_a?(String) and x =~ /^\w+$/
end

.option_value?(x) ⇒ Boolean

Is x valid as option value?

Parameters:

  • x

    an input value to be checked

Returns:

  • (Boolean)

    ‘true` if `x` is a valid option value, `false` if not



66
67
68
# File 'lib/puppet/util/ptomulik/package/ports/options.rb', line 66

def self.option_value?(x)
  ['on', 'off', :on, :off, true, false].include?(x)
end

.parse(string) ⇒ Puppet::Util::PTomulik::Package::Ports::Options

Parse string for options.

Parameters:

  • string (String)

    a content of options file to be scanned for options,

Returns:



123
124
125
126
127
128
129
130
# File 'lib/puppet/util/ptomulik/package/ports/options.rb', line 123

def self.parse(string)
  re1 = /OPTIONS_FILE_((?:UN)?SET)\s*\+=\s*(\w+)/
  re2 = /(WITH(?:OUT)?)_(\w+)\s*=.*/
  opt_re = /^\s*(?:#{re1})|(?:#{re2})\s*$/
  Options[string.scan(opt_re).map { |m|
    (m[2] && m[3]) ? [m[3], m[2] == 'WITH'] : [m[1], m[0]=='SET']
  } ]
end

.query_pkgng(key, packages = nil, params = {}) ⇒ Hash

Query pkgng for package options.

This method executes

pkg query "#{key} %Ok %Ov" ...

to extract package options for (a list of) installed package(s). See pkg-query(8) for query formats used by ‘pkg query`.

Parameters:

  • key (String)

    determines what will be used as keys in the returned hash; example values are ‘’%n’‘ - return pkgnames in keys, `’%o’‘ return pkgorigins in keys,

  • packages (Array) (defaults to: nil)

    list of packages to be queried; if not given, query all the installed packages,

  • params (Hash) (defaults to: {})

    additional parameters to alter method’s behavior,

Options Hash (params):

  • :execpipe (Method)

    handle to a method which provides ‘execpipe` functionality, should have same interface as `Puppet::Util::Execution#execpipe`,

  • :pkg (String)

    absolute path to the ‘pkg` command,

Returns:

  • (Hash)

    a hash in form ‘’package’=>{‘OPTION’=>value,…, … }‘, what is put in keys (`’package’‘ in the above example) depends on the __key__ argument,



181
182
183
184
185
186
187
188
189
190
191
# File 'lib/puppet/util/ptomulik/package/ports/options.rb', line 181

def self.query_pkgng(key,packages=nil,params={})
  options = {}
  if packages
    packages.each_slice(self::PKG_ARGS_MAX) do |slice|
      query_pkgng_1(key,slice,params) { |hash| options.merge!(hash) }
    end
  else
    query_pkgng_1(key,[],params) {|hash| options.merge!(hash) }
  end
  options
end

Instance Method Details

#generate(params) ⇒ String

Write to a string all the options in form suitable to be saved as an options file. This is symmetric to what parse does.

Parameters:

  • params (Hash)

    hash of parameters to alter method’s behavior

Options Hash (params):

  • :pkgname (String)

    package name to which the options apply, by convention it should be a pkgname of the given package.

  • :syntax (Symbol)

    choose syntax:

    • ‘:with_without` - variables are written in form `WITH_XXX=true|false`

    • ‘:set_unset` - variables are written in form `OPTIONS_FILE_SET+=XXX`

Returns:

  • (String)

    the generated content as string.



220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/puppet/util/ptomulik/package/ports/options.rb', line 220

def generate(params)
  content  = "# This file is auto-generated by puppet\n"
  if params[:pkgname]
    content += "# Options for #{params[:pkgname]}\n"
    content += "_OPTIONS_READ=#{params[:pkgname]}\n"
  end
  genvar = if params[:syntax] == :with_without
             lambda { |k,v| "WITH#{ v ? '' : 'OUT'}_#{k}=true\n" }
           else
             lambda { |k,v| "OPTIONS_FILE_#{v ? '':'UN'}SET+=#{k}\n" }
           end
  keys.sort.each { |k| content += genvar.call(k, self[k]) }
  content
end

#save(file, params = {}) ⇒ Object

Note:

by default we do not allow to create directories recursivelly; we assume, that ‘/var/db/ports’ already exists and user saves its options to ‘/var/db/ports/my_port/options’;

Save package options to options file.

Parameters:

  • file (String)

    path to options’ file.

  • params (Hash) (defaults to: {})

    additional parameters to function

Options Hash (params):

  • :pkgname (String)

    package name to which the options apply, by convention it should be a pkgname of the given package,

  • :mkdir_p (Boolean)

    create directories recursively if they don’t exist; if ‘false`, only last level subdirectory is allowed to be created.

  • :syntax (Symbol)

    see #generate



250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/puppet/util/ptomulik/package/ports/options.rb', line 250

def save(file,params={})
  dir = File.dirname(file)
  if not File.exists?(dir)
    msg = "Creating directory #{dir}"
    respond_to?(:debug) ? debug(msg) : Puppet.debug(msg)
    params[:mkdir_p] ?  FileUtils.mkdir_p(dir) : Dir.mkdir(dir)
  end
  msg = params[:pkgname] ?
    "Saving options for '#{params[:pkgname]}' port to file '#{file}'" :
    "Saving port options to file '#{file}'"
  respond_to?(:debug) ? debug(msg) : Puppet.debug(msg)
  File.open(file, 'w') { |f| f.write(generate(params)) }
end

#vash_key_name(*args) ⇒ Object

Used by Vash as a key name.



106
# File 'lib/puppet/util/ptomulik/package/ports/options.rb', line 106

def vash_key_name(*args);   'option name';                       end

#vash_munge_key(key) ⇒ Object

Required by Vash to have key munging in place.



102
# File 'lib/puppet/util/ptomulik/package/ports/options.rb', line 102

def vash_munge_key(key);    self.class.munge_option_name(key);   end

#vash_munge_value(val) ⇒ Object

Required by Vash to have value munging in place.



104
# File 'lib/puppet/util/ptomulik/package/ports/options.rb', line 104

def vash_munge_value(val);  self.class.munge_option_value(val);  end

#vash_valid_key?(x) ⇒ Boolean

Required by Vash to have key validation in place.

Returns:

  • (Boolean)


98
# File 'lib/puppet/util/ptomulik/package/ports/options.rb', line 98

def vash_valid_key?(x);     self.class.option_name?(x);          end

#vash_valid_value?(x) ⇒ Boolean

Required by Vash to have value validation in place.

Returns:

  • (Boolean)


100
# File 'lib/puppet/util/ptomulik/package/ports/options.rb', line 100

def vash_valid_value?(x);   self.class.option_value?(x);         end

#vash_value_exception(val, *args) ⇒ Object

Used by Vash as to generate exceptions for invalid option values.



108
109
110
111
112
113
114
# File 'lib/puppet/util/ptomulik/package/ports/options.rb', line 108

def vash_value_exception(val,*args)
  name = vash_value_name(val,*args)
  msg  = "invalid value #{val.inspect}"
  msg += " at position  #{args[0].inspect}" unless args[0].nil?
  msg += " for option #{args[1].to_s}" unless args.length < 2
  [Puppet::Util::PTomulik::Vash::InvalidValueError, msg]
end