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:
Patrick Carlisle 2012-03-16 11:49:11 -07:00
Родитель 3df8eef6c1 dba27c9809
Коммит 75476e1ae2
13 изменённых файлов: 78 добавлений и 1079 удалений

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

@ -1,5 +1,4 @@
require 'sync'
require 'puppet/external/event-loop'
require 'puppet/application'
# A general class for triggering a run of another
@ -75,18 +74,6 @@ class Puppet::Agent
@splayed = true
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
@sync ||= Sync.new
end

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

@ -1,6 +1,5 @@
require 'puppet'
require 'puppet/util/pidlock'
require 'puppet/external/event-loop'
require 'puppet/application'
# A module that handles operations common to all daemons. This is included
@ -120,10 +119,77 @@ class Puppet::Daemon
create_pidfile
raise Puppet::DevError, "Daemons must have an agent, server, or both" unless agent or server
# Start the listening server, if required.
server.start if server
agent.start if agent
EventLoop.current.run
# 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

1
lib/puppet/external/event-loop.rb поставляемый
Просмотреть файл

@ -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

355
lib/puppet/external/event-loop/event-loop.rb поставляемый
Просмотреть файл

@ -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)
@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)
else
@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
# +metadata+ instance.
def self.evaluate(metadata, filename)
returning(new(metadata)) do |builder|
builder = new(metadata)
if File.file?(filename)
builder.instance_eval(File.read(filename.to_s), filename.to_s, 1)
else
Puppet.warning "No Modulefile: #{filename}"
end
end
return builder
end
# Instantiate with the Metadata +metadata+ instance.

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

@ -1,7 +1,6 @@
require 'puppet'
require 'sync'
require 'getoptlong'
require 'puppet/external/event-loop'
require 'puppet/util/loadedfile'
# The class for handling configuration files.
@ -296,10 +295,6 @@ class Puppet::Util::Settings
@sync.synchronize do
unsafe_parse(self[:config])
end
# Create a timer so that this file will get checked automatically
# and reparsed if necessary.
set_filetimeout_timer
end
# 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)) }
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.
def to_catalog(*sections)
sections = nil if sections.empty?

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

@ -270,36 +270,4 @@ describe Puppet::Agent do
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

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

@ -49,7 +49,7 @@ describe Puppet::Daemon do
before do
@daemon.stubs(:create_pidfile)
@daemon.stubs(:set_signal_traps)
EventLoop.current.stubs(:run)
@daemon.stubs(:run_event_loop)
end
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
@daemon.stubs(:agent).returns stub('agent', :start => nil)
@daemon.expects(:create_pidfile)
@daemon.start
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
server = mock 'server'
server.expects(:start)
@ -78,13 +69,6 @@ describe Puppet::Daemon do
@daemon.start
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
describe "when stopping" do

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

@ -411,13 +411,6 @@ describe Puppet::Util::Settings do
@settings.parse
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
text = "[main]
one = fileval
@ -559,12 +552,6 @@ describe Puppet::Util::Settings do
File.expects(:expand_path).with(somefile).returns somefile
@settings[:config] = somefile
end
it "should not set a timer" do
EventLoop::Timer.expects(:new).never
@settings.parse
end
end
end
@ -1057,46 +1044,6 @@ describe Puppet::Util::Settings do
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
it "should return false if there is no user setting" do
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
class TestPuppetModule < Test::Unit::TestCase
include PuppetTest
include SignalObserver
def mkfakeclient
Class.new(Puppet::Network::Client) do