diff options
Diffstat (limited to 'lib/puppet/simple_graph.rb')
-rw-r--r-- | lib/puppet/simple_graph.rb | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/lib/puppet/simple_graph.rb b/lib/puppet/simple_graph.rb index c926258ca..73a6bdfed 100644 --- a/lib/puppet/simple_graph.rb +++ b/lib/puppet/simple_graph.rb @@ -94,10 +94,47 @@ class Puppet::SimpleGraph @edges.clear end + # Which resources a given resource depends upon. + def dependents(resource) + tree_from_vertex(resource).keys + end + + # Which resources depend upon the given resource. + def dependencies(resource) + # Cache the reversal graph, because it's somewhat expensive + # to create. + unless defined? @reversal and @reversal + @reversal = reversal + end + # Strangely, it's significantly faster to search a reversed + # tree in the :out direction than to search a normal tree + # in the :in direction. + @reversal.tree_from_vertex(resource, :out).keys + end + # Whether our graph is directed. Always true. Used to produce dot files. def directed? true end + + # Collect all of the edges that the passed events match. Returns + # an array of edges. + def matching_edges(events, base = nil) + events.collect do |event| + source = base || event.source + + unless vertex?(source) + Puppet.warning "Got an event from invalid vertex %s" % source.ref + next + end + # Get all of the edges that this vertex should forward events + # to, which is the same thing as saying all edges directly below + # This vertex in the graph. + adjacent(source, :direction => :out, :type => :edges).find_all do |edge| + edge.match?(event.name) + end + end.compact.flatten + end # Return a reversed version of this graph. def reversal @@ -154,6 +191,7 @@ class Puppet::SimpleGraph # Add a new vertex to the graph. def add_vertex(vertex) + @reversal = nil return false if vertex?(vertex) setup_vertex(vertex) true # don't return the VertexWrapper instance. @@ -180,6 +218,7 @@ class Puppet::SimpleGraph # Add a new edge. The graph user has to create the edge instance, # since they have to specify what kind of edge it is. def add_edge(source, target = nil, label = nil) + @reversal = nil if target edge = Puppet::Relationship.new(source, target, label) else @@ -250,6 +289,52 @@ class Puppet::SimpleGraph # induced_subgraph(gv).write_to_graphic_file('jpg', name) # end # end + + # Take container information from another graph and use it + # to replace any container vertices with their respective leaves. + # This creates direct relationships where there were previously + # indirect relationships through the containers. + def splice!(other, type) + # We have to get the container list via a topological sort on the + # configuration graph, because otherwise containers that contain + # other containers will add those containers back into the + # graph. We could get a similar affect by only setting relationships + # to container leaves, but that would result in many more + # relationships. + containers = other.topsort.find_all { |v| v.is_a?(type) and vertex?(v) } + containers.each do |container| + # Get the list of children from the other graph. + children = other.adjacent(container, :direction => :out) + + # Just remove the container if it's empty. + if children.empty? + remove_vertex!(container) + next + end + + # First create new edges for each of the :in edges + [:in, :out].each do |dir| + edges = adjacent(container, :direction => dir, :type => :edges) + edges.each do |edge| + children.each do |child| + if dir == :in + s = edge.source + t = child + else + s = child + t = edge.target + end + + add_edge(s, t, edge.label) + end + + # Now get rid of the edge, so remove_vertex! works correctly. + remove_edge!(edge) + end + end + remove_vertex!(container) + end + end def to_yaml_properties instance_variables @@ -263,6 +348,16 @@ class Puppet::SimpleGraph end end + # A different way of walking a tree, and a much faster way than the + # one that comes with GRATR. + def tree_from_vertex(start, direction = :out) + predecessor={} + walk(start, direction) do |parent, child| + predecessor[child] = parent + end + predecessor + end + # LAK:FIXME This is just a paste of the GRATR code with slight modifications. # Return a DOT::DOTDigraph for directed graphs or a DOT::DOTSubgraph for an @@ -304,6 +399,14 @@ class Puppet::SimpleGraph system('dotty', dotfile) end + # Just walk the tree and pass each edge. + def walk(source, direction, &block) + adjacent(source, :direction => direction).each do |target| + yield source, target + walk(target, direction, &block) + end + end + # Use +dot+ to create a graphical representation of the graph. Returns the # filename of the graphics file. def write_to_graphic_file (fmt='png', dotfile='graph') |