diff options
author | Gordon Malm <gmalm+github-chef-chef-2018@engineyard.com> | 2018-03-21 23:09:22 +0000 |
---|---|---|
committer | Gordon Malm <gmalm+github-chef-chef-2018@engineyard.com> | 2018-03-21 23:09:22 +0000 |
commit | 03fffdcd91b71ee0ff346310c5c9616976ca3f1b (patch) | |
tree | 053289f164b69774a7f0e5fd1c299b500f66093f | |
parent | 50958e958a41f23fb75e9b3c3c9f4c0b519ae295 (diff) | |
download | chef-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.rb | 58 |
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 |