facter 1.7.6 → 2.0.1.rc1

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.

Files changed (155) hide show
  1. checksums.yaml +7 -0
  2. data/COMMITTERS.md +194 -0
  3. data/CONTRIBUTING.md +63 -235
  4. data/Gemfile +12 -8
  5. data/README.md +1 -2
  6. data/Rakefile +1 -1
  7. data/bin/facter +0 -4
  8. data/ext/build_defaults.yaml +2 -2
  9. data/ext/project_data.yaml +18 -0
  10. data/install.rb +1 -16
  11. data/lib/facter.rb +171 -171
  12. data/lib/facter/application.rb +65 -54
  13. data/lib/facter/core/aggregate.rb +220 -0
  14. data/lib/facter/core/directed_graph.rb +46 -0
  15. data/lib/facter/core/execution.rb +100 -0
  16. data/lib/facter/core/execution/base.rb +73 -0
  17. data/lib/facter/core/execution/posix.rb +50 -0
  18. data/lib/facter/core/execution/windows.rb +57 -0
  19. data/lib/facter/core/logging.rb +169 -0
  20. data/lib/facter/core/resolvable.rb +94 -0
  21. data/lib/facter/core/suitable.rb +117 -0
  22. data/lib/facter/domain.rb +15 -9
  23. data/lib/facter/filesystems.rb +1 -1
  24. data/lib/facter/hardwaremodel.rb +1 -1
  25. data/lib/facter/hostname.rb +3 -3
  26. data/lib/facter/interfaces.rb +6 -1
  27. data/lib/facter/ipaddress.rb +2 -2
  28. data/lib/facter/kernel.rb +1 -1
  29. data/lib/facter/kernelrelease.rb +1 -1
  30. data/lib/facter/ldom.rb +1 -1
  31. data/lib/facter/lsbdistcodename.rb +1 -1
  32. data/lib/facter/lsbdistdescription.rb +1 -1
  33. data/lib/facter/lsbdistid.rb +1 -1
  34. data/lib/facter/lsbdistrelease.rb +1 -1
  35. data/lib/facter/lsbrelease.rb +1 -1
  36. data/lib/facter/macaddress.rb +1 -14
  37. data/lib/facter/macosx.rb +2 -2
  38. data/lib/facter/memory.rb +8 -19
  39. data/lib/facter/operatingsystem.rb +1 -1
  40. data/lib/facter/operatingsystemrelease.rb +34 -1
  41. data/lib/facter/physicalprocessorcount.rb +6 -6
  42. data/lib/facter/processor.rb +11 -10
  43. data/lib/facter/selinux.rb +4 -15
  44. data/lib/facter/ssh.rb +5 -2
  45. data/lib/facter/util/architecture.rb +2 -2
  46. data/lib/facter/util/collection.rb +42 -38
  47. data/lib/facter/util/config.rb +19 -9
  48. data/lib/facter/util/confine.rb +34 -4
  49. data/lib/facter/util/ec2.rb +1 -1
  50. data/lib/facter/util/fact.rb +108 -36
  51. data/lib/facter/util/file_read.rb +7 -6
  52. data/lib/facter/util/formatter.rb +38 -0
  53. data/lib/facter/util/ip.rb +3 -3
  54. data/lib/facter/util/loader.rb +62 -42
  55. data/lib/facter/util/macosx.rb +7 -8
  56. data/lib/facter/util/manufacturer.rb +3 -3
  57. data/lib/facter/util/memory.rb +13 -13
  58. data/lib/facter/util/monkey_patches.rb +0 -31
  59. data/lib/facter/util/netmask.rb +3 -3
  60. data/lib/facter/util/normalization.rb +94 -0
  61. data/lib/facter/util/nothing_loader.rb +3 -6
  62. data/lib/facter/util/parser.rb +3 -5
  63. data/lib/facter/util/plist/generator.rb +1 -1
  64. data/lib/facter/util/processor.rb +15 -15
  65. data/lib/facter/util/resolution.rb +112 -289
  66. data/lib/facter/util/solaris_zones.rb +4 -4
  67. data/lib/facter/util/uptime.rb +8 -3
  68. data/lib/facter/util/values.rb +67 -1
  69. data/lib/facter/util/virtual.rb +10 -10
  70. data/lib/facter/util/xendomains.rb +1 -1
  71. data/lib/facter/version.rb +42 -39
  72. data/lib/facter/virtual.rb +6 -7
  73. data/lib/facter/zfs_version.rb +3 -3
  74. data/lib/facter/zpool_version.rb +3 -3
  75. data/spec/fixtures/unit/netmask/darwin_10_8_5.txt +30 -0
  76. data/spec/unit/application_spec.rb +46 -1
  77. data/spec/unit/core/aggregate_spec.rb +125 -0
  78. data/spec/unit/core/directed_graph_spec.rb +79 -0
  79. data/spec/unit/core/execution/base_spec.rb +119 -0
  80. data/spec/unit/core/execution/posix_spec.rb +86 -0
  81. data/spec/unit/core/execution/windows_spec.rb +106 -0
  82. data/spec/unit/core/execution_spec.rb +37 -0
  83. data/spec/unit/core/logging_spec.rb +104 -0
  84. data/spec/unit/core/resolvable_spec.rb +81 -0
  85. data/spec/unit/core/suitable_spec.rb +96 -0
  86. data/spec/unit/domain_spec.rb +5 -5
  87. data/spec/unit/facter_spec.rb +61 -222
  88. data/spec/unit/filesystems_spec.rb +2 -2
  89. data/spec/unit/hardwareisa_spec.rb +5 -5
  90. data/spec/unit/hardwaremodel_spec.rb +1 -1
  91. data/spec/unit/hostname_spec.rb +4 -4
  92. data/spec/unit/id_spec.rb +3 -3
  93. data/spec/unit/interfaces_spec.rb +10 -0
  94. data/spec/unit/ipaddress6_spec.rb +4 -4
  95. data/spec/unit/ipaddress_spec.rb +1 -1
  96. data/spec/unit/kernel_spec.rb +2 -2
  97. data/spec/unit/kernelmajversion_spec.rb +1 -1
  98. data/spec/unit/kernelrelease_spec.rb +4 -4
  99. data/spec/unit/kernelversion_spec.rb +2 -2
  100. data/spec/unit/ldom_spec.rb +2 -2
  101. data/spec/unit/lsbdistcodename_spec.rb +2 -2
  102. data/spec/unit/lsbdistdescription_spec.rb +2 -2
  103. data/spec/unit/lsbdistid_spec.rb +2 -2
  104. data/spec/unit/lsbdistrelease_spec.rb +2 -2
  105. data/spec/unit/lsbrelease_spec.rb +2 -2
  106. data/spec/unit/manufacturer_spec.rb +1 -1
  107. data/spec/unit/memory_spec.rb +24 -31
  108. data/spec/unit/netmask_spec.rb +9 -0
  109. data/spec/unit/operatingsystem_spec.rb +1 -1
  110. data/spec/unit/operatingsystemrelease_spec.rb +62 -4
  111. data/spec/unit/physicalprocessorcount_spec.rb +10 -10
  112. data/spec/unit/processor_spec.rb +11 -11
  113. data/spec/unit/selinux_spec.rb +2 -8
  114. data/spec/unit/ssh_spec.rb +3 -2
  115. data/spec/unit/uniqueid_spec.rb +3 -3
  116. data/spec/unit/util/collection_spec.rb +37 -35
  117. data/spec/unit/util/config_spec.rb +20 -0
  118. data/spec/unit/util/confine_spec.rb +21 -0
  119. data/spec/unit/util/directory_loader_spec.rb +1 -0
  120. data/spec/unit/util/ec2_spec.rb +6 -6
  121. data/spec/unit/util/fact_spec.rb +92 -90
  122. data/spec/unit/util/ip_spec.rb +2 -2
  123. data/spec/unit/util/loader_spec.rb +127 -186
  124. data/spec/unit/util/macaddress_spec.rb +2 -2
  125. data/spec/unit/util/macosx_spec.rb +8 -8
  126. data/spec/unit/util/manufacturer_spec.rb +3 -3
  127. data/spec/unit/util/normalization_spec.rb +113 -0
  128. data/spec/unit/util/parser_spec.rb +25 -3
  129. data/spec/unit/util/processor_spec.rb +2 -2
  130. data/spec/unit/util/resolution_spec.rb +60 -631
  131. data/spec/unit/util/solaris_zones_spec.rb +5 -5
  132. data/spec/unit/util/uptime_spec.rb +1 -1
  133. data/spec/unit/util/values_spec.rb +131 -0
  134. data/spec/unit/util/virtual_spec.rb +16 -16
  135. data/spec/unit/util/xendomains_spec.rb +2 -2
  136. data/spec/unit/virtual_spec.rb +39 -39
  137. data/spec/unit/zfs_version_spec.rb +11 -11
  138. data/spec/unit/zonename_spec.rb +2 -2
  139. data/spec/unit/zones_spec.rb +1 -1
  140. data/spec/unit/zpool_version_spec.rb +11 -11
  141. metadata +466 -447
  142. data/lib/facter/util/cfpropertylist.rb +0 -6
  143. data/lib/facter/util/cfpropertylist/LICENSE +0 -19
  144. data/lib/facter/util/cfpropertylist/README +0 -44
  145. data/lib/facter/util/cfpropertylist/Rakefile +0 -44
  146. data/lib/facter/util/cfpropertylist/THANKS +0 -7
  147. data/lib/facter/util/cfpropertylist/lib/cfpropertylist.rb +0 -6
  148. data/lib/facter/util/cfpropertylist/lib/rbBinaryCFPropertyList.rb +0 -562
  149. data/lib/facter/util/cfpropertylist/lib/rbCFPlistError.rb +0 -26
  150. data/lib/facter/util/cfpropertylist/lib/rbCFPropertyList.rb +0 -407
  151. data/lib/facter/util/cfpropertylist/lib/rbCFTypes.rb +0 -244
  152. data/lib/facter/util/cfpropertylist/lib/rbLibXMLParser.rb +0 -135
  153. data/lib/facter/util/cfpropertylist/lib/rbNokogiriParser.rb +0 -140
  154. data/lib/facter/util/cfpropertylist/lib/rbREXMLParser.rb +0 -136
  155. data/spec/unit/util/monkey_patches_spec.rb +0 -42
