summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2007-03-19 08:15:36 +0000
committerluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2007-03-19 08:15:36 +0000
commit5b2ffbcb5d2e4113efec9c8ba882c5506d53c242 (patch)
treeb4127af05cf5682f38fbca928c9fb53e0b42f52b /lib
parent80dac92b3a5ebd2cb8904505845d63759b5cebb3 (diff)
downloadpuppet-5b2ffbcb5d2e4113efec9c8ba882c5506d53c242.tar.gz
puppet-5b2ffbcb5d2e4113efec9c8ba882c5506d53c242.tar.xz
puppet-5b2ffbcb5d2e4113efec9c8ba882c5506d53c242.zip
Adding provider features. Woot!
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@2313 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'lib')
-rw-r--r--lib/puppet/metatype/providers.rb76
-rw-r--r--lib/puppet/provider.rb8
-rw-r--r--lib/puppet/type/package.rb27
-rw-r--r--lib/puppet/util/provider_features.rb108
4 files changed, 216 insertions, 3 deletions
diff --git a/lib/puppet/metatype/providers.rb b/lib/puppet/metatype/providers.rb
index ef7f73c6c..c078ced24 100644
--- a/lib/puppet/metatype/providers.rb
+++ b/lib/puppet/metatype/providers.rb
@@ -1,4 +1,8 @@
+require 'puppet/util/provider_features'
class Puppet::Type
+ # Add the feature handling module.
+ extend Puppet::Util::ProviderFeatures
+
attr_reader :provider
# the Type class attribute accessors
@@ -41,6 +45,74 @@ class Puppet::Type
return @defaultprovider
end
+ # Define one or more features. Currently, features are just a list of
+ # methods; if all methods are defined as instance methods on the provider,
+ # then the provider has that feature, otherwise it does not.
+ def self.dis_features(hash)
+ @features ||= {}
+ hash.each do |name, methods|
+ name = symbolize(name)
+ methods = methods.collect { |m| symbolize(m) }
+ if @features.include?(name)
+ raise Puppet::DevError, "Feature %s is already defined" % name
+ end
+ @features[name] = methods
+ end
+ end
+
+ # Generate a module that sets up the boolean methods to test for given
+ # features.
+ def self.dis_feature_module
+ unless defined? @feature_module
+ @features ||= {}
+ @feature_module = ::Module.new
+ const_set("FeatureModule", @feature_module)
+ features = @features
+ @feature_module.send(:define_method, :feature?) do |name|
+ method = name.to_s + "?"
+ if respond_to?(method) and send(method)
+ return true
+ else
+ return false
+ end
+ end
+ @feature_module.send(:define_method, :features) do
+ return false unless defined?(features)
+ features.keys.find_all { |n| feature?(n) }.sort { |a,b|
+ a.to_s <=> b.to_s
+ }
+ end
+ #if defined?(@features)
+ @features.each do |name, methods|
+ method = name.to_s + "?"
+ @feature_module.send(:define_method, method) do
+ set = nil
+ methods.each do |m|
+ if is_a?(Class)
+ unless public_method_defined?(m)
+ set = false
+ break
+ end
+ else
+ unless respond_to?(m)
+ set = false
+ break
+ end
+ end
+ end
+
+ if set.nil?
+ true
+ else
+ false
+ end
+ end
+ end
+ #end
+ end
+ @feature_module
+ end
+
# Convert a hash, as provided by, um, a provider, into an instance of self.
def self.hash2obj(hash)
obj = nil
@@ -161,6 +233,10 @@ class Puppet::Type
:attributes => options
)
+ # Add the feature module to both the instances and classes.
+ provider.send(:include, feature_module)
+ provider.send(:extend, feature_module)
+
return provider
end
diff --git a/lib/puppet/provider.rb b/lib/puppet/provider.rb
index 23c921ac0..f5e45ba6d 100644
--- a/lib/puppet/provider.rb
+++ b/lib/puppet/provider.rb
@@ -212,6 +212,14 @@ class Puppet::Provider
end
end
+ dochook(:features) do
+ if features().length > 0
+ return " Supported features: " + features().collect do |f|
+ "``#{f}``"
+ end.join(", ") + "."
+ end
+ end
+
# Remove the reference to the model, so GC can clean up.
def clear
@model = nil
diff --git a/lib/puppet/type/package.rb b/lib/puppet/type/package.rb
index 107acc20d..14ce4a941 100644
--- a/lib/puppet/type/package.rb
+++ b/lib/puppet/type/package.rb
@@ -17,8 +17,23 @@ module Puppet
Puppet will automatically guess the packaging format that you are
using based on the platform you are on, but you can override it
- using the ``type`` parameter; obviously, if you specify that you
- want to use ``rpm`` then the ``rpm`` tools must be available."
+ using the ``provider`` parameter; each provider defines what it
+ requires in order to function, and you must meet those requirements
+ to use a given provider."
+
+ feature :installable, "The provider can install packages.",
+ :methods => [:install]
+ feature :uninstallable, "The provider can uninstall packages.",
+ :methods => [:uninstall]
+ feature :upgradeable, "The provider can upgrade to the latest version of a
+ package. This feature is used by specifying ``latest`` as the
+ desired value for the package.",
+ :methods => [:update, :latest]
+ feature :purgeable, "The provider can purge packages. This generally means
+ that all traces of the package are removed, including
+ existing configuration files. This feature is thus destructive
+ and should be used with the utmost care.",
+ :methods => [:purge]
ensurable do
desc "What state the package should be in.
@@ -42,6 +57,12 @@ module Puppet
end
newvalue(:purged, :event => :package_purged) do
+ unless provider.purgeable?
+ self.fail(
+ "Package provider %s does not purging" %
+ @parent[:provider]
+ )
+ end
provider.purge
end
@@ -49,7 +70,7 @@ module Puppet
aliasvalue(:installed, :present)
newvalue(:latest) do
- unless provider.respond_to?(:latest)
+ unless provider.upgradeable?
self.fail(
"Package provider %s does not support specifying 'latest'" %
@parent[:provider]
diff --git a/lib/puppet/util/provider_features.rb b/lib/puppet/util/provider_features.rb
new file mode 100644
index 000000000..c378ff805
--- /dev/null
+++ b/lib/puppet/util/provider_features.rb
@@ -0,0 +1,108 @@
+# Provides feature definitions.
+module Puppet::Util::ProviderFeatures
+ class ProviderFeature
+ require 'puppet/util/methodhelper'
+ require 'puppet/util'
+ include Puppet::Util
+ include Puppet::Util::MethodHelper
+ attr_accessor :name, :docs, :methods
+ def initialize(name, docs, hash)
+ self.name = symbolize(name)
+ self.docs = docs
+ hash = symbolize_options(hash)
+ set_options(hash)
+ end
+ end
+
+ # Define one or more features. At a minimum, features require a name
+ # and docs, and at this point they should also specify a list of methods
+ # required to determine if the feature is present.
+ def feature(name, docs, hash)
+ @features ||= {}
+ if @features.include?(name)
+ raise Puppet::DevError, "Feature %s is already defined" % name
+ end
+ begin
+ obj = ProviderFeature.new(name, docs, hash)
+ @features[obj.name] = obj
+ rescue ArgumentError => detail
+ error = ArgumentError.new(
+ "Could not create feature %s: %s" % [name, detail]
+ )
+ error.set_backtrace(detail.backtrace)
+ raise error
+ end
+ end
+
+ # Return a hash of all feature documentation.
+ def featuredocs
+ str = ""
+ @features ||= {}
+ return nil if @features.empty?
+ @features.each do |name, feature|
+ doc = feature.docs.gsub(/\n\s+/, " ")
+ str += " - **%s**: %s\n" % [name, doc]
+ end
+ str
+ end
+
+ # Generate a module that sets up the boolean methods to test for given
+ # features.
+ def feature_module
+ unless defined? @feature_module
+ @features ||= {}
+ @feature_module = ::Module.new
+ const_set("FeatureModule", @feature_module)
+ features = @features
+ # Create a feature? method that can be passed a feature name and
+ # determine if the feature is present.
+ @feature_module.send(:define_method, :feature?) do |name|
+ method = name.to_s + "?"
+ if respond_to?(method) and send(method)
+ return true
+ else
+ return false
+ end
+ end
+
+ # Create a method that will list all functional features.
+ @feature_module.send(:define_method, :features) do
+ return false unless defined?(features)
+ features.keys.find_all { |n| feature?(n) }.sort { |a,b|
+ a.to_s <=> b.to_s
+ }
+ end
+
+ # Create a boolean method for each feature so you can test them
+ # individually as you might need.
+ @features.each do |name, feature|
+ method = name.to_s + "?"
+ @feature_module.send(:define_method, method) do
+ set = nil
+ feature.methods.each do |m|
+ if is_a?(Class)
+ unless public_method_defined?(m)
+ set = false
+ break
+ end
+ else
+ unless respond_to?(m)
+ set = false
+ break
+ end
+ end
+ end
+
+ if set.nil?
+ true
+ else
+ false
+ end
+ end
+ end
+ end
+ @feature_module
+ end
+end
+
+# $Id$