class SortedWalking
class Vertex
attr_accessor :weight, :label
def initialize(label, weight = nil)
@label = label
@weight = weight || 5
end
def to_s
label
end
end
class ShadowMap
Shadow = Struct.new(:failed, :noop, :events, :dependents)
attr_reader :map
def initialize
@map = {}
@failed = {}
end
def [](vertex)
@map[vertex]
end
# Store a failure for later.
def fail(vertex, reason)
@failed[vertex] ||= []
@failed[vertex] << resource
end
def shadow(edge)
target_shadow = find_or_make_shadow(edge)
add_failures(edge.target, target_shadow)
target_shadow
end
private
def add_failures(vertex, shadow)
if failures = @failed[vertex]
shadow.failures += failures
end
end
def find_or_make_shadow(edge)
unless target_shadow = map[edge.target]
unless source_shadow = map[edge.source]
# This should be the top-level initialization
map[edge.source] = Shadow.new([], [], [], [])
end
target_shadow = map[edge.target] = make_target_shadow(target, source_shadow)
end
end
def make_target_shadow(target, source_shadow)
# We clone so that each shadow has its own array, rather than using
# the same instance variables, as a 'dup' would do.
shadow = source_shadow.clone
end
end
def vertex(name)
@graph.vertices.find { |v| v.label == name } || Vertex.new(name)
end
def add_edge(source, target, type = :container)
edge = Puppet::Relationship.new(vertex(source), vertex(target))
edge.type = type
@graph.add_edge(edge)
end
def initialize
Puppet[:graphdir] = "/Users/luke/Desktop/graph_testing"
Puppet[:graph] = true
@graph = Puppet::SimpleGraph.new
add_edge("top", "a")
add_edge("top", "A")
add_edge("a", "b")
add_edge("b", "c")
add_edge("a", "d")
add_edge("d", "e")
add_edge("d", "f")
add_edge("a", "g")
add_edge("A", "B")
add_edge("B", "C")
add_edge("A", "D")
add_edge("D", "E")
add_edge("D", "F")
add_edge("A", "G")
# Now add our dependency edges
#@dependencies = {"B" => "b", "C" => "d", "D" => "d"}
#@dependencies = {"B" => "b", "C" => "d"}
#@dependencies = {"B" => "b", "C" => "d", "D" => "g"}
#@dependencies = {"A" => "a"}
#@dependencies = {}
#@weights = {}
#@weights = { "A" => 4, "d" => 1 }
@failures = %w{f}
add_dependencies
add_weights
@shadow_map = ShadowMap.new
end
def add_dependencies
return unless defined?(@dependencies)
@dependencies.each do |source, target|
add_edge(source, target, :dependency)
end
end
def add_weights
return unless defined?(@weights)
@weights.each do |v, weight|
vertex(v).weight = weight
end
end
def apply_shadow(edge)
return unless edge.container?
shadow = @shadow_map.shadow(edge)
# Track all of our dependents
shadow.dependents += dependent_edges(edge.target)
# Track failure state
if @failures.include?(edge.target.label)
shadow.failed << "%s failed" % edge.target.label
# Mark all of our dependents as failed, too
shadow.dependents.each do |edge|
@shadow_map.fail(edge.source, shadow.failed[-1])
end
end
shadow
end
def dependent_edges(vertex)
adjacent(vertex, :direction => :in, :type => :edges).reject { |e| e.container? }
end
def run
top = @graph.vertices.find { |v| v.label == "top" }
result = []
@graph.dfs_walk(top, :out) do |edge|
begin
#apply_shadow(edge)
rescue => detail
puts "Skipping %s: %s" % [edge.target, detail]
next
end
result << edge.target.label unless result.include?(edge.target.label)
end
@graph.write_graph("test")
p result
end
end