@@ -10,19 +10,40 @@ class Facter::Util::Confine
10
10
 
11
11
  # Add the restriction. Requires the fact name, an operator, and the value
12
12
  # we're comparing to.
13
- def initialize(fact, *values)
14
- raise ArgumentError, "The fact name must be provided" unless fact
15
- raise ArgumentError, "One or more values must be provided" if values.empty?
13
+ #
14
+ # @param fact [Symbol] Name of the fact
15
+ # @param values [Array] One or more values to match against.
16
+ # They can be any type that provides a === method.
17
+ # @param block [Proc] Alternatively a block can be supplied as a check. The fact
18
+ # value will be passed as the argument to the block. If the block returns
19
+ # true then the fact will be enabled, otherwise it will be disabled.
20
+ def initialize(fact = nil, *values, &block)
21
+ raise ArgumentError, "The fact name must be provided" unless fact or block_given?
22
+ if values.empty? and not block_given?
23
+ raise ArgumentError, "One or more values or a block must be provided"
24
+ end
16
25
  @fact = fact
17
26
  @values = values
27
+ @block = block
18
28
  end
19
29
 
20
30
  def to_s
31
+ return @block.to_s if @block
21
32
  return "'%s' '%s'" % [@fact, @values.join(",")]
22
33
  end
