diff options
author | Bryan McLellan <btm@opscode.com> | 2011-08-05 09:05:07 -0700 |
---|---|---|
committer | Bryan McLellan <btm@opscode.com> | 2011-08-05 09:05:07 -0700 |
commit | 47ade45014af680a1e16a6b9c0f021bd277509f5 (patch) | |
tree | e1090984b1a869d03321fbc0f2130a3707117b7c | |
parent | 9aa5b4d3af9de4f7c9bd4e5b2a1ae5936fedc70e (diff) | |
download | chef-47ade45014af680a1e16a6b9c0f021bd277509f5.tar.gz |
CHEF-2483: refactor apt provider to use apt-cache and not aptitude for speed
-rw-r--r-- | chef/lib/chef/provider/package/apt.rb | 58 | ||||
-rw-r--r-- | chef/spec/unit/provider/package/apt_spec.rb | 133 |
2 files changed, 121 insertions, 70 deletions
diff --git a/chef/lib/chef/provider/package/apt.rb b/chef/lib/chef/provider/package/apt.rb index e818116e82..4a4721d7ec 100644 --- a/chef/lib/chef/provider/package/apt.rb +++ b/chef/lib/chef/provider/package/apt.rb @@ -19,6 +19,8 @@ require 'chef/provider/package' require 'chef/mixin/command' require 'chef/resource/package' +require 'chef/mixin/shell_out' + class Chef class Provider @@ -39,36 +41,44 @@ class Chef Chef::Log.debug("#{@new_resource} checking package status for #{package}") installed = false - shell_out!("aptitude show #{package}").stdout.each_line do |line| + shell_out!("apt-cache policy #{package}").stdout.each_line do |line| case line - when /^State: installed/ - installed = true - when /^State: not a real package/ - @is_virtual_package = true - when /^Version: (.*)/ - @candidate_version = $1 - if installed - @current_resource.version($1) - else + when /^\s{2}Installed: (.+)$/ + installed_version = $1 + if installed_version == '(none)' + Chef::Log.debug("#{@new_resource} current version is nil") @current_resource.version(nil) + else + Chef::Log.debug("#{@new_resource} current version is #{installed_version}") + @current_resource.version(installed_version) + installed = true + end + when /^\s{2}Candidate: (.+)$/ + candidate_version = $1 + if candidate_version == '(none)' + # This may not be an appropriate assumption, but it shouldn't break anything that already worked -- btm + @is_virtual_package = true + showpkg = shell_out!("apt-cache showpkg #{package}").stdout + providers = Hash.new + showpkg.rpartition(/Reverse Provides:? #{$/}/)[2].each_line do |line| + provider, version = line.split + providers[provider] = version + end + # Check if the package providing this virtual package is installed + num_providers = providers.length + raise Chef::Exceptions::Package, "#{@new_resource.package_name} has no candidate in the apt-cache" if num_providers == 0 + # apt will only install a virtual package if there is a single providing package + raise Chef::Exceptions::Package, "#{@new_resource.package_name} is a virtual package provided by #{num_providers} packages, you must explicitly select one to install" if num_providers > 1 + # Check if the package providing this virtual package is installed + Chef::Log.info("#{@new_resource} is a virtual package, actually acting on package[#{providers.keys.first}]") + installed = check_package_state(providers.keys.first) + else + Chef::Log.debug("#{@new_resource} candidate version is #{$1}") + @candidate_version = $1 end - # If we are a virtual package with one provider package, install it - when /^Provided by: ([\w\d\-\.]*)$/ - next unless @is_virtual_package - virtual_provider = $1 - Chef::Log.info("#{@new_resource} is a virtual package, actually acting on package[#{virtual_provider}]") - installed = check_package_state(virtual_provider) - # If there is a comma, it is a list of packages. In this case fail to force the user to choose. - when /^Provided by: .*,/ - next unless @is_virtual_package - raise Chef::Exceptions::Package, "#{@new_resource.package_name} is a virtual package provided by multiple packages, you must explicitly select one to install" end end - if @candidate_version.nil? - raise Chef::Exceptions::Package, "apt does not have a version of package #{@new_resource.package_name}" - end - return installed end diff --git a/chef/spec/unit/provider/package/apt_spec.rb b/chef/spec/unit/provider/package/apt_spec.rb index 8ebbf9d4a3..b5d35d7a73 100644 --- a/chef/spec/unit/provider/package/apt_spec.rb +++ b/chef/spec/unit/provider/package/apt_spec.rb @@ -30,12 +30,14 @@ describe Chef::Provider::Package::Apt do @status = mock("Status", :exitstatus => 0) @provider = Chef::Provider::Package::Apt.new(@new_resource, @run_context) Chef::Resource::Package.stub!(:new).and_return(@current_resource) - @provider.stub!(:popen4).and_return(@status) @stdin = StringIO.new @stdout =<<-PKG_STATUS -Package: irssi -State: not installed -Version: 0.8.12-7 +irssi: + Installed: (none) + Candidate: 0.8.14-1ubuntu4 + Version table: + 0.8.14-1ubuntu4 0 + 500 http://us.archive.ubuntu.com/ubuntu/ lucid/main Packages PKG_STATUS @stderr = StringIO.new @pid = 12345 @@ -56,8 +58,8 @@ PKG_STATUS @provider.load_current_resource end - it "should run aptitude show with the package name" do - @provider.should_receive(:shell_out!).with("aptitude show #{@new_resource.package_name}").and_return(@shell_out) + it "should run apt-cache policy with the package name" do + @provider.should_receive(:shell_out!).with("apt-cache policy #{@new_resource.package_name}").and_return(@shell_out) @provider.load_current_resource end @@ -69,33 +71,21 @@ PKG_STATUS it "should set the installed version if package has one" do @stdout.replace(<<-INSTALLED) -Package: sudo -State: installed -Automatically installed: no -Version: 1.7.2p1-1ubuntu5 -Priority: important -Section: admin -Maintainer: Ubuntu Core Developers <ubuntu-devel-discuss@lists.ubuntu.com> -Uncompressed Size: 602k -Depends: libc6 (>= 2.8), libpam0g (>= 0.99.7.1), libpam-modules -Conflicts: sudo-ldap -Replaces: sudo-ldap -Provided by: sudo-ldap -Description: Provide limited super user privileges to specific users -Sudo is a program designed to allow a sysadmin to give limited root privileges -to users and log root activity. The basic philosophy is to give as few -privileges as possible but still allow people to get their work done. +sudo: + Installed: 1.7.2p1-1ubuntu5.3 + Candidate: 1.7.2p1-1ubuntu5.3 + Version table: + *** 1.7.2p1-1ubuntu5.3 0 + 500 http://us.archive.ubuntu.com/ubuntu/ lucid-updates/main Packages + 500 http://security.ubuntu.com/ubuntu/ lucid-security/main Packages + 100 /var/lib/dpkg/status + 1.7.2p1-1ubuntu5 0 + 500 http://us.archive.ubuntu.com/ubuntu/ lucid/main Packages INSTALLED @provider.should_receive(:shell_out!).and_return(@shell_out) @provider.load_current_resource - @current_resource.version.should == "1.7.2p1-1ubuntu5" - @provider.candidate_version.should eql("1.7.2p1-1ubuntu5") - end - - it "should raise an exception if aptitude show does not return a candidate version" do - @stdout.replace("E: Unable to locate package magic") - @provider.should_receive(:shell_out!).and_return(@shell_out) - lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package) + @current_resource.version.should == "1.7.2p1-1ubuntu5.3" + @provider.candidate_version.should eql("1.7.2p1-1ubuntu5.3") end it "should return the current resouce" do @@ -106,22 +96,50 @@ INSTALLED # libmysqlclient-dev is a real package in newer versions of debian + ubuntu # list of virtual packages: http://www.debian.org/doc/packaging-manuals/virtual-package-names-list.txt it "should not install the virtual package there is a single provider package and it is installed" do - @new_resource.package_name("libmysqlclient-dev") + @new_resource.package_name("libmysqlclient15-dev") virtual_package_out=<<-VPKG_STDOUT -No current or candidate version found for libmysqlclient-dev -Package: libmysqlclient-dev -State: not a real package -Provided by: libmysqlclient15-dev +libmysqlclient15-dev: + Installed: (none) + Candidate: (none) + Version table: VPKG_STDOUT virtual_package = mock(:stdout => virtual_package_out,:exitstatus => 0) - @provider.should_receive(:shell_out!).with("aptitude show libmysqlclient-dev").and_return(virtual_package) - real_package_out =<<-REALPKG_STDOUT + @provider.should_receive(:shell_out!).with("apt-cache policy libmysqlclient15-dev").and_return(virtual_package) + showpkg_out =<<-SHOWPKG_STDOUT Package: libmysqlclient15-dev -State: installed -Version: 5.0.51a-24+lenny4 -REALPKG_STDOUT +Versions: + +Reverse Depends: + libmysqlclient-dev,libmysqlclient15-dev + libmysqlclient-dev,libmysqlclient15-dev + libmysqlclient-dev,libmysqlclient15-dev + libmysqlclient-dev,libmysqlclient15-dev + libmysqlclient-dev,libmysqlclient15-dev + libmysqlclient-dev,libmysqlclient15-dev +Dependencies: +Provides: +Reverse Provides: +libmysqlclient-dev 5.1.41-3ubuntu12.7 +libmysqlclient-dev 5.1.41-3ubuntu12.10 +libmysqlclient-dev 5.1.41-3ubuntu12 +SHOWPKG_STDOUT + showpkg = mock(:stdout => showpkg_out,:exitstatus => 0) + @provider.should_receive(:shell_out!).with("apt-cache showpkg libmysqlclient15-dev").and_return(showpkg) + real_package_out=<<-RPKG_STDOUT +libmysqlclient-dev: + Installed: 5.1.41-3ubuntu12.10 + Candidate: 5.1.41-3ubuntu12.10 + Version table: + *** 5.1.41-3ubuntu12.10 0 + 500 http://us.archive.ubuntu.com/ubuntu/ lucid-updates/main Packages + 100 /var/lib/dpkg/status + 5.1.41-3ubuntu12.7 0 + 500 http://security.ubuntu.com/ubuntu/ lucid-security/main Packages + 5.1.41-3ubuntu12 0 + 500 http://us.archive.ubuntu.com/ubuntu/ lucid/main Packages +RPKG_STDOUT real_package = mock(:stdout => real_package_out,:exitstatus => 0) - @provider.should_receive(:shell_out!).with("aptitude show libmysqlclient15-dev").and_return(real_package) + @provider.should_receive(:shell_out!).with("apt-cache policy libmysqlclient-dev").and_return(real_package) @provider.should_not_receive(:run_command_with_systems_locale) @provider.load_current_resource end @@ -129,13 +147,36 @@ REALPKG_STDOUT it "should raise an exception if you specify a virtual package with multiple provider packages" do @new_resource.package_name("mp3-decoder") virtual_package_out=<<-VPKG_STDOUT -No current or candidate version found for mp3-decoder -Package: mp3-decoder -State: not a real package -Provided by: mpg123, mpg123-oss-i486, mpg321, opencubicplayer, vlc, vlc-nox +mp3-decoder: + Installed: (none) + Candidate: (none) + Version table: VPKG_STDOUT virtual_package = mock(:stdout => virtual_package_out,:exitstatus => 0) - @provider.should_receive(:shell_out!).with("aptitude show mp3-decoder").and_return(virtual_package) + @provider.should_receive(:shell_out!).with("apt-cache policy mp3-decoder").and_return(virtual_package) + showpkg_out=<<-SHOWPKG_STDOUT +Package: mp3-decoder +Versions: + +Reverse Depends: + nautilus,mp3-decoder + vux,mp3-decoder + plait,mp3-decoder + ecasound,mp3-decoder + nautilus,mp3-decoder +Dependencies: +Provides: +Reverse Provides: +vlc-nox 1.0.6-1ubuntu1.8 +vlc 1.0.6-1ubuntu1.8 +vlc-nox 1.0.6-1ubuntu1 +vlc 1.0.6-1ubuntu1 +opencubicplayer 1:0.1.17-2 +mpg321 0.2.10.6 +mpg123 1.12.1-0ubuntu1 +SHOWPKG_STDOUT + showpkg = mock(:stdout => showpkg_out,:exitstatus => 0) + @provider.should_receive(:shell_out!).with("apt-cache showpkg mp3-decoder").and_return(showpkg) lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package) end end |