summaryrefslogtreecommitdiffstats
path: root/lib/puppet
diff options
context:
space:
mode:
authorMatt Robinson <matt@puppetlabs.com>2011-03-22 15:46:26 -0700
committerMatt Robinson <matt@puppetlabs.com>2011-03-22 15:46:26 -0700
commit8542160479538fe6575475c2dccf5d4696fa3e5d (patch)
treea2d09b68de0e7101116062d44e622d76b0abd1f8 /lib/puppet
parent6bf5b7fea8ef4d04809e78eef84029a0773d4747 (diff)
parent0170cebba039378597fdf9f0086339c2766df408 (diff)
downloadpuppet-8542160479538fe6575475c2dccf5d4696fa3e5d.tar.gz
puppet-8542160479538fe6575475c2dccf5d4696fa3e5d.tar.xz
puppet-8542160479538fe6575475c2dccf5d4696fa3e5d.zip
Merge branch 'feature/next/6257-pip_package_provider' into next
* feature/next/6257-pip_package_provider: (#6527) Fix uninstall problem and refactor (#6527) Added pip package provider.
Diffstat (limited to 'lib/puppet')
-rw-r--r--lib/puppet/provider/package/pip.rb109
1 files changed, 109 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..5abbc135a
--- /dev/null
+++ b/lib/puppet/provider/package/pip.rb
@@ -0,0 +1,109 @@
+# 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 = []
+ pip_cmd = which('pip') or return []
+ execpipe "#{pip_cmd} freeze" do |process|
+ process.collect do |line|
+ next unless options = parse(line)
+ packages << new(options)
+ end
+ end
+ packages
+ end
+
+ # Return structured information about a particular package or `nil` if
+ # it is not installed or `pip` itself is not available.
+ def query
+ self.class.instances.each do |provider_pip|
+ return provider_pip.properties if @resource[:name] == provider_pip.name
+ end
+ return 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')
+ self.class.commands :pip => pathname
+ pip *args
+ else
+ raise e
+ end
+ end
+
+end