[Libguestfs] [PATCH 4/4] rpm: Choose providers better (RHBZ#1266918).
Pino Toscano
ptoscano at redhat.com
Tue Oct 13 13:16:48 UTC 2015
On Tuesday 13 October 2015 13:54:31 Richard W.M. Jones wrote:
> In the referenced bug, a customer had installed a web browser called
> 'palemoon'. The RPM of this web browser provides and requires various
> core libraries, such as:
>
> Provides: libnss3.so()(64bit) # normally provided by 'nss'
> Requires: libxul.so()(64bit) # normally provided by 'firefox'
>
> Our previous algorithm -- inherited from the days when we used to run
> 'rpm' commands -- takes every provider of a particular requirement and
> adds it to a big list, so if any other package requires
> 'libnss3.so()(64bit)', then both 'nss' and 'palemoon' are added to the
> package list.
>
> Yum used to handle this differently - it used to only pick the package
> with the shortest name. Later on, before yum was retired, it had a
> more complex decision algorithm described here:
> http://yum.baseurl.org/wiki/CompareProviders
>
> This change makes supermin use the shortest name algorithm, so in the
> case above, it always picks 'nss' over 'palemoon'.
>
> There is a second possible problem which is not fixed by the current
> patch set: If a package both provides and requires the same
> dependency, we should ignore that dependency. For example, 'palemoon'
> both Provides and Requires 'libxul.so()(64bit)', so if 'palemoon' is
> pulled in, then 'firefox' would not be an additional requirement.
> Because we store all the packages in a big list, we lose track of
> where a dependency originates from, so it is not easy to implement
> this second change.
> ---
> src/rpm.ml | 55 +++++++++++++++++++++++++++++++++++++++----------------
> 1 file changed, 39 insertions(+), 16 deletions(-)
>
> diff --git a/src/rpm.ml b/src/rpm.ml
> index 4d31472..d3ab7da 100644
> --- a/src/rpm.ml
> +++ b/src/rpm.ml
> @@ -210,8 +210,42 @@ let rpm_package_name pkg =
> let rpm_get_package_database_mtime () =
> (lstat "/var/lib/rpm/Packages").st_mtime
>
> -(* Memo of resolved provides. *)
> -let rpm_providers = Hashtbl.create 13
> +(* Return the best provider of a particular RPM requirement.
> + *
> + * There may be multiple, or no providers. In case there are multiple,
> + * choose the one with the shortest name (as yum used to).
> + *
> + * We could do better here: http://yum.baseurl.org/wiki/CompareProviders
> + *)
> +let provider =
> + (* Memo of resolved provides. *)
> + let rpm_providers = Hashtbl.create 13 in
> + fun req ->
> + try Hashtbl.find rpm_providers req
> + with Not_found ->
> + try
> + (* 'providers' here is an array of just package names. *)
> + let providers = rpm_pkg_whatprovides (get_rpm ()) req in
> + let providers = Array.to_list providers in
> + (* --whatprovides will return duplicate identical packages, so: *)
> + let providers = sort_uniq providers in
> + match providers with
> + | [] -> None
> + | [name] -> Some name
> + | names ->
> + if !settings.debug >= 2 then
> + printf "supermin: rpm: multiple providers: requirement %s: providers: %s\n"
> + req (String.concat " " names);
> + let cmp name1 name2 =
> + let len1 = String.length name1 and len2 = String.length name2 in
> + if len1 <> len2 then compare len1 len2
> + else compare name1 name2 in
> + let names = List.sort cmp names in
> + let best_name = List.hd names in
> + if !settings.debug >= 2 then
> + printf "supermin: rpm: multiple providers: picked %s\n" best_name;
> + Some best_name
> + with Not_found -> None
This is nicer indeed, although there are two issues:
- the caching of providers (rpm_providers) is not done, so it will do
the search every time (and things like "/bin/sh provided by bash"
appear a lot in packages)
- the old code was checking each provided name was really a package
(using rpm_package_of_string). The new code should then pick the
first one in the list that is actually installed (i.e. with a Some
result of rpm_package_of_string); the two cases
| + | [name] -> Some name
| + | names ->
could be joined together, printing the debug output only if there is
more than one element. I hope List.sort on one element should be a
no-op...
Thanks,
--
Pino Toscano
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part.
URL: <http://listman.redhat.com/archives/libguestfs/attachments/20151013/04f67104/attachment.sig>
More information about the Libguestfs
mailing list