23
34
 
24
35
  # Evaluate the fact, returning true or false.
36
+ # if we have a block paramter then we only evaluate that instead
25
37
  def true?
38
+ if @block and not @fact then
39
+ begin
40
+ return !! @block.call
41
+ rescue StandardError => error
42
+ Facter.debug "Confine raised #{error.class} #{error}"
43
+ return false
44
+ end
45
+ end
46
+
26
47
  unless fact = Facter[@fact]
27
48
  Facter.debug "No fact for %s" % @fact
28
49
  return false
@@ -31,6 +52,15 @@ class Facter::Util::Confine
31
52
 
32
53
  return false if value.nil?
33
54
 
34
- return @values.any? { |v| convert(v) === value }
55
+ if @block then
56
+ begin
57
+ return !! @block.call(value)
58
+ rescue StandardError => error
59
+ Facter.debug "Confine raised #{error.class} #{error}"
60
+ return false
61
+ end
62
+ end
63
+
64
+ return @values.any? do |v| convert(v) === value end
35
65
  end
36
66
  end
@@ -52,7 +52,7 @@ module Facter::Util::EC2
52
52
  "arp -an"
53
53
  end
54
54
 
55
- if arp_table = Facter::Util::Resolution.exec(arp_command)
55
+ if arp_table = Facter::Core::Execution.exec(arp_command)
56
56
  return true if arp_table.match(mac_address_re)
