arborist 0.0.1.pre20160128152542 → 0.0.1.pre20160606141735
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +2 -0
- data/ChangeLog +426 -1
- data/Manifest.txt +17 -2
- data/Nodes.md +70 -0
- data/Protocol.md +68 -9
- data/README.md +3 -5
- data/Rakefile +4 -1
- data/TODO.md +52 -20
- data/lib/arborist.rb +19 -6
- data/lib/arborist/cli.rb +39 -25
- data/lib/arborist/client.rb +97 -4
- data/lib/arborist/command/client.rb +2 -1
- data/lib/arborist/command/start.rb +51 -5
- data/lib/arborist/dependency.rb +286 -0
- data/lib/arborist/event.rb +7 -2
- data/lib/arborist/event/{node_matching.rb → node.rb} +11 -5
- data/lib/arborist/event/node_acked.rb +5 -7
- data/lib/arborist/event/node_delta.rb +30 -3
- data/lib/arborist/event/node_disabled.rb +16 -0
- data/lib/arborist/event/node_down.rb +10 -0
- data/lib/arborist/event/node_quieted.rb +11 -0
- data/lib/arborist/event/node_unknown.rb +10 -0
- data/lib/arborist/event/node_up.rb +10 -0
- data/lib/arborist/event/node_update.rb +2 -11
- data/lib/arborist/event/sys_node_added.rb +10 -0
- data/lib/arborist/event/sys_node_removed.rb +10 -0
- data/lib/arborist/exceptions.rb +4 -0
- data/lib/arborist/manager.rb +188 -18
- data/lib/arborist/manager/event_publisher.rb +1 -1
- data/lib/arborist/manager/tree_api.rb +92 -13
- data/lib/arborist/mixins.rb +17 -0
- data/lib/arborist/monitor.rb +10 -1
- data/lib/arborist/monitor/socket.rb +123 -2
- data/lib/arborist/monitor_runner.rb +6 -5
- data/lib/arborist/node.rb +420 -94
- data/lib/arborist/node/ack.rb +72 -0
- data/lib/arborist/node/host.rb +43 -8
- data/lib/arborist/node/resource.rb +73 -0
- data/lib/arborist/node/root.rb +6 -0
- data/lib/arborist/node/service.rb +89 -22
- data/lib/arborist/observer.rb +1 -1
- data/lib/arborist/subscription.rb +11 -6
- data/spec/arborist/client_spec.rb +93 -5
- data/spec/arborist/dependency_spec.rb +375 -0
- data/spec/arborist/event/node_delta_spec.rb +66 -0
- data/spec/arborist/event/node_down_spec.rb +84 -0
- data/spec/arborist/event/node_spec.rb +59 -0
- data/spec/arborist/event/node_update_spec.rb +14 -3
- data/spec/arborist/event_spec.rb +3 -3
- data/spec/arborist/manager/tree_api_spec.rb +295 -3
- data/spec/arborist/manager_spec.rb +240 -57
- data/spec/arborist/monitor_spec.rb +26 -3
- data/spec/arborist/node/ack_spec.rb +74 -0
- data/spec/arborist/node/host_spec.rb +79 -0
- data/spec/arborist/node/resource_spec.rb +56 -0
- data/spec/arborist/node/service_spec.rb +68 -2
- data/spec/arborist/node_spec.rb +288 -11
- data/spec/arborist/subscription_spec.rb +23 -14
- data/spec/arborist_spec.rb +0 -4
- data/spec/data/observers/webservices.rb +10 -2
- data/spec/spec_helper.rb +8 -0
- metadata +58 -15
- metadata.gz.sig +0 -0
- data/LICENSE +0 -29
data/lib/arborist/client.rb
CHANGED
@@ -58,10 +58,11 @@ class Arborist::Client
|
|
58
58
|
|
59
59
|
|
60
60
|
### Return the manager's current node tree.
|
61
|
-
def make_list_request( from: nil )
|
61
|
+
def make_list_request( from: nil, depth: nil )
|
62
62
|
header = {}
|
63
63
|
self.log.debug "From is: %p" % [ from ]
|
64
64
|
header[:from] = from if from
|
65
|
+
header[:depth] = depth if depth
|
65
66
|
|
66
67
|
return self.pack_message( :list, header )
|
67
68
|
end
|
@@ -75,19 +76,54 @@ class Arborist::Client
|
|
75
76
|
|
76
77
|
|
77
78
|
### Return the manager's current node tree.
|
78
|
-
def make_fetch_request( criteria, include_down: false, properties: :all )
|
79
|
+
def make_fetch_request( criteria, include_down: false, properties: :all, exclude: {} )
|
79
80
|
header = {}
|
80
81
|
header[ :include_down ] = true if include_down
|
81
82
|
header[ :return ] = properties if properties != :all
|
82
83
|
|
83
|
-
return self.pack_message( :fetch, header, criteria )
|
84
|
+
return self.pack_message( :fetch, header, [ criteria, exclude ] )
|
84
85
|
end
|
85
86
|
|
86
87
|
|
88
|
+
### Mark a node as 'acknowledged' if it's down, or 'disabled' if
|
89
|
+
### it's up. (A pre-emptive acknowledgement.) Requires the node
|
90
|
+
### +identifier+, an acknowledgement +message+, and +sender+. You
|
91
|
+
### can optionally include a +via+ (source), and override the default
|
92
|
+
### +time+ of now.
|
93
|
+
def acknowledge( node, message, sender, via=nil, time=Time.now )
|
94
|
+
data = {
|
95
|
+
node => {
|
96
|
+
ack: {
|
97
|
+
message: message,
|
98
|
+
sender: sender,
|
99
|
+
via: via,
|
100
|
+
time: time.to_s
|
101
|
+
}
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
request = self.make_update_request( data )
|
106
|
+
self.send_tree_api_request( request )
|
107
|
+
return true
|
108
|
+
end
|
109
|
+
alias_method :ack, :acknowledge
|
110
|
+
|
111
|
+
|
112
|
+
### Clear an acknowledged/disabled +node+.
|
113
|
+
def clear_acknowledgement( node )
|
114
|
+
data = { node => { ack: nil } }
|
115
|
+
request = self.make_update_request( data )
|
116
|
+
self.send_tree_api_request( request )
|
117
|
+
return true
|
118
|
+
end
|
119
|
+
alias_method :clear_ack, :clear_acknowledgement
|
120
|
+
|
121
|
+
|
87
122
|
### Update the identified nodes in the manager with the specified data.
|
88
123
|
def update( *args )
|
89
124
|
request = self.make_update_request( *args )
|
90
|
-
|
125
|
+
self.send_tree_api_request( request )
|
126
|
+
return true
|
91
127
|
end
|
92
128
|
|
93
129
|
|
@@ -133,6 +169,63 @@ class Arborist::Client
|
|
133
169
|
end
|
134
170
|
|
135
171
|
|
172
|
+
### Remove a node
|
173
|
+
def prune( *args )
|
174
|
+
request = self.make_prune_request( *args )
|
175
|
+
response = self.send_tree_api_request( request )
|
176
|
+
return response
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
### Remove the node with the specified +identfier+.
|
181
|
+
def make_prune_request( identifier )
|
182
|
+
self.log.debug "Making prune request for identifier: %s" % [ identifier ]
|
183
|
+
|
184
|
+
return self.pack_message( :prune, identifier: identifier )
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
### Add a new node to the tree.
|
189
|
+
def graft( *args )
|
190
|
+
request = self.make_graft_request( *args )
|
191
|
+
response = self.send_tree_api_request( request )
|
192
|
+
return response
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
### Add a node with the specified +identifier+ and +arguments+.
|
197
|
+
def make_graft_request( identifier, attributes={} )
|
198
|
+
self.log.debug "Making graft request for identifer: %s" % [ identifier ]
|
199
|
+
|
200
|
+
parent = attributes.delete( :parent )
|
201
|
+
type = attributes.delete( :type )
|
202
|
+
|
203
|
+
header = {
|
204
|
+
identifier: identifier,
|
205
|
+
parent: parent,
|
206
|
+
type: type
|
207
|
+
}
|
208
|
+
|
209
|
+
return self.pack_message( :graft, header, attributes )
|
210
|
+
end
|
211
|
+
|
212
|
+
|
213
|
+
### Modify operational attributes of a node.
|
214
|
+
def modify( *args )
|
215
|
+
request = self.make_modify_request( *args )
|
216
|
+
response = self.send_tree_api_request( request )
|
217
|
+
return true
|
218
|
+
end
|
219
|
+
|
220
|
+
|
221
|
+
### Modify the operations +attributes+ of the node with the specified +identifier+.
|
222
|
+
def make_modify_request( identifier, attributes={} )
|
223
|
+
self.log.debug "Making modify request for identifer: %s" % [ identifier ]
|
224
|
+
|
225
|
+
return self.pack_message( :modify, {identifier: identifier}, attributes )
|
226
|
+
end
|
227
|
+
|
228
|
+
|
136
229
|
### Send the packed +request+ via the Tree API socket, raise an error on
|
137
230
|
### unsuccessful response, and return the response body.
|
138
231
|
def send_tree_api_request( request )
|
@@ -22,11 +22,15 @@ module Arborist::CLI::Start
|
|
22
22
|
cmd.flag :loader, desc: "Specify a loader type to use.",
|
23
23
|
default_value: 'file'
|
24
24
|
|
25
|
+
cmd.desc "Run under the profiler in the given MODE (one of wall, cpu, or object; defaults to wall)."
|
26
|
+
cmd.arg_name :MODE
|
27
|
+
cmd.flag [:p, 'profiler'], must_match: ['wall', 'cpu', 'object']
|
28
|
+
|
25
29
|
cmd.action do |globals, options, args|
|
26
30
|
appname = args.shift
|
27
31
|
source = args.shift
|
28
32
|
|
29
|
-
loader = Arborist::Loader.create( options
|
33
|
+
loader = Arborist::Loader.create( options[:loader], source )
|
30
34
|
runner = case appname
|
31
35
|
when 'manager'
|
32
36
|
Arborist.manager_for( loader )
|
@@ -39,7 +43,7 @@ module Arborist::CLI::Start
|
|
39
43
|
end
|
40
44
|
|
41
45
|
unless_dryrun( "starting #{appname}" ) do
|
42
|
-
start( runner )
|
46
|
+
start( runner, options[:p] )
|
43
47
|
end
|
44
48
|
end
|
45
49
|
end
|
@@ -51,10 +55,52 @@ module Arborist::CLI::Start
|
|
51
55
|
|
52
56
|
### Start the specified +runner+ instance after setting up the environment for
|
53
57
|
### it.
|
54
|
-
def start( runner )
|
55
|
-
|
56
|
-
|
58
|
+
def start( runner, profile_mode=nil )
|
59
|
+
Process.setproctitle( runner.class.name )
|
60
|
+
|
61
|
+
if profile_mode
|
62
|
+
self.with_profiling_enabled( profile_mode, runner ) do
|
63
|
+
runner.run
|
64
|
+
end
|
65
|
+
else
|
66
|
+
runner.run
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
### Wrap the profiler around the specified +callable+.
|
72
|
+
def self::with_profiling_enabled( profile_arg, runner, &block )
|
73
|
+
require 'stackprof'
|
74
|
+
mode, outfile = self.parse_profile_args( profile_arg, runner )
|
75
|
+
|
76
|
+
self.log.info "Profiling in %s mode, outputting to %s" % [ mode, outfile ]
|
77
|
+
StackProf.run( mode: mode.to_sym, out: outfile, &block )
|
78
|
+
rescue LoadError => err
|
79
|
+
self.log.debug "%p while loading the StackProf profiler: %s"
|
80
|
+
exit_now!( "Couldn't load the profiler; you probably need to `gem install stackprof`", 254 )
|
57
81
|
end
|
58
82
|
|
83
|
+
|
84
|
+
### Set up the StackProf profiler to run in the given +mode+.
|
85
|
+
def self::parse_profile_args( arg, runner )
|
86
|
+
profile_mode, profile_filename = arg.split( ':', 2 )
|
87
|
+
profile_filename ||= self.default_profile_filename( profile_mode, runner )
|
88
|
+
|
89
|
+
return profile_mode, profile_filename
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
### Return a filename for a StackProf profile run over the given +runner+.
|
94
|
+
def self::default_profile_filename( mode, runner )
|
95
|
+
basename = runner.class.name.gsub( /.*::/, '' )
|
96
|
+
return "%s-%s-%s.%d.dump" % [
|
97
|
+
basename,
|
98
|
+
mode,
|
99
|
+
Time.now.strftime('%Y%m%d%H%M%S'),
|
100
|
+
Process.pid,
|
101
|
+
]
|
102
|
+
end
|
103
|
+
|
104
|
+
|
59
105
|
end # module Arborist::CLI::Start
|
60
106
|
|
@@ -0,0 +1,286 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
#encoding: utf-8
|
3
|
+
|
4
|
+
require 'set'
|
5
|
+
require 'time'
|
6
|
+
require 'loggability'
|
7
|
+
|
8
|
+
require 'arborist' unless defined?( Arborist )
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
# A inter-node dependency that is outside of the implicit ones expressed by the
|
13
|
+
# tree.
|
14
|
+
class Arborist::Dependency
|
15
|
+
extend Loggability
|
16
|
+
|
17
|
+
|
18
|
+
# Loggability API -- log to the Arborist logger
|
19
|
+
log_to :arborist
|
20
|
+
|
21
|
+
|
22
|
+
### Construct a new Dependency for the specified +behavior+ on the given +identifiers+
|
23
|
+
### with +prefixes+.
|
24
|
+
def self::on( behavior, *identifiers, prefixes: nil )
|
25
|
+
deps, identifiers = identifiers.flatten.uniq.partition {|obj| obj.is_a?(self.class) }
|
26
|
+
prefixes = Array( prefixes ).uniq
|
27
|
+
identifiers = prefixes.product( identifiers ).map {|pair| pair.join('-') } unless
|
28
|
+
prefixes.empty?
|
29
|
+
|
30
|
+
return self.new( behavior, identifiers + deps )
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
### Construct a new instance using the specified +hash+, which should be in the same form
|
35
|
+
### as that generated by #to_h:
|
36
|
+
###
|
37
|
+
### {
|
38
|
+
### behavior: <string>,
|
39
|
+
### identifiers: [<identifier_1>, <identifier_n>],
|
40
|
+
### subdeps: [<dephash_1>, <dephash_n>],
|
41
|
+
### }
|
42
|
+
###
|
43
|
+
def self::from_hash( hash )
|
44
|
+
self.log.debug "Creating a new %p from a hash: %p" % [ self, hash ]
|
45
|
+
|
46
|
+
hash[:subdeps] ||= []
|
47
|
+
subdeps = hash[:subdeps].map {|subhash| self.from_hash(subhash) }
|
48
|
+
|
49
|
+
return self.new( hash[:behavior], hash[:identifiers] + subdeps )
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
### Create a new Dependency on the specified +nodes_or_subdeps+ with the given +behavior+
|
54
|
+
### (one of :any or :all)
|
55
|
+
def initialize( behavior, *nodes_or_subdeps )
|
56
|
+
@behavior = behavior
|
57
|
+
@subdeps, identifiers = nodes_or_subdeps.flatten.
|
58
|
+
partition {|obj| obj.is_a?(self.class) }
|
59
|
+
@identifier_states = identifiers.product([ nil ]).to_h
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
### Dup constructor -- dup internal datastructures without ephemeral state on #dup.
|
64
|
+
def initialize_dup( original ) # :nodoc:
|
65
|
+
@subdeps = @subdeps.map( &:dup )
|
66
|
+
@identifier_states = @identifier_states.keys.product([ nil ]).to_h
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
### Clone constructor -- clone internal datastructures without ephemeral state on #clone.
|
71
|
+
def initialize_clone( original ) # :nodoc:
|
72
|
+
@subdeps = @subdeps.map( &:clone )
|
73
|
+
@identifier_states = @identifier_states.keys.product([ nil ]).to_h
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
######
|
78
|
+
public
|
79
|
+
######
|
80
|
+
|
81
|
+
##
|
82
|
+
# The behavior that determines if the dependency is met by any or all of the
|
83
|
+
# nodes.
|
84
|
+
attr_reader :behavior
|
85
|
+
|
86
|
+
##
|
87
|
+
# The Hash of identifier states
|
88
|
+
attr_reader :identifier_states
|
89
|
+
|
90
|
+
##
|
91
|
+
# The Array of sub-dependencies (instances of Dependency).
|
92
|
+
attr_reader :subdeps
|
93
|
+
|
94
|
+
|
95
|
+
### Return a Set of identifiers belonging to this dependency.
|
96
|
+
def identifiers
|
97
|
+
return Set.new( self.identifier_states.keys )
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
### Return a Set of identifiers which have been marked down in this dependency.
|
102
|
+
def down_identifiers
|
103
|
+
return Set.new( self.identifier_states.select {|_, mark| mark }.map(&:first) )
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
### Return a Set of identifiers which have not been marked down in this dependency.
|
108
|
+
def up_identifiers
|
109
|
+
return Set.new( self.identifier_states.reject {|_, mark| mark }.map(&:first) )
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
### Return a Set of identifiers for all of this Dependency's sub-dependencies.
|
114
|
+
def subdep_identifiers
|
115
|
+
return self.subdeps.map( &:all_identifiers ).reduce( :+ ) || Set.new
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
### Return the Set of this Dependency's identifiers as well as those of all of its
|
120
|
+
### sub-dependencies.
|
121
|
+
def all_identifiers
|
122
|
+
return self.identifiers + self.subdep_identifiers
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
### Return any of this dependency's sub-dependencies that are down.
|
127
|
+
def down_subdeps
|
128
|
+
return self.subdeps.select( &:down? )
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
### Return any of this dependency's sub-dependencies that are up.
|
133
|
+
def up_subdeps
|
134
|
+
return self.subdeps.select( &:up? )
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
### Yield each unique identifier and Time of downed nodes from both direct and
|
139
|
+
### sub-dependencies.
|
140
|
+
def each_downed
|
141
|
+
return enum_for( __method__ ) unless block_given?
|
142
|
+
|
143
|
+
yielded = Set.new
|
144
|
+
self.identifier_states.each do |ident, time|
|
145
|
+
if time
|
146
|
+
yield( ident, time ) unless yielded.include?( ident )
|
147
|
+
yielded.add( ident )
|
148
|
+
end
|
149
|
+
end
|
150
|
+
self.subdeps.each do |subdep|
|
151
|
+
subdep.each_downed do |ident, time|
|
152
|
+
if time
|
153
|
+
yield( ident, time ) unless yielded.include?( ident )
|
154
|
+
yielded.add( ident )
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
### Returns +true+ if the receiver includes all of the given +identifiers+.
|
162
|
+
def include?( *identifiers )
|
163
|
+
return self.all_identifiers.include?( *identifiers )
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
### Returns +true+ if this dependency doesn't contain any identifiers or
|
168
|
+
### sub-dependencies.
|
169
|
+
def empty?
|
170
|
+
return self.all_identifiers.empty?
|
171
|
+
end
|
172
|
+
|
173
|
+
|
174
|
+
### Mark the specified +identifier+ as being down and propagate it to any subdependencies.
|
175
|
+
def mark_down( identifier, time=Time.now )
|
176
|
+
self.identifier_states[ identifier ] = time if self.identifier_states.key?( identifier )
|
177
|
+
self.subdeps.each do |dep|
|
178
|
+
dep.mark_down( identifier, time )
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
### Mark the specified +identifier+ as being up and propagate it to any subdependencies.
|
184
|
+
def mark_up( identifier )
|
185
|
+
self.subdeps.each do |dep|
|
186
|
+
dep.mark_up( identifier )
|
187
|
+
end
|
188
|
+
self.identifier_states[ identifier ] = nil if self.identifier_states.key?( identifier )
|
189
|
+
end
|
190
|
+
|
191
|
+
|
192
|
+
### Returns +true+ if this dependency cannot be met.
|
193
|
+
def down?
|
194
|
+
case self.behavior
|
195
|
+
when :all
|
196
|
+
self.identifier_states.values.any? || self.subdeps.any?( &:down? )
|
197
|
+
when :any
|
198
|
+
self.identifier_states.values.all? && self.subdeps.all?( &:down? )
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
### Returns +true+ if this dependency is met.
|
204
|
+
def up?
|
205
|
+
return !self.down?
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
### Returns the earliest Time a node was marked down.
|
210
|
+
def earliest_down_time
|
211
|
+
return self.identifier_states.values.compact.min
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
### Returns the latest Time a node was marked down.
|
216
|
+
def latest_down_time
|
217
|
+
return self.identifier_states.values.compact.max
|
218
|
+
end
|
219
|
+
|
220
|
+
|
221
|
+
### Return an English description of why this dependency is not met. If it is
|
222
|
+
### met, returns +nil+.
|
223
|
+
def down_reason
|
224
|
+
ids = self.down_identifiers
|
225
|
+
subdeps = self.down_subdeps
|
226
|
+
|
227
|
+
return nil if ids.empty? && subdeps.empty?
|
228
|
+
|
229
|
+
msg = nil
|
230
|
+
case self.behavior
|
231
|
+
when :all
|
232
|
+
msg = ids.first.dup
|
233
|
+
if ids.size == 1
|
234
|
+
msg << " is down"
|
235
|
+
else
|
236
|
+
msg << " (and %d other%s) are down" % [ ids.size - 1, ids.size == 2 ? '' : 's' ]
|
237
|
+
end
|
238
|
+
|
239
|
+
msg << " as of %s" % [ self.earliest_down_time ]
|
240
|
+
|
241
|
+
when :any
|
242
|
+
msg = "%s are all down" % [ ids.to_a.join(', ') ]
|
243
|
+
msg << " as of %s" % [ self.latest_down_time ]
|
244
|
+
|
245
|
+
else
|
246
|
+
raise "Don't know how to build a description of down behavior for %p" % [ self.behavior ]
|
247
|
+
end
|
248
|
+
|
249
|
+
return msg
|
250
|
+
end
|
251
|
+
|
252
|
+
|
253
|
+
### Return the entire dependency tree as a nested Hash.
|
254
|
+
def to_h
|
255
|
+
return {
|
256
|
+
behavior: self.behavior,
|
257
|
+
identifiers: self.identifier_states.keys,
|
258
|
+
subdeps: self.subdeps.map( &:to_h )
|
259
|
+
}
|
260
|
+
end
|
261
|
+
|
262
|
+
|
263
|
+
### Returns true if +other+ is the same object or if they both have the same
|
264
|
+
### identifiers, sub-dependencies, and identifier states.
|
265
|
+
def eql?( other )
|
266
|
+
self.log.debug "Comparing %p to %p (with states)" % [ self, other ]
|
267
|
+
return true if other.equal?( self )
|
268
|
+
return self == other &&
|
269
|
+
self.identifier_states.eql?( other.identifier_states ) &&
|
270
|
+
self.subdeps.eql?( other.subdeps )
|
271
|
+
end
|
272
|
+
|
273
|
+
|
274
|
+
### Equality comparison operator -- return true if the +other+ dependency has the same
|
275
|
+
### behavior, identifiers, and sub-dependencies. Does not consider identifier states.
|
276
|
+
def ==( other )
|
277
|
+
return true if other.equal?( self )
|
278
|
+
return false unless other.is_a?( self.class )
|
279
|
+
|
280
|
+
return self.behavior == other.behavior &&
|
281
|
+
self.identifiers == other.identifiers &&
|
282
|
+
self.subdeps == other.subdeps
|
283
|
+
end
|
284
|
+
|
285
|
+
end # class Arborist::Dependency
|
286
|
+
|