diff options
| author | Nick Lewis <nick@puppetlabs.com> | 2011-07-25 17:02:24 -0700 |
|---|---|---|
| committer | Nick Lewis <nick@puppetlabs.com> | 2011-07-25 17:02:24 -0700 |
| commit | b13427b56d8529731d0334d420b24a592ecb43ea (patch) | |
| tree | 1d2f89907e6136bea2ace8e84a57966779af89d1 /lib/puppet/interface | |
| parent | 043c3e87c882d38b9708b6e215425a9935f74769 (diff) | |
| parent | 8baa4897e777f9515dc1663317f432ace3067bae (diff) | |
| download | puppet-b13427b56d8529731d0334d420b24a592ecb43ea.tar.gz puppet-b13427b56d8529731d0334d420b24a592ecb43ea.tar.xz puppet-b13427b56d8529731d0334d420b24a592ecb43ea.zip | |
Merge branch '2.7.x'
Conflicts:
lib/puppet/type/file/source.rb
spec/unit/resource/catalog_spec.rb
Diffstat (limited to 'lib/puppet/interface')
| -rw-r--r-- | lib/puppet/interface/action.rb | 82 | ||||
| -rw-r--r-- | lib/puppet/interface/face_collection.rb | 50 |
2 files changed, 92 insertions, 40 deletions
diff --git a/lib/puppet/interface/action.rb b/lib/puppet/interface/action.rb index fc1121eb6..bd47a36ea 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 @@ -195,15 +196,12 @@ class Puppet::Interface::Action wrapper = <<WRAPPER def #{@name}(#{decl.join(", ")}) #{optn} - args = #{args} - options = args.last - - action = get_action(#{name.inspect}) - action.add_default_args(args) - action.validate_args(args) - __invoke_decorations(:before, action, args, options) + args = #{args} + action = get_action(#{name.inspect}) + args << action.validate_and_clean(args.pop) + __invoke_decorations(:before, action, args, args.last) rval = self.__send__(#{internal_name.inspect}, *args) - __invoke_decorations(:after, action, args, options) + __invoke_decorations(:after, action, args, args.last) return rval end WRAPPER @@ -253,35 +251,59 @@ WRAPPER option end - def add_default_args(args) - options.map {|x| get_option(x) }.each do |option| - if option.has_default? and not option.aliases.any? {|x| args.last.has_key? x} - args.last[option.name] = option.default + def validate_and_clean(original) + # The final set of arguments; effectively a hand-rolled shallow copy of + # the original, which protects the caller from the surprises they might + # get if they passed us a hash and we mutated it... + result = {} + + # Check for multiple aliases for the same option, and canonicalize the + # name of the argument while we are about it. + overlap = Hash.new do |h, k| h[k] = [] end + unknown = [] + original.keys.each do |name| + if option = get_option(name) then + canonical = option.name + if result.has_key? canonical + overlap[canonical] << name + else + result[canonical] = original[name] + end + else + unknown << name end end - end - def validate_args(args) - # Check for multiple aliases for the same option... - args.last.keys.each do |name| - # #7290: If this isn't actually an option, ignore it for now. We should - # probably fail, but that wasn't our API, and I don't want to perturb - # behaviour this late in the RC cycle. --daniel 2011-04-29 - if option = get_option(name) then - overlap = (option.aliases & args.last.keys) - unless overlap.length == 1 then - raise ArgumentError, "Multiple aliases for the same option passed: #{overlap.join(', ')}" - end + unless overlap.empty? + msg = overlap.map {|k, v| "(#{k}, #{v.sort.join(', ')})" }.join(", ") + raise ArgumentError, "Multiple aliases for the same option passed: #{msg}" + end + + unless unknown.empty? + msg = unknown.sort.join(", ") + raise ArgumentError, "Unknown options passed: #{msg}" + end + + # Inject default arguments and check for missing mandating options. + missing = [] + options.map {|x| get_option(x) }.each do |option| + name = option.name + next if result.has_key? name + + if option.has_default? + result[name] = option.default + elsif option.required? + missing << name end end - # Check for missing mandatory options. - required = options.map do |name| - get_option(name) - end.select(&:required?).collect(&:name) - args.last.keys + unless missing.empty? + msg = missing.sort.join(', ') + raise ArgumentError, "The following options are required: #{msg}" + end - return if required.empty? - raise ArgumentError, "The following options are required: #{required.join(', ')}" + # All done. + return result end ######################################################################## 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 |
