diff options
| author | Richard Crowley <r@rcrowley.org> | 2011-03-01 20:44:11 +0000 |
|---|---|---|
| committer | Matt Robinson <matt@puppetlabs.com> | 2011-03-22 15:35:18 -0700 |
| commit | af42367dce6ab1ad18a1a8d10e4d54b5accae449 (patch) | |
| tree | 4afe00813f6d3f5239e0ff2736f9872860e27caa /lib | |
| parent | e80063468e404a6827ea6ec458ae34ca84619eed (diff) | |
| download | puppet-af42367dce6ab1ad18a1a8d10e4d54b5accae449.tar.gz puppet-af42367dce6ab1ad18a1a8d10e4d54b5accae449.tar.xz puppet-af42367dce6ab1ad18a1a8d10e4d54b5accae449.zip | |
(#6527) Added pip package provider.
Python's pip package manager is analogous to RubyGems and should be included in Puppet.
Reviewed-by: Matt Robinson <matt@puppetlabs.com>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/puppet/provider/package/pip.rb | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/lib/puppet/provider/package/pip.rb b/lib/puppet/provider/package/pip.rb new file mode 100644 index 000000000..00797563a --- /dev/null +++ b/lib/puppet/provider/package/pip.rb @@ -0,0 +1,115 @@ +# Puppet package provider for Python's `pip` package management frontend. +# <http://pip.openplans.org/> + +require 'puppet/provider/package' +require 'xmlrpc/client' + +Puppet::Type.type(:package).provide :pip, + :parent => ::Puppet::Provider::Package do + + desc "Python packages via `pip`." + + has_feature :installable, :uninstallable, :upgradeable, :versionable + + # Parse lines of output from `pip freeze`, which are structured as + # _package_==_version_. + def self.parse(line) + if line.chomp =~ /^([^=]+)==([^=]+)$/ + {:ensure => $2, :name => $1, :provider => name} + else + nil + end + end + + # Return an array of structured information about every installed package + # that's managed by `pip` or an empty array if `pip` is not available. + def self.instances + packages = [] + execpipe "#{command :pip} freeze" do |process| + process.collect do |line| + next unless options = parse(line) + packages << new(options) + end + end + packages + rescue Puppet::DevError + [] + end + + # Return structured information about a particular package or `nil` if + # it is not installed or `pip` itself is not available. + def query + execpipe "#{command :pip} freeze" do |process| + process.each do |line| + options = self.class.parse(line) + return options if options[:name] == @resource[:name] + end + end + nil + rescue Puppet::DevError + nil + end + + # Ask the PyPI API for the latest version number. There is no local + # cache of PyPI's package list so this operation will always have to + # ask the web service. + def latest + client = XMLRPC::Client.new2("http://pypi.python.org/pypi") + client.http_header_extra = {"Content-Type" => "text/xml"} + result = client.call("package_releases", @resource[:name]) + result.first + end + + # Install a package. The ensure parameter may specify installed, + # latest, a version number, or, in conjunction with the source + # parameter, an SCM revision. In that case, the source parameter + # gives the fully-qualified URL to the repository. + def install + args = %w{install -q} + if @resource[:source] + args << "-e" + if String === @resource[:ensure] + args << "#{@resource[:source]}@#{@resource[:ensure]}#egg=#{ + @resource[:name]}" + else + args << "#{@resource[:source]}#egg=#{@resource[:name]}" + end + else + case @resource[:ensure] + when String + args << "#{@resource[:name]}==#{@resource[:ensure]}" + when :latest + args << "--upgrade" << @resource[:name] + else + args << @resource[:name] + end + end + lazy_pip *args + end + + # Uninstall a package. Uninstall won't work reliably on Debian/Ubuntu + # unless this issue gets fixed. + # <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=562544> + def uninstall + lazy_pip "uninstall", "-y", "-q", @resource[:name] + end + + def update + install + end + + # Execute a `pip` command. If Puppet doesn't yet know how to do so, + # try to teach it and if even that fails, raise the error. + private + def lazy_pip(*args) + pip *args + rescue NoMethodError => e + if pathname = `which pip`.chomp + self.class.commands :pip => pathname + pip *args + else + raise e + end + end + +end |
