summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIngo Becker <ingo@orgizm.net>2018-11-23 17:19:15 +0100
committerTim Smith <tsmith84@gmail.com>2020-04-20 12:21:28 -0700
commitca0c6371fe884753c9f1303f49dfc2142f3c0cd5 (patch)
tree0e3d020fa5d1aabeef22d958e66cf3c804aaf0e1
parent9b1744ec6a8eaf2be5aad1b4e3445ea98dd15e03 (diff)
downloadchef-ca0c6371fe884753c9f1303f49dfc2142f3c0cd5.tar.gz
added multipackage support for pacman resource
Signed-off-by: Ingo Becker <ingo@orgizm.net>
-rw-r--r--lib/chef/provider/package/pacman.rb57
-rw-r--r--spec/unit/provider/package/pacman_spec.rb212
2 files changed, 88 insertions, 181 deletions
diff --git a/lib/chef/provider/package/pacman.rb b/lib/chef/provider/package/pacman.rb
index a3b2d75846..18206c4cc9 100644
--- a/lib/chef/provider/package/pacman.rb
+++ b/lib/chef/provider/package/pacman.rb
@@ -27,29 +27,12 @@ class Chef
provides :package, platform: "arch"
provides :pacman_package
+ use_multipackage_api
+
def load_current_resource
@current_resource = Chef::Resource::Package.new(new_resource.name)
current_resource.package_name(new_resource.package_name)
-
- logger.trace("#{new_resource} checking pacman for #{new_resource.package_name}")
- status = shell_out("pacman", "-Qi", new_resource.package_name)
- status.stdout.each_line do |line|
- case line
- when /^Version(\s?)*: (.+)$/
- logger.trace("#{new_resource} current version is #{$2}")
- current_resource.version($2)
- end
- end
-
- unless status.exitstatus == 0 || status.exitstatus == 1
- raise Chef::Exceptions::Package, "pacman failed - #{status.inspect}!"
- end
-
- current_resource
- end
-
- def candidate_version
- return @candidate_version if @candidate_version
+ current_resource.version = []
repos = %w{extra core community}
@@ -58,31 +41,37 @@ class Chef
repos = pacman.scan(/\[(.+)\]/).flatten
end
- package_repos = repos.map { |r| Regexp.escape(r) }.join("|")
-
+ repos = repos.map { |r| Regexp.escape(r) }.join("|")
status = shell_out("pacman", "-Sl")
- status.stdout.each_line do |line|
- case line
- when /^(#{package_repos}) #{Regexp.escape(new_resource.package_name)} (.+)$/
- # $2 contains a string like "4.4.0-1" or "3.10-4 [installed]"
- # simply split by space and use first token
- @candidate_version = $2.split(" ").first
- end
- end
unless status.exitstatus == 0 || status.exitstatus == 1
raise Chef::Exceptions::Package, "pacman failed - #{status.inspect}!"
end
- unless @candidate_version
- raise Chef::Exceptions::Package, "pacman does not have a version of package #{new_resource.package_name}"
+ pkg_db_data = status.stdout
+ @candidate_version = []
+ package_name_array.each do |pkg|
+ pkg_data = pkg_db_data.match(/(#{repos}) #{pkg} (?<candidate>.*?-[0-9]+)(?<installed> \[.*?( (?<current>.*?-[0-9]+))?\])?\n/m)
+ unless pkg_data
+ raise Chef::Exceptions::Package, "pacman does not have a version of package #{pkg}"
+ end
+ @candidate_version << pkg_data[:candidate]
+ if pkg_data[:installed]
+ current_resource.version << (pkg_data[:current] || pkg_data[:candidate])
+ else
+ current_resource.version << nil
+ end
end
+ current_resource
+ end
+
+ def candidate_version
@candidate_version
end
def install_package(name, version)
- shell_out!( "pacman", "--sync", "--noconfirm", "--noprogressbar", options, name)
+ shell_out!("pacman", "--sync", "--noconfirm", "--noprogressbar", options, *name)
end
def upgrade_package(name, version)
@@ -90,7 +79,7 @@ class Chef
end
def remove_package(name, version)
- shell_out!( "pacman", "--remove", "--noconfirm", "--noprogressbar", options, name )
+ shell_out!("pacman", "--remove", "--noconfirm", "--noprogressbar", options, *name)
end
def purge_package(name, version)
diff --git a/spec/unit/provider/package/pacman_spec.rb b/spec/unit/provider/package/pacman_spec.rb
index c869992a0f..2e2a3f7763 100644
--- a/spec/unit/provider/package/pacman_spec.rb
+++ b/spec/unit/provider/package/pacman_spec.rb
@@ -15,179 +15,97 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-
require "spec_helper"
-describe Chef::Provider::Package::Pacman do
+def create_provider_for(name)
+ @new_resource = Chef::Resource::Package.new(name)
+ provider = Chef::Provider::Package::Pacman.new(@new_resource, @run_context)
+ allow(provider).to receive(:shell_out_compacted).and_return(@status)
+ provider
+end
+
+RSpec.shared_examples "current_resource" do |pkg, version, candidate|
+ let(:current_resource) { @provider.load_current_resource }
before(:each) do
- @node = Chef::Node.new
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::Package.new("nano")
- @current_resource = Chef::Resource::Package.new("nano")
-
- @status = double(stdout: "", exitstatus: 0)
- @provider = Chef::Provider::Package::Pacman.new(@new_resource, @run_context)
- allow(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
-
- allow(@provider).to receive(:shell_out_compacted).and_return(@status)
- @stdin = StringIO.new
- @stdout = StringIO.new(<<~ERR)
- error: package "nano" not found
- ERR
- @stderr = StringIO.new
- @pid = 2342
+ @provider = create_provider_for(pkg)
end
- describe "when determining the current package state" do
- it "should create a current resource with the name of the new_resource" do
- expect(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
- @provider.load_current_resource
- end
-
- it "should set the current resources package name to the new resources package name" do
- expect(@current_resource).to receive(:package_name).with(@new_resource.package_name)
- @provider.load_current_resource
- end
-
- it "should run pacman query with the package name" do
- expect(@provider).to receive(:shell_out_compacted).with("pacman", "-Qi", @new_resource.package_name, { timeout: 900 }).and_return(@status)
- @provider.load_current_resource
- end
-
- it "should read stdout on pacman" do
- allow(@provider).to receive(:shell_out_compacted).and_return(@status)
- @provider.load_current_resource
- end
-
- it "should set the installed version to nil on the current resource if pacman installed version not exists" do
- allow(@provider).to receive(:shell_out_compacted).and_return(@status)
- @provider.load_current_resource
- end
-
- it "should set the installed version if pacman has one" do
- stdout = <<~PACMAN
- Name : nano
- Version : 2.2.2-1
- URL : http://www.nano-editor.org
- Licenses : GPL
- Groups : base
- Provides : None
- Depends On : glibc ncurses
- Optional Deps : None
- Required By : None
- Conflicts With : None
- Replaces : None
- Installed Size : 1496.00 K
- Packager : Andreas Radke <andyrtr@archlinux.org>
- Architecture : i686
- Build Date : Mon 18 Jan 2010 06:16:16 PM CET
- Install Date : Mon 01 Feb 2010 10:06:30 PM CET
- Install Reason : Explicitly installed
- Install Script : Yes
- Description : Pico editor clone with enhancements
- PACMAN
-
- status = double(stdout: stdout, exitstatus: 0)
- allow(@provider).to receive(:shell_out_compacted).and_return(status)
- @provider.load_current_resource
- expect(@current_resource.version).to eq("2.2.2-1")
- end
-
- it "should set the candidate version if pacman has one" do
- status = double(stdout: "core nano 2.2.3-1", exitstatus: 0)
- allow(@provider).to receive(:shell_out_compacted).and_return(status)
- @provider.load_current_resource
- expect(@provider.candidate_version).to eql("2.2.3-1")
- end
-
- it "should use pacman.conf to determine valid repo names for package versions" do
- @pacman_conf = <<~PACMAN_CONF
- [options]
- HoldPkg = pacman glibc
- Architecture = auto
+ it "sets current_resource name" do
+ expect(current_resource.package_name).to eql(pkg)
+ end
- [customrepo]
- Server = https://my.custom.repo
+ it "sets current_resource version" do
+ expect(current_resource.version).to eql(version)
+ end
- [core]
- Include = /etc/pacman.d/mirrorlist
+ it "sets candidate version" do
+ current_resource
+ expect(@provider.candidate_version).to eql(candidate)
+ end
+end
- [extra]
- Include = /etc/pacman.d/mirrorlist
+describe Chef::Provider::Package::Pacman do
+ before(:each) do
+ @node = Chef::Node.new
+ @events = Chef::EventDispatch::Dispatcher.new
+ @run_context = Chef::RunContext.new(@node, {}, @events)
+ @pacman_conf = <<~PACMAN_CONF
+ [options]
+ HoldPkg = pacman glibc
+ Architecture = auto
- [community]
- Include = /etc/pacman.d/mirrorlist
- PACMAN_CONF
+ [customrepo]
+ Server = https://my.custom.repo
- status = double(stdout: "customrepo nano 1.2.3-4", exitstatus: 0)
- allow(::File).to receive(:exist?).with("/etc/pacman.conf").and_return(true)
- allow(::File).to receive(:read).with("/etc/pacman.conf").and_return(@pacman_conf)
- allow(@provider).to receive(:shell_out_compacted).and_return(status)
+ [core]
+ Include = /etc/pacman.d/mirrorlist
- @provider.load_current_resource
- expect(@provider.candidate_version).to eql("1.2.3-4")
- end
+ [extra]
+ Include = /etc/pacman.d/mirrorlist
- it "should raise an exception if pacman fails" do
- expect(@status).to receive(:exitstatus).and_return(2)
- expect { @provider.load_current_resource }.to raise_error(Chef::Exceptions::Package)
- end
+ [community]
+ Include = /etc/pacman.d/mirrorlist
+ PACMAN_CONF
- it "should not raise an exception if pacman succeeds" do
- expect(@status).to receive(:exitstatus).and_return(0)
- expect { @provider.load_current_resource }.not_to raise_error
- end
+ allow(::File).to receive(:exist?).with("/etc/pacman.conf").and_return(true)
+ allow(::File).to receive(:read).with("/etc/pacman.conf").and_return(@pacman_conf)
- it "should raise an exception if pacman does not return a candidate version" do
- allow(@provider).to receive(:shell_out_compacted).and_return(@status)
- expect { @provider.candidate_version }.to raise_error(Chef::Exceptions::Package)
- end
+ pacman_out = <<~PACMAN_OUT
+ extra nano 3.450-1
+ extra emacs 0.12.0-1 [installed]
+ core sed 3.234-2 [installed: 3.234-1]
+ PACMAN_OUT
+ @status = double(stdout: pacman_out, exitstatus: 0)
- it "should return the current resouce" do
- expect(@provider.load_current_resource).to eql(@current_resource)
- end
end
- describe Chef::Provider::Package::Pacman, "install_package" do
- it "should run pacman install with the package name and version" do
- expect(@provider).to receive(:shell_out_compacted!).with("pacman", "--sync", "--noconfirm", "--noprogressbar", "nano", { timeout: 900 })
- @provider.install_package("nano", "1.0")
- end
-
- it "should run pacman install with the package name and version and options if specified" do
- expect(@provider).to receive(:shell_out_compacted!).with("pacman", "--sync", "--noconfirm", "--noprogressbar", "--debug", "nano", { timeout: 900 })
- @new_resource.options("--debug")
+ describe "loading the current resource" do
- @provider.install_package("nano", "1.0")
+ describe "for an existing and installed but upgradable package" do
+ include_examples "current_resource", ["sed"], ["3.234-1"], ["3.234-2"]
end
- end
- describe Chef::Provider::Package::Pacman, "upgrade_package" do
- it "should run install_package with the name and version" do
- expect(@provider).to receive(:install_package).with("nano", "1.0")
- @provider.upgrade_package("nano", "1.0")
+ describe "for an existing and installed package" do
+ include_examples "current_resource", ["emacs"], ["0.12.0-1"], ["0.12.0-1"]
end
- end
- describe Chef::Provider::Package::Pacman, "remove_package" do
- it "should run pacman remove with the package name" do
- expect(@provider).to receive(:shell_out_compacted!).with("pacman", "--remove", "--noconfirm", "--noprogressbar", "nano", { timeout: 900 })
- @provider.remove_package("nano", "1.0")
+ describe "for an existing non installed package" do
+ include_examples "current_resource", ["nano"], [nil], ["3.450-1"]
end
- it "should run pacman remove with the package name and options if specified" do
- expect(@provider).to receive(:shell_out_compacted!).with("pacman", "--remove", "--noconfirm", "--noprogressbar", "--debug", "nano", { timeout: 900 })
- @new_resource.options("--debug")
-
- @provider.remove_package("nano", "1.0")
+ describe "for a non existing and an upgradable package" do
+ include_examples "current_resource", %w{nano sed}, [nil, "3.234-1"], ["3.450-1", "3.234-2"]
end
- end
- describe Chef::Provider::Package::Pacman, "purge_package" do
- it "should run remove_package with the name and version" do
- expect(@provider).to receive(:remove_package).with("nano", "1.0")
- @provider.purge_package("nano", "1.0")
+ describe "for a non existing package" do
+ let(:current_resource) { @provider.load_current_resource }
+ before(:each) do
+ @provider = create_provider_for("vim")
+ end
+
+ it "raises an error" do
+ expect { current_resource }.to raise_error(Chef::Exceptions::Package)
+ end
end
end