This allows rubygems to be used to extend or override puppet behavior. Unfortunately the features system uses the autoloader so checking for the rubygems feature causes a call loop. It's possible that a more elegant way to avoid this exist rather than just checking the @path but this did what I needed to do.
Without caching the directories the tests would take forever to run and eventually crash my server. Caching seems to avoid the biggest of the performance hit. Signed-off-by: R.I.Pienaar <r...@devco.net> --- Local-branch: feature/master/7788 lib/puppet/configurer.rb | 5 +++-- lib/puppet/parser/compiler.rb | 1 + lib/puppet/util/autoload.rb | 19 +++++++++++++++++-- spec/unit/util/autoload_spec.rb | 10 +++++++++- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/lib/puppet/configurer.rb b/lib/puppet/configurer.rb index cfeb73a..00c3b18 100644 --- a/lib/puppet/configurer.rb +++ b/lib/puppet/configurer.rb @@ -156,9 +156,10 @@ class Puppet::Configurer return end ensure - # Make sure we forget the retained module_directories of any autoload - # we might have used. + # Make sure we forget the retained module_directories and gem search + # path of any autoload we might have used. Thread.current[:env_module_directories] = nil + Thread.current[:gemsearch_directories] = nil # Now close all of our existing http connections, since there's no # reason to leave them lying open. diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb index c1daade..68498ad 100644 --- a/lib/puppet/parser/compiler.rb +++ b/lib/puppet/parser/compiler.rb @@ -22,6 +22,7 @@ class Puppet::Parser::Compiler # stick until the next entry to this function. Thread.current[:known_resource_types] = nil Thread.current[:env_module_directories] = nil + Thread.current[:gemsearch_directories] = nil # ...and we actually do the compile now we have caching ready. new(node).compile.to_resource diff --git a/lib/puppet/util/autoload.rb b/lib/puppet/util/autoload.rb index 6537a4a..e61f4cd 100644 --- a/lib/puppet/util/autoload.rb +++ b/lib/puppet/util/autoload.rb @@ -124,9 +124,24 @@ class Puppet::Util::Autoload searchpath.map { |dir| Dir.glob("#{dir}/*.rb") }.flatten end - # The list of directories to search through for loadable plugins. + # features uses the autoloader which causes a loop so avoid trying to + # ask Gem for its path during feature loading. + # + # We're using a per-thread cache based on the code in #module_directories. + def gemsearchpaths + unless @path == "puppet/feature" + if Puppet.features.rubygems? + return Thread.current[:gemsearch_directories] ||= Gem.all_load_paths + end + end + + return [] + end + + # The list of directories to search through for loadable plugins. We search gem paths first + # so that people can use the gem packages to override core puppet features if they wish. def searchpath(env=nil) - search_directories(env).uniq.collect { |d| File.join(d, @path) }.find_all { |d| FileTest.directory?(d) } + [gemsearchpaths, search_directories(env)].flatten.uniq.collect { |d| File.join(d, @path) }.find_all { |d| FileTest.directory?(d) } end def module_directories(env=nil) diff --git a/spec/unit/util/autoload_spec.rb b/spec/unit/util/autoload_spec.rb index d61b768..e962b1e 100755 --- a/spec/unit/util/autoload_spec.rb +++ b/spec/unit/util/autoload_spec.rb @@ -51,13 +51,21 @@ describe Puppet::Util::Autoload do @autoload.search_directories.should == %w{/one /two /libdir1 /lib/dir/two /third/lib/dir} + $LOAD_PATH end + it "should not try to merge rubygems dirs when called from the feature system" do + @autoload = Puppet::Util::Autoload.new("foo", "puppet/feature") + Puppet.features.expects(:rubygems?).never + @autoload.gemsearchpaths + end + it "should include in its search path all of the unique search directories that have a subdirectory matching the autoload path" do @autoload = Puppet::Util::Autoload.new("foo", "loaddir") @autoload.expects(:search_directories).returns %w{/one /two /three /three} + @autoload.expects(:gemsearchpaths).returns %w{/four /four} FileTest.expects(:directory?).with("/one/loaddir").returns true FileTest.expects(:directory?).with("/two/loaddir").returns false FileTest.expects(:directory?).with("/three/loaddir").returns true - @autoload.searchpath.should == ["/one/loaddir", "/three/loaddir"] + FileTest.expects(:directory?).with("/four/loaddir").returns true + @autoload.searchpath.should == ["/four/loaddir", "/one/loaddir", "/three/loaddir"] end end -- 1.7.1 -- You received this message because you are subscribed to the Google Groups "Puppet Developers" group. To post to this group, send email to puppet-dev@googlegroups.com. To unsubscribe from this group, send email to puppet-dev+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en.