Module: Puppet::Util::Plist

Defined in:
lib/puppet/util/plist.rb

Defined Under Namespace

Classes: FormatError

Class Method Summary collapse

Class Method Details

.binary_plist_magic_numberObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Defines the magic number for binary plists



15
16
17
# File 'lib/puppet/util/plist.rb', line 15

def binary_plist_magic_number
  "bplist00"
end

.convert_cfpropertylist_to_native_types(plist_obj) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Helper method to assist in converting a native CFPropertyList object to a native Ruby object (hash). It’s its own method for stubbing purposes



103
104
105
# File 'lib/puppet/util/plist.rb', line 103

def convert_cfpropertylist_to_native_types(plist_obj)
  CFPropertyList.native_types(plist_obj.value)
end

.dump_plist(plist_data, format = :xml) ⇒ Object



147
148
149
150
151
# File 'lib/puppet/util/plist.rb', line 147

def dump_plist(plist_data, format = :xml)
  plist_to_save       = CFPropertyList::List.new
  plist_to_save.value = CFPropertyList.guess(plist_data)
  plist_to_save.to_str(to_format(format), :formatted => true)
end

.new_cfpropertylist(plist_opts) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Helper method to assist in generating a new CFPropertyList Plist. It’s its own method for stubbing purposes



95
96
97
# File 'lib/puppet/util/plist.rb', line 95

def new_cfpropertylist(plist_opts)
  CFPropertyList::List.new(plist_opts)
end

.open_file_with_args(file, args) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Helper method to assist in reading a file. It’s its own method for stubbing purposes

Parameters:

  • args (String)

    Extra file operation mode information to use (defaults to read-only mode ‘r’) This is the standard mechanism Ruby uses in the IO class, and therefore encoding may be explicitly like fmode : encoding or fmode : “BOM|UTF-*” for example, a:ASCII or w+:UTF-8



87
88
89
# File 'lib/puppet/util/plist.rb', line 87

def open_file_with_args(file, args)
  File.open(file, args).read
end

.parse_plist(plist_data, file_path = '') ⇒ Object

Read plist text using the CFPropertyList gem.



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/puppet/util/plist.rb', line 55

def parse_plist(plist_data, file_path = '')
  bad_xml_doctype = /^.*<!DOCTYPE plist PUBLIC -\/\/Apple Computer.*$/
  begin
    if plist_data =~ bad_xml_doctype
      plist_data.gsub!( bad_xml_doctype, plist_xml_doctype )
      Puppet.debug("Had to fix plist with incorrect DOCTYPE declaration: #{file_path}")
    end
  rescue ArgumentError => e
    Puppet.debug "Failed with #{e.class} on #{file_path}: #{e.inspect}"
    return nil
  end

  begin
    plist_obj = new_cfpropertylist(:data => plist_data)
  # CFPropertyList library will raise NoMethodError for invalid data
  rescue CFFormatError, NoMethodError => e
    Puppet.debug "Failed with #{e.class} on #{file_path}: #{e.inspect}"
    return nil
  end
  convert_cfpropertylist_to_native_types(plist_obj)
end

.plist_xml_doctypeObject

Defines a default doctype string that should be at the top of most plist files. Useful if we need to modify an invalid doctype string in memory. In version 10.9 and lower of OS X the plist at /System/Library/LaunchDaemons/org.ntp.ntpd.plist had an invalid doctype string. This corrects for that.



24
25
26
# File 'lib/puppet/util/plist.rb', line 24

def plist_xml_doctype
  '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'
end

.read_file_with_offset(file_path, offset) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Helper method to assist in reading a file with an offset value. It’s its own method for stubbing purposes



119
120
121
# File 'lib/puppet/util/plist.rb', line 119

def read_file_with_offset(file_path, offset)
  IO.read(file_path, offset)
end

.read_plist_file(file_path) ⇒ Object

Read a plist file, whether its format is XML or in Apple’s “binary1” format, using the CFPropertyList gem.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/puppet/util/plist.rb', line 30

def read_plist_file(file_path)
  # We can't really read the file until we know the source encoding in
  # Ruby 1.9.x, so we use the magic number to detect it.
  # NOTE: We used IO.read originally to be Ruby 1.8.x compatible.
  if read_file_with_offset(file_path, binary_plist_magic_number.length) == binary_plist_magic_number
    plist_obj = new_cfpropertylist(:file => file_path)
    return convert_cfpropertylist_to_native_types(plist_obj)
  else
    plist_data = open_file_with_args(file_path, "r:UTF-8")
    plist = parse_plist(plist_data, file_path)
    return plist if plist

    Puppet.debug "Plist #{file_path} ill-formatted, converting with plutil"
    begin
      plist = Puppet::Util::Execution.execute(['/usr/bin/plutil', '-convert', 'xml1', '-o', '/dev/stdout', file_path],
                                              {:failonfail => true, :combine => true})
      return parse_plist(plist)
    rescue Puppet::ExecutionFailure => detail
      Puppet.warning(_("Cannot read file %{file_path}; Puppet is skipping it.\n") % { file_path: file_path } + _("Details: %{detail}") % { detail: detail })
    end
  end
  return nil
end

.string_to_blob(str) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Helper method to convert a string into a CFProperty::Blob, which is needed to properly handle binary strings



111
112
113
# File 'lib/puppet/util/plist.rb', line 111

def string_to_blob(str)
  CFPropertyList::Blob.new(str)
end

.to_format(format) ⇒ Object



123
124
125
126
127
128
129
130
131
132
133
# File 'lib/puppet/util/plist.rb', line 123

def to_format(format)
  if format.to_sym == :xml
    plist_format = CFPropertyList::List::FORMAT_XML
  elsif format.to_sym == :binary
    plist_format = CFPropertyList::List::FORMAT_BINARY
  elsif format.to_sym == :plain
    plist_format = CFPropertyList::List::FORMAT_PLAIN
  else
    raise FormatError.new "Unknown plist format #{format}"
  end
end

.write_plist_file(plist, file_path, format = :xml) ⇒ Object

This method will write a plist file using a specified format (or XML by default)



137
138
139
140
141
142
143
144
145
# File 'lib/puppet/util/plist.rb', line 137

def write_plist_file(plist, file_path, format = :xml)
  begin
    plist_to_save       = CFPropertyList::List.new
    plist_to_save.value = CFPropertyList.guess(plist)
    plist_to_save.save(file_path, to_format(format), :formatted => true)
  rescue IOError => e
    Puppet.err(_("Unable to write the file %{file_path}. %{error}") % { file_path: file_path, error: e.inspect })
  end
end