facter 1.3.7 → 1.3.8
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of facter might be problematic. Click here for more details.
- data/CHANGELOG +16 -0
- data/Rakefile +3 -3
- data/bin/facter +5 -1
- data/lib/facter.rb +92 -23
- data/lib/facter/ipmess.rb +85 -0
- data/lib/facter/macosx.rb +84 -0
- data/lib/facter/manufacturer.rb +48 -0
- data/lib/facter/util/plist.rb +24 -0
- data/lib/facter/util/plist/generator.rb +226 -0
- data/lib/facter/util/plist/parser.rb +227 -0
- metadata +13 -6
data/CHANGELOG
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
1.3.8:
|
2
|
+
Fixed Rdoc::usage bug on CentOS 5 - closed Puppet #753 and Facter #40
|
3
|
+
|
4
|
+
Added support to return multiple interfaces and their IP addresses and
|
5
|
+
MAC addressess as facts. Returns interface_interfacename and
|
6
|
+
macaddress_interfacename. Existing ipaddress and macaddress facts are
|
7
|
+
unchanged and still returned. Currently Linux only. Closes #6.
|
8
|
+
|
9
|
+
Added macaddress fact support for FreeBSD and OpenBSD - closes #37
|
10
|
+
|
11
|
+
Added hardwareisa support for *BSD platforms - closed #38
|
12
|
+
|
13
|
+
Facter now detects the Mandriva distribution - closes #39
|
14
|
+
|
15
|
+
Facter now correctly detects ipaddress on NetBSD - closes #42
|
16
|
+
|
1
17
|
1.3.7:
|
2
18
|
A couple of small bugfixes, including fixing Facter.flush so it correctly
|
3
19
|
flushes cached values, and the mac address fact only returns one
|
data/Rakefile
CHANGED
@@ -24,8 +24,8 @@ project = Rake::RedLabProject.new("facter") do |p|
|
|
24
24
|
'etc/*'
|
25
25
|
]
|
26
26
|
|
27
|
-
p.epmhosts = %w{culain}
|
28
|
-
p.rpmhost = "fedora1"
|
27
|
+
#p.epmhosts = %w{culain}
|
28
|
+
#p.rpmhost = "fedora1"
|
29
29
|
#p.sunpkghost = "sol10b"
|
30
30
|
end
|
31
31
|
|
@@ -43,4 +43,4 @@ if project.has?(:epm)
|
|
43
43
|
task.rubylibs = FileList.new('lib/**/*')
|
44
44
|
end
|
45
45
|
end
|
46
|
-
# $Id
|
46
|
+
# $Id$
|
data/bin/facter
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
#
|
7
7
|
# = Usage
|
8
8
|
#
|
9
|
-
# facter [-d|--debug] [-h|--help] [-v|--version] [fact] [fact] [...]
|
9
|
+
# facter [-d|--debug] [-h|--help] [-v|--version] [-y|--yaml] [fact] [fact] [...]
|
10
10
|
#
|
11
11
|
# = Description
|
12
12
|
#
|
@@ -27,6 +27,9 @@
|
|
27
27
|
# version::
|
28
28
|
# Print the version and exit.
|
29
29
|
#
|
30
|
+
# yaml::
|
31
|
+
# Emit facts in YAML format.
|
32
|
+
#
|
30
33
|
# = Example
|
31
34
|
#
|
32
35
|
# facter kernel
|
@@ -46,6 +49,7 @@ require 'facter'
|
|
46
49
|
$haveusage = true
|
47
50
|
|
48
51
|
begin
|
52
|
+
require 'rdoc/ri/ri_paths'
|
49
53
|
require 'rdoc/usage'
|
50
54
|
rescue Exception
|
51
55
|
$haveusage = false
|
data/lib/facter.rb
CHANGED
@@ -21,7 +21,7 @@ class Facter
|
|
21
21
|
include Comparable
|
22
22
|
include Enumerable
|
23
23
|
|
24
|
-
FACTERVERSION = '1.3.
|
24
|
+
FACTERVERSION = '1.3.8'
|
25
25
|
# = Facter
|
26
26
|
# Functions as a hash of 'facts' you might care about about your
|
27
27
|
# system, such as mac address, IP address, Video card, etc.
|
@@ -229,7 +229,7 @@ class Facter
|
|
229
229
|
|
230
230
|
@value = nil
|
231
231
|
|
232
|
-
@ldapname = name
|
232
|
+
@ldapname = name.to_s
|
233
233
|
end
|
234
234
|
|
235
235
|
# Add a new resolution mechanism. This requires a block, which will then
|
@@ -473,7 +473,7 @@ class Facter
|
|
473
473
|
# Set the name by which this parameter is known in LDAP. The default
|
474
474
|
# is just the fact name.
|
475
475
|
def setldapname(name)
|
476
|
-
@fact.ldapname = name
|
476
|
+
@fact.ldapname = name.to_s
|
477
477
|
end
|
478
478
|
|
479
479
|
# Is this resolution mechanism suitable on the system in question?
|
@@ -618,16 +618,20 @@ class Facter
|
|
618
618
|
setcode 'uname -r'
|
619
619
|
end
|
620
620
|
|
621
|
-
{ "LSBRelease" =>
|
622
|
-
"LSBDistId" =>
|
623
|
-
"LSBDistRelease" =>
|
624
|
-
"LSBDistDescription" =>
|
625
|
-
"LSBDistCodeName" =>
|
621
|
+
{ "LSBRelease" => %r{^LSB Version:\t(.*)$},
|
622
|
+
"LSBDistId" => %r{^Distributor ID:\t(.*)$},
|
623
|
+
"LSBDistRelease" => %r{^Release:\t(.*)$},
|
624
|
+
"LSBDistDescription" => %r{^Description:\t(.*)$},
|
625
|
+
"LSBDistCodeName" => %r{^Codename:\t(.*)$}
|
626
626
|
}.each do |fact, pattern|
|
627
627
|
Facter.add(fact) do
|
628
628
|
setcode do
|
629
|
-
|
630
|
-
|
629
|
+
unless defined?(@@lsbdata) and defined?(@@lsbtime) and (Time.now.to_i - @@lsbtime.to_i < 5)
|
630
|
+
type = nil
|
631
|
+
@@lsbtime = Time.now
|
632
|
+
@@lsbdata = Resolution.exec('lsb_release -a 2>/dev/null')
|
633
|
+
end
|
634
|
+
if pattern.match(@@lsbdata)
|
631
635
|
$1
|
632
636
|
else
|
633
637
|
nil
|
@@ -636,15 +640,6 @@ class Facter
|
|
636
640
|
end
|
637
641
|
end
|
638
642
|
|
639
|
-
Facter.add(:operatingsystem) do
|
640
|
-
# Default to just returning the kernel as the operating system
|
641
|
-
setcode do Facter[:kernel].value end
|
642
|
-
end
|
643
|
-
|
644
|
-
Facter.add(:operatingsystemrelease) do
|
645
|
-
setcode do Facter[:kernelrelease].value end
|
646
|
-
end
|
647
|
-
|
648
643
|
Facter.add(:operatingsystem) do
|
649
644
|
confine :kernel => :sunos
|
650
645
|
setcode do "Solaris" end
|
@@ -659,6 +654,8 @@ class Facter
|
|
659
654
|
"Gentoo"
|
660
655
|
elsif FileTest.exists?("/etc/fedora-release")
|
661
656
|
"Fedora"
|
657
|
+
elsif FileTest.exists?("/etc/mandriva-release")
|
658
|
+
"Mandriva"
|
662
659
|
elsif FileTest.exists?("/etc/redhat-release")
|
663
660
|
txt = File.read("/etc/redhat-release")
|
664
661
|
if txt =~ /centos/i
|
@@ -672,6 +669,43 @@ class Facter
|
|
672
669
|
end
|
673
670
|
end
|
674
671
|
|
672
|
+
Facter.add(:operatingsystem) do
|
673
|
+
# Default to just returning the kernel as the operating system
|
674
|
+
setcode do Facter[:kernel].value end
|
675
|
+
end
|
676
|
+
|
677
|
+
Facter.add(:operatingsystemrelease) do
|
678
|
+
confine :operatingsystem => :fedora
|
679
|
+
setcode do
|
680
|
+
File::open("/etc/fedora-release", "r") do |f|
|
681
|
+
line = f.readline.chomp
|
682
|
+
if line =~ /\(Rawhide\)$/
|
683
|
+
"Rawhide"
|
684
|
+
elsif line =~ /release (\d+)/
|
685
|
+
$1
|
686
|
+
end
|
687
|
+
end
|
688
|
+
end
|
689
|
+
end
|
690
|
+
|
691
|
+
Facter.add(:operatingsystemrelease) do
|
692
|
+
confine :operatingsystem => :redhat
|
693
|
+
setcode do
|
694
|
+
File::open("/etc/redhat-release", "r") do |f|
|
695
|
+
line = f.readline.chomp
|
696
|
+
if line =~ /\(Rawhide\)$/
|
697
|
+
"Rawhide"
|
698
|
+
elsif line =~ /release (\d+)/
|
699
|
+
$1
|
700
|
+
end
|
701
|
+
end
|
702
|
+
end
|
703
|
+
end
|
704
|
+
|
705
|
+
Facter.add(:operatingsystemrelease) do
|
706
|
+
setcode do Facter[:kernelrelease].value end
|
707
|
+
end
|
708
|
+
|
675
709
|
Facter.add(:hardwaremodel) do
|
676
710
|
setcode 'uname -m'
|
677
711
|
end
|
@@ -865,7 +899,9 @@ class Facter
|
|
865
899
|
filepath = File.join(dir,file)
|
866
900
|
if FileTest.file?(filepath)
|
867
901
|
begin
|
868
|
-
|
902
|
+
File.open(filepath) { |f|
|
903
|
+
value = f.read.chomp.split(/\s+/)[1]
|
904
|
+
}
|
869
905
|
rescue
|
870
906
|
value = nil
|
871
907
|
end
|
@@ -883,7 +919,7 @@ class Facter
|
|
883
919
|
|
884
920
|
Facter.add(:hardwareisa) do
|
885
921
|
setcode 'uname -p', '/bin/sh'
|
886
|
-
confine :operatingsystem => %w{Solaris Linux Fedora RedHat CentOS SuSE Debian Gentoo}
|
922
|
+
confine :operatingsystem => %w{Solaris Linux Fedora RedHat CentOS SuSE Debian Gentoo FreeBSD OpenBSD NetBSD}
|
887
923
|
end
|
888
924
|
|
889
925
|
Facter.add(:macaddress) do
|
@@ -898,6 +934,20 @@ class Facter
|
|
898
934
|
end
|
899
935
|
end
|
900
936
|
|
937
|
+
Facter.add(:macaddress) do
|
938
|
+
confine :operatingsystem => %w{FreeBSD OpenBSD}
|
939
|
+
setcode do
|
940
|
+
ether = []
|
941
|
+
output = %x{/sbin/ifconfig}
|
942
|
+
output.each {|s|
|
943
|
+
if s =~ /(?:ether|lladdr)\s+(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)/
|
944
|
+
ether.push($1)
|
945
|
+
end
|
946
|
+
}
|
947
|
+
ether[0]
|
948
|
+
end
|
949
|
+
end
|
950
|
+
|
901
951
|
Facter.add(:macaddress) do
|
902
952
|
confine :kernel => :darwin
|
903
953
|
setcode do
|
@@ -935,7 +985,7 @@ class Facter
|
|
935
985
|
end
|
936
986
|
end
|
937
987
|
Facter.add(:ipaddress) do
|
938
|
-
confine :kernel => %w{FreeBSD
|
988
|
+
confine :kernel => %w{FreeBSD OpenBSD solaris}
|
939
989
|
setcode do
|
940
990
|
ip = nil
|
941
991
|
output = %x{/sbin/ifconfig}
|
@@ -953,6 +1003,25 @@ class Facter
|
|
953
1003
|
ip
|
954
1004
|
end
|
955
1005
|
end
|
1006
|
+
Facter.add(:ipaddress) do
|
1007
|
+
confine :kernel => %w{NetBSD}
|
1008
|
+
setcode do
|
1009
|
+
ip = nil
|
1010
|
+
output = %x{/sbin/ifconfig -a}
|
1011
|
+
|
1012
|
+
output.split(/^\S/).each { |str|
|
1013
|
+
if str =~ /inet ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/
|
1014
|
+
tmp = $1
|
1015
|
+
unless tmp =~ /127\./
|
1016
|
+
ip = tmp
|
1017
|
+
break
|
1018
|
+
end
|
1019
|
+
end
|
1020
|
+
}
|
1021
|
+
|
1022
|
+
ip
|
1023
|
+
end
|
1024
|
+
end
|
956
1025
|
Facter.add(:ipaddress) do
|
957
1026
|
confine :kernel => %w{darwin}
|
958
1027
|
setcode do
|
@@ -1071,4 +1140,4 @@ class Facter
|
|
1071
1140
|
Facter.loadfacts
|
1072
1141
|
end
|
1073
1142
|
|
1074
|
-
# $Id
|
1143
|
+
# $Id$
|
@@ -0,0 +1,85 @@
|
|
1
|
+
#
|
2
|
+
# ipmess.rb
|
3
|
+
# Try to get additional Facts about the machine's network interfaces on Linux
|
4
|
+
#
|
5
|
+
# Original concept Copyright (C) 2007 psychedelys <psychedelys@gmail.com>
|
6
|
+
# Update and *BSD support (C) 2007 James Turnbull <james@lovedthanlost.net>
|
7
|
+
#
|
8
|
+
# This program is free software; you can redistribute it and/or
|
9
|
+
# modify it under the terms of the GNU General Public License
|
10
|
+
# as published by the Free Software Foundation (version 2 of the License)
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with this program; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston MA 02110-1301 USA
|
18
|
+
#
|
19
|
+
|
20
|
+
if Facter.kernel == "Linux"
|
21
|
+
|
22
|
+
output = %x{/sbin/ifconfig -a}
|
23
|
+
int = nil
|
24
|
+
output.scan(/^(\w+)(\d+)/) { |str|
|
25
|
+
output_int = %x{/sbin/ifconfig #{str}}
|
26
|
+
int = "#{str}"
|
27
|
+
tmp1 = nil
|
28
|
+
tmp2 = nil
|
29
|
+
test = {}
|
30
|
+
output_int.each { |s|
|
31
|
+
int = "#{str}"
|
32
|
+
tmp1 = $1 if s =~ /inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/
|
33
|
+
tmp2 = $1 if s =~ /(?:ether|HWaddr) (\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2}:\w{1,2})/
|
34
|
+
if tmp1 != nil && tmp2 != nil && int != "lo"
|
35
|
+
test["ipaddress_" + int] = tmp1
|
36
|
+
test["macaddress_" + int] = tmp2
|
37
|
+
int = nil
|
38
|
+
tmp1 = nil
|
39
|
+
tmp2 = nil
|
40
|
+
end
|
41
|
+
}
|
42
|
+
test.each{|name,fact|
|
43
|
+
Facter.add(name) do
|
44
|
+
confine :kernel => :linux
|
45
|
+
setcode do
|
46
|
+
fact
|
47
|
+
end
|
48
|
+
end
|
49
|
+
}
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
if Facter.kernel == "FreeBSD" || Facter.kernel == "OpenBSD" || Facter.kernel == "NetBSD"
|
54
|
+
|
55
|
+
output = %x{/sbin/ifconfig -a}
|
56
|
+
int = nil
|
57
|
+
output.scan(/^(\w+)(\d+):/) { |str|
|
58
|
+
output_int = %x{/sbin/ifconfig #{str}}
|
59
|
+
int = "#{str}"
|
60
|
+
tmp1 = nil
|
61
|
+
tmp2 = nil
|
62
|
+
test = {}
|
63
|
+
output_int.each { |s|
|
64
|
+
int = "#{str}"
|
65
|
+
tmp1 = $1 if s =~ /inet ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/
|
66
|
+
tmp2 = $1 if s =~ /(?:ether|lladdr)\s+(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)/
|
67
|
+
if tmp1 != nil && tmp2 != nil && int != "lo"
|
68
|
+
test["ipaddress_" + int] = tmp1
|
69
|
+
test["macaddress_" + int] = tmp2
|
70
|
+
int = nil
|
71
|
+
tmp1 = nil
|
72
|
+
tmp2 = nil
|
73
|
+
end
|
74
|
+
}
|
75
|
+
test.each{|name,fact|
|
76
|
+
Facter.add(name) do
|
77
|
+
confine :kernel => :linux
|
78
|
+
setcode do
|
79
|
+
fact
|
80
|
+
end
|
81
|
+
end
|
82
|
+
}
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
@@ -0,0 +1,84 @@
|
|
1
|
+
#
|
2
|
+
# macosx.rb
|
3
|
+
# Additional Facts coming from Mac OS X system_profiler command
|
4
|
+
#
|
5
|
+
# Copyright (C) 2007 Jeff McCune
|
6
|
+
# Author: Jeff McCune <jeff.mccune@northstarlabs.net>
|
7
|
+
#
|
8
|
+
# This program is free software; you can redistribute it and/or
|
9
|
+
# modify it under the terms of the GNU General Public License
|
10
|
+
# as published by the Free Software Foundation (version 2 of the License)
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with this program; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston MA 02110-1301 USA
|
18
|
+
|
19
|
+
# Jeff McCune
|
20
|
+
# There's a lot more information coming out of system_profiler -xml
|
21
|
+
# We could add quite a bit more, but I didn't want to overload facter
|
22
|
+
# at this point in time.
|
23
|
+
# In particular, Installed Software might be an interesting addition.
|
24
|
+
|
25
|
+
module Facter::Macosx
|
26
|
+
require 'thread'
|
27
|
+
require 'facter/util/plist'
|
28
|
+
|
29
|
+
# JJM I'd really like to dynamically generate these methods
|
30
|
+
# by looking at the _name key of the _items dict for each _dataType
|
31
|
+
|
32
|
+
def self.hardware_overview
|
33
|
+
# JJM Perhaps we should cache the XML data in a "class" level object.
|
34
|
+
top_level_plist = Plist::parse_xml %x{/usr/sbin/system_profiler -xml SPHardwareDataType}
|
35
|
+
system_hardware = top_level_plist[0]['_items'][0]
|
36
|
+
system_hardware.delete '_name'
|
37
|
+
system_hardware
|
38
|
+
end
|
39
|
+
|
40
|
+
# SPSoftwareDataType
|
41
|
+
def self.os_overview
|
42
|
+
top_level_plist = Plist::parse_xml %x{/usr/sbin/system_profiler -xml SPSoftwareDataType}
|
43
|
+
os_stuff = top_level_plist[0]['_items'][0]
|
44
|
+
os_stuff.delete '_name'
|
45
|
+
os_stuff
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.sw_vers
|
49
|
+
ver = Hash.new
|
50
|
+
[ "productName", "productVersion", "buildVersion" ].each do |option|
|
51
|
+
ver["macosx_#{option}"] = %x{sw_vers -#{option}}.strip
|
52
|
+
end
|
53
|
+
ver
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
if Facter.kernel == "Darwin"
|
58
|
+
Facter::Macosx.hardware_overview.each do |fact, value|
|
59
|
+
Facter.add("sp_#{fact}") do
|
60
|
+
confine :kernel => :darwin
|
61
|
+
setcode do
|
62
|
+
value
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
Facter::Macosx.os_overview.each do |fact, value|
|
68
|
+
Facter.add("sp_#{fact}") do
|
69
|
+
confine :kernel => :darwin
|
70
|
+
setcode do
|
71
|
+
value
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
Facter::Macosx.sw_vers.each do |fact, value|
|
77
|
+
Facter.add(fact) do
|
78
|
+
confine :kernel => :darwin
|
79
|
+
setcode do
|
80
|
+
value
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# Info about the manufacturer
|
2
|
+
#
|
3
|
+
|
4
|
+
module Facter::Manufacturer
|
5
|
+
def self.dmi_find_system_info(name)
|
6
|
+
return nil unless FileTest.exists?("/usr/sbin/dmidecode")
|
7
|
+
|
8
|
+
# Do not run the command more than every five seconds.
|
9
|
+
unless defined?(@data) and defined?(@time) and (Time.now.to_i - @time.to_i < 5)
|
10
|
+
@data = {}
|
11
|
+
type = nil
|
12
|
+
@time = Time.now
|
13
|
+
# It's *much* easier to just parse the whole darn file than
|
14
|
+
# to just match a chunk of it.
|
15
|
+
%x{/usr/sbin/dmidecode 2>/dev/null}.split("\n").each do |line|
|
16
|
+
case line
|
17
|
+
when /^(\S.+)$/
|
18
|
+
type = $1.chomp
|
19
|
+
@data[type] ||= {}
|
20
|
+
when /^\s+(\S.+): (\S.*)$/
|
21
|
+
unless type
|
22
|
+
next
|
23
|
+
end
|
24
|
+
@data[type][$1] = $2
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
if data = @data["System Information"]
|
30
|
+
data[name]
|
31
|
+
else
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Add the facts to Facter
|
38
|
+
|
39
|
+
{:SerialNumber => "Serial Number",
|
40
|
+
:Manufacturer => "Manufacturer",
|
41
|
+
:ProductName=> "Product Name"}.each do |fact, name|
|
42
|
+
Facter.add(fact) do
|
43
|
+
confine :kernel => :linux
|
44
|
+
setcode do
|
45
|
+
Facter::Manufacturer.dmi_find_system_info(name)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#--
|
2
|
+
##############################################################
|
3
|
+
# Copyright 2006, Ben Bleything <ben@bleything.net> and #
|
4
|
+
# Patrick May <patrick@hexane.org> #
|
5
|
+
# #
|
6
|
+
# Distributed under the MIT license. #
|
7
|
+
##############################################################
|
8
|
+
#++
|
9
|
+
# = Plist
|
10
|
+
#
|
11
|
+
# This is the main file for plist. Everything interesting happens in Plist and Plist::Emit.
|
12
|
+
|
13
|
+
require 'base64'
|
14
|
+
require 'cgi'
|
15
|
+
require 'stringio'
|
16
|
+
|
17
|
+
require 'facter/util/plist/generator'
|
18
|
+
require 'facter/util/plist/parser'
|
19
|
+
|
20
|
+
module Plist
|
21
|
+
VERSION = '3.0.0'
|
22
|
+
end
|
23
|
+
|
24
|
+
# $Id: plist.rb 1781 2006-10-16 01:01:35Z luke $
|
@@ -0,0 +1,226 @@
|
|
1
|
+
#--###########################################################
|
2
|
+
# Copyright 2006, Ben Bleything <ben@bleything.net> and #
|
3
|
+
# Patrick May <patrick@hexane.org> #
|
4
|
+
# #
|
5
|
+
# Distributed under the MIT license. #
|
6
|
+
##############################################################
|
7
|
+
#++
|
8
|
+
# See Plist::Emit.
|
9
|
+
module Plist
|
10
|
+
# === Create a plist
|
11
|
+
# You can dump an object to a plist in one of two ways:
|
12
|
+
#
|
13
|
+
# * <tt>Plist::Emit.dump(obj)</tt>
|
14
|
+
# * <tt>obj.to_plist</tt>
|
15
|
+
# * This requires that you mixin the <tt>Plist::Emit</tt> module, which is already done for +Array+ and +Hash+.
|
16
|
+
#
|
17
|
+
# The following Ruby classes are converted into native plist types:
|
18
|
+
# Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time, true, false
|
19
|
+
# * +Array+ and +Hash+ are both recursive; their elements will be converted into plist nodes inside the <array> and <dict> containers (respectively).
|
20
|
+
# * +IO+ (and its descendants) and +StringIO+ objects are read from and their contents placed in a <data> element.
|
21
|
+
# * User classes may implement +to_plist_node+ to dictate how they should be serialized; otherwise the object will be passed to <tt>Marshal.dump</tt> and the result placed in a <data> element.
|
22
|
+
#
|
23
|
+
# For detailed usage instructions, refer to USAGE[link:files/docs/USAGE.html] and the methods documented below.
|
24
|
+
module Emit
|
25
|
+
# Helper method for injecting into classes. Calls <tt>Plist::Emit.dump</tt> with +self+.
|
26
|
+
def to_plist(envelope = true)
|
27
|
+
return Plist::Emit.dump(self, envelope)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Helper method for injecting into classes. Calls <tt>Plist::Emit.save_plist</tt> with +self+.
|
31
|
+
def save_plist(filename)
|
32
|
+
Plist::Emit.save_plist(self, filename)
|
33
|
+
end
|
34
|
+
|
35
|
+
# The following Ruby classes are converted into native plist types:
|
36
|
+
# Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time
|
37
|
+
#
|
38
|
+
# Write us (via RubyForge) if you think another class can be coerced safely into one of the expected plist classes.
|
39
|
+
#
|
40
|
+
# +IO+ and +StringIO+ objects are encoded and placed in <data> elements; other objects are <tt>Marshal.dump</tt>'ed unless they implement +to_plist_node+.
|
41
|
+
#
|
42
|
+
# The +envelope+ parameters dictates whether or not the resultant plist fragment is wrapped in the normal XML/plist header and footer. Set it to false if you only want the fragment.
|
43
|
+
def self.dump(obj, envelope = true)
|
44
|
+
output = plist_node(obj)
|
45
|
+
|
46
|
+
output = wrap(output) if envelope
|
47
|
+
|
48
|
+
return output
|
49
|
+
end
|
50
|
+
|
51
|
+
# Writes the serialized object's plist to the specified filename.
|
52
|
+
def self.save_plist(obj, filename)
|
53
|
+
File.open(filename, 'wb') do |f|
|
54
|
+
f.write(obj.to_plist)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def self.plist_node(element)
|
60
|
+
output = ''
|
61
|
+
|
62
|
+
if element.respond_to? :to_plist_node
|
63
|
+
output << element.to_plist_node
|
64
|
+
else
|
65
|
+
case element
|
66
|
+
when Array
|
67
|
+
if element.empty?
|
68
|
+
output << "<array/>\n"
|
69
|
+
else
|
70
|
+
output << tag('array') {
|
71
|
+
element.collect {|e| plist_node(e)}
|
72
|
+
}
|
73
|
+
end
|
74
|
+
when Hash
|
75
|
+
if element.empty?
|
76
|
+
output << "<dict/>\n"
|
77
|
+
else
|
78
|
+
inner_tags = []
|
79
|
+
|
80
|
+
element.keys.sort.each do |k|
|
81
|
+
v = element[k]
|
82
|
+
inner_tags << tag('key', CGI::escapeHTML(k.to_s))
|
83
|
+
inner_tags << plist_node(v)
|
84
|
+
end
|
85
|
+
|
86
|
+
output << tag('dict') {
|
87
|
+
inner_tags
|
88
|
+
}
|
89
|
+
end
|
90
|
+
when true, false
|
91
|
+
output << "<#{element}/>\n"
|
92
|
+
when Time
|
93
|
+
output << tag('date', element.utc.strftime('%Y-%m-%dT%H:%M:%SZ'))
|
94
|
+
when Date # also catches DateTime
|
95
|
+
output << tag('date', element.strftime('%Y-%m-%dT%H:%M:%SZ'))
|
96
|
+
when String, Symbol, Fixnum, Bignum, Integer, Float
|
97
|
+
output << tag(element_type(element), CGI::escapeHTML(element.to_s))
|
98
|
+
when IO, StringIO
|
99
|
+
element.rewind
|
100
|
+
contents = element.read
|
101
|
+
# note that apple plists are wrapped at a different length then
|
102
|
+
# what ruby's base64 wraps by default.
|
103
|
+
# I used #encode64 instead of #b64encode (which allows a length arg)
|
104
|
+
# because b64encode is b0rked and ignores the length arg.
|
105
|
+
data = "\n"
|
106
|
+
Base64::encode64(contents).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" }
|
107
|
+
output << tag('data', data)
|
108
|
+
else
|
109
|
+
output << comment( 'The <data> element below contains a Ruby object which has been serialized with Marshal.dump.' )
|
110
|
+
data = "\n"
|
111
|
+
Base64::encode64(Marshal.dump(element)).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" }
|
112
|
+
output << tag('data', data )
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
return output
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.comment(content)
|
120
|
+
return "<!-- #{content} -->\n"
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.tag(type, contents = '', &block)
|
124
|
+
out = nil
|
125
|
+
|
126
|
+
if block_given?
|
127
|
+
out = IndentedString.new
|
128
|
+
out << "<#{type}>"
|
129
|
+
out.raise_indent
|
130
|
+
|
131
|
+
out << block.call
|
132
|
+
|
133
|
+
out.lower_indent
|
134
|
+
out << "</#{type}>"
|
135
|
+
else
|
136
|
+
out = "<#{type}>#{contents.to_s}</#{type}>\n"
|
137
|
+
end
|
138
|
+
|
139
|
+
return out.to_s
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.wrap(contents)
|
143
|
+
output = ''
|
144
|
+
|
145
|
+
output << '<?xml version="1.0" encoding="UTF-8"?>' + "\n"
|
146
|
+
output << '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' + "\n"
|
147
|
+
output << '<plist version="1.0">' + "\n"
|
148
|
+
|
149
|
+
output << contents
|
150
|
+
|
151
|
+
output << '</plist>' + "\n"
|
152
|
+
|
153
|
+
return output
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.element_type(item)
|
157
|
+
return case item
|
158
|
+
when String, Symbol: 'string'
|
159
|
+
when Fixnum, Bignum, Integer: 'integer'
|
160
|
+
when Float: 'real'
|
161
|
+
else
|
162
|
+
raise "Don't know about this data type... something must be wrong!"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
private
|
166
|
+
class IndentedString #:nodoc:
|
167
|
+
attr_accessor :indent_string
|
168
|
+
|
169
|
+
@@indent_level = 0
|
170
|
+
|
171
|
+
def initialize(str = "\t")
|
172
|
+
@indent_string = str
|
173
|
+
@contents = ''
|
174
|
+
end
|
175
|
+
|
176
|
+
def to_s
|
177
|
+
return @contents
|
178
|
+
end
|
179
|
+
|
180
|
+
def raise_indent
|
181
|
+
@@indent_level += 1
|
182
|
+
end
|
183
|
+
|
184
|
+
def lower_indent
|
185
|
+
@@indent_level -= 1 if @@indent_level > 0
|
186
|
+
end
|
187
|
+
|
188
|
+
def <<(val)
|
189
|
+
if val.is_a? Array
|
190
|
+
val.each do |f|
|
191
|
+
self << f
|
192
|
+
end
|
193
|
+
else
|
194
|
+
# if it's already indented, don't bother indenting further
|
195
|
+
unless val =~ /\A#{@indent_string}/
|
196
|
+
indent = @indent_string * @@indent_level
|
197
|
+
|
198
|
+
@contents << val.gsub(/^/, indent)
|
199
|
+
else
|
200
|
+
@contents << val
|
201
|
+
end
|
202
|
+
|
203
|
+
# it already has a newline, don't add another
|
204
|
+
@contents << "\n" unless val =~ /\n$/
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# we need to add this so sorting hash keys works properly
|
212
|
+
class Symbol #:nodoc:
|
213
|
+
def <=> (other)
|
214
|
+
self.to_s <=> other.to_s
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
class Array #:nodoc:
|
219
|
+
include Plist::Emit
|
220
|
+
end
|
221
|
+
|
222
|
+
class Hash #:nodoc:
|
223
|
+
include Plist::Emit
|
224
|
+
end
|
225
|
+
|
226
|
+
# $Id: generator.rb 1781 2006-10-16 01:01:35Z luke $
|
@@ -0,0 +1,227 @@
|
|
1
|
+
#--###########################################################
|
2
|
+
# Copyright 2006, Ben Bleything <ben@bleything.net> and #
|
3
|
+
# Patrick May <patrick@hexane.org> #
|
4
|
+
# #
|
5
|
+
# Distributed under the MIT license. #
|
6
|
+
##############################################################
|
7
|
+
#++
|
8
|
+
# Plist parses Mac OS X xml property list files into ruby data structures.
|
9
|
+
#
|
10
|
+
# === Load a plist file
|
11
|
+
# This is the main point of the library:
|
12
|
+
#
|
13
|
+
# r = Plist::parse_xml( filename_or_xml )
|
14
|
+
module Plist
|
15
|
+
# Note that I don't use these two elements much:
|
16
|
+
#
|
17
|
+
# + Date elements are returned as DateTime objects.
|
18
|
+
# + Data elements are implemented as Tempfiles
|
19
|
+
#
|
20
|
+
# Plist::parse_xml will blow up if it encounters a data element.
|
21
|
+
# If you encounter such an error, or if you have a Date element which
|
22
|
+
# can't be parsed into a Time object, please send your plist file to
|
23
|
+
# plist@hexane.org so that I can implement the proper support.
|
24
|
+
def Plist::parse_xml( filename_or_xml )
|
25
|
+
listener = Listener.new
|
26
|
+
#parser = REXML::Parsers::StreamParser.new(File.new(filename), listener)
|
27
|
+
parser = StreamParser.new(filename_or_xml, listener)
|
28
|
+
parser.parse
|
29
|
+
listener.result
|
30
|
+
end
|
31
|
+
|
32
|
+
class Listener
|
33
|
+
#include REXML::StreamListener
|
34
|
+
|
35
|
+
attr_accessor :result, :open
|
36
|
+
|
37
|
+
def initialize
|
38
|
+
@result = nil
|
39
|
+
@open = Array.new
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def tag_start(name, attributes)
|
44
|
+
@open.push PTag::mappings[name].new
|
45
|
+
end
|
46
|
+
|
47
|
+
def text( contents )
|
48
|
+
@open.last.text = contents if @open.last
|
49
|
+
end
|
50
|
+
|
51
|
+
def tag_end(name)
|
52
|
+
last = @open.pop
|
53
|
+
if @open.empty?
|
54
|
+
@result = last.to_ruby
|
55
|
+
else
|
56
|
+
@open.last.children.push last
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class StreamParser
|
62
|
+
def initialize( filename_or_xml, listener )
|
63
|
+
@filename_or_xml = filename_or_xml
|
64
|
+
@listener = listener
|
65
|
+
end
|
66
|
+
|
67
|
+
TEXT = /([^<]+)/
|
68
|
+
XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>*/um
|
69
|
+
DOCTYPE_PATTERN = /\s*<!DOCTYPE\s+(.*?)(\[|>)/um
|
70
|
+
COMMENT_START = /\A<!--/u
|
71
|
+
COMMENT_END = /.*?-->/um
|
72
|
+
|
73
|
+
|
74
|
+
def parse
|
75
|
+
plist_tags = PTag::mappings.keys.join('|')
|
76
|
+
start_tag = /<(#{plist_tags})([^>]*)>/i
|
77
|
+
end_tag = /<\/(#{plist_tags})[^>]*>/i
|
78
|
+
|
79
|
+
require 'strscan'
|
80
|
+
|
81
|
+
contents = (
|
82
|
+
if (File.exists? @filename_or_xml)
|
83
|
+
File.open(@filename_or_xml) {|f| f.read}
|
84
|
+
else
|
85
|
+
@filename_or_xml
|
86
|
+
end
|
87
|
+
)
|
88
|
+
|
89
|
+
@scanner = StringScanner.new( contents )
|
90
|
+
until @scanner.eos?
|
91
|
+
if @scanner.scan(COMMENT_START)
|
92
|
+
@scanner.scan(COMMENT_END)
|
93
|
+
elsif @scanner.scan(XMLDECL_PATTERN)
|
94
|
+
elsif @scanner.scan(DOCTYPE_PATTERN)
|
95
|
+
elsif @scanner.scan(start_tag)
|
96
|
+
@listener.tag_start(@scanner[1], nil)
|
97
|
+
if (@scanner[2] =~ /\/$/)
|
98
|
+
@listener.tag_end(@scanner[1])
|
99
|
+
end
|
100
|
+
elsif @scanner.scan(TEXT)
|
101
|
+
@listener.text(@scanner[1])
|
102
|
+
elsif @scanner.scan(end_tag)
|
103
|
+
@listener.tag_end(@scanner[1])
|
104
|
+
else
|
105
|
+
raise "Unimplemented element"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class PTag
|
112
|
+
@@mappings = { }
|
113
|
+
def PTag::mappings
|
114
|
+
@@mappings
|
115
|
+
end
|
116
|
+
|
117
|
+
def PTag::inherited( sub_class )
|
118
|
+
key = sub_class.to_s.downcase
|
119
|
+
key.gsub!(/^plist::/, '' )
|
120
|
+
key.gsub!(/^p/, '') unless key == "plist"
|
121
|
+
|
122
|
+
@@mappings[key] = sub_class
|
123
|
+
end
|
124
|
+
|
125
|
+
attr_accessor :text, :children
|
126
|
+
def initialize
|
127
|
+
@children = Array.new
|
128
|
+
end
|
129
|
+
|
130
|
+
def to_ruby
|
131
|
+
raise "Unimplemented: " + self.class.to_s + "#to_ruby on #{self.inspect}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class PList < PTag
|
136
|
+
def to_ruby
|
137
|
+
children.first.to_ruby if children.first
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class PDict < PTag
|
142
|
+
def to_ruby
|
143
|
+
dict = Hash.new
|
144
|
+
key = nil
|
145
|
+
|
146
|
+
children.each do |c|
|
147
|
+
if key.nil?
|
148
|
+
key = c.to_ruby
|
149
|
+
else
|
150
|
+
dict[key] = c.to_ruby
|
151
|
+
key = nil
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
dict
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
class PKey < PTag
|
160
|
+
def to_ruby
|
161
|
+
CGI::unescapeHTML(text || '')
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
class PString < PTag
|
166
|
+
def to_ruby
|
167
|
+
CGI::unescapeHTML(text || '')
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
class PArray < PTag
|
172
|
+
def to_ruby
|
173
|
+
children.collect do |c|
|
174
|
+
c.to_ruby
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
class PInteger < PTag
|
180
|
+
def to_ruby
|
181
|
+
text.to_i
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
class PTrue < PTag
|
186
|
+
def to_ruby
|
187
|
+
true
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
class PFalse < PTag
|
192
|
+
def to_ruby
|
193
|
+
false
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
class PReal < PTag
|
198
|
+
def to_ruby
|
199
|
+
text.to_f
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
require 'date'
|
204
|
+
class PDate < PTag
|
205
|
+
def to_ruby
|
206
|
+
DateTime.parse(text)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
require 'base64'
|
211
|
+
class PData < PTag
|
212
|
+
def to_ruby
|
213
|
+
data = Base64.decode64(text.gsub(/\s+/, ''))
|
214
|
+
|
215
|
+
begin
|
216
|
+
return Marshal.load(data)
|
217
|
+
rescue Exception => e
|
218
|
+
io = StringIO.new
|
219
|
+
io.write data
|
220
|
+
io.rewind
|
221
|
+
return io
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# $Id: parser.rb 1781 2006-10-16 01:01:35Z luke $
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.
|
2
|
+
rubygems_version: 0.9.4
|
3
3
|
specification_version: 1
|
4
4
|
name: facter
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.3.
|
7
|
-
date: 2007-
|
6
|
+
version: 1.3.8
|
7
|
+
date: 2007-09-24 00:00:00 +02:00
|
8
8
|
summary: Facter collects Operating system facts.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -25,21 +25,28 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement
|
|
25
25
|
platform: ruby
|
26
26
|
signing_key:
|
27
27
|
cert_chain:
|
28
|
+
post_install_message:
|
28
29
|
authors:
|
29
30
|
-
|
30
31
|
files:
|
31
32
|
- install.rb
|
33
|
+
- COPYING
|
32
34
|
- TODO
|
33
|
-
-
|
35
|
+
- INSTALL
|
34
36
|
- Rakefile
|
35
37
|
- README
|
38
|
+
- LICENSE
|
36
39
|
- CHANGELOG
|
37
|
-
- INSTALL
|
38
|
-
- COPYING
|
39
40
|
- bin/facter
|
40
41
|
- lib/facter.rb
|
41
42
|
- lib/facter/processor.rb
|
42
43
|
- lib/facter/memory.rb
|
44
|
+
- lib/facter/util/plist.rb
|
45
|
+
- lib/facter/util/plist/parser.rb
|
46
|
+
- lib/facter/util/plist/generator.rb
|
47
|
+
- lib/facter/macosx.rb
|
48
|
+
- lib/facter/manufacturer.rb
|
49
|
+
- lib/facter/ipmess.rb
|
43
50
|
- etc/facter.conf
|
44
51
|
test_files: []
|
45
52
|
|