Skip to content

Commit 33d73a5

Browse files
danpdanielsdeleo
authored andcommitted
Improve for CHEF-1575 based on ticket discussion
1 parent aa933d4 commit 33d73a5

2 files changed

Lines changed: 158 additions & 26 deletions

File tree

chef/lib/chef/provider/package/portage.rb

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,44 +24,59 @@ class Chef
2424
class Provider
2525
class Package
2626
class Portage < Chef::Provider::Package
27+
PACKAGE_NAME_PATTERN = %r{(([^/]+)/)?([^/]+)}
2728

2829
def load_current_resource
2930
@current_resource = Chef::Resource::Package.new(@new_resource.name)
3031
@current_resource.package_name(@new_resource.package_name)
3132

3233
@current_resource.version(nil)
3334

34-
_, category_with_slash, category, pkg = %r{^(([^/]+)+/)?([^/]+)$}.match(@new_resource.package_name).to_a
35+
_, category_with_slash, category, pkg = %r{^#{PACKAGE_NAME_PATTERN}$}.match(@new_resource.package_name).to_a
3536

36-
possibilities = Dir["/var/db/pkg/#{category || "*"}/#{pkg}-*"].map {|d| ::File.basename(d) }
37-
possibilities.each do |entry|
38-
if(entry =~ /^#{Regexp.escape(pkg)}\-(\d[\.\d]*((_(alpha|beta|pre|rc|p)\d*)*)?(-r\d+)?)/)
39-
@current_resource.version($1)
40-
Chef::Log.debug("Got current version #{$1}")
41-
break
37+
possibilities = Dir["/var/db/pkg/#{category || "*"}/#{pkg}-*"].map {|d| d.sub(%r{/var/db/pkg/}, "") }
38+
versions = possibilities.map do |entry|
39+
if(entry =~ %r{[^/]+/#{Regexp.escape(pkg)}\-(\d[\.\d]*((_(alpha|beta|pre|rc|p)\d*)*)?(-r\d+)?)})
40+
[$&, $1]
4241
end
42+
end.compact
43+
44+
if versions.size > 1
45+
atoms = versions.map {|v| v.first }.sort
46+
raise Chef::Exceptions::Package, "Multiple packages found for #{@new_resource.package_name}: #{atoms.join(" ")}. Specify a category."
47+
elsif versions.size == 1
48+
@current_resource.version(versions.first.last)
49+
Chef::Log.debug("Got current version #{$1}")
4350
end
4451

4552
@current_resource
4653
end
4754

4855

4956
def parse_emerge(package, txt)
50-
available, installed, pkg = nil
57+
availables = {}
58+
package_without_category = package.split("/").last
59+
found_package_name = nil
60+
5161
txt.each do |line|
52-
if line =~ /\*(.*)/
53-
pkg = $1.strip
54-
end
55-
if (pkg == package) || (pkg.split('/').last == package rescue false)
56-
if line =~ /Latest version available: (.*)/
57-
available = $1
58-
elsif line =~ /Latest version installed: (.*)/
59-
installed = $1
62+
if line =~ /\*\s+#{PACKAGE_NAME_PATTERN}/
63+
found_package_name = $&.strip
64+
if found_package_name == package || found_package_name.split("/").last == package_without_category
65+
availables[found_package_name] = nil
6066
end
6167
end
68+
69+
if line =~ /Latest version available: (.*)/ && availables.has_key?(found_package_name)
70+
availables[found_package_name] = $1.strip
71+
end
6272
end
63-
available = installed unless available
64-
[available, installed]
73+
74+
if availables.size > 1
75+
# shouldn't happen if a category is specified so just use `package`
76+
raise Chef::Exceptions::Package, "Multiple emerge results found for #{package}: #{availables.keys.join(" ")}. Specify a category."
77+
end
78+
79+
availables.values.first
6580
end
6681

6782
def candidate_version

chef/spec/unit/provider/package/portage_spec.rb

Lines changed: 125 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,27 +74,144 @@
7474
@provider.load_current_resource
7575
@provider.current_resource.version.should be_nil
7676
end
77+
78+
it "should throw an exception if a category isn't specified and multiple packages are found" do
79+
::Dir.stub!(:[]).with("/var/db/pkg/*/git-*").and_return(["/var/db/pkg/dev-util/git-1.0.0", "/var/db/pkg/funny-words/git-1.0.0"])
80+
@provider = Chef::Provider::Package::Portage.new(@new_resource_without_category, @run_context)
81+
lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package)
82+
end
7783
end
7884

7985
describe "once the state of the package is known" do
8086

8187
describe Chef::Provider::Package::Portage, "candidate_version" do
82-
it "should return the candidate_version variable if already setup" do
88+
it "should return the candidate_version variable if already set" do
8389
@provider.candidate_version = "1.0.0"
8490
@provider.should_not_receive(:popen4)
8591
@provider.candidate_version
8692
end
8793

88-
it "should lookup the candidate_version if the variable is not already set" do
89-
@status = mock("Status", :exitstatus => 0)
94+
it "should throw an exception if the exitstatus is not 0" do
95+
@status = mock("Status", :exitstatus => 1)
9096
@provider.stub!(:popen4).and_return(@status)
91-
@provider.should_receive(:popen4)
92-
@provider.candidate_version
97+
lambda { @provider.candidate_version }.should raise_error(Chef::Exceptions::Package)
9398
end
9499

95-
it "should throw and exception if the exitstatus is not 0" do
96-
@status = mock("Status", :exitstatus => 1)
97-
@provider.stub!(:popen4).and_return(@status)
100+
it "should find the candidate_version if a category is specifed and there are no duplicates" do
101+
output = <<EOF
102+
Searching...
103+
[ Results for search key : git ]
104+
[ Applications found : 14 ]
105+
106+
* app-misc/digitemp [ Masked ]
107+
Latest version available: 3.5.0
108+
Latest version installed: [ Not Installed ]
109+
Size of files: 261 kB
110+
Homepage: http://www.digitemp.com/ http://www.ibutton.com/
111+
Description: Temperature logging and reporting using Dallas Semiconductor's iButtons and 1-Wire protocol
112+
License: GPL-2
113+
114+
* dev-util/git
115+
Latest version available: 1.6.0.6
116+
Latest version installed: ignore
117+
Size of files: 2,725 kB
118+
Homepage: http://git.or.cz/
119+
Description: GIT - the stupid content tracker, the revision control system heavily used by the Linux kernel team
120+
License: GPL-2
121+
122+
* dev-util/gitosis [ Masked ]
123+
Latest version available: 0.2_p20080825
124+
Latest version installed: [ Not Installed ]
125+
Size of files: 31 kB
126+
Homepage: http://eagain.net/gitweb/?p=gitosis.git;a=summary
127+
Description: gitosis -- software for hosting git repositories
128+
License: GPL-2
129+
EOF
130+
131+
@status = mock("Status", :exitstatus => 0)
132+
@provider.should_receive(:popen4).and_yield(nil, nil, StringIO.new(output), nil).and_return(@status)
133+
@provider.candidate_version.should == "1.6.0.6"
134+
end
135+
136+
it "should find the candidate_version if a category is not specifed and there are no duplicates" do
137+
output = <<EOF
138+
Searching...
139+
[ Results for search key : git ]
140+
[ Applications found : 14 ]
141+
142+
* app-misc/digitemp [ Masked ]
143+
Latest version available: 3.5.0
144+
Latest version installed: [ Not Installed ]
145+
Size of files: 261 kB
146+
Homepage: http://www.digitemp.com/ http://www.ibutton.com/
147+
Description: Temperature logging and reporting using Dallas Semiconductor's iButtons and 1-Wire protocol
148+
License: GPL-2
149+
150+
* dev-util/git
151+
Latest version available: 1.6.0.6
152+
Latest version installed: ignore
153+
Size of files: 2,725 kB
154+
Homepage: http://git.or.cz/
155+
Description: GIT - the stupid content tracker, the revision control system heavily used by the Linux kernel team
156+
License: GPL-2
157+
158+
* dev-util/gitosis [ Masked ]
159+
Latest version available: 0.2_p20080825
160+
Latest version installed: [ Not Installed ]
161+
Size of files: 31 kB
162+
Homepage: http://eagain.net/gitweb/?p=gitosis.git;a=summary
163+
Description: gitosis -- software for hosting git repositories
164+
License: GPL-2
165+
EOF
166+
167+
@status = mock("Status", :exitstatus => 0)
168+
@provider = Chef::Provider::Package::Portage.new(@new_resource_without_category, @run_context)
169+
@provider.should_receive(:popen4).and_yield(nil, nil, StringIO.new(output), nil).and_return(@status)
170+
@provider.candidate_version.should == "1.6.0.6"
171+
end
172+
173+
it "should throw an exception if a category is not specified and there are duplicates" do
174+
output = <<EOF
175+
Searching...
176+
[ Results for search key : git ]
177+
[ Applications found : 14 ]
178+
179+
* app-misc/digitemp [ Masked ]
180+
Latest version available: 3.5.0
181+
Latest version installed: [ Not Installed ]
182+
Size of files: 261 kB
183+
Homepage: http://www.digitemp.com/ http://www.ibutton.com/
184+
Description: Temperature logging and reporting using Dallas Semiconductor's iButtons and 1-Wire protocol
185+
License: GPL-2
186+
187+
* app-misc/git
188+
Latest version available: 4.3.20
189+
Latest version installed: [ Not Installed ]
190+
Size of files: 416 kB
191+
Homepage: http://www.gnu.org/software/git/
192+
Description: GNU Interactive Tools - increase speed and efficiency of most daily task
193+
License: GPL-2
194+
195+
* dev-util/git
196+
Latest version available: 1.6.0.6
197+
Latest version installed: ignore
198+
Size of files: 2,725 kB
199+
Homepage: http://git.or.cz/
200+
Description: GIT - the stupid content tracker, the revision control system heavily used by the Linux kernel team
201+
License: GPL-2
202+
203+
* dev-util/gitosis [ Masked ]
204+
Latest version available: 0.2_p20080825
205+
Latest version installed: [ Not Installed ]
206+
Size of files: 31 kB
207+
Homepage: http://eagain.net/gitweb/?p=gitosis.git;a=summary
208+
Description: gitosis -- software for hosting git repositories
209+
License: GPL-2
210+
EOF
211+
212+
@status = mock("Status", :exitstatus => 0)
213+
@provider = Chef::Provider::Package::Portage.new(@new_resource_without_category, @run_context)
214+
@provider.should_receive(:popen4).and_yield(nil, nil, StringIO.new(output), nil).and_return(@status)
98215
lambda { @provider.candidate_version }.should raise_error(Chef::Exceptions::Package)
99216
end
100217

0 commit comments

Comments
 (0)