Fixing #606 -- now only components mention @children.

git-svn-id: https://reductivelabs.com/svn/puppet/trunk@2499 980ebf18-57e1-0310-9a29-db15c13687c0
This commit is contained in:
luke 2007-05-09 21:30:44 +00:00
Родитель 13c7f2f155
Коммит 3e7d44e628
6 изменённых файлов: 202 добавлений и 206 удалений

Просмотреть файл

@ -524,17 +524,10 @@ class Puppet::Type
# when an error has been encountered
def delete(attr)
attr = symbolize(attr)
case attr
when Puppet::Type
if @children.include?(attr)
@children.delete(attr)
end
if @parameters.has_key?(attr)
@parameters.delete(attr)
else
if @parameters.has_key?(attr)
@parameters.delete(attr)
else
raise Puppet::DevError.new("Undefined attribute '#{attr}' in #{self}")
end
raise Puppet::DevError.new("Undefined attribute '#{attr}' in #{self}")
end
end

Просмотреть файл

@ -1,5 +1,4 @@
class Puppet::Type
attr_accessor :children
# this is a retarded hack method to get around the difference between
# component children and file children
@ -31,48 +30,14 @@ class Puppet::Type
elsif defined? @parent and @parent.parentof?(child)
debug "My parent is parent of child"
return true
elsif @children.include?(child)
debug "child is already in children array"
return true
else
return false
end
end
def push(*childs)
unless defined? @children
@children = []
end
childs.each { |child|
# Make sure we don't have any loops here.
if parentof?(child)
devfail "Already the parent of %s[%s]" % [child.class.name, child.title]
end
unless child.is_a?(Puppet::Element)
self.debug "Got object of type %s" % child.class
self.devfail(
"Containers can only contain Puppet::Elements, not %s" %
child.class
)
end
@children.push(child)
child.parent = self
}
end
# Remove an object. The argument determines whether the object's
# subscriptions get eliminated, too.
def remove(rmdeps = true)
# Our children remove themselves from our @children array (else the object
# we called this on at the top would not be removed), so we duplicate the
# array and iterate over that. If we don't do this, only half of the
# objects get removed.
@children.dup.each { |child|
child.remove(rmdeps)
}
@children.clear
# This is hackish (mmm, cut and paste), but it works for now, and it's
# better than warnings.
@parameters.each do |name, obj|

Просмотреть файл

@ -106,40 +106,6 @@ class Type < Puppet::Element
define_method(:validate, &block)
#@validate = block
end
# iterate across all children, and then iterate across properties
# we do children first so we're sure that all dependent objects
# are checked first
# we ignore parameters here, because they only modify how work gets
# done, they don't ever actually result in work specifically
def each
# we want to return the properties in the order that each type
# specifies it, because it may (as in the case of File#create)
# be important
if self.class.depthfirst?
@children.each { |child|
yield child
}
end
self.eachproperty { |property|
yield property
}
unless self.class.depthfirst?
@children.each { |child|
yield child
}
end
end
# Recurse deeply through the tree, but only yield types, not properties.
def delve(&block)
self.each do |obj|
if obj.is_a? Puppet::Type
obj.delve(&block)
end
end
block.call(self)
end
# create a log at specified level
def log(msg)
@ -157,7 +123,6 @@ class Type < Puppet::Element
public
def initvars
@children = []
@evalcount = 0
@tags = []

Просмотреть файл

