diff options
author | Phil Dibowitz <phil@ipom.com> | 2014-12-19 19:03:44 -0800 |
---|---|---|
committer | Phil Dibowitz <phil@ipom.com> | 2015-02-03 19:32:35 -0800 |
commit | 36ce3c58d7deb3467858ff7aefb05c819be9c416 (patch) | |
tree | 7832a6cb8c4581cd699fa09487bd75a384e67607 /lib/chef/provider/package/apt.rb | |
parent | 23cb1c709d83f1476e6a155a2ec8d0cdde14c0f9 (diff) | |
download | chef-36ce3c58d7deb3467858ff7aefb05c819be9c416.tar.gz |
Multipackge support
Allow the `package` provider to take an array of packages to handle in one
transaction.
This solves two large problems:
* There are times when you cannot install two packages in sequence, like when a
binary is moving between two packages - they *must* be done in the same
transaction.
* When using Chef to install the vast majority of your base system, it
can make imaging take a very, very long time because executing yum or apt once
for every single package is painfully slow.
This solves both. The scaffolding is all there in the Package HWRP, plus the
underlying implementation for both apt and yum, the two I have access to test.
Diffstat (limited to 'lib/chef/provider/package/apt.rb')
-rw-r--r-- | lib/chef/provider/package/apt.rb | 137 |
1 files changed, 93 insertions, 44 deletions
diff --git a/lib/chef/provider/package/apt.rb b/lib/chef/provider/package/apt.rb index fd132c817c..099a4a9b61 100644 --- a/lib/chef/provider/package/apt.rb +++ b/lib/chef/provider/package/apt.rb @@ -51,54 +51,89 @@ class Chef end def check_package_state(package) - Chef::Log.debug("#{@new_resource} checking package status for #{package}") - installed = false - - shell_out!("apt-cache#{expand_options(default_release_options)} policy #{package}", :timeout => @new_resource.timeout).stdout.each_line do |line| - case line - 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}", :timeout => @new_resource.timeout).stdout - providers = Hash.new - # Returns all lines after 'Reverse Provides:' - showpkg.rpartition(/Reverse Provides:\s*#{$/}/)[2].each_line do |line| - provider, version = line.split - providers[provider] = version + if package.is_a?(Array) + final_installed_version = [] + final_candidate_version = [] + final_installed = [] + final_virtual = [] + end + installed = virtual = false + installed_version = candidate_version = nil + + [package].flatten.each do |pkg| + installed = virtual = false + installed_version = candidate_version = nil + shell_out!("apt-cache#{expand_options(default_release_options)} policy #{pkg}").stdout.each_line do |line| + case line + when /^\s{2}Installed: (.+)$/ + installed_version = $1 + if installed_version == '(none)' + Chef::Log.debug("#{@new_resource} current version is nil") + installed_version = nil + else + Chef::Log.debug("#{@new_resource} current version is #{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 + virtual = 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}") 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 end + if package.is_a?(Array) + final_installed_version << installed_version + final_candidate_version << candidate_version + final_installed << installed + final_virtual << virtual + else + final_installed_version = installed_version + final_candidate_version = candidate_version + final_installed = installed + final_virtual = virtual + end end - - return installed + @candidate_version = final_candidate_version + @current_resource.version(final_installed_version) + @is_virtual_package = final_virtual + + return final_installed.is_a?(Array) ? final_installed.any? : final_installed end def install_package(name, version) - package_name = "#{name}=#{version}" - package_name = name if @is_virtual_package + if name.is_a?(Array) + index = 0 + package_name = name.zip(version).map do |x, y| + namestr = nil + if @is_virtual_package[index] + namestr = x + else + namestr = "#{x}=#{y}" + end + index += 1 + namestr + end.join(' ') + else + package_name = "#{name}=#{version}" + package_name = name if @is_virtual_package + end run_noninteractive("apt-get -q -y#{expand_options(default_release_options)}#{expand_options(@new_resource.options)} install #{package_name}") end @@ -107,12 +142,21 @@ class Chef end def remove_package(name, version) - package_name = "#{name}" + if name.is_a?(Array) + package_name = name.join(' ') + else + package_name = name + end run_noninteractive("apt-get -q -y#{expand_options(@new_resource.options)} remove #{package_name}") end def purge_package(name, version) - run_noninteractive("apt-get -q -y#{expand_options(@new_resource.options)} purge #{@new_resource.package_name}") + if name.is_a?(Array) + package_name = name.join(' ') + else + package_name = "#{name}" + end + run_noninteractive("apt-get -q -y#{expand_options(@new_resource.options)} purge #{package_name}") end def preseed_package(preseed_file) @@ -121,8 +165,13 @@ class Chef end def reconfig_package(name, version) + if name.is_a?(Array) + package_name = name.join(' ') + else + package_name = "#{name}" + end Chef::Log.info("#{@new_resource} reconfiguring") - run_noninteractive("dpkg-reconfigure #{name}") + run_noninteractive("dpkg-reconfigure #{package_name}") end private |