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


105
106
107
# File 'lib/puppet/util/plist.rb', line 105

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

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


149
150
151
152
153
# File 'lib/puppet/util/plist.rb', line 149

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


97
98
99
# File 'lib/puppet/util/plist.rb', line 97

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


89
90
91
# File 'lib/puppet/util/plist.rb', line 89

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.


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

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


121
122
123
# File 'lib/puppet/util/plist.rb', line 121

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
53
54
# 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', '-', file_path],
                                              {:failonfail => true, :combine => true})
      return parse_plist(plist)
    rescue Puppet::ExecutionFailure => detail
      message = _("Cannot read file %{file_path}; Puppet is skipping it.") % { file_path: file_path }
      message += '\n' + _("Details: %{detail}") % { detail: detail }
      Puppet.warning(message)
    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


113
114
115
# File 'lib/puppet/util/plist.rb', line 113

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

.to_format(format) ⇒ Object


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

def to_format(format)
  if format.to_sym == :xml
    CFPropertyList::List::FORMAT_XML
  elsif format.to_sym == :binary
    CFPropertyList::List::FORMAT_BINARY
  elsif format.to_sym == :plain
    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)


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

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