57
57
  end
58
58
  return false
@@ -1,24 +1,33 @@
1
1
  require 'facter'
2
2
  require 'facter/util/resolution'
3
-
3
+ require 'facter/core/aggregate'
4
+
5
+ # This class represents a fact. Each fact has a name and multiple
6
+ # {Facter::Util::Resolution resolutions}.
7
+ #
8
+ # Create facts using {Facter.add}
9
+ #
10
+ # @api public
4
11
  class Facter::Util::Fact
5
- TIMEOUT = 5
6
-
7
- attr_accessor :name, :ldapname
8
-
9
- # Create a new fact, with no resolution mechanisms.
12
+ # The name of the fact
13
+ # @return [String]
14
+ attr_accessor :name
15
+
16
+ # @return [String]
17
+ # @deprecated
18
+ attr_accessor :ldapname
19
+
20
+ # Creates a new fact, with no resolution mechanisms. See {Facter.add}
21
+ # for the public API for creating facts.
22
+ # @param name [String] the fact name
23
+ # @param options [Hash] optional parameters
24
+ # @option options [String] :ldapname set the ldapname property on the fact
25
+ #
26
+ # @api private
10
27
  def initialize(name, options = {})
11
28
  @name = name.to_s.downcase.intern
12
29
 
13
- # LAK:NOTE: This is slow for many options, but generally we won't have any and at
14
- # worst we'll have one. If we add more, this should be made more efficient.
15
- options.each do |name, value|
16
- case name
17
- when :ldapname; self.ldapname = value
18
- else
19
- raise ArgumentError, "Invalid fact option '%s'" % name
20
- end
21
- end
30
+ extract_ldapname_option!(options)
22
31
 
23
32
  @ldapname ||= @name.to_s
24
33
 
@@ -28,33 +37,68 @@ class Facter::Util::Fact
28
37
  @value = nil
29
38
  end
30
39
 
31
- # Add a new resolution mechanism. This requires a block, which will then
32
- # be evaluated in the context of the new mechanism.
33
- def add(value = nil, &block)
34
- begin
35
- resolve = Facter::Util::Resolution.new(@name)
40
+ # Adds a new {Facter::Util::Resolution resolution}. This requires a
41
+ # block, which will then be evaluated in the context of the new
42
+ # resolution.
43
+ #
44
+ # @param options [Hash] A hash of options to set on the resolution
45
+ #
46
+ # @return [Facter::Util::Resolution]
47
+ #
48
+ # @api private
49
+ def add(options = {}, &block)
50
+ define_resolution(nil, options, &block)
51
+ end
36
52
 
37
- resolve.instance_eval(&block) if block
38
- @resolves << resolve
53
+ # Define a new named resolution or return an existing resolution with
54
+ # the given name.
55
+ #
56
+ # @param resolution_name [String] The name of the resolve to define or look up
57
+ # @param options [Hash] A hash of options to set on the resolution
58
+ # @return [Facter::Util::Resolution]
59
+ #
60
+ # @api public
61
+ def define_resolution(resolution_name, options = {}, &block)
39
62
 
40
- resolve
41
- rescue => e
42
- Facter.warn "Unable to add resolve for #{@name}: #{e}"
43
- nil
44
- end
63
+ resolution_type = options.delete(:type) || :simple
64
+
65
+ resolve = create_or_return_resolution(resolution_name, resolution_type)
66
+
67
+ resolve.set_options(options) unless options.empty?
68
+ resolve.evaluate(&block) if block
69
+
70
+ resolve
71
+ rescue => e
72
+ Facter.log_exception(e, "Unable to add resolve #{resolution_name.inspect} for fact #{@name}: #{e.message}")
45
73
  end
46
74
 
47
- ##
48
- # Flush any cached values. If the resolver has a callback block defined
49
- # using the on_flush DSL method, then invoke that block by sending a message
50
- # to Resolution#flush.
75
+ # Retrieve an existing resolution by name
76
+ #
77
+ # @param name [String]
78
+ #
79
+ # @return [Facter::Util::Resolution, nil] The resolution if exists, nil if
80
+ # it doesn't exist or name is nil
81
+ def resolution(name)
82
+ return nil if name.nil?
83
+
84
+ @resolves.find { |resolve| resolve.name == name }
85
+ end
86
+
87
+ # Flushes any cached values.
88
+ #
89
+ # @return [void]
90
+ #
91
+ # @api private
51
92
  def flush
