facter 1.7.6 → 2.0.1.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of facter might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/COMMITTERS.md +194 -0
- data/CONTRIBUTING.md +63 -235
- data/Gemfile +12 -8
- data/README.md +1 -2
- data/Rakefile +1 -1
- data/bin/facter +0 -4
- data/ext/build_defaults.yaml +2 -2
- data/ext/project_data.yaml +18 -0
- data/install.rb +1 -16
- data/lib/facter.rb +171 -171
- data/lib/facter/application.rb +65 -54
- data/lib/facter/core/aggregate.rb +220 -0
- data/lib/facter/core/directed_graph.rb +46 -0
- data/lib/facter/core/execution.rb +100 -0
- data/lib/facter/core/execution/base.rb +73 -0
- data/lib/facter/core/execution/posix.rb +50 -0
- data/lib/facter/core/execution/windows.rb +57 -0
- data/lib/facter/core/logging.rb +169 -0
- data/lib/facter/core/resolvable.rb +94 -0
- data/lib/facter/core/suitable.rb +117 -0
- data/lib/facter/domain.rb +15 -9
- data/lib/facter/filesystems.rb +1 -1
- data/lib/facter/hardwaremodel.rb +1 -1
- data/lib/facter/hostname.rb +3 -3
- data/lib/facter/interfaces.rb +6 -1
- data/lib/facter/ipaddress.rb +2 -2
- data/lib/facter/kernel.rb +1 -1
- data/lib/facter/kernelrelease.rb +1 -1
- data/lib/facter/ldom.rb +1 -1
- data/lib/facter/lsbdistcodename.rb +1 -1
- data/lib/facter/lsbdistdescription.rb +1 -1
- data/lib/facter/lsbdistid.rb +1 -1
- data/lib/facter/lsbdistrelease.rb +1 -1
- data/lib/facter/lsbrelease.rb +1 -1
- data/lib/facter/macaddress.rb +1 -14
- data/lib/facter/macosx.rb +2 -2
- data/lib/facter/memory.rb +8 -19
- data/lib/facter/operatingsystem.rb +1 -1
- data/lib/facter/operatingsystemrelease.rb +34 -1
- data/lib/facter/physicalprocessorcount.rb +6 -6
- data/lib/facter/processor.rb +11 -10
- data/lib/facter/selinux.rb +4 -15
- data/lib/facter/ssh.rb +5 -2
- data/lib/facter/util/architecture.rb +2 -2
- data/lib/facter/util/collection.rb +42 -38
- data/lib/facter/util/config.rb +19 -9
- data/lib/facter/util/confine.rb +34 -4
- data/lib/facter/util/ec2.rb +1 -1
- data/lib/facter/util/fact.rb +108 -36
- data/lib/facter/util/file_read.rb +7 -6
- data/lib/facter/util/formatter.rb +38 -0
- data/lib/facter/util/ip.rb +3 -3
- data/lib/facter/util/loader.rb +62 -42
- data/lib/facter/util/macosx.rb +7 -8
- data/lib/facter/util/manufacturer.rb +3 -3
- data/lib/facter/util/memory.rb +13 -13
- data/lib/facter/util/monkey_patches.rb +0 -31
- data/lib/facter/util/netmask.rb +3 -3
- data/lib/facter/util/normalization.rb +94 -0
- data/lib/facter/util/nothing_loader.rb +3 -6
- data/lib/facter/util/parser.rb +3 -5
- data/lib/facter/util/plist/generator.rb +1 -1
- data/lib/facter/util/processor.rb +15 -15
- data/lib/facter/util/resolution.rb +112 -289
- data/lib/facter/util/solaris_zones.rb +4 -4
- data/lib/facter/util/uptime.rb +8 -3
- data/lib/facter/util/values.rb +67 -1
- data/lib/facter/util/virtual.rb +10 -10
- data/lib/facter/util/xendomains.rb +1 -1
- data/lib/facter/version.rb +42 -39
- data/lib/facter/virtual.rb +6 -7
- data/lib/facter/zfs_version.rb +3 -3
- data/lib/facter/zpool_version.rb +3 -3
- data/spec/fixtures/unit/netmask/darwin_10_8_5.txt +30 -0
- data/spec/unit/application_spec.rb +46 -1
- data/spec/unit/core/aggregate_spec.rb +125 -0
- data/spec/unit/core/directed_graph_spec.rb +79 -0
- data/spec/unit/core/execution/base_spec.rb +119 -0
- data/spec/unit/core/execution/posix_spec.rb +86 -0
- data/spec/unit/core/execution/windows_spec.rb +106 -0
- data/spec/unit/core/execution_spec.rb +37 -0
- data/spec/unit/core/logging_spec.rb +104 -0
- data/spec/unit/core/resolvable_spec.rb +81 -0
- data/spec/unit/core/suitable_spec.rb +96 -0
- data/spec/unit/domain_spec.rb +5 -5
- data/spec/unit/facter_spec.rb +61 -222
- data/spec/unit/filesystems_spec.rb +2 -2
- data/spec/unit/hardwareisa_spec.rb +5 -5
- data/spec/unit/hardwaremodel_spec.rb +1 -1
- data/spec/unit/hostname_spec.rb +4 -4
- data/spec/unit/id_spec.rb +3 -3
- data/spec/unit/interfaces_spec.rb +10 -0
- data/spec/unit/ipaddress6_spec.rb +4 -4
- data/spec/unit/ipaddress_spec.rb +1 -1
- data/spec/unit/kernel_spec.rb +2 -2
- data/spec/unit/kernelmajversion_spec.rb +1 -1
- data/spec/unit/kernelrelease_spec.rb +4 -4
- data/spec/unit/kernelversion_spec.rb +2 -2
- data/spec/unit/ldom_spec.rb +2 -2
- data/spec/unit/lsbdistcodename_spec.rb +2 -2
- data/spec/unit/lsbdistdescription_spec.rb +2 -2
- data/spec/unit/lsbdistid_spec.rb +2 -2
- data/spec/unit/lsbdistrelease_spec.rb +2 -2
- data/spec/unit/lsbrelease_spec.rb +2 -2
- data/spec/unit/manufacturer_spec.rb +1 -1
- data/spec/unit/memory_spec.rb +24 -31
- data/spec/unit/netmask_spec.rb +9 -0
- data/spec/unit/operatingsystem_spec.rb +1 -1
- data/spec/unit/operatingsystemrelease_spec.rb +62 -4
- data/spec/unit/physicalprocessorcount_spec.rb +10 -10
- data/spec/unit/processor_spec.rb +11 -11
- data/spec/unit/selinux_spec.rb +2 -8
- data/spec/unit/ssh_spec.rb +3 -2
- data/spec/unit/uniqueid_spec.rb +3 -3
- data/spec/unit/util/collection_spec.rb +37 -35
- data/spec/unit/util/config_spec.rb +20 -0
- data/spec/unit/util/confine_spec.rb +21 -0
- data/spec/unit/util/directory_loader_spec.rb +1 -0
- data/spec/unit/util/ec2_spec.rb +6 -6
- data/spec/unit/util/fact_spec.rb +92 -90
- data/spec/unit/util/ip_spec.rb +2 -2
- data/spec/unit/util/loader_spec.rb +127 -186
- data/spec/unit/util/macaddress_spec.rb +2 -2
- data/spec/unit/util/macosx_spec.rb +8 -8
- data/spec/unit/util/manufacturer_spec.rb +3 -3
- data/spec/unit/util/normalization_spec.rb +113 -0
- data/spec/unit/util/parser_spec.rb +25 -3
- data/spec/unit/util/processor_spec.rb +2 -2
- data/spec/unit/util/resolution_spec.rb +60 -631
- data/spec/unit/util/solaris_zones_spec.rb +5 -5
- data/spec/unit/util/uptime_spec.rb +1 -1
- data/spec/unit/util/values_spec.rb +131 -0
- data/spec/unit/util/virtual_spec.rb +16 -16
- data/spec/unit/util/xendomains_spec.rb +2 -2
- data/spec/unit/virtual_spec.rb +39 -39
- data/spec/unit/zfs_version_spec.rb +11 -11
- data/spec/unit/zonename_spec.rb +2 -2
- data/spec/unit/zones_spec.rb +1 -1
- data/spec/unit/zpool_version_spec.rb +11 -11
- metadata +466 -447
- data/lib/facter/util/cfpropertylist.rb +0 -6
- data/lib/facter/util/cfpropertylist/LICENSE +0 -19
- data/lib/facter/util/cfpropertylist/README +0 -44
- data/lib/facter/util/cfpropertylist/Rakefile +0 -44
- data/lib/facter/util/cfpropertylist/THANKS +0 -7
- data/lib/facter/util/cfpropertylist/lib/cfpropertylist.rb +0 -6
- data/lib/facter/util/cfpropertylist/lib/rbBinaryCFPropertyList.rb +0 -562
- data/lib/facter/util/cfpropertylist/lib/rbCFPlistError.rb +0 -26
- data/lib/facter/util/cfpropertylist/lib/rbCFPropertyList.rb +0 -407
- data/lib/facter/util/cfpropertylist/lib/rbCFTypes.rb +0 -244
- data/lib/facter/util/cfpropertylist/lib/rbLibXMLParser.rb +0 -135
- data/lib/facter/util/cfpropertylist/lib/rbNokogiriParser.rb +0 -140
- data/lib/facter/util/cfpropertylist/lib/rbREXMLParser.rb +0 -136
- data/spec/unit/util/monkey_patches_spec.rb +0 -42
data/lib/facter/application.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'facter'
|
3
|
+
require 'facter/util/formatter'
|
4
|
+
|
1
5
|
module Facter
|
2
6
|
module Application
|
3
7
|
|
@@ -7,7 +11,7 @@ module Facter
|
|
7
11
|
begin
|
8
12
|
Facter::Util::Config.ext_fact_loader = Facter::Util::DirectoryLoader.loader_for(dir)
|
9
13
|
rescue Facter::Util::DirectoryLoader::NoSuchDirectoryError => error
|
10
|
-
|
14
|
+
Facter.log_exception(error, "Specified external facts directory #{dir} does not exist.")
|
11
15
|
exit(1)
|
12
16
|
end
|
13
17
|
end
|
@@ -17,9 +21,6 @@ module Facter
|
|
17
21
|
end
|
18
22
|
|
19
23
|
def self.run(argv)
|
20
|
-
require 'optparse'
|
21
|
-
require 'facter'
|
22
|
-
|
23
24
|
options = parse(argv)
|
24
25
|
|
25
26
|
# Accept fact names to return from the command line
|
@@ -35,8 +36,8 @@ module Facter
|
|
35
36
|
begin
|
36
37
|
facts[name] = Facter.value(name)
|
37
38
|
rescue => error
|
38
|
-
|
39
|
-
exit
|
39
|
+
Facter.log_exception(error, "Could not retrieve #{name}: #{error.message}")
|
40
|
+
exit(10)
|
40
41
|
end
|
41
42
|
end
|
42
43
|
end
|
@@ -44,44 +45,24 @@ module Facter
|
|
44
45
|
# Print everything if they didn't ask for specific facts.
|
45
46
|
facts ||= Facter.to_hash
|
46
47
|
|
47
|
-
|
48
|
-
if options[:yaml]
|
49
|
-
require 'yaml'
|
50
|
-
puts YAML.dump(facts)
|
51
|
-
exit(0)
|
52
|
-
end
|
48
|
+
output = nil
|
53
49
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
rescue LoadError
|
61
|
-
$stderr.puts "You do not have JSON support in your version of Ruby. JSON output disabled"
|
62
|
-
exit(1)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
# Print the value of a single fact, otherwise print a list sorted by fact
|
67
|
-
# name and separated by "=>"
|
68
|
-
if facts.length == 1
|
69
|
-
if value = facts.values.first
|
70
|
-
puts value
|
71
|
-
end
|
50
|
+
if options[:yaml]
|
51
|
+
output = Facter::Util::Formatter.format_yaml(facts)
|
52
|
+
elsif options[:json]
|
53
|
+
output = Facter::Util::Formatter.format_json(facts)
|
54
|
+
elsif options[:plaintext]
|
55
|
+
output = Facter::Util::Formatter.format_plaintext(facts)
|
72
56
|
else
|
73
|
-
|
74
|
-
puts "#{name} => #{value}"
|
75
|
-
end
|
57
|
+
output = Facter::Util::Formatter.format_plaintext(facts)
|
76
58
|
end
|
77
59
|
|
60
|
+
puts output
|
61
|
+
exit(0)
|
62
|
+
|
78
63
|
rescue => e
|
79
|
-
|
80
|
-
|
81
|
-
else
|
82
|
-
$stderr.puts "Error: #{e}"
|
83
|
-
exit(12)
|
84
|
-
end
|
64
|
+
Facter.log_exception(e)
|
65
|
+
exit(12)
|
85
66
|
end
|
86
67
|
|
87
68
|
private
|
@@ -95,18 +76,23 @@ module Facter
|
|
95
76
|
options = {}
|
96
77
|
parser = OptionParser.new do |opts|
|
97
78
|
opts.banner = <<-BANNER
|
98
|
-
|
99
|
-
|
79
|
+
facter(8) -- Gather system information
|
80
|
+
======
|
81
|
+
|
82
|
+
SYNOPSIS
|
83
|
+
--------
|
100
84
|
|
101
85
|
Collect and display facts about the system.
|
102
86
|
|
103
|
-
|
104
|
-
|
87
|
+
USAGE
|
88
|
+
-----
|
105
89
|
|
106
|
-
|
90
|
+
facter [-h|--help] [-t|--timing] [-d|--debug] [-p|--puppet] [-v|--version]
|
91
|
+
[-y|--yaml] [-j|--json] [--plaintext] [--external-dir DIR] [--no-external-dir]
|
92
|
+
[fact] [fact] [...]
|
107
93
|
|
108
|
-
|
109
|
-
|
94
|
+
DESCRIPTION
|
95
|
+
-----------
|
110
96
|
|
111
97
|
Collect and display facts about the current system. The library behind
|
112
98
|
Facter is easy to expand, making Facter an easy way to collect information
|
@@ -115,19 +101,42 @@ about a system from within the shell or within Ruby.
|
|
115
101
|
If no facts are specifically asked for, then all facts will be returned.
|
116
102
|
|
117
103
|
EXAMPLE
|
118
|
-
|
119
|
-
|
104
|
+
-------
|
105
|
+
|
106
|
+
Display all facts:
|
107
|
+
|
108
|
+
$ facter
|
109
|
+
architecture => amd64
|
110
|
+
blockdevices => sda,sr0
|
111
|
+
domain => example.com
|
112
|
+
fqdn => puppet.example.com
|
113
|
+
hardwaremodel => x86_64
|
114
|
+
[...]
|
115
|
+
|
116
|
+
Display a single fact:
|
117
|
+
|
118
|
+
$ facter kernel
|
119
|
+
Linux
|
120
|
+
|
121
|
+
Format facts as JSON:
|
122
|
+
|
123
|
+
$ facter --json architecture kernel hardwaremodel
|
124
|
+
{
|
125
|
+
"architecture": "amd64",
|
126
|
+
"kernel": "Linux",
|
127
|
+
"hardwaremodel": "x86_64"
|
128
|
+
}
|
120
129
|
|
121
130
|
AUTHOR
|
122
|
-
|
131
|
+
------
|
123
132
|
Luke Kanies
|
124
133
|
|
125
134
|
COPYRIGHT
|
126
|
-
|
127
|
-
Copyright (c) 2011-
|
135
|
+
---------
|
136
|
+
Copyright (c) 2011-2014 Puppet Labs, Inc Licensed under the Apache 2.0 license
|
128
137
|
|
129
|
-
|
130
|
-
|
138
|
+
OPTIONS
|
139
|
+
-------
|
131
140
|
BANNER
|
132
141
|
opts.on("-y",
|
133
142
|
"--yaml",
|
@@ -135,8 +144,10 @@ USAGE
|
|
135
144
|
opts.on("-j",
|
136
145
|
"--json",
|
137
146
|
"Emit facts in JSON format.") { |v| options[:json] = v }
|
147
|
+
opts.on("--plaintext",
|
148
|
+
"Emit facts in plaintext format.") { |v| options[:plaintext] = v }
|
138
149
|
opts.on("--trace",
|
139
|
-
"Enable backtraces.") { |v|
|
150
|
+
"Enable backtraces.") { |v| Facter.trace(true) }
|
140
151
|
opts.on("--external-dir DIR",
|
141
152
|
"The directory to use for external facts.") { |v| create_directory_loader(v) }
|
142
153
|
opts.on("--no-external-dir",
|
@@ -0,0 +1,220 @@
|
|
1
|
+
require 'facter'
|
2
|
+
require 'facter/core/directed_graph'
|
3
|
+
require 'facter/core/suitable'
|
4
|
+
require 'facter/core/resolvable'
|
5
|
+
require 'facter/util/values'
|
6
|
+
|
7
|
+
# Aggregates provide a mechanism for facts to be resolved in multiple steps.
|
8
|
+
#
|
9
|
+
# Aggregates are evaluated in two parts: generating individual chunks and then
|
10
|
+
# aggregating all chunks together. Each chunk is a block of code that generates
|
11
|
+
# a value, and may depend on other chunks when it runs. After all chunks have
|
12
|
+
# been evaluated they are passed to the aggregate block as Hash<name, result>.
|
13
|
+
# The aggregate block converts the individual chunks into a single value that is
|
14
|
+
# returned as the final value of the aggregate.
|
15
|
+
#
|
16
|
+
# @api public
|
17
|
+
# @since 2.0.0
|
18
|
+
class Facter::Core::Aggregate
|
19
|
+
|
20
|
+
include Facter::Core::Suitable
|
21
|
+
include Facter::Core::Resolvable
|
22
|
+
|
23
|
+
# @!attribute [r] name
|
24
|
+
# @return [Symbol] The name of the aggregate resolution
|
25
|
+
attr_reader :name
|
26
|
+
|
27
|
+
# @!attribute [r] deps
|
28
|
+
# @api private
|
29
|
+
# @return [Facter::Core::DirectedGraph]
|
30
|
+
attr_reader :deps
|
31
|
+
|
32
|
+
# @!attribute [r] confines
|
33
|
+
# @return [Array<Facter::Core::Confine>] An array of confines restricting
|
34
|
+
# this to a specific platform
|
35
|
+
# @see Facter::Core::Suitable
|
36
|
+
attr_reader :confines
|
37
|
+
|
38
|
+
# @!attribute [r] fact
|
39
|
+
# @return [Facter::Util::Fact]
|
40
|
+
# @api private
|
41
|
+
attr_reader :fact
|
42
|
+
|
43
|
+
def initialize(name, fact)
|
44
|
+
@name = name
|
45
|
+
@fact = fact
|
46
|
+
|
47
|
+
@confines = []
|
48
|
+
@chunks = {}
|
49
|
+
|
50
|
+
@aggregate = nil
|
51
|
+
@deps = Facter::Core::DirectedGraph.new
|
52
|
+
end
|
53
|
+
|
54
|
+
def set_options(options)
|
55
|
+
if options[:name]
|
56
|
+
@name = options.delete(:name)
|
57
|
+
end
|
58
|
+
|
59
|
+
if options.has_key?(:timeout)
|
60
|
+
@timeout = options.delete(:timeout)
|
61
|
+
end
|
62
|
+
|
63
|
+
if options.has_key?(:weight)
|
64
|
+
@weight = options.delete(:weight)
|
65
|
+
end
|
66
|
+
|
67
|
+
if not options.keys.empty?
|
68
|
+
raise ArgumentError, "Invalid aggregate options #{options.keys.inspect}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def evaluate(&block)
|
73
|
+
instance_eval(&block)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Define a new chunk for the given aggregate
|
77
|
+
#
|
78
|
+
# @api public
|
79
|
+
#
|
80
|
+
# @example Defining a chunk with no dependencies
|
81
|
+
# aggregate.chunk(:mountpoints) do
|
82
|
+
# # generate mountpoint information
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# @example Defining an chunk to add mount options
|
86
|
+
# aggregate.chunk(:mount_options, :require => [:mountpoints]) do |mountpoints|
|
87
|
+
# # `mountpoints` is the result of the previous chunk
|
88
|
+
# # generate mount option information based on the mountpoints
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# @param name [Symbol] A name unique to this aggregate describing the chunk
|
92
|
+
# @param opts [Hash]
|
93
|
+
# @options opts [Array<Symbol>, Symbol] :require One or more chunks
|
94
|
+
# to evaluate and pass to this block.
|
95
|
+
# @yield [*Object] Zero or more chunk results
|
96
|
+
#
|
97
|
+
# @return [void]
|
98
|
+
def chunk(name, opts = {}, &block)
|
99
|
+
if not block_given?
|
100
|
+
raise ArgumentError, "#{self.class.name}#chunk requires a block"
|
101
|
+
end
|
102
|
+
|
103
|
+
deps = Array(opts.delete(:require))
|
104
|
+
|
105
|
+
if not opts.empty?
|
106
|
+
raise ArgumentError, "Unexpected options passed to #{self.class.name}#chunk: #{opts.keys.inspect}"
|
107
|
+
end
|
108
|
+
|
109
|
+
@deps[name] = deps
|
110
|
+
@chunks[name] = block
|
111
|
+
end
|
112
|
+
|
113
|
+
# Define how all chunks should be combined
|
114
|
+
#
|
115
|
+
# @api public
|
116
|
+
#
|
117
|
+
# @example Merge all chunks
|
118
|
+
# aggregate.aggregate do |chunks|
|
119
|
+
# final_result = {}
|
120
|
+
# chunks.each_value do |chunk|
|
121
|
+
# final_result.deep_merge(chunk)
|
122
|
+
# end
|
123
|
+
# final_result
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# @example Sum all chunks
|
127
|
+
# aggregate.aggregate do |chunks|
|
128
|
+
# total = 0
|
129
|
+
# chunks.each_value do |chunk|
|
130
|
+
# total += chunk
|
131
|
+
# end
|
132
|
+
# total
|
133
|
+
# end
|
134
|
+
#
|
135
|
+
# @yield [Hash<Symbol, Object>] A hash containing chunk names and
|
136
|
+
# chunk values
|
137
|
+
#
|
138
|
+
# @return [void]
|
139
|
+
def aggregate(&block)
|
140
|
+
if block_given?
|
141
|
+
@aggregate = block
|
142
|
+
else
|
143
|
+
raise ArgumentError, "#{self.class.name}#aggregate requires a block"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def resolution_type
|
148
|
+
:aggregate
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
# Evaluate the results of this aggregate.
|
154
|
+
#
|
155
|
+
# @see Facter::Core::Resolvable#value
|
156
|
+
# @return [Object]
|
157
|
+
def resolve_value
|
158
|
+
chunk_results = run_chunks()
|
159
|
+
aggregate_results(chunk_results)
|
160
|
+
end
|
161
|
+
|
162
|
+
# Order all chunks based on their dependencies and evaluate each one, passing
|
163
|
+
# dependent chunks as needed.
|
164
|
+
#
|
165
|
+
# @return [Hash<Symbol, Object>] A hash containing the chunk that
|
166
|
+
# generated value and the related value.
|
167
|
+
def run_chunks
|
168
|
+
results = {}
|
169
|
+
order_chunks.each do |(name, block)|
|
170
|
+
input = @deps[name].map { |dep_name| results[dep_name] }
|
171
|
+
|
172
|
+
output = block.call(*input)
|
173
|
+
results[name] = Facter::Util::Values.deep_freeze(output)
|
174
|
+
end
|
175
|
+
|
176
|
+
results
|
177
|
+
end
|
178
|
+
|
179
|
+
# Process the results of all chunks with the aggregate block and return the
|
180
|
+
# results. If no aggregate block has been specified, fall back to deep
|
181
|
+
# merging the given data structure
|
182
|
+
#
|
183
|
+
# @param results [Hash<Symbol, Object>] A hash of chunk names and the output
|
184
|
+
# of that chunk.
|
185
|
+
# @return [Object]
|
186
|
+
def aggregate_results(results)
|
187
|
+
if @aggregate
|
188
|
+
@aggregate.call(results)
|
189
|
+
else
|
190
|
+
default_aggregate(results)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def default_aggregate(results)
|
195
|
+
results.values.inject do |result, current|
|
196
|
+
Facter::Util::Values.deep_merge(result, current)
|
197
|
+
end
|
198
|
+
rescue Facter::Util::Values::DeepMergeError => e
|
199
|
+
raise ArgumentError, "Could not deep merge all chunks (Original error: " +
|
200
|
+
"#{e.message}), ensure that chunks return either an Array or Hash or " +
|
201
|
+
"override the aggregate block", e.backtrace
|
202
|
+
end
|
203
|
+
|
204
|
+
# Order chunks based on their dependencies
|
205
|
+
#
|
206
|
+
# @return [Array<Symbol, Proc>] A list of chunk names and blocks in evaluation order.
|
207
|
+
def order_chunks
|
208
|
+
if not @deps.acyclic?
|
209
|
+
raise DependencyError, "Could not order chunks; found the following dependency cycles: #{@deps.cycles.inspect}"
|
210
|
+
end
|
211
|
+
|
212
|
+
sorted_names = @deps.tsort
|
213
|
+
|
214
|
+
sorted_names.map do |name|
|
215
|
+
[name, @chunks[name]]
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
class DependencyError < StandardError; end
|
220
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'tsort'
|
3
|
+
|
4
|
+
module Facter
|
5
|
+
module Core
|
6
|
+
class DirectedGraph < Hash
|
7
|
+
include TSort
|
8
|
+
|
9
|
+
def acyclic?
|
10
|
+
cycles.empty?
|
11
|
+
end
|
12
|
+
|
13
|
+
def cycles
|
14
|
+
cycles = []
|
15
|
+
each_strongly_connected_component do |component|
|
16
|
+
cycles << component if component.size > 1
|
17
|
+
end
|
18
|
+
cycles
|
19
|
+
end
|
20
|
+
|
21
|
+
alias tsort_each_node each_key
|
22
|
+
|
23
|
+
def tsort_each_child(node)
|
24
|
+
fetch(node, []).each do |child|
|
25
|
+
yield child
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def tsort
|
30
|
+
missing = Set.new(self.values.flatten) - Set.new(self.keys)
|
31
|
+
|
32
|
+
if not missing.empty?
|
33
|
+
raise MissingVertex, "Cannot sort elements; cannot depend on missing elements #{missing.to_a}"
|
34
|
+
end
|
35
|
+
|
36
|
+
super
|
37
|
+
|
38
|
+
rescue TSort::Cyclic
|
39
|
+
raise CycleError, "Cannot sort elements; found the following cycles: #{cycles.inspect}"
|
40
|
+
end
|
41
|
+
|
42
|
+
class CycleError < StandardError; end
|
43
|
+
class MissingVertex < StandardError; end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|