scripts: environment: Build environments as profiles.

Fixes <http://bugs.gnu.org/19816>.

* guix/scripts/environment.scm (evaluate-input-search-paths)
(build-inputs): Delete.
(evaluate-profile-search-paths, strip-input-name)
(package-or-package+output?, package-environment-inputs)
(build-environment, inputs->profile-derivations): New procedures.
(create-environment, show-search-paths, launch-environment)
(launch-environment/container): Replace 'inputs' argument
with 'profile' argument.
(package+propagated-inputs): Strip off names off of input tuples.
(options/resolve-packages): Handle input tuples that specify an output
in expressions.
(guix-environment): Convert inputs into a profile to use in the
environment.  Remove non-package inputs such as origins from
environment inputs.
* doc/guix.texi ("invoking guix environment"): Document package+output
tuples for --expression option.
* tests/guix-environment.sh: Update tests.
* tests/guix-environment-container.sh: Likewise.

Co-authored-by: Ludovic Courtès <ludo@gnu.org>
This commit is contained in:
David Thompson 2016-02-12 21:39:26 +01:00 committed by Ludovic Courtès
parent e5f04c2dde
commit 779aa003fb
4 changed files with 205 additions and 145 deletions

View File

@ -5093,6 +5093,13 @@ guix environment --ad-hoc -e '(@@ (gnu) %base-packages)'
starts a shell with all the GuixSD base packages available. starts a shell with all the GuixSD base packages available.
The above commands only the use default output of the given packages.
To select other outputs, two element tuples can be specified:
@example
guix environment --ad-hoc -e '(list (@ (gnu packages bash) bash) "include")'
@end example
@item --load=@var{file} @item --load=@var{file}
@itemx -l @var{file} @itemx -l @var{file}
Create an environment for the package or list of packages that the code Create an environment for the package or list of packages that the code

View File