52
93
  @resolves.each { |r| r.flush }
53
94
  @value = nil
54
95
  end
55
96
 
56
- # Return the value for a given fact. Searches through all of the mechanisms
57
- # and returns either the first value or nil.
97
+ # Returns the value for this fact. This searches all resolutions by
98
+ # suitability and weight (see {Facter::Util::Resolution}). If no
99
+ # suitable resolution is found, it returns nil.
100
+ #
101
+ # @api public
58
102
  def value
59
103
  return @value if @value
60
104
 
@@ -75,6 +119,14 @@ class Facter::Util::Fact
75
119
  end
76
120
  end
77
121
 
122
+ # @api private
123
+ # @deprecated
124
+ def extract_ldapname_option!(options)
125
+ if options[:ldapname]
126
+ Facter.warnonce("ldapname is deprecated and will be removed in a future version")
127
+ self.ldapname = options.delete(:ldapname)
128
+ end
129
+ end
78
130
 
79
131
  private
80
132
 
@@ -106,7 +158,7 @@ class Facter::Util::Fact
106
158
 
107
159
  def find_first_real_value(resolutions)
108
160
  resolutions.each do |resolve|
109
- value = normalize_value(resolve.value)
161
+ value = resolve.value
110
162
  if not value.nil?
111
163
  return value
112
164
  end
@@ -126,7 +178,27 @@ class Facter::Util::Fact
126
178
  end
127
179
  end
128
180
 
129
- def normalize_value(value)
130
- value == "" ? nil : value
181
+ def create_or_return_resolution(resolution_name, resolution_type)
182
+ resolve = self.resolution(resolution_name)
183
+
184
+ if resolve
185
+ if resolution_type != resolve.resolution_type
186
+ raise ArgumentError, "Cannot return resolution #{resolution_name} with type" +
187
+ " #{resolution_type}; already defined as #{resolve.resolution_type}"
188
+ end
189
+ else
190
+ case resolution_type
191
+ when :simple
192
+ resolve = Facter::Util::Resolution.new(resolution_name, self)
193
+ when :aggregate
194
+ resolve = Facter::Core::Aggregate.new(resolution_name, self)
195
+ else
196
+ raise ArgumentError, "Expected resolution type to be one of (:simple, :aggregate) but was #{resolution_type}"
197
+ end
198
+
199
+ @resolves << resolve
200
+ end
201
+
202
+ resolve
131
203
  end
132
204
  end
@@ -1,26 +1,27 @@
1
1
  module Facter
2
2
  module Util
3
- ##
3
+
4
4
  # {Facter::Util::FileRead} is a utility module intended to provide easily
5
5
  # mockable methods that delegate to simple file read methods. The intent is to
6
6
  # avoid the need to execute the `cat` system command or `File.read` directly in
7
7
  # Ruby, as mocking these behaviors can have wide-ranging effects.
8
8
  #
9
9
  # All Facter facts are encouraged to use this method instead of File.read or
10
- # Facter::Util::Resolution.exec('cat ...')
10
+ # Facter::Core::Execution.exec('cat ...')
11
11
  #
12
12
  # @api public
13
13
  module FileRead
14
- ##
15
14
  # read returns the raw content of a file as a string. If the file does not
16
15
  # exist, or the process does not have permission to read the file then nil is
17
16
  # returned.
18
17
  #
19
18
  # @api public
20
19
  #
21
- # @return [String] the raw contents of the file at {path} or {nil} if the
22
- # file cannot be read because it does not exist or the process does not have
23
- # permission to read the file.
20
+ # @param path [String] the path to be read
21
+ #
22
+ # @return [String, nil] the raw contents of the file or `nil` if the
23
+ # file cannot be read because it does not exist or the process does not have
24
+ # permission to read the file.
24
25
  def self.read(path)
25
26
  File.read(path)
26
27
  rescue Errno::ENOENT, Errno::EACCES => detail
