summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGordon Malm <gmalm+github-chef-chef-2018@engineyard.com>2018-03-21 23:09:22 +0000
committerGordon Malm <gmalm+github-chef-chef-2018@engineyard.com>2018-03-21 23:09:22 +0000
commit03fffdcd91b71ee0ff346310c5c9616976ca3f1b (patch)
tree053289f164b69774a7f0e5fd1c299b500f66093f
parent50958e958a41f23fb75e9b3c3c9f4c0b519ae295 (diff)
downloadchef-03fffdcd91b71ee0ff346310c5c9616976ca3f1b.tar.gz
Rewrite candidate_version determination for increased speed, reduced
sensitivity to upstream changes, reduced complexity. Currently Chef determines this by parsing 'emerge'. This change results in a large speed increase for Gentoo-based systems. Reference: https://github.com/chef/chef/issues/7026 Signed-off-by: Gordon Malm <gmalm+github-chef-chef-2018@engineyard.com>
-rw-r--r--lib/chef/provider/package/portage.rb58
1 files changed, 26 insertions, 32 deletions
diff --git a/lib/chef/provider/package/portage.rb b/lib/chef/provider/package/portage.rb
index e43e71f210..936707911e 100644
--- a/lib/chef/provider/package/portage.rb
+++ b/lib/chef/provider/package/portage.rb
@@ -59,46 +59,40 @@ class Chef
current_resource
end
- def parse_emerge(package, txt)
- availables = {}
- found_package_name = nil
-
- txt.each_line do |line|
- if line =~ /\*\s+#{PACKAGE_NAME_PATTERN}/
- found_package_name = $&.delete("*").strip
- if package =~ /\// # the category is specified
- if found_package_name == package
- availables[found_package_name] = nil
- end
- else # the category is not specified
- if found_package_name.split("/").last == package
- availables[found_package_name] = nil
- end
+ def raise_error_for_query(msg)
+ raise Chef::Exceptions::Package, "Query for '#{new_resource.package_name}' #{msg}"
+ end
+
+ def candidate_version
+ return @candidate_version if @candidate_version
+
+ pkginfo = shell_out_compact("portageq", "best_visible", "/", new_resource.package_name)
+
+ if pkginfo.exitstatus != 0
+ pkginfo.stderr.each_line do |line|
+ if line =~ /[Uu]nqualified atom .*match.* multiple/
+ raise_error_for_query("matched multiple packages (please specify a category):\n#{pkginfo.inspect}")
end
end
- if line =~ /Latest version available: (.*)/ && availables.key?(found_package_name)
- availables[found_package_name] = $1.strip
+ if pkginfo.stdout.strip.empty?
+ raise_error_for_query("did not find a matching package:\n#{pkginfo.inspect}")
end
- end
- if availables.size > 1
- # shouldn't happen if a category is specified so just use `package`
- raise Chef::Exceptions::Package, "Multiple emerge results found for #{package}: #{availables.keys.join(' ')}. Specify a category."
+ raise_error_for_query("resulted in an unknown error:\n#{pkginfo.inspect}")
end
- availables.values.first
- end
-
- def candidate_version
- return @candidate_version if @candidate_version
-
- status = shell_out_compact("emerge", "--color", "n", "--nospinner", "--search", new_resource.package_name.split("/").last)
- available, installed = parse_emerge(new_resource.package_name, status.stdout)
- @candidate_version = available
+ if pkginfo.stdout.lines.count > 1
+ raise_error_for_query("produced unexpected output (multiple lines):\n#{pkginfo.inspect}")
+ end
- unless status.exitstatus == 0
- raise Chef::Exceptions::Package, "emerge --search failed - #{status.inspect}!"
+ pkginfo.stdout.chomp!
+ if pkginfo.stdout =~ /-r[[:digit:]]+$/
+ # Latest/Best version of the package is a revision (-rX).
+ @candidate_version = pkginfo.stdout.split(/(?<=-)/).last(2).join
+ else
+ # Latest/Best version of the package is NOT a revision (-rX).
+ @candidate_version = pkginfo.stdout.split('-').last
end
@candidate_version