@ -7,153 +7,227 @@ require 'puppet/type'
require 'puppet/transaction'
require 'puppet/pgraph'
module Puppet
newtype(:component) do
include Enumerable
Puppet::Type.newtype(:component) do
include Enumerable
attr_accessor :children
newparam(:name) do
desc "The name of the component. Generally optional."
isnamevar
newparam(:name) do
desc "The name of the component. Generally optional."
isnamevar
end
newparam(:type) do
desc "The type that this component maps to. Generally some kind of
class from the language."
defaultto "component"
end
# Remove a child from the component.
def delete(child)
if @children.include?(child)
@children.delete(child)
return true
else
return super
end
end
newparam(:type) do
desc "The type that this component maps to. Generally some kind of
class from the language."
defaultto "component"
# Recurse deeply through the tree, but only yield types, not properties.
def delve(&block)
self.each do |obj|
if obj.is_a?(self.class)
obj.delve(&block)
end
end
block.call(self)
end
# Remove a child from the component.
def delete(child)
if @children.include?(child)
@children.delete(child)
return true
# Return each child in turn.
def each
@children.each { |child| yield child }
end
# flatten all children, sort them, and evaluate them in order
# this is only called on one component over the whole system
# this also won't work with scheduling, but eh
def evaluate
self.finalize unless self.finalized?
transaction = Puppet::Transaction.new(self)
transaction.component = self
return transaction
end
# Do all of the polishing off, mostly doing autorequires and making
# dependencies. This will get run once on the top-level component,
# and it will do everything necessary.
def finalize
started = {}
finished = {}
# First do all of the finish work, which mostly involves
self.delve do |object|
# Make sure we don't get into loops
if started.has_key?(object)
debug "Already finished %s" % object.title
next
else
return false
started[object] = true
end
unless finished.has_key?(object)
object.finish
finished[object] = true
end
end
# Return each child in turn.
def each
@children.each { |child| yield child }
@finalized = true
end
def finalized?
if defined? @finalized
return @finalized
else
return false
end
end
# flatten all children, sort them, and evaluate them in order
# this is only called on one component over the whole system
# this also won't work with scheduling, but eh
def evaluate
self.finalize unless self.finalized?
transaction = Puppet::Transaction.new(self)
transaction.component = self
return transaction
# Initialize a new component
def initialize(args)
@children = []
super(args)
end
def initvars
super
@children = []
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
# Do all of the polishing off, mostly doing autorequires and making
# dependencies. This will get run once on the top-level component,
# and it will do everything necessary.
def finalize
started = {}
finished = {}
# First do all of the finish work, which mostly involves
self.delve do |object|
# Make sure we don't get into loops
if started.has_key?(object)
debug "Already finished %s" % object.title
next
else
started[object] = true
end
unless finished.has_key?(object)
object.finish
finished[object] = true
end
end
@finalized = true
# Add a hook for testing for recursion.
def parentof?(child)
if super(child)
return true
elsif @children.include?(child)
debug "child is already in children array"
return true
else
return false
end
end
def finalized?
if defined? @finalized
return @finalized
else
return false
end
end
# Initialize a new component
def initialize(args)
def push(*childs)
unless defined? @children
@children = []
super(args)
end
childs.each { |child|
# Make sure we don't have any loops here.
if parentof?(child)
devfail "Already the parent of %s[%s]" % [child.class.name, child.title]
end
unless child.is_a?(Puppet::Element)
self.debug "Got object of type %s" % child.class
self.devfail(
"Containers can only contain Puppet::Elements, not %s" %
child.class
)
end
@children.push(child)
child.parent = self
}
end
# Component paths are special because they function as containers.
def pathbuilder
tmp = []
if defined? @parent and @parent
tmp += [@parent.pathbuilder, self.title]
else
# The top-level name is always main[top], so we don't bother with
# that.
if self.title == "main[top]"
tmp << "" # This empty field results in "//" in the path
else
tmp << self.title
end
end
# Component paths are special because they function as containers.
def pathbuilder
tmp = []
if defined? @parent and @parent
tmp += [@parent.pathbuilder, self.title]
else
# The top-level name is always main[top], so we don't bother with
# that.
if self.title == "main[top]"
tmp << "" # This empty field results in "//" in the path
else
tmp << self.title
tmp
end
# Remove an object. The argument determines whether the object's
# subscriptions get eliminated, too.
def remove(rmdeps = true)
# Our children remove themselves from our @children array (else the object
# we called this on at the top would not be removed), so we duplicate the
# array and iterate over that. If we don't do this, only half of the
# objects get removed.
@children.dup.each { |child|
child.remove(rmdeps)
}
@children.clear
# Get rid of params and provider, too.
super
@parent = nil
end
# We have a different way of setting the title
def title
unless defined? @title
if self[:type] == self[:name] # this is the case for classes
@title = self[:type]
elsif self[:name] =~ /\[.+\]/ # most components already have ref info in the name
@title = self[:name]
else # else, set it up
@title = "%s[%s]" % [self[:type].capitalize, self[:name]]
end
end
return @title
end
def refresh
@children.collect { |child|
if child.respond_to?(:refresh)
child.refresh
child.log "triggering %s" % :refresh
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
tmp
end
# We have a different way of setting the title
def title
unless defined? @title
if self[:type] == self[:name] # this is the case for classes
@title = self[:type]
elsif self[:name] =~ /\[.+\]/ # most components already have ref info in the name
@title = self[:name]
else # else, set it up
@title = "%s[%s]" % [self[:type].capitalize, self[:name]]
end
end
return @title
end
def refresh
@children.collect { |child|
if child.respond_to?(:refresh)
child.refresh
child.log "triggering %s" % :refresh
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|
if child.is_a?(Puppet::Type)
graph.add_edge!(obj, child)
delver.call(child)
end
end
end
delver.call(self)
return graph
end
delver.call(self)
return graph
end
def to_s
if self.title =~ /\[/
return self.title
else
return "component(%s)" % self.title
end
def to_s
if self.title =~ /\[/
return self.title
else
return "component(%s)" % self.title
end
end
end
end
# $Id$

Просмотреть файл

@ -1136,8 +1136,7 @@ module Puppet
# There are some cases where all of the work does not get done on
# file creation/modification, so we have to do some extra checking.
def property_fix
self.each do |thing|
next unless thing.is_a? Puppet::Property
properties.each do |thing|
next unless [:mode, :owner, :group].include?(thing.name)
# Make sure we get a new stat objct

Просмотреть файл

@ -285,7 +285,7 @@ class TestType < Test::Unit::TestCase
def test_object_recursion
comp = Puppet.type(:component).create(:name => "top")
file = Puppet.type(:file).create(:path => tempfile, :ensure => :file)
file = Puppet.type(:component).create(:name => "middle")
assert_raise(Puppet::DevError) do
comp.push(comp)