@@ -0,0 +1,38 @@
1
+ require 'yaml'
2
+
3
+ module Facter
4
+ module Util
5
+ module Formatter
6
+
7
+ def self.format_json(hash)
8
+ if Facter.json?
9
+ JSON.pretty_generate(hash)
10
+ else
11
+ raise "Cannot format facts as JSON; 'json' library is not present"
12
+ end
13
+ end
14
+
15
+ def self.format_yaml(hash)
16
+ YAML.dump(hash)
17
+ end
18
+
19
+ def self.format_plaintext(hash)
20
+ output = ''
21
+
22
+ # Print the value of a single fact, otherwise print a list sorted by fact
23
+ # name and separated by "=>"
24
+ if hash.length == 1
25
+ if value = hash.values.first
26
+ output = value
27
+ end
28
+ else
29
+ hash.sort_by { |(name, value)| name }.each do |name,value|
30
+ output << "#{name} => #{value}\n"
31
+ end
32
+ end
33
+
34
+ output
35
+ end
36
+ end
37
+ end
38
+ end
@@ -96,7 +96,7 @@ module Facter::Util::IP
96
96
  #
97
97
  # @return [String] the output of `ifconfig #{arguments} 2>/dev/null` or nil
98
98
  def self.exec_ifconfig(additional_arguments=[])
99
- Facter::Util::Resolution.exec("#{self.get_ifconfig} #{additional_arguments.join(' ')}")
99
+ Facter::Core::Execution.exec("#{self.get_ifconfig} #{additional_arguments.join(' ')}")
100
100
  end
101
101
  ##
102
102
  # get_ifconfig looks up the ifconfig binary
@@ -110,7 +110,7 @@ module Facter::Util::IP
110
110
  # hpux_netstat_in is a delegate method that allows us to stub netstat -in
111
111
  # without stubbing exec.
112
112
  def self.hpux_netstat_in
113
- Facter::Util::Resolution.exec("/bin/netstat -in")
113
+ Facter::Core::Execution.exec("/bin/netstat -in")
114
114
  end
115
115
 
116
116
  def self.get_infiniband_macaddress(interface)
@@ -160,7 +160,7 @@ module Facter::Util::IP
160
160
  end
161
161
 
162
162
  def self.hpux_lanscan
163
- Facter::Util::Resolution.exec("/usr/sbin/lanscan")
163
+ Facter::Core::Execution.exec("/usr/sbin/lanscan")
164
164
  end
165
165
 
166
166
  def self.get_output_for_interface_and_label(interface, label)
@@ -5,45 +5,48 @@ require 'facter/util/directory_loader'
5
5
  # Load facts on demand.
6
6
  class Facter::Util::Loader
7
7
 
8
- def initialize
8
+ def initialize(environment_vars = ENV)
9
9
  @loaded = []
10
- @valid_path = {}
10
+ @environment_vars = environment_vars
11
11
  end
12
12
 
13
13
  # Load all resolutions for a single fact.
14
+ #
15
+ # @api public
16
+ # @param name [Symbol]
14
17
  def load(fact)
15
18
  # Now load from the search path
16
19
  shortname = fact.to_s.downcase
17
20
  load_env(shortname)
18
21
 
19
22
  filename = shortname + ".rb"
20
- search_path.each do |dir|
21
- # Load individual files
22
- file = File.join(dir, filename)
23
23
 
24
- load_file(file) if FileTest.exist?(file)
24
+ paths = search_path
25
+ unless paths.nil?
26
+ paths.each do |dir|
27
+ # Load individual files
28
+ file = File.join(dir, filename)
25
29
 
26
- # And load any directories matching the name
27
- factdir = File.join(dir, shortname)
28
- load_dir(factdir) if FileTest.directory?(factdir)
30
+ load_file(file) if File.file?(file)
31
+ end
29
32
  end
30
33
  end
31
34
 
32
35
  # Load all facts from all directories.
36
+ #
37
+ # @api public
33
38
  def load_all
34
39
  return if defined?(@loaded_all)
35
40
 
36
41
  load_env
37
42
 
38
- search_path.each do |dir|
39
- next unless FileTest.directory?(dir)
40
-
41
- Dir.entries(dir).sort.each do |file|
42
- path = File.join(dir, file)
43
- if File.directory?(path)
44
- load_dir(path)
45
- elsif file =~ /\.rb$/
46
- load_file(File.join(dir, file))
43
+ paths = search_path
44
+ unless paths.nil?
45
+ paths.each do |dir|
46
+ # dir is already an absolute path
47
+ Dir.glob(File.join(dir, '*.rb')).each do |path|
48
+ # exclude dirs that end with .rb
49
+ load_file(path) if File.file?(path)
47
50
  end
