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 '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
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) 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