Subject: Re: [bug#27271] [PATCH 0/4] Catch collisions at profile creation time

From: [email-masked] (Ludovic Courtès)
Date: Sat, 17 Jun 2017 14:30:03 +0200

Hi,

Ricardo Wurmus <[email-masked]> skribis:

> I just tried it and I didn’t work the way I thought it would.
>
> Here’s what I did:
>
>   # install old numpy
>   guix package -p /tmp/test -i /gnu/store/s02iw98l234ngkcnxqi7jz54vqqgx6hj-python2-numpy-1.10.4
>
>   # install a package depending on a later version of numpy
>   guix package -p /tmp/test -i bamm
>
> It built bamm and then proceeded to build a profile, while spitting out
> hundreds of lines about conflicts between python2-numpy-1.10.4 and
> python2-numpy-1.12.0.

Oops, good catch.  This is fixed with the attached patch.  Now I get:

--8<---------------cut here---------------start------------->8---
$ ./pre-inst-env guix package -p /tmp/test -i bamm
substitute: updating list of substitutes from 'https://mirror.hydra.gnu.org'... 100.0%
The following package will be installed:
   bamm	1.7.3	/gnu/store/lcb2s2x3s50gmf24asl2mvv34jhx8n1x-bamm-1.7.3

guix package: error: profile contains conflicting entries for python2-numpy:out
guix package: error:   first entry: [email-masked]:out /gnu/store/pzf5yszv5dlzmk71w7srdi2qdqh2j40a-python2-numpy-1.12.0
guix package: error:    ... propagated from [email-masked]
guix package: error:   second entry: [email-masked]:out /gnu/store/pykndifwj34mc1h7m78d1b6c03gb5zq1-python2-numpy-1.10.4
--8<---------------cut here---------------end--------------->8---

I’ll add a test case for this.

> I also wonder if we should add a way to force Guix to build the profile
> despite the detected conflict.

Good question.  I wouldn’t be hard to do, but maybe we can wait until
there’s demand so we can analyze the use case better?

Thanks for testing!

Ludo’.

diff --git a/guix/profiles.scm b/guix/profiles.scm
index 980229ca7..52a8bd2ea 100644
--- a/guix/profiles.scm
+++ b/guix/profiles.scm
@@ -157,6 +157,19 @@
 ;; Convenient alias, to avoid name clashes.
 (define make-manifest manifest)
 
+(define (manifest-transitive-entries manifest)
+  "Return the entries of MANIFEST along with their propagated inputs,
+recursively."
+  (let loop ((entries (manifest-entries manifest))
+             (result  '()))
+    (match entries
+      (()
+       (reverse result))
+      ((head . tail)
+       (loop (append (manifest-entry-dependencies head)
+                     tail)
+             (cons head result))))))
+
 (define-record-type* <manifest-entry> manifest-entry
   make-manifest-entry
   manifest-entry?
@@ -250,7 +263,7 @@ file name."
                (#f                                ;no conflict
                 (return result))))
            #t
-           (manifest-entries manifest))))
+           (manifest-transitive-entries manifest))))
 
 (define* (package->manifest-entry package #:optional (output "out")
                                   #:key (parent (delay #f)))