48
51
  end
49
52
  end
@@ -51,43 +54,60 @@ class Facter::Util::Loader
51
54
  @loaded_all = true
52
55
  end
53
56
 
54
- # The list of directories we're going to search through for facts.
57
+ # List directories to search for fact files.
58
+ #
59
+ # Search paths are gathered from the following sources:
60
+ #
61
+ # 1. $LOAD_PATH entries are expanded to absolute paths
62
+ # 2. ENV['FACTERLIB'] is split and used verbatim
63
+ # 3. Entries from Facter.search_path are used verbatim
64
+ #
65
+ # A warning will be generated for paths in Facter.search_path that are not
66
+ # absolute directories.
67
+ #
68
+ # @api public
69
+ # @return [Array<String>]
55
70
  def search_path
56
- result = []
57
- result += $LOAD_PATH.collect { |d| File.join(d, "facter") }
58
- if ENV.include?("FACTERLIB")
59
- result += ENV["FACTERLIB"].split(File::PATH_SEPARATOR)
71
+ search_paths = []
72
+ search_paths += $LOAD_PATH.map { |path| File.expand_path('facter', path) }
73
+
74
+ if @environment_vars.include?("FACTERLIB")
75
+ search_paths += @environment_vars["FACTERLIB"].split(File::PATH_SEPARATOR)
60
76
  end
61
77
 
62
- # This allows others to register additional paths we should search.
63
- result += Facter.search_path
78
+ search_paths.delete_if { |path| ! valid_search_path?(path) }
64
79
 
65
- result.select do |dir|
66
- good = valid_search_path? dir
67
- Facter.debugonce("Relative directory #{dir} removed from search path.") unless good
68
- good
80
+ Facter.search_path.each do |path|
81
+ if valid_search_path?(path)
82
+ search_paths << path
83
+ else
84
+ Facter.warn "Excluding #{path} from search path. Fact file paths must be an absolute directory"
85
+ end
69
86
  end
70
- end
71
87
 
72
- def valid_search_path?(path)
73
- return @valid_path[path] unless @valid_path[path].nil?
88
+ search_paths.delete_if { |path| ! File.directory?(path) }
74
89
 
75
- return @valid_path[path] = Pathname.new(path).absolute?
90
+ search_paths.uniq
76
91
  end
77
- private :valid_search_path?
78
92
 
79
93
  private
80
94
 
81
- def load_dir(dir)
82
- return if dir =~ /\/\.+$/ or dir =~ /\/util$/ or dir =~ /\/lib$/
83
-
84
- Dir.entries(dir).find_all { |f| f =~ /\.rb$/ }.sort.each do |file|
85
- load_file(File.join(dir, file))
86
- end
95
+ # Validate that the given path is valid, ie it is an absolute path.
96
+ #
97
+ # @api private
98
+ # @param path [String]
99
+ # @return [Boolean]
100
+ def valid_search_path?(path)
101
+ Pathname.new(path).absolute?
87
102
  end
88
103
 
104
+ # Load a file and record is paths to prevent duplicate loads.
105
+ #
106
+ # @api private
107
+ # @params file [String] The *absolute path* to the file to load
89
108
  def load_file(file)
90
109
  return if @loaded.include? file
110
+
91
111
  # We have to specify Kernel.load, because we have a load method.
92
112
  begin
93
113
  # Store the file path so we don't try to reload it
@@ -97,7 +117,7 @@ class Facter::Util::Loader
97
117
  # Don't store the path if the file can't be loaded
98
118
  # in case it's loadable later on.
99
119
  @loaded.delete(file)
100
- Facter.warn "Error loading fact #{file} #{detail}"
120
+ Facter.log_exception(detail, "Error loading fact #{file}: #{detail.message}")
101
121
  end
102
122
  end
103
123
 
@@ -105,7 +125,7 @@ class Facter::Util::Loader
105
125
  # all will be loaded.
106
126
  def load_env(fact = nil)
107
127
  # Load from the environment, if possible
108
- ENV.each do |name, value|
128
+ @environment_vars.each do |name, value|
109
129
  # Skip anything that doesn't match our regex.
110
130
  next unless name =~ /^facter_?(\w+)$/i
111
131
  env_name = $1