diff --git a/lib/puppet/provider/package/pkgin.rb b/lib/puppet/provider/package/pkgin.rb index 5061cd3c9..5cdb858d5 100644 --- a/lib/puppet/provider/package/pkgin.rb +++ b/lib/puppet/provider/package/pkgin.rb @@ -1,62 +1,87 @@ require "puppet/provider/package" Puppet::Type.type(:package).provide :pkgin, :parent => Puppet::Provider::Package do desc "Package management using pkgin, a binary package manager for pkgsrc." commands :pkgin => "pkgin" - defaultfor :operatingsystem => :dragonfly + defaultfor :operatingsystem => [ :dragonfly , :smartos ] - has_feature :installable, :uninstallable + has_feature :installable, :uninstallable, :upgradeable, :versionable - def self.parse_pkgin_line(package, force_status=nil) + def self.parse_pkgin_line(package) # e.g. # vim-7.2.446 = Vim editor (vi clone) without GUI match, name, version, status = *package.match(/(\S+)-(\S+)(?: (=|>|<))?\s+.+$/) if match - ensure_status = if force_status - force_status - elsif status - :present - else - :absent - end - { :name => name, - :ensure => ensure_status, - :provider => :pkgin + :status => status, + :ensure => version } end end + def self.prefetch(packages) + super + # Withouth -f, no fresh pkg_summary files are downloaded + pkgin("-yf", :update) + end + def self.instances pkgin(:list).split("\n").map do |package| - new(parse_pkgin_line(package, :present)) + new(parse_pkgin_line(package)) end end def query + packages = parse_pkgsearch_line + + if packages.empty? + if @resource[:ensure] == :absent + notice "declared as absent but unavailable #{@resource.file}:#{resource.line}" + return false + else + @resource.fail "No candidate to be installed" + end + end + + packages.first.update( :ensure => :absent ) + end + + def parse_pkgsearch_line packages = pkgin(:search, resource[:name]).split("\n") - # Remove the last three lines of help text. - packages.slice!(-3, 3) + return [] if packages.length == 1 - matching_package = nil - packages.detect do |package| - properties = self.class.parse_pkgin_line(package) - matching_package = properties if properties && resource[:name] == properties[:name] - end + # Remove the last three lines of help text. + packages.slice!(-4, 4) - matching_package + pkglist = packages.map{ |line| self.class.parse_pkgin_line(line) } + pkglist.select{ |package| resource[:name] == package[:name] } end def install - pkgin("-y", :install, resource[:name]) + if String === @resource[:ensure] + pkgin("-y", :install, "#{resource[:name]}-#{resource[:ensure]}") + else + pkgin("-y", :install, resource[:name]) + end end def uninstall pkgin("-y", :remove, resource[:name]) end + + def latest + package = parse_pkgsearch_line.detect{ |package| package[:status] == '<' } + return properties[:ensure] if not package + return package[:ensure] + end + + def update + pkgin("-y", :install, resource[:name]) + end + end diff --git a/spec/unit/provider/package/pkgin_spec.rb b/spec/unit/provider/package/pkgin_spec.rb index c62ab685a..fe897eb3d 100644 --- a/spec/unit/provider/package/pkgin_spec.rb +++ b/spec/unit/provider/package/pkgin_spec.rb @@ -1,176 +1,177 @@ require "spec_helper" provider_class = Puppet::Type.type(:package).provider(:pkgin) describe provider_class do - let(:resource) { Puppet::Type.type(:package).new(:name => "vim") } + let(:resource) { Puppet::Type.type(:package).new(:name => "vim", :ensure => "7.2.446") } subject { provider_class.new(resource) } describe "Puppet provider interface" do it "can return the list of all packages" do provider_class.should respond_to(:instances) end end describe "#install" do - before { resource[:ensure] = :absent } + describe "a package not installed" do + before { resource[:ensure] = :absent } it "uses pkgin install to install" do - subject.expects(:pkgin).with("-y", :install, "vim") + subject.expects(:pkgin).with("-y", :install, "vim").once() + subject.install + end + end + + describe "a package with a fixed version" do + it "uses pkgin install to install a fixed version" do + subject.expects(:pkgin).with("-y", :install, "vim-7.2.446").once() subject.install end + end + end describe "#uninstall" do - before { resource[:ensure] = :present } - it "uses pkgin remove to uninstall" do - subject.expects(:pkgin).with("-y", :remove, "vim") + subject.expects(:pkgin).with("-y", :remove, "vim").once() subject.uninstall end end describe "#instances" do let(:pkgin_ls_output) do "zlib-1.2.3 General purpose data compression library\nzziplib-0.13.59 Library for ZIP archive handling\n" end before do provider_class.stubs(:pkgin).with(:list).returns(pkgin_ls_output) end it "returns an array of providers for each package" do instances = provider_class.instances instances.should have(2).items instances.each do |instance| instance.should be_a(provider_class) end end it "populates each provider with an installed package" do zlib_provider, zziplib_provider = provider_class.instances zlib_provider.get(:name).should == "zlib" - zlib_provider.get(:ensure).should == :present + zlib_provider.get(:ensure).should == "1.2.3" zziplib_provider.get(:name).should == "zziplib" - zziplib_provider.get(:ensure).should == :present + zziplib_provider.get(:ensure).should == "0.13.59" end end - describe "#query" do + describe "#latest" do before do provider_class.stubs(:pkgin).with(:search, "vim").returns(pkgin_search_output) end context "when the package is installed" do let(:pkgin_search_output) do "vim-7.2.446 = Vim editor (vi clone) without GUI\nvim-share-7.2.446 = Data files for the vim editor (vi clone)\n\n=: package is installed and up-to-date\n<: package is installed but newer version is available\n>: installed package has a greater version than available package\n" end - it "returns a hash stating the package is present" do - result = subject.query - result[:ensure].should == :present - result[:name].should == "vim" - result[:provider].should == :pkgin + it "returns installed version" do + subject.expects(:properties).returns( { :ensure => "7.2.446" } ) + subject.latest.should == "7.2.446" end end context "when the package is out of date" do let(:pkgin_search_output) do - "vim-7.2.446 < Vim editor (vi clone) without GUI\nvim-share-7.2.446 = Data files for the vim editor (vi clone)\n\n=: package is installed and up-to-date\n<: package is installed but newer version is available\n>: installed package has a greater version than available package\n" + "vim-7.2.447 < Vim editor (vi clone) without GUI\nvim-share-7.2.447 < Data files for the vim editor (vi clone)\n\n=: package is installed and up-to-date\n<: package is installed but newer version is available\n>: installed package has a greater version than available package\n" end - it "returns a hash stating the package is present" do - result = subject.query - result[:ensure].should == :present - result[:name].should == "vim" - result[:provider].should == :pkgin + it "returns the version to be installed" do + subject.latest.should == "7.2.447" end end context "when the package is ahead of date" do let(:pkgin_search_output) do - "vim-7.2.446 > Vim editor (vi clone) without GUI\nvim-share-7.2.446 = Data files for the vim editor (vi clone)\n\n=: package is installed and up-to-date\n<: package is installed but newer version is available\n>: installed package has a greater version than available package\n" + "vim-7.2.446 > Vim editor (vi clone) without GUI\nvim-share-7.2.446 > Data files for the vim editor (vi clone)\n\n=: package is installed and up-to-date\n<: package is installed but newer version is available\n>: installed package has a greater version than available package\n" end - it "returns a hash stating the package is present" do - result = subject.query - result[:ensure].should == :present - result[:name].should == "vim" - result[:provider].should == :pkgin + it "returns current version" do + subject.expects(:properties).returns( { :ensure => "7.2.446" } ) + subject.latest.should == "7.2.446" end end - context "when the package is not installed" do + context "when multiple candidates do exists" do let(:pkgin_search_output) do - "vim-7.2.446 Vim editor (vi clone) without GUI\nvim-share-7.2.446 = Data files for the vim editor (vi clone)\n\n=: package is installed and up-to-date\n<: package is installed but newer version is available\n>: installed package has a greater version than available package\n" + <<-SEARCH +vim-7.1 > Vim editor (vi clone) without GUI +vim-share-7.1 > Data files for the vim editor (vi clone) +vim-7.2.446 = Vim editor (vi clone) without GUI +vim-share-7.2.446 = Data files for the vim editor (vi clone) +vim-7.3 < Vim editor (vi clone) without GUI +vim-share-7.3 < Data files for the vim editor (vi clone) + +=: package is installed and up-to-date +<: package is installed but newer version is available +>: installed package has a greater version than available package +SEARCH end - it "returns a hash stating the package is present" do - result = subject.query - result[:ensure].should == :absent - result[:name].should == "vim" - result[:provider].should == :pkgin + it "returns the newest available version" do + provider_class.stubs(:pkgin).with(:search, "vim").returns(pkgin_search_output) + subject.latest.should == "7.3" end end context "when the package cannot be found" do let(:pkgin_search_output) do - "\n=: package is installed and up-to-date\n<: package is installed but newer version is available\n>: installed package has a greater version than available package\n" + "No results found for is-puppet" end it "returns nil" do - subject.query.should be_nil + expect { subject.latest }.to raise_error(Puppet::Error, "No candidate to be installed") end end end describe "#parse_pkgin_line" do context "with an installed package" do let(:package) { "vim-7.2.446 = Vim editor (vi clone) without GUI" } it "extracts the name and status" do - hash = provider_class.parse_pkgin_line(package) - hash[:name].should == "vim" - hash[:ensure].should == :present - hash[:provider].should == :pkgin + provider_class.parse_pkgin_line(package).should == { :name => "vim" , + :status => "=" , + :ensure => "7.2.446" } end end context "with an installed package with a hyphen in the name" do - let(:package) { "ruby18-puppet-0.25.5nb1 = Configuration management framework written in Ruby" } + let(:package) { "ruby18-puppet-0.25.5nb1 > Configuration management framework written in Ruby" } it "extracts the name and status" do - hash = provider_class.parse_pkgin_line(package) - hash[:name].should == "ruby18-puppet" - hash[:ensure].should == :present - hash[:provider].should == :pkgin + provider_class.parse_pkgin_line(package).should == { :name => "ruby18-puppet", + :status => ">" , + :ensure => "0.25.5nb1" } end end context "with a package not yet installed" do let(:package) { "vim-7.2.446 Vim editor (vi clone) without GUI" } it "extracts the name and status" do - hash = provider_class.parse_pkgin_line(package) - hash[:name].should == "vim" - hash[:ensure].should == :absent - hash[:provider].should == :pkgin + provider_class.parse_pkgin_line(package).should == { :name => "vim" , + :status => nil , + :ensure => "7.2.446" } end - it "extracts the name and an overridden status" do - hash = provider_class.parse_pkgin_line(package, :present) - hash[:name].should == "vim" - hash[:ensure].should == :present - hash[:provider].should == :pkgin - end end context "with an invalid package" do let(:package) { "" } it "returns nil" do provider_class.parse_pkgin_line(package).should be_nil end end end end