Subject: [bug#50878] [PATCH] union: Resolve collisions by stable-sort'ing them.

From: Liliana Marie Prikler <[email-masked]>
Date: Wed, 29 Sep 2021 19:42:57 +0200

Hi,

Am Dienstag, den 28.09.2021, 23:40 +0200 schrieb Attila Lendvai:
> [...]
> index 961ac3298b..747902ec6c 100644
> --- a/guix/build/union.scm
> +++ b/guix/build/union.scm
> @@ -23,11 +23,12 @@
>    #:use-module (ice-9 format)
>    #:use-module (srfi srfi-1)
>    #:use-module (srfi srfi-26)
> +  #:use-module (srfi srfi-43)
>    #:use-module (rnrs bytevectors)
>    #:use-module (rnrs io ports)
>    #:export (union-build
>  
> -            warn-about-collision
> +            default-collision-resolver
>  
>              relative-file-name
>              symlink-relative))
> @@ -102,10 +103,23 @@ identical, #f otherwise."
>    ;; applications via 'glib-or-gtk-build-system'.
>    '("icon-theme.cache" "gschemas.compiled"))
>  
> -(define (warn-about-collision files)
> -  "Handle the collision among FILES by emitting a warning and
> choosing the
> -first one of THEM."
> -  (let ((file (first files)))
> +(define (resolve-collision/alphanumeric-last files)
> +  ;; Let's do a stable-sort at least, so that multiple foo-
> 1.2.3/bin/foo
> +  ;; variants will predictably resolve to the highest versioned one.
> +  (let* ((original-files (list->vector files))
> +         (count (vector-length original-files))
> +         (stripped-files (vector-map (lambda (_ el)
> +                                       (strip-store-file-name el))
> +                                     original-files))
> +         (indices (vector-unfold values count)))
> +    (stable-sort! indices
> +                  (lambda (a b)
> +                    (string> (vector-ref stripped-files a)
> +                             (vector-ref stripped-files b))))
> +    (vector-ref original-files (vector-ref indices 0))))
Instead of stable-sort!-ing the indices of a vector, what about stable-
sort!-ing (map strip-store-file-name original-files) in more or less
one go?

> +(define (default-collision-resolver files)
> +  (let ((file (resolve-collision/alphanumeric-last files)))
>      (unless (member (basename file) %harmless-collisions)
>        (format (current-error-port)
>                "~%warning: collision encountered:~%~{  ~a~%~}"
> @@ -117,7 +131,7 @@ first one of THEM."
>                        #:key (log-port (current-error-port))
>                        (create-all-directories? #f)
>                        (symlink symlink)
> -                      (resolve-collision warn-about-collision))
> +                      (resolve-collision default-collision-
> resolver))
>    "Build in the OUTPUT directory a symlink tree that is the union of
> all the
>  INPUTS, using SYMLINK to create symlinks.  As a special case, if
>  CREATE-ALL-DIRECTORIES?, creates the subdirectories in the output
> directory to
I don't think the default collision resolver ought to sort the files. 
The rationale behind ignoring certain collisions, e.g. icon caches
relies on the fact that Guix will use the correct files because they
are put first in the manifest.  The hooks themselves have no special
names that could put them "always first" and profiles are themselves
union-built.

I do however support the addition of sorting methods as collision
resolvers in general and would welcome a way of doing so for profiles
pre-hook.

Regards,
Liliana