@ -35,6 +35,9 @@
#:use-module (gnu system file-systems) #:use-module (gnu system file-systems)
#:use-module (gnu packages) #:use-module (gnu packages)
#:use-module (gnu packages bash) #:use-module (gnu packages bash)
#:use-module (gnu packages commencement)
#:use-module (gnu packages guile)
#:use-module ((gnu packages bootstrap) #:select (%bootstrap-guile))
#:use-module (ice-9 format) #:use-module (ice-9 format)
#:use-module (ice-9 match) #:use-module (ice-9 match)
#:use-module (ice-9 rdelim) #:use-module (ice-9 rdelim)
@ -45,19 +48,10 @@
#:use-module (srfi srfi-98) #:use-module (srfi srfi-98)
#:export (guix-environment)) #:export (guix-environment))
(define (evaluate-input-search-paths inputs search-paths) (define (evaluate-profile-search-paths profile search-paths)
"Evaluate SEARCH-PATHS, a list of search-path specifications, for the "Evaluate SEARCH-PATHS, a list of search-path specifications, for the
directories corresponding to INPUTS, a list of (DERIVATION) or (DERIVATION directories in PROFILE, the store path of a profile."
OUTPUT) tuples." (evaluate-search-paths search-paths (list profile)))
(let ((directories (map (match-lambda
(((? derivation? drv))
(derivation->output-path drv))
(((? derivation? drv) output)
(derivation->output-path drv output))
(((? string? item))
item))
inputs)))
(evaluate-search-paths search-paths directories)))
;; Protect some env vars from purification. Borrowed from nix-shell. ;; Protect some env vars from purification. Borrowed from nix-shell.
(define %precious-variables (define %precious-variables
@ -81,11 +75,10 @@ as 'HOME' and 'USER' are left untouched."
(((names . _) ...) (((names . _) ...)
names))))) names)))))
(define (create-environment inputs paths pure?) (define (create-environment profile paths pure?)
"Set the environment variables specified by PATHS for all the packages "Set the environment variables specified by PATHS for PROFILE. When PURE?
within INPUTS. When PURE? is #t, unset the variables in the current is #t, unset the variables in the current environment. Otherwise, augment
environment. Otherwise, augment existing enviroment variables with additional existing enviroment variables with additional search paths."
search paths."
(when pure? (purify-environment)) (when pure? (purify-environment))
(for-each (match-lambda (for-each (match-lambda
((($ <search-path-specification> variable _ separator) . value) ((($ <search-path-specification> variable _ separator) . value)
@ -94,15 +87,14 @@ search paths."
(if (and current (not pure?)) (if (and current (not pure?))
(string-append value separator current) (string-append value separator current)
value))))) value)))))
(evaluate-input-search-paths inputs paths)) (evaluate-profile-search-paths profile paths))
;; Give users a way to know that they're in 'guix environment', so they can ;; Give users a way to know that they're in 'guix environment', so they can
;; adjust 'PS1' accordingly, for instance. ;; adjust 'PS1' accordingly, for instance.
(setenv "GUIX_ENVIRONMENT" "t")) (setenv "GUIX_ENVIRONMENT" "t"))
(define (show-search-paths inputs search-paths pure?) (define (show-search-paths profile search-paths pure?)
"Display SEARCH-PATHS applied to the packages specified by INPUTS, a list of "Display SEARCH-PATHS applied to PROFILE. When PURE? is #t, do not augment
(DERIVATION) or (DERIVATION OUTPUT) tuples. When PURE? is #t, do not augment
existing environment variables with additional search paths." existing environment variables with additional search paths."
(for-each (match-lambda (for-each (match-lambda
((search-path . value) ((search-path . value)
@ -110,12 +102,37 @@ existing environment variables with additional search paths."
(search-path-definition search-path value (search-path-definition search-path value
#:kind (if pure? 'exact 'prefix))) #:kind (if pure? 'exact 'prefix)))
(newline))) (newline)))
(evaluate-input-search-paths inputs search-paths))) (evaluate-profile-search-paths profile search-paths)))
(define (strip-input-name input)
"Remove the name element from the tuple INPUT."
(match input
((_ package) package)
((_ package output)
(list package output))))
(define (package+propagated-inputs package output) (define (package+propagated-inputs package output)
"Return the union of PACKAGE's OUTPUT and its transitive propagated inputs." "Return the union of PACKAGE's OUTPUT and its transitive propagated inputs."
`((,(package-name package) ,package ,output) (cons (list package output)
,@(package-transitive-propagated-inputs package))) (map strip-input-name
(package-transitive-propagated-inputs package))))
(define (package-or-package+output? expr)
"Return #t if EXPR is a package or a 2 element list consisting of a package
and an output string."
(match expr
((or (? package?) ; bare package object
((? package?) (? string?))) ; package+output tuple
#t)
(_ #f)))
(define (package-environment-inputs package)
"Return a list of the transitive input packages for PACKAGE."
;; Remove non-package inputs such as origin records.
(filter package-or-package+output?
(map strip-input-name
(bag-transitive-inputs
(package->bag package)))))
(define (show-help) (define (show-help)
(display (_ "Usage: guix environment [OPTION]... PACKAGE... [-- COMMAND...] (display (_ "Usage: guix environment [OPTION]... PACKAGE... [-- COMMAND...]
@ -252,17 +269,19 @@ COMMAND or an interactive shell in that environment.\n"))
(define (options/resolve-packages opts) (define (options/resolve-packages opts)
"Return OPTS with package specification strings replaced by actual "Return OPTS with package specification strings replaced by actual
packages." packages."
(define (package->outputs package mode) (define (package->output package mode)
(map (lambda (output) (match package
(list mode package output)) ((? package?)
(package-outputs package))) (list mode package "out"))
(((? package? package) (? string? output))
(list mode package output))))
(define (packages->outputs packages mode) (define (packages->outputs packages mode)
(match packages (match packages
((? package? package) ((? package-or-package+output? package) ; single package
(package->outputs package mode)) (list (package->output package mode)))
(((? package? packages) ...) (((? package-or-package+output?) ...) ; many packages
(append-map (cut package->outputs <> mode) packages)))) (map (cut package->output <> mode) packages))))
(compact (compact
(append-map (match-lambda (append-map (match-lambda
@ -280,22 +299,30 @@ packages."
(_ '(#f))) (_ '(#f)))
opts))) opts)))
(define (build-inputs inputs opts) (define* (build-environment derivations opts)
"Build the derivations in INPUTS, a list of (DERIVATION) or (DERIVATION "Build the DERIVATIONS required by the environment using the build options
OUTPUT) tuples, using the build options in OPTS." in OPTS."
(let ((substitutes? (assoc-ref opts 'substitutes?)) (let ((substitutes? (assoc-ref opts 'substitutes?))
(dry-run? (assoc-ref opts 'dry-run?))) (dry-run? (assoc-ref opts 'dry-run?)))
(match inputs (mbegin %store-monad
(((derivations _ ...) ...) (show-what-to-build* derivations
(mbegin %store-monad #:use-substitutes? substitutes?
(show-what-to-build* derivations #:dry-run? dry-run?)
#:use-substitutes? substitutes? (if dry-run?
#:dry-run? dry-run?) (return #f)
(if dry-run? (mbegin %store-monad
(return #f) (set-build-options-from-command-line* opts)
(mbegin %store-monad (built-derivations derivations))))))
(built-derivations derivations)
(return derivations)))))))) (define (inputs->profile-derivation inputs system bootstrap?)
"Return the derivation for a profile consisting of INPUTS for SYSTEM.
BOOTSTRAP? specifies whether to use the bootstrap Guile to build the
profile."
(profile-derivation (packages->manifest inputs)
#:system system
#:hooks (if bootstrap?
'()
%default-profile-hooks)))
(define requisites* (store-lift requisites)) (define requisites* (store-lift requisites))
@ -334,16 +361,15 @@ variables are cleared before setting the new ones."
(apply system* command)) (apply system* command))
(define* (launch-environment/container #:key command bash user-mappings (define* (launch-environment/container #:key command bash user-mappings
inputs paths network?) profile paths network?)
"Run COMMAND within a Linux container. The environment features INPUTS, a "Run COMMAND within a container that features the software in PROFILE.
list of derivations to be shared from the host system. Environment variables Environment variables are set according to PATHS, a list of native search
are set according to PATHS, a list of native search paths. The global shell paths. The global shell is BASH, a file name for a GNU Bash binary in the
is BASH, a file name for a GNU Bash binary in the store. When NETWORK?, store. When NETWORK?, access to the host system network is permitted.
access to the host system network is permitted. USER-MAPPINGS, a list of file USER-MAPPINGS, a list of file system mappings, contains the user-specified
system mappings, contains the user-specified host file systems to mount inside host file systems to mount inside the container."
the container."
(mlet %store-monad ((reqs (inputs->requisites (mlet %store-monad ((reqs (inputs->requisites
(cons (direct-store-path bash) inputs)))) (list (direct-store-path bash) profile))))
(return (return
(let* ((cwd (getcwd)) (let* ((cwd (getcwd))
;; Bind-mount all requisite store items, user-specified mappings, ;; Bind-mount all requisite store items, user-specified mappings,
@ -408,7 +434,7 @@ the container."
(primitive-exit/status (primitive-exit/status
;; A container's environment is already purified, so no need to ;; A container's environment is already purified, so no need to
;; request it be purified again. ;; request it be purified again.
(launch-environment command inputs paths #f))) (launch-environment command profile paths #f)))
#:namespaces (if network? #:namespaces (if network?
(delq 'net %namespaces) ; share host network (delq 'net %namespaces) ; share host network
%namespaces))))))) %namespaces)))))))
@ -482,64 +508,65 @@ message if any test fails."
(('ad-hoc-package package output) (('ad-hoc-package package output)
(package+propagated-inputs package (package+propagated-inputs package
output)) output))
(('package package output) (('package package _)
(bag-transitive-inputs (package-environment-inputs package)))
(package->bag package))))
packages))) packages)))
(paths (delete-duplicates (paths (delete-duplicates
(cons $PATH (cons $PATH
(append-map (match-lambda (append-map (match-lambda
((label (? package? p) _ ...) ((or ((? package? p) _ ...)
(package-native-search-paths p)) (? package? p))
(_ (package-native-search-paths p))
'())) (_ '()))
inputs)) inputs))
eq?))) eq?)))
(when container? (assert-container-features)) (when container? (assert-container-features))
(with-store store (with-store store
(set-build-options-from-command-line store opts) ;; Use the bootstrap Guile when requested.
(run-with-store store (parameterize ((%guile-for-build
(mlet* %store-monad ((inputs (lower-inputs (package-derivation
(map (match-lambda store
((label item) (if bootstrap?
(list item)) %bootstrap-guile
((label item output) (canonical-package guile-2.0)))))
(list item output))) (set-build-options-from-command-line store opts)
inputs) (run-with-store store
#:system system)) ;; Containers need a Bourne shell at /bin/sh.
;; Containers need a Bourne shell at /bin/sh. (mlet* %store-monad ((bash (environment-bash container?
(bash (environment-bash container? bootstrap?
bootstrap? system))
system))) (prof-drv (inputs->profile-derivation
(mbegin %store-monad inputs system bootstrap?))
(profile -> (derivation->output-path prof-drv)))
;; First build the inputs. This is necessary even for ;; First build the inputs. This is necessary even for
;; --search-paths. Additionally, we might need to build bash ;; --search-paths. Additionally, we might need to build bash for
;; for a container. ;; a container.
(build-inputs (if (derivation? bash) (mbegin %store-monad
`((,bash "out") ,@inputs) (build-environment (if (derivation? bash)
inputs) (list prof-drv bash)
opts) (list prof-drv))
(cond opts)
((assoc-ref opts 'dry-run?) (cond
(return #t)) ((assoc-ref opts 'dry-run?)
((assoc-ref opts 'search-paths) (return #t))
(show-search-paths inputs paths pure?) ((assoc-ref opts 'search-paths)
(return #t)) (show-search-paths profile paths pure?)
(container? (return #t))
(let ((bash-binary (container?
(if bootstrap? (let ((bash-binary
bash (if bootstrap?
(string-append (derivation->output-path bash) bash
"/bin/sh")))) (string-append (derivation->output-path bash)
(launch-environment/container #:command command "/bin/sh"))))
#:bash bash-binary (launch-environment/container #:command command
#:user-mappings mappings #:bash bash-binary
#:inputs inputs #:user-mappings mappings
#:paths paths #:profile profile
#:network? network?))) #:paths paths
(else #:network? network?)))
(return (else
(exit/status (return
(launch-environment command inputs paths pure?)))))))))))) (exit/status
(launch-environment command profile paths pure?)))))))))))))

View File

@ -73,7 +73,7 @@ guix environment --container --ad-hoc --bootstrap guile-bootstrap \
-- guile -c "$mount_test_code" > $tmpdir/mounts -- guile -c "$mount_test_code" > $tmpdir/mounts
cat "$tmpdir/mounts" cat "$tmpdir/mounts"
test `wc -l < $tmpdir/mounts` -eq 3 test `wc -l < $tmpdir/mounts` -eq 4
current_dir="`cd $PWD; pwd -P`" current_dir="`cd $PWD; pwd -P`"
grep -e "$current_dir$" $tmpdir/mounts # current directory grep -e "$current_dir$" $tmpdir/mounts # current directory

View File

@ -1,5 +1,5 @@
# GNU Guix --- Functional package management for GNU # GNU Guix --- Functional package management for GNU
# Copyright © 2015 Ludovic Courtès <ludo@gnu.org> # Copyright © 2015, 2016 Ludovic Courtès <ludo@gnu.org>
# #
# This file is part of GNU Guix. # This file is part of GNU Guix.
# #
@ -34,17 +34,23 @@ mkdir "$tmpdir"
export SHELL export SHELL
# Check the environment variables for the bootstrap Guile. # Check the environment variables for the bootstrap Guile.
guix environment --ad-hoc guile-bootstrap --pure --search-paths > "$tmpdir/a" guix environment --bootstrap --ad-hoc guile-bootstrap --pure \
guix environment --ad-hoc guile-bootstrap:out --pure --search-paths > "$tmpdir/b" --search-paths > "$tmpdir/a"
guix environment --bootstrap --ad-hoc guile-bootstrap:out --pure \
--search-paths > "$tmpdir/b"
# $PATH must appear in the search paths, and nothing else. # $PATH must appear in the search paths, and nothing else.
grep -E '^export PATH=.*guile-bootstrap-[0-9.]+/bin' "$tmpdir/a" grep -E '^export PATH=.*profile/bin' "$tmpdir/a"
test "`wc -l < "$tmpdir/a"`" = 1 test "`wc -l < "$tmpdir/a"`" = 1
# Guile must be on $PATH.
test -x `sed -r 's/^export PATH="(.*)"/\1/' "$tmpdir/a"`/guile
cmp "$tmpdir/a" "$tmpdir/b" cmp "$tmpdir/a" "$tmpdir/b"
# Make sure the exit value is preserved. # Make sure the exit value is preserved.
if guix environment --ad-hoc guile-bootstrap --pure -- guile -c '(exit 42)' if guix environment --bootstrap --ad-hoc guile-bootstrap --pure \
-- guile -c '(exit 42)'
then then
false false
else else
@ -52,7 +58,8 @@ else
fi fi
# Same as above, but with deprecated -E flag. # Same as above, but with deprecated -E flag.
if guix environment --ad-hoc guile-bootstrap --pure -E "guile -c '(exit 42)'" if guix environment --bootstrap --ad-hoc guile-bootstrap --pure \
-E "guile -c '(exit 42)'"
then then
false false
else else
@ -62,22 +69,29 @@ fi
if guile -c '(getaddrinfo "www.gnu.org" "80" AI_NUMERICSERV)' 2> /dev/null if guile -c '(getaddrinfo "www.gnu.org" "80" AI_NUMERICSERV)' 2> /dev/null
then then
# Compute the build environment for the initial GNU Make. # Compute the build environment for the initial GNU Make.
guix environment -e '(@@ (gnu packages commencement) gnu-make-boot0)' \ guix environment --bootstrap --no-substitutes --search-paths --pure \
--no-substitutes --search-paths --pure > "$tmpdir/a" -e '(@@ (gnu packages commencement) gnu-make-boot0)' > "$tmpdir/a"
# Make sure bootstrap binaries are in the profile.
profile=`grep "^export PATH" "$tmpdir/a" | sed -r 's|^.*="(.*)/bin"|\1|'`
# Make sure the bootstrap binaries are all listed where they belong. # Make sure the bootstrap binaries are all listed where they belong.
grep -E '^export PATH=.*-bootstrap-binaries-0/bin' "$tmpdir/a" grep -E "^export PATH=\"$profile/bin\"" "$tmpdir/a"
grep -E '^export CPATH=.*-gcc-bootstrap-0/include' "$tmpdir/a" grep -E "^export CPATH=\"$profile/include\"" "$tmpdir/a"
grep -E '^export CPATH=.*-glibc-bootstrap-0/include' "$tmpdir/a" grep -E "^export LIBRARY_PATH=\"$profile/lib\"" "$tmpdir/a"
grep -E '^export LIBRARY_PATH=.*-glibc-bootstrap-0/lib' "$tmpdir/a" for dep in bootstrap-binaries-0 gcc-bootstrap-0 glibc-bootstrap-0
do
guix gc --references "$profile" | grep "$dep"
done
# 'make-boot0' itself must not be listed. # 'make-boot0' itself must not be listed.
if grep "make-boot0" "$tmpdir/a"; then false; else true; fi if guix gc --references "$profile" | grep make-boot0
then false; else true; fi
# Make sure that the shell spawned with '--exec' sees the same environment # Make sure that the shell spawned with '--exec' sees the same environment
# as returned by '--search-paths'. # as returned by '--search-paths'.
guix environment -e '(@@ (gnu packages commencement) gnu-make-boot0)' \ guix environment --bootstrap --no-substitutes --pure \
--no-substitutes --pure \ -e '(@@ (gnu packages commencement) gnu-make-boot0)' \
-- /bin/sh -c 'echo $PATH $CPATH $LIBRARY_PATH' > "$tmpdir/b" -- /bin/sh -c 'echo $PATH $CPATH $LIBRARY_PATH' > "$tmpdir/b"
( . "$tmpdir/a" ; echo $PATH $CPATH $LIBRARY_PATH ) > "$tmpdir/c" ( . "$tmpdir/a" ; echo $PATH $CPATH $LIBRARY_PATH ) > "$tmpdir/c"
cmp "$tmpdir/b" "$tmpdir/c" cmp "$tmpdir/b" "$tmpdir/c"
@ -85,45 +99,57 @@ then
rm "$tmpdir"/* rm "$tmpdir"/*
# Compute the build environment for the initial GNU Findutils. # Compute the build environment for the initial GNU Findutils.
guix environment -e '(@@ (gnu packages commencement) findutils-boot0)' \ guix environment --bootstrap --no-substitutes --search-paths --pure \
--no-substitutes --search-paths --pure > "$tmpdir/a" -e '(@@ (gnu packages commencement) findutils-boot0)' > "$tmpdir/a"
profile=`grep "^export PATH" "$tmpdir/a" | sed -r 's|^.*="(.*)/bin"|\1|'`
# Make sure the bootstrap binaries are all listed where they belong. # Make sure the bootstrap binaries are all listed where they belong.
grep -E '^export PATH=.*-bootstrap-binaries-0/bin' "$tmpdir/a" grep -E "^export PATH=\"$profile/bin\"" "$tmpdir/a"
grep -E '^export PATH=.*-make-boot0-[0-9.]+/bin' "$tmpdir/a" grep -E "^export CPATH=\"$profile/include\"" "$tmpdir/a"
grep -E '^export CPATH=.*-gcc-bootstrap-0/include' "$tmpdir/a" grep -E "^export LIBRARY_PATH=\"$profile/lib\"" "$tmpdir/a"
grep -E '^export CPATH=.*-glibc-bootstrap-0/include' "$tmpdir/a" for dep in bootstrap-binaries-0 gcc-bootstrap-0 glibc-bootstrap-0 \
grep -E '^export LIBRARY_PATH=.*-glibc-bootstrap-0/lib' "$tmpdir/a" make-boot0
do
guix gc --references "$profile" | grep "$dep"
done
# The following test assumes 'make-boot0' has a "debug" output. # The following test assumes 'make-boot0' has a "debug" output.
make_boot0_debug="`guix build -e '(@@ (gnu packages commencement) gnu-make-boot0)' | grep -e -debug`" make_boot0_debug="`guix build -e '(@@ (gnu packages commencement) gnu-make-boot0)' | grep -e -debug`"
test "x$make_boot0_debug" != "x" test "x$make_boot0_debug" != "x"
# Make sure the "debug" output is not listed. # Make sure the "debug" output is not listed.
if grep -E "$make_boot0_debug" "$tmpdir/a"; then false; else true; fi if guix gc --references "$profile" | grep "$make_boot0_debug"
then false; else true; fi
# Compute the build environment for the initial GNU Make, but add in the # Compute the build environment for the initial GNU Make, but add in the
# bootstrap Guile as an ad-hoc addition. # bootstrap Guile as an ad-hoc addition.
guix environment -e '(@@ (gnu packages commencement) gnu-make-boot0)' \ guix environment --bootstrap --no-substitutes --search-paths --pure \
--ad-hoc guile-bootstrap --no-substitutes --search-paths \ -e '(@@ (gnu packages commencement) gnu-make-boot0)' \
--pure > "$tmpdir/a" --ad-hoc guile-bootstrap > "$tmpdir/a"
profile=`grep "^export PATH" "$tmpdir/a" | sed -r 's|^.*="(.*)/bin"|\1|'`
# Make sure the bootstrap binaries are all listed where they belong. # Make sure the bootstrap binaries are all listed where they belong.
cat $tmpdir/a grep -E "^export PATH=\"$profile/bin\"" "$tmpdir/a"
grep -E '^export PATH=.*-bootstrap-binaries-0/bin' "$tmpdir/a" grep -E "^export CPATH=\"$profile/include\"" "$tmpdir/a"
grep -E '^export PATH=.*-guile-bootstrap-2.0/bin' "$tmpdir/a" grep -E "^export LIBRARY_PATH=\"$profile/lib\"" "$tmpdir/a"
grep -E '^export CPATH=.*-gcc-bootstrap-0/include' "$tmpdir/a" for dep in bootstrap-binaries-0 gcc-bootstrap-0 glibc-bootstrap-0 \
grep -E '^export CPATH=.*-glibc-bootstrap-0/include' "$tmpdir/a" guile-bootstrap
grep -E '^export LIBRARY_PATH=.*-glibc-bootstrap-0/lib' "$tmpdir/a" do
guix gc --references "$profile" | grep "$dep"
done
# Make sure a package list can be used with -e. # Make sure a package list with plain package objects and package+output
# tuples can be used with -e.
expr_list_test_code=" expr_list_test_code="
(list (@@ (gnu packages commencement) gnu-make-boot0) (list (@@ (gnu packages commencement) gnu-make-boot0)
(@ (gnu packages bootstrap) %bootstrap-guile))" (list (@ (gnu packages bootstrap) %bootstrap-guile) \"out\"))"
guix environment --ad-hoc --no-substitutes --search-paths --pure \ guix environment --bootstrap --ad-hoc --no-substitutes --search-paths \
-e "$expr_list_test_code" > "$tmpdir/a" --pure -e "$expr_list_test_code" > "$tmpdir/a"
profile=`grep "^export PATH" "$tmpdir/a" | sed -r 's|^.*="(.*)/bin"|\1|'`
grep -E '^export PATH=.*-make-boot0-4.1/bin' "$tmpdir/a" for dep in make-boot0 guile-bootstrap
grep -E '^export PATH=.*-guile-bootstrap-2.0/bin' "$tmpdir/a" do
guix gc --references "$profile" | grep "$dep"
done
fi fi