summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomas Volf <~@wolfsden.cz>2026-05-14 21:26:16 +0200
committerMaxim Cournoyer <maxim@guixotic.coop>2026-06-15 10:48:17 +0900
commitd11615f609d2cd58fb1305205a4fa975dc8e4657 (patch)
tree7f282d90f61523ff71c5d342aaa53ed7dd98b5bb
parent2c646830c1de33fba8e761b86a173041150a030c (diff)
environment: Allow setting environment variables with -E.
* guix/scripts/environment.scm (show-environment-options-help) [-E]: Document the change. * guix/scripts/environment.scm (%options) [-E]: If arg contains =, split it and store under 'extra-env. * guix/scripts/environment.scm (launch-environment, launch-environment/fork) (launch-environment/container): Take and use `environment-variables' keyword argument. * guix/scripts/environment.scm (guix-environment*): Process 'environment-variables opts. * guix/profiles.scm (load-profile): Add `environment-variables' keyword argument. * doc/guix.texi (Invoking guix shell): Document the change. * tests/guix-environment.sh (GUIX_TEST_ZZZ): Test it. Change-Id: Ib1db19ef73dda8f561b05731079a96eda076e365 Signed-off-by: Maxim Cournoyer <maxim@guixotic.coop> Modified-by: Maxim Cournoyer <maxim@guixotic.coop>
-rw-r--r--doc/guix.texi17
-rw-r--r--guix/profiles.scm8
-rw-r--r--guix/scripts/environment.scm54
-rw-r--r--tests/guix-environment.sh5
4 files changed, 63 insertions, 21 deletions
diff --git a/doc/guix.texi b/doc/guix.texi
index c624c497d2a..05eac9bda96 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -6803,20 +6803,26 @@ creating an environment in which search paths only contain package inputs.
6803 6803
6804@item --preserve=@var{regexp} 6804@item --preserve=@var{regexp}
6805@itemx -E @var{regexp} 6805@itemx -E @var{regexp}
6806@itemx -E @var{var}=@var{value}
6806When used alongside @option{--pure}, preserve the environment variables 6807When used alongside @option{--pure}, preserve the environment variables
6807matching @var{regexp}---in other words, put them on a ``white list'' of 6808matching @var{regexp}---in other words, put them on a ``white list'' of
6808environment variables that must be preserved. This option can be repeated 6809environment variables that must be preserved. This option can be
6809several times. 6810repeated several times.
6811
6812When @var{regexp} contains a variable assignment (with a @samp{=}
6813character), the @var{var} environment variable is directly set to the
6814@var{value} in the environment. This is used in the example below to
6815set the number of threads OpenMPI should use:
6810 6816
6811@example 6817@example
6812guix shell --pure --preserve=^SLURM openmpi @dots{} \ 6818guix shell --pure --preserve=^SLURM -E OMP_NUM_THREADS=16 openmpi @dots{} \
6813 -- mpirun @dots{} 6819 -- mpirun @dots{}
6814@end example 6820@end example
6815 6821
6816This example runs @command{mpirun} in a context where the only environment 6822This example runs @command{mpirun} in a context where the only environment
6817variables defined are @env{PATH}, environment variables whose name starts 6823variables defined are @env{PATH}, environment variables whose name starts
6818with @samp{SLURM}, as well as the usual ``precious'' variables (@env{HOME}, 6824with @samp{SLURM}, variable @env{TERM} set to @samp{no=color}, as well as
6819@env{USER}, etc.). 6825the usual ``precious'' variables (@env{HOME}, @env{USER}, etc.).
6820 6826
6821@item --search-paths 6827@item --search-paths
6822Display the environment variable definitions that make up the 6828Display the environment variable definitions that make up the
@@ -7319,6 +7325,7 @@ creating an environment in which search paths only contain package inputs.
7319 7325
7320@item --preserve=@var{regexp} 7326@item --preserve=@var{regexp}
7321@itemx -E @var{regexp} 7327@itemx -E @var{regexp}
7328@itemx -E @var{var}=@var{value}
7322When used alongside @option{--pure}, preserve the environment variables 7329When used alongside @option{--pure}, preserve the environment variables
7323matching @var{regexp}---in other words, put them on a ``white list'' of 7330matching @var{regexp}---in other words, put them on a ``white list'' of
7324environment variables that must be preserved. This option can be repeated 7331environment variables that must be preserved. This option can be repeated
diff --git a/guix/profiles.scm b/guix/profiles.scm
index b39116bc0bf..aced7bd25cb 100644
--- a/guix/profiles.scm
+++ b/guix/profiles.scm
@@ -2171,14 +2171,20 @@ WHITE-LIST-REGEXPS and those listed in WHITE-LIST."
2171(define* (load-profile profile 2171(define* (load-profile profile
2172 #:optional (manifest (profile-manifest profile)) 2172 #:optional (manifest (profile-manifest profile))
2173 #:key pure? (white-list-regexps '()) 2173 #:key pure? (white-list-regexps '())
2174 (environment-variables '())
2174 (white-list %precious-variables)) 2175 (white-list %precious-variables))
2175 "Set the environment variables specified by MANIFEST for PROFILE. When 2176 "Set the environment variables specified by MANIFEST for PROFILE. When
2176PURE? is #t, unset the variables in the current environment except those that 2177PURE? is #t, unset the variables in the current environment except those that
2177match the regexps in WHITE-LIST-REGEXPS and those listed in WHITE-LIST. 2178match the regexps in WHITE-LIST-REGEXPS and those listed in WHITE-LIST.
2178Otherwise, augment existing environment variables with additional search 2179Otherwise, augment existing environment variables with additional search
2179paths." 2180paths. Environment variables in ENVIRONMENT-VARIABLES, a list of pairs, are
2181@emph{set} in the environment."
2180 (when pure? 2182 (when pure?
2181 (purify-environment white-list white-list-regexps)) 2183 (purify-environment white-list white-list-regexps))
2184 (map (match-lambda
2185 ((name . value)
2186 (setenv name value)))
2187 environment-variables)
2182 (for-each (match-lambda 2188 (for-each (match-lambda
2183 ((($ <search-path-specification> variable _ separator) . value) 2189 ((($ <search-path-specification> variable _ separator) . value)
2184 (let ((current (getenv variable))) 2190 (let ((current (getenv variable)))
diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm
index dc7f3b9b280..bd7d4ca6ed4 100644
--- a/guix/scripts/environment.scm
+++ b/guix/scripts/environment.scm
@@ -100,7 +100,9 @@ shell'."
100 (display (G_ " 100 (display (G_ "
101 --pure unset existing environment variables")) 101 --pure unset existing environment variables"))
102 (display (G_ " 102 (display (G_ "
103 -E, --preserve=REGEXP preserve environment variables that match REGEXP")) 103 -E, --preserve=REGEXP
104 -E VAR=VALUE preserve environment variables that match REGEXP;
105 if REGEXP contains `=', set VAR to VALUE instead"))
104 (display (G_ " 106 (display (G_ "
105 --search-paths display needed environment variable definitions")) 107 --search-paths display needed environment variable definitions"))
106 (display (G_ " 108 (display (G_ "
@@ -212,9 +214,15 @@ COMMAND or an interactive shell in that environment.\n"))
212 (alist-cons 'pure #t result))) 214 (alist-cons 'pure #t result)))
213 (option '(#\E "preserve") #t #f 215 (option '(#\E "preserve") #t #f
214 (lambda (opt name arg result) 216 (lambda (opt name arg result)
215 (alist-cons 'inherit-regexp 217 (let ((=-index (string-index arg #\=)))
216 (make-regexp* arg) 218 (if =-index
217 result))) 219 (alist-cons 'environment-variables
220 (cons (substring arg 0 =-index)
221 (substring arg (1+ =-index)))
222 result)
223 (alist-cons 'inherit-regexp
224 (make-regexp* arg)
225 result)))))
218 (option '("inherit") #t #f ;deprecated 226 (option '("inherit") #t #f ;deprecated
219 (lambda (opt name arg result) 227 (lambda (opt name arg result)
220 (warning (G_ "'--inherit' is deprecated, \ 228 (warning (G_ "'--inherit' is deprecated, \
@@ -513,19 +521,23 @@ and suitable for 'exit'."
513 521
514(define* (launch-environment command profile manifest 522(define* (launch-environment command profile manifest
515 #:key pure? (white-list '()) 523 #:key pure? (white-list '())
524 (environment-variables '())
516 emulate-fhs?) 525 emulate-fhs?)
517 "Load the environment of PROFILE, which corresponds to MANIFEST, and execute 526 "Load the environment of PROFILE, which corresponds to MANIFEST, and execute
518COMMAND. When PURE?, pre-existing environment variables are cleared before 527COMMAND. When PURE?, pre-existing environment variables are cleared before
519setting the new ones, except those matching the regexps in WHITE-LIST. When 528setting the new ones, except those matching the regexps in WHITE-LIST.
520EMULATE-FHS?, first set up an FHS environment with $PATH and generate the LD 529Variables in ENVIRONMENT-VARIABLES (a list of pairs) are set in the
521cache." 530environment. When EMULATE-FHS?, first set up an FHS environment with $PATH
531and generate the LD cache."
522 ;; Properly handle SIGINT, so pressing C-c in an interactive terminal 532 ;; Properly handle SIGINT, so pressing C-c in an interactive terminal
523 ;; application works. 533 ;; application works.
524 (sigaction SIGINT SIG_DFL) 534 (sigaction SIGINT SIG_DFL)
525 ;; Restore original action for SIGPIPE. 535 ;; Restore original action for SIGPIPE.
526 (sigaction SIGPIPE SIG_DFL) 536 (sigaction SIGPIPE SIG_DFL)
527 (load-profile profile manifest 537 (load-profile profile manifest
528 #:pure? pure? #:white-list-regexps white-list) 538 #:pure? pure?
539 #:white-list-regexps white-list
540 #:environment-variables environment-variables)
529 541
530 ;; Give users a way to know that they're in 'guix environment', so they can 542 ;; Give users a way to know that they're in 'guix environment', so they can
531 ;; adjust 'PS1' accordingly, for instance. Set it to PROFILE so users can 543 ;; adjust 'PS1' accordingly, for instance. Set it to PROFILE so users can
@@ -734,15 +746,19 @@ command name."
734 closest)))))))) 746 closest))))))))
735 747
736(define* (launch-environment/fork command profile manifest 748(define* (launch-environment/fork command profile manifest
737 #:key pure? (white-list '())) 749 #:key
750 pure? (white-list '())
751 (environment-variables '()))
738 "Run COMMAND in a new process with an environment containing PROFILE, with 752 "Run COMMAND in a new process with an environment containing PROFILE, with
739the search paths specified by MANIFEST. When PURE?, pre-existing environment 753the search paths specified by MANIFEST. When PURE?, pre-existing environment
740variables are cleared before setting the new ones, except those matching the 754variables are cleared before setting the new ones, except those matching the
741regexps in WHITE-LIST." 755regexps in WHITE-LIST. Variables in ENVIRONMENT-VARIABLES (a list of pairs)
756are set in the environment."
742 (match (primitive-fork) 757 (match (primitive-fork)
743 (0 (launch-environment command profile manifest 758 (0 (launch-environment command profile manifest
744 #:pure? pure? 759 #:pure? pure?
745 #:white-list white-list)) 760 #:white-list white-list
761 #:environment-variables environment-variables))
746 (pid (match (waitpid pid) 762 (pid (match (waitpid pid)
747 ((_ . status) 763 ((_ . status)
748 status))))) 764 status)))))
@@ -752,7 +768,8 @@ regexps in WHITE-LIST."
752 map-cwd? cwd emulate-fhs? nesting? 768 map-cwd? cwd emulate-fhs? nesting?
753 writable-root? 769 writable-root?
754 (setup-hook #f) 770 (setup-hook #f)
755 (symlinks '()) (white-list '())) 771 (symlinks '()) (white-list '())
772 (environment-variables '()))
756 "Run COMMAND within a container that features the software in PROFILE. 773 "Run COMMAND within a container that features the software in PROFILE.
757Environment variables are set according to the search paths of MANIFEST. The 774Environment variables are set according to the search paths of MANIFEST. The
758global shell is BASH, a file name for a GNU Bash binary in the store. When 775global shell is BASH, a file name for a GNU Bash binary in the store. When
@@ -777,7 +794,10 @@ SYMLINKS must be a list of (SOURCE -> TARGET) tuples denoting symlinks to be
777added to the container. 794added to the container.
778 795
779Preserve environment variables whose name matches the one of the regexps in 796Preserve environment variables whose name matches the one of the regexps in
780WHILE-LIST." 797WHILE-LIST.
798
799Variables in ENVIRONMENT-VARIABLES (a list of pairs) are set in the
800environment."
781 (define (optional-mapping->fs mapping) 801 (define (optional-mapping->fs mapping)
782 (and (file-exists? (file-system-mapping-source mapping)) 802 (and (file-exists? (file-system-mapping-source mapping))
783 (file-system-mapping->bind-mount mapping))) 803 (file-system-mapping->bind-mount mapping)))
@@ -977,6 +997,7 @@ WHILE-LIST."
977 (string-append home-dir "/.guix-profile") 997 (string-append home-dir "/.guix-profile")
978 profile) 998 profile)
979 manifest #:pure? #f 999 manifest #:pure? #f
1000 #:environment-variables environment-variables
980 #:emulate-fhs? emulate-fhs?))) 1001 #:emulate-fhs? emulate-fhs?)))
981 #:populate-file-system 1002 #:populate-file-system
982 (lambda () 1003 (lambda ()
@@ -1171,7 +1192,8 @@ command-line option processing with 'parse-command-line'."
1171 '("/bin/sh") 1192 '("/bin/sh")
1172 (list %default-shell)))) 1193 (list %default-shell))))
1173 (mappings (pick-all opts 'file-system-mapping)) 1194 (mappings (pick-all opts 'file-system-mapping))
1174 (white-list (pick-all opts 'inherit-regexp))) 1195 (white-list (pick-all opts 'inherit-regexp))
1196 (environment-variables (pick-all opts 'environment-variables)))
1175 1197
1176 (define store-needed? 1198 (define store-needed?
1177 ;; Whether connecting to the daemon is needed. 1199 ;; Whether connecting to the daemon is needed.
@@ -1291,6 +1313,8 @@ when using '--container'; doing nothing~%"))
1291 #:profile profile 1313 #:profile profile
1292 #:manifest manifest 1314 #:manifest manifest
1293 #:white-list white-list 1315 #:white-list white-list
1316 #:environment-variables
1317 environment-variables
1294 #:link-profile? link-prof? 1318 #:link-profile? link-prof?
1295 #:network? network? 1319 #:network? network?
1296 #:map-cwd? (not no-cwd?) 1320 #:map-cwd? (not no-cwd?)
@@ -1308,6 +1332,8 @@ when using '--container'; doing nothing~%"))
1308 (exit/status 1332 (exit/status
1309 (launch-environment/fork command profile manifest 1333 (launch-environment/fork command profile manifest
1310 #:white-list white-list 1334 #:white-list white-list
1335 #:environment-variables
1336 environment-variables
1311 #:pure? pure?))))))))))))) 1337 #:pure? pure?)))))))))))))
1312 1338
1313;;; Local Variables: 1339;;; Local Variables:
diff --git a/tests/guix-environment.sh b/tests/guix-environment.sh
index 56cb289f2ff..450f0265221 100644
--- a/tests/guix-environment.sh
+++ b/tests/guix-environment.sh
@@ -49,18 +49,21 @@ test -x `sed -r 's/^export PATH="(.*)"/\1/' "$tmpdir/a"`/guile
49 49
50cmp "$tmpdir/a" "$tmpdir/b" 50cmp "$tmpdir/a" "$tmpdir/b"
51 51
52# Check '--preserve'. 52# Check '--preserve', as well as its -E VAR=VALUE special case.
53GUIX_TEST_ABC=1 53GUIX_TEST_ABC=1
54GUIX_TEST_DEF=2 54GUIX_TEST_DEF=2
55GUIX_TEST_XYZ=3 55GUIX_TEST_XYZ=3
56GUIX_TEST_ZZZ=4
56export GUIX_TEST_ABC GUIX_TEST_DEF GUIX_TEST_XYZ 57export GUIX_TEST_ABC GUIX_TEST_DEF GUIX_TEST_XYZ
57guix environment --bootstrap --ad-hoc guile-bootstrap --pure \ 58guix environment --bootstrap --ad-hoc guile-bootstrap --pure \
58 --preserve='^GUIX_TEST_A' --preserve='^GUIX_TEST_D' \ 59 --preserve='^GUIX_TEST_A' --preserve='^GUIX_TEST_D' \
60 --preserve='^GUIX_TEST_Z' -E 'GUIX_TEST_ZZZ=overridden' \
59 -- "$SHELL" -c set > "$tmpdir/a" 61 -- "$SHELL" -c set > "$tmpdir/a"
60grep '^PATH=' "$tmpdir/a" 62grep '^PATH=' "$tmpdir/a"
61grep '^GUIX_TEST_ABC=1' "$tmpdir/a" 63grep '^GUIX_TEST_ABC=1' "$tmpdir/a"
62grep '^GUIX_TEST_DEF=2' "$tmpdir/a" 64grep '^GUIX_TEST_DEF=2' "$tmpdir/a"
63grep '^GUIX_TEST_XYZ=3' "$tmpdir/a" && false 65grep '^GUIX_TEST_XYZ=3' "$tmpdir/a" && false
66grep '^GUIX_TEST_ZZZ=overridden' "$tmpdir/a"
64 67
65# Make sure the exit value is preserved. 68# Make sure the exit value is preserved.
66if guix environment --bootstrap --ad-hoc guile-bootstrap --pure \ 69if guix environment --bootstrap --ad-hoc guile-bootstrap --pure \