Merge remote-tracking branch 'daniel-pittman/refactor/2.7.x/4862-remove-the-event-loop-library' into 2.7.x
* daniel-pittman/refactor/2.7.x/4862-remove-the-event-loop-library: (#4862) Finally remove the event-loop library. (#4862) define_method is not a public method in Ruby. (#4862) `returning` is not a standard Ruby method. (#4862) Stop using EventLoop in the Puppet daemon.
This commit is contained in:
Коммит
75476e1ae2
|
@ -1,5 +1,4 @@
|
||||||
require 'sync'
|
require 'sync'
|
||||||
require 'puppet/external/event-loop'
|
|
||||||
require 'puppet/application'
|
require 'puppet/application'
|
||||||
|
|
||||||
# A general class for triggering a run of another
|
# A general class for triggering a run of another
|
||||||
|
@ -75,18 +74,6 @@ class Puppet::Agent
|
||||||
@splayed = true
|
@splayed = true
|
||||||
end
|
end
|
||||||
|
|
||||||
# Start listening for events. We're pretty much just listening for
|
|
||||||
# timer events here.
|
|
||||||
def start
|
|
||||||
# Create our timer. Puppet will handle observing it and such.
|
|
||||||
timer = EventLoop::Timer.new(:interval => Puppet[:runinterval], :tolerance => 1, :start? => true) do
|
|
||||||
run
|
|
||||||
end
|
|
||||||
|
|
||||||
# Run once before we start following the timer
|
|
||||||
timer.sound_alarm
|
|
||||||
end
|
|
||||||
|
|
||||||
def sync
|
def sync
|
||||||
@sync ||= Sync.new
|
@sync ||= Sync.new
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
require 'puppet'
|
require 'puppet'
|
||||||
require 'puppet/util/pidlock'
|
require 'puppet/util/pidlock'
|
||||||
require 'puppet/external/event-loop'
|
|
||||||
require 'puppet/application'
|
require 'puppet/application'
|
||||||
|
|
||||||
# A module that handles operations common to all daemons. This is included
|
# A module that handles operations common to all daemons. This is included
|
||||||
|
@ -120,10 +119,77 @@ class Puppet::Daemon
|
||||||
create_pidfile
|
create_pidfile
|
||||||
|
|
||||||
raise Puppet::DevError, "Daemons must have an agent, server, or both" unless agent or server
|
raise Puppet::DevError, "Daemons must have an agent, server, or both" unless agent or server
|
||||||
server.start if server
|
|
||||||
agent.start if agent
|
|
||||||
|
|
||||||
EventLoop.current.run
|
# Start the listening server, if required.
|
||||||
|
server.start if server
|
||||||
|
|
||||||
|
# Finally, loop forever running events - or, at least, until we exit.
|
||||||
|
run_event_loop
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_event_loop
|
||||||
|
# Now, we loop waiting for either the configuration file to change, or the
|
||||||
|
# next agent run to be due. Fun times.
|
||||||
|
#
|
||||||
|
# We want to trigger the reparse if 15 seconds passed since the previous
|
||||||
|
# wakeup, and the agent run if Puppet[:runinterval] seconds have passed
|
||||||
|
# since the previous wakeup.
|
||||||
|
#
|
||||||
|
# We always want to run the agent on startup, so it was always before now.
|
||||||
|
# Because 0 means "continuously run", `to_i` does the right thing when the
|
||||||
|
# input is strange or badly formed by returning 0. Integer will raise,
|
||||||
|
# which we don't want, and we want to protect against -1 or below.
|
||||||
|
next_agent_run = 0
|
||||||
|
agent_run_interval = [Puppet[:runinterval].to_i, 0].max
|
||||||
|
|
||||||
|
# We may not want to reparse; that can be disable. Fun times.
|
||||||
|
next_reparse = 0
|
||||||
|
reparse_interval = Puppet[:filetimeout].to_i
|
||||||
|
|
||||||
|
loop do
|
||||||
|
now = Time.now.to_i
|
||||||
|
|
||||||
|
# Handle reparsing of configuration files, if desired and required.
|
||||||
|
# `reparse` will just check if the action is required, and would be
|
||||||
|
# better named `reparse_if_changed` instead.
|
||||||
|
if reparse_interval > 0 and now >= next_reparse
|
||||||
|
Puppet.settings.reparse
|
||||||
|
|
||||||
|
# The time to the next reparse might have changed, so recalculate
|
||||||
|
# now. That way we react dynamically to reconfiguration.
|
||||||
|
reparse_interval = Puppet[:filetimeout].to_i
|
||||||
|
next_reparse = now + reparse_interval
|
||||||
|
|
||||||
|
# We should also recalculate the agent run interval, and adjust the
|
||||||
|
# next time it is scheduled to run, just in case. In the event that
|
||||||
|
# we made no change the result will be a zero second adjustment.
|
||||||
|
new_run_interval = [Puppet[:runinterval].to_i, 0].max
|
||||||
|
next_agent_run += agent_run_interval - new_run_interval
|
||||||
|
agent_run_interval = new_run_interval
|
||||||
|
end
|
||||||
|
|
||||||
|
# Handle triggering another agent run. This will block the next check
|
||||||
|
# for configuration reparsing, which is a desired and deliberate
|
||||||
|
# behaviour. You should not change that. --daniel 2012-02-21
|
||||||
|
if agent and now >= next_agent_run
|
||||||
|
agent.run
|
||||||
|
next_agent_run = now + agent_run_interval
|
||||||
|
end
|
||||||
|
|
||||||
|
# Finally, an interruptable able sleep until the next scheduled event.
|
||||||
|
# We also set a default wakeup of "one hour from now", which will
|
||||||
|
# recheck everything at a minimum every hour. Just in case something in
|
||||||
|
# the math messes up or something; it should be inexpensive enough to
|
||||||
|
# wake once an hour, then go back to sleep after doing nothing, if
|
||||||
|
# someone only wants listen mode.
|
||||||
|
next_event = now + 60 * 60
|
||||||
|
next_event > next_reparse and next_event = next_reparse
|
||||||
|
next_event > next_agent_run and next_event = next_agent_run
|
||||||
|
|
||||||
|
how_long = next_event - now
|
||||||
|
|
||||||
|
how_long > 0 and select([], [], [], how_long)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
require "puppet/external/event-loop/event-loop"
|
|
|
@ -1,367 +0,0 @@
|
||||||
## better-definers.rb --- better attribute and method definers
|
|
||||||
# Copyright (C) 2005 Daniel Brockman
|
|
||||||
|
|
||||||
# This program is free software; you can redistribute it
|
|
||||||
# and/or modify it under the terms of the GNU General Public
|
|
||||||
# License as published by the Free Software Foundation;
|
|
||||||
# either version 2 of the License, or (at your option) any
|
|
||||||
# later version.
|
|
||||||
|
|
||||||
# This file is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
||||||
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
# See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
# You should have received a copy of the GNU General Public
|
|
||||||
# License along with this program; if not, write to the Free
|
|
||||||
# Software Foundation, 51 Franklin Street, Fifth Floor,
|
|
||||||
# Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
class Symbol
|
|
||||||
def predicate?
|
|
||||||
to_s.include? "?" end
|
|
||||||
def imperative?
|
|
||||||
to_s.include? "!" end
|
|
||||||
def writer?
|
|
||||||
to_s.include? "=" end
|
|
||||||
|
|
||||||
def punctuated?
|
|
||||||
predicate? or imperative? or writer? end
|
|
||||||
def without_punctuation
|
|
||||||
to_s.delete("?!=").to_sym end
|
|
||||||
|
|
||||||
def predicate
|
|
||||||
without_punctuation.to_s + "?" end
|
|
||||||
def imperative
|
|
||||||
without_punctuation.to_s + "!" end
|
|
||||||
def writer
|
|
||||||
without_punctuation.to_s + "=" end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Hash
|
|
||||||
def collect! (&block)
|
|
||||||
replace Hash[*collect(&block).flatten]
|
|
||||||
end
|
|
||||||
|
|
||||||
def flatten
|
|
||||||
to_a.flatten
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
module Kernel
|
|
||||||
def returning (value)
|
|
||||||
yield value ; value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Module
|
|
||||||
def define_hard_aliases (name_pairs)
|
|
||||||
for new_aliases, existing_name in name_pairs do
|
|
||||||
new_aliases.kind_of? Array or new_aliases = [new_aliases]
|
|
||||||
for new_alias in new_aliases do
|
|
||||||
alias_method(new_alias, existing_name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def define_soft_aliases (name_pairs)
|
|
||||||
for new_aliases, existing_name in name_pairs do
|
|
||||||
new_aliases.kind_of? Array or new_aliases = [new_aliases]
|
|
||||||
for new_alias in new_aliases do
|
|
||||||
class_eval %{def #{new_alias}(*args, &block)
|
|
||||||
#{existing_name}(*args, &block) end}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
define_soft_aliases \
|
|
||||||
:define_hard_alias => :define_hard_aliases,
|
|
||||||
:define_soft_alias => :define_soft_aliases
|
|
||||||
|
|
||||||
# This method lets you define predicates like :foo?,
|
|
||||||
# which will be defined to return the value of @foo.
|
|
||||||
def define_readers (*names)
|
|
||||||
for name in names.map { |x| x.to_sym } do
|
|
||||||
if name.punctuated?
|
|
||||||
# There's no way to define an efficient reader whose
|
|
||||||
# name is different from the instance variable.
|
|
||||||
class_eval %{def #{name} ; @#{name.without_punctuation} end}
|
|
||||||
else
|
|
||||||
# Use `attr_reader' to define an efficient method.
|
|
||||||
attr_reader(name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def writer_defined? (name)
|
|
||||||
method_defined?(name.to_sym.writer)
|
|
||||||
end
|
|
||||||
|
|
||||||
# If you pass a predicate symbol :foo? to this method, it'll first
|
|
||||||
# define a regular writer method :foo, without a question mark.
|
|
||||||
# Then it'll define an imperative writer method :foo! as a shorthand
|
|
||||||
# for setting the property to true.
|
|
||||||
def define_writers (*names, &body)
|
|
||||||
for name in names.map { |x| x.to_sym } do
|
|
||||||
if block_given?
|
|
||||||
define_method(name.writer, &body)
|
|
||||||
else
|
|
||||||
attr_writer(name.without_punctuation)
|
|
||||||
end
|
|
||||||
if name.predicate?
|
|
||||||
class_eval %{def #{name.imperative}
|
|
||||||
self.#{name.writer} true end}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
define_soft_aliases \
|
|
||||||
:define_reader => :define_readers,
|
|
||||||
:define_writer => :define_writers
|
|
||||||
|
|
||||||
# We don't need a singular alias for `define_accessors',
|
|
||||||
# because it always defines at least two methods.
|
|
||||||
|
|
||||||
def define_accessors (*names)
|
|
||||||
define_readers(*names)
|
|
||||||
define_writers(*names)
|
|
||||||
end
|
|
||||||
|
|
||||||
def define_opposite_readers (name_pairs)
|
|
||||||
name_pairs.collect! { |k, v| [k.to_sym, v.to_sym] }
|
|
||||||
for opposite_name, name in name_pairs do
|
|
||||||
define_reader(name) unless method_defined?(name)
|
|
||||||
class_eval %{def #{opposite_name} ; not #{name} end}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def define_opposite_writers (name_pairs)
|
|
||||||
name_pairs.collect! { |k, v| [k.to_sym, v.to_sym] }
|
|
||||||
for opposite_name, name in name_pairs do
|
|
||||||
define_writer(name) unless writer_defined?(name)
|
|
||||||
class_eval %{def #{opposite_name.writer} x
|
|
||||||
self.#{name.writer} !x end}
|
|
||||||
class_eval %{def #{opposite_name.imperative}
|
|
||||||
self.#{name.writer} false end}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
define_soft_aliases \
|
|
||||||
:define_opposite_reader => :define_opposite_readers,
|
|
||||||
:define_opposite_writer => :define_opposite_writers
|
|
||||||
|
|
||||||
def define_opposite_accessors (name_pairs)
|
|
||||||
define_opposite_readers name_pairs
|
|
||||||
define_opposite_writers name_pairs
|
|
||||||
end
|
|
||||||
|
|
||||||
def define_reader_with_opposite (name_pair, &body)
|
|
||||||
name, opposite_name = name_pair.flatten.collect { |x| x.to_sym }
|
|
||||||
define_method(name, &body)
|
|
||||||
define_opposite_reader(opposite_name => name)
|
|
||||||
end
|
|
||||||
|
|
||||||
def define_writer_with_opposite (name_pair, &body)
|
|
||||||
name, opposite_name = name_pair.flatten.collect { |x| x.to_sym }
|
|
||||||
define_writer(name, &body)
|
|
||||||
define_opposite_writer(opposite_name => name)
|
|
||||||
end
|
|
||||||
|
|
||||||
public :define_method
|
|
||||||
|
|
||||||
def define_methods (*names, &body)
|
|
||||||
names.each { |name| define_method(name, &body) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def define_private_methods (*names, &body)
|
|
||||||
define_methods(*names, &body)
|
|
||||||
names.each { |name| private name }
|
|
||||||
end
|
|
||||||
|
|
||||||
def define_protected_methods (*names, &body)
|
|
||||||
define_methods(*names, &body)
|
|
||||||
names.each { |name| protected name }
|
|
||||||
end
|
|
||||||
|
|
||||||
def define_private_method (name, &body)
|
|
||||||
define_method(name, &body)
|
|
||||||
private name
|
|
||||||
end
|
|
||||||
|
|
||||||
def define_protected_method (name, &body)
|
|
||||||
define_method(name, &body)
|
|
||||||
protected name
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class ImmutableAttributeError < StandardError
|
|
||||||
def initialize (attribute=nil, message=nil)
|
|
||||||
super message
|
|
||||||
@attribute = attribute
|
|
||||||
end
|
|
||||||
|
|
||||||
define_accessors :attribute
|
|
||||||
|
|
||||||
def to_s
|
|
||||||
if @attribute and @message
|
|
||||||
"cannot change the value of `#@attribute': #@message"
|
|
||||||
elsif @attribute
|
|
||||||
"cannot change the value of `#@attribute'"
|
|
||||||
elsif @message
|
|
||||||
"cannot change the value of attribute: #@message"
|
|
||||||
else
|
|
||||||
"cannot change the value of attribute"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Module
|
|
||||||
# Guard each of the specified attributes by replacing the writer
|
|
||||||
# method with a proxy that asks the supplied block before proceeding
|
|
||||||
# with the change.
|
|
||||||
#
|
|
||||||
# If it's okay to change the attribute, the block should return
|
|
||||||
# either nil or the symbol :mutable. If it isn't okay, the block
|
|
||||||
# should return a string saying why the attribute can't be changed.
|
|
||||||
# If you don't want to provide a reason, you can have the block
|
|
||||||
# return just the symbol :immutable.
|
|
||||||
def guard_writers(*names, &predicate)
|
|
||||||
for name in names.map { |x| x.to_sym } do
|
|
||||||
define_hard_alias("__unguarded_#{name.writer}" => name.writer)
|
|
||||||
define_method(name.writer) do |new_value|
|
|
||||||
case result = predicate.call
|
|
||||||
when :mutable, nil
|
|
||||||
__send__("__unguarded_#{name.writer}", new_value)
|
|
||||||
when :immutable
|
|
||||||
raise ImmutableAttributeError.new(name)
|
|
||||||
else
|
|
||||||
raise ImmutableAttributeError.new(name, result)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def define_guarded_writers (*names, &block)
|
|
||||||
define_writers(*names)
|
|
||||||
guard_writers(*names, &block)
|
|
||||||
end
|
|
||||||
|
|
||||||
define_soft_alias :guard_writer => :guard_writers
|
|
||||||
define_soft_alias :define_guarded_writer => :define_guarded_writers
|
|
||||||
end
|
|
||||||
|
|
||||||
if __FILE__ == $0
|
|
||||||
require "test/unit"
|
|
||||||
|
|
||||||
class DefineAccessorsTest < Test::Unit::TestCase
|
|
||||||
def setup
|
|
||||||
@X = Class.new
|
|
||||||
@Y = Class.new @X
|
|
||||||
@x = @X.new
|
|
||||||
@y = @Y.new
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_define_hard_aliases
|
|
||||||
@X.define_method(:foo) { 123 }
|
|
||||||
@X.define_method(:baz) { 321 }
|
|
||||||
@X.define_hard_aliases :bar => :foo, :quux => :baz
|
|
||||||
assert_equal @x.foo, 123
|
|
||||||
assert_equal @x.bar, 123
|
|
||||||
assert_equal @y.foo, 123
|
|
||||||
assert_equal @y.bar, 123
|
|
||||||
assert_equal @x.baz, 321
|
|
||||||
assert_equal @x.quux, 321
|
|
||||||
assert_equal @y.baz, 321
|
|
||||||
assert_equal @y.quux, 321
|
|
||||||
@Y.define_method(:foo) { 456 }
|
|
||||||
assert_equal @y.foo, 456
|
|
||||||
assert_equal @y.bar, 123
|
|
||||||
@Y.define_method(:quux) { 654 }
|
|
||||||
assert_equal @y.baz, 321
|
|
||||||
assert_equal @y.quux, 654
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_define_soft_aliases
|
|
||||||
@X.define_method(:foo) { 123 }
|
|
||||||
@X.define_method(:baz) { 321 }
|
|
||||||
@X.define_soft_aliases :bar => :foo, :quux => :baz
|
|
||||||
assert_equal @x.foo, 123
|
|
||||||
assert_equal @x.bar, 123
|
|
||||||
assert_equal @y.foo, 123
|
|
||||||
assert_equal @y.bar, 123
|
|
||||||
assert_equal @x.baz, 321
|
|
||||||
assert_equal @x.quux, 321
|
|
||||||
assert_equal @y.baz, 321
|
|
||||||
assert_equal @y.quux, 321
|
|
||||||
@Y.define_method(:foo) { 456 }
|
|
||||||
assert_equal @y.foo, @y.bar, 456
|
|
||||||
@Y.define_method(:quux) { 654 }
|
|
||||||
assert_equal @y.baz, 321
|
|
||||||
assert_equal @y.quux, 654
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_define_readers
|
|
||||||
@X.define_readers :foo, :bar
|
|
||||||
assert !@x.respond_to?(:foo=)
|
|
||||||
assert !@x.respond_to?(:bar=)
|
|
||||||
@x.instance_eval { @foo = 123 ; @bar = 456 }
|
|
||||||
assert_equal @x.foo, 123
|
|
||||||
assert_equal @x.bar, 456
|
|
||||||
@X.define_readers :baz?, :quux?
|
|
||||||
assert !@x.respond_to?(:baz=)
|
|
||||||
assert !@x.respond_to?(:quux=)
|
|
||||||
@x.instance_eval { @baz = false ; @quux = true }
|
|
||||||
assert !@x.baz?
|
|
||||||
assert @x.quux?
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_define_writers
|
|
||||||
assert !@X.writer_defined?(:foo)
|
|
||||||
assert !@X.writer_defined?(:bar)
|
|
||||||
@X.define_writers :foo, :bar
|
|
||||||
assert @X.writer_defined?(:foo)
|
|
||||||
assert @X.writer_defined?(:bar)
|
|
||||||
assert @X.writer_defined?(:foo=)
|
|
||||||
assert @X.writer_defined?(:bar=)
|
|
||||||
assert @X.writer_defined?(:foo?)
|
|
||||||
assert @X.writer_defined?(:bar?)
|
|
||||||
assert !@x.respond_to?(:foo)
|
|
||||||
assert !@x.respond_to?(:bar)
|
|
||||||
@x.foo = 123
|
|
||||||
@x.bar = 456
|
|
||||||
assert_equal @x.instance_eval { @foo }, 123
|
|
||||||
assert_equal @x.instance_eval { @bar }, 456
|
|
||||||
@X.define_writers :baz?, :quux?
|
|
||||||
assert !@x.respond_to?(:baz?)
|
|
||||||
assert !@x.respond_to?(:quux?)
|
|
||||||
@x.baz = true
|
|
||||||
@x.quux = false
|
|
||||||
assert_equal @x.instance_eval { @baz }, true
|
|
||||||
assert_equal @x.instance_eval { @quux }, false
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_define_accessors
|
|
||||||
@X.define_accessors :foo, :bar
|
|
||||||
@x.foo = 123 ; @x.bar = 456
|
|
||||||
assert_equal @x.foo, 123
|
|
||||||
assert_equal @x.bar, 456
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_define_opposite_readers
|
|
||||||
@X.define_opposite_readers :foo? => :bar?, :baz? => :quux?
|
|
||||||
assert !@x.respond_to?(:foo=)
|
|
||||||
assert !@x.respond_to?(:bar=)
|
|
||||||
assert !@x.respond_to?(:baz=)
|
|
||||||
assert !@x.respond_to?(:quux=)
|
|
||||||
@x.instance_eval { @bar = true ; @quux = false }
|
|
||||||
assert !@x.foo?
|
|
||||||
assert @x.bar?
|
|
||||||
assert @x.baz?
|
|
||||||
assert !@x.quux?
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_define_opposite_writers
|
|
||||||
@X.define_opposite_writers :foo? => :bar?, :baz => :quux
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,355 +0,0 @@
|
||||||
## event-loop.rb --- high-level IO multiplexer
|
|
||||||
# Copyright (C) 2005 Daniel Brockman
|
|
||||||
|
|
||||||
# This program is free software; you can redistribute it
|
|
||||||
# and/or modify it under the terms of the GNU General Public
|
|
||||||
# License as published by the Free Software Foundation;
|
|
||||||
# either version 2 of the License, or (at your option) any
|
|
||||||
# later version.
|
|
||||||
|
|
||||||
# This file is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
||||||
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
# See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
# You should have received a copy of the GNU General Public
|
|
||||||
# License along with this program; if not, write to the Free
|
|
||||||
# Software Foundation, 51 Franklin Street, Fifth Floor,
|
|
||||||
# Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
require "puppet/external/event-loop/better-definers"
|
|
||||||
require "puppet/external/event-loop/signal-system"
|
|
||||||
|
|
||||||
require "fcntl"
|
|
||||||
|
|
||||||
class EventLoop
|
|
||||||
include SignalEmitter
|
|
||||||
|
|
||||||
IO_STATES = [:readable, :writable, :exceptional]
|
|
||||||
|
|
||||||
class << self
|
|
||||||
def default ; @default ||= new end
|
|
||||||
def default= x ; @default = x end
|
|
||||||
|
|
||||||
def current
|
|
||||||
Thread.current["event-loop::current"] || default end
|
|
||||||
def current= x
|
|
||||||
Thread.current["event-loop::current"] = x end
|
|
||||||
|
|
||||||
def with_current (new)
|
|
||||||
if current == new
|
|
||||||
yield
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
old = self.current
|
|
||||||
self.current = new
|
|
||||||
yield
|
|
||||||
ensure
|
|
||||||
self.current = old
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def method_missing (name, *args, &block)
|
|
||||||
if current.respond_to? name
|
|
||||||
current.__send__(name, *args, &block)
|
|
||||||
else
|
|
||||||
super
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
define_signals :before_sleep, :after_sleep
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
@running = false
|
|
||||||
@awake = false
|
|
||||||
@wakeup_time = nil
|
|
||||||
@timers = []
|
|
||||||
|
|
||||||
@io_arrays = [[], [], []]
|
|
||||||
@ios = Hash.new do |h, k| raise ArgumentError,
|
|
||||||
"invalid IO event: #{k}", caller(2) end
|
|
||||||
IO_STATES.each_with_index { |x, i| @ios[x] = @io_arrays[i] }
|
|
||||||
|
|
||||||
@notify_src, @notify_snk = IO.pipe
|
|
||||||
|
|
||||||
# prevent file descriptor leaks
|
|
||||||
if @notify_src.respond_to?(:fcntl) and defined?(Fcntl) and defined?(Fcntl::F_SETFD) and defined?(Fcntl::FD_CLOEXEC)
|
|
||||||
@notify_src.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
|
||||||
@notify_snk.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
|
||||||
end
|
|
||||||
|
|
||||||
@notify_src.will_block = false
|
|
||||||
@notify_snk.will_block = false
|
|
||||||
|
|
||||||
# Each time a byte is sent through the notification pipe
|
|
||||||
# we need to read it, or IO.select will keep returning.
|
|
||||||
monitor_io(@notify_src, :readable)
|
|
||||||
@notify_src.extend(Watchable)
|
|
||||||
@notify_src.on_readable do
|
|
||||||
begin
|
|
||||||
@notify_src.sysread(256)
|
|
||||||
rescue Errno::EAGAIN
|
|
||||||
# The pipe wasn't readable after all.
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
define_opposite_accessors \
|
|
||||||
:stopped? => :running?,
|
|
||||||
:sleeping? => :awake?
|
|
||||||
|
|
||||||
def run
|
|
||||||
if block_given?
|
|
||||||
thread = Thread.new { run }
|
|
||||||
yield ; quit ; thread.join
|
|
||||||
else
|
|
||||||
running!
|
|
||||||
iterate while running?
|
|
||||||
end
|
|
||||||
ensure
|
|
||||||
quit
|
|
||||||
end
|
|
||||||
|
|
||||||
def iterate (user_timeout=nil)
|
|
||||||
t1, t2 = user_timeout, max_timeout
|
|
||||||
timeout = t1 && t2 ? [t1, t2].min : t1 || t2
|
|
||||||
select(timeout).zip(IO_STATES) do |ios, state|
|
|
||||||
ios.each { |x| x.signal(state) } if ios
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def select (timeout)
|
|
||||||
@wakeup_time = timeout ? Time.now + timeout : nil
|
|
||||||
# puts "waiting: #{timeout} seconds"
|
|
||||||
signal :before_sleep ; sleeping!
|
|
||||||
IO.select(*@io_arrays + [timeout]) || []
|
|
||||||
ensure
|
|
||||||
awake! ; signal :after_sleep
|
|
||||||
@timers.each { |x| x.sound_alarm if x.ready? }
|
|
||||||
end
|
|
||||||
|
|
||||||
public
|
|
||||||
|
|
||||||
def quit ; stopped! ; wake_up ; self end
|
|
||||||
|
|
||||||
def monitoring_io? (io, event)
|
|
||||||
@ios[event].include? io end
|
|
||||||
def monitoring_timer? (timer)
|
|
||||||
@timers.include? timer end
|
|
||||||
|
|
||||||
def monitor_io (io, *events)
|
|
||||||
for event in events do
|
|
||||||
@ios[event] << io ; wake_up unless monitoring_io?(io, event)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def monitor_timer (timer)
|
|
||||||
@timers << timer unless monitoring_timer? timer
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_timer (timer)
|
|
||||||
wake_up if timer.end_time < @wakeup_time
|
|
||||||
end
|
|
||||||
|
|
||||||
def ignore_io (io, *events)
|
|
||||||
events = IO_STATES if events.empty?
|
|
||||||
for event in events do
|
|
||||||
wake_up if @ios[event].delete(io)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def ignore_timer (timer)
|
|
||||||
# Don't need to wake up for this.
|
|
||||||
@timers.delete(timer)
|
|
||||||
end
|
|
||||||
|
|
||||||
def max_timeout
|
|
||||||
return nil if @timers.empty?
|
|
||||||
[@timers.collect { |x| x.time_left }.min, 0].max
|
|
||||||
end
|
|
||||||
|
|
||||||
def wake_up
|
|
||||||
@notify_snk.write('.') if sleeping?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Symbol
|
|
||||||
def io_state?
|
|
||||||
EventLoop::IO_STATES.include? self
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
module EventLoop::Watchable
|
|
||||||
include SignalEmitter
|
|
||||||
|
|
||||||
define_signals :readable, :writable, :exceptional
|
|
||||||
|
|
||||||
def monitor_events (*events)
|
|
||||||
EventLoop.monitor_io(self, *events) end
|
|
||||||
def ignore_events (*events)
|
|
||||||
EventLoop.ignore_io(self, *events) end
|
|
||||||
|
|
||||||
define_soft_aliases \
|
|
||||||
:monitor_event => :monitor_events,
|
|
||||||
:ignore_event => :ignore_events
|
|
||||||
|
|
||||||
def close ; super
|
|
||||||
ignore_events end
|
|
||||||
def close_read ; super
|
|
||||||
ignore_event :readable end
|
|
||||||
def close_write ; super
|
|
||||||
ignore_event :writable end
|
|
||||||
|
|
||||||
module Automatic
|
|
||||||
include EventLoop::Watchable
|
|
||||||
|
|
||||||
def add_signal_handler (name, &handler) super
|
|
||||||
monitor_event(name) if name.io_state?
|
|
||||||
end
|
|
||||||
|
|
||||||
def remove_signal_handler (name, handler) super
|
|
||||||
if @signal_handlers[name].empty?
|
|
||||||
ignore_event(name) if name.io_state?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class IO
|
|
||||||
def on_readable &block
|
|
||||||
extend EventLoop::Watchable::Automatic
|
|
||||||
on_readable(&block)
|
|
||||||
end
|
|
||||||
|
|
||||||
def on_writable &block
|
|
||||||
extend EventLoop::Watchable::Automatic
|
|
||||||
on_writable(&block)
|
|
||||||
end
|
|
||||||
|
|
||||||
def on_exceptional &block
|
|
||||||
extend EventLoop::Watchable::Automatic
|
|
||||||
on_exceptional(&block)
|
|
||||||
end
|
|
||||||
|
|
||||||
def will_block?
|
|
||||||
if respond_to?(:fcntl) and defined?(Fcntl) and defined?(Fcntl::F_GETFL) and defined?(Fcntl::O_NONBLOCK)
|
|
||||||
fcntl(Fcntl::F_GETFL, 0) & Fcntl::O_NONBLOCK == 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def will_block= (wants_blocking)
|
|
||||||
if respond_to?(:fcntl) and defined?(Fcntl) and defined?(Fcntl::F_GETFL) and defined?(Fcntl::O_NONBLOCK)
|
|
||||||
flags = fcntl(Fcntl::F_GETFL, 0)
|
|
||||||
if wants_blocking
|
|
||||||
flags &= ~Fcntl::O_NONBLOCK
|
|
||||||
else
|
|
||||||
flags |= Fcntl::O_NONBLOCK
|
|
||||||
end
|
|
||||||
fcntl(Fcntl::F_SETFL, flags)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class EventLoop::Timer
|
|
||||||
include SignalEmitter
|
|
||||||
|
|
||||||
DEFAULT_INTERVAL = 0.0
|
|
||||||
DEFAULT_TOLERANCE = 0.001
|
|
||||||
|
|
||||||
def initialize (options={}, &handler)
|
|
||||||
@running = false
|
|
||||||
@start_time = nil
|
|
||||||
|
|
||||||
options = { :interval => options } if options.kind_of? Numeric
|
|
||||||
|
|
||||||
if options[:interval]
|
|
||||||
@interval = options[:interval].to_f
|
|
||||||
else
|
|
||||||
@interval = DEFAULT_INTERVAL
|
|
||||||
end
|
|
||||||
|
|
||||||
if options[:tolerance]
|
|
||||||
@tolerance = options[:tolerance].to_f
|
|
||||||
elsif DEFAULT_TOLERANCE < @interval
|
|
||||||
@tolerance = DEFAULT_TOLERANCE
|
|
||||||
else
|
|
||||||
@tolerance = 0.0
|
|
||||||
end
|
|
||||||
|
|
||||||
@event_loop = options[:event_loop] || EventLoop.current
|
|
||||||
|
|
||||||
if block_given?
|
|
||||||
add_signal_handler(:alarm, &handler)
|
|
||||||
start unless options[:start?] == false
|
|
||||||
else
|
|
||||||
start if options[:start?]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
define_readers :interval, :tolerance
|
|
||||||
define_signal :alarm
|
|
||||||
|
|
||||||
def stopped? ; @start_time == nil end
|
|
||||||
def running? ; @start_time != nil end
|
|
||||||
|
|
||||||
def interval= (new_interval)
|
|
||||||
old_interval = @interval
|
|
||||||
@interval = new_interval
|
|
||||||
@event_loop.check_timer(self) if new_interval < old_interval
|
|
||||||
end
|
|
||||||
|
|
||||||
def end_time
|
|
||||||
@start_time + @interval end
|
|
||||||
def time_left
|
|
||||||
end_time - Time.now end
|
|
||||||
def ready?
|
|
||||||
time_left <= @tolerance end
|
|
||||||
|
|
||||||
def restart
|
|
||||||
@start_time = Time.now
|
|
||||||
end
|
|
||||||
|
|
||||||
def sound_alarm
|
|
||||||
signal :alarm
|
|
||||||
restart if running?
|
|
||||||
end
|
|
||||||
|
|
||||||
def start
|
|
||||||
@start_time = Time.now
|
|
||||||
@event_loop.monitor_timer(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
def stop
|
|
||||||
@start_time = nil
|
|
||||||
@event_loop.ignore_timer(self)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if __FILE__ == $0
|
|
||||||
require "test/unit"
|
|
||||||
|
|
||||||
class TimerTest < Test::Unit::TestCase
|
|
||||||
def setup
|
|
||||||
@timer = EventLoop::Timer.new(:interval => 0.001)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_timer
|
|
||||||
@timer.on_alarm do
|
|
||||||
puts "[#{@timer.time_left} seconds left after alarm]"
|
|
||||||
EventLoop.quit
|
|
||||||
end
|
|
||||||
8.times do
|
|
||||||
t0 = Time.now
|
|
||||||
@timer.start ; EventLoop.run
|
|
||||||
t1 = Time.now
|
|
||||||
assert(t1 - t0 > @timer.interval - @timer.tolerance)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
## event-loop.rb ends here.
|
|
|
@ -1,218 +0,0 @@
|
||||||
## signal-system.rb --- simple intra-process signal system
|
|
||||||
# Copyright (C) 2005 Daniel Brockman
|
|
||||||
|
|
||||||
# This program is free software; you can redistribute it
|
|
||||||
# and/or modify it under the terms of the GNU General Public
|
|
||||||
# License as published by the Free Software Foundation;
|
|
||||||
# either version 2 of the License, or (at your option) any
|
|
||||||
# later version.
|
|
||||||
|
|
||||||
# This file is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
||||||
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
# See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
# You should have received a copy of the GNU General Public
|
|
||||||
# License along with this program; if not, write to the Free
|
|
||||||
# Software Foundation, 51 Franklin Street, Fifth Floor,
|
|
||||||
# Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
require "puppet/external/event-loop/better-definers"
|
|
||||||
|
|
||||||
module SignalEmitterModule
|
|
||||||
def self.extended (object)
|
|
||||||
if object.kind_of? Module and not object < SignalEmitter
|
|
||||||
if object.respond_to? :fcall
|
|
||||||
# This is the way to call private methods
|
|
||||||
# in Ruby 1.9 as of November 16.
|
|
||||||
object.fcall :include, SignalEmitter
|
|
||||||
else
|
|
||||||
object.__send__ :include, SignalEmitter
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def define_signal (name, slot=:before, &body)
|
|
||||||
# Can't use `define_method' and take a block pre-1.9.
|
|
||||||
class_eval %{ def on_#{name} &block
|
|
||||||
add_signal_handler(:#{name}, &block) end }
|
|
||||||
define_signal_handler(name, :before, &lambda {|*a|})
|
|
||||||
define_signal_handler(name, :after, &lambda {|*a|})
|
|
||||||
define_signal_handler(name, slot, &body) if block_given?
|
|
||||||
end
|
|
||||||
|
|
||||||
def define_signals (*names, &body)
|
|
||||||
names.each { |x| define_signal(x, &body) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def define_signal_handler (name, slot=:before, &body)
|
|
||||||
case slot
|
|
||||||
when :before
|
|
||||||
define_protected_method "handle_#{name}", &body
|
|
||||||
when :after
|
|
||||||
define_protected_method "after_handle_#{name}", &body
|
|
||||||
else
|
|
||||||
raise ArgumentError, "invalid slot `#{slot.inspect}'; " +
|
|
||||||
"should be `:before' or `:after'", caller(1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# This is an old name for the same thing.
|
|
||||||
SignalEmitterClass = SignalEmitterModule
|
|
||||||
|
|
||||||
module SignalEmitter
|
|
||||||
def self.included (includer)
|
|
||||||
includer.extend SignalEmitterClass if not includer.kind_of? SignalEmitterClass
|
|
||||||
end
|
|
||||||
|
|
||||||
def __maybe_initialize_signal_emitter
|
|
||||||
@signal_handlers ||= Hash.new { |h, k| h[k] = Array.new }
|
|
||||||
@allow_dynamic_signals ||= false
|
|
||||||
end
|
|
||||||
|
|
||||||
define_accessors :allow_dynamic_signals?
|
|
||||||
|
|
||||||
def add_signal_handler (name, &handler)
|
|
||||||
__maybe_initialize_signal_emitter
|
|
||||||
@signal_handlers[name] << handler
|
|
||||||
handler
|
|
||||||
end
|
|
||||||
|
|
||||||
define_soft_aliases [:on, :on_signal] => :add_signal_handler
|
|
||||||
|
|
||||||
def remove_signal_handler (name, handler)
|
|
||||||
__maybe_initialize_signal_emitter
|
|
||||||
@signal_handlers[name].delete(handler)
|
|
||||||
end
|
|
||||||
|
|
||||||
def __signal__ (name, *args, &block)
|
|
||||||
__maybe_initialize_signal_emitter
|
|
||||||
respond_to? "on_#{name}" or allow_dynamic_signals? or
|
|
||||||
fail "undefined signal `#{name}' for #{self}:#{self.class}"
|
|
||||||
__send__("handle_#{name}", *args, &block) if
|
|
||||||
respond_to? "handle_#{name}"
|
|
||||||
@signal_handlers[name].each { |x| x.call(*args, &block) }
|
|
||||||
__send__("after_handle_#{name}", *args, &block) if
|
|
||||||
respond_to? "after_handle_#{name}"
|
|
||||||
end
|
|
||||||
|
|
||||||
define_soft_alias :signal => :__signal__
|
|
||||||
end
|
|
||||||
|
|
||||||
# This module is indended to be a convenience mixin to be used by
|
|
||||||
# classes whose objects need to observe foreign signals. That is,
|
|
||||||
# if you want to observe some signals coming from an object, *you*
|
|
||||||
# should mix in this module.
|
|
||||||
#
|
|
||||||
# You cannot use this module at two different places of the same
|
|
||||||
# inheritance chain to observe signals coming from the same object.
|
|
||||||
#
|
|
||||||
# XXX: This has not seen much use, and I'd like to provide a
|
|
||||||
# better solution for the problem in the future.
|
|
||||||
module SignalObserver
|
|
||||||
def __maybe_initialize_signal_observer
|
|
||||||
@observed_signals ||= Hash.new do |signals, object|
|
|
||||||
signals[object] = Hash.new do |handlers, name|
|
|
||||||
handlers[name] = Array.new
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def observe_signal (subject, name, &handler)
|
|
||||||
__maybe_initialize_signal_observer
|
|
||||||
@observed_signals[subject][name] << handler
|
|
||||||
subject.add_signal_handler(name, &handler)
|
|
||||||
end
|
|
||||||
|
|
||||||
def map_signals (source, pairs={})
|
|
||||||
pairs.each do |src_name, dst_name|
|
|
||||||
observe_signal(source, src_name) do |*args|
|
|
||||||
__signal__(dst_name, *args)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def absorb_signals (subject, *names)
|
|
||||||
names.each do |name|
|
|
||||||
observe_signal(subject, name) do |*args|
|
|
||||||
__signal__(name, *args)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
define_soft_aliases \
|
|
||||||
:map_signal => :map_signals,
|
|
||||||
:absorb_signal => :absorb_signals
|
|
||||||
|
|
||||||
def ignore_signal (subject, name)
|
|
||||||
__maybe_initialize_signal_observer
|
|
||||||
__ignore_signal_1(subject, name)
|
|
||||||
@observed_signals.delete(subject) if
|
|
||||||
@observed_signals[subject].empty?
|
|
||||||
end
|
|
||||||
|
|
||||||
def ignore_signals (subject, *names)
|
|
||||||
__maybe_initialize_signal_observer
|
|
||||||
names = @observed_signals[subject] if names.empty?
|
|
||||||
names.each { |x| __ignore_signal_1(subject, x) }
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def __ignore_signal_1(subject, name)
|
|
||||||
@observed_signals[subject][name].each do |handler|
|
|
||||||
subject.remove_signal_handler(name, handler) end
|
|
||||||
@observed_signals[subject].delete(name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if __FILE__ == $0
|
|
||||||
require "test/unit"
|
|
||||||
class SignalEmitterTest < Test::Unit::TestCase
|
|
||||||
class X
|
|
||||||
include SignalEmitter
|
|
||||||
define_signal :foo
|
|
||||||
end
|
|
||||||
|
|
||||||
def setup
|
|
||||||
@x = X.new
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_on_signal
|
|
||||||
moomin = 0
|
|
||||||
@x.on_signal(:foo) { moomin = 1 }
|
|
||||||
@x.signal :foo
|
|
||||||
assert moomin == 1
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_on_foo
|
|
||||||
moomin = 0
|
|
||||||
@x.on_foo { moomin = 1 }
|
|
||||||
@x.signal :foo
|
|
||||||
assert moomin == 1
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_multiple_on_signal
|
|
||||||
moomin = 0
|
|
||||||
@x.on_signal(:foo) { moomin += 1 }
|
|
||||||
@x.on_signal(:foo) { moomin += 2 }
|
|
||||||
@x.on_signal(:foo) { moomin += 4 }
|
|
||||||
@x.on_signal(:foo) { moomin += 8 }
|
|
||||||
@x.signal :foo
|
|
||||||
assert moomin == 15
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_multiple_on_foo
|
|
||||||
moomin = 0
|
|
||||||
@x.on_foo { moomin += 1 }
|
|
||||||
@x.on_foo { moomin += 2 }
|
|
||||||
@x.on_foo { moomin += 4 }
|
|
||||||
@x.on_foo { moomin += 8 }
|
|
||||||
@x.signal :foo
|
|
||||||
assert moomin == 15
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
## application-signals.rb ends here.
|
|
|
@ -212,7 +212,7 @@ WRAPPER
|
||||||
|
|
||||||
if @face.is_a?(Class)
|
if @face.is_a?(Class)
|
||||||
@face.class_eval do eval wrapper, nil, file, line end
|
@face.class_eval do eval wrapper, nil, file, line end
|
||||||
@face.define_method(internal_name, &block)
|
@face.send(:define_method, internal_name, &block)
|
||||||
@when_invoked = @face.instance_method(name)
|
@when_invoked = @face.instance_method(name)
|
||||||
else
|
else
|
||||||
@face.instance_eval do eval wrapper, nil, file, line end
|
@face.instance_eval do eval wrapper, nil, file, line end
|
||||||
|
|
|
@ -10,13 +10,13 @@ module Puppet::Module::Tool
|
||||||
# Read the +filename+ and eval its Ruby code to set values in the Metadata
|
# Read the +filename+ and eval its Ruby code to set values in the Metadata
|
||||||
# +metadata+ instance.
|
# +metadata+ instance.
|
||||||
def self.evaluate(metadata, filename)
|
def self.evaluate(metadata, filename)
|
||||||
returning(new(metadata)) do |builder|
|
builder = new(metadata)
|
||||||
if File.file?(filename)
|
if File.file?(filename)
|
||||||
builder.instance_eval(File.read(filename.to_s), filename.to_s, 1)
|
builder.instance_eval(File.read(filename.to_s), filename.to_s, 1)
|
||||||
else
|
else
|
||||||
Puppet.warning "No Modulefile: #{filename}"
|
Puppet.warning "No Modulefile: #{filename}"
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
return builder
|
||||||
end
|
end
|
||||||
|
|
||||||
# Instantiate with the Metadata +metadata+ instance.
|
# Instantiate with the Metadata +metadata+ instance.
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
require 'puppet'
|
require 'puppet'
|
||||||
require 'sync'
|
require 'sync'
|
||||||
require 'getoptlong'
|
require 'getoptlong'
|
||||||
require 'puppet/external/event-loop'
|
|
||||||
require 'puppet/util/loadedfile'
|
require 'puppet/util/loadedfile'
|
||||||
|
|
||||||
# The class for handling configuration files.
|
# The class for handling configuration files.
|
||||||
|
@ -296,10 +295,6 @@ class Puppet::Util::Settings
|
||||||
@sync.synchronize do
|
@sync.synchronize do
|
||||||
unsafe_parse(self[:config])
|
unsafe_parse(self[:config])
|
||||||
end
|
end
|
||||||
|
|
||||||
# Create a timer so that this file will get checked automatically
|
|
||||||
# and reparsed if necessary.
|
|
||||||
set_filetimeout_timer
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Unsafely parse the file -- this isn't thread-safe and causes plenty of problems if used directly.
|
# Unsafely parse the file -- this isn't thread-safe and causes plenty of problems if used directly.
|
||||||
|
@ -549,12 +544,6 @@ class Puppet::Util::Settings
|
||||||
call.each { |setting| setting.handle(self.value(setting.name)) }
|
call.each { |setting| setting.handle(self.value(setting.name)) }
|
||||||
end
|
end
|
||||||
|
|
||||||
# Create a timer to check whether the file should be reparsed.
|
|
||||||
def set_filetimeout_timer
|
|
||||||
return unless timeout = self[:filetimeout] and timeout = Integer(timeout) and timeout > 0
|
|
||||||
timer = EventLoop::Timer.new(:interval => timeout, :tolerance => 1, :start? => true) { self.reparse }
|
|
||||||
end
|
|
||||||
|
|
||||||
# Convert the settings we manage into a catalog full of resources that model those settings.
|
# Convert the settings we manage into a catalog full of resources that model those settings.
|
||||||
def to_catalog(*sections)
|
def to_catalog(*sections)
|
||||||
sections = nil if sections.empty?
|
sections = nil if sections.empty?
|
||||||
|
|
|
@ -270,36 +270,4 @@ describe Puppet::Agent do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "when starting" do
|
|
||||||
before do
|
|
||||||
@agent.stubs(:observe_signal)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should create a timer with the runinterval, a tolerance of 1, and :start? set to true" do
|
|
||||||
Puppet.settings.expects(:value).with(:runinterval).returns 5
|
|
||||||
timer = stub 'timer', :sound_alarm => nil
|
|
||||||
EventLoop::Timer.expects(:new).with(:interval => 5, :start? => true, :tolerance => 1).returns timer
|
|
||||||
|
|
||||||
@agent.stubs(:run)
|
|
||||||
@agent.start
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should run once immediately" do
|
|
||||||
timer = mock 'timer'
|
|
||||||
EventLoop::Timer.expects(:new).returns timer
|
|
||||||
|
|
||||||
timer.expects(:sound_alarm)
|
|
||||||
|
|
||||||
@agent.start
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should run within the block passed to the timer" do
|
|
||||||
timer = stub 'timer', :sound_alarm => nil
|
|
||||||
EventLoop::Timer.expects(:new).returns(timer).yields
|
|
||||||
@agent.expects(:run)
|
|
||||||
|
|
||||||
@agent.start
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -49,7 +49,7 @@ describe Puppet::Daemon do
|
||||||
before do
|
before do
|
||||||
@daemon.stubs(:create_pidfile)
|
@daemon.stubs(:create_pidfile)
|
||||||
@daemon.stubs(:set_signal_traps)
|
@daemon.stubs(:set_signal_traps)
|
||||||
EventLoop.current.stubs(:run)
|
@daemon.stubs(:run_event_loop)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should fail if it has neither agent nor server" do
|
it "should fail if it has neither agent nor server" do
|
||||||
|
@ -58,19 +58,10 @@ describe Puppet::Daemon do
|
||||||
|
|
||||||
it "should create its pidfile" do
|
it "should create its pidfile" do
|
||||||
@daemon.stubs(:agent).returns stub('agent', :start => nil)
|
@daemon.stubs(:agent).returns stub('agent', :start => nil)
|
||||||
|
|
||||||
@daemon.expects(:create_pidfile)
|
@daemon.expects(:create_pidfile)
|
||||||
@daemon.start
|
@daemon.start
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should start the agent if the agent is configured" do
|
|
||||||
agent = mock 'agent'
|
|
||||||
agent.expects(:start)
|
|
||||||
@daemon.stubs(:agent).returns agent
|
|
||||||
|
|
||||||
@daemon.start
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should start its server if one is configured" do
|
it "should start its server if one is configured" do
|
||||||
server = mock 'server'
|
server = mock 'server'
|
||||||
server.expects(:start)
|
server.expects(:start)
|
||||||
|
@ -78,13 +69,6 @@ describe Puppet::Daemon do
|
||||||
|
|
||||||
@daemon.start
|
@daemon.start
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should let the current EventLoop run" do
|
|
||||||
@daemon.stubs(:agent).returns stub('agent', :start => nil)
|
|
||||||
EventLoop.current.expects(:run)
|
|
||||||
|
|
||||||
@daemon.start
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "when stopping" do
|
describe "when stopping" do
|
||||||
|
|
|
@ -411,13 +411,6 @@ describe Puppet::Util::Settings do
|
||||||
@settings.parse
|
@settings.parse
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should set a timer that triggers reparsing, even if the file does not exist" do
|
|
||||||
FileTest.expects(:exist?).returns false
|
|
||||||
@settings.expects(:set_filetimeout_timer)
|
|
||||||
|
|
||||||
@settings.parse
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return values set in the configuration file" do
|
it "should return values set in the configuration file" do
|
||||||
text = "[main]
|
text = "[main]
|
||||||
one = fileval
|
one = fileval
|
||||||
|
@ -559,12 +552,6 @@ describe Puppet::Util::Settings do
|
||||||
File.expects(:expand_path).with(somefile).returns somefile
|
File.expects(:expand_path).with(somefile).returns somefile
|
||||||
@settings[:config] = somefile
|
@settings[:config] = somefile
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should not set a timer" do
|
|
||||||
EventLoop::Timer.expects(:new).never
|
|
||||||
|
|
||||||
@settings.parse
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1057,46 +1044,6 @@ describe Puppet::Util::Settings do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "when setting a timer to trigger configuration file reparsing" do
|
|
||||||
before do
|
|
||||||
@settings = Puppet::Util::Settings.new
|
|
||||||
@settings.setdefaults :foo, :filetimeout => [5, "eh"]
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should do nothing if no filetimeout setting is available" do
|
|
||||||
@settings.expects(:value).with(:filetimeout).returns nil
|
|
||||||
EventLoop::Timer.expects(:new).never
|
|
||||||
@settings.set_filetimeout_timer
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should always convert the timer interval to an integer" do
|
|
||||||
@settings.expects(:value).with(:filetimeout).returns "10"
|
|
||||||
EventLoop::Timer.expects(:new).with(:interval => 10, :start? => true, :tolerance => 1)
|
|
||||||
@settings.set_filetimeout_timer
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should do nothing if the filetimeout setting is not greater than 0" do
|
|
||||||
@settings.expects(:value).with(:filetimeout).returns -2
|
|
||||||
EventLoop::Timer.expects(:new).never
|
|
||||||
@settings.set_filetimeout_timer
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should create a timer with its interval set to the filetimeout, start? set to true, and a tolerance of 1" do
|
|
||||||
@settings.expects(:value).with(:filetimeout).returns 5
|
|
||||||
EventLoop::Timer.expects(:new).with(:interval => 5, :start? => true, :tolerance => 1)
|
|
||||||
|
|
||||||
@settings.set_filetimeout_timer
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should reparse when the timer goes off" do
|
|
||||||
EventLoop::Timer.expects(:new).with(:interval => 5, :start? => true, :tolerance => 1).yields
|
|
||||||
|
|
||||||
@settings.expects(:reparse)
|
|
||||||
|
|
||||||
@settings.set_filetimeout_timer
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "when determining if the service user is available" do
|
describe "when determining if the service user is available" do
|
||||||
it "should return false if there is no user setting" do
|
it "should return false if there is no user setting" do
|
||||||
Puppet::Util::Settings.new.should_not be_service_user_available
|
Puppet::Util::Settings.new.should_not be_service_user_available
|
||||||
|
|
|
@ -8,7 +8,6 @@ require 'puppettest'
|
||||||
# Test the different features of the main puppet module
|
# Test the different features of the main puppet module
|
||||||
class TestPuppetModule < Test::Unit::TestCase
|
class TestPuppetModule < Test::Unit::TestCase
|
||||||
include PuppetTest
|
include PuppetTest
|
||||||
include SignalObserver
|
|
||||||
|
|
||||||
def mkfakeclient
|
def mkfakeclient
|
||||||
Class.new(Puppet::Network::Client) do
|
Class.new(Puppet::Network::Client) do
|
||||||
|
|
Загрузка…
Ссылка в новой задаче