summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2007-09-17 15:21:44 -0700
committerLuke Kanies <luke@madstop.com>2007-09-17 15:21:44 -0700
commit9fa2628a844c75b8f554f283dfece01667f20594 (patch)
tree7c1b57c56879b2b083063895bae6423f2b94dc9c /lib
parentb3c8cdb67d9a423a1d14764f1e58f677d7ef8d41 (diff)
This is basically another intermediate commit. I feel like
I've gone too far down the rabbit hole to turn back now, but the code is clearly getting more centralized around the Configuration class, which is the goal. Things are currently a bit muddy between recursion, dynamic resource generation, transactions, and the configuration, and I don't expect to be able to clear it up much until we rewrite all of the tests for the Transaction class, since that is when we'll actually be setting its behaviour. At this point, Files (which are currently the only resources that generate other resources) are responsible for adding their edges to the relationship graph. This puts them knowing more than I would like about how the relationship graph works, but it'll have to do for now. There are still failing tests, but files seem to work again. Now to go through the rest of the tests and make them work.
Diffstat (limited to 'lib')
-rw-r--r--lib/puppet/dsl.rb7
-rw-r--r--lib/puppet/metatype/closure.rb13
-rw-r--r--lib/puppet/metatype/container.rb8
-rw-r--r--lib/puppet/metatype/instances.rb7
-rwxr-xr-xlib/puppet/network/handler/resource.rb13
-rw-r--r--lib/puppet/node/configuration.rb164
-rw-r--r--lib/puppet/reports/store.rb2
-rw-r--r--lib/puppet/transaction.rb89
-rw-r--r--lib/puppet/transportable.rb7
-rw-r--r--lib/puppet/type.rb13
-rw-r--r--lib/puppet/type/component.rb24
-rw-r--r--lib/puppet/type/pfile.rb18
-rw-r--r--lib/puppet/util/config.rb18
-rw-r--r--lib/puppet/util/graph.rb39
14 files changed, 204 insertions, 218 deletions
diff --git a/lib/puppet/dsl.rb b/lib/puppet/dsl.rb
index 795358e83..3696cd9ee 100644
--- a/lib/puppet/dsl.rb
+++ b/lib/puppet/dsl.rb
@@ -67,11 +67,8 @@ module Puppet
def apply
bucket = export()
- objects = bucket.to_type
- master = Puppet::Network::Client.master.new :Master => "whatever"
- master.objects = objects
-
- master.apply
+ configuration = bucket.to_configuration
+ configuration.apply
end
def export
diff --git a/lib/puppet/metatype/closure.rb b/lib/puppet/metatype/closure.rb
index efb4712c6..727bc6884 100644
--- a/lib/puppet/metatype/closure.rb
+++ b/lib/puppet/metatype/closure.rb
@@ -1,19 +1,6 @@
class Puppet::Type
attr_writer :implicit
- def self.implicitcreate(hash)
- unless hash.include?(:implicit)
- hash[:implicit] = true
- end
- if obj = self.create(hash)
- obj.implicit = true
-
- return obj
- else
- return nil
- end
- end
-
# Is this type's name isomorphic with the object? That is, if the
# name conflicts, does it necessarily mean that the objects conflict?
# Defaults to true.
diff --git a/lib/puppet/metatype/container.rb b/lib/puppet/metatype/container.rb
index 7c44a7def..7bbccf8a0 100644
--- a/lib/puppet/metatype/container.rb
+++ b/lib/puppet/metatype/container.rb
@@ -14,14 +14,6 @@ class Puppet::Type
self.class.depthfirst?
end
- def parent=(parent)
- if self.parentof?(parent)
- devfail "%s[%s] is already the parent of %s[%s]" %
- [self.class.name, self.title, parent.class.name, parent.title]
- end
- @parent = parent
- end
-
# Add a hook for testing for recursion.
def parentof?(child)
if (self == child)
diff --git a/lib/puppet/metatype/instances.rb b/lib/puppet/metatype/instances.rb
index f6c2fdd34..4fd72e85c 100644
--- a/lib/puppet/metatype/instances.rb
+++ b/lib/puppet/metatype/instances.rb
@@ -79,8 +79,7 @@ class Puppet::Type
end
# Force users to call this, so that we can merge objects if
- # necessary. FIXME This method should be responsible for most of the
- # error handling.
+ # necessary.
def self.create(args)
# Don't modify the original hash; instead, create a duplicate and modify it.
# We have to dup and use the ! so that it stays a TransObject if it is
@@ -308,8 +307,8 @@ class Puppet::Type
# Create the path for logging and such.
def pathbuilder
- if defined? @parent and @parent
- [@parent.pathbuilder, self.ref].flatten
+ if p = parent
+ [p.pathbuilder, self.ref].flatten
else
[self.ref]
end
diff --git a/lib/puppet/network/handler/resource.rb b/lib/puppet/network/handler/resource.rb
index ac29dce53..7709b85fe 100755
--- a/lib/puppet/network/handler/resource.rb
+++ b/lib/puppet/network/handler/resource.rb
@@ -39,21 +39,14 @@ class Puppet::Network::Handler
end
end
- component = bucket.to_type
-
- # Create a client, but specify the remote machine as the server
- # because the class requires it, even though it's unused
- client = Puppet::Network::Client.client(:Master).new(:Master => client||"localhost")
-
- # Set the objects
- client.objects = component
+ config = bucket.to_configuration
# And then apply the configuration. This way we're reusing all
# the code in there. It should probably just be separated out, though.
- transaction = client.apply
+ transaction = config.apply
# And then clean up
- component.remove
+ config.clear(true)
# It'd be nice to return some kind of report, but... at this point
# we have no such facility.
diff --git a/lib/puppet/node/configuration.rb b/lib/puppet/node/configuration.rb
index 9cd23926e..c882e0ee1 100644
--- a/lib/puppet/node/configuration.rb
+++ b/lib/puppet/node/configuration.rb
@@ -35,20 +35,22 @@ class Puppet::Node::Configuration < Puppet::PGraph
tag(*classes)
end
- # Add a resource to our graph and to our resource table.
- def add_resource(resource)
- unless resource.respond_to?(:ref)
- raise ArgumentError, "Can only add objects that respond to :ref"
- end
+ # Add one or more resources to our graph and to our resource table.
+ def add_resource(*resources)
+ resources.each do |resource|
+ unless resource.respond_to?(:ref)
+ raise ArgumentError, "Can only add objects that respond to :ref"
+ end
- ref = resource.ref
- if @resource_table.include?(ref)
- raise ArgumentError, "Resource %s is already defined" % ref
- else
- @resource_table[ref] = resource
+ ref = resource.ref
+ if @resource_table.include?(ref)
+ raise ArgumentError, "Resource %s is already defined" % ref
+ else
+ @resource_table[ref] = resource
+ end
+ resource.configuration = self
+ add_vertex!(resource)
end
- resource.configuration = self
- add_vertex!(resource)
end
# Apply our configuration to the local host.
@@ -58,6 +60,8 @@ class Puppet::Node::Configuration < Puppet::PGraph
transaction.addtimes :config_retrieval => @retrieval_duration
+ @applying = true
+
begin
transaction.evaluate
rescue Puppet::Error => detail
@@ -83,22 +87,62 @@ class Puppet::Node::Configuration < Puppet::PGraph
return transaction
ensure
+ @applying = false
+ cleanup()
if defined? transaction and transaction
transaction.cleanup
end
end
+
+ # Are we in the middle of applying the configuration?
+ def applying?
+ @applying
+ end
def clear(remove_resources = true)
super()
# We have to do this so that the resources clean themselves up.
@resource_table.values.each { |resource| resource.remove } if remove_resources
@resource_table.clear
+
+ if defined?(@relationship_graph) and @relationship_graph
+ @relationship_graph.clear(false)
+ @relationship_graph = nil
+ end
end
def classes
@classes.dup
end
+ # Create an implicit resource, meaning that it will lose out
+ # to any explicitly defined resources. This method often returns
+ # nil.
+ def create_implicit_resource(type, options)
+ unless options.include?(:implicit)
+ options[:implicit] = true
+ end
+ if resource = create_resource(type, options)
+ resource.implicit = true
+
+ return resource
+ else
+ return nil
+ end
+ end
+
+ # Create a new resource and register it in the configuration.
+ def create_resource(type, options)
+ unless klass = Puppet::Type.type(type)
+ raise ArgumentError, "Unknown resource type %s" % type
+ end
+ return unless resource = klass.create(options)
+
+ @transient_resources << resource if applying?
+ add_resource(resource)
+ resource
+ end
+
# Make sure we support the requested extraction format.
def extraction_format=(value)
unless respond_to?("extract_to_%s" % value)
@@ -174,6 +218,12 @@ class Puppet::Node::Configuration < Puppet::PGraph
# Make sure all of our resources are "finished".
def finalize
@resource_table.values.each { |resource| resource.finish }
+
+ write_graph(:resources)
+ end
+
+ def host_config?
+ host_config || false
end
def initialize(name = nil)
@@ -183,20 +233,76 @@ class Puppet::Node::Configuration < Puppet::PGraph
@tags = []
@classes = []
@resource_table = {}
+ @transient_resources = []
+ @applying = false
if block_given?
yield(self)
finalize()
end
end
+
+ # Create a graph of all of the relationships in our configuration.
+ def relationship_graph
+ unless defined? @relationship_graph and @relationship_graph
+ relationships = self.class.new
+
+ # First create the dependency graph
+ self.vertices.each do |vertex|
+ relationships.add_resource vertex
+ vertex.builddepends.each do |edge|
+ relationships.add_edge!(edge)
+ end
+ end
+
+ # Lastly, add in any autorequires
+ relationships.vertices.each do |vertex|
+ vertex.autorequire.each do |edge|
+ unless relationships.edge?(edge)
+ unless relationships.edge?(edge.target, edge.source)
+ vertex.debug "Autorequiring %s" % [edge.source]
+ relationships.add_edge!(edge)
+ else
+ vertex.debug "Skipping automatic relationship with %s" % (edge.source == vertex ? edge.target : edge.source)
+ end
+ end
+ end
+ end
+
+ relationships.write_graph(:relationships)
+
+ # Then splice in the container information
+ relationships.splice!(self, Puppet::Type::Component)
+
+ relationships.write_graph(:expanded_relationships)
+ @relationship_graph = relationships
+ end
+ @relationship_graph
+ end
- # Look a resource up by its reference (e.g., File[/etc/passwd]).
- def resource(ref)
- @resource_table[ref]
+ # Remove the resource from our configuration. Notice that we also call
+ # 'remove' on the resource, at least until resource classes no longer maintain
+ # references to the resource instances.
+ def remove_resource(*resources)
+ resources.each do |resource|
+ @resource_table.delete(resource.ref) if @resource_table.include?(resource.ref)
+ remove_vertex!(resource) if vertex?(resource)
+ resource.remove
+ end
end
- def host_config?
- host_config || false
+ # Look a resource up by its reference (e.g., File[/etc/passwd]).
+ def resource(type, title = nil)
+ if title
+ ref = "%s[%s]" % [type.to_s.capitalize, title]
+ else
+ ref = type
+ end
+ if resource = @resource_table[ref]
+ return resource
+ elsif defined?(@relationship_graph) and @relationship_graph
+ @relationship_graph.resource(ref)
+ end
end
# Add a tag.
@@ -217,4 +323,28 @@ class Puppet::Node::Configuration < Puppet::PGraph
def tags
@tags.dup
end
+
+ # Produce the graph files if requested.
+ def write_graph(name)
+ # We only want to graph the main host configuration.
+ return unless host_config?
+
+ return unless Puppet[:graph]
+
+ Puppet.config.use(:graphing)
+
+ file = File.join(Puppet[:graphdir], "%s.dot" % name.to_s)
+ File.open(file, "w") { |f|
+ f.puts to_dot("name" => name.to_s.capitalize)
+ }
+ end
+
+ private
+
+ def cleanup
+ unless @transient_resources.empty?
+ remove_resource(*@transient_resources)
+ @transient_resources.clear
+ end
+ end
end
diff --git a/lib/puppet/reports/store.rb b/lib/puppet/reports/store.rb
index 8d6e11379..d51f50372 100644
--- a/lib/puppet/reports/store.rb
+++ b/lib/puppet/reports/store.rb
@@ -13,7 +13,7 @@ Puppet::Network::Handler.report.newreport(:store, :useyaml => true) do
def mkclientdir(client, dir)
config = Puppet::Util::Config.new
config.setdefaults("reportclient-#{client}",
- "clientdir-#{client}" => { :default => dir,
+ "client-#{client}-dir" => { :default => dir,
:mode => 0750,
:desc => "Client dir for %s" % client,
:owner => Puppet[:user],
diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb
index 0d81b1e63..43889927c 100644
--- a/lib/puppet/transaction.rb
+++ b/lib/puppet/transaction.rb
@@ -7,7 +7,7 @@ require 'puppet/propertychange'
module Puppet
class Transaction
attr_accessor :component, :configuration, :ignoreschedules
- attr_accessor :relgraph, :sorted_resources, :configurator
+ attr_accessor :sorted_resources, :configurator
# The report, once generated.
attr_reader :report
@@ -32,7 +32,7 @@ class Transaction
# dependencies, then don't delete it unless it's implicit or the
# dependency is itself being deleted.
if resource.purging? and resource.deleting?
- if deps = @relgraph.dependents(resource) and ! deps.empty? and deps.detect { |d| ! d.deleting? }
+ if deps = relationship_graph.dependents(resource) and ! deps.empty? and deps.detect { |d| ! d.deleting? }
resource.warning "%s still depend%s on me -- not purging" %
[deps.collect { |r| r.ref }.join(","), deps.length > 1 ? "":"s"]
return false
@@ -144,12 +144,7 @@ class Transaction
# contained resources might never get cleaned up.
def cleanup
if defined? @generated
- @generated.each do |resource|
- resource.remove
- end
- end
- if defined? @relgraph
- @relgraph.clear
+ relationship_graph.remove_resource(*@generated)
end
end
@@ -164,10 +159,11 @@ class Transaction
else
edge = [resource, gen_child]
end
- unless @relgraph.edge?(edge[1], edge[0])
- @relgraph.add_edge!(*edge)
+ relationship_graph.add_resource(gen_child) unless relationship_graph.resource(gen_child.ref)
+
+ unless relationship_graph.edge?(edge[1], edge[0])
+ relationship_graph.add_edge!(*edge)
else
- @relgraph.add_vertex!(gen_child)
resource.debug "Skipping automatic relationship to %s" % gen_child
end
end
@@ -198,7 +194,8 @@ class Transaction
children.each do |child|
child.finish
# Make sure that the vertex is in the relationship graph.
- @relgraph.add_vertex!(child)
+ relationship_graph.add_resource(child) unless relationship_graph.resource(child.ref)
+ child.configuration = relationship_graph
end
@generated += children
return children
@@ -271,7 +268,7 @@ class Transaction
# Collect the targets of any subscriptions to those events. We pass
# the parent resource in so it will override the source in the events,
# since eval_generated children can't have direct relationships.
- @relgraph.matching_edges(events, resource).each do |edge|
+ relationship_graph.matching_edges(events, resource).each do |edge|
edge = edge.dup
label = edge.label
label[:event] = events.collect { |e| e.event }
@@ -289,8 +286,6 @@ class Transaction
def evaluate
@count = 0
- graph(@configuration, :resources)
-
# Start logging.
Puppet::Util::Log.newdestination(@report)
@@ -320,6 +315,7 @@ class Transaction
Puppet.debug "Finishing transaction %s with %s changes" %
[self.object_id, @count]
+ @events = allevents
allevents
end
@@ -339,7 +335,7 @@ class Transaction
# enough to check the immediate dependencies, which is why we use
# a tree from the reversed graph.
skip = false
- deps = @relgraph.dependencies(resource)
+ deps = relationship_graph.dependencies(resource)
deps.each do |dep|
if fails = failed?(dep)
resource.notice "Dependency %s[%s] has %s failures" %
@@ -375,7 +371,8 @@ class Transaction
end
made.uniq!
made.each do |res|
- @configuration.add_vertex!(res)
+ @configuration.add_resource(res)
+ res.configuration = configuration
newlist << res
@generated << res
res.finish
@@ -416,21 +413,6 @@ class Transaction
return @report
end
- # Produce the graph files if requested.
- def graph(gr, name)
- # We only want to graph the main host configuration.
- return unless @configuration.host_config?
-
- return unless Puppet[:graph]
-
- Puppet.config.use(:graphing)
-
- file = File.join(Puppet[:graphdir], "%s.dot" % name.to_s)
- File.open(file, "w") { |f|
- f.puts gr.to_dot("name" => name.to_s.capitalize)
- }
- end
-
# Should we ignore tags?
def ignore_tags?
! @configuration.host_config?
@@ -514,48 +496,13 @@ class Transaction
# Now add any dynamically generated resources
generate()
-
- # Create a relationship graph from our resource graph
- @relgraph = relationship_graph
# This will throw an error if there are cycles in the graph.
- @sorted_resources = @relgraph.topsort
+ @sorted_resources = relationship_graph.topsort
end
-
- # Create a graph of all of the relationships in our resource graph.
- def relationship_graph
- graph = Puppet::PGraph.new
-
- # First create the dependency graph
- @configuration.vertices.each do |vertex|
- graph.add_vertex!(vertex)
- vertex.builddepends.each do |edge|
- graph.add_edge!(edge)
- end
- end
-
- # Lastly, add in any autorequires
- graph.vertices.each do |vertex|
- vertex.autorequire.each do |edge|
- unless graph.edge?(edge)
- unless graph.edge?(edge.target, edge.source)
- vertex.debug "Autorequiring %s" % [edge.source]
- graph.add_edge!(edge)
- else
- vertex.debug "Skipping automatic relationship with %s" % (edge.source == vertex ? edge.target : edge.source)
- end
- end
- end
- end
-
- graph(graph, :relationships)
-
- # Then splice in the container information
- graph.splice!(@configuration, Puppet::Type::Component)
- graph(graph, :expanded_relationships)
-
- return graph
+ def relationship_graph
+ configuration.relationship_graph
end
# Send off the transaction report.
@@ -621,7 +568,7 @@ class Transaction
end
# FIXME This won't work right now.
- @relgraph.matching_edges(events).each do |edge|
+ relationship_graph.matching_edges(events).each do |edge|
@targets[edge.target] << edge
end
diff --git a/lib/puppet/transportable.rb b/lib/puppet/transportable.rb
index e4cde6e37..ecd179ed7 100644
--- a/lib/puppet/transportable.rb
+++ b/lib/puppet/transportable.rb
@@ -174,12 +174,7 @@ module Puppet
end
end
- str = nil
- if self.top
- str = "%s"
- else
- str = "#{@keyword} #{@type} {\n%s\n}"
- end
+ str = "#{@keyword} #{@name} {\n%s\n}"
str % @children.collect { |child|
child.to_manifest
}.collect { |str|
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index 03f571d4a..1db435224 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -312,6 +312,19 @@ class Type
return self[:name]
end
+ # Look up our parent in the configuration, if we have one.
+ def parent
+ return nil unless configuration
+
+ # We should never have more than one parent, so let's just ignore
+ # it if we happen to.
+ if parents = configuration.adjacent(self, :direction => :in)
+ return parents.shift
+ else
+ return nil
+ end
+ end
+
# Return the "type[name]" style reference.
def ref
"%s[%s]" % [self.class.name.to_s.capitalize, self.title]
diff --git a/lib/puppet/type/component.rb b/lib/puppet/type/component.rb
index 1615abad8..1eadeb060 100644
--- a/lib/puppet/type/component.rb
+++ b/lib/puppet/type/component.rb
@@ -163,8 +163,8 @@ Puppet::Type.newtype(:component) do
else
myname = self.title
end
- if self.parent
- return [@parent.pathbuilder, myname]
+ if p = self.parent
+ return [p.pathbuilder, myname]
else
return [myname]
end
@@ -215,24 +215,6 @@ Puppet::Type.newtype(:component) do
end
}
end
-
- # Convert to a graph object with all of the container info.
- def to_graph
- graph = Puppet::PGraph.new
-
- delver = proc do |obj|
- obj.each do |child|
- graph.add_edge!(obj, child)
- if child.is_a?(self.class)
- delver.call(child)
- end
- end
- end
-
- delver.call(self)
-
- return graph
- end
def to_s
if self.title =~ /\[/
@@ -242,5 +224,3 @@ Puppet::Type.newtype(:component) do
end
end
end
-
-# $Id$
diff --git a/lib/puppet/type/pfile.rb b/lib/puppet/type/pfile.rb
index 99b5a7435..da345e5d6 100644
--- a/lib/puppet/type/pfile.rb
+++ b/lib/puppet/type/pfile.rb
@@ -574,6 +574,9 @@ module Puppet
# Create a new file or directory object as a child to the current
# object.
def newchild(path, local, hash = {})
+ unless configuration
+ raise Puppet::DevError, "File recursion cannot happen without a configuration"
+ end
# make local copy of arguments
args = symbolize_options(@arghash)
@@ -608,13 +611,12 @@ module Puppet
}
child = nil
- klass = self.class
# The child might already exist because 'localrecurse' runs
# before 'sourcerecurse'. I could push the override stuff into
# a separate method or something, but the work is the same other
# than this last bit, so it doesn't really make sense.
- if child = klass[path]
+ if child = configuration.resource(:file, path)
unless child.parent.object_id == self.object_id
self.debug "Not managing more explicit file %s" %
path
@@ -640,12 +642,7 @@ module Puppet
#notice "Creating new file with args %s" % args.inspect
args[:parent] = self
begin
- child = klass.implicitcreate(args)
-
- # implicit creation can return nil
- if child.nil?
- return nil
- end
+ return nil unless child = configuration.create_implicit_resource(:file, args)
rescue Puppet::Error => detail
self.notice(
"Cannot manage: %s" %
@@ -661,6 +658,7 @@ module Puppet
self.debug args.inspect
child = nil
end
+ configuration.relationship_graph.add_edge! self, child
end
return child
end
@@ -695,9 +693,7 @@ module Puppet
# files.
def recurse
# are we at the end of the recursion?
- unless self.recurse?
- return
- end
+ return unless self.recurse?
recurse = self[:recurse]
# we might have a string, rather than a number
diff --git a/lib/puppet/util/config.rb b/lib/puppet/util/config.rb
index 5875f141b..3988b3fe0 100644
--- a/lib/puppet/util/config.rb
+++ b/lib/puppet/util/config.rb
@@ -555,9 +555,9 @@ class Puppet::Util::Config
end
# Convert our list of objects into a component that can be applied.
- def to_component
+ def to_configuration
transport = self.to_transportable
- return transport.to_type
+ return transport.to_configuration
end
# Convert our list of objects into a configuration file.
@@ -615,10 +615,7 @@ Generated on #{Time.now}.
end
sections.each do |section|
obj = section_to_transportable(section, done)
- #puts obj.to_manifest
- #puts "%s: %s" % [section, obj.inspect]
topbucket.push obj
- #topbucket.push section_to_transportable(section, done)
end
topbucket
@@ -1109,6 +1106,11 @@ Generated on #{Time.now}.
# Set the type appropriately. Yep, a hack. This supports either naming
# the variable 'dir', or adding a slash at the end.
def munge(value)
+ # If it's not a fully qualified path...
+ if value.is_a?(String) and value !~ /^\$/ and value !~ /^\//
+ # Make it one
+ value = File.join(Dir.getwd, value)
+ end
if value.to_s =~ /\/$/
@type = :directory
return value.sub(/\/$/, '')
@@ -1131,9 +1133,6 @@ Generated on #{Time.now}.
end
# Convert the object to a TransObject instance.
- # FIXME There's no dependency system in place right now; if you use
- # a section that requires another section, there's nothing done to
- # correct that for you, at the moment.
def to_transportable
type = self.type
return nil unless type
@@ -1142,9 +1141,6 @@ Generated on #{Time.now}.
objects = []
path = self.value
- unless path =~ /^#{File::SEPARATOR}/
- path = File.join(Dir.getwd, path)
- end
# Skip plain files that don't exist, since we won't be managing them anyway.
return nil unless self.name.to_s =~ /dir$/ or File.exist?(path)
diff --git a/lib/puppet/util/graph.rb b/lib/puppet/util/graph.rb
deleted file mode 100644
index e51b8e25a..000000000
--- a/lib/puppet/util/graph.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-# Created by Luke Kanies on 2006-11-16.
-# Copyright (c) 2006. All rights reserved.
-
-require 'puppet'
-require 'puppet/pgraph'
-
-# A module that handles the small amount of graph stuff in Puppet.
-module Puppet::Util::Graph
- # Make a graph where each of our children gets converted to
- # the receiving end of an edge. Call the same thing on all
- # of our children, optionally using a block
- def to_graph(graph = nil, &block)
- # Allow our calling function to send in a graph, so that we
- # can call this recursively with one graph.
- graph ||= Puppet::PGraph.new
-
- self.each do |child|
- unless block_given? and ! yield(child)
- graph.add_edge!(self, child)
-
- if graph.cyclic?
- raise Puppet::Error, "%s created a cyclic graph" % self
- end
-
- if child.respond_to?(:to_graph)
- child.to_graph(graph, &block)
- end
- end
- end
-
- if graph.cyclic?
- raise Puppet::Error, "%s created a cyclic graph" % self
- end
-
- graph
- end
-end
-
-# $Id$