diff options
| author | Daniel Pittman <daniel@puppetlabs.com> | 2011-07-22 13:30:05 -0700 |
|---|---|---|
| committer | Daniel Pittman <daniel@puppetlabs.com> | 2011-07-22 13:30:05 -0700 |
| commit | feec7b3df713569f76b93ae8cef882e9ddc1bf35 (patch) | |
| tree | 89d10d48744e76da63a083de85a86d5b867565ca | |
| parent | f309e1e45c456cc1d53469863f59cbad0df37241 (diff) | |
| parent | 532c4f37e4f8289cf4a9871ebc0cb5086c2ba26a (diff) | |
| download | puppet-feec7b3df713569f76b93ae8cef882e9ddc1bf35.tar.gz puppet-feec7b3df713569f76b93ae8cef882e9ddc1bf35.tar.xz puppet-feec7b3df713569f76b93ae8cef882e9ddc1bf35.zip | |
Merge branch 'feature/2.7.x/7184-better-action-loading' into 2.7.x
| -rw-r--r-- | lib/puppet/application/face_base.rb | 3 | ||||
| -rw-r--r-- | lib/puppet/interface.rb | 4 | ||||
| -rw-r--r-- | lib/puppet/interface/action.rb | 1 | ||||
| -rw-r--r-- | lib/puppet/interface/face_collection.rb | 50 | ||||
| -rwxr-xr-x | spec/lib/puppet/face/1.0.0/huzzah.rb | 9 | ||||
| -rwxr-xr-x | spec/lib/puppet/face/huzzah.rb | 2 | ||||
| -rw-r--r-- | spec/lib/puppet/face/huzzah/obsolete.rb | 6 | ||||
| -rwxr-xr-x | spec/unit/application/face_base_spec.rb | 1 | ||||
| -rwxr-xr-x | spec/unit/interface/face_collection_spec.rb | 42 | ||||
| -rwxr-xr-x | spec/unit/interface_spec.rb | 9 |
10 files changed, 108 insertions, 19 deletions
diff --git a/lib/puppet/application/face_base.rb b/lib/puppet/application/face_base.rb index ea5ba4aaf..a111518f1 100644 --- a/lib/puppet/application/face_base.rb +++ b/lib/puppet/application/face_base.rb @@ -100,7 +100,8 @@ class Puppet::Application::FaceBase < Puppet::Application # action object it represents; if this is an invalid action name that # will be nil, and handled later. action_name = item.to_sym - @action = @face.get_action(action_name) + @action = Puppet::Face.find_action(@face.name, action_name) + @face = @action.face if @action end end diff --git a/lib/puppet/interface.rb b/lib/puppet/interface.rb index 6c288f3c0..eba99d6be 100644 --- a/lib/puppet/interface.rb +++ b/lib/puppet/interface.rb @@ -64,6 +64,10 @@ class Puppet::Interface end face end + + def find_action(name, action, version = :current) + Puppet::Interface::FaceCollection.get_action_for_face(name, action, version) + end end def set_default_format(format) diff --git a/lib/puppet/interface/action.rb b/lib/puppet/interface/action.rb index fc1121eb6..ce9c60b49 100644 --- a/lib/puppet/interface/action.rb +++ b/lib/puppet/interface/action.rb @@ -38,6 +38,7 @@ class Puppet::Interface::Action def to_s() "#{@face}##{@name}" end attr_reader :name + attr_reader :face attr_accessor :default def default? !!@default diff --git a/lib/puppet/interface/face_collection.rb b/lib/puppet/interface/face_collection.rb index 4522824fd..b1f6ba398 100644 --- a/lib/puppet/interface/face_collection.rb +++ b/lib/puppet/interface/face_collection.rb @@ -20,6 +20,24 @@ module Puppet::Interface::FaceCollection get_face(name, version) or load_face(name, version) end + def self.get_action_for_face(name, action_name, version) + name = underscorize(name) + + # If the version they request specifically doesn't exist, don't search + # elsewhere. Usually this will start from :current and all... + return nil unless face = self[name, version] + unless action = face.get_action(action_name) + # ...we need to search for it bound to an o{lder,ther} version. Since + # we load all actions when the face is first references, this will be in + # memory in the known set of versions of the face. + (@faces[name].keys - [ :current ]).sort.reverse.each do |version| + break if action = @faces[name][version].get_action(action_name) + end + end + + return action + end + # get face from memory, without loading. def self.get_face(name, pattern) return nil unless @faces.has_key? name @@ -38,9 +56,7 @@ module Puppet::Interface::FaceCollection # # We use require to avoid executing the code multiple times, like any # other Ruby library that we might want to use. --daniel 2011-04-06 - begin - require "puppet/face/#{name}" - + if safely_require name then # If we wanted :current, we need to index to find that; direct version # requests just work™ as they go. --daniel 2011-04-06 if version == :current then @@ -72,18 +88,32 @@ module Puppet::Interface::FaceCollection latest_ver = @faces[name].keys.sort.last @faces[name][:current] = @faces[name][latest_ver] end - rescue LoadError => e - raise unless e.message =~ %r{-- puppet/face/#{name}$} - # ...guess we didn't find the file; return a much better problem. - rescue SyntaxError => e - raise unless e.message =~ %r{puppet/face/#{name}\.rb:\d+: } - Puppet.err "Failed to load face #{name}:\n#{e}" - # ...but we just carry on after complaining. + end + + unless version == :current or get_face(name, version) + # Try an obsolete version of the face, if needed, to see if that helps? + safely_require name, version end return get_face(name, version) end + def self.safely_require(name, version = nil) + path = File.join 'puppet' ,'face', version.to_s, name.to_s + require path + true + + rescue LoadError => e + raise unless e.message =~ %r{-- #{path}$} + # ...guess we didn't find the file; return a much better problem. + nil + rescue SyntaxError => e + raise unless e.message =~ %r{#{path}\.rb:\d+: } + Puppet.err "Failed to load face #{name}:\n#{e}" + # ...but we just carry on after complaining. + nil + end + def self.register(face) @faces[underscorize(face.name)][face.version] = face end diff --git a/spec/lib/puppet/face/1.0.0/huzzah.rb b/spec/lib/puppet/face/1.0.0/huzzah.rb new file mode 100755 index 000000000..00f20f096 --- /dev/null +++ b/spec/lib/puppet/face/1.0.0/huzzah.rb @@ -0,0 +1,9 @@ +require 'puppet/face' +Puppet::Face.define(:huzzah, '1.0.0') do + copyright "Puppet Labs", 2011 + license "Apache 2 license; see COPYING" + summary "life is a thing for celebration" + script :obsolete_in_core do |_| "you are in obsolete core now!" end + + script :call_newer do method_on_newer end +end diff --git a/spec/lib/puppet/face/huzzah.rb b/spec/lib/puppet/face/huzzah.rb index ab465d9e0..47cc3f32c 100755 --- a/spec/lib/puppet/face/huzzah.rb +++ b/spec/lib/puppet/face/huzzah.rb @@ -4,4 +4,6 @@ Puppet::Face.define(:huzzah, '2.0.1') do license "Apache 2 license; see COPYING" summary "life is a thing for celebration" script :bar do |options| "is where beer comes from" end + + script :call_older do method_on_older end end diff --git a/spec/lib/puppet/face/huzzah/obsolete.rb b/spec/lib/puppet/face/huzzah/obsolete.rb new file mode 100644 index 000000000..1f717ea2f --- /dev/null +++ b/spec/lib/puppet/face/huzzah/obsolete.rb @@ -0,0 +1,6 @@ +Puppet::Face.define(:huzzah, '1.0.0') do + action :obsolete do + summary "This is an action on version 1.0.0 of the face" + when_invoked do |options| options end + end +end diff --git a/spec/unit/application/face_base_spec.rb b/spec/unit/application/face_base_spec.rb index 0a4a86be6..bebc26210 100755 --- a/spec/unit/application/face_base_spec.rb +++ b/spec/unit/application/face_base_spec.rb @@ -55,6 +55,7 @@ describe Puppet::Application::FaceBase do it "should stop if the first thing found is not an action" do app.command_line.stubs(:args).returns %w{banana count_args} expect { app.run }.to exit_with 1 + @logs.first.should_not be_nil @logs.first.message.should =~ /has no 'banana' action/ end diff --git a/spec/unit/interface/face_collection_spec.rb b/spec/unit/interface/face_collection_spec.rb index 98887a778..514a624b1 100755 --- a/spec/unit/interface/face_collection_spec.rb +++ b/spec/unit/interface/face_collection_spec.rb @@ -35,7 +35,8 @@ describe Puppet::Interface::FaceCollection do end it "should attempt to load the face if it isn't found" do - subject.expects(:require).with('puppet/face/bar') + subject.expects(:require).once.with('puppet/face/bar') + subject.expects(:require).once.with('puppet/face/0.0.1/bar') subject["bar", '0.0.1'] end @@ -64,7 +65,8 @@ describe Puppet::Interface::FaceCollection do it "should return false if the face file itself is missing" do subject.stubs(:require). - raises(LoadError, 'no such file to load -- puppet/face/bar') + raises(LoadError, 'no such file to load -- puppet/face/bar').then. + raises(LoadError, 'no such file to load -- puppet/face/0.0.1/bar') subject["bar", '0.0.1'].should be_false end @@ -97,6 +99,42 @@ describe Puppet::Interface::FaceCollection do end end + describe "::get_action_for_face" do + it "should return an action on the current face" do + Puppet::Face::FaceCollection.get_action_for_face(:huzzah, :bar, :current). + should be_an_instance_of Puppet::Interface::Action + end + + it "should return an action on an older version of a face" do + action = Puppet::Face::FaceCollection. + get_action_for_face(:huzzah, :obsolete, :current) + + action.should be_an_instance_of Puppet::Interface::Action + action.face.version.should == SemVer.new('1.0.0') + end + + it "should load the full older version of a face" do + action = Puppet::Face::FaceCollection. + get_action_for_face(:huzzah, :obsolete, :current) + + action.face.version.should == SemVer.new('1.0.0') + action.face.should be_action :obsolete_in_core + end + + it "should not add obsolete actions to the current version" do + action = Puppet::Face::FaceCollection. + get_action_for_face(:huzzah, :obsolete, :current) + + action.face.version.should == SemVer.new('1.0.0') + action.face.should be_action :obsolete_in_core + + current = Puppet::Face[:huzzah, :current] + current.version.should == SemVer.new('2.0.1') + current.should_not be_action :obsolete_in_core + current.should_not be_action :obsolete + end + end + describe "::register" do it "should store the face by name" do face = Puppet::Face.new(:my_face, '0.0.1') diff --git a/spec/unit/interface_spec.rb b/spec/unit/interface_spec.rb index 4cb1f8743..4ff71ac3d 100755 --- a/spec/unit/interface_spec.rb +++ b/spec/unit/interface_spec.rb @@ -126,14 +126,11 @@ describe Puppet::Interface do end it "should try to require faces that are not known" do - pending "mocking require causes random stack overflow" - subject::FaceCollection.expects(:require).with "puppet/face/foo" - subject[:foo, '0.0.1'] + subject::FaceCollection.expects(:load_face).with(:foo, :current) + subject::FaceCollection.expects(:load_face).with(:foo, '0.0.1') + expect { subject[:foo, '0.0.1'] }.to raise_error Puppet::Error end - it "should be able to load all actions in all search paths" - - it_should_behave_like "things that declare options" do def add_options_to(&block) subject.new(:with_options, '0.0.1', &block) |
