summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorRichard Crowley <r@rcrowley.org>2011-03-01 20:44:11 +0000
committerMatt Robinson <matt@puppetlabs.com>2011-03-22 15:35:18 -0700
commitaf42367dce6ab1ad18a1a8d10e4d54b5accae449 (patch)
tree4afe00813f6d3f5239e0ff2736f9872860e27caa /lib
parente80063468e404a6827ea6ec458ae34ca84619eed (diff)
downloadpuppet-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.rb115
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