guix package: Add '--allow-collisions'.

Fixes <https://bugs.gnu.org/30830>.
Suggested by Ricardo Wurmus <rekado@elephly.net>.

* guix/scripts/package.scm (build-and-use-profile): Add
 #:allow-collisions? and pass it to 'profile-derivation'.
(show-help, %options): Add '--allow-collisions'.
(manifest-action, process-actions): Pass #:allow-collisions? to
'build-and-use-profile'.
* tests/guix-package.sh: Add collision test.
* doc/guix.texi (Invoking guix package): Document '--allow-collisions'.
This commit is contained in:
Ludovic Courtès 2018-03-31 23:14:56 +02:00
parent e1bff5a75c
commit fc95dc4c34
No known key found for this signature in database
GPG key ID: 090B11993D9AEBB5
3 changed files with 33 additions and 2 deletions

View file

@ -2039,6 +2039,16 @@ variable, even though, taken individually, neither @file{foo} nor
@itemx -p @var{profile} @itemx -p @var{profile}
Use @var{profile} instead of the user's default profile. Use @var{profile} instead of the user's default profile.
@cindex collisions, in a profile
@cindex colliding packages in profiles
@cindex profile collisions
@item --allow-collisions
Allow colliding packages in the new profile. Use at your own risk!
By default, @command{guix package} reports as an error @dfn{collisions}
in the profile. Collisions happen when two or more different versions
or variants of a given package end up in the profile.
@item --verbose @item --verbose
Produce verbose output. In particular, emit the build log of the Produce verbose output. In particular, emit the build log of the
environment on the standard error port. environment on the standard error port.

View file

@ -194,15 +194,18 @@ (define (delete-matching-generations store profile pattern)
(define* (build-and-use-profile store profile manifest (define* (build-and-use-profile store profile manifest
#:key #:key
allow-collisions?
bootstrap? use-substitutes? bootstrap? use-substitutes?
dry-run?) dry-run?)
"Build a new generation of PROFILE, a file name, using the packages "Build a new generation of PROFILE, a file name, using the packages
specified in MANIFEST, a manifest object." specified in MANIFEST, a manifest object. When ALLOW-COLLISIONS? is true,
do not treat collisions in MANIFEST as an error."
(when (equal? profile %current-profile) (when (equal? profile %current-profile)
(ensure-default-profile)) (ensure-default-profile))
(let* ((prof-drv (run-with-store store (let* ((prof-drv (run-with-store store
(profile-derivation manifest (profile-derivation manifest
#:allow-collisions? allow-collisions?
#:hooks (if bootstrap? #:hooks (if bootstrap?
'() '()
%default-profile-hooks) %default-profile-hooks)
@ -407,6 +410,8 @@ (define (show-help)
(display (G_ " (display (G_ "
-p, --profile=PROFILE use PROFILE instead of the user's default profile")) -p, --profile=PROFILE use PROFILE instead of the user's default profile"))
(newline) (newline)
(display (G_ "
--allow-collisions do not treat collisions in the profile as an error"))
(display (G_ " (display (G_ "
--bootstrap use the bootstrap Guile to build the profile")) --bootstrap use the bootstrap Guile to build the profile"))
(display (G_ " (display (G_ "
@ -544,6 +549,10 @@ (define %options
(lambda (opt name arg result arg-handler) (lambda (opt name arg result arg-handler)
(values (alist-cons 'verbose? #t result) (values (alist-cons 'verbose? #t result)
#f))) #f)))
(option '("allow-collisions") #f #f
(lambda (opt name arg result arg-handler)
(values (alist-cons 'allow-collisions? #t result)
#f)))
(option '(#\s "search") #t #f (option '(#\s "search") #t #f
(lambda (opt name arg result arg-handler) (lambda (opt name arg result arg-handler)
(values (cons `(query search ,(or arg "")) (values (cons `(query search ,(or arg ""))
@ -831,13 +840,15 @@ (define* (manifest-action store profile file opts
(let* ((user-module (make-user-module '((guix profiles) (gnu)))) (let* ((user-module (make-user-module '((guix profiles) (gnu))))
(manifest (load* file user-module)) (manifest (load* file user-module))
(bootstrap? (assoc-ref opts 'bootstrap?)) (bootstrap? (assoc-ref opts 'bootstrap?))
(substitutes? (assoc-ref opts 'substitutes?))) (substitutes? (assoc-ref opts 'substitutes?))
(allow-collisions? (assoc-ref opts 'allow-collisions?)))
(if dry-run? (if dry-run?
(format #t (G_ "would install new manifest from '~a' with ~d entries~%") (format #t (G_ "would install new manifest from '~a' with ~d entries~%")
file (length (manifest-entries manifest))) file (length (manifest-entries manifest)))
(format #t (G_ "installing new manifest from '~a' with ~d entries~%") (format #t (G_ "installing new manifest from '~a' with ~d entries~%")
file (length (manifest-entries manifest)))) file (length (manifest-entries manifest))))
(build-and-use-profile store profile manifest (build-and-use-profile store profile manifest
#:allow-collisions? allow-collisions?
#:bootstrap? bootstrap? #:bootstrap? bootstrap?
#:use-substitutes? substitutes? #:use-substitutes? substitutes?
#:dry-run? dry-run?))) #:dry-run? dry-run?)))
@ -856,6 +867,7 @@ (define (process-actions store opts)
(define dry-run? (assoc-ref opts 'dry-run?)) (define dry-run? (assoc-ref opts 'dry-run?))
(define bootstrap? (assoc-ref opts 'bootstrap?)) (define bootstrap? (assoc-ref opts 'bootstrap?))
(define substitutes? (assoc-ref opts 'substitutes?)) (define substitutes? (assoc-ref opts 'substitutes?))
(define allow-collisions? (assoc-ref opts 'allow-collisions?))
(define profile (or (assoc-ref opts 'profile) %current-profile)) (define profile (or (assoc-ref opts 'profile) %current-profile))
(define transform (options->transformation opts)) (define transform (options->transformation opts))
@ -894,6 +906,7 @@ (define (transform-entry entry)
(show-manifest-transaction store manifest step3 (show-manifest-transaction store manifest step3
#:dry-run? dry-run?) #:dry-run? dry-run?)
(build-and-use-profile store profile new (build-and-use-profile store profile new
#:allow-collisions? allow-collisions?
#:bootstrap? bootstrap? #:bootstrap? bootstrap?
#:use-substitutes? substitutes? #:use-substitutes? substitutes?
#:dry-run? dry-run?)))) #:dry-run? dry-run?))))

View file

@ -60,6 +60,14 @@ test -L "$profile" && test -L "$profile-1-link"
! test -f "$profile-2-link" ! test -f "$profile-2-link"
test -f "$profile/bin/guile" test -f "$profile/bin/guile"
# Collisions are properly flagged (in this case, 'python-wrapper' propagates
# python@3, which conflicts with python@2.)
if guix package --bootstrap -n -p "$profile" -i python@2 python-wrapper
then false; else true; fi
guix package --bootstrap -n -p "$profile" -i python@2 python-wrapper \
--allow-collisions
# No search path env. var. here. # No search path env. var. here.
guix package -p "$profile" --search-paths guix package -p "$profile" --search-paths
guix package -p "$profile" --search-paths | grep '^export PATH=' guix package -p "$profile" --search-paths | grep